diff options
1021 files changed, 45711 insertions, 0 deletions
diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..223ede7d --- /dev/null +++ b/COPYING @@ -0,0 +1,504 @@ +		  GNU LESSER GENERAL PUBLIC LICENSE +		       Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. +     59 Temple Place, Suite 330, Boston, MA  02111-1307  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 Lesser GPL.  It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + +			    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 Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it.  You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + +  When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + +  To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +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 other code 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. + +  We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + +  To protect each distributor, we want to make it very clear that +there is no warranty for the free library.  Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + +  Finally, software patents pose a constant threat to the existence of +any free program.  We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder.  Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + +  Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License.  This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License.  We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + +  When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library.  The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom.  The Lesser General +Public License permits more lax criteria for linking other code with +the library. + +  We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License.  It also provides other free software developers Less +of an advantage over competing non-free programs.  These disadvantages +are the reason we use the ordinary General Public License for many +libraries.  However, the Lesser license provides advantages in certain +special circumstances. + +  For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard.  To achieve this, non-free programs must be +allowed to use the library.  A more frequent case is that a free +library does the same job as widely used non-free libraries.  In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + +  In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software.  For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + +  Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + +  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, whereas the latter must +be combined with the library in order to run. + +		  GNU LESSER GENERAL PUBLIC LICENSE +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +  0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser 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 combine 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) Use a suitable shared library mechanism for linking with the +    Library.  A suitable mechanism is one that (1) uses at run time a +    copy of the library already present on the user's computer system, +    rather than copying library functions into the executable, and (2) +    will operate properly with a modified version of the library, if +    the user installs one, as long as the modified version is +    interface-compatible with the version that the work was made with. + +    c) 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. + +    d) 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. + +    e) 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 materials to be 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 with +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 Lesser 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 + +           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 Lesser 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 +    Lesser General Public License for more details. + +    You should have received a copy of the GNU Lesser General Public +    License along with this library; if not, write to the Free Software +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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/COPYRIGHT b/COPYRIGHT new file mode 100644 index 00000000..30a74a21 --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,31 @@ +musl as a whole is licensed under the GNU LGPL version 2.1 or later. +See the file COPYING for the text of this license. + +See below for the copyright status on all code included in musl: + +The TRE regular expression implementation (src/regex/reg* and +src/regex/tre*) is Copyright © 2001-2006 Ville Laurikari and licensed +under the terms of the GNU LGPL version 2.1 or later. The included +version was heavily modified in Spring 2006 by Rich Felker in the +interests of size, simplicity, and namespace cleanliness. + +Most of the math library code (src/math/*) is Copyright © 1993 Sun +Microsystems, Inc. Some files are Copyright © 2003 Steven G. Kargl and +labelled as such. All have been licensed under extremely permissive +terms which are compatible with the GNU LGPL. See the comments in the +individual files for details. + +The implementation of DES for crypt (src/misc/crypt.c) is Copyright © +1994 David Burren. It is licensed under a BSD license compatible with +the GNU LGPL. + +All files which have no copyright comments are original works +Copyright © 2005-2011 Rich Felker, the main author of this library. +The decision to exclude such comments is intentional, as it should be +possible to carry around the complete source code on tiny storage +media. All public header files (include/*) should be treated as Public +Domain as they intentionally contain no content which can be covered +by copyright. Some source modules may fall in this category as well. +If you believe that a file is so trivial that it should be in the +Public Domain, please contact me and, if I agree, I will explicitly +release it from copyright. diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..2470a5bf --- /dev/null +++ b/INSTALL @@ -0,0 +1,61 @@ + +A quick-and-simple guide to installing musl: + + +STEP 1: Configuration + +Edit config.mak to override installation prefix, compiler options, +etc. as needed. The defaults should be okay for trying out musl with +static linking only. The only arch supported at present is i386. If +you're on an x86_64 machine, you can add -m32 to the compiler options +to build a working 32bit musl. In this case you will also need to add +-m32 in two locations in the generated tools/musl-gcc script if you +intend to use it. + +DO NOT set the prefix to /, /usr, or even /usr/local unless you really +know what you're doing! You'll probably break your system such that +you'll no longer be able to compile and link programs against glibc! +This kind of setup should only be used if you're building a system +where musl is the default/primary/only libc. + +The default prefix is /usr/local/musl for a reason, but some people +may prefer /opt/musl or $HOME/musl. + + +STEP 2: Compiling + +Run "make". (GNU make is required.) + + +STEP 3: Installation + +With appropriate privileges, run "make install". + + +STEP 4: Using the gcc wrapper. + +musl comes with a script "musl-gcc" (installed in /usr/local/bin by +default) that can be used to compile and link C programs against musl. +It requires a version of gcc with the -wrapper option (gcc 4.x should +work). For example: + +cat > hello.c <<EOF +#include <stdio.h> +int main() +{ +	printf("hello, world!\n"); +	return 0; +} +EOF +musl-gcc hello.c +./a.out + +For compiling programs that use autoconf, you'll need to configure +them with a command like this: + +CC=musl-gcc ./configure + +Be aware that (at present) libraries linked against glibc are unlikely +to be usable, and the musl-gcc wrapper inhibits search of the system +library paths in any case. You'll need to compile any prerequisite +libraries (like ncurses, glib, etc.) yourself. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..e4235cb5 --- /dev/null +++ b/Makefile @@ -0,0 +1,97 @@ +# +# Makefile for musl (requires GNU make) +# +# This is how simple every makefile should be... +# No, I take that back - actually most should be less than half this size. +# +# Use config.mak to override any of the following variables. +# Do not make changes here. +# + +exec_prefix = /usr/local +bindir = $(exec_prefix)/bin + +prefix = /usr/local/musl +includedir = $(prefix)/include +libdir = $(prefix)/lib + +SRCS = $(sort $(wildcard src/*/*.c)) +OBJS = $(SRCS:.c=.o) +LOBJS = $(OBJS:.o=.lo) +GENH = include/bits/alltypes.h + +CFLAGS  = -Os -nostdinc -ffreestanding -pipe +LDFLAGS = -nostdlib -shared -Wl,-Bsymbolic +INC     = -I./include -I./src/internal +PIC     = -fPIC +AR      = $(CROSS_COMPILE)ar +RANLIB  = $(CROSS_COMPILE)ranlib +OBJCOPY = $(CROSS_COMPILE)objcopy + +ALL_INCLUDES = $(sort $(wildcard include/*.h include/*/*.h) $(GENH)) + +EMPTY_LIB_NAMES = m rt pthread crypt util xnet resolv +EMPTY_LIBS = $(EMPTY_LIB_NAMES:%=lib/lib%.a) +CRT_LIBS = lib/crt1.o lib/crti.o lib/crtn.o +LIBC_LIBS = lib/libc.a +ALL_LIBS = $(LIBC_LIBS) $(CRT_LIBS) $(EMPTY_LIBS) + +ALL_TOOLS = tools/musl-gcc + +-include config.mak + +all: $(ALL_LIBS) $(ALL_TOOLS) + +install: $(ALL_LIBS:lib/%=$(DESTDIR)$(libdir)/%) $(ALL_INCLUDES:include/%=$(DESTDIR)$(includedir)/%) $(ALL_TOOLS:tools/%=$(DESTDIR)$(bindir)/%) + +clean: +	rm -f crt/*.o +	rm -f $(OBJS) +	rm -f $(LOBJS) +	rm -f $(ALL_LIBS) lib/* +	rm -f $(ALL_TOOLS) +	rm -f $(GENH)  + +include/bits/alltypes.h: include/bits/alltypes.h.sh +	sh $< > $@ + +%.o: $(ARCH)/%.s +	$(CC) $(CFLAGS) $(INC) -c -o $@ $< + +%.o: %.c $(GENH) +	$(CC) $(CFLAGS) $(INC) -c -o $@ $< + +%.lo: $(ARCH)/%.s +	$(CC) $(CFLAGS) $(INC) $(PIC) -c -o $@ $< + +%.lo: %.c $(GENH) +	$(CC) $(CFLAGS) $(INC) $(PIC) -c -o $@ $< + +lib/libc.so: $(LOBJS) +	$(CC) $(LDFLAGS) -o $@ $(LOBJS) -lgcc +	$(OBJCOPY) --weaken $@ + +lib/libc.a: $(OBJS) +	rm -f $@ +	$(AR) rc $@ $(OBJS) +	$(RANLIB) $@ + +$(EMPTY_LIBS): +	$(AR) rc $@ + +lib/%.o: crt/%.o +	cp $< $@ + +tools/musl-gcc: tools/gen-musl-gcc.sh config.mak +	sh $< "$(prefix)" > $@ || { rm -f $@ ; exit 1 ; } +	chmod +x $@ + +$(DESTDIR)$(bindir)/%: tools/% +	install -D $< $@ + +$(DESTDIR)$(prefix)/%: % +	install -D -m 644 $< $@ + +.PRECIOUS: $(CRT_LIBS:lib/%=crt/%) + +.PHONY: all clean install @@ -0,0 +1,44 @@ + +musl libc - a new standard library to power a new generation of +Linux-based devices. musl is lightweight, fast, simple, free, and +strives to be correct in the sense of standards-conformance and +safety. + +musl is an alternative to glibc, eglibc, uClibc, dietlibc, and klibc. +For reasons why one might prefer musl, please see the FAQ and libc +comparison chart on the project website, + +    http://www.etalabs.net/musl/ + +For installation instructions, see the INSTALL file. + +Please refer to the COPYRIGHT file for details on the copyright status +of code included in musl, and the COPYING file for the license (LGPL) +under which the library as a whole is distributed. + + + +Greetings libc hackers! + +This package is an _alpha_ release of musl, intended for the curious +and the adventurous. While it can be used to build a complete small +Linux system (musl is self-hosted on the system I use to develop it), +at this point doing so requires a lot of manual effort. Nonetheless, I +hope low-level Linux enthusiasts will try out building some compact +static binaries with musl using the provided gcc wrapper (which allows +you to link programs with musl on a "standard" glibc Linux system), +find whatever embarassing bugs I've let slip through, and provide +feedback on issues encountered building various software against musl. + +Please visit #musl on Freenode IRC or contact me via email at dalias +AT etalabs DOT net for bug reports, support requests, or to get +involved in development. As this has been a one-person project so far, +mailing lists will be setup in due time on an as-needed basis. + +Thank you for trying out musl. + +Cheers, + +Rich Felker / dalias + + diff --git a/crt/crt1.c b/crt/crt1.c new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/crt/crt1.c diff --git a/crt/crti.c b/crt/crti.c new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/crt/crti.c diff --git a/crt/crtn.c b/crt/crtn.c new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/crt/crtn.c diff --git a/crt/i386/crt1.s b/crt/i386/crt1.s new file mode 100644 index 00000000..050adec8 --- /dev/null +++ b/crt/i386/crt1.s @@ -0,0 +1,17 @@ +.text +.global _start +_start: +	xorl %ebp,%ebp +	popl %ecx +	movl %esp,%eax +	andl $-16,%esp +	pushl %esp +	pushl %esp +	pushl %edx +	pushl $0 +	pushl $0 +	pushl %eax +	pushl %ecx +	pushl $main +	call __libc_start_main +.L0:	jmp .L0 diff --git a/dist/config.mak b/dist/config.mak new file mode 100644 index 00000000..51205522 --- /dev/null +++ b/dist/config.mak @@ -0,0 +1,25 @@ +# +# musl config.mak template (original in dist/config.mak) +# + +# Target CPU architecture. Supported values: i386 +ARCH = i386 + +# Installation prefix. DO NOT use /, /usr, or /usr/local ! +prefix = /usr/local/musl + +# Installation prefix for musl-gcc compiler wrapper. +exec_prefix = /usr/local + +# Uncomment if you want to build i386 musl on a 64-bit host +#CFLAGS += -m32 + +# Uncomment for smaller code size. +#CFLAGS += -fomit-frame-pointer -mno-accumulate-outgoing-args + +# Uncomment for warnings (as errors). Might need tuning to your gcc version. +#CFLAGS += -Werror -Wall -Wpointer-arith -Wcast-align -Wno-parentheses -Wno-char-subscripts -Wno-uninitialized -Wno-sequence-point -Wno-missing-braces -Wno-unused-value +#CFLAGS += -Wno-pointer-sign + +# Uncomment if you want to build a shared library (experimental). +#LIBC_LIBS += lib/libc.so diff --git a/include/alloca.h b/include/alloca.h new file mode 100644 index 00000000..ac78e460 --- /dev/null +++ b/include/alloca.h @@ -0,0 +1,9 @@ +#ifndef	_ALLOCA_H +#define	_ALLOCA_H + +#define	__NEED_size_t +#include <bits/alltypes.h> + +void *alloca(size_t); + +#endif diff --git a/include/arpa/inet.h b/include/arpa/inet.h new file mode 100644 index 00000000..93427130 --- /dev/null +++ b/include/arpa/inet.h @@ -0,0 +1,33 @@ +#ifndef _ARPA_INET_H +#define	_ARPA_INET_H + +#include <netinet/in.h> +#include <inttypes.h> + +#define __NEED_socklen_t +#define __NEED_in_addr_t +#define __NEED_in_port_t +#define __NEED_uint16_t +#define __NEED_uint32_t +#define __NEED_struct_in_addr + +#include <bits/alltypes.h> + +uint32_t htonl(uint32_t); +uint16_t htons(uint16_t); +uint32_t ntohl(uint32_t); +uint16_t ntohs(uint16_t); + +in_addr_t inet_addr (const char *); +char *inet_ntoa (struct in_addr); +int inet_pton (int, const char *, void *); +const char *inet_ntop (int, const void *, char *, socklen_t); + +int inet_aton (const char *, struct in_addr *); /* nonstandard but widely used */ + +#undef INET_ADDRSTRLEN +#undef INET6_ADDRSTRLEN +#define INET_ADDRSTRLEN  16 +#define INET6_ADDRSTRLEN 46 + +#endif diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h new file mode 100644 index 00000000..0f854600 --- /dev/null +++ b/include/arpa/nameser.h @@ -0,0 +1,465 @@ +#ifndef _ARPA_NAMESER_H_ +#define _ARPA_NAMESER_H_ + +#define __NAMESER	19991006 +#define NS_PACKETSZ	512 +#define NS_MAXDNAME	1025 +#define NS_MAXMSG	65535 +#define NS_MAXCDNAME	255 +#define NS_MAXLABEL	63 +#define NS_HFIXEDSZ	12 +#define NS_QFIXEDSZ	4 +#define NS_RRFIXEDSZ	10 +#define NS_INT32SZ	4 +#define NS_INT16SZ	2 +#define NS_INT8SZ	1 +#define NS_INADDRSZ	4 +#define NS_IN6ADDRSZ	16 +#define NS_CMPRSFLGS	0xc0 +#define NS_DEFAULTPORT	53 + +typedef enum __ns_sect { +	ns_s_qd = 0, +	ns_s_zn = 0, +	ns_s_an = 1, +	ns_s_pr = 1, +	ns_s_ns = 2, +	ns_s_ud = 2, +	ns_s_ar = 3, +	ns_s_max = 4 +} ns_sect; + +typedef struct __ns_msg { +	const unsigned char *_msg, *_eom; +	uint16_t _id, _flags, _counts[ns_s_max]; +	const unsigned char *_sections[ns_s_max]; +	ns_sect _sect; +	int _rrnum; +	const unsigned char *_msg_ptr; +} ns_msg; + +struct _ns_flagdata {  int mask, shift;  }; +extern const struct _ns_flagdata _ns_flagdata[]; + +#define ns_msg_id(handle) ((handle)._id + 0) +#define ns_msg_base(handle) ((handle)._msg + 0) +#define ns_msg_end(handle) ((handle)._eom + 0) +#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) +#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) + +typedef	struct __ns_rr { +	char		name[NS_MAXDNAME]; +	uint16_t	type; +	uint16_t	rr_class; +	uint32_t	ttl; +	uint16_t	rdlength; +	const unsigned char *rdata; +} ns_rr; + +#define ns_rr_name(rr)	(((rr).name[0] != '\0') ? (rr).name : ".") +#define ns_rr_type(rr)	((ns_type)((rr).type + 0)) +#define ns_rr_class(rr)	((ns_class)((rr).rr_class + 0)) +#define ns_rr_ttl(rr)	((rr).ttl + 0) +#define ns_rr_rdlen(rr)	((rr).rdlength + 0) +#define ns_rr_rdata(rr)	((rr).rdata + 0) + +typedef enum __ns_flag { +	ns_f_qr, +	ns_f_opcode, +	ns_f_aa, +	ns_f_tc, +	ns_f_rd, +	ns_f_ra, +	ns_f_z, +	ns_f_ad, +	ns_f_cd, +	ns_f_rcode, +	ns_f_max +} ns_flag; + +typedef enum __ns_opcode { +	ns_o_query = 0, +	ns_o_iquery = 1, +	ns_o_status = 2, +	ns_o_notify = 4, +	ns_o_update = 5, +	ns_o_max = 6 +} ns_opcode; + +typedef	enum __ns_rcode { +	ns_r_noerror = 0, +	ns_r_formerr = 1, +	ns_r_servfail = 2, +	ns_r_nxdomain = 3, +	ns_r_notimpl = 4, +	ns_r_refused = 5, +	ns_r_yxdomain = 6, +	ns_r_yxrrset = 7, +	ns_r_nxrrset = 8, +	ns_r_notauth = 9, +	ns_r_notzone = 10, +	ns_r_max = 11, +	ns_r_badvers = 16, +	ns_r_badsig = 16, +	ns_r_badkey = 17, +	ns_r_badtime = 18 +} ns_rcode; + +typedef enum __ns_update_operation { +	ns_uop_delete = 0, +	ns_uop_add = 1, +	ns_uop_max = 2 +} ns_update_operation; + +struct ns_tsig_key { +        char name[NS_MAXDNAME], alg[NS_MAXDNAME]; +        unsigned char *data; +        int len; +}; +typedef struct ns_tsig_key ns_tsig_key; + +struct ns_tcp_tsig_state { +	int counter; +	struct dst_key *key; +	void *ctx; +	unsigned char sig[NS_PACKETSZ]; +	int siglen; +}; +typedef struct ns_tcp_tsig_state ns_tcp_tsig_state; + +#define NS_TSIG_FUDGE 300 +#define NS_TSIG_TCP_COUNT 100 +#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT" + +#define NS_TSIG_ERROR_NO_TSIG -10 +#define NS_TSIG_ERROR_NO_SPACE -11 +#define NS_TSIG_ERROR_FORMERR -12 + +typedef enum __ns_type { +	ns_t_invalid = 0, +	ns_t_a = 1, +	ns_t_ns = 2, +	ns_t_md = 3, +	ns_t_mf = 4, +	ns_t_cname = 5, +	ns_t_soa = 6, +	ns_t_mb = 7, +	ns_t_mg = 8, +	ns_t_mr = 9, +	ns_t_null = 10, +	ns_t_wks = 11, +	ns_t_ptr = 12, +	ns_t_hinfo = 13, +	ns_t_minfo = 14, +	ns_t_mx = 15, +	ns_t_txt = 16, +	ns_t_rp = 17, +	ns_t_afsdb = 18, +	ns_t_x25 = 19, +	ns_t_isdn = 20, +	ns_t_rt = 21, +	ns_t_nsap = 22, +	ns_t_nsap_ptr = 23, +	ns_t_sig = 24, +	ns_t_key = 25, +	ns_t_px = 26, +	ns_t_gpos = 27, +	ns_t_aaaa = 28, +	ns_t_loc = 29, +	ns_t_nxt = 30, +	ns_t_eid = 31, +	ns_t_nimloc = 32, +	ns_t_srv = 33, +	ns_t_atma = 34, +	ns_t_naptr = 35, +	ns_t_kx = 36, +	ns_t_cert = 37, +	ns_t_a6 = 38, +	ns_t_dname = 39, +	ns_t_sink = 40, +	ns_t_opt = 41, +	ns_t_apl = 42, +	ns_t_tkey = 249, +	ns_t_tsig = 250, +	ns_t_ixfr = 251, +	ns_t_axfr = 252, +	ns_t_mailb = 253, +	ns_t_maila = 254, +	ns_t_any = 255, +	ns_t_zxfr = 256, +	ns_t_max = 65536 +} ns_type; + +#define	ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \ +		      (t) == ns_t_mailb || (t) == ns_t_maila) +#define	ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt) +#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t)) +#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr) +#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \ +		       (t) == ns_t_zxfr) + +typedef enum __ns_class { +	ns_c_invalid = 0, +	ns_c_in = 1, +	ns_c_2 = 2, +	ns_c_chaos = 3, +	ns_c_hs = 4, +	ns_c_none = 254, +	ns_c_any = 255, +	ns_c_max = 65536 +} ns_class; + +typedef enum __ns_key_types { +	ns_kt_rsa = 1, +	ns_kt_dh  = 2, +	ns_kt_dsa = 3, +	ns_kt_private = 254 +} ns_key_types; + +typedef enum __ns_cert_types { +	cert_t_pkix = 1, +	cert_t_spki = 2, +	cert_t_pgp  = 3, +	cert_t_url  = 253, +	cert_t_oid  = 254 +} ns_cert_types; + +#define	NS_KEY_TYPEMASK		0xC000 +#define	NS_KEY_TYPE_AUTH_CONF	0x0000 +#define	NS_KEY_TYPE_CONF_ONLY	0x8000 +#define	NS_KEY_TYPE_AUTH_ONLY	0x4000 +#define	NS_KEY_TYPE_NO_KEY	0xC000 +#define	NS_KEY_NO_AUTH		0x8000 +#define	NS_KEY_NO_CONF		0x4000 +#define	NS_KEY_RESERVED2	0x2000 +#define	NS_KEY_EXTENDED_FLAGS	0x1000 +#define	NS_KEY_RESERVED4	0x0800 +#define	NS_KEY_RESERVED5	0x0400 +#define	NS_KEY_NAME_TYPE	0x0300 +#define	NS_KEY_NAME_USER	0x0000 +#define	NS_KEY_NAME_ENTITY	0x0200 +#define	NS_KEY_NAME_ZONE	0x0100 +#define	NS_KEY_NAME_RESERVED	0x0300 +#define	NS_KEY_RESERVED8	0x0080 +#define	NS_KEY_RESERVED9	0x0040 +#define	NS_KEY_RESERVED10	0x0020 +#define	NS_KEY_RESERVED11	0x0010 +#define	NS_KEY_SIGNATORYMASK	0x000F +#define	NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \ +				  NS_KEY_RESERVED4 | \ +				  NS_KEY_RESERVED5 | \ +				  NS_KEY_RESERVED8 | \ +				  NS_KEY_RESERVED9 | \ +				  NS_KEY_RESERVED10 | \ +				  NS_KEY_RESERVED11 ) +#define NS_KEY_RESERVED_BITMASK2 0xFFFF +#define	NS_ALG_MD5RSA		1 +#define	NS_ALG_DH               2 +#define	NS_ALG_DSA              3 +#define	NS_ALG_DSS              NS_ALG_DSA +#define	NS_ALG_EXPIRE_ONLY	253 +#define	NS_ALG_PRIVATE_OID	254 + +#define NS_KEY_PROT_TLS         1 +#define NS_KEY_PROT_EMAIL       2 +#define NS_KEY_PROT_DNSSEC      3 +#define NS_KEY_PROT_IPSEC       4 +#define NS_KEY_PROT_ANY		255 + +#define	NS_MD5RSA_MIN_BITS	 512 +#define	NS_MD5RSA_MAX_BITS	4096 +#define	NS_MD5RSA_MAX_BYTES	((NS_MD5RSA_MAX_BITS+7/8)*2+3) +#define	NS_MD5RSA_MAX_BASE64	(((NS_MD5RSA_MAX_BYTES+2)/3)*4) +#define NS_MD5RSA_MIN_SIZE	((NS_MD5RSA_MIN_BITS+7)/8) +#define NS_MD5RSA_MAX_SIZE	((NS_MD5RSA_MAX_BITS+7)/8) + +#define NS_DSA_SIG_SIZE         41 +#define NS_DSA_MIN_SIZE         213 +#define NS_DSA_MAX_BYTES        405 + +#define	NS_SIG_TYPE	0 +#define	NS_SIG_ALG	2 +#define	NS_SIG_LABELS	3 +#define	NS_SIG_OTTL	4 +#define	NS_SIG_EXPIR	8 +#define	NS_SIG_SIGNED	12 +#define	NS_SIG_FOOT	16 +#define	NS_SIG_SIGNER	18 +#define	NS_NXT_BITS 8 +#define	NS_NXT_BIT_SET(  n,p) (p[(n)/NS_NXT_BITS] |=  (0x80>>((n)%NS_NXT_BITS))) +#define	NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS))) +#define	NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] &   (0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_MAX 127 + +#define NS_OPT_DNSSEC_OK        0x8000U +#define NS_OPT_NSID		3 + +#define NS_GET16(s, cp) do { \ +	register const unsigned char *t_cp = (const unsigned char *)(cp); \ +	(s) = ((uint16_t)t_cp[0] << 8) \ +	    | ((uint16_t)t_cp[1]) \ +	    ; \ +	(cp) += NS_INT16SZ; \ +} while (0) + +#define NS_GET32(l, cp) do { \ +	register const unsigned char *t_cp = (const unsigned char *)(cp); \ +	(l) = ((uint32_t)t_cp[0] << 24) \ +	    | ((uint32_t)t_cp[1] << 16) \ +	    | ((uint32_t)t_cp[2] << 8) \ +	    | ((uint32_t)t_cp[3]) \ +	    ; \ +	(cp) += NS_INT32SZ; \ +} while (0) + +#define NS_PUT16(s, cp) do { \ +	register uint16_t t_s = (uint16_t)(s); \ +	register unsigned char *t_cp = (unsigned char *)(cp); \ +	*t_cp++ = t_s >> 8; \ +	*t_cp   = t_s; \ +	(cp) += NS_INT16SZ; \ +} while (0) + +#define NS_PUT32(l, cp) do { \ +	register uint32_t t_l = (uint32_t)(l); \ +	register unsigned char *t_cp = (unsigned char *)(cp); \ +	*t_cp++ = t_l >> 24; \ +	*t_cp++ = t_l >> 16; \ +	*t_cp++ = t_l >> 8; \ +	*t_cp   = t_l; \ +	(cp) += NS_INT32SZ; \ +} while (0) + + + + +#define	__BIND		19950621 + +typedef struct { +	unsigned	id :16; +#if __BYTE_ORDER == __BIG_ENDIAN +	unsigned	qr: 1; +	unsigned	opcode: 4; +	unsigned	aa: 1; +	unsigned	tc: 1; +	unsigned	rd: 1; +	unsigned	ra: 1; +	unsigned	unused :1; +	unsigned	ad: 1; +	unsigned	cd: 1; +	unsigned	rcode :4; +#else +	unsigned	rd :1; +	unsigned	tc :1; +	unsigned	aa :1; +	unsigned	opcode :4; +	unsigned	qr :1; +	unsigned	rcode :4; +	unsigned	cd: 1; +	unsigned	ad: 1; +	unsigned	unused :1; +	unsigned	ra :1; +#endif +	unsigned	qdcount :16; +	unsigned	ancount :16; +	unsigned	nscount :16; +	unsigned	arcount :16; +} HEADER; + +#define PACKETSZ	NS_PACKETSZ +#define MAXDNAME	NS_MAXDNAME +#define MAXCDNAME	NS_MAXCDNAME +#define MAXLABEL	NS_MAXLABEL +#define	HFIXEDSZ	NS_HFIXEDSZ +#define QFIXEDSZ	NS_QFIXEDSZ +#define RRFIXEDSZ	NS_RRFIXEDSZ +#define	INT32SZ		NS_INT32SZ +#define	INT16SZ		NS_INT16SZ +#define INT8SZ		NS_INT8SZ +#define	INADDRSZ	NS_INADDRSZ +#define	IN6ADDRSZ	NS_IN6ADDRSZ +#define	INDIR_MASK	NS_CMPRSFLGS +#define NAMESERVER_PORT	NS_DEFAULTPORT + +#define S_ZONE		ns_s_zn +#define S_PREREQ	ns_s_pr +#define S_UPDATE	ns_s_ud +#define S_ADDT		ns_s_ar + +#define QUERY		ns_o_query +#define IQUERY		ns_o_iquery +#define STATUS		ns_o_status +#define	NS_NOTIFY_OP	ns_o_notify +#define	NS_UPDATE_OP	ns_o_update + +#define NOERROR		ns_r_noerror +#define FORMERR		ns_r_formerr +#define SERVFAIL	ns_r_servfail +#define NXDOMAIN	ns_r_nxdomain +#define NOTIMP		ns_r_notimpl +#define REFUSED		ns_r_refused +#define YXDOMAIN	ns_r_yxdomain +#define YXRRSET		ns_r_yxrrset +#define NXRRSET		ns_r_nxrrset +#define NOTAUTH		ns_r_notauth +#define NOTZONE		ns_r_notzone + +#define DELETE		ns_uop_delete +#define ADD		ns_uop_add + +#define T_A		ns_t_a +#define T_NS		ns_t_ns +#define T_MD		ns_t_md +#define T_MF		ns_t_mf +#define T_CNAME		ns_t_cname +#define T_SOA		ns_t_soa +#define T_MB		ns_t_mb +#define T_MG		ns_t_mg +#define T_MR		ns_t_mr +#define T_NULL		ns_t_null +#define T_WKS		ns_t_wks +#define T_PTR		ns_t_ptr +#define T_HINFO		ns_t_hinfo +#define T_MINFO		ns_t_minfo +#define T_MX		ns_t_mx +#define T_TXT		ns_t_txt +#define	T_RP		ns_t_rp +#define T_AFSDB		ns_t_afsdb +#define T_X25		ns_t_x25 +#define T_ISDN		ns_t_isdn +#define T_RT		ns_t_rt +#define T_NSAP		ns_t_nsap +#define T_NSAP_PTR	ns_t_nsap_ptr +#define	T_SIG		ns_t_sig +#define	T_KEY		ns_t_key +#define	T_PX		ns_t_px +#define	T_GPOS		ns_t_gpos +#define	T_AAAA		ns_t_aaaa +#define	T_LOC		ns_t_loc +#define	T_NXT		ns_t_nxt +#define	T_EID		ns_t_eid +#define	T_NIMLOC	ns_t_nimloc +#define	T_SRV		ns_t_srv +#define T_ATMA		ns_t_atma +#define T_NAPTR		ns_t_naptr +#define T_A6		ns_t_a6 +#define T_DNAME		ns_t_dname +#define	T_TSIG		ns_t_tsig +#define	T_IXFR		ns_t_ixfr +#define T_AXFR		ns_t_axfr +#define T_MAILB		ns_t_mailb +#define T_MAILA		ns_t_maila +#define T_ANY		ns_t_any + +#define C_IN		ns_c_in +#define C_CHAOS		ns_c_chaos +#define C_HS		ns_c_hs +#define C_NONE		ns_c_none +#define C_ANY		ns_c_any + +#define	GETSHORT		NS_GET16 +#define	GETLONG			NS_GET32 +#define	PUTSHORT		NS_PUT16 +#define	PUTLONG			NS_PUT32 + +#endif diff --git a/include/arpa/telnet.h b/include/arpa/telnet.h new file mode 100644 index 00000000..e2ad9742 --- /dev/null +++ b/include/arpa/telnet.h @@ -0,0 +1,251 @@ +#ifndef _ARPA_TELNET_H +#define	_ARPA_TELNET_H + +#define	IAC	255 +#define	DONT	254 +#define	DO	253 +#define	WONT	252 +#define	WILL	251 +#define	SB	250 +#define	GA	249 +#define	EL	248 +#define	EC	247 +#define	AYT	246 +#define	AO	245 +#define	IP	244 +#define	BREAK	243 +#define	DM	242 +#define	NOP	241 +#define	SE	240 +#define EOR     239 +#define	ABORT	238 +#define	SUSP	237 +#define	xEOF	236 + +#define SYNCH	242 + +#define telcmds ((char [][6]){ "EOF", "SUSP", "ABORT", "EOR", "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0 }) + +#define	TELCMD_FIRST	xEOF +#define	TELCMD_LAST	IAC +#define	TELCMD_OK(x)	((unsigned int)(x) <= TELCMD_LAST && \ +			 (unsigned int)(x) >= TELCMD_FIRST) +#define	TELCMD(x)	telcmds[(x)-TELCMD_FIRST] + +#define TELOPT_BINARY	0 +#define TELOPT_ECHO	1 +#define	TELOPT_RCP	2 +#define	TELOPT_SGA	3 +#define	TELOPT_NAMS	4 +#define	TELOPT_STATUS	5 +#define	TELOPT_TM	6 +#define	TELOPT_RCTE	7 +#define TELOPT_NAOL 	8 +#define TELOPT_NAOP 	9 +#define TELOPT_NAOCRD	10 +#define TELOPT_NAOHTS	11 +#define TELOPT_NAOHTD	12 +#define TELOPT_NAOFFD	13 +#define TELOPT_NAOVTS	14 +#define TELOPT_NAOVTD	15 +#define TELOPT_NAOLFD	16 +#define TELOPT_XASCII	17 +#define	TELOPT_LOGOUT	18 +#define	TELOPT_BM	19 +#define	TELOPT_DET	20 +#define	TELOPT_SUPDUP	21 +#define	TELOPT_SUPDUPOUTPUT 22 +#define	TELOPT_SNDLOC	23 +#define	TELOPT_TTYPE	24 +#define	TELOPT_EOR	25 +#define	TELOPT_TUID	26 +#define	TELOPT_OUTMRK	27 +#define	TELOPT_TTYLOC	28 +#define	TELOPT_3270REGIME 29 +#define	TELOPT_X3PAD	30 +#define	TELOPT_NAWS	31 +#define	TELOPT_TSPEED	32 +#define	TELOPT_LFLOW	33 +#define TELOPT_LINEMODE	34 +#define TELOPT_XDISPLOC	35 +#define TELOPT_OLD_ENVIRON 36 +#define	TELOPT_AUTHENTICATION 37/* Authenticate */ +#define	TELOPT_ENCRYPT	38 +#define TELOPT_NEW_ENVIRON 39 +#define	TELOPT_EXOPL	255 + + +#define	NTELOPTS	(1+TELOPT_NEW_ENVIRON) +#ifdef TELOPTS +char *telopts[NTELOPTS+1] = { +	"BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", +	"STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", +	"NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", +	"NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", +	"DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", +	"SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", +	"TACACS UID", "OUTPUT MARKING", "TTYLOC", +	"3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", +	"LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", +	"ENCRYPT", "NEW-ENVIRON", +	0, +}; +#define	TELOPT_FIRST	TELOPT_BINARY +#define	TELOPT_LAST	TELOPT_NEW_ENVIRON +#define	TELOPT_OK(x)	((unsigned int)(x) <= TELOPT_LAST) +#define	TELOPT(x)	telopts[(x)-TELOPT_FIRST] +#endif + +#define	TELQUAL_IS	0 +#define	TELQUAL_SEND	1 +#define	TELQUAL_INFO	2 +#define	TELQUAL_REPLY	2 +#define	TELQUAL_NAME	3 + +#define	LFLOW_OFF		0 +#define	LFLOW_ON		1 +#define	LFLOW_RESTART_ANY	2 +#define	LFLOW_RESTART_XON	3 + + +#define	LM_MODE		1 +#define	LM_FORWARDMASK	2 +#define	LM_SLC		3 + +#define	MODE_EDIT	0x01 +#define	MODE_TRAPSIG	0x02 +#define	MODE_ACK	0x04 +#define MODE_SOFT_TAB	0x08 +#define MODE_LIT_ECHO	0x10 + +#define	MODE_MASK	0x1f + +#define MODE_FLOW		0x0100 +#define MODE_ECHO		0x0200 +#define MODE_INBIN		0x0400 +#define MODE_OUTBIN		0x0800 +#define MODE_FORCE		0x1000 + +#define	SLC_SYNCH	1 +#define	SLC_BRK		2 +#define	SLC_IP		3 +#define	SLC_AO		4 +#define	SLC_AYT		5 +#define	SLC_EOR		6 +#define	SLC_ABORT	7 +#define	SLC_EOF		8 +#define	SLC_SUSP	9 +#define	SLC_EC		10 +#define	SLC_EL		11 +#define	SLC_EW		12 +#define	SLC_RP		13 +#define	SLC_LNEXT	14 +#define	SLC_XON		15 +#define	SLC_XOFF	16 +#define	SLC_FORW1	17 +#define	SLC_FORW2	18 + +#define	NSLC		18 + +#define	SLC_NAMELIST	"0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ +			"ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ +			"LNEXT", "XON", "XOFF", "FORW1", "FORW2", 0, +#ifdef	SLC_NAMES +char *slc_names[] = { +	SLC_NAMELIST +}; +#else +extern char *slc_names[]; +#define	SLC_NAMES SLC_NAMELIST +#endif + +#define	SLC_NAME_OK(x)	((unsigned int)(x) <= NSLC) +#define SLC_NAME(x)	slc_names[x] + +#define	SLC_NOSUPPORT	0 +#define	SLC_CANTCHANGE	1 +#define	SLC_VARIABLE	2 +#define	SLC_DEFAULT	3 +#define	SLC_LEVELBITS	0x03 + +#define	SLC_FUNC	0 +#define	SLC_FLAGS	1 +#define	SLC_VALUE	2 + +#define	SLC_ACK		0x80 +#define	SLC_FLUSHIN	0x40 +#define	SLC_FLUSHOUT	0x20 + +#define	OLD_ENV_VAR	1 +#define	OLD_ENV_VALUE	0 +#define	NEW_ENV_VAR	0 +#define	NEW_ENV_VALUE	1 +#define	ENV_ESC		2 +#define ENV_USERVAR	3 + +#define	AUTH_WHO_CLIENT		0 +#define	AUTH_WHO_SERVER		1 +#define	AUTH_WHO_MASK		1 + +#define	AUTH_HOW_ONE_WAY	0 +#define	AUTH_HOW_MUTUAL		2 +#define	AUTH_HOW_MASK		2 + +#define	AUTHTYPE_NULL		0 +#define	AUTHTYPE_KERBEROS_V4	1 +#define	AUTHTYPE_KERBEROS_V5	2 +#define	AUTHTYPE_SPX		3 +#define	AUTHTYPE_MINK		4 +#define	AUTHTYPE_CNT		5 + +#define	AUTHTYPE_TEST		99 + +#ifdef	AUTH_NAMES +char *authtype_names[] = { +	"NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", 0, +}; +#else +extern char *authtype_names[]; +#endif + +#define	AUTHTYPE_NAME_OK(x)	((unsigned int)(x) < AUTHTYPE_CNT) +#define	AUTHTYPE_NAME(x)	authtype_names[x] + +#define	ENCRYPT_IS		0 +#define	ENCRYPT_SUPPORT		1 +#define	ENCRYPT_REPLY		2 +#define	ENCRYPT_START		3 +#define	ENCRYPT_END		4 +#define	ENCRYPT_REQSTART	5 +#define	ENCRYPT_REQEND		6 +#define	ENCRYPT_ENC_KEYID	7 +#define	ENCRYPT_DEC_KEYID	8 +#define	ENCRYPT_CNT		9 + +#define	ENCTYPE_ANY		0 +#define	ENCTYPE_DES_CFB64	1 +#define	ENCTYPE_DES_OFB64	2 +#define	ENCTYPE_CNT		3 + +#ifdef	ENCRYPT_NAMES +char *encrypt_names[] = { +	"IS", "SUPPORT", "REPLY", "START", "END", +	"REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID", +	0, +}; +char *enctype_names[] = { +	"ANY", "DES_CFB64",  "DES_OFB64",  0, +}; +#else +extern char *encrypt_names[]; +extern char *enctype_names[]; +#endif + + +#define	ENCRYPT_NAME_OK(x)	((unsigned int)(x) < ENCRYPT_CNT) +#define	ENCRYPT_NAME(x)		encrypt_names[x] + +#define	ENCTYPE_NAME_OK(x)	((unsigned int)(x) < ENCTYPE_CNT) +#define	ENCTYPE_NAME(x)		enctype_names[x] + +#endif diff --git a/include/assert.h b/include/assert.h new file mode 100644 index 00000000..bad2ccd0 --- /dev/null +++ b/include/assert.h @@ -0,0 +1,17 @@ +#undef assert + +#ifdef NDEBUG +#define	assert(x) (void)0 +#else +#define assert(x) ((x) || (__assert_fail(#x, __FILE__, __LINE__, __func__),0)) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +void __assert_fail (const char *, const char *, int, const char *); + +#ifdef __cplusplus +} +#endif diff --git a/include/bits/alltypes.h.sh b/include/bits/alltypes.h.sh new file mode 100755 index 00000000..595bf13e --- /dev/null +++ b/include/bits/alltypes.h.sh @@ -0,0 +1,115 @@ +#!/bin/sh +sed -e << EOF \ +'/^TYPEDEF/s/TYPEDEF \(.*\) \([^ ]*\);$/#if defined(__NEED_\2) \&\& !defined(__DEFINED_\2)\ +typedef \1 \2;\ +#define __DEFINED_\2\ +#endif\ +/ +/^STRUCT/s/STRUCT * \([^ ]*\) \(.*\);$/#if defined(__NEED_struct_\1) \&\& !defined(__DEFINED_struct_\1)\ +struct \1 \2;\ +#define __DEFINED_struct_\1\ +#endif\ +/ +/^UNION/s/UNION * \([^ ]*\) \(.*\);$/#if defined(__NEED_union_\1) \&\& !defined(__DEFINED_union_\1)\ +union \1 \2;\ +#define __DEFINED_union_\1\ +#endif\ +/' + +TYPEDEF unsigned size_t; +TYPEDEF int ssize_t; +TYPEDEF long ptrdiff_t; +TYPEDEF struct __va_list * va_list; + +TYPEDEF long wchar_t; +TYPEDEF long wint_t; +TYPEDEF long wctrans_t; +TYPEDEF long wctype_t; + +TYPEDEF char      int8_t; +TYPEDEF short     int16_t; +TYPEDEF int       int32_t; +TYPEDEF long long int64_t; + +TYPEDEF unsigned char      uint8_t; +TYPEDEF unsigned short     uint16_t; +TYPEDEF unsigned int       uint32_t; +TYPEDEF unsigned long long uint64_t; + +TYPEDEF unsigned char      __uint8_t; +TYPEDEF unsigned short     __uint16_t; +TYPEDEF unsigned int       __uint32_t; +TYPEDEF unsigned long long __uint64_t; + +TYPEDEF int8_t  int_least8_t; +TYPEDEF int16_t int_least16_t; +TYPEDEF int32_t int_least32_t; +TYPEDEF int64_t int_least64_t; + +TYPEDEF uint8_t  uint_least8_t; +TYPEDEF uint16_t uint_least16_t; +TYPEDEF uint32_t uint_least32_t; +TYPEDEF uint64_t uint_least64_t; + +TYPEDEF int8_t    int_fast8_t; +TYPEDEF int       int_fast16_t; +TYPEDEF int       int_fast32_t; +TYPEDEF int64_t   int_fast64_t; + +TYPEDEF unsigned char      uint_fast8_t; +TYPEDEF unsigned int       uint_fast16_t; +TYPEDEF unsigned int       uint_fast32_t; +TYPEDEF uint64_t           uint_fast64_t; + +TYPEDEF long          intptr_t; +TYPEDEF unsigned long uintptr_t; + +TYPEDEF long long          intmax_t; +TYPEDEF unsigned long long uintmax_t; + +TYPEDEF long time_t; +TYPEDEF unsigned int useconds_t; +TYPEDEF int suseconds_t; +STRUCT timeval { time_t tv_sec; long tv_usec; }; +STRUCT timespec { time_t tv_sec; long tv_nsec; }; + +TYPEDEF int pid_t; +TYPEDEF int id_t; +TYPEDEF int uid_t; +TYPEDEF int gid_t; +TYPEDEF int key_t; +TYPEDEF struct __pthread * pthread_t; + +TYPEDEF long long off_t; + +TYPEDEF unsigned int mode_t; + +TYPEDEF unsigned int nlink_t; +TYPEDEF unsigned long long ino_t; +TYPEDEF long long dev_t; +TYPEDEF long blksize_t; +TYPEDEF long long blkcnt_t; +TYPEDEF unsigned long long fsblkcnt_t; +TYPEDEF unsigned long long fsfilcnt_t; + +TYPEDEF int timer_t; +TYPEDEF int clockid_t; +TYPEDEF unsigned long clock_t; + +TYPEDEF struct { unsigned long __bits[1024/sizeof(long)]; } sigset_t; +TYPEDEF struct __siginfo siginfo_t; + +TYPEDEF unsigned int socklen_t; +TYPEDEF unsigned short sa_family_t; +TYPEDEF unsigned short in_port_t; +TYPEDEF unsigned int in_addr_t; +STRUCT in_addr { in_addr_t s_addr; }; + +TYPEDEF struct __FILE_s FILE; + +TYPEDEF int nl_item; + +TYPEDEF struct __locale * locale_t; + + +EOF diff --git a/include/bits/endian.h b/include/bits/endian.h new file mode 100644 index 00000000..172c338f --- /dev/null +++ b/include/bits/endian.h @@ -0,0 +1 @@ +#define __BYTE_ORDER __LITTLE_ENDIAN diff --git a/include/bits/errno.h b/include/bits/errno.h new file mode 100644 index 00000000..fddea5ef --- /dev/null +++ b/include/bits/errno.h @@ -0,0 +1,125 @@ +#define EPERM            1 +#define ENOENT           2 +#define ESRCH            3 +#define EINTR            4 +#define EIO              5 +#define ENXIO            6 +#define E2BIG            7 +#define ENOEXEC          8 +#define EBADF            9 +#define ECHILD          10 +#define EAGAIN          11 +#define ENOMEM          12 +#define EACCES          13 +#define EFAULT          14 +#define ENOTBLK         15 +#define EBUSY           16 +#define EEXIST          17 +#define EXDEV           18 +#define ENODEV          19 +#define ENOTDIR         20 +#define EISDIR          21 +#define EINVAL          22 +#define ENFILE          23 +#define EMFILE          24 +#define ENOTTY          25 +#define ETXTBSY         26 +#define EFBIG           27 +#define ENOSPC          28 +#define ESPIPE          29 +#define EROFS           30 +#define EMLINK          31 +#define EPIPE           32 +#define EDOM            33 +#define ERANGE          34 +#define EDEADLK         35 +#define ENAMETOOLONG    36 +#define ENOLCK          37 +#define ENOSYS          38 +#define ENOTEMPTY       39 +#define ELOOP           40 +#define EWOULDBLOCK     EAGAIN +#define ENOMSG          42 +#define EIDRM           43 +#define ECHRNG          44 +#define EL2NSYNC        45 +#define EL3HLT          46 +#define EL3RST          47 +#define ELNRNG          48 +#define EUNATCH         49 +#define ENOCSI          50 +#define EL2HLT          51 +#define EBADE           52 +#define EBADR           53 +#define EXFULL          54 +#define ENOANO          55 +#define EBADRQC         56 +#define EBADSLT         57 +#define EDEADLOCK       EDEADLK +#define EBFONT          59 +#define ENOSTR          60 +#define ENODATA         61 +#define ETIME           62 +#define ENOSR           63 +#define ENONET          64 +#define ENOPKG          65 +#define EREMOTE         66 +#define ENOLINK         67 +#define EADV            68 +#define ESRMNT          69 +#define ECOMM           70 +#define EPROTO          71 +#define EMULTIHOP       72 +#define EDOTDOT         73 +#define EBADMSG         74 +#define EOVERFLOW       75 +#define ENOTUNIQ        76 +#define EBADFD          77 +#define EREMCHG         78 +#define ELIBACC         79 +#define ELIBBAD         80 +#define ELIBSCN         81 +#define ELIBMAX         82 +#define ELIBEXEC        83 +#define EILSEQ          84 +#define ERESTART        85 +#define ESTRPIPE        86 +#define EUSERS          87 +#define ENOTSOCK        88 +#define EDESTADDRREQ    89 +#define EMSGSIZE        90 +#define EPROTOTYPE      91 +#define ENOPROTOOPT     92 +#define EPROTONOSUPPORT 93 +#define ESOCKTNOSUPPORT 94 +#define EOPNOTSUPP      95 +#define EPFNOSUPPORT    96 +#define EAFNOSUPPORT    97 +#define EADDRINUSE      98 +#define EADDRNOTAVAIL   99 +#define ENETDOWN        100 +#define ENETUNREACH     101 +#define ENETRESET       102 +#define ECONNABORTED    103 +#define ECONNRESET      104 +#define ENOBUFS         105 +#define EISCONN         106 +#define ENOTCONN        107 +#define ESHUTDOWN       108 +#define ETOOMANYREFS    109 +#define ETIMEDOUT       110 +#define ECONNREFUSED    111 +#define EHOSTDOWN       112 +#define EHOSTUNREACH    113 +#define EALREADY        114 +#define EINPROGRESS     115 +#define ESTALE          116 +#define EUCLEAN         117 +#define ENOTNAM         118 +#define ENAVAIL         119 +#define EISNAM          120 +#define EREMOTEIO       121 +#define EDQUOT          122 +#define ENOMEDIUM       123 +#define EMEDIUMTYPE     124 +#define ECANCELED       125 diff --git a/include/bits/fcntl.h b/include/bits/fcntl.h new file mode 100644 index 00000000..550152fd --- /dev/null +++ b/include/bits/fcntl.h @@ -0,0 +1,59 @@ +#define O_ACCMODE 03 +#define O_RDONLY  00 +#define O_WRONLY  01 +#define O_RDWR    02 + +#define O_CREAT        0100 +#define O_EXCL         0200 +#define O_NOCTTY       0400 +#define O_TRUNC       01000 +#define O_APPEND      02000 +#define O_NONBLOCK    04000 +#define O_SYNC       010000 +#define O_DIRECTORY 0200000 +#define O_NOFOLLOW  0400000 +#define O_CLOEXEC  02000000 + +#ifdef _GNU_SOURCE +#define O_ASYNC      020000 +#define O_DIRECT     040000 +#define O_NOATIME  01000000 +#define F_DUPFD_CLOEXEC 1030 +#define FAPPENT O_APPEND +#define FFSYNC O_FSYNC +#define FASYNC O_ASYNC +#define FNONBLOCK O_NONBLOCK +#define FNDELAY O_NDELAY +#endif + +#define F_DUPFD  0 +#define F_GETFD  1 +#define F_SETFD  2 +#define F_GETFL  3 +#define F_SETFL  4 + +#define F_SETOWN 8 +#define F_GETOWN 9 + +#define F_GETLK 12 +#define F_SETLK 13 +#define F_SETLKW 14 + +#define FD_CLOEXEC 1 + +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +#define AT_FDCWD (-100) +#define AT_SYMLINK_NOFOLLOW 0x100 +#define AT_REMOVEDIR 0x200 +#define AT_SYMLINK_FOLLOW 0x400 +#define AT_EACCESS 0x200 + +#define POSIX_FADV_NORMAL     0 +#define POSIX_FADV_RANDOM     1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_WILLNEED   3 +#define POSIX_FADV_DONTNEED   4 +#define POSIX_FADV_NOREUSE    5 diff --git a/include/bits/fenv.h b/include/bits/fenv.h new file mode 100644 index 00000000..24df0417 --- /dev/null +++ b/include/bits/fenv.h @@ -0,0 +1,34 @@ +#define FE_INVALID    1 +#define __FE_DENORM   2 +#define FE_DIVBYZERO  4 +#define FE_OVERFLOW   8 +#define FE_UNDERFLOW  16 +#define FE_INEXACT    32 + +#define FE_ALL_EXCEPT 63 + +#define FE_TONEAREST  0 +#define FE_DOWNWARD   0x400 +#define FE_UPWARD     0x800 +#define FE_TOWARDZERO 0xc00 + +typedef unsigned short fexcept_t; + +typedef struct { +	unsigned short __control_word; +	unsigned short __unused1; +	unsigned short __status_word; +	unsigned short __unused2; +	unsigned short __tags; +	unsigned short __unused3; +	unsigned int __eip; +	unsigned short __cs_selector; +	unsigned int __opcode:11; +	unsigned int __unused4:5; +	unsigned int __data_offset; +	unsigned short __data_selector; +	unsigned short __unused5; +	unsigned int __mxcsr; +} fenv_t; + +#define FE_DFL_ENV      ((const fenv_t *) -1) diff --git a/include/bits/float.h b/include/bits/float.h new file mode 100644 index 00000000..162b3e46 --- /dev/null +++ b/include/bits/float.h @@ -0,0 +1,11 @@ +#define LDBL_MIN     3.3621031431120935063e-4932L +#define LDBL_MAX     1.1897314953572317650e+4932L +#define LDBL_EPSILON 1.0842021724855044340e-19L + +#define LDBL_MANT_DIG 64 +#define LDBL_MIN_EXP (-16381) +#define LDBL_MAX_EXP 16384 + +#define LDBL_DIG 18 +#define LDBL_MIN_10_EXP (-4931) +#define LDBL_MAX_10_EXP 4932 diff --git a/include/bits/in.h b/include/bits/in.h new file mode 100644 index 00000000..53ca31ca --- /dev/null +++ b/include/bits/in.h @@ -0,0 +1,89 @@ +#define IP_TOS             1 +#define IP_TTL             2 +#define IP_HDRINCL         3 +#define IP_OPTIONS         4 +#define IP_ROUTER_ALERT    5 +#define IP_RECVOPTS        6 +#define IP_RETOPTS         7 +//#define IP_PKTINFO         8 +#define IP_PKTOPTIONS      9 +#define IP_PMTUDISC        10 +#define IP_MTU_DISCOVER    10 +#define IP_RECVERR         11 +#define IP_RECVTTL         12 +#define IP_RECVTOS         13 +#define IP_MULTICAST_IF    32 +#define IP_MULTICAST_TTL   33 +#define IP_MULTICAST_LOOP  34 +#define IP_ADD_MEMBERSHIP  35 +#define IP_DROP_MEMBERSHIP 36 + +#define IP_RECVRETOPTS IP_RETOPTS + +#define IP_PMTUDISC_DONT   0 +#define IP_PMTUDISC_WANT   1 +#define IP_PMTUDISC_DO     2 + +#define SOL_IP 0 + +#define IP_DEFAULT_MULTICAST_TTL        1 +#define IP_DEFAULT_MULTICAST_LOOP       1 +#define IP_MAX_MEMBERSHIPS              20 + +struct ip_opts +{ +	struct in_addr ip_dst; +	char ip_opts[40]; +}; + +struct ip_mreq +{ +	struct in_addr imr_multiaddr; +	struct in_addr imr_interface; +}; + +struct ip_mreqn +{ +	struct in_addr imr_multiaddr; +	struct in_addr imr_address; +	int imr_ifindex; +}; + +struct in_pktinfo +{ +	int ipi_ifindex; +	struct in_addr ipi_spec_dst; +	struct in_addr ipi_addr; +}; + +#define IPV6_ADDRFORM           1 +#define IPV6_PKTINFO            2 +#define IPV6_HOPOPTS            3 +#define IPV6_DSTOPTS            4 +#define IPV6_RXSRCRT            5 +#define IPV6_PKTOPTIONS         6 +#define IPV6_CHECKSUM           7 +#define IPV6_HOPLIMIT           8 +#define IPV6_NEXTHOP            9 +#define IPV6_AUTHHDR            10 +#define IPV6_UNICAST_HOPS       16 +#define IPV6_MULTICAST_IF       17 +#define IPV6_MULTICAST_HOPS     18 +#define IPV6_MULTICAST_LOOP     19 +#define IPV6_ADD_MEMBERSHIP     20 +#define IPV6_DROP_MEMBERSHIP    21 +#define IPV6_ROUTER_ALERT       22 + +#define SCM_SRCRT               IPV6_RXSRCRT + +#define IPV6_RXHOPOPTS          IPV6_HOPOPTS +#define IPV6_RXDSTOPTS          IPV6_DSTOPTS + + +#define IPV6_PMTUDISC_DONT      0 +#define IPV6_PMTUDISC_WANT      1 +#define IPV6_PMTUDISC_DO        2 + + +#define SOL_IPV6        41 +#define SOL_ICMPV6      58 diff --git a/include/bits/ioctl.h b/include/bits/ioctl.h new file mode 100644 index 00000000..bb63ffb4 --- /dev/null +++ b/include/bits/ioctl.h @@ -0,0 +1,182 @@ +#define _IOC(a,b,c,d) ( ((a)<<30) | ((b)<<8) | (c) | ((d)<<16) ) +#define _IOC_NONE  0U +#define _IOC_WRITE 1U +#define _IOC_READ  2U + +#define _IO(a,b) _IOC(_IOC_NONE,(a),(b),0) +#define _IOW(a,b,c) _IOC(1,(a),(b),sizeof(c)) +#define _IOR(a,b,c) _IOC(2,(a),(b),sizeof(c)) +#define _IOWR(a,b,c) _IOC(3,(a),(b),sizeof(c)) + +#define TCGETS		0x5401 +#define TCSETS		0x5402 +#define TCSETSW		0x5403 +#define TCSETSF		0x5404 +#define TCGETA		0x5405 +#define TCSETA		0x5406 +#define TCSETAW		0x5407 +#define TCSETAF		0x5408 +#define TCSBRK		0x5409 +#define TCXONC		0x540A +#define TCFLSH		0x540B +#define TIOCEXCL	0x540C +#define TIOCNXCL	0x540D +#define TIOCSCTTY	0x540E +#define TIOCGPGRP	0x540F +#define TIOCSPGRP	0x5410 +#define TIOCOUTQ	0x5411 +#define TIOCSTI		0x5412 +#define TIOCGWINSZ	0x5413 +#define TIOCSWINSZ	0x5414 +#define TIOCMGET	0x5415 +#define TIOCMBIS	0x5416 +#define TIOCMBIC	0x5417 +#define TIOCMSET	0x5418 +#define TIOCGSOFTCAR	0x5419 +#define TIOCSSOFTCAR	0x541A +#define FIONREAD	0x541B +#define TIOCINQ		FIONREAD +#define TIOCLINUX	0x541C +#define TIOCCONS	0x541D +#define TIOCGSERIAL	0x541E +#define TIOCSSERIAL	0x541F +#define TIOCPKT		0x5420 +#define FIONBIO		0x5421 +#define TIOCNOTTY	0x5422 +#define TIOCSETD	0x5423 +#define TIOCGETD	0x5424 +#define TCSBRKP		0x5425 +#define TIOCTTYGSTRUCT	0x5426 +#define TIOCSBRK	0x5427 +#define TIOCCBRK	0x5428 +#define TIOCGSID	0x5429 +#define TIOCGPTN	0x80045430 +#define TIOCSPTLCK	0x40045431 + +#define FIONCLEX	0x5450 +#define FIOCLEX		0x5451 +#define FIOASYNC	0x5452 +#define TIOCSERCONFIG	0x5453 +#define TIOCSERGWILD	0x5454 +#define TIOCSERSWILD	0x5455 +#define TIOCGLCKTRMIOS	0x5456 +#define TIOCSLCKTRMIOS	0x5457 +#define TIOCSERGSTRUCT	0x5458 +#define TIOCSERGETLSR   0x5459 +#define TIOCSERGETMULTI 0x545A +#define TIOCSERSETMULTI 0x545B + +#define TIOCMIWAIT	0x545C +#define TIOCGICOUNT	0x545D +#define TIOCGHAYESESP   0x545E +#define TIOCSHAYESESP   0x545F +#define FIOQSIZE	0x5460 + +#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 + +#define TIOCSER_TEMT    0x01 + +struct winsize { +	unsigned short ws_row; +	unsigned short ws_col; +	unsigned short ws_xpixel; +	unsigned short ws_ypixel; +}; + +#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 +#define TIOCM_OUT1      0x2000 +#define TIOCM_OUT2      0x4000 +#define TIOCM_LOOP      0x8000 +#define TIOCM_MODEM_BITS TIOCM_OUT2 + +#define N_TTY           0 +#define N_SLIP          1 +#define N_MOUSE         2 +#define N_PPP           3 +#define N_STRIP         4 +#define N_AX25          5 +#define N_X25           6 +#define N_6PACK         7 +#define N_MASC          8 +#define N_R3964         9 +#define N_PROFIBUS_FDL  10 +#define N_IRDA          11 +#define N_SMSBLOCK      12 +#define N_HDLC          13 +#define N_SYNC_PPP      14 +#define N_HCI           15 + +#define SIOCADDRT       0x890B +#define SIOCDELRT       0x890C +#define SIOCRTMSG       0x890D + +#define SIOCGIFNAME     0x8910 +#define SIOCSIFLINK     0x8911 +#define SIOCGIFCONF     0x8912 +#define SIOCGIFFLAGS    0x8913 +#define SIOCSIFFLAGS    0x8914 +#define SIOCGIFADDR     0x8915 +#define SIOCSIFADDR     0x8916 +#define SIOCGIFDSTADDR  0x8917 +#define SIOCSIFDSTADDR  0x8918 +#define SIOCGIFBRDADDR  0x8919 +#define SIOCSIFBRDADDR  0x891a +#define SIOCGIFNETMASK  0x891b +#define SIOCSIFNETMASK  0x891c +#define SIOCGIFMETRIC   0x891d +#define SIOCSIFMETRIC   0x891e +#define SIOCGIFMEM      0x891f +#define SIOCSIFMEM      0x8920 +#define SIOCGIFMTU      0x8921 +#define SIOCSIFMTU      0x8922 +#define SIOCSIFHWADDR   0x8924 +#define SIOCGIFENCAP    0x8925 +#define SIOCSIFENCAP    0x8926 +#define SIOCGIFHWADDR   0x8927 +#define SIOCGIFSLAVE    0x8929 +#define SIOCSIFSLAVE    0x8930 +#define SIOCADDMULTI    0x8931 +#define SIOCDELMULTI    0x8932 +#define SIOCGIFINDEX    0x8933 +#define SIOGIFINDEX     SIOCGIFINDEX +#define SIOCSIFPFLAGS   0x8934 +#define SIOCGIFPFLAGS   0x8935 +#define SIOCDIFADDR     0x8936 +#define SIOCSIFHWBROADCAST 0x8937 +#define SIOCGIFCOUNT    0x8938 + +#define SIOCGIFBR       0x8940 +#define SIOCSIFBR       0x8941 + +#define SIOCGIFTXQLEN   0x8942 +#define SIOCSIFTXQLEN   0x8943 + +#define SIOCDARP        0x8953 +#define SIOCGARP        0x8954 +#define SIOCSARP        0x8955 + +#define SIOCDRARP       0x8960 +#define SIOCGRARP       0x8961 +#define SIOCSRARP       0x8962 + +#define SIOCGIFMAP      0x8970 +#define SIOCSIFMAP      0x8971 + +#define SIOCADDDLCI     0x8980 +#define SIOCDELDLCI     0x8981 diff --git a/include/bits/ipc.h b/include/bits/ipc.h new file mode 100644 index 00000000..8e3ef9b9 --- /dev/null +++ b/include/bits/ipc.h @@ -0,0 +1,22 @@ +#define IPC_CREAT  01000 +#define IPC_EXCL   02000 +#define IPC_NOWAIT 04000 + +#define IPC_RMID 0 +#define IPC_SET  1 +#define IPC_STAT 2 + +#define IPC_PRIVATE ((key_t) 0) + +struct ipc_perm +{ +	key_t key; +	uid_t uid; +	gid_t gid; +	uid_t cuid; +	gid_t cgid; +	mode_t mode; +	int seq; +	long __pad1; +	long __pad2; +}; diff --git a/include/bits/limits.h b/include/bits/limits.h new file mode 100644 index 00000000..48fdd7a1 --- /dev/null +++ b/include/bits/limits.h @@ -0,0 +1,32 @@ +#define PIPE_BUF 4096 +#define PAGESIZE 4096 +#define PAGE_SIZE PAGESIZE +#define FILESIZEBITS 64 +#define NAME_MAX 255 +#define SYMLINK_MAX 255 +#define PATH_MAX 4096 +#define NZERO 20 +#define NGROUPS_MAX 32 +#define ARG_MAX 131072 +#define IOV_MAX 1024 +#define SYMLOOP_MAX 40 + +#define WORD_BIT 32 +#define LONG_BIT 32 + +#define SHRT_MIN  (-1-0x7fff) +#define SHRT_MAX  0x7fff +#define USHRT_MAX 0xffff + +#define INT_MIN  (-1-0x7fffffff) +#define INT_MAX  0x7fffffff +#define UINT_MAX 0xffffffff + +#define LONG_MIN  (-1-0x7fffffffL) +#define LONG_MAX  0x7fffffffL +#define ULONG_MAX 0xffffffffL + +#define LLONG_MIN  (-1-0x7fffffffffffffffLL) +#define LLONG_MAX  0x7fffffffffffffffLL +#define ULLONG_MAX 0xffffffffffffffffULL + diff --git a/include/bits/mman.h b/include/bits/mman.h new file mode 100644 index 00000000..e02d488c --- /dev/null +++ b/include/bits/mman.h @@ -0,0 +1,39 @@ +#define MAP_FAILED ((void *) -1) + +#define	PROT_NONE      0 +#define	PROT_READ      1 +#define	PROT_WRITE     2 +#define	PROT_EXEC      4 + +#define	MAP_SHARED     0x01 +#define	MAP_PRIVATE    0x02 +#define	MAP_FIXED      0x10 + +/* linux extensions */ +#define MAP_TYPE       0x0f +#define MAP_FILE       0x00 +#define MAP_ANON       0x20 +#define MAP_ANONYMOUS  MAP_ANON + +#define MADV_NORMAL     0 +#define MADV_RANDOM     1 +#define MADV_SEQUENTIAL 2 +#define MADV_WILLNEED   3 +#define MADV_DONTNEED   4 + +#define POSIX_MADV_NORMAL       0 +#define POSIX_MADV_RANDOM       1 +#define POSIX_MADV_SEQUENTIAL   2 +#define POSIX_MADV_WILLNEED     3 +#define POSIX_MADV_DONTNEED     0 + +#define MS_ASYNC        1 +#define MS_INVALIDATE   2 +#define MS_SYNC         4 + +#define MCL_CURRENT     1 +#define MCL_FUTURE      2 + +/* linux extensions */ +#define MREMAP_MAYMOVE  1 +#define MREMAP_FIXED    2 diff --git a/include/bits/posix.h b/include/bits/posix.h new file mode 100644 index 00000000..30a38714 --- /dev/null +++ b/include/bits/posix.h @@ -0,0 +1,2 @@ +#define _POSIX_V6_ILP32_OFFBIG  1 +#define _POSIX_V7_ILP32_OFFBIG  1 diff --git a/include/bits/pthread.h b/include/bits/pthread.h new file mode 100644 index 00000000..7d19065d --- /dev/null +++ b/include/bits/pthread.h @@ -0,0 +1,6 @@ +struct __ptcb { +	long __jb[7]; +	int __dummy; +	struct __ptcb *__next; +	void *__ptrs[3]; +}; diff --git a/include/bits/reg.h b/include/bits/reg.h new file mode 100644 index 00000000..8bc2582d --- /dev/null +++ b/include/bits/reg.h @@ -0,0 +1,19 @@ +#undef __WORDSIZE +#define __WORDSIZE 32 +#define EBX 0 +#define ECX 1 +#define EDX 2 +#define ESI 3 +#define EDI 4 +#define EBP 5 +#define EAX 6 +#define DS 7 +#define ES 8 +#define FS 9 +#define GS 10 +#define ORIG_EAX 11 +#define EIP 12 +#define CS 13 +#define EFL 14 +#define UESP 15 +#define SS 16 diff --git a/include/bits/setjmp.h b/include/bits/setjmp.h new file mode 100644 index 00000000..b6595bd2 --- /dev/null +++ b/include/bits/setjmp.h @@ -0,0 +1 @@ +typedef unsigned long jmp_buf [7]; diff --git a/include/bits/shm.h b/include/bits/shm.h new file mode 100644 index 00000000..46774237 --- /dev/null +++ b/include/bits/shm.h @@ -0,0 +1,18 @@ +#define SHMLBA 4096 + +#define SHM_RDONLY 010000 +#define SHM_RND    020000 + +struct shmid_ds +{ +	struct ipc_perm shm_perm; +	size_t shm_segsz; +	time_t shm_atime; +	time_t shm_dtime; +	time_t shm_ctime; +	pid_t shm_cpid; +	pid_t shm_lpid; +	unsigned long shm_nattch; +	unsigned long __pad1; +	unsigned long __pad2; +}; diff --git a/include/bits/signal.h b/include/bits/signal.h new file mode 100644 index 00000000..2427f37a --- /dev/null +++ b/include/bits/signal.h @@ -0,0 +1,98 @@ +struct __siginfo +{ +	int si_signo; +	int si_errno; +	int si_code; +	union +	{ +		char __pad[128 - 3*sizeof(int)]; +		struct { +			pid_t si_pid; +			uid_t si_uid; +			union sigval si_sigval; +		} __rt; +		struct { +			unsigned int si_timer1; +			unsigned int si_timer2; +		} __timer; +		struct { +			pid_t si_pid; +			uid_t si_uid; +			int si_status; +			clock_t si_utime; +			clock_t si_stime; +		} __sigchld; +		struct { +			void *si_addr; +		} __sigfault; +		struct { +			long int si_band; +			int si_fd; +		} __sigpoll; +	} __si_fields; +}; + +#define si_pid     __si_fields.__sigchld.si_pid +#define si_uid     __si_fields.__sigchld.si_uid +#define si_status  __si_fields.__sigchld.si_status +#define si_utime   __si_fields.__sigchld.si_utime +#define si_stime   __si_fields.__sigchld.si_stime +#define si_value   __si_fields.__rt.si_sigval +#define si_addr    __si_fields.__sigfault.si_addr +#define si_band    __si_fields.__sigpoll.si_band + +#define SA_NOCLDSTOP  1 +#define SA_NOCLDWAIT  2 +#define SA_SIGINFO    4 +#define SA_ONSTACK    0x08000000 +#define SA_RESTART    0x10000000 +#define SA_NODEFER    0x40000000 +#define SA_RESETHAND  0x80000000 + +#define SS_ONSTACK    1 +#define SS_DISABLE    2 + +#define SIG_BLOCK     0 +#define SIG_UNBLOCK   1 +#define SIG_SETMASK   2 + +#define SIG_ERR  ((void (*)(int))-1) +#define SIG_DFL  ((void (*)(int)) 0) +#define SIG_IGN  ((void (*)(int)) 1) +#define SIG_HOLD ((void (*)(int)) 2) + +#define NSIG      64 + +#define SIGHUP    1 +#define SIGINT    2 +#define SIGQUIT   3 +#define SIGILL    4 +#define SIGTRAP   5 +#define SIGABRT   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   29 +#define SIGPWR    30 +#define SIGSYS    31 +#define SIGUNUSED SIGSYS diff --git a/include/bits/socket.h b/include/bits/socket.h new file mode 100644 index 00000000..7a51f792 --- /dev/null +++ b/include/bits/socket.h @@ -0,0 +1,189 @@ +struct iovec; + +struct msghdr +{ +	void *msg_name; +	socklen_t msg_namelen; +	struct iovec *msg_iov; +	int msg_iovlen; +	void *msg_control; +	socklen_t msg_controllen; +	int msg_flags; +}; + +struct cmsghdr +{ +	socklen_t cmsg_len; +	int cmsg_level; +	int cmsg_type; +}; + +struct ucred +{ +	pid_t pid; +	uid_t uid; +	gid_t gid; +}; + +struct linger +{ +	int l_onoff; +	int l_linger; +}; + +#define SHUT_RD 0 +#define SHUT_WD 1 +#define SHUT_RDWR 2 + +#define SOCK_STREAM    1 +#define SOCK_DGRAM     2 +#define SOCK_RAW       3 +#define SOCK_RDM       4 +#define SOCK_SEQPACKET 5 +#define SOCK_PACKET    10 + +#define AF_UNSPEC       0 +#define AF_LOCAL        1 +#define AF_UNIX         AF_LOCAL +#define AF_FILE         AF_LOCAL +#define AF_INET         2 +#define AF_AX25         3 +#define AF_IPX          4 +#define AF_APPLETALK    5 +#define AF_NETROM       6 +#define AF_BRIDGE       7 +#define AF_ATMPVC       8 +#define AF_X25          9 +#define AF_INET6        10 +#define AF_ROSE         11 +#define AF_DECnet       12 +#define AF_NETBEUI      13 +#define AF_SECURITY     14 +#define AF_KEY          15 +#define AF_NETLINK      16 +#define AF_ROUTE        AF_NETLINK +#define AF_PACKET       17 +#define AF_ASH          18 +#define AF_ECONET       19 +#define AF_ATMSVC       20 +#define AF_SNA          22 +#define AF_IRDA         23 +#define AF_PPPOX        24 +#define AF_WANPIPE      25 +#define AF_BLUETOOTH    31 + +#define PF_UNSPEC       0 +#define PF_LOCAL        1 +#define PF_UNIX         PF_LOCAL +#define PF_FILE         PF_LOCAL +#define PF_INET         2 +#define PF_AX25         3 +#define PF_IPX          4 +#define PF_APPLETALK    5 +#define PF_NETROM       6 +#define PF_BRIDGE       7 +#define PF_ATMPVC       8 +#define PF_X25          9 +#define PF_INET6        10 +#define PF_ROSE         11 +#define PF_DECnet       12 +#define PF_NETBEUI      13 +#define PF_SECURITY     14 +#define PF_KEY          15 +#define PF_NETLINK      16 +#define PF_ROUTE        PF_NETLINK +#define PF_PACKET       17 +#define PF_ASH          18 +#define PF_ECONET       19 +#define PF_ATMSVC       20 +#define PF_SNA          22 +#define PF_IRDA         23 +#define PF_PPPOX        24 +#define PF_WANPIPE      25 +#define PF_BLUETOOTH    31 + +#define SO_DEBUG        1 +#define SO_REUSEADDR    2 +#define SO_TYPE         3 +#define SO_ERROR        4 +#define SO_DONTROUTE    5 +#define SO_BROADCAST    6 +#define SO_SNDBUF       7 +#define SO_RCVBUF       8 +#define SO_KEEPALIVE    9 +#define SO_OOBINLINE    10 +#define SO_NO_CHECK     11 +#define SO_PRIORITY     12 +#define SO_LINGER       13 +#define SO_BSDCOMPAT    14 +#define SO_REUSEPORT    15 +#define SO_PASSCRED     16 +#define SO_PEERCRED     17 +#define SO_RCVLOWAT     18 +#define SO_SNDLOWAT     19 +#define SO_RCVTIMEO     20 +#define SO_SNDTIMEO     21 + +#define SO_SECURITY_AUTHENTICATION              22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT        23 +#define SO_SECURITY_ENCRYPTION_NETWORK          24 + +#define SO_BINDTODEVICE 25 + +#define SO_ATTACH_FILTER        26 +#define SO_DETACH_FILTER        27 + +#define SO_PEERNAME             28 +#define SO_TIMESTAMP            29 +#define SCM_TIMESTAMP           SO_TIMESTAMP + +#define SO_ACCEPTCONN           30 + +#define SOL_SOCKET      1 + +/* ??? */ +#define SOL_RAW         255 +#define SOL_DECNET      261 +#define SOL_X25         262 +#define SOL_PACKET      263 +#define SOL_ATM         264 +#define SOL_AAL         265 +#define SOL_IRDA        266 + +#define SOMAXCONN       128 + +#define MSG_OOB       0x0001 +#define MSG_PEEK      0x0002 +#define MSG_DONTROUTE 0x0004 +#define MSG_CTRUNC    0x0008 +#define MSG_PROXY     0x0010 +#define MSG_TRUNC     0x0020 +#define MSG_DONTWAIT  0x0040 +#define MSG_EOR       0x0080 +#define MSG_WAITALL   0x0100 +#define MSG_FIN       0x0200 +#define MSD_SYN       0x0400 +#define MSG_CONFIRM   0x0800 +#define MSG_RST       0x1000 +#define MSG_ERRQUEUE  0x2000 +#define MSG_NOSIGNAL  0x4000 +#define MSG_MORE      0x8000 + +/* Internal use only!! to make CMSG_NXTHDR definition readable by mortals */ +#define __CMSG_LEN(cmsg) (((cmsg)->cmsg_len + sizeof(long) - 1) & ~(long)(sizeof(long) - 1)) +#define __CMSG_NEXT(cmsg) ((unsigned char *)(cmsg) + __CMSG_LEN(cmsg)) +#define __MHDR_END(mhdr) ((unsigned char *)(mhdr)->msg_control + (mhdr)->msg_controllen) + +#define CMSG_DATA(cmsg) ((unsigned char *) (((struct cmsghdr *)(cmsg)) + 1)) +#define CMSG_NXTHDR(mhdr, cmsg) ((cmsg)->cmsg_len < sizeof (struct cmsghdr) ? (struct cmsghdr *)0 : \ +        (__CMSG_NEXT(cmsg) + sizeof (struct cmsghdr) >= __MHDR_END(mhdr) ? (struct cmsghdr *)0 : \ +        ((struct cmsghdr *)__CMSG_NEXT(cmsg)))) +#define CMSG_FIRSTHDR(mhdr) ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr) ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) 0) + +/* Are these valid? */ +#define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) +#define CMSG_SPACE(len) (CMSG_ALIGN (len) + CMSG_ALIGN (sizeof (struct cmsghdr))) +#define CMSG_LEN(len)   (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) + +#define SCM_RIGHTS      0x01 +#define SCM_CREDENTIALS 0x02 diff --git a/include/bits/stat.h b/include/bits/stat.h new file mode 100644 index 00000000..1ef34698 --- /dev/null +++ b/include/bits/stat.h @@ -0,0 +1,25 @@ +/* copied from kernel definition, but with padding replaced + * by the corresponding correctly-sized userspace types. */ + +struct stat +{ +	dev_t st_dev; +	int __st_dev_padding; +	long __st_ino_truncated; +	mode_t st_mode; +	nlink_t st_nlink; +	uid_t st_uid; +	gid_t st_gid; +	dev_t st_rdev; +	int __st_rdev_padding; +	off_t st_size; +	blksize_t st_blksize; +	blkcnt_t st_blocks; +	time_t st_atime; +	unsigned long __st_atime_nsec; +	time_t st_mtime; +	unsigned long __st_mtime_nsec; +	time_t st_ctime; +	unsigned long __st_ctime_nsec; +	ino_t st_ino; +}; diff --git a/include/bits/statfs.h b/include/bits/statfs.h new file mode 100644 index 00000000..9dda4400 --- /dev/null +++ b/include/bits/statfs.h @@ -0,0 +1,16 @@ +struct statvfs { +	unsigned long f_type; +	unsigned long f_bsize; +	fsblkcnt_t f_blocks; +	fsblkcnt_t f_bfree; +	fsblkcnt_t f_bavail; +	fsfilcnt_t f_files; +	fsfilcnt_t f_ffree; +	unsigned long f_fsid; +	unsigned long __unused; +	unsigned long f_namemax; +	unsigned long f_frsize; +	fsfilcnt_t f_favail; +	unsigned long f_flag; +	unsigned long __reserved[2]; +}; diff --git a/include/bits/stdint.h b/include/bits/stdint.h new file mode 100644 index 00000000..8e21a8cb --- /dev/null +++ b/include/bits/stdint.h @@ -0,0 +1,23 @@ +#define INT_FAST8_MIN   INT8_MIN +#define INT_FAST16_MIN  INT32_MIN +#define INT_FAST32_MIN  INT32_MIN +#define INT_FAST64_MIN  INT64_MIN + +#define INT_FAST8_MAX   INT8_MAX +#define INT_FAST16_MAX  INT32_MAX +#define INT_FAST32_MAX  INT32_MAX +#define INT_FAST64_MAX  INT64_MAX + +#define UINT_FAST8_MAX  UINT8_MAX +#define UINT_FAST16_MAX UINT32_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +#define INTPTR_MIN      INT32_MIN +#define INTPTR_MAX      INT32_MAX +#define UINTPTR_MAX     UINT32_MAX +#define PTRDIFF_MIN     INT32_MIN +#define PTRDIFF_MAX     INT32_MAX +#define SIG_ATOMIC_MIN  INT32_MIN +#define SIG_ATOMIC_MAX  INT32_MAX +#define SIZE_MAX        UINT32_MAX diff --git a/include/bits/stdio.h b/include/bits/stdio.h new file mode 100644 index 00000000..0afd8b40 --- /dev/null +++ b/include/bits/stdio.h @@ -0,0 +1,10 @@ +#define BUFSIZ 1024 + +#define FILENAME_MAX 4095 +#define FOPEN_MAX 1000 +#define TMP_MAX 10000 + +#define L_cuserid 20 +#define L_ctermid 20 +#define L_tmpnam 20 +#define P_tmpdir "/tmp" diff --git a/include/bits/sysmacros.h b/include/bits/sysmacros.h new file mode 100644 index 00000000..da29022d --- /dev/null +++ b/include/bits/sysmacros.h @@ -0,0 +1,7 @@ +#define major(x) (((x) >> 8) & 0xff) +#define minor(x) ((x) & 0xff) +#define makedev(x,y) (((x)<<8)|((y)&0xff)) + +//#define makedev(x,y) \ +//	((x)*0x100000001ULL)&(0xfffffffffff0) +//	((y)*0x1001 & 0xffff0ff) diff --git a/include/bits/tcp.h b/include/bits/tcp.h new file mode 100644 index 00000000..923231b2 --- /dev/null +++ b/include/bits/tcp.h @@ -0,0 +1 @@ +#define TCP_NODELAY 1 diff --git a/include/bits/termios.h b/include/bits/termios.h new file mode 100644 index 00000000..316baeb2 --- /dev/null +++ b/include/bits/termios.h @@ -0,0 +1,158 @@ +struct termios +{ +	tcflag_t c_iflag; +	tcflag_t c_oflag; +	tcflag_t c_cflag; +	tcflag_t c_lflag; +	cc_t c_line; +	cc_t c_cc[NCCS]; +	speed_t __c_ispeed; +	speed_t __c_ospeed; +}; + +#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 + +#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 + +#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 BSDLY  0020000 +#define BS0    0000000 +#define BS1    0020000 +#define FFDLY  0100000 +#define FF0    0000000 +#define FF1    0100000 + +#define VTDLY  0040000 +#define VT0    0000000 +#define VT1    0040000 + +/* ?? */ +#define XTABS  0014000 + +#define B0       0000000 +#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 B57600   0010001 +#define B115200  0010002 +#define B230400  0010003 +#define B460800  0010004 +#define B500000  0010005 +#define B576000  0010006 +#define B921600  0010007 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 + +#define CBAUD    0010017 + +#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 CRTSCTS  020000000000 + +#define ISIG   0000001 +#define ICANON 0000002 +#define ECHO   0000010 +#define ECHOE  0000020 +#define ECHOK  0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define IEXTEN 0100000 + +/* Extensions? */ +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 + +#define TCOOFF 0 +#define TCOON  1 +#define TCIOFF 2 +#define TCION  3 + +#define TCIFLUSH  0 +#define TCOFLUSH  1 +#define TCIOFLUSH 2 + +#define TCSANOW   0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 diff --git a/include/bits/uio.h b/include/bits/uio.h new file mode 100644 index 00000000..43252653 --- /dev/null +++ b/include/bits/uio.h @@ -0,0 +1,4 @@ +struct iovec { +	void *iov_base; +	size_t iov_len; +}; diff --git a/include/bits/user.h b/include/bits/user.h new file mode 100644 index 00000000..13ff027b --- /dev/null +++ b/include/bits/user.h @@ -0,0 +1,77 @@ +#undef __WORDSIZE +#define __WORDSIZE 32 + +struct user_fpregs_struct +{ +	long int cwd; +	long int swd; +	long int twd; +	long int fip; +	long int fcs; +	long int foo; +	long int fos; +	long int st_space[20]; +}; + +struct user_fpxregs_struct +{ +	unsigned short int cwd; +	unsigned short int swd; +	unsigned short int twd; +	unsigned short int fop; +	long int fip; +	long int fcs; +	long int foo; +	long int fos; +	long int mxcsr; +	long int reserved; +	long int st_space[32]; +	long int xmm_space[32]; +	long int padding[56]; +}; + +struct user_regs_struct +{ +	long int ebx; +	long int ecx; +	long int edx; +	long int esi; +	long int edi; +	long int ebp; +	long int eax; +	long int xds; +	long int xes; +	long int xfs; +	long int xgs; +	long int orig_eax; +	long int eip; +	long int xcs; +	long int eflags; +	long int esp; +	long int xss; +}; + +struct user +{ +	struct user_regs_struct		regs; +	int				u_fpvalid; +	struct user_fpregs_struct	i387; +	unsigned long int		u_tsize; +	unsigned long int		u_dsize; +	unsigned long int		u_ssize; +	unsigned long			start_code; +	unsigned long			start_stack; +	long int			signal; +	int				reserved; +	struct user_regs_struct		*u_ar0; +	struct user_fpregs_struct	*u_fpstate; +	unsigned long int		magic; +	char				u_comm[32]; +	int				u_debugreg[8]; +}; + +#define PAGE_MASK		(~(PAGE_SIZE-1)) +#define NBPG			PAGE_SIZE +#define UPAGES			1 +#define HOST_TEXT_START_ADDR	(u.start_code) +#define HOST_STACK_END_ADDR	(u.start_stack + u.u_ssize * NBPG) diff --git a/include/bits/wait.h b/include/bits/wait.h new file mode 100644 index 00000000..ca9b57e0 --- /dev/null +++ b/include/bits/wait.h @@ -0,0 +1,11 @@ +#define WNOHANG    1 +#define WUNTRACED  2 + +#define WSTOPPED   2 +#define WEXITED    4 +#define WCONTINUED 8 +#define WNOWAIT    0x1000000 + +#define P_ALL  0 +#define P_PID  1 +#define P_PGID 2 diff --git a/include/bits/wexitstatus.h b/include/bits/wexitstatus.h new file mode 100644 index 00000000..34a80238 --- /dev/null +++ b/include/bits/wexitstatus.h @@ -0,0 +1,9 @@ +#ifndef WEXITSTATUS +#define WEXITSTATUS(s) (((s) & 0xff00) >> 8) +#define WTERMSIG(s) ((s) & 0x7f) +#define WSTOPSIG(s) WEXITSTATUS(s) +#define WCOREDUMP(s) ((s) & 0x80) +#define WIFEXITED(s) (!WTERMSIG(s)) +#define WIFSTOPPED(s) (((s) & 0xff) == 0x7f) +#define WIFSIGNALED(s) (!WIFSTOPPED(s) && !WIFEXITED(s)) +#endif diff --git a/include/byteswap.h b/include/byteswap.h new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/byteswap.h diff --git a/include/cpio.h b/include/cpio.h new file mode 100644 index 00000000..39a1f8bb --- /dev/null +++ b/include/cpio.h @@ -0,0 +1,29 @@ +#ifndef _CPIO_H +#define _CPIO_H + +#define MAGIC "070707" + +#define C_IRUSR  000400 +#define C_IWUSR  000200 +#define C_IXUSR  000100 +#define C_IRGRP  000040 +#define C_IWGRP  000020 +#define C_IXGRP  000010 +#define C_IROTH  000004 +#define C_IWOTH  000002 +#define C_IXOTH  000001 + +#define C_ISUID  004000 +#define C_ISGID  002000 +#define C_ISVTX  001000 + +#define C_ISBLK  060000 +#define C_ISCHR  020000 +#define C_ISDIR  040000 +#define C_ISFIFO 010000 +#define C_ISSOCK 0140000 +#define C_ISLNK  0120000 +#define C_ISCTG  0110000 +#define C_ISREG  0100000 + +#endif diff --git a/include/ctype.h b/include/ctype.h new file mode 100644 index 00000000..02f81fa7 --- /dev/null +++ b/include/ctype.h @@ -0,0 +1,53 @@ +#ifndef	_CTYPE_H +#define	_CTYPE_H + +int   isalnum(int); +int   isalpha(int); +int   isblank(int); +int   iscntrl(int); +int   isdigit(int); +int   isgraph(int); +int   islower(int); +int   isprint(int); +int   ispunct(int); +int   isspace(int); +int   isupper(int); +int   isxdigit(int); +int   tolower(int); +int   toupper(int); + +int   isascii(int); +int   toascii(int); + +#define _tolower(a) ((a)|0x20) +#define _toupper(a) ((a)&0x5f) + +#define isalpha(a) ((unsigned)(((a)|32)-'a') < 26) +#define isdigit(a) ((unsigned)((a)-'0') < 10) +#define islower(a) ((unsigned)((a)-'a') < 26) +#define isupper(a) ((unsigned)((a)-'A') < 26) +#define isprint(a) ((unsigned)((a)-0x20) < 0x5f) +#define isgraph(a) ((unsigned)((a)-0x21) < 0x5e) + +#if 1 + +#define __NEED_locale_t +#include <bits/alltypes.h> + +int   isalnum_l(int, locale_t); +int   isalpha_l(int, locale_t); +int   isblank_l(int, locale_t); +int   iscntrl_l(int, locale_t); +int   isdigit_l(int, locale_t); +int   isgraph_l(int, locale_t); +int   islower_l(int, locale_t); +int   isprint_l(int, locale_t); +int   ispunct_l(int, locale_t); +int   isspace_l(int, locale_t); +int   isupper_l(int, locale_t); +int   isxdigit_l(int, locale_t); +int   tolower_l(int, locale_t); +int   toupper_l(int, locale_t); +#endif + +#endif diff --git a/include/dirent.h b/include/dirent.h new file mode 100644 index 00000000..a9170936 --- /dev/null +++ b/include/dirent.h @@ -0,0 +1,41 @@ +#ifndef	_DIRENT_H +#define	_DIRENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_ino_t +#define __NEED_off_t + +#include <bits/alltypes.h> + +typedef struct __DIR_s DIR; + +struct dirent +{ +	ino_t d_ino; +	off_t d_off; +	unsigned short d_reclen; +	unsigned char d_type; +	char d_name[1]; +}; + +int            closedir(DIR *); +DIR           *fdopendir(int); +DIR           *opendir(const char *); +struct dirent *readdir(DIR *); +int            readdir_r(DIR *, struct dirent *, struct dirent **); +void           rewinddir(DIR *); +void           seekdir(DIR *, long); +long           telldir(DIR *); +int            dirfd(DIR *); + +int alphasort(const struct dirent **, const struct dirent **); +int scandir(const char *, struct dirent ***, int (*)(const struct dirent *), int (*)(const struct dirent **, const struct dirent **)); + +#ifdef __cplusplus +extern } +#endif + +#endif diff --git a/include/dlfcn.h b/include/dlfcn.h new file mode 100644 index 00000000..81b829c8 --- /dev/null +++ b/include/dlfcn.h @@ -0,0 +1,19 @@ +#ifndef	_DLFCN_H +#define	_DLFCN_H + +#define RTLD_LAZY   0x10000 +#define RTLD_NOW    0x20000 +#define RTLD_GLOBAL 0x40000 +#define RTLD_LOCAL  0x80000 + +#if 1 +#define RTLD_NEXT    ((void *) -1l) +#define RTLD_DEFAULT ((void *) 0) +#endif + +int    dlclose(void *); +char  *dlerror(void); +void  *dlopen(const char *, int); +void  *dlsym(void *, const char *); + +#endif diff --git a/include/elf.h b/include/elf.h new file mode 100644 index 00000000..b011e784 --- /dev/null +++ b/include/elf.h @@ -0,0 +1,2524 @@ +#ifndef _ELF_H +#define	_ELF_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +typedef uint32_t Elf32_Word; +typedef	int32_t  Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef	int32_t  Elf64_Sword; + +typedef uint64_t Elf32_Xword; +typedef	int64_t  Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef	int64_t  Elf64_Sxword; + +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + +#define EI_NIDENT (16) + +typedef struct { +  unsigned char	e_ident[EI_NIDENT]; +  Elf32_Half	e_type; +  Elf32_Half	e_machine; +  Elf32_Word	e_version; +  Elf32_Addr	e_entry; +  Elf32_Off	e_phoff; +  Elf32_Off	e_shoff; +  Elf32_Word	e_flags; +  Elf32_Half	e_ehsize; +  Elf32_Half	e_phentsize; +  Elf32_Half	e_phnum; +  Elf32_Half	e_shentsize; +  Elf32_Half	e_shnum; +  Elf32_Half	e_shstrndx; +} Elf32_Ehdr; + +typedef struct { +  unsigned char	e_ident[EI_NIDENT]; +  Elf64_Half	e_type; +  Elf64_Half	e_machine; +  Elf64_Word	e_version; +  Elf64_Addr	e_entry; +  Elf64_Off	e_phoff; +  Elf64_Off	e_shoff; +  Elf64_Word	e_flags; +  Elf64_Half	e_ehsize; +  Elf64_Half	e_phentsize; +  Elf64_Half	e_phnum; +  Elf64_Half	e_shentsize; +  Elf64_Half	e_shnum; +  Elf64_Half	e_shstrndx; +} Elf64_Ehdr; + +#define EI_MAG0		0 +#define ELFMAG0		0x7f + +#define EI_MAG1		1 +#define ELFMAG1		'E' + +#define EI_MAG2		2 +#define ELFMAG2		'L' + +#define EI_MAG3		3 +#define ELFMAG3		'F' + + +#define	ELFMAG		"\177ELF" +#define	SELFMAG		4 + +#define EI_CLASS	4 +#define ELFCLASSNONE	0 +#define ELFCLASS32	1 +#define ELFCLASS64	2 +#define ELFCLASSNUM	3 + +#define EI_DATA		5 +#define ELFDATANONE	0 +#define ELFDATA2LSB	1 +#define ELFDATA2MSB	2 +#define ELFDATANUM	3 + +#define EI_VERSION	6 + + +#define EI_OSABI	7 +#define ELFOSABI_NONE		0 +#define ELFOSABI_SYSV		0 +#define ELFOSABI_HPUX		1 +#define ELFOSABI_NETBSD		2 +#define ELFOSABI_LINUX		3 +#define ELFOSABI_SOLARIS	6 +#define ELFOSABI_AIX		7 +#define ELFOSABI_IRIX		8 +#define ELFOSABI_FREEBSD	9 +#define ELFOSABI_TRU64		10 +#define ELFOSABI_MODESTO	11 +#define ELFOSABI_OPENBSD	12 +#define ELFOSABI_ARM		97 +#define ELFOSABI_STANDALONE	255 + +#define EI_ABIVERSION	8 + +#define EI_PAD		9 + + + +#define ET_NONE		0 +#define ET_REL		1 +#define ET_EXEC		2 +#define ET_DYN		3 +#define ET_CORE		4 +#define	ET_NUM		5 +#define ET_LOOS		0xfe00 +#define ET_HIOS		0xfeff +#define ET_LOPROC	0xff00 +#define ET_HIPROC	0xffff + + + +#define EM_NONE		 0 +#define EM_M32		 1 +#define EM_SPARC	 2 +#define EM_386		 3 +#define EM_68K		 4 +#define EM_88K		 5 +#define EM_860		 7 +#define EM_MIPS		 8 +#define EM_S370		 9 +#define EM_MIPS_RS3_LE	10 + +#define EM_PARISC	15 +#define EM_VPP500	17 +#define EM_SPARC32PLUS	18 +#define EM_960		19 +#define EM_PPC		20 +#define EM_PPC64	21 +#define EM_S390		22 + +#define EM_V800		36 +#define EM_FR20		37 +#define EM_RH32		38 +#define EM_RCE		39 +#define EM_ARM		40 +#define EM_FAKE_ALPHA	41 +#define EM_SH		42 +#define EM_SPARCV9	43 +#define EM_TRICORE	44 +#define EM_ARC		45 +#define EM_H8_300	46 +#define EM_H8_300H	47 +#define EM_H8S		48 +#define EM_H8_500	49 +#define EM_IA_64	50 +#define EM_MIPS_X	51 +#define EM_COLDFIRE	52 +#define EM_68HC12	53 +#define EM_MMA		54 +#define EM_PCP		55 +#define EM_NCPU		56 +#define EM_NDR1		57 +#define EM_STARCORE	58 +#define EM_ME16		59 +#define EM_ST100	60 +#define EM_TINYJ	61 +#define EM_X86_64	62 +#define EM_PDSP		63 + +#define EM_FX66		66 +#define EM_ST9PLUS	67 +#define EM_ST7		68 +#define EM_68HC16	69 +#define EM_68HC11	70 +#define EM_68HC08	71 +#define EM_68HC05	72 +#define EM_SVX		73 +#define EM_ST19		74 +#define EM_VAX		75 +#define EM_CRIS		76 +#define EM_JAVELIN	77 +#define EM_FIREPATH	78 +#define EM_ZSP		79 +#define EM_MMIX		80 +#define EM_HUANY	81 +#define EM_PRISM	82 +#define EM_AVR		83 +#define EM_FR30		84 +#define EM_D10V		85 +#define EM_D30V		86 +#define EM_V850		87 +#define EM_M32R		88 +#define EM_MN10300	89 +#define EM_MN10200	90 +#define EM_PJ		91 +#define EM_OPENRISC	92 +#define EM_ARC_A5	93 +#define EM_XTENSA	94 +#define EM_NUM		95 +#define EM_ALPHA	0x9026 + +#define EV_NONE		0 +#define EV_CURRENT	1 +#define EV_NUM		2 + +typedef struct { +  Elf32_Word	sh_name; +  Elf32_Word	sh_type; +  Elf32_Word	sh_flags; +  Elf32_Addr	sh_addr; +  Elf32_Off	sh_offset; +  Elf32_Word	sh_size; +  Elf32_Word	sh_link; +  Elf32_Word	sh_info; +  Elf32_Word	sh_addralign; +  Elf32_Word	sh_entsize; +} Elf32_Shdr; + +typedef struct { +  Elf64_Word	sh_name; +  Elf64_Word	sh_type; +  Elf64_Xword	sh_flags; +  Elf64_Addr	sh_addr; +  Elf64_Off	sh_offset; +  Elf64_Xword	sh_size; +  Elf64_Word	sh_link; +  Elf64_Word	sh_info; +  Elf64_Xword	sh_addralign; +  Elf64_Xword	sh_entsize; +} Elf64_Shdr; + + + +#define SHN_UNDEF	0 +#define SHN_LORESERVE	0xff00 +#define SHN_LOPROC	0xff00 +#define SHN_BEFORE	0xff00 + +#define SHN_AFTER	0xff01 + +#define SHN_HIPROC	0xff1f +#define SHN_LOOS	0xff20 +#define SHN_HIOS	0xff3f +#define SHN_ABS		0xfff1 +#define SHN_COMMON	0xfff2 +#define SHN_XINDEX	0xffff +#define SHN_HIRESERVE	0xffff + + + +#define SHT_NULL	  0 +#define SHT_PROGBITS	  1 +#define SHT_SYMTAB	  2 +#define SHT_STRTAB	  3 +#define SHT_RELA	  4 +#define SHT_HASH	  5 +#define SHT_DYNAMIC	  6 +#define SHT_NOTE	  7 +#define SHT_NOBITS	  8 +#define SHT_REL		  9 +#define SHT_SHLIB	  10 +#define SHT_DYNSYM	  11 +#define SHT_INIT_ARRAY	  14 +#define SHT_FINI_ARRAY	  15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP	  17 +#define SHT_SYMTAB_SHNDX  18 +#define	SHT_NUM		  19 +#define SHT_LOOS	  0x60000000 +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 +#define SHT_GNU_HASH	  0x6ffffff6 +#define SHT_GNU_LIBLIST	  0x6ffffff7 +#define SHT_CHECKSUM	  0x6ffffff8 +#define SHT_LOSUNW	  0x6ffffffa +#define SHT_SUNW_move	  0x6ffffffa +#define SHT_SUNW_COMDAT   0x6ffffffb +#define SHT_SUNW_syminfo  0x6ffffffc +#define SHT_GNU_verdef	  0x6ffffffd +#define SHT_GNU_verneed	  0x6ffffffe +#define SHT_GNU_versym	  0x6fffffff +#define SHT_HISUNW	  0x6fffffff +#define SHT_HIOS	  0x6fffffff +#define SHT_LOPROC	  0x70000000 +#define SHT_HIPROC	  0x7fffffff +#define SHT_LOUSER	  0x80000000 +#define SHT_HIUSER	  0x8fffffff + +#define SHF_WRITE	     (1 << 0) +#define SHF_ALLOC	     (1 << 1) +#define SHF_EXECINSTR	     (1 << 2) +#define SHF_MERGE	     (1 << 4) +#define SHF_STRINGS	     (1 << 5) +#define SHF_INFO_LINK	     (1 << 6) +#define SHF_LINK_ORDER	     (1 << 7) +#define SHF_OS_NONCONFORMING (1 << 8) + +#define SHF_GROUP	     (1 << 9) +#define SHF_TLS		     (1 << 10) +#define SHF_MASKOS	     0x0ff00000 +#define SHF_MASKPROC	     0xf0000000 +#define SHF_ORDERED	     (1 << 30) +#define SHF_EXCLUDE	     (1 << 31) + +#define GRP_COMDAT	0x1 + +typedef struct { +  Elf32_Word	st_name; +  Elf32_Addr	st_value; +  Elf32_Word	st_size; +  unsigned char	st_info; +  unsigned char	st_other; +  Elf32_Section	st_shndx; +} Elf32_Sym; + +typedef struct { +  Elf64_Word	st_name; +  unsigned char	st_info; +  unsigned char st_other; +  Elf64_Section	st_shndx; +  Elf64_Addr	st_value; +  Elf64_Xword	st_size; +} Elf64_Sym; + +typedef struct { +  Elf32_Half si_boundto; +  Elf32_Half si_flags; +} Elf32_Syminfo; + +typedef struct { +  Elf64_Half si_boundto; +  Elf64_Half si_flags; +} Elf64_Syminfo; + +#define SYMINFO_BT_SELF		0xffff +#define SYMINFO_BT_PARENT	0xfffe +#define SYMINFO_BT_LOWRESERVE	0xff00 + +#define SYMINFO_FLG_DIRECT	0x0001 +#define SYMINFO_FLG_PASSTHRU	0x0002 +#define SYMINFO_FLG_COPY	0x0004 +#define SYMINFO_FLG_LAZYLOAD	0x0008 + +#define SYMINFO_NONE		0 +#define SYMINFO_CURRENT		1 +#define SYMINFO_NUM		2 + +#define ELF32_ST_BIND(val)		(((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val)		((val) & 0xf) +#define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf)) + +#define ELF64_ST_BIND(val)		ELF32_ST_BIND (val) +#define ELF64_ST_TYPE(val)		ELF32_ST_TYPE (val) +#define ELF64_ST_INFO(bind, type)	ELF32_ST_INFO ((bind), (type)) + +#define STB_LOCAL	0 +#define STB_GLOBAL	1 +#define STB_WEAK	2 +#define	STB_NUM		3 +#define STB_LOOS	10 +#define STB_GNU_UNIQUE	10 +#define STB_HIOS	12 +#define STB_LOPROC	13 +#define STB_HIPROC	15 + +#define STT_NOTYPE	0 +#define STT_OBJECT	1 +#define STT_FUNC	2 +#define STT_SECTION	3 +#define STT_FILE	4 +#define STT_COMMON	5 +#define STT_TLS		6 +#define	STT_NUM		7 +#define STT_LOOS	10 +#define STT_GNU_IFUNC	10 +#define STT_HIOS	12 +#define STT_LOPROC	13 +#define STT_HIPROC	15 + +#define STN_UNDEF	0 + +#define ELF32_ST_VISIBILITY(o)	((o) & 0x03) +#define ELF64_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY (o) + +#define STV_DEFAULT	0 +#define STV_INTERNAL	1 +#define STV_HIDDEN	2 +#define STV_PROTECTED	3 + + + + +typedef struct +{ +  Elf32_Addr	r_offset; +  Elf32_Word	r_info; +} Elf32_Rel; + +typedef struct { +  Elf64_Addr	r_offset; +  Elf64_Xword	r_info; +} Elf64_Rel; + + + +typedef struct { +  Elf32_Addr	r_offset; +  Elf32_Word	r_info; +  Elf32_Sword	r_addend; +} Elf32_Rela; + +typedef struct { +  Elf64_Addr	r_offset; +  Elf64_Xword	r_info; +  Elf64_Sxword	r_addend; +} Elf64_Rela; + + + +#define ELF32_R_SYM(val)		((val) >> 8) +#define ELF32_R_TYPE(val)		((val) & 0xff) +#define ELF32_R_INFO(sym, type)		(((sym) << 8) + ((type) & 0xff)) + +#define ELF64_R_SYM(i)			((i) >> 32) +#define ELF64_R_TYPE(i)			((i) & 0xffffffff) +#define ELF64_R_INFO(sym,type)		((((Elf64_Xword) (sym)) << 32) + (type)) + + + +typedef struct { +  Elf32_Word	p_type; +  Elf32_Off	p_offset; +  Elf32_Addr	p_vaddr; +  Elf32_Addr	p_paddr; +  Elf32_Word	p_filesz; +  Elf32_Word	p_memsz; +  Elf32_Word	p_flags; +  Elf32_Word	p_align; +} Elf32_Phdr; + +typedef struct { +  Elf64_Word	p_type; +  Elf64_Word	p_flags; +  Elf64_Off	p_offset; +  Elf64_Addr	p_vaddr; +  Elf64_Addr	p_paddr; +  Elf64_Xword	p_filesz; +  Elf64_Xword	p_memsz; +  Elf64_Xword	p_align; +} Elf64_Phdr; + + + +#define	PT_NULL		0 +#define PT_LOAD		1 +#define PT_DYNAMIC	2 +#define PT_INTERP	3 +#define PT_NOTE		4 +#define PT_SHLIB	5 +#define PT_PHDR		6 +#define PT_TLS		7 +#define	PT_NUM		8 +#define PT_LOOS		0x60000000 +#define PT_GNU_EH_FRAME	0x6474e550 +#define PT_GNU_STACK	0x6474e551 +#define PT_GNU_RELRO	0x6474e552 +#define PT_LOSUNW	0x6ffffffa +#define PT_SUNWBSS	0x6ffffffa +#define PT_SUNWSTACK	0x6ffffffb +#define PT_HISUNW	0x6fffffff +#define PT_HIOS		0x6fffffff +#define PT_LOPROC	0x70000000 +#define PT_HIPROC	0x7fffffff + + + +#define PF_X		(1 << 0) +#define PF_W		(1 << 1) +#define PF_R		(1 << 2) +#define PF_MASKOS	0x0ff00000 +#define PF_MASKPROC	0xf0000000 + + + +#define NT_PRSTATUS	1 +#define NT_FPREGSET	2 +#define NT_PRPSINFO	3 +#define NT_PRXREG	4 +#define NT_TASKSTRUCT	4 +#define NT_PLATFORM	5 +#define NT_AUXV		6 +#define NT_GWINDOWS	7 +#define NT_ASRS		8 +#define NT_PSTATUS	10 +#define NT_PSINFO	13 +#define NT_PRCRED	14 +#define NT_UTSNAME	15 +#define NT_LWPSTATUS	16 +#define NT_LWPSINFO	17 +#define NT_PRFPXREG	20 +#define NT_PRXFPREG	0x46e62b7f +#define NT_PPC_VMX	0x100 +#define NT_PPC_SPE	0x101 +#define NT_PPC_VSX	0x102 +#define NT_386_TLS	0x200 +#define NT_386_IOPERM	0x201 +#define NT_VERSION	1 + + + + +typedef struct { +  Elf32_Sword d_tag; +  union { +      Elf32_Word d_val; +      Elf32_Addr d_ptr; +  } d_un; +} Elf32_Dyn; + +typedef struct { +  Elf64_Sxword d_tag; +  union { +      Elf64_Xword d_val; +      Elf64_Addr d_ptr; +  } d_un; +} Elf64_Dyn; + + + +#define DT_NULL		0 +#define DT_NEEDED	1 +#define DT_PLTRELSZ	2 +#define DT_PLTGOT	3 +#define DT_HASH		4 +#define DT_STRTAB	5 +#define DT_SYMTAB	6 +#define DT_RELA		7 +#define DT_RELASZ	8 +#define DT_RELAENT	9 +#define DT_STRSZ	10 +#define DT_SYMENT	11 +#define DT_INIT		12 +#define DT_FINI		13 +#define DT_SONAME	14 +#define DT_RPATH	15 +#define DT_SYMBOLIC	16 +#define DT_REL		17 +#define DT_RELSZ	18 +#define DT_RELENT	19 +#define DT_PLTREL	20 +#define DT_DEBUG	21 +#define DT_TEXTREL	22 +#define DT_JMPREL	23 +#define	DT_BIND_NOW	24 +#define	DT_INIT_ARRAY	25 +#define	DT_FINI_ARRAY	26 +#define	DT_INIT_ARRAYSZ	27 +#define	DT_FINI_ARRAYSZ	28 +#define DT_RUNPATH	29 +#define DT_FLAGS	30 +#define DT_ENCODING	32 +#define DT_PREINIT_ARRAY 32 +#define DT_PREINIT_ARRAYSZ 33 +#define	DT_NUM		34 +#define DT_LOOS		0x6000000d +#define DT_HIOS		0x6ffff000 +#define DT_LOPROC	0x70000000 +#define DT_HIPROC	0x7fffffff +#define	DT_PROCNUM	DT_MIPS_NUM + +#define DT_VALRNGLO	0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 +#define DT_CHECKSUM	0x6ffffdf8 +#define DT_PLTPADSZ	0x6ffffdf9 +#define DT_MOVEENT	0x6ffffdfa +#define DT_MOVESZ	0x6ffffdfb +#define DT_FEATURE_1	0x6ffffdfc +#define DT_POSFLAG_1	0x6ffffdfd + +#define DT_SYMINSZ	0x6ffffdfe +#define DT_SYMINENT	0x6ffffdff +#define DT_VALRNGHI	0x6ffffdff +#define DT_VALTAGIDX(tag)	(DT_VALRNGHI - (tag)) +#define DT_VALNUM 12 + +#define DT_ADDRRNGLO	0x6ffffe00 +#define DT_GNU_HASH	0x6ffffef5 +#define DT_TLSDESC_PLT	0x6ffffef6 +#define DT_TLSDESC_GOT	0x6ffffef7 +#define DT_GNU_CONFLICT	0x6ffffef8 +#define DT_GNU_LIBLIST	0x6ffffef9 +#define DT_CONFIG	0x6ffffefa +#define DT_DEPAUDIT	0x6ffffefb +#define DT_AUDIT	0x6ffffefc +#define	DT_PLTPAD	0x6ffffefd +#define	DT_MOVETAB	0x6ffffefe +#define DT_SYMINFO	0x6ffffeff +#define DT_ADDRRNGHI	0x6ffffeff +#define DT_ADDRTAGIDX(tag)	(DT_ADDRRNGHI - (tag)) +#define DT_ADDRNUM 11 + + + +#define DT_VERSYM	0x6ffffff0 + +#define DT_RELACOUNT	0x6ffffff9 +#define DT_RELCOUNT	0x6ffffffa + + +#define DT_FLAGS_1	0x6ffffffb +#define	DT_VERDEF	0x6ffffffc + +#define	DT_VERDEFNUM	0x6ffffffd +#define	DT_VERNEED	0x6ffffffe + +#define	DT_VERNEEDNUM	0x6fffffff +#define DT_VERSIONTAGIDX(tag)	(DT_VERNEEDNUM - (tag)) +#define DT_VERSIONTAGNUM 16 + + + +#define DT_AUXILIARY    0x7ffffffd +#define DT_FILTER       0x7fffffff +#define DT_EXTRATAGIDX(tag)	((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) +#define DT_EXTRANUM	3 + + +#define DF_ORIGIN	0x00000001 +#define DF_SYMBOLIC	0x00000002 +#define DF_TEXTREL	0x00000004 +#define DF_BIND_NOW	0x00000008 +#define DF_STATIC_TLS	0x00000010 + + + +#define DF_1_NOW	0x00000001 +#define DF_1_GLOBAL	0x00000002 +#define DF_1_GROUP	0x00000004 +#define DF_1_NODELETE	0x00000008 +#define DF_1_LOADFLTR	0x00000010 +#define DF_1_INITFIRST	0x00000020 +#define DF_1_NOOPEN	0x00000040 +#define DF_1_ORIGIN	0x00000080 +#define DF_1_DIRECT	0x00000100 +#define DF_1_TRANS	0x00000200 +#define DF_1_INTERPOSE	0x00000400 +#define DF_1_NODEFLIB	0x00000800 +#define DF_1_NODUMP	0x00001000 +#define DF_1_CONFALT	0x00002000 +#define DF_1_ENDFILTEE	0x00004000 +#define	DF_1_DISPRELDNE	0x00008000 +#define	DF_1_DISPRELPND	0x00010000 + + +#define DTF_1_PARINIT	0x00000001 +#define DTF_1_CONFEXP	0x00000002 + + +#define DF_P1_LAZYLOAD	0x00000001 +#define DF_P1_GROUPPERM	0x00000002 + + + + +typedef struct { +  Elf32_Half	vd_version; +  Elf32_Half	vd_flags; +  Elf32_Half	vd_ndx; +  Elf32_Half	vd_cnt; +  Elf32_Word	vd_hash; +  Elf32_Word	vd_aux; +  Elf32_Word	vd_next; +} Elf32_Verdef; + +typedef struct { +  Elf64_Half	vd_version; +  Elf64_Half	vd_flags; +  Elf64_Half	vd_ndx; +  Elf64_Half	vd_cnt; +  Elf64_Word	vd_hash; +  Elf64_Word	vd_aux; +  Elf64_Word	vd_next; +} Elf64_Verdef; + + + +#define VER_DEF_NONE	0 +#define VER_DEF_CURRENT	1 +#define VER_DEF_NUM	2 + + +#define VER_FLG_BASE	0x1 +#define VER_FLG_WEAK	0x2 + + +#define	VER_NDX_LOCAL		0 +#define	VER_NDX_GLOBAL		1 +#define	VER_NDX_LORESERVE	0xff00 +#define	VER_NDX_ELIMINATE	0xff01 + + + +typedef struct { +  Elf32_Word	vda_name; +  Elf32_Word	vda_next; +} Elf32_Verdaux; + +typedef struct { +  Elf64_Word	vda_name; +  Elf64_Word	vda_next; +} Elf64_Verdaux; + + + + +typedef struct { +  Elf32_Half	vn_version; +  Elf32_Half	vn_cnt; +  Elf32_Word	vn_file; +  Elf32_Word	vn_aux; +  Elf32_Word	vn_next; +} Elf32_Verneed; + +typedef struct { +  Elf64_Half	vn_version; +  Elf64_Half	vn_cnt; +  Elf64_Word	vn_file; +  Elf64_Word	vn_aux; +  Elf64_Word	vn_next; +} Elf64_Verneed; + + + +#define VER_NEED_NONE	 0 +#define VER_NEED_CURRENT 1 +#define VER_NEED_NUM	 2 + + + +typedef struct { +  Elf32_Word	vna_hash; +  Elf32_Half	vna_flags; +  Elf32_Half	vna_other; +  Elf32_Word	vna_name; +  Elf32_Word	vna_next; +} Elf32_Vernaux; + +typedef struct { +  Elf64_Word	vna_hash; +  Elf64_Half	vna_flags; +  Elf64_Half	vna_other; +  Elf64_Word	vna_name; +  Elf64_Word	vna_next; +} Elf64_Vernaux; + + + +#define VER_FLG_WEAK	0x2 + + + +typedef struct { +  uint32_t a_type; +  union { +      uint32_t a_val; +  } a_un; +} Elf32_auxv_t; + +typedef struct { +  uint64_t a_type; +  union { +      uint64_t a_val; +  } a_un; +} Elf64_auxv_t; + + + +#define AT_NULL		0 +#define AT_IGNORE	1 +#define AT_EXECFD	2 +#define AT_PHDR		3 +#define AT_PHENT	4 +#define AT_PHNUM	5 +#define AT_PAGESZ	6 +#define AT_BASE		7 +#define AT_FLAGS	8 +#define AT_ENTRY	9 +#define AT_NOTELF	10 +#define AT_UID		11 +#define AT_EUID		12 +#define AT_GID		13 +#define AT_EGID		14 +#define AT_CLKTCK	17 + + +#define AT_PLATFORM	15 +#define AT_HWCAP	16 + + + + +#define AT_FPUCW	18 + + +#define AT_DCACHEBSIZE	19 +#define AT_ICACHEBSIZE	20 +#define AT_UCACHEBSIZE	21 + + + +#define AT_IGNOREPPC	22 + +#define	AT_SECURE	23 + +#define AT_BASE_PLATFORM 24 + +#define AT_RANDOM	25 + +#define AT_EXECFN	31 + + + +#define AT_SYSINFO	32 +#define AT_SYSINFO_EHDR	33 + + + +#define AT_L1I_CACHESHAPE	34 +#define AT_L1D_CACHESHAPE	35 +#define AT_L2_CACHESHAPE	36 +#define AT_L3_CACHESHAPE	37 + + + + +typedef struct { +  Elf32_Word n_namesz; +  Elf32_Word n_descsz; +  Elf32_Word n_type; +} Elf32_Nhdr; + +typedef struct { +  Elf64_Word n_namesz; +  Elf64_Word n_descsz; +  Elf64_Word n_type; +} Elf64_Nhdr; + + + + +#define ELF_NOTE_SOLARIS	"SUNW Solaris" + + +#define ELF_NOTE_GNU		"GNU" + + + + + +#define ELF_NOTE_PAGESIZE_HINT	1 + + +#define NT_GNU_ABI_TAG	1 +#define ELF_NOTE_ABI	NT_GNU_ABI_TAG + + + +#define ELF_NOTE_OS_LINUX	0 +#define ELF_NOTE_OS_GNU		1 +#define ELF_NOTE_OS_SOLARIS2	2 +#define ELF_NOTE_OS_FREEBSD	3 + +#define NT_GNU_BUILD_ID	3 +#define NT_GNU_GOLD_VERSION	4 + + + +typedef struct { +  Elf32_Xword m_value; +  Elf32_Word m_info; +  Elf32_Word m_poffset; +  Elf32_Half m_repeat; +  Elf32_Half m_stride; +} Elf32_Move; + +typedef struct { +  Elf64_Xword m_value; +  Elf64_Xword m_info; +  Elf64_Xword m_poffset; +  Elf64_Half m_repeat; +  Elf64_Half m_stride; +} Elf64_Move; + + +#define ELF32_M_SYM(info)	((info) >> 8) +#define ELF32_M_SIZE(info)	((unsigned char) (info)) +#define ELF32_M_INFO(sym, size)	(((sym) << 8) + (unsigned char) (size)) + +#define ELF64_M_SYM(info)	ELF32_M_SYM (info) +#define ELF64_M_SIZE(info)	ELF32_M_SIZE (info) +#define ELF64_M_INFO(sym, size)	ELF32_M_INFO (sym, size) + +#define EF_CPU32	0x00810000 + +#define R_68K_NONE	0 +#define R_68K_32	1 +#define R_68K_16	2 +#define R_68K_8		3 +#define R_68K_PC32	4 +#define R_68K_PC16	5 +#define R_68K_PC8	6 +#define R_68K_GOT32	7 +#define R_68K_GOT16	8 +#define R_68K_GOT8	9 +#define R_68K_GOT32O	10 +#define R_68K_GOT16O	11 +#define R_68K_GOT8O	12 +#define R_68K_PLT32	13 +#define R_68K_PLT16	14 +#define R_68K_PLT8	15 +#define R_68K_PLT32O	16 +#define R_68K_PLT16O	17 +#define R_68K_PLT8O	18 +#define R_68K_COPY	19 +#define R_68K_GLOB_DAT	20 +#define R_68K_JMP_SLOT	21 +#define R_68K_RELATIVE	22 +#define R_68K_NUM	23 + +#define R_386_NONE	   0 +#define R_386_32	   1 +#define R_386_PC32	   2 +#define R_386_GOT32	   3 +#define R_386_PLT32	   4 +#define R_386_COPY	   5 +#define R_386_GLOB_DAT	   6 +#define R_386_JMP_SLOT	   7 +#define R_386_RELATIVE	   8 +#define R_386_GOTOFF	   9 +#define R_386_GOTPC	   10 +#define R_386_32PLT	   11 +#define R_386_TLS_TPOFF	   14 +#define R_386_TLS_IE	   15 +#define R_386_TLS_GOTIE	   16 +#define R_386_TLS_LE	   17 +#define R_386_TLS_GD	   18 +#define R_386_TLS_LDM	   19 +#define R_386_16	   20 +#define R_386_PC16	   21 +#define R_386_8		   22 +#define R_386_PC8	   23 +#define R_386_TLS_GD_32	   24 +#define R_386_TLS_GD_PUSH  25 +#define R_386_TLS_GD_CALL  26 +#define R_386_TLS_GD_POP   27 +#define R_386_TLS_LDM_32   28 +#define R_386_TLS_LDM_PUSH 29 +#define R_386_TLS_LDM_CALL 30 +#define R_386_TLS_LDM_POP  31 +#define R_386_TLS_LDO_32   32 +#define R_386_TLS_IE_32	   33 +#define R_386_TLS_LE_32	   34 +#define R_386_TLS_DTPMOD32 35 +#define R_386_TLS_DTPOFF32 36 +#define R_386_TLS_TPOFF32  37 +#define R_386_TLS_GOTDESC  39 +#define R_386_TLS_DESC_CALL 40 +#define R_386_TLS_DESC     41 +#define R_386_IRELATIVE	   42 +#define R_386_NUM	   43 + + + + + +#define STT_SPARC_REGISTER	13 + + + +#define EF_SPARCV9_MM		3 +#define EF_SPARCV9_TSO		0 +#define EF_SPARCV9_PSO		1 +#define EF_SPARCV9_RMO		2 +#define EF_SPARC_LEDATA		0x800000 +#define EF_SPARC_EXT_MASK	0xFFFF00 +#define EF_SPARC_32PLUS		0x000100 +#define EF_SPARC_SUN_US1	0x000200 +#define EF_SPARC_HAL_R1		0x000400 +#define EF_SPARC_SUN_US3	0x000800 + + + +#define R_SPARC_NONE		0 +#define R_SPARC_8		1 +#define R_SPARC_16		2 +#define R_SPARC_32		3 +#define R_SPARC_DISP8		4 +#define R_SPARC_DISP16		5 +#define R_SPARC_DISP32		6 +#define R_SPARC_WDISP30		7 +#define R_SPARC_WDISP22		8 +#define R_SPARC_HI22		9 +#define R_SPARC_22		10 +#define R_SPARC_13		11 +#define R_SPARC_LO10		12 +#define R_SPARC_GOT10		13 +#define R_SPARC_GOT13		14 +#define R_SPARC_GOT22		15 +#define R_SPARC_PC10		16 +#define R_SPARC_PC22		17 +#define R_SPARC_WPLT30		18 +#define R_SPARC_COPY		19 +#define R_SPARC_GLOB_DAT	20 +#define R_SPARC_JMP_SLOT	21 +#define R_SPARC_RELATIVE	22 +#define R_SPARC_UA32		23 + + + +#define R_SPARC_PLT32		24 +#define R_SPARC_HIPLT22		25 +#define R_SPARC_LOPLT10		26 +#define R_SPARC_PCPLT32		27 +#define R_SPARC_PCPLT22		28 +#define R_SPARC_PCPLT10		29 +#define R_SPARC_10		30 +#define R_SPARC_11		31 +#define R_SPARC_64		32 +#define R_SPARC_OLO10		33 +#define R_SPARC_HH22		34 +#define R_SPARC_HM10		35 +#define R_SPARC_LM22		36 +#define R_SPARC_PC_HH22		37 +#define R_SPARC_PC_HM10		38 +#define R_SPARC_PC_LM22		39 +#define R_SPARC_WDISP16		40 +#define R_SPARC_WDISP19		41 +#define R_SPARC_GLOB_JMP	42 +#define R_SPARC_7		43 +#define R_SPARC_5		44 +#define R_SPARC_6		45 +#define R_SPARC_DISP64		46 +#define R_SPARC_PLT64		47 +#define R_SPARC_HIX22		48 +#define R_SPARC_LOX10		49 +#define R_SPARC_H44		50 +#define R_SPARC_M44		51 +#define R_SPARC_L44		52 +#define R_SPARC_REGISTER	53 +#define R_SPARC_UA64		54 +#define R_SPARC_UA16		55 +#define R_SPARC_TLS_GD_HI22	56 +#define R_SPARC_TLS_GD_LO10	57 +#define R_SPARC_TLS_GD_ADD	58 +#define R_SPARC_TLS_GD_CALL	59 +#define R_SPARC_TLS_LDM_HI22	60 +#define R_SPARC_TLS_LDM_LO10	61 +#define R_SPARC_TLS_LDM_ADD	62 +#define R_SPARC_TLS_LDM_CALL	63 +#define R_SPARC_TLS_LDO_HIX22	64 +#define R_SPARC_TLS_LDO_LOX10	65 +#define R_SPARC_TLS_LDO_ADD	66 +#define R_SPARC_TLS_IE_HI22	67 +#define R_SPARC_TLS_IE_LO10	68 +#define R_SPARC_TLS_IE_LD	69 +#define R_SPARC_TLS_IE_LDX	70 +#define R_SPARC_TLS_IE_ADD	71 +#define R_SPARC_TLS_LE_HIX22	72 +#define R_SPARC_TLS_LE_LOX10	73 +#define R_SPARC_TLS_DTPMOD32	74 +#define R_SPARC_TLS_DTPMOD64	75 +#define R_SPARC_TLS_DTPOFF32	76 +#define R_SPARC_TLS_DTPOFF64	77 +#define R_SPARC_TLS_TPOFF32	78 +#define R_SPARC_TLS_TPOFF64	79 +#define R_SPARC_GOTDATA_HIX22	80 +#define R_SPARC_GOTDATA_LOX10	81 +#define R_SPARC_GOTDATA_OP_HIX22	82 +#define R_SPARC_GOTDATA_OP_LOX10	83 +#define R_SPARC_GOTDATA_OP	84 +#define R_SPARC_H34		85 +#define R_SPARC_SIZE32		86 +#define R_SPARC_SIZE64		87 +#define R_SPARC_GNU_VTINHERIT	250 +#define R_SPARC_GNU_VTENTRY	251 +#define R_SPARC_REV32		252 + +#define R_SPARC_NUM		253 + + + +#define DT_SPARC_REGISTER 0x70000001 +#define DT_SPARC_NUM	2 + + + +#define HWCAP_SPARC_FLUSH	1 +#define HWCAP_SPARC_STBAR	2 +#define HWCAP_SPARC_SWAP	4 +#define HWCAP_SPARC_MULDIV	8 +#define HWCAP_SPARC_V9		16 +#define HWCAP_SPARC_ULTRA3	32 +#define HWCAP_SPARC_BLKINIT	64 +#define HWCAP_SPARC_N2		128 + + + + + +#define EF_MIPS_NOREORDER   1 +#define EF_MIPS_PIC	    2 +#define EF_MIPS_CPIC	    4 +#define EF_MIPS_XGOT	    8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2	    32 +#define EF_MIPS_ABI_ON32    64 +#define EF_MIPS_ARCH	    0xf0000000 + + + +#define EF_MIPS_ARCH_1	    0x00000000 +#define EF_MIPS_ARCH_2	    0x10000000 +#define EF_MIPS_ARCH_3	    0x20000000 +#define EF_MIPS_ARCH_4	    0x30000000 +#define EF_MIPS_ARCH_5	    0x40000000 +#define EF_MIPS_ARCH_32	    0x60000000 +#define EF_MIPS_ARCH_64	    0x70000000 + + + +#define E_MIPS_ARCH_1	  0x00000000 +#define E_MIPS_ARCH_2	  0x10000000 +#define E_MIPS_ARCH_3	  0x20000000 +#define E_MIPS_ARCH_4	  0x30000000 +#define E_MIPS_ARCH_5	  0x40000000 +#define E_MIPS_ARCH_32	  0x60000000 +#define E_MIPS_ARCH_64	  0x70000000 + + + +#define SHN_MIPS_ACOMMON    0xff00 +#define SHN_MIPS_TEXT	    0xff01 +#define SHN_MIPS_DATA	    0xff02 +#define SHN_MIPS_SCOMMON    0xff03 +#define SHN_MIPS_SUNDEFINED 0xff04 + + + +#define SHT_MIPS_LIBLIST       0x70000000 +#define SHT_MIPS_MSYM	       0x70000001 +#define SHT_MIPS_CONFLICT      0x70000002 +#define SHT_MIPS_GPTAB	       0x70000003 +#define SHT_MIPS_UCODE	       0x70000004 +#define SHT_MIPS_DEBUG	       0x70000005 +#define SHT_MIPS_REGINFO       0x70000006 +#define SHT_MIPS_PACKAGE       0x70000007 +#define SHT_MIPS_PACKSYM       0x70000008 +#define SHT_MIPS_RELD	       0x70000009 +#define SHT_MIPS_IFACE         0x7000000b +#define SHT_MIPS_CONTENT       0x7000000c +#define SHT_MIPS_OPTIONS       0x7000000d +#define SHT_MIPS_SHDR	       0x70000010 +#define SHT_MIPS_FDESC	       0x70000011 +#define SHT_MIPS_EXTSYM	       0x70000012 +#define SHT_MIPS_DENSE	       0x70000013 +#define SHT_MIPS_PDESC	       0x70000014 +#define SHT_MIPS_LOCSYM	       0x70000015 +#define SHT_MIPS_AUXSYM	       0x70000016 +#define SHT_MIPS_OPTSYM	       0x70000017 +#define SHT_MIPS_LOCSTR	       0x70000018 +#define SHT_MIPS_LINE	       0x70000019 +#define SHT_MIPS_RFDESC	       0x7000001a +#define SHT_MIPS_DELTASYM      0x7000001b +#define SHT_MIPS_DELTAINST     0x7000001c +#define SHT_MIPS_DELTACLASS    0x7000001d +#define SHT_MIPS_DWARF         0x7000001e +#define SHT_MIPS_DELTADECL     0x7000001f +#define SHT_MIPS_SYMBOL_LIB    0x70000020 +#define SHT_MIPS_EVENTS	       0x70000021 +#define SHT_MIPS_TRANSLATE     0x70000022 +#define SHT_MIPS_PIXIE	       0x70000023 +#define SHT_MIPS_XLATE	       0x70000024 +#define SHT_MIPS_XLATE_DEBUG   0x70000025 +#define SHT_MIPS_WHIRL	       0x70000026 +#define SHT_MIPS_EH_REGION     0x70000027 +#define SHT_MIPS_XLATE_OLD     0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + + + +#define SHF_MIPS_GPREL	 0x10000000 +#define SHF_MIPS_MERGE	 0x20000000 +#define SHF_MIPS_ADDR	 0x40000000 +#define SHF_MIPS_STRINGS 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL	 0x04000000 +#define SHF_MIPS_NAMES	 0x02000000 +#define SHF_MIPS_NODUPE	 0x01000000 + + + + + +#define STO_MIPS_DEFAULT		0x0 +#define STO_MIPS_INTERNAL		0x1 +#define STO_MIPS_HIDDEN			0x2 +#define STO_MIPS_PROTECTED		0x3 +#define STO_MIPS_PLT			0x8 +#define STO_MIPS_SC_ALIGN_UNUSED	0xff + + +#define STB_MIPS_SPLIT_COMMON		13 + + + +typedef union { +  struct { +      Elf32_Word gt_current_g_value; +      Elf32_Word gt_unused; +  } gt_header; +  struct { +      Elf32_Word gt_g_value; +      Elf32_Word gt_bytes; +  } gt_entry; +} Elf32_gptab; + + + +typedef struct { +  Elf32_Word	ri_gprmask; +  Elf32_Word	ri_cprmask[4]; +  Elf32_Sword	ri_gp_value; +} Elf32_RegInfo; + + + +typedef struct { +  unsigned char kind; + +  unsigned char size; +  Elf32_Section section; + +  Elf32_Word info; +} Elf_Options; + + + +#define ODK_NULL	0 +#define ODK_REGINFO	1 +#define ODK_EXCEPTIONS	2 +#define ODK_PAD		3 +#define ODK_HWPATCH	4 +#define ODK_FILL	5 +#define ODK_TAGS	6 +#define ODK_HWAND	7 +#define ODK_HWOR	8 + + + +#define OEX_FPU_MIN	0x1f +#define OEX_FPU_MAX	0x1f00 +#define OEX_PAGE0	0x10000 +#define OEX_SMM		0x20000 +#define OEX_FPDBUG	0x40000 +#define OEX_PRECISEFP	OEX_FPDBUG +#define OEX_DISMISS	0x80000 + +#define OEX_FPU_INVAL	0x10 +#define OEX_FPU_DIV0	0x08 +#define OEX_FPU_OFLO	0x04 +#define OEX_FPU_UFLO	0x02 +#define OEX_FPU_INEX	0x01 + + + +#define OHW_R4KEOP	0x1 +#define OHW_R8KPFETCH	0x2 +#define OHW_R5KEOP	0x4 +#define OHW_R5KCVTL	0x8 + +#define OPAD_PREFIX	0x1 +#define OPAD_POSTFIX	0x2 +#define OPAD_SYMBOL	0x4 + + + +typedef struct { +  Elf32_Word hwp_flags1; +  Elf32_Word hwp_flags2; +} Elf_Options_Hw; + + + +#define OHWA0_R4KEOP_CHECKED	0x00000001 +#define OHWA1_R4KEOP_CLEAN	0x00000002 + + + +#define R_MIPS_NONE		0 +#define R_MIPS_16		1 +#define R_MIPS_32		2 +#define R_MIPS_REL32		3 +#define R_MIPS_26		4 +#define R_MIPS_HI16		5 +#define R_MIPS_LO16		6 +#define R_MIPS_GPREL16		7 +#define R_MIPS_LITERAL		8 +#define R_MIPS_GOT16		9 +#define R_MIPS_PC16		10 +#define R_MIPS_CALL16		11 +#define R_MIPS_GPREL32		12 + +#define R_MIPS_SHIFT5		16 +#define R_MIPS_SHIFT6		17 +#define R_MIPS_64		18 +#define R_MIPS_GOT_DISP		19 +#define R_MIPS_GOT_PAGE		20 +#define R_MIPS_GOT_OFST		21 +#define R_MIPS_GOT_HI16		22 +#define R_MIPS_GOT_LO16		23 +#define R_MIPS_SUB		24 +#define R_MIPS_INSERT_A		25 +#define R_MIPS_INSERT_B		26 +#define R_MIPS_DELETE		27 +#define R_MIPS_HIGHER		28 +#define R_MIPS_HIGHEST		29 +#define R_MIPS_CALL_HI16	30 +#define R_MIPS_CALL_LO16	31 +#define R_MIPS_SCN_DISP		32 +#define R_MIPS_REL16		33 +#define R_MIPS_ADD_IMMEDIATE	34 +#define R_MIPS_PJUMP		35 +#define R_MIPS_RELGOT		36 +#define R_MIPS_JALR		37 +#define R_MIPS_TLS_DTPMOD32	38 +#define R_MIPS_TLS_DTPREL32	39 +#define R_MIPS_TLS_DTPMOD64	40 +#define R_MIPS_TLS_DTPREL64	41 +#define R_MIPS_TLS_GD		42 +#define R_MIPS_TLS_LDM		43 +#define R_MIPS_TLS_DTPREL_HI16	44 +#define R_MIPS_TLS_DTPREL_LO16	45 +#define R_MIPS_TLS_GOTTPREL	46 +#define R_MIPS_TLS_TPREL32	47 +#define R_MIPS_TLS_TPREL64	48 +#define R_MIPS_TLS_TPREL_HI16	49 +#define R_MIPS_TLS_TPREL_LO16	50 +#define R_MIPS_GLOB_DAT		51 +#define R_MIPS_COPY		126 +#define R_MIPS_JUMP_SLOT        127 + +#define R_MIPS_NUM		128 + + + +#define PT_MIPS_REGINFO	0x70000000 +#define PT_MIPS_RTPROC  0x70000001 +#define PT_MIPS_OPTIONS 0x70000002 + + + +#define PF_MIPS_LOCAL	0x10000000 + + + +#define DT_MIPS_RLD_VERSION  0x70000001 +#define DT_MIPS_TIME_STAMP   0x70000002 +#define DT_MIPS_ICHECKSUM    0x70000003 +#define DT_MIPS_IVERSION     0x70000004 +#define DT_MIPS_FLAGS	     0x70000005 +#define DT_MIPS_BASE_ADDRESS 0x70000006 +#define DT_MIPS_MSYM	     0x70000007 +#define DT_MIPS_CONFLICT     0x70000008 +#define DT_MIPS_LIBLIST	     0x70000009 +#define DT_MIPS_LOCAL_GOTNO  0x7000000a +#define DT_MIPS_CONFLICTNO   0x7000000b +#define DT_MIPS_LIBLISTNO    0x70000010 +#define DT_MIPS_SYMTABNO     0x70000011 +#define DT_MIPS_UNREFEXTNO   0x70000012 +#define DT_MIPS_GOTSYM	     0x70000013 +#define DT_MIPS_HIPAGENO     0x70000014 +#define DT_MIPS_RLD_MAP	     0x70000016 +#define DT_MIPS_DELTA_CLASS  0x70000017 +#define DT_MIPS_DELTA_CLASS_NO    0x70000018 + +#define DT_MIPS_DELTA_INSTANCE    0x70000019 +#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a + +#define DT_MIPS_DELTA_RELOC  0x7000001b +#define DT_MIPS_DELTA_RELOC_NO 0x7000001c + +#define DT_MIPS_DELTA_SYM    0x7000001d + +#define DT_MIPS_DELTA_SYM_NO 0x7000001e + +#define DT_MIPS_DELTA_CLASSSYM 0x70000020 + +#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 + +#define DT_MIPS_CXX_FLAGS    0x70000022 +#define DT_MIPS_PIXIE_INIT   0x70000023 +#define DT_MIPS_SYMBOL_LIB   0x70000024 +#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 +#define DT_MIPS_LOCAL_GOTIDX 0x70000026 +#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 +#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 +#define DT_MIPS_OPTIONS	     0x70000029 +#define DT_MIPS_INTERFACE    0x7000002a +#define DT_MIPS_DYNSTR_ALIGN 0x7000002b +#define DT_MIPS_INTERFACE_SIZE 0x7000002c +#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d + +#define DT_MIPS_PERF_SUFFIX  0x7000002e + +#define DT_MIPS_COMPACT_SIZE 0x7000002f +#define DT_MIPS_GP_VALUE     0x70000030 +#define DT_MIPS_AUX_DYNAMIC  0x70000031 + +#define DT_MIPS_PLTGOT	     0x70000032 + +#define DT_MIPS_RWPLT        0x70000034 +#define DT_MIPS_NUM	     0x35 + + + +#define RHF_NONE		   0 +#define RHF_QUICKSTART		   (1 << 0) +#define RHF_NOTPOT		   (1 << 1) +#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) +#define RHF_NO_MOVE		   (1 << 3) +#define RHF_SGI_ONLY		   (1 << 4) +#define RHF_GUARANTEE_INIT	   (1 << 5) +#define RHF_DELTA_C_PLUS_PLUS	   (1 << 6) +#define RHF_GUARANTEE_START_INIT   (1 << 7) +#define RHF_PIXIE		   (1 << 8) +#define RHF_DEFAULT_DELAY_LOAD	   (1 << 9) +#define RHF_REQUICKSTART	   (1 << 10) +#define RHF_REQUICKSTARTED	   (1 << 11) +#define RHF_CORD		   (1 << 12) +#define RHF_NO_UNRES_UNDEF	   (1 << 13) +#define RHF_RLD_ORDER_SAFE	   (1 << 14) + + + +typedef struct +{ +  Elf32_Word l_name; +  Elf32_Word l_time_stamp; +  Elf32_Word l_checksum; +  Elf32_Word l_version; +  Elf32_Word l_flags; +} Elf32_Lib; + +typedef struct +{ +  Elf64_Word l_name; +  Elf64_Word l_time_stamp; +  Elf64_Word l_checksum; +  Elf64_Word l_version; +  Elf64_Word l_flags; +} Elf64_Lib; + + + + +#define LL_NONE		  0 +#define LL_EXACT_MATCH	  (1 << 0) +#define LL_IGNORE_INT_VER (1 << 1) +#define LL_REQUIRE_MINOR  (1 << 2) +#define LL_EXPORTS	  (1 << 3) +#define LL_DELAY_LOAD	  (1 << 4) +#define LL_DELTA	  (1 << 5) + + + +typedef Elf32_Addr Elf32_Conflict; + + + + + + +#define EF_PARISC_TRAPNIL	0x00010000 +#define EF_PARISC_EXT		0x00020000 +#define EF_PARISC_LSB		0x00040000 +#define EF_PARISC_WIDE		0x00080000 +#define EF_PARISC_NO_KABP	0x00100000 + +#define EF_PARISC_LAZYSWAP	0x00400000 +#define EF_PARISC_ARCH		0x0000ffff + + + +#define EFA_PARISC_1_0		    0x020b +#define EFA_PARISC_1_1		    0x0210 +#define EFA_PARISC_2_0		    0x0214 + + + +#define SHN_PARISC_ANSI_COMMON	0xff00 + +#define SHN_PARISC_HUGE_COMMON	0xff01 + + + +#define SHT_PARISC_EXT		0x70000000 +#define SHT_PARISC_UNWIND	0x70000001 +#define SHT_PARISC_DOC		0x70000002 + + + +#define SHF_PARISC_SHORT	0x20000000 +#define SHF_PARISC_HUGE		0x40000000 +#define SHF_PARISC_SBP		0x80000000 + + + +#define STT_PARISC_MILLICODE	13 + +#define STT_HP_OPAQUE		(STT_LOOS + 0x1) +#define STT_HP_STUB		(STT_LOOS + 0x2) + + + +#define R_PARISC_NONE		0 +#define R_PARISC_DIR32		1 +#define R_PARISC_DIR21L		2 +#define R_PARISC_DIR17R		3 +#define R_PARISC_DIR17F		4 +#define R_PARISC_DIR14R		6 +#define R_PARISC_PCREL32	9 +#define R_PARISC_PCREL21L	10 +#define R_PARISC_PCREL17R	11 +#define R_PARISC_PCREL17F	12 +#define R_PARISC_PCREL14R	14 +#define R_PARISC_DPREL21L	18 +#define R_PARISC_DPREL14R	22 +#define R_PARISC_GPREL21L	26 +#define R_PARISC_GPREL14R	30 +#define R_PARISC_LTOFF21L	34 +#define R_PARISC_LTOFF14R	38 +#define R_PARISC_SECREL32	41 +#define R_PARISC_SEGBASE	48 +#define R_PARISC_SEGREL32	49 +#define R_PARISC_PLTOFF21L	50 +#define R_PARISC_PLTOFF14R	54 +#define R_PARISC_LTOFF_FPTR32	57 +#define R_PARISC_LTOFF_FPTR21L	58 +#define R_PARISC_LTOFF_FPTR14R	62 +#define R_PARISC_FPTR64		64 +#define R_PARISC_PLABEL32	65 +#define R_PARISC_PLABEL21L	66 +#define R_PARISC_PLABEL14R	70 +#define R_PARISC_PCREL64	72 +#define R_PARISC_PCREL22F	74 +#define R_PARISC_PCREL14WR	75 +#define R_PARISC_PCREL14DR	76 +#define R_PARISC_PCREL16F	77 +#define R_PARISC_PCREL16WF	78 +#define R_PARISC_PCREL16DF	79 +#define R_PARISC_DIR64		80 +#define R_PARISC_DIR14WR	83 +#define R_PARISC_DIR14DR	84 +#define R_PARISC_DIR16F		85 +#define R_PARISC_DIR16WF	86 +#define R_PARISC_DIR16DF	87 +#define R_PARISC_GPREL64	88 +#define R_PARISC_GPREL14WR	91 +#define R_PARISC_GPREL14DR	92 +#define R_PARISC_GPREL16F	93 +#define R_PARISC_GPREL16WF	94 +#define R_PARISC_GPREL16DF	95 +#define R_PARISC_LTOFF64	96 +#define R_PARISC_LTOFF14WR	99 +#define R_PARISC_LTOFF14DR	100 +#define R_PARISC_LTOFF16F	101 +#define R_PARISC_LTOFF16WF	102 +#define R_PARISC_LTOFF16DF	103 +#define R_PARISC_SECREL64	104 +#define R_PARISC_SEGREL64	112 +#define R_PARISC_PLTOFF14WR	115 +#define R_PARISC_PLTOFF14DR	116 +#define R_PARISC_PLTOFF16F	117 +#define R_PARISC_PLTOFF16WF	118 +#define R_PARISC_PLTOFF16DF	119 +#define R_PARISC_LTOFF_FPTR64	120 +#define R_PARISC_LTOFF_FPTR14WR	123 +#define R_PARISC_LTOFF_FPTR14DR	124 +#define R_PARISC_LTOFF_FPTR16F	125 +#define R_PARISC_LTOFF_FPTR16WF	126 +#define R_PARISC_LTOFF_FPTR16DF	127 +#define R_PARISC_LORESERVE	128 +#define R_PARISC_COPY		128 +#define R_PARISC_IPLT		129 +#define R_PARISC_EPLT		130 +#define R_PARISC_TPREL32	153 +#define R_PARISC_TPREL21L	154 +#define R_PARISC_TPREL14R	158 +#define R_PARISC_LTOFF_TP21L	162 +#define R_PARISC_LTOFF_TP14R	166 +#define R_PARISC_LTOFF_TP14F	167 +#define R_PARISC_TPREL64	216 +#define R_PARISC_TPREL14WR	219 +#define R_PARISC_TPREL14DR	220 +#define R_PARISC_TPREL16F	221 +#define R_PARISC_TPREL16WF	222 +#define R_PARISC_TPREL16DF	223 +#define R_PARISC_LTOFF_TP64	224 +#define R_PARISC_LTOFF_TP14WR	227 +#define R_PARISC_LTOFF_TP14DR	228 +#define R_PARISC_LTOFF_TP16F	229 +#define R_PARISC_LTOFF_TP16WF	230 +#define R_PARISC_LTOFF_TP16DF	231 +#define R_PARISC_GNU_VTENTRY	232 +#define R_PARISC_GNU_VTINHERIT	233 +#define R_PARISC_TLS_GD21L	234 +#define R_PARISC_TLS_GD14R	235 +#define R_PARISC_TLS_GDCALL	236 +#define R_PARISC_TLS_LDM21L	237 +#define R_PARISC_TLS_LDM14R	238 +#define R_PARISC_TLS_LDMCALL	239 +#define R_PARISC_TLS_LDO21L	240 +#define R_PARISC_TLS_LDO14R	241 +#define R_PARISC_TLS_DTPMOD32	242 +#define R_PARISC_TLS_DTPMOD64	243 +#define R_PARISC_TLS_DTPOFF32	244 +#define R_PARISC_TLS_DTPOFF64	245 +#define R_PARISC_TLS_LE21L	R_PARISC_TPREL21L +#define R_PARISC_TLS_LE14R	R_PARISC_TPREL14R +#define R_PARISC_TLS_IE21L	R_PARISC_LTOFF_TP21L +#define R_PARISC_TLS_IE14R	R_PARISC_LTOFF_TP14R +#define R_PARISC_TLS_TPREL32	R_PARISC_TPREL32 +#define R_PARISC_TLS_TPREL64	R_PARISC_TPREL64 +#define R_PARISC_HIRESERVE	255 + + + +#define PT_HP_TLS		(PT_LOOS + 0x0) +#define PT_HP_CORE_NONE		(PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION	(PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL	(PT_LOOS + 0x3) +#define PT_HP_CORE_COMM		(PT_LOOS + 0x4) +#define PT_HP_CORE_PROC		(PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE	(PT_LOOS + 0x6) +#define PT_HP_CORE_STACK	(PT_LOOS + 0x7) +#define PT_HP_CORE_SHM		(PT_LOOS + 0x8) +#define PT_HP_CORE_MMF		(PT_LOOS + 0x9) +#define PT_HP_PARALLEL		(PT_LOOS + 0x10) +#define PT_HP_FASTBIND		(PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT		(PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT		(PT_LOOS + 0x13) +#define PT_HP_STACK		(PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT	0x70000000 +#define PT_PARISC_UNWIND	0x70000001 + + + +#define PF_PARISC_SBP		0x08000000 + +#define PF_HP_PAGE_SIZE		0x00100000 +#define PF_HP_FAR_SHARED	0x00200000 +#define PF_HP_NEAR_SHARED	0x00400000 +#define PF_HP_CODE		0x01000000 +#define PF_HP_MODIFY		0x02000000 +#define PF_HP_LAZYSWAP		0x04000000 +#define PF_HP_SBP		0x08000000 + + + + + + +#define EF_ALPHA_32BIT		1 +#define EF_ALPHA_CANRELAX	2 + + + + +#define SHT_ALPHA_DEBUG		0x70000001 +#define SHT_ALPHA_REGINFO	0x70000002 + + + +#define SHF_ALPHA_GPREL		0x10000000 + + +#define STO_ALPHA_NOPV		0x80 +#define STO_ALPHA_STD_GPLOAD	0x88 + + + +#define R_ALPHA_NONE		0 +#define R_ALPHA_REFLONG		1 +#define R_ALPHA_REFQUAD		2 +#define R_ALPHA_GPREL32		3 +#define R_ALPHA_LITERAL		4 +#define R_ALPHA_LITUSE		5 +#define R_ALPHA_GPDISP		6 +#define R_ALPHA_BRADDR		7 +#define R_ALPHA_HINT		8 +#define R_ALPHA_SREL16		9 +#define R_ALPHA_SREL32		10 +#define R_ALPHA_SREL64		11 +#define R_ALPHA_GPRELHIGH	17 +#define R_ALPHA_GPRELLOW	18 +#define R_ALPHA_GPREL16		19 +#define R_ALPHA_COPY		24 +#define R_ALPHA_GLOB_DAT	25 +#define R_ALPHA_JMP_SLOT	26 +#define R_ALPHA_RELATIVE	27 +#define R_ALPHA_TLS_GD_HI	28 +#define R_ALPHA_TLSGD		29 +#define R_ALPHA_TLS_LDM		30 +#define R_ALPHA_DTPMOD64	31 +#define R_ALPHA_GOTDTPREL	32 +#define R_ALPHA_DTPREL64	33 +#define R_ALPHA_DTPRELHI	34 +#define R_ALPHA_DTPRELLO	35 +#define R_ALPHA_DTPREL16	36 +#define R_ALPHA_GOTTPREL	37 +#define R_ALPHA_TPREL64		38 +#define R_ALPHA_TPRELHI		39 +#define R_ALPHA_TPRELLO		40 +#define R_ALPHA_TPREL16		41 + +#define R_ALPHA_NUM		46 + + +#define LITUSE_ALPHA_ADDR	0 +#define LITUSE_ALPHA_BASE	1 +#define LITUSE_ALPHA_BYTOFF	2 +#define LITUSE_ALPHA_JSR	3 +#define LITUSE_ALPHA_TLS_GD	4 +#define LITUSE_ALPHA_TLS_LDM	5 + + +#define DT_ALPHA_PLTRO		(DT_LOPROC + 0) +#define DT_ALPHA_NUM		1 + + + + +#define EF_PPC_EMB		0x80000000 + + +#define EF_PPC_RELOCATABLE	0x00010000 +#define EF_PPC_RELOCATABLE_LIB	0x00008000 + + + +#define R_PPC_NONE		0 +#define R_PPC_ADDR32		1 +#define R_PPC_ADDR24		2 +#define R_PPC_ADDR16		3 +#define R_PPC_ADDR16_LO		4 +#define R_PPC_ADDR16_HI		5 +#define R_PPC_ADDR16_HA		6 +#define R_PPC_ADDR14		7 +#define R_PPC_ADDR14_BRTAKEN	8 +#define R_PPC_ADDR14_BRNTAKEN	9 +#define R_PPC_REL24		10 +#define R_PPC_REL14		11 +#define R_PPC_REL14_BRTAKEN	12 +#define R_PPC_REL14_BRNTAKEN	13 +#define R_PPC_GOT16		14 +#define R_PPC_GOT16_LO		15 +#define R_PPC_GOT16_HI		16 +#define R_PPC_GOT16_HA		17 +#define R_PPC_PLTREL24		18 +#define R_PPC_COPY		19 +#define R_PPC_GLOB_DAT		20 +#define R_PPC_JMP_SLOT		21 +#define R_PPC_RELATIVE		22 +#define R_PPC_LOCAL24PC		23 +#define R_PPC_UADDR32		24 +#define R_PPC_UADDR16		25 +#define R_PPC_REL32		26 +#define R_PPC_PLT32		27 +#define R_PPC_PLTREL32		28 +#define R_PPC_PLT16_LO		29 +#define R_PPC_PLT16_HI		30 +#define R_PPC_PLT16_HA		31 +#define R_PPC_SDAREL16		32 +#define R_PPC_SECTOFF		33 +#define R_PPC_SECTOFF_LO	34 +#define R_PPC_SECTOFF_HI	35 +#define R_PPC_SECTOFF_HA	36 + + +#define R_PPC_TLS		67 +#define R_PPC_DTPMOD32		68 +#define R_PPC_TPREL16		69 +#define R_PPC_TPREL16_LO	70 +#define R_PPC_TPREL16_HI	71 +#define R_PPC_TPREL16_HA	72 +#define R_PPC_TPREL32		73 +#define R_PPC_DTPREL16		74 +#define R_PPC_DTPREL16_LO	75 +#define R_PPC_DTPREL16_HI	76 +#define R_PPC_DTPREL16_HA	77 +#define R_PPC_DTPREL32		78 +#define R_PPC_GOT_TLSGD16	79 +#define R_PPC_GOT_TLSGD16_LO	80 +#define R_PPC_GOT_TLSGD16_HI	81 +#define R_PPC_GOT_TLSGD16_HA	82 +#define R_PPC_GOT_TLSLD16	83 +#define R_PPC_GOT_TLSLD16_LO	84 +#define R_PPC_GOT_TLSLD16_HI	85 +#define R_PPC_GOT_TLSLD16_HA	86 +#define R_PPC_GOT_TPREL16	87 +#define R_PPC_GOT_TPREL16_LO	88 +#define R_PPC_GOT_TPREL16_HI	89 +#define R_PPC_GOT_TPREL16_HA	90 +#define R_PPC_GOT_DTPREL16	91 +#define R_PPC_GOT_DTPREL16_LO	92 +#define R_PPC_GOT_DTPREL16_HI	93 +#define R_PPC_GOT_DTPREL16_HA	94 + + + +#define R_PPC_EMB_NADDR32	101 +#define R_PPC_EMB_NADDR16	102 +#define R_PPC_EMB_NADDR16_LO	103 +#define R_PPC_EMB_NADDR16_HI	104 +#define R_PPC_EMB_NADDR16_HA	105 +#define R_PPC_EMB_SDAI16	106 +#define R_PPC_EMB_SDA2I16	107 +#define R_PPC_EMB_SDA2REL	108 +#define R_PPC_EMB_SDA21		109 +#define R_PPC_EMB_MRKREF	110 +#define R_PPC_EMB_RELSEC16	111 +#define R_PPC_EMB_RELST_LO	112 +#define R_PPC_EMB_RELST_HI	113 +#define R_PPC_EMB_RELST_HA	114 +#define R_PPC_EMB_BIT_FLD	115 +#define R_PPC_EMB_RELSDA	116 + + +#define R_PPC_DIAB_SDA21_LO	180 +#define R_PPC_DIAB_SDA21_HI	181 +#define R_PPC_DIAB_SDA21_HA	182 +#define R_PPC_DIAB_RELSDA_LO	183 +#define R_PPC_DIAB_RELSDA_HI	184 +#define R_PPC_DIAB_RELSDA_HA	185 + + +#define R_PPC_IRELATIVE		248 + + +#define R_PPC_REL16		249 +#define R_PPC_REL16_LO		250 +#define R_PPC_REL16_HI		251 +#define R_PPC_REL16_HA		252 + + + +#define R_PPC_TOC16		255 + + +#define DT_PPC_GOT		(DT_LOPROC + 0) +#define DT_PPC_NUM		1 + + +#define R_PPC64_NONE		R_PPC_NONE +#define R_PPC64_ADDR32		R_PPC_ADDR32 +#define R_PPC64_ADDR24		R_PPC_ADDR24 +#define R_PPC64_ADDR16		R_PPC_ADDR16 +#define R_PPC64_ADDR16_LO	R_PPC_ADDR16_LO +#define R_PPC64_ADDR16_HI	R_PPC_ADDR16_HI +#define R_PPC64_ADDR16_HA	R_PPC_ADDR16_HA +#define R_PPC64_ADDR14		R_PPC_ADDR14 +#define R_PPC64_ADDR14_BRTAKEN	R_PPC_ADDR14_BRTAKEN +#define R_PPC64_ADDR14_BRNTAKEN	R_PPC_ADDR14_BRNTAKEN +#define R_PPC64_REL24		R_PPC_REL24 +#define R_PPC64_REL14		R_PPC_REL14 +#define R_PPC64_REL14_BRTAKEN	R_PPC_REL14_BRTAKEN +#define R_PPC64_REL14_BRNTAKEN	R_PPC_REL14_BRNTAKEN +#define R_PPC64_GOT16		R_PPC_GOT16 +#define R_PPC64_GOT16_LO	R_PPC_GOT16_LO +#define R_PPC64_GOT16_HI	R_PPC_GOT16_HI +#define R_PPC64_GOT16_HA	R_PPC_GOT16_HA + +#define R_PPC64_COPY		R_PPC_COPY +#define R_PPC64_GLOB_DAT	R_PPC_GLOB_DAT +#define R_PPC64_JMP_SLOT	R_PPC_JMP_SLOT +#define R_PPC64_RELATIVE	R_PPC_RELATIVE + +#define R_PPC64_UADDR32		R_PPC_UADDR32 +#define R_PPC64_UADDR16		R_PPC_UADDR16 +#define R_PPC64_REL32		R_PPC_REL32 +#define R_PPC64_PLT32		R_PPC_PLT32 +#define R_PPC64_PLTREL32	R_PPC_PLTREL32 +#define R_PPC64_PLT16_LO	R_PPC_PLT16_LO +#define R_PPC64_PLT16_HI	R_PPC_PLT16_HI +#define R_PPC64_PLT16_HA	R_PPC_PLT16_HA + +#define R_PPC64_SECTOFF		R_PPC_SECTOFF +#define R_PPC64_SECTOFF_LO	R_PPC_SECTOFF_LO +#define R_PPC64_SECTOFF_HI	R_PPC_SECTOFF_HI +#define R_PPC64_SECTOFF_HA	R_PPC_SECTOFF_HA +#define R_PPC64_ADDR30		37 +#define R_PPC64_ADDR64		38 +#define R_PPC64_ADDR16_HIGHER	39 +#define R_PPC64_ADDR16_HIGHERA	40 +#define R_PPC64_ADDR16_HIGHEST	41 +#define R_PPC64_ADDR16_HIGHESTA	42 +#define R_PPC64_UADDR64		43 +#define R_PPC64_REL64		44 +#define R_PPC64_PLT64		45 +#define R_PPC64_PLTREL64	46 +#define R_PPC64_TOC16		47 +#define R_PPC64_TOC16_LO	48 +#define R_PPC64_TOC16_HI	49 +#define R_PPC64_TOC16_HA	50 +#define R_PPC64_TOC		51 +#define R_PPC64_PLTGOT16	52 +#define R_PPC64_PLTGOT16_LO	53 +#define R_PPC64_PLTGOT16_HI	54 +#define R_PPC64_PLTGOT16_HA	55 + +#define R_PPC64_ADDR16_DS	56 +#define R_PPC64_ADDR16_LO_DS	57 +#define R_PPC64_GOT16_DS	58 +#define R_PPC64_GOT16_LO_DS	59 +#define R_PPC64_PLT16_LO_DS	60 +#define R_PPC64_SECTOFF_DS	61 +#define R_PPC64_SECTOFF_LO_DS	62 +#define R_PPC64_TOC16_DS	63 +#define R_PPC64_TOC16_LO_DS	64 +#define R_PPC64_PLTGOT16_DS	65 +#define R_PPC64_PLTGOT16_LO_DS	66 + + +#define R_PPC64_TLS		67 +#define R_PPC64_DTPMOD64	68 +#define R_PPC64_TPREL16		69 +#define R_PPC64_TPREL16_LO	70 +#define R_PPC64_TPREL16_HI	71 +#define R_PPC64_TPREL16_HA	72 +#define R_PPC64_TPREL64		73 +#define R_PPC64_DTPREL16	74 +#define R_PPC64_DTPREL16_LO	75 +#define R_PPC64_DTPREL16_HI	76 +#define R_PPC64_DTPREL16_HA	77 +#define R_PPC64_DTPREL64	78 +#define R_PPC64_GOT_TLSGD16	79 +#define R_PPC64_GOT_TLSGD16_LO	80 +#define R_PPC64_GOT_TLSGD16_HI	81 +#define R_PPC64_GOT_TLSGD16_HA	82 +#define R_PPC64_GOT_TLSLD16	83 +#define R_PPC64_GOT_TLSLD16_LO	84 +#define R_PPC64_GOT_TLSLD16_HI	85 +#define R_PPC64_GOT_TLSLD16_HA	86 +#define R_PPC64_GOT_TPREL16_DS	87 +#define R_PPC64_GOT_TPREL16_LO_DS 88 +#define R_PPC64_GOT_TPREL16_HI	89 +#define R_PPC64_GOT_TPREL16_HA	90 +#define R_PPC64_GOT_DTPREL16_DS	91 +#define R_PPC64_GOT_DTPREL16_LO_DS 92 +#define R_PPC64_GOT_DTPREL16_HI	93 +#define R_PPC64_GOT_DTPREL16_HA	94 +#define R_PPC64_TPREL16_DS	95 +#define R_PPC64_TPREL16_LO_DS	96 +#define R_PPC64_TPREL16_HIGHER	97 +#define R_PPC64_TPREL16_HIGHERA	98 +#define R_PPC64_TPREL16_HIGHEST	99 +#define R_PPC64_TPREL16_HIGHESTA 100 +#define R_PPC64_DTPREL16_DS	101 +#define R_PPC64_DTPREL16_LO_DS	102 +#define R_PPC64_DTPREL16_HIGHER	103 +#define R_PPC64_DTPREL16_HIGHERA 104 +#define R_PPC64_DTPREL16_HIGHEST 105 +#define R_PPC64_DTPREL16_HIGHESTA 106 + + +#define R_PPC64_JMP_IREL	247 +#define R_PPC64_IRELATIVE	248 +#define R_PPC64_REL16		249 +#define R_PPC64_REL16_LO	250 +#define R_PPC64_REL16_HI	251 +#define R_PPC64_REL16_HA	252 + + +#define DT_PPC64_GLINK  (DT_LOPROC + 0) +#define DT_PPC64_OPD	(DT_LOPROC + 1) +#define DT_PPC64_OPDSZ	(DT_LOPROC + 2) +#define DT_PPC64_NUM    3 + + + + + +#define EF_ARM_RELEXEC		0x01 +#define EF_ARM_HASENTRY		0x02 +#define EF_ARM_INTERWORK	0x04 +#define EF_ARM_APCS_26		0x08 +#define EF_ARM_APCS_FLOAT	0x10 +#define EF_ARM_PIC		0x20 +#define EF_ARM_ALIGN8		0x40 +#define EF_ARM_NEW_ABI		0x80 +#define EF_ARM_OLD_ABI		0x100 +#define EF_ARM_SOFT_FLOAT	0x200 +#define EF_ARM_VFP_FLOAT	0x400 +#define EF_ARM_MAVERICK_FLOAT	0x800 + + + + +#define EF_ARM_SYMSARESORTED	0x04 +#define EF_ARM_DYNSYMSUSESEGIDX	0x08 +#define EF_ARM_MAPSYMSFIRST	0x10 +#define EF_ARM_EABIMASK		0XFF000000 + + +#define EF_ARM_BE8	    0x00800000 +#define EF_ARM_LE8	    0x00400000 + +#define EF_ARM_EABI_VERSION(flags)	((flags) & EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN	0x00000000 +#define EF_ARM_EABI_VER1	0x01000000 +#define EF_ARM_EABI_VER2	0x02000000 +#define EF_ARM_EABI_VER3	0x03000000 +#define EF_ARM_EABI_VER4	0x04000000 +#define EF_ARM_EABI_VER5	0x05000000 + + +#define STT_ARM_TFUNC		STT_LOPROC +#define STT_ARM_16BIT		STT_HIPROC + + +#define SHF_ARM_ENTRYSECT	0x10000000 +#define SHF_ARM_COMDEF		0x80000000 + + + +#define PF_ARM_SB		0x10000000 + +#define PF_ARM_PI		0x20000000 +#define PF_ARM_ABS		0x40000000 + + +#define PT_ARM_EXIDX		(PT_LOPROC + 1) + + +#define SHT_ARM_EXIDX		(SHT_LOPROC + 1) +#define SHT_ARM_PREEMPTMAP	(SHT_LOPROC + 2) +#define SHT_ARM_ATTRIBUTES	(SHT_LOPROC + 3) + + + + +#define R_ARM_NONE		0 +#define R_ARM_PC24		1 +#define R_ARM_ABS32		2 +#define R_ARM_REL32		3 +#define R_ARM_PC13		4 +#define R_ARM_ABS16		5 +#define R_ARM_ABS12		6 +#define R_ARM_THM_ABS5		7 +#define R_ARM_ABS8		8 +#define R_ARM_SBREL32		9 +#define R_ARM_THM_PC22		10 +#define R_ARM_THM_PC8		11 +#define R_ARM_AMP_VCALL9	12 +#define R_ARM_SWI24		13 +#define R_ARM_THM_SWI8		14 +#define R_ARM_XPC25		15 +#define R_ARM_THM_XPC22		16 +#define R_ARM_TLS_DTPMOD32	17 +#define R_ARM_TLS_DTPOFF32	18 +#define R_ARM_TLS_TPOFF32	19 +#define R_ARM_COPY		20 +#define R_ARM_GLOB_DAT		21 +#define R_ARM_JUMP_SLOT		22 +#define R_ARM_RELATIVE		23 +#define R_ARM_GOTOFF		24 +#define R_ARM_GOTPC		25 +#define R_ARM_GOT32		26 +#define R_ARM_PLT32		27 +#define R_ARM_ALU_PCREL_7_0	32 +#define R_ARM_ALU_PCREL_15_8	33 +#define R_ARM_ALU_PCREL_23_15	34 +#define R_ARM_LDR_SBREL_11_0	35 +#define R_ARM_ALU_SBREL_19_12	36 +#define R_ARM_ALU_SBREL_27_20	37 +#define R_ARM_GNU_VTENTRY	100 +#define R_ARM_GNU_VTINHERIT	101 +#define R_ARM_THM_PC11		102 +#define R_ARM_THM_PC9		103 +#define R_ARM_TLS_GD32		104 + +#define R_ARM_TLS_LDM32		105 + +#define R_ARM_TLS_LDO32		106 + +#define R_ARM_TLS_IE32		107 + +#define R_ARM_TLS_LE32		108 + +#define R_ARM_RXPC25		249 +#define R_ARM_RSBREL32		250 +#define R_ARM_THM_RPC22		251 +#define R_ARM_RREL32		252 +#define R_ARM_RABS22		253 +#define R_ARM_RPC24		254 +#define R_ARM_RBASE		255 + +#define R_ARM_NUM		256 + + + + +#define EF_IA_64_MASKOS		0x0000000f +#define EF_IA_64_ABI64		0x00000010 +#define EF_IA_64_ARCH		0xff000000 + + +#define PT_IA_64_ARCHEXT	(PT_LOPROC + 0) +#define PT_IA_64_UNWIND		(PT_LOPROC + 1) +#define PT_IA_64_HP_OPT_ANOT	(PT_LOOS + 0x12) +#define PT_IA_64_HP_HSL_ANOT	(PT_LOOS + 0x13) +#define PT_IA_64_HP_STACK	(PT_LOOS + 0x14) + + +#define PF_IA_64_NORECOV	0x80000000 + + +#define SHT_IA_64_EXT		(SHT_LOPROC + 0) +#define SHT_IA_64_UNWIND	(SHT_LOPROC + 1) + + +#define SHF_IA_64_SHORT		0x10000000 +#define SHF_IA_64_NORECOV	0x20000000 + + +#define DT_IA_64_PLT_RESERVE	(DT_LOPROC + 0) +#define DT_IA_64_NUM		1 + + +#define R_IA64_NONE		0x00 +#define R_IA64_IMM14		0x21 +#define R_IA64_IMM22		0x22 +#define R_IA64_IMM64		0x23 +#define R_IA64_DIR32MSB		0x24 +#define R_IA64_DIR32LSB		0x25 +#define R_IA64_DIR64MSB		0x26 +#define R_IA64_DIR64LSB		0x27 +#define R_IA64_GPREL22		0x2a +#define R_IA64_GPREL64I		0x2b +#define R_IA64_GPREL32MSB	0x2c +#define R_IA64_GPREL32LSB	0x2d +#define R_IA64_GPREL64MSB	0x2e +#define R_IA64_GPREL64LSB	0x2f +#define R_IA64_LTOFF22		0x32 +#define R_IA64_LTOFF64I		0x33 +#define R_IA64_PLTOFF22		0x3a +#define R_IA64_PLTOFF64I	0x3b +#define R_IA64_PLTOFF64MSB	0x3e +#define R_IA64_PLTOFF64LSB	0x3f +#define R_IA64_FPTR64I		0x43 +#define R_IA64_FPTR32MSB	0x44 +#define R_IA64_FPTR32LSB	0x45 +#define R_IA64_FPTR64MSB	0x46 +#define R_IA64_FPTR64LSB	0x47 +#define R_IA64_PCREL60B		0x48 +#define R_IA64_PCREL21B		0x49 +#define R_IA64_PCREL21M		0x4a +#define R_IA64_PCREL21F		0x4b +#define R_IA64_PCREL32MSB	0x4c +#define R_IA64_PCREL32LSB	0x4d +#define R_IA64_PCREL64MSB	0x4e +#define R_IA64_PCREL64LSB	0x4f +#define R_IA64_LTOFF_FPTR22	0x52 +#define R_IA64_LTOFF_FPTR64I	0x53 +#define R_IA64_LTOFF_FPTR32MSB	0x54 +#define R_IA64_LTOFF_FPTR32LSB	0x55 +#define R_IA64_LTOFF_FPTR64MSB	0x56 +#define R_IA64_LTOFF_FPTR64LSB	0x57 +#define R_IA64_SEGREL32MSB	0x5c +#define R_IA64_SEGREL32LSB	0x5d +#define R_IA64_SEGREL64MSB	0x5e +#define R_IA64_SEGREL64LSB	0x5f +#define R_IA64_SECREL32MSB	0x64 +#define R_IA64_SECREL32LSB	0x65 +#define R_IA64_SECREL64MSB	0x66 +#define R_IA64_SECREL64LSB	0x67 +#define R_IA64_REL32MSB		0x6c +#define R_IA64_REL32LSB		0x6d +#define R_IA64_REL64MSB		0x6e +#define R_IA64_REL64LSB		0x6f +#define R_IA64_LTV32MSB		0x74 +#define R_IA64_LTV32LSB		0x75 +#define R_IA64_LTV64MSB		0x76 +#define R_IA64_LTV64LSB		0x77 +#define R_IA64_PCREL21BI	0x79 +#define R_IA64_PCREL22		0x7a +#define R_IA64_PCREL64I		0x7b +#define R_IA64_IPLTMSB		0x80 +#define R_IA64_IPLTLSB		0x81 +#define R_IA64_COPY		0x84 +#define R_IA64_SUB		0x85 +#define R_IA64_LTOFF22X		0x86 +#define R_IA64_LDXMOV		0x87 +#define R_IA64_TPREL14		0x91 +#define R_IA64_TPREL22		0x92 +#define R_IA64_TPREL64I		0x93 +#define R_IA64_TPREL64MSB	0x96 +#define R_IA64_TPREL64LSB	0x97 +#define R_IA64_LTOFF_TPREL22	0x9a +#define R_IA64_DTPMOD64MSB	0xa6 +#define R_IA64_DTPMOD64LSB	0xa7 +#define R_IA64_LTOFF_DTPMOD22	0xaa +#define R_IA64_DTPREL14		0xb1 +#define R_IA64_DTPREL22		0xb2 +#define R_IA64_DTPREL64I	0xb3 +#define R_IA64_DTPREL32MSB	0xb4 +#define R_IA64_DTPREL32LSB	0xb5 +#define R_IA64_DTPREL64MSB	0xb6 +#define R_IA64_DTPREL64LSB	0xb7 +#define R_IA64_LTOFF_DTPREL22	0xba + + + + +#define	R_SH_NONE		0 +#define	R_SH_DIR32		1 +#define	R_SH_REL32		2 +#define	R_SH_DIR8WPN		3 +#define	R_SH_IND12W		4 +#define	R_SH_DIR8WPL		5 +#define	R_SH_DIR8WPZ		6 +#define	R_SH_DIR8BP		7 +#define	R_SH_DIR8W		8 +#define	R_SH_DIR8L		9 +#define	R_SH_SWITCH16		25 +#define	R_SH_SWITCH32		26 +#define	R_SH_USES		27 +#define	R_SH_COUNT		28 +#define	R_SH_ALIGN		29 +#define	R_SH_CODE		30 +#define	R_SH_DATA		31 +#define	R_SH_LABEL		32 +#define	R_SH_SWITCH8		33 +#define	R_SH_GNU_VTINHERIT	34 +#define	R_SH_GNU_VTENTRY	35 +#define	R_SH_TLS_GD_32		144 +#define	R_SH_TLS_LD_32		145 +#define	R_SH_TLS_LDO_32		146 +#define	R_SH_TLS_IE_32		147 +#define	R_SH_TLS_LE_32		148 +#define	R_SH_TLS_DTPMOD32	149 +#define	R_SH_TLS_DTPOFF32	150 +#define	R_SH_TLS_TPOFF32	151 +#define	R_SH_GOT32		160 +#define	R_SH_PLT32		161 +#define	R_SH_COPY		162 +#define	R_SH_GLOB_DAT		163 +#define	R_SH_JMP_SLOT		164 +#define	R_SH_RELATIVE		165 +#define	R_SH_GOTOFF		166 +#define	R_SH_GOTPC		167 + +#define	R_SH_NUM		256 + + + +#define R_390_NONE		0 +#define R_390_8			1 +#define R_390_12		2 +#define R_390_16		3 +#define R_390_32		4 +#define R_390_PC32		5 +#define R_390_GOT12		6 +#define R_390_GOT32		7 +#define R_390_PLT32		8 +#define R_390_COPY		9 +#define R_390_GLOB_DAT		10 +#define R_390_JMP_SLOT		11 +#define R_390_RELATIVE		12 +#define R_390_GOTOFF32		13 +#define R_390_GOTPC		14 +#define R_390_GOT16		15 +#define R_390_PC16		16 +#define R_390_PC16DBL		17 +#define R_390_PLT16DBL		18 +#define R_390_PC32DBL		19 +#define R_390_PLT32DBL		20 +#define R_390_GOTPCDBL		21 +#define R_390_64		22 +#define R_390_PC64		23 +#define R_390_GOT64		24 +#define R_390_PLT64		25 +#define R_390_GOTENT		26 +#define R_390_GOTOFF16		27 +#define R_390_GOTOFF64		28 +#define R_390_GOTPLT12		29 +#define R_390_GOTPLT16		30 +#define R_390_GOTPLT32		31 +#define R_390_GOTPLT64		32 +#define R_390_GOTPLTENT		33 +#define R_390_PLTOFF16		34 +#define R_390_PLTOFF32		35 +#define R_390_PLTOFF64		36 +#define R_390_TLS_LOAD		37 +#define R_390_TLS_GDCALL	38 + +#define R_390_TLS_LDCALL	39 + +#define R_390_TLS_GD32		40 + +#define R_390_TLS_GD64		41 + +#define R_390_TLS_GOTIE12	42 + +#define R_390_TLS_GOTIE32	43 + +#define R_390_TLS_GOTIE64	44 + +#define R_390_TLS_LDM32		45 + +#define R_390_TLS_LDM64		46 + +#define R_390_TLS_IE32		47 + +#define R_390_TLS_IE64		48 + +#define R_390_TLS_IEENT		49 + +#define R_390_TLS_LE32		50 + +#define R_390_TLS_LE64		51 + +#define R_390_TLS_LDO32		52 + +#define R_390_TLS_LDO64		53 + +#define R_390_TLS_DTPMOD	54 +#define R_390_TLS_DTPOFF	55 +#define R_390_TLS_TPOFF		56 + +#define R_390_20		57 +#define R_390_GOT20		58 +#define R_390_GOTPLT20		59 +#define R_390_TLS_GOTIE20	60 + + +#define R_390_NUM		61 + + + +#define R_CRIS_NONE		0 +#define R_CRIS_8		1 +#define R_CRIS_16		2 +#define R_CRIS_32		3 +#define R_CRIS_8_PCREL		4 +#define R_CRIS_16_PCREL		5 +#define R_CRIS_32_PCREL		6 +#define R_CRIS_GNU_VTINHERIT	7 +#define R_CRIS_GNU_VTENTRY	8 +#define R_CRIS_COPY		9 +#define R_CRIS_GLOB_DAT		10 +#define R_CRIS_JUMP_SLOT	11 +#define R_CRIS_RELATIVE		12 +#define R_CRIS_16_GOT		13 +#define R_CRIS_32_GOT		14 +#define R_CRIS_16_GOTPLT	15 +#define R_CRIS_32_GOTPLT	16 +#define R_CRIS_32_GOTREL	17 +#define R_CRIS_32_PLT_GOTREL	18 +#define R_CRIS_32_PLT_PCREL	19 + +#define R_CRIS_NUM		20 + + + +#define R_X86_64_NONE		0 +#define R_X86_64_64		1 +#define R_X86_64_PC32		2 +#define R_X86_64_GOT32		3 +#define R_X86_64_PLT32		4 +#define R_X86_64_COPY		5 +#define R_X86_64_GLOB_DAT	6 +#define R_X86_64_JUMP_SLOT	7 +#define R_X86_64_RELATIVE	8 +#define R_X86_64_GOTPCREL	9 + +#define R_X86_64_32		10 +#define R_X86_64_32S		11 +#define R_X86_64_16		12 +#define R_X86_64_PC16		13 +#define R_X86_64_8		14 +#define R_X86_64_PC8		15 +#define R_X86_64_DTPMOD64	16 +#define R_X86_64_DTPOFF64	17 +#define R_X86_64_TPOFF64	18 +#define R_X86_64_TLSGD		19 + +#define R_X86_64_TLSLD		20 + +#define R_X86_64_DTPOFF32	21 +#define R_X86_64_GOTTPOFF	22 + +#define R_X86_64_TPOFF32	23 +#define R_X86_64_PC64		24 +#define R_X86_64_GOTOFF64	25 +#define R_X86_64_GOTPC32	26 + + +#define R_X86_64_GOTPC32_TLSDESC 34 +#define R_X86_64_TLSDESC_CALL   35 + +#define R_X86_64_TLSDESC        36 +#define R_X86_64_IRELATIVE	37 + +#define R_X86_64_NUM		38 + + + +#define R_MN10300_NONE		0 +#define R_MN10300_32		1 +#define R_MN10300_16		2 +#define R_MN10300_8		3 +#define R_MN10300_PCREL32	4 +#define R_MN10300_PCREL16	5 +#define R_MN10300_PCREL8	6 +#define R_MN10300_GNU_VTINHERIT	7 +#define R_MN10300_GNU_VTENTRY	8 +#define R_MN10300_24		9 +#define R_MN10300_GOTPC32	10 +#define R_MN10300_GOTPC16	11 +#define R_MN10300_GOTOFF32	12 +#define R_MN10300_GOTOFF24	13 +#define R_MN10300_GOTOFF16	14 +#define R_MN10300_PLT32		15 +#define R_MN10300_PLT16		16 +#define R_MN10300_GOT32		17 +#define R_MN10300_GOT24		18 +#define R_MN10300_GOT16		19 +#define R_MN10300_COPY		20 +#define R_MN10300_GLOB_DAT	21 +#define R_MN10300_JMP_SLOT	22 +#define R_MN10300_RELATIVE	23 + +#define R_MN10300_NUM		24 + + + +#define R_M32R_NONE		0 +#define R_M32R_16		1 +#define R_M32R_32		2 +#define R_M32R_24		3 +#define R_M32R_10_PCREL		4 +#define R_M32R_18_PCREL		5 +#define R_M32R_26_PCREL		6 +#define R_M32R_HI16_ULO		7 +#define R_M32R_HI16_SLO		8 +#define R_M32R_LO16		9 +#define R_M32R_SDA16		10 +#define R_M32R_GNU_VTINHERIT	11 +#define R_M32R_GNU_VTENTRY	12 + +#define R_M32R_16_RELA		33 +#define R_M32R_32_RELA		34 +#define R_M32R_24_RELA		35 +#define R_M32R_10_PCREL_RELA	36 +#define R_M32R_18_PCREL_RELA	37 +#define R_M32R_26_PCREL_RELA	38 +#define R_M32R_HI16_ULO_RELA	39 +#define R_M32R_HI16_SLO_RELA	40 +#define R_M32R_LO16_RELA	41 +#define R_M32R_SDA16_RELA	42 +#define R_M32R_RELA_GNU_VTINHERIT	43 +#define R_M32R_RELA_GNU_VTENTRY	44 +#define R_M32R_REL32		45 + +#define R_M32R_GOT24		48 +#define R_M32R_26_PLTREL	49 +#define R_M32R_COPY		50 +#define R_M32R_GLOB_DAT		51 +#define R_M32R_JMP_SLOT		52 +#define R_M32R_RELATIVE		53 +#define R_M32R_GOTOFF		54 +#define R_M32R_GOTPC24		55 +#define R_M32R_GOT16_HI_ULO	56 + +#define R_M32R_GOT16_HI_SLO	57 + +#define R_M32R_GOT16_LO		58 +#define R_M32R_GOTPC_HI_ULO	59 + +#define R_M32R_GOTPC_HI_SLO	60 + +#define R_M32R_GOTPC_LO		61 + +#define R_M32R_GOTOFF_HI_ULO	62 + +#define R_M32R_GOTOFF_HI_SLO	63 + +#define R_M32R_GOTOFF_LO	64 +#define R_M32R_NUM		256 + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/include/endian.h b/include/endian.h new file mode 100644 index 00000000..bcf67662 --- /dev/null +++ b/include/endian.h @@ -0,0 +1,17 @@ +#ifndef _ENDIAN_H +#define _ENDIAN_H + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __PDP_ENDIAN 3412 + +#include <bits/endian.h> + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#define BIG_ENDIAN __BIG_ENDIAN +#define LITTLE_ENDIAN __LITTLE_ENDIAN +#define PDP_ENDIAN __PDP_ENDIAN +#define BYTE_ORDER __BYTE_ORDER +#endif + +#endif diff --git a/include/errno.h b/include/errno.h new file mode 100644 index 00000000..d9c2c9c7 --- /dev/null +++ b/include/errno.h @@ -0,0 +1,18 @@ +#ifndef	_ERRNO_H +#define _ERRNO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <bits/errno.h> + +extern int *__errno_location(void); +#define errno (*__errno_location()) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/fcntl.h b/include/fcntl.h new file mode 100644 index 00000000..61a6cb55 --- /dev/null +++ b/include/fcntl.h @@ -0,0 +1,43 @@ +#ifndef	_FCNTL_H +#define	_FCNTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_off_t +#define __NEED_pid_t +#define __NEED_mode_t + +#include <bits/alltypes.h> + +#include <bits/fcntl.h> + +struct flock +{ +	short l_type; +	short l_whence; +	off_t l_start; +	off_t l_len; +	pid_t l_pid; +}; + +int creat(const char *, mode_t); +int fcntl(int, int, ...); +int open(const char *, int, ...); +int openat(int, const char *, int, ...); +int posix_fadvise(int, off_t, off_t, int); +int posix_fallocate(int, off_t, off_t); + +#undef SEEK_SET +#undef SEEK_CUR +#undef SEEK_END +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/features.h b/include/features.h new file mode 100644 index 00000000..851afb66 --- /dev/null +++ b/include/features.h @@ -0,0 +1 @@ +#warning "features.h is bogus" diff --git a/include/fenv.h b/include/fenv.h new file mode 100644 index 00000000..05de990c --- /dev/null +++ b/include/fenv.h @@ -0,0 +1,28 @@ +#ifndef _FENV_H +#define _FENV_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <bits/fenv.h> + +int feclearexcept(int); +int fegetexceptflag(fexcept_t *, int); +int feraiseexcept(int); +int fesetexceptflag(const fexcept_t *, int); +int fetestexcept(int); + +int fegetround(void); +int fesetround(int); + +int fegetenv(fenv_t *); +int feholdexcept(fenv_t *); +int fesetenv(const fenv_t *); +int feupdateenv(const fenv_t *); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/include/float.h b/include/float.h new file mode 100644 index 00000000..ef91f37d --- /dev/null +++ b/include/float.h @@ -0,0 +1,34 @@ +#ifndef _FLOAT_H +#define _FLOAT_H + +#define FLT_RADIX 2 + +#define FLT_MIN 1.17549435e-38F +#define FLT_MAX 3.40282347e+38F +#define FLT_EPSILON 1.19209290e-07F + +#define FLT_MANT_DIG 24 +#define FLT_MIN_EXP (-125) +#define FLT_MAX_EXP 128 + +#define FLT_DIG 6 +#define FLT_MIN_10_EXP (-37) +#define FLT_MAX_10_EXP 38 + +#define DBL_MIN 2.2250738585072014e-308 +#define DBL_MAX 1.7976931348623157e+308 +#define DBL_EPSILON 2.2204460492503131e-16 + +#define DBL_MANT_DIG 53 +#define DBL_MIN_EXP (-1021) +#define DBL_MAX_EXP 1024 + +#define DBL_DIG 15 +#define DBL_MIN_10_EXP (-307) +#define DBL_MAX_10_EXP 308 + +#include <bits/float.h> + +#define DECIMAL_DIG LDBL_DIG + +#endif diff --git a/include/fnmatch.h b/include/fnmatch.h new file mode 100644 index 00000000..b7aee504 --- /dev/null +++ b/include/fnmatch.h @@ -0,0 +1,25 @@ +#ifndef	_FNMATCH_H +#define	_FNMATCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define	FNM_PATHNAME 0x1 +#define	FNM_NOESCAPE 0x2 +#define	FNM_PERIOD   0x4 + +#ifdef _GNU_SOURCE +#define	FNM_CASEFOLD 0x10 +#endif + +#define	FNM_NOMATCH 1 +#define FNM_NOSYS   (-1) + +int fnmatch(const char *, const char *, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/ftw.h b/include/ftw.h new file mode 100644 index 00000000..8d31c6d9 --- /dev/null +++ b/include/ftw.h @@ -0,0 +1,31 @@ +#ifndef _FTW_H +#define	_FTW_H + +/* Normally we do not nest header includes. However useless bloat + * like ftw may be treated as a special case. Otherwise we would + * have to deal with duplicating all the stat.h mess. */ +#include <sys/stat.h> + +#define FTW_F   1 +#define FTW_D   2 +#define FTW_DNR 3 +#define FTW_NS  4 +#define FTW_SL  5 +#define FTW_DP  6 +#define FTW_SLN 7 + +#define FTW_PHYS  1 +#define FTW_MOUNT 2 +#define FTW_CHDIR 4 +#define FTW_DEPTH 8 + +struct FTW +{ +	int base; +	int level; +}; + +int ftw(const char *, int (*)(const char *, const struct stat *, int), int); +int nftw(const char *, int (*)(const char *, const struct stat *, int, struct FTW *), int, int); + +#endif diff --git a/include/getopt.h b/include/getopt.h new file mode 100644 index 00000000..0de05aef --- /dev/null +++ b/include/getopt.h @@ -0,0 +1,33 @@ +#ifndef _GETOPT_H +#define _GETOPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +int getopt(int, char * const [], const char *); +extern char *optarg; +extern int optind, opterr, optopt; + +#ifdef _GNU_SOURCE +struct option +{ +	const char *name; +	int has_arg; +	int *flag; +	int val; +}; + +int getopt_long(int, char *const *, const char *, const struct option *, int *); +int getopt_long_only(int, char *const *, const char *, const struct option *, int *); + +#define no_argument        0 +#define required_argument  1 +#define optional_argument  2 +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/glob.h b/include/glob.h new file mode 100644 index 00000000..185912df --- /dev/null +++ b/include/glob.h @@ -0,0 +1,41 @@ +#ifndef	_GLOB_H +#define	_GLOB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t + +#include <bits/alltypes.h> + +typedef struct { +	size_t gl_pathc; +	char **gl_pathv; +	size_t gl_offs; +	int __dummy1; +	void *__dummy2[5]; +} glob_t; + +int  glob(const char *, int, int (*)(const char *, int), glob_t *); +void globfree(glob_t *); + +#define GLOB_ERR      0x01 +#define GLOB_MARK     0x02 +#define GLOB_NOSORT   0x04 +#define GLOB_DOOFFS   0x08 +#define GLOB_NOCHECK  0x10 +#define GLOB_APPEND   0x20 +#define GLOB_NOESCAPE 0x40 +#define	GLOB_PERIOD   0x80 + +#define GLOB_NOSPACE 1 +#define GLOB_ABORTED 2 +#define GLOB_NOMATCH 3 +#define GLOB_NOSYS   4 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/grp.h b/include/grp.h new file mode 100644 index 00000000..d4a3526a --- /dev/null +++ b/include/grp.h @@ -0,0 +1,35 @@ +#ifndef	_GRP_H +#define	_GRP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t +#define __NEED_gid_t + +#include <bits/alltypes.h> + +struct group +{ +	char *gr_name; +	char *gr_passwd; +	gid_t gr_gid; +	char **gr_mem; +}; + +struct group  *getgrgid(gid_t); +struct group  *getgrnam(const char *); + +int getgrgid_r(gid_t, struct group *, char *, size_t, struct group **); +int getgrnam_r(const char *, struct group *, char *, size_t, struct group **); + +struct group  *getgrent(void); +void           endgrent(void); +void           setgrent(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/iconv.h b/include/iconv.h new file mode 100644 index 00000000..f2ccaf8c --- /dev/null +++ b/include/iconv.h @@ -0,0 +1,22 @@ +#ifndef _ICONV_H +#define _ICONV_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t + +#include <bits/alltypes.h> + +typedef void *iconv_t; + +iconv_t iconv_open(const char *, const char *); +size_t iconv(iconv_t, char **, size_t *, char **, size_t *); +int iconv_close(iconv_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/inttypes.h b/include/inttypes.h new file mode 100644 index 00000000..13ba6e0f --- /dev/null +++ b/include/inttypes.h @@ -0,0 +1,227 @@ +#ifndef _INTTYPES_H +#define _INTTYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +#define __NEED_wchar_t +#include <bits/alltypes.h> + +typedef struct { intmax_t quot, rem; } imaxdiv_t; + +intmax_t imaxabs(intmax_t); +imaxdiv_t imaxdiv(intmax_t, intmax_t); + +intmax_t strtoimax(const char *, char **, int); +uintmax_t strtoumax(const char *, char **, int); + +intmax_t wcstoimax(const wchar_t *, wchar_t **, int); +uintmax_t wcstoumax(const wchar_t *, wchar_t **, int); + +#if !defined __cplusplus || defined __STDC_FORMAT_MACROS + +#define __PRI64  "ll" +#define __PRIPTR "l" + +#define PRId8  "d" +#define PRId16 "d" +#define PRId32 "d" +#define PRId64 __PRI64 "d" + +#define PRIdLEAST8  "d" +#define PRIdLEAST16 "d" +#define PRIdLEAST32 "d" +#define PRIdLEAST64 __PRI64 "d" + +#define PRIdFAST8  "d" +#define PRIdFAST16 "d" +#define PRIdFAST32 "d" +#define PRIdFAST64 __PRI64 "d" + +#define PRIi8  "i" +#define PRIi16 "i" +#define PRIi32 "i" +#define PRIi64 __PRI64 "i" + +#define PRIiLEAST8  "i" +#define PRIiLEAST16 "i" +#define PRIiLEAST32 "i" +#define PRIiLEAST64 __PRI64 "i" + +#define PRIiFAST8  "i" +#define PRIiFAST16 "i" +#define PRIiFAST32 "i" +#define PRIiFAST64 __PRI64 "i" + +#define PRIo8  "o" +#define PRIo16 "o" +#define PRIo32 "o" +#define PRIo64 __PRI64 "o" + +#define PRIoLEAST8  "o" +#define PRIoLEAST16 "o" +#define PRIoLEAST32 "o" +#define PRIoLEAST64 __PRI64 "o" + +#define PRIoFAST8  "o" +#define PRIoFAST16 "o" +#define PRIoFAST32 "o" +#define PRIoFAST64 __PRI64 "o" + +#define PRIu8  "u" +#define PRIu16 "u" +#define PRIu32 "u" +#define PRIu64 __PRI64 "u" + +#define PRIuLEAST8  "u" +#define PRIuLEAST16 "u" +#define PRIuLEAST32 "u" +#define PRIuLEAST64 __PRI64 "u" + +#define PRIuFAST8  "u" +#define PRIuFAST16 "u" +#define PRIuFAST32 "u" +#define PRIuFAST64 __PRI64 "u" + +#define PRIx8  "x" +#define PRIx16 "x" +#define PRIx32 "x" +#define PRIx64 __PRI64 "x" + +#define PRIxLEAST8  "x" +#define PRIxLEAST16 "x" +#define PRIxLEAST32 "x" +#define PRIxLEAST64 __PRI64 "x" + +#define PRIxFAST8  "x" +#define PRIxFAST16 "x" +#define PRIxFAST32 "x" +#define PRIxFAST64 __PRI64 "x" + +#define PRIX8  "X" +#define PRIX16 "X" +#define PRIX32 "X" +#define PRIX64 __PRI64 "X" + +#define PRIXLEAST8  "X" +#define PRIXLEAST16 "X" +#define PRIXLEAST32 "X" +#define PRIXLEAST64 __PRI64 "X" + +#define PRIXFAST8  "X" +#define PRIXFAST16 "X" +#define PRIXFAST32 "X" +#define PRIXFAST64 __PRI64 "X" + +#define PRIdMAX __PRI64 "d" +#define PRIiMAX __PRI64 "i" +#define PRIoMAX __PRI64 "o" +#define PRIuMAX __PRI64 "u" +#define PRIxMAX __PRI64 "x" +#define PRIXMAX __PRI64 "X" + +#define PRIdPTR __PRIPTR "d" +#define PRIiPTR __PRIPTR "i" +#define PRIoPTR __PRIPTR "o" +#define PRIuPTR __PRIPTR "u" +#define PRIxPTR __PRIPTR "x" +#define PRIXPTR __PRIPTR "X" + +#define SCNd8   "hhd" +#define SCNd16  "hd" +#define SCNd32  "d" +#define SCNd64  __PRI64 "d" + +#define SCNdLEAST8  "hhd" +#define SCNdLEAST16 "hd" +#define SCNdLEAST32 "d" +#define SCNdLEAST64 __PRI64 "d" + +#define SCNdFAST8  "hhd" +#define SCNdFAST16 __PRIPTR "d" +#define SCNdFAST32 __PRIPTR "d" +#define SCNdFAST64 __PRI64 "d" + +#define SCNi8   "hhi" +#define SCNi16  "hi" +#define SCNi32  "i" +#define SCNi64  __PRI64 "i" + +#define SCNiLEAST8  "hhi" +#define SCNiLEAST16 "hi" +#define SCNiLEAST32 "i" +#define SCNiLEAST64 __PRI64 "i" + +#define SCNiFAST8  "hhi" +#define SCNiFAST16 __PRIPTR "i" +#define SCNiFAST32 __PRIPTR "i" +#define SCNiFAST64 __PRI64 "i" + +#define SCNu8   "hhu" +#define SCNu16  "hu" +#define SCNu32  "u" +#define SCNu64  __PRI64 "u" + +#define SCNuLEAST8  "hhu" +#define SCNuLEAST16 "hu" +#define SCNuLEAST32 "u" +#define SCNuLEAST64 __PRI64 "u" + +#define SCNuFAST8 "hhu" +#define SCNuFAST16 __PRIPTR "u" +#define SCNuFAST32 __PRIPTR "u" +#define SCNuFAST64 __PRI64 "u" + +#define SCNo8   "hho" +#define SCNo16  "ho" +#define SCNo32  "o" +#define SCNo64  __PRI64 "o" + +#define SCNoLEAST8  "hho" +#define SCNoLEAST16 "ho" +#define SCNoLEAST32 "o" +#define SCNoLEAST64 __PRI64 "o" + +#define SCNoFAST8  "hho" +#define SCNoFAST16 __PRIPTR "o" +#define SCNoFAST32 __PRIPTR "o" +#define SCNoFAST64 __PRI64 "o" + +#define SCNx8   "hhx" +#define SCNx16  "hx" +#define SCNx32  "x" +#define SCNx64  __PRI64 "x" + +#define SCNxLEAST8  "hhx" +#define SCNxLEAST16 "hx" +#define SCNxLEAST32 "x" +#define SCNxLEAST64 __PRI64 "x" + +#define SCNxFAST8  "hhx" +#define SCNxFAST16 __PRIPTR "x" +#define SCNxFAST32 __PRIPTR "x" +#define SCNxFAST64 __PRI64 "x" + +#define SCNdMAX __PRI64 "d" +#define SCNiMAX __PRI64 "i" +#define SCNoMAX __PRI64 "o" +#define SCNuMAX __PRI64 "u" +#define SCNxMAX __PRI64 "x" + +#define SCNdPTR __PRIPTR "d" +#define SCNiPTR __PRIPTR "i" +#define SCNoPTR __PRIPTR "o" +#define SCNuPTR __PRIPTR "u" +#define SCNxPTR __PRIPTR "x" + +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/langinfo.h b/include/langinfo.h new file mode 100644 index 00000000..4d9e0997 --- /dev/null +++ b/include/langinfo.h @@ -0,0 +1,85 @@ +#ifndef _LANGINFO_H +#define _LANGINFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_nl_item + +#include <bits/alltypes.h> + +#define ABDAY_1 0x20000 +#define ABDAY_2 0x20001 +#define ABDAY_3 0x20002 +#define ABDAY_4 0x20003 +#define ABDAY_5 0x20004 +#define ABDAY_6 0x20005 +#define ABDAY_7 0x20006 + +#define DAY_1 0x20007 +#define DAY_2 0x20008 +#define DAY_3 0x20009 +#define DAY_4 0x2000A +#define DAY_5 0x2000B +#define DAY_6 0x2000C +#define DAY_7 0x2000D + +#define ABMON_1 0x2000E +#define ABMON_2 0x2000F +#define ABMON_3 0x20010 +#define ABMON_4 0x20011 +#define ABMON_5 0x20012 +#define ABMON_6 0x20013 +#define ABMON_7 0x20014 +#define ABMON_8 0x20015 +#define ABMON_9 0x20016 +#define ABMON_10 0x20017 +#define ABMON_11 0x20018 +#define ABMON_12 0x20019 + +#define MON_1 0x2001A +#define MON_2 0x2001B +#define MON_3 0x2001C +#define MON_4 0x2001D +#define MON_5 0x2001E +#define MON_6 0x2001F +#define MON_7 0x20020 +#define MON_8 0x20021 +#define MON_9 0x20022 +#define MON_10 0x20023 +#define MON_11 0x20024 +#define MON_12 0x20025 + +#define AM_STR 0x20026 +#define PM_STR 0x20027 + +#define D_T_FMT 0x20028 +#define D_FMT 0x20029 +#define T_FMT 0x2002A +#define T_FMT_AMPM 0x2002B + +#define ERA 0x2002C +#define ERA_D_FMT 0x2002E +#define ALT_DIGITS 0x2002F +#define ERA_D_T_FMT 0x20030 +#define ERA_T_FMT 0x20031 + +#define CODESET 14 + +#define CRNCYSTR 0x4000F + +#define RADIXCHAR 0x10000 +#define THOUSEP 0x10001 +#define YESEXPR 0x50000 +#define NOEXPR 0x50001 +#define YESSTR 0x50002 +#define NOSTR 0x50003 + +char *nl_langinfo(nl_item); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/libgen.h b/include/libgen.h new file mode 100644 index 00000000..7c7fd9c6 --- /dev/null +++ b/include/libgen.h @@ -0,0 +1,15 @@ +#ifndef _LIBGEN_H +#define _LIBGEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +char *dirname(char *); +char *basename(char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/libintl.h b/include/libintl.h new file mode 100644 index 00000000..a2dada67 --- /dev/null +++ b/include/libintl.h @@ -0,0 +1,25 @@ +#ifndef _LIBINTL_H +#define _LIBINTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __USE_GNU_GETTEXT 1 +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 1 : -1) + +char *gettext(const char *); +char *dgettext(const char *, const char *); +char *dcgettext(const char *, const char *, int); +char *ngettext(const char *, const char *, unsigned long); +char *dngettext(const char *, const char *, const char *, unsigned long); +char *dcngettext(const char *, const char *, const char *, unsigned long, int); +char *textdomain(const char *); +char *bindtextdomain (const char *, const char *); +char *bind_textdomain_codeset(const char *, const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/limits.h b/include/limits.h new file mode 100644 index 00000000..4499afbf --- /dev/null +++ b/include/limits.h @@ -0,0 +1,101 @@ +#ifndef _LIMITS_H +#define _LIMITS_H + +/* Most limits are system-specific */ + +#include <bits/limits.h> + +/* Some universal constants... */ + +#define CHAR_BIT 8 +#define SCHAR_MIN (-128) +#define SCHAR_MAX 127 +#define UCHAR_MAX 255 +#define CHAR_MIN (-128) +#define CHAR_MAX 127 +#define SSIZE_MAX LONG_MAX + +#define MB_LEN_MAX 4 +#define TZNAME_MAX 6 +#define TTY_NAME_MAX 20 +#define HOST_NAME_MAX 255 + +/* Implementation choices... */ + +#define PTHREAD_KEYS_MAX  1024 +#define PTHREAD_STACK_MIN (2*PAGE_SIZE) + +/* Arbitrary numbers... */ + +#define BC_BASE_MAX 99 +#define BC_DIM_MAX 2048 +#define BC_SCALE_MAX 99 +#define BC_STRING_MAX 1000 +#define CHARCLASS_NAME_MAX 14 +#define COLL_WEIGHTS_MAX 2 +#define EXPR_NEST_MAX 32 +#define LINE_MAX 4096 +#define RE_DUP_MAX 255 + +#define NL_ARGMAX 9 +#define NL_LANGMAX 32 +#define NL_MSGMAX 32767 +#define NL_NMAX (MB_LEN_MAX*4) +#define NL_SETMAX 255 +#define NL_TEXTMAX 2048 + +/* POSIX/SUS requirements follow. These numbers come directly + * from SUS and have nothing to do with the host system. */ + +#define _POSIX_AIO_LISTIO_MAX   2 +#define _POSIX_AIO_MAX          1 +#define _POSIX_ARG_MAX          4096 +#define _POSIX_CHILD_MAX        25 +#define _POSIX_DELAYTIMER_MAX   32 +#define _POSIX_HOST_NAME_MAX    255 +#define _POSIX_LINK_MAX         8 +#define _POSIX_LOGIN_NAME_MAX   9 +#define _POSIX_MAX_CANON        255 +#define _POSIX_MAX_INPUT        255 +#define _POSIX_MQ_OPEN_MAX      8 +#define _POSIX_MQ_PRIO_MAX      32 +#define _POSIX_NAME_MAX         14 +#define _POSIX_NGROUPS_MAX      8 +#define _POSIX_OPEN_MAX         20 +#define _POSIX_PATH_MAX         256 +#define _POSIX_PIPE_BUF         512 +#define _POSIX_RE_DUP_MAX       255 +#define _POSIX_RTSIG_MAX        8 +#define _POSIX_SEM_NSEMS_MAX    256 +#define _POSIX_SEM_VALUE_MAX    32767 +#define _POSIX_SIGQUEUE_MAX     32 +#define _POSIX_SSIZE_MAX        32767 +#define _POSIX_STREAM_MAX       8 +#define _POSIX_SS_REPL_MAX      4 +#define _POSIX_SYMLINK_MAX      255 +#define _POSIX_SYMLOOP_MAX      8 +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 +#define _POSIX_THREAD_KEYS_MAX  128 +#define _POSIX_THREAD_THREADS_MAX 64 +#define _POSIX_TIMER_MAX        32 +#define _POSIX_TRACE_EVENT_NAME_MAX 30 +#define _POSIX_TRACE_NAME_MAX   8 +#define _POSIX_TRACE_SYS_MAX    8 +#define _POSIX_TRACE_USER_EVENT_MAX 32 +#define _POSIX_TTY_NAME_MAX     9 +#define _POSIX_TZNAME_MAX       6 +#define _POSIX2_BC_BASE_MAX     99 +#define _POSIX2_BC_DIM_MAX      2048 +#define _POSIX2_BC_SCALE_MAX    99 +#define _POSIX2_BC_STRING_MAX   1000 +#define _POSIX2_CHARCLASS_NAME_MAX 14 +#define _POSIX2_COLL_WEIGHTS_MAX 2 +#define _POSIX2_EXPR_NEST_MAX   32 +#define _POSIX2_LINE_MAX        2048 +#define _POSIX2_RE_DUP_MAX      255 + +#define _XOPEN_IOV_MAX          16 +#define _XOPEN_NAME_MAX         255 +#define _XOPEN_PATH_MAX         1024 + +#endif diff --git a/include/linux/loop.h b/include/linux/loop.h new file mode 100644 index 00000000..41aad407 --- /dev/null +++ b/include/linux/loop.h @@ -0,0 +1,69 @@ +#ifndef _LINUX_LOOP_H +#define _LINUX_LOOP_H + +#include <stdint.h> + +#define LO_NAME_SIZE	64 +#define LO_KEY_SIZE	32 + +enum { +	LO_FLAGS_READ_ONLY	= 1, +	LO_FLAGS_USE_AOPS	= 2, +	LO_FLAGS_AUTOCLEAR	= 4, +}; + +struct loop_info { +	int                lo_number; +	long               lo_device; +	unsigned long	   lo_inode; +	long               lo_rdevice; +	int		   lo_offset; +	int		   lo_encrypt_type; +	int		   lo_encrypt_key_size; +	int		   lo_flags; +	char		   lo_name[LO_NAME_SIZE]; +	unsigned char	   lo_encrypt_key[LO_KEY_SIZE]; +	unsigned long	   lo_init[2]; +	char		   reserved[4]; +}; + +struct loop_info64 { +	uint64_t	   lo_device; +	uint64_t	   lo_inode; +	uint64_t	   lo_rdevice; +	uint64_t	   lo_offset; +	uint64_t	   lo_sizelimit; +	uint32_t	   lo_number; +	uint32_t	   lo_encrypt_type; +	uint32_t	   lo_encrypt_key_size; +	uint32_t	   lo_flags; +	uint8_t		   lo_file_name[LO_NAME_SIZE]; +	uint8_t		   lo_crypt_name[LO_NAME_SIZE]; +	uint8_t		   lo_encrypt_key[LO_KEY_SIZE]; +	uint64_t	   lo_init[2]; +}; + + +#define LO_CRYPT_NONE		0 +#define LO_CRYPT_XOR		1 +#define LO_CRYPT_DES		2 +#define LO_CRYPT_FISH2		3 +#define LO_CRYPT_BLOW		4 +#define LO_CRYPT_CAST128	5 +#define LO_CRYPT_IDEA		6 +#define LO_CRYPT_DUMMY		9 +#define LO_CRYPT_SKIPJACK	10 +#define LO_CRYPT_CRYPTOAPI	18 +#define MAX_LO_CRYPT		20 + + +#define LOOP_SET_FD		0x4C00 +#define LOOP_CLR_FD		0x4C01 +#define LOOP_SET_STATUS		0x4C02 +#define LOOP_GET_STATUS		0x4C03 +#define LOOP_SET_STATUS64	0x4C04 +#define LOOP_GET_STATUS64	0x4C05 +#define LOOP_CHANGE_FD		0x4C06 +#define LOOP_SET_CAPACITY	0x4C07 + +#endif diff --git a/include/linux/version.h b/include/linux/version.h new file mode 100644 index 00000000..e6a89ef2 --- /dev/null +++ b/include/linux/version.h @@ -0,0 +1,2 @@ +#define LINUX_VERSION_CODE 132638 +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) diff --git a/include/locale.h b/include/locale.h new file mode 100644 index 00000000..70230237 --- /dev/null +++ b/include/locale.h @@ -0,0 +1,84 @@ +#ifndef	_LOCALE_H +#define	_LOCALE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#undef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void*)0) +#endif + +#define LC_CTYPE    0 +#define LC_NUMERIC  1 +#define LC_TIME     2 +#define LC_COLLATE  3 +#define LC_MONETARY 4 +#define LC_MESSAGES 5 +#define LC_ALL      6 + +struct lconv { +	char *decimal_point; +	char *thousands_sep; +	char *grouping; + +	char *int_curr_symbol; +	char *currency_symbol; +	char *mon_decimal_point; +	char *mon_thousands_sep; +	char *mon_grouping; +	char *positive_sign; +	char *negative_sign; +	char int_frac_digits; +	char frac_digits; +	char p_cs_precedes; +	char p_sep_by_space; +	char n_cs_precedes; +	char n_sep_by_space; +	char p_sign_posn; +	char n_sign_posn; +	char int_p_cs_precedes; +	char int_p_sep_by_space; +	char int_n_cs_precedes; +	char int_n_sep_by_space; +	char int_p_sign_posn; +	char int_n_sign_posn; +}; + + +char *setlocale (int, const char *); +struct lconv *localeconv(void); + + +#if 1 + +#define __NEED_locale_t + +#include <bits/alltypes.h> + +#define LC_GLOBAL_LOCALE ((locale_t)-1) + +#define LC_CTYPE_MASK    (1<<LC_CTYPE) +#define LC_NUMERIC_MASK  (1<<LC_NUMERIC) +#define LC_TIME_MASK     (1<<LC_TIME) +#define LC_COLLATE_MASK  (1<<LC_COLLATE) +#define LC_MONETARY_MASK (1<<LC_MONETARY) +#define LC_MESSAGES_MASK (1<<LC_MESSAGES) +#define LC_ALL_MASK      0x7fffffff + +locale_t duplocale(locale_t); +void freelocale(locale_t); +locale_t newlocale(int, const char *, locale_t); +locale_t uselocale(locale_t); + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/malloc.h b/include/malloc.h new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/malloc.h diff --git a/include/math.h b/include/math.h new file mode 100644 index 00000000..cc9befb7 --- /dev/null +++ b/include/math.h @@ -0,0 +1,300 @@ +#ifndef _MATH_H +#define _MATH_H + +#define __NEED___uint16_t +#define __NEED___uint32_t +#define __NEED___uint64_t +#include <bits/alltypes.h> + +#define M_E             2.7182818284590452354   /* e */ +#define M_LOG2E         1.4426950408889634074   /* log_2 e */ +#define M_LOG10E        0.43429448190325182765  /* log_10 e */ +#define M_LN2           0.69314718055994530942  /* log_e 2 */ +#define M_LN10          2.30258509299404568402  /* log_e 10 */ +#define M_PI            3.14159265358979323846  /* pi */ +#define M_PI_2          1.57079632679489661923  /* pi/2 */ +#define M_PI_4          0.78539816339744830962  /* pi/4 */ +#define M_1_PI          0.31830988618379067154  /* 1/pi */ +#define M_2_PI          0.63661977236758134308  /* 2/pi */ +#define M_2_SQRTPI      1.12837916709551257390  /* 2/sqrt(pi) */ +#define M_SQRT2         1.41421356237309504880  /* sqrt(2) */ +#define M_SQRT1_2       0.70710678118654752440  /* 1/sqrt(2) */ + +#define __MAKE_FLOAT(i) (((union { int __i; float __f; }){ .__i = i }).__f) + +#define NAN       __MAKE_FLOAT(0x7fc00000) +#define INFINITY  __MAKE_FLOAT(0x7f800000) + +#define HUGE_VALF INFINITY +#define HUGE_VAL  ((double)INFINITY) +#define HUGE_VALL ((long double)INFINITY) + +#define MAXFLOAT  __MAKE_FLOAT(0x7f7fffff) + +#define MATH_ERRNO  1 +#define MATH_EXCEPT 2 +#define math_errhandling 2 + +#define FP_ILOGBNAN (((unsigned)-1)>>1) +#define FP_ILOGB0 (~FP_ILOGBNAN) + +#define FP_NAN       0 +#define FP_INFINITE  1 +#define FP_ZERO      2 +#define FP_SUBNORMAL 3 +#define FP_NORMAL    4 + +int __fpclassifyf(float); +int __fpclassify(double); +int __fpclassifyl(long double); + +#define fpclassify(x) ( \ +	sizeof(x) == sizeof(float) ? __fpclassifyf(x) : \ +	sizeof(x) == sizeof(double) ? __fpclassify(x) : \ +	__fpclassifyl(x) ) + +#define isinf(x)    (fpclassify(x) == FP_INFINITE) +#define isnan(x)    (fpclassify(x) == FP_NAN) +#define isnormal(x) (fpclassify(x) == FP_NORMAL) +#define isfinite(x) (fpclassify(x) > FP_INFINITE) + +double      acos(double); +float       acosf(float); +long double acosl(long double); + +double      acosh(double); +float       acoshf(float); +long double acoshl(long double); + +double      asin(double); +float       asinf(float); +long double asinl(long double); + +double      asinh(double); +float       asinhf(float); +long double asinhl(long double); + +double      atan(double); +float       atanf(float); +long double atanl(long double); + +double      atan2(double, double); +float       atan2f(float, float); +long double atan2l(long double, long double); + +double      atanh(double); +float       atanhf(float); +long double atanhl(long double); + +double      cbrt(double); +float       cbrtf(float); +long double cbrtl(long double); + +double      ceil(double); +float       ceilf(float); +long double ceill(long double); + +double      copysign(double, double); +float       copysignf(float, float); +long double copysignl(long double, long double); + +double      cos(double); +float       cosf(float); +long double cosl(long double); + +double      cosh(double); +float       coshf(float); +long double coshl(long double); + +double      erf(double); +float       erff(float); +long double erfl(long double); + +double      erfc(double); +float       erfcf(float); +long double erfcl(long double); + +double      exp(double); +float       expf(float); +long double expl(long double); + +double      exp2(double); +float       exp2f(float); +long double exp2l(long double); + +double      expm1(double); +float       expm1f(float); +long double expm1l(long double); + +double      fabs(double); +float       fabsf(float); +long double fabsl(long double); + +double      fdim(double, double); +float       fdimf(float, float); +long double fdiml(long double, long double); + +double      floor(double); +float       floorf(float); +long double floorl(long double); + +double      fma(double, double, double); +float       fmaf(float, float, float); +long double fmal(long double, long double, long double); + +double      fmax(double, double); +float       fmaxf(float, float); +long double fmaxl(long double, long double); + +double      fmin(double, double); +float       fminf(float, float); +long double fminl(long double, long double); + +double      fmod(double, double); +float       fmodf(float, float); +long double fmodl(long double, long double); + +double      frexp(double, int *); +float       frexpf(float value, int *); +long double frexpl(long double value, int *); + +double      hypot(double, double); +float       hypotf(float, float); +long double hypotl(long double, long double); + +int         ilogb(double); +int         ilogbf(float); +int         ilogbl(long double); + +double      ldexp(double, int); +float       ldexpf(float, int); +long double ldexpl(long double, int); + +double      lgamma(double); +float       lgammaf(float); +long double lgammal(long double); + +long long   llrint(double); +long long   llrintf(float); +long long   llrintl(long double); + +long long   llround(double); +long long   llroundf(float); +long long   llroundl(long double); + +double      log(double); +float       logf(float); +long double logl(long double); + +double      log10(double); +float       log10f(float); +long double log10l(long double); + +double      log1p(double); +float       log1pf(float); +long double log1pl(long double); + +double      log2(double); +float       log2f(float); +long double log2l(long double); + +double      logb(double); +float       logbf(float); +long double logbl(long double); + +long        lrint(double); +long        lrintf(float); +long        lrintl(long double); + +long        lround(double); +long        lroundf(float); +long        lroundl(long double); + +double      modf(double, double *); +float       modff(float, float *); +long double modfl(long double, long double *); + +double      nan(const char *); +float       nanf(const char *); +long double nanl(const char *); + +double      nearbyint(double); +float       nearbyintf(float); +long double nearbyintl(long double); + +double      nextafter(double, double); +float       nextafterf(float, float); +long double nextafterl(long double, long double); + +double      nexttoward(double, long double); +float       nexttowardf(float, long double); +long double nexttowardl(long double, long double); + +double      pow(double, double); +float       powf(float, float); +long double powl(long double, long double); + +double      remainder(double, double); +float       remainderf(float, float); +long double remainderl(long double, long double); + +double      remquo(double, double, int *); +float       remquof(float, float, int *); +long double remquol(long double, long double, int *); + +double      rint(double); +float       rintf(float); +long double rintl(long double); + +double      round(double); +float       roundf(float); +long double roundl(long double); + +double      scalbln(double, long); +float       scalblnf(float, long); +long double scalblnl(long double, long); + +double      scalbn(double, int); +float       scalbnf(float, int); +long double scalbnl(long double, int); + +double      sin(double); +float       sinf(float); +long double sinl(long double); + +double      sinh(double); +float       sinhf(float); +long double sinhl(long double); + +double      sqrt(double); +float       sqrtf(float); +long double sqrtl(long double); + +double      tan(double); +float       tanf(float); +long double tanl(long double); + +double      tanh(double); +float       tanhf(float); +long double tanhl(long double); + +double      tgamma(double); +float       tgammaf(float); +long double tgammal(long double); + +double      trunc(double); +float       truncf(float); +long double truncl(long double); + +/* XSI stuff */ +double      j0(double); +double      j1(double); +double      jn(int, double); +double      scalb(double, double); +double      y0(double); +double      y1(double); +double      yn(int, double); + +extern int signgam; + +#endif diff --git a/include/mntent.h b/include/mntent.h new file mode 100644 index 00000000..c0fed7fc --- /dev/null +++ b/include/mntent.h @@ -0,0 +1,43 @@ +#ifndef _MNTENT_H +#define _MNTENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_FILE +#include <bits/alltypes.h> + +#define MOUNTED "/etc/mtab" + +#define MNTTYPE_IGNORE	"ignore" +#define MNTTYPE_NFS	"nfs" +#define MNTTYPE_SWAP	"swap" +#define MNTOPT_DEFAULTS	"defaults" +#define MNTOPT_RO	"ro" +#define MNTOPT_RW	"rw" +#define MNTOPT_SUID	"suid" +#define MNTOPT_NOSUID	"nosuid" +#define MNTOPT_NOAUTO	"noauto" + +struct mntent +{ +	char *mnt_fsname; +	char *mnt_dir; +	char *mnt_type; +	char *mnt_opts; +	int mnt_freq; +	int mnt_passno; +}; + +FILE *setmntent(const char *, const char *); +int endmntent(FILE *); +struct mntent *getmntent(FILE *); +int addmntent(FILE *, const struct mntent *); +char *hasmntopt(const struct mntent *, const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/net/ethernet.h b/include/net/ethernet.h new file mode 100644 index 00000000..a536502d --- /dev/null +++ b/include/net/ethernet.h @@ -0,0 +1,47 @@ +#ifndef __NET_ETHERNET_H +#define __NET_ETHERNET_H 1 + +#include <stdint.h> +#include <sys/types.h> +#include <netinet/if_ether.h> + +struct ether_addr { +	uint8_t ether_addr_octet[ETH_ALEN]; +}; + +struct ether_header { +	uint8_t  ether_dhost[ETH_ALEN]; +	uint8_t  ether_shost[ETH_ALEN]; +	uint16_t ether_type; +}; + +#define	ETHERTYPE_PUP		0x0200 +#define ETHERTYPE_SPRITE	0x0500 +#define	ETHERTYPE_IP		0x0800 +#define	ETHERTYPE_ARP		0x0806 +#define	ETHERTYPE_REVARP	0x8035 +#define ETHERTYPE_AT		0x809B +#define ETHERTYPE_AARP		0x80F3 +#define	ETHERTYPE_VLAN		0x8100 +#define ETHERTYPE_IPX		0x8137 +#define	ETHERTYPE_IPV6		0x86dd +#define ETHERTYPE_LOOPBACK	0x9000 + + +#define	ETHER_ADDR_LEN	ETH_ALEN +#define	ETHER_TYPE_LEN	2 +#define	ETHER_CRC_LEN	4 +#define	ETHER_HDR_LEN	ETH_HLEN +#define	ETHER_MIN_LEN	(ETH_ZLEN + ETHER_CRC_LEN) +#define	ETHER_MAX_LEN	(ETH_FRAME_LEN + ETHER_CRC_LEN) + +#define	ETHER_IS_VALID_LEN(foo)	\ +	((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) + +#define	ETHERTYPE_TRAIL		0x1000 +#define	ETHERTYPE_NTRAILER	16 + +#define	ETHERMTU	ETH_DATA_LEN +#define	ETHERMIN	(ETHER_MIN_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN) + +#endif diff --git a/include/net/if.h b/include/net/if.h new file mode 100644 index 00000000..2ae5f89e --- /dev/null +++ b/include/net/if.h @@ -0,0 +1,122 @@ +#ifndef _NET_IF_H +#define _NET_IF_H + +#define IF_NAMESIZE 16 + +struct if_nameindex +{ +	unsigned int if_index; +	char *if_name; +}; + +unsigned int if_nametoindex (const char *); +char *if_indextoname (unsigned int, char *); +struct if_nameindex *if_nameindex (void); +void if_freenameindex (struct if_nameindex *); + + + + +#ifdef _GNU_SOURCE + +#include <sys/socket.h> + +#define IFF_UP	0x1 +#define IFF_BROADCAST 0x2 +#define IFF_DEBUG 0x4 +#define IFF_LOOPBACK 0x8 +#define IFF_POINTOPOINT 0x10 +#define IFF_NOTRAILERS 0x20 +#define IFF_RUNNING 0x40 +#define IFF_NOARP 0x80 +#define IFF_PROMISC 0x100 +#define IFF_ALLMULTI 0x200 +#define IFF_MASTER 0x400 +#define IFF_SLAVE 0x800 +#define IFF_MULTICAST 0x1000 +#define IFF_PORTSEL 0x2000 +#define IFF_AUTOMEDIA 0x4000 +#define IFF_DYNAMIC 0x8000 + +struct ifaddr { +	struct sockaddr ifa_addr; +	union { +		struct sockaddr	ifu_broadaddr; +		struct sockaddr	ifu_dstaddr; +	} ifa_ifu; +	struct iface *ifa_ifp; +	struct ifaddr *ifa_next; +}; + +#define ifa_broadaddr	ifa_ifu.ifu_broadaddr +#define ifa_dstaddr	ifa_ifu.ifu_dstaddr + +struct ifmap { +	unsigned long int mem_start; +	unsigned long int mem_end; +	unsigned short int base_addr; +	unsigned char irq; +	unsigned char dma; +	unsigned char port; +}; + +#define IFHWADDRLEN	6 +#define IFNAMSIZ	IF_NAMESIZE + +struct ifreq { +	union { +		char ifrn_name[IFNAMSIZ]; +	} ifr_ifrn; +	union { +		struct sockaddr ifru_addr; +		struct sockaddr ifru_dstaddr; +		struct sockaddr ifru_broadaddr; +		struct sockaddr ifru_netmask; +		struct sockaddr ifru_hwaddr; +		short int ifru_flags; +		int ifru_ivalue; +		int ifru_mtu; +		struct ifmap ifru_map; +		char ifru_slave[IFNAMSIZ]; +		char ifru_newname[IFNAMSIZ]; +		void *ifru_data; +	} ifr_ifru; +}; + +#define ifr_name	ifr_ifrn.ifrn_name +#define ifr_hwaddr	ifr_ifru.ifru_hwaddr +#define ifr_addr	ifr_ifru.ifru_addr +#define ifr_dstaddr	ifr_ifru.ifru_dstaddr +#define ifr_broadaddr	ifr_ifru.ifru_broadaddr +#define ifr_netmask	ifr_ifru.ifru_netmask +#define ifr_flags	ifr_ifru.ifru_flags +#define ifr_metric	ifr_ifru.ifru_ivalue +#define ifr_mtu		ifr_ifru.ifru_mtu +#define ifr_map		ifr_ifru.ifru_map +#define ifr_slave	ifr_ifru.ifru_slave +#define ifr_data	ifr_ifru.ifru_data +#define ifr_ifindex	ifr_ifru.ifru_ivalue +#define ifr_bandwidth	ifr_ifru.ifru_ivalue +#define ifr_qlen	ifr_ifru.ifru_ivalue +#define ifr_newname	ifr_ifru.ifru_newname +#define _IOT_ifreq	_IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0) +#define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0) +#define _IOT_ifreq_int	_IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0) + +struct ifconf { +	int ifc_len;		 +	union { +		void *ifcu_buf; +		struct ifreq *ifcu_req; +	} ifc_ifcu; +}; + +#define ifc_buf		ifc_ifcu.ifcu_buf +#define ifc_req		ifc_ifcu.ifcu_req +#define _IOT_ifconf _IOT(_IOTS(struct ifconf),1,0,0,0,0) + +#endif + + + +#endif diff --git a/include/net/if_arp.h b/include/net/if_arp.h new file mode 100644 index 00000000..bb5eadf1 --- /dev/null +++ b/include/net/if_arp.h @@ -0,0 +1,133 @@ +/* Nonstandard header */ +#ifndef _NET_IF_ARP_H +#define _NET_IF_ARP_H +#ifdef __cplusplus +extern "C" { +#endif + +#include <inttypes.h> +#include <sys/types.h> +#include <sys/socket.h> + +#define MAX_ADDR_LEN	7 + +#define	ARPOP_REQUEST	1 +#define	ARPOP_REPLY	2 +#define	ARPOP_RREQUEST	3 +#define	ARPOP_RREPLY	4 +#define	ARPOP_InREQUEST	8 +#define	ARPOP_InREPLY	9 +#define	ARPOP_NAK	10 + +struct arphdr { +	uint16_t ar_hrd; +	uint16_t ar_pro; +	uint8_t ar_hln; +	uint8_t ar_pln; +	uint16_t ar_op; +}; + + +#define ARPHRD_NETROM	0 +#define ARPHRD_ETHER 	1 +#define	ARPHRD_EETHER	2 +#define	ARPHRD_AX25	3 +#define	ARPHRD_PRONET	4 +#define	ARPHRD_CHAOS	5 +#define	ARPHRD_IEEE802	6 +#define	ARPHRD_ARCNET	7 +#define	ARPHRD_APPLETLK	8 +#define	ARPHRD_DLCI	15 +#define	ARPHRD_ATM	19 +#define	ARPHRD_METRICOM	23 +#define ARPHRD_IEEE1394	24 +#define ARPHRD_EUI64		27 +#define ARPHRD_INFINIBAND	32 +#define ARPHRD_SLIP	256 +#define ARPHRD_CSLIP	257 +#define ARPHRD_SLIP6	258 +#define ARPHRD_CSLIP6	259 +#define ARPHRD_RSRVD	260 +#define ARPHRD_ADAPT	264 +#define ARPHRD_ROSE	270 +#define ARPHRD_X25	271 +#define ARPHRD_HWX25	272 +#define ARPHRD_PPP	512 +#define ARPHRD_CISCO	513 +#define ARPHRD_HDLC	ARPHRD_CISCO +#define ARPHRD_LAPB	516 +#define ARPHRD_DDCMP	517 +#define	ARPHRD_RAWHDLC	518 + +#define ARPHRD_TUNNEL	768 +#define ARPHRD_TUNNEL6	769 +#define ARPHRD_FRAD	770 +#define ARPHRD_SKIP	771 +#define ARPHRD_LOOPBACK	772 +#define ARPHRD_LOCALTLK 773 +#define ARPHRD_FDDI	774 +#define ARPHRD_BIF	775 +#define ARPHRD_SIT	776 +#define ARPHRD_IPDDP	777 +#define ARPHRD_IPGRE	778 +#define ARPHRD_PIMREG	779 +#define ARPHRD_HIPPI	780 +#define ARPHRD_ASH	781 +#define ARPHRD_ECONET	782 +#define ARPHRD_IRDA	783 +#define ARPHRD_FCPP	784 +#define ARPHRD_FCAL	785 +#define ARPHRD_FCPL	786 +#define ARPHRD_FCFABRIC 787 +#define ARPHRD_IEEE802_TR 800 +#define ARPHRD_IEEE80211 801 +#define ARPHRD_IEEE80211_PRISM 802 +#define ARPHRD_IEEE80211_RADIOTAP 803 +#define ARPHRD_IEEE802154 804 +#define ARPHRD_IEEE802154_PHY 805 + +#define ARPHRD_VOID	  0xFFFF +#define ARPHRD_NONE	  0xFFFE + +struct arpreq { +	struct sockaddr arp_pa; +	struct sockaddr arp_ha; +	int arp_flags; +	struct sockaddr arp_netmask; +	char arp_dev[16]; +}; + +struct arpreq_old { +	struct sockaddr arp_pa; +	struct sockaddr arp_ha; +	int arp_flags; +	struct sockaddr arp_netmask; +}; + +#define ATF_COM		0x02 +#define	ATF_PERM	0x04 +#define	ATF_PUBL	0x08 +#define	ATF_USETRAILERS	0x10 +#define ATF_NETMASK     0x20 +#define ATF_DONTPUB	0x40 +#define ATF_MAGIC	0x80 + +#define ARPD_UPDATE	0x01 +#define ARPD_LOOKUP	0x02 +#define ARPD_FLUSH	0x03 + +struct arpd_request { +	uint16_t req; +	uint32_t ip; +	uint32_t dev; +	uint32_t stamp; +	uint32_t updated; +	uint8_t ha[MAX_ADDR_LEN]; +}; + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/net/route.h b/include/net/route.h new file mode 100644 index 00000000..3aaab978 --- /dev/null +++ b/include/net/route.h @@ -0,0 +1,116 @@ +#ifndef _NET_ROUTE_H +#define _NET_ROUTE_H + +#include <stdint.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <netinet/in.h> + + +struct rtentry { +	unsigned long int rt_pad1; +	struct sockaddr rt_dst; +	struct sockaddr rt_gateway; +	struct sockaddr rt_genmask; +	unsigned short int rt_flags; +	short int rt_pad2; +	unsigned long int rt_pad3; +	unsigned char rt_tos; +	unsigned char rt_class; +	short int rt_pad4[sizeof(long)/2-1]; +	short int rt_metric; +	char *rt_dev; +	unsigned long int rt_mtu; +	unsigned long int rt_window; +	unsigned short int rt_irtt; +}; + +#define rt_mss	rt_mtu + + +struct in6_rtmsg { +	struct in6_addr rtmsg_dst; +	struct in6_addr rtmsg_src; +	struct in6_addr rtmsg_gateway; +	uint32_t rtmsg_type; +	uint16_t rtmsg_dst_len; +	uint16_t rtmsg_src_len; +	uint32_t rtmsg_metric; +	unsigned long int rtmsg_info; +	uint32_t rtmsg_flags; +	int rtmsg_ifindex; +}; + + +#define	RTF_UP		0x0001 +#define	RTF_GATEWAY	0x0002 + +#define	RTF_HOST	0x0004 +#define RTF_REINSTATE	0x0008 +#define	RTF_DYNAMIC	0x0010 +#define	RTF_MODIFIED	0x0020 +#define RTF_MTU		0x0040 +#define RTF_MSS		RTF_MTU +#define RTF_WINDOW	0x0080 +#define RTF_IRTT	0x0100 +#define RTF_REJECT	0x0200 +#define	RTF_STATIC	0x0400 +#define	RTF_XRESOLVE	0x0800 +#define RTF_NOFORWARD   0x1000 +#define RTF_THROW	0x2000 +#define RTF_NOPMTUDISC  0x4000 + +#define RTF_DEFAULT	0x00010000 +#define RTF_ALLONLINK	0x00020000 +#define RTF_ADDRCONF	0x00040000 + +#define RTF_LINKRT	0x00100000 +#define RTF_NONEXTHOP	0x00200000 + +#define RTF_CACHE	0x01000000 +#define RTF_FLOW	0x02000000 +#define RTF_POLICY	0x04000000 + +#define RTCF_VALVE	0x00200000 +#define RTCF_MASQ	0x00400000 +#define RTCF_NAT	0x00800000 +#define RTCF_DOREDIRECT 0x01000000 +#define RTCF_LOG	0x02000000 +#define RTCF_DIRECTSRC	0x04000000 + +#define RTF_LOCAL	0x80000000 +#define RTF_INTERFACE	0x40000000 +#define RTF_MULTICAST	0x20000000 +#define RTF_BROADCAST	0x10000000 +#define RTF_NAT		0x08000000 + +#define RTF_ADDRCLASSMASK	0xF8000000 +#define RT_ADDRCLASS(flags)	((uint32_t) flags >> 23) + +#define RT_TOS(tos)		((tos) & IPTOS_TOS_MASK) + +#define RT_LOCALADDR(flags)	((flags & RTF_ADDRCLASSMASK) \ +				 == (RTF_LOCAL|RTF_INTERFACE)) + +#define RT_CLASS_UNSPEC		0 +#define RT_CLASS_DEFAULT	253 + +#define RT_CLASS_MAIN		254 +#define RT_CLASS_LOCAL		255 +#define RT_CLASS_MAX		255 + + +#define RTMSG_ACK		NLMSG_ACK +#define RTMSG_OVERRUN		NLMSG_OVERRUN + +#define RTMSG_NEWDEVICE		0x11 +#define RTMSG_DELDEVICE		0x12 +#define RTMSG_NEWROUTE		0x21 +#define RTMSG_DELROUTE		0x22 +#define RTMSG_NEWRULE		0x31 +#define RTMSG_DELRULE		0x32 +#define RTMSG_CONTROL		0x40 + +#define RTMSG_AR_FAILED		0x51 + +#endif diff --git a/include/netdb.h b/include/netdb.h new file mode 100644 index 00000000..5f1dd3f1 --- /dev/null +++ b/include/netdb.h @@ -0,0 +1,148 @@ +#ifndef	_NETDB_H +#define	_NETDB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _GNU_SOURCE +#define __NEED_size_t +#endif + +#define __NEED_socklen_t +#define __NEED_uint32_t + +#include <bits/alltypes.h> + +struct addrinfo +{ +	int ai_flags; +	int ai_family; +	int ai_socktype; +	int ai_protocol; +	socklen_t ai_addrlen; +	struct sockaddr *ai_addr; +	char *ai_canonname; +	struct addrinfo *ai_next; +}; + +#define IPPORT_RESERVED 1024 + +#define AI_PASSIVE      0x01 +#define AI_CANONNAME    0x02 +#define AI_NUMERICHOST  0x04 +#define AI_V4MAPPED     0x08 +#define AI_ALL          0x10 +#define AI_ADDRCONFIG   0x20 +#define AI_NUMERICSERV  0x400 + + +#define NI_NUMERICHOST  0x01 +#define NI_NUMERICSERV  0x02 +#define NI_NOFQDN       0x04 +#define NI_NAMEREQD     0x08 +#define NI_DGRAM        0x10 +/*#define NI_NUMERICSCOPE */ + +#define NI_MAXHOST 255 +#define NI_MAXSERV 32 + +#define EAI_BADFLAGS   -1 +#define EAI_NONAME     -2 +#define EAI_AGAIN      -3 +#define EAI_FAIL       -4 +#define EAI_FAMILY     -6 +#define EAI_SOCKTYPE   -7 +#define EAI_SERVICE    -8 +#define EAI_MEMORY     -10 +#define EAI_SYSTEM     -11 +#define EAI_OVERFLOW   -12 + +int getaddrinfo (const char *, const char *, const struct addrinfo *, struct addrinfo **); +void freeaddrinfo (struct addrinfo *); +int getnameinfo (const struct sockaddr *, socklen_t, char *, socklen_t, char *, socklen_t, int); +const char *gai_strerror(int); + + +/* Legacy functions follow (marked OBsolete in SUS) */ + +struct netent +{ +	char *n_name; +	char **n_aliases; +	int n_addrtype; +	uint32_t n_net; +}; + +struct hostent +{ +	char *h_name; +	char **h_aliases; +	int h_addrtype; +	int h_length; +	char **h_addr_list; +}; +#define h_addr h_addr_list[0] + +struct servent +{ +	char *s_name; +	char **s_aliases; +	int s_port; +	char *s_proto; +}; + +struct protoent +{ +	char *p_name; +	char **p_aliases; +	int p_proto; +}; + +extern int h_errno; + +#define HOST_NOT_FOUND 1 +#define TRY_AGAIN      2 +#define NO_RECOVERY    3 +#define NO_DATA        4 + +void sethostent (int); +void endhostent (void); +struct hostent *gethostent (void); +struct hostent *gethostbyaddr (const void *, socklen_t, int); +struct hostent *gethostbyname (const char *); + +void setnetent (int); +void endnetent (void); +struct netent *getnetent (void); +struct netent *getnetbyaddr (uint32_t, int); +struct netent *getnetbyname (const char *); + +void setservent (int); +void endservent (void); +struct servent *getservent (void); +struct servent *getservbyname (const char *, const char *); +struct servent *getservbyport (int, const char *); + +void setprotoent (int); +void endprotoent (void); +struct protoent *getprotoent (void); +struct protoent *getprotobyname (const char *); +struct protoent *getprotobynumber (int); + +#ifdef _GNU_SOURCE +const char *hstrerror(int); +int gethostbyname_r(const char *, struct hostent *, char *, size_t, struct hostent **, int *); +int gethostbyname2_r(const char *, int, struct hostent *, char *, size_t, struct hostent **, int *); +struct hostent *gethostbyname2(const char *, int); +int gethostbyaddr_r(const void *, socklen_t, int, struct hostent *, char *, size_t, struct hostent **, int *); +int getservbyport_r(int, const char *, struct servent *, char *, size_t, struct servent **); +int getservbyname_r(const char *, const char *, struct servent *, char *, size_t, struct servent **); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netinet/icmp6.h b/include/netinet/icmp6.h new file mode 100644 index 00000000..01269e7d --- /dev/null +++ b/include/netinet/icmp6.h @@ -0,0 +1,305 @@ +#ifndef _NETINET_ICMP6_H +#define _NETINET_ICMP6_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <string.h> +#include <sys/types.h> +#include <netinet/in.h> + +#define ICMP6_FILTER 1 + +#define ICMP6_FILTER_BLOCK		1 +#define ICMP6_FILTER_PASS		2 +#define ICMP6_FILTER_BLOCKOTHERS	3 +#define ICMP6_FILTER_PASSONLY		4 + +struct icmp6_filter { +	uint32_t icmp6_filt[8]; +}; + +struct icmp6_hdr { +	uint8_t     icmp6_type; +	uint8_t     icmp6_code; +	uint16_t    icmp6_cksum; +	union { +		uint32_t  icmp6_un_data32[1]; +		uint16_t  icmp6_un_data16[2]; +		uint8_t   icmp6_un_data8[4]; +	} icmp6_dataun; +}; + +#define icmp6_data32    icmp6_dataun.icmp6_un_data32 +#define icmp6_data16    icmp6_dataun.icmp6_un_data16 +#define icmp6_data8     icmp6_dataun.icmp6_un_data8 +#define icmp6_pptr      icmp6_data32[0] +#define icmp6_mtu       icmp6_data32[0] +#define icmp6_id        icmp6_data16[0] +#define icmp6_seq       icmp6_data16[1] +#define icmp6_maxdelay  icmp6_data16[0] + +#define ICMP6_DST_UNREACH             1 +#define ICMP6_PACKET_TOO_BIG          2 +#define ICMP6_TIME_EXCEEDED           3 +#define ICMP6_PARAM_PROB              4 + +#define ICMP6_INFOMSG_MASK  0x80 + +#define ICMP6_ECHO_REQUEST          128 +#define ICMP6_ECHO_REPLY            129 +#define MLD_LISTENER_QUERY          130 +#define MLD_LISTENER_REPORT         131 +#define MLD_LISTENER_REDUCTION      132 + +#define ICMP6_DST_UNREACH_NOROUTE     0 +#define ICMP6_DST_UNREACH_ADMIN       1 +#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 +#define ICMP6_DST_UNREACH_ADDR        3 +#define ICMP6_DST_UNREACH_NOPORT      4 + +#define ICMP6_TIME_EXCEED_TRANSIT     0 +#define ICMP6_TIME_EXCEED_REASSEMBLY  1 + +#define ICMP6_PARAMPROB_HEADER        0 +#define ICMP6_PARAMPROB_NEXTHEADER    1 +#define ICMP6_PARAMPROB_OPTION        2 + +#define ICMP6_FILTER_WILLPASS(type, filterp) \ +	((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0) + +#define ICMP6_FILTER_WILLBLOCK(type, filterp) \ +	((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) != 0) + +#define ICMP6_FILTER_SETPASS(type, filterp) \ +	((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type) & 31)))) + +#define ICMP6_FILTER_SETBLOCK(type, filterp) \ +	((((filterp)->icmp6_filt[(type) >> 5]) |=  (1 << ((type) & 31)))) + +#define ICMP6_FILTER_SETPASSALL(filterp) \ +	memset (filterp, 0, sizeof (struct icmp6_filter)); + +#define ICMP6_FILTER_SETBLOCKALL(filterp) \ +	memset (filterp, 0xFF, sizeof (struct icmp6_filter)); + +#define ND_ROUTER_SOLICIT           133 +#define ND_ROUTER_ADVERT            134 +#define ND_NEIGHBOR_SOLICIT         135 +#define ND_NEIGHBOR_ADVERT          136 +#define ND_REDIRECT                 137 + +struct nd_router_solicit { +	struct icmp6_hdr  nd_rs_hdr; +}; + +#define nd_rs_type               nd_rs_hdr.icmp6_type +#define nd_rs_code               nd_rs_hdr.icmp6_code +#define nd_rs_cksum              nd_rs_hdr.icmp6_cksum +#define nd_rs_reserved           nd_rs_hdr.icmp6_data32[0] + +struct nd_router_advert { +	struct icmp6_hdr  nd_ra_hdr; +	uint32_t   nd_ra_reachable; +	uint32_t   nd_ra_retransmit; +}; + +#define nd_ra_type               nd_ra_hdr.icmp6_type +#define nd_ra_code               nd_ra_hdr.icmp6_code +#define nd_ra_cksum              nd_ra_hdr.icmp6_cksum +#define nd_ra_curhoplimit        nd_ra_hdr.icmp6_data8[0] +#define nd_ra_flags_reserved     nd_ra_hdr.icmp6_data8[1] +#define ND_RA_FLAG_MANAGED       0x80 +#define ND_RA_FLAG_OTHER         0x40 +#define ND_RA_FLAG_HOME_AGENT    0x20 +#define nd_ra_router_lifetime    nd_ra_hdr.icmp6_data16[1] + +struct nd_neighbor_solicit { +	struct icmp6_hdr  nd_ns_hdr; +	struct in6_addr   nd_ns_target; +}; + +#define nd_ns_type               nd_ns_hdr.icmp6_type +#define nd_ns_code               nd_ns_hdr.icmp6_code +#define nd_ns_cksum              nd_ns_hdr.icmp6_cksum +#define nd_ns_reserved           nd_ns_hdr.icmp6_data32[0] + +struct nd_neighbor_advert { +	struct icmp6_hdr  nd_na_hdr; +	struct in6_addr   nd_na_target; +}; + +#define nd_na_type               nd_na_hdr.icmp6_type +#define nd_na_code               nd_na_hdr.icmp6_code +#define nd_na_cksum              nd_na_hdr.icmp6_cksum +#define nd_na_flags_reserved     nd_na_hdr.icmp6_data32[0] +#if     __BYTE_ORDER == __BIG_ENDIAN +#define ND_NA_FLAG_ROUTER        0x80000000 +#define ND_NA_FLAG_SOLICITED     0x40000000 +#define ND_NA_FLAG_OVERRIDE      0x20000000 +#else +#define ND_NA_FLAG_ROUTER        0x00000080 +#define ND_NA_FLAG_SOLICITED     0x00000040 +#define ND_NA_FLAG_OVERRIDE      0x00000020 +#endif + +struct nd_redirect { +	struct icmp6_hdr  nd_rd_hdr; +	struct in6_addr   nd_rd_target; +	struct in6_addr   nd_rd_dst; +}; + +#define nd_rd_type               nd_rd_hdr.icmp6_type +#define nd_rd_code               nd_rd_hdr.icmp6_code +#define nd_rd_cksum              nd_rd_hdr.icmp6_cksum +#define nd_rd_reserved           nd_rd_hdr.icmp6_data32[0] + +struct nd_opt_hdr { +	uint8_t  nd_opt_type; +	uint8_t  nd_opt_len; +}; + +#define ND_OPT_SOURCE_LINKADDR		1 +#define ND_OPT_TARGET_LINKADDR		2 +#define ND_OPT_PREFIX_INFORMATION	3 +#define ND_OPT_REDIRECTED_HEADER	4 +#define ND_OPT_MTU			5 +#define ND_OPT_RTR_ADV_INTERVAL		7 +#define ND_OPT_HOME_AGENT_INFO		8 + +struct nd_opt_prefix_info { +	uint8_t   nd_opt_pi_type; +	uint8_t   nd_opt_pi_len; +	uint8_t   nd_opt_pi_prefix_len; +	uint8_t   nd_opt_pi_flags_reserved; +	uint32_t  nd_opt_pi_valid_time; +	uint32_t  nd_opt_pi_preferred_time; +	uint32_t  nd_opt_pi_reserved2; +	struct in6_addr  nd_opt_pi_prefix; +}; + +#define ND_OPT_PI_FLAG_ONLINK	0x80 +#define ND_OPT_PI_FLAG_AUTO	0x40 +#define ND_OPT_PI_FLAG_RADDR	0x20 + +struct nd_opt_rd_hdr { +	uint8_t   nd_opt_rh_type; +	uint8_t   nd_opt_rh_len; +	uint16_t  nd_opt_rh_reserved1; +	uint32_t  nd_opt_rh_reserved2; +}; + +struct nd_opt_mtu { +	uint8_t   nd_opt_mtu_type; +	uint8_t   nd_opt_mtu_len; +	uint16_t  nd_opt_mtu_reserved; +	uint32_t  nd_opt_mtu_mtu; +}; + +struct mld_hdr { +	struct icmp6_hdr    mld_icmp6_hdr; +	struct in6_addr     mld_addr; +}; + +#define mld_type        mld_icmp6_hdr.icmp6_type +#define mld_code        mld_icmp6_hdr.icmp6_code +#define mld_cksum       mld_icmp6_hdr.icmp6_cksum +#define mld_maxdelay    mld_icmp6_hdr.icmp6_data16[0] +#define mld_reserved    mld_icmp6_hdr.icmp6_data16[1] + +#define ICMP6_ROUTER_RENUMBERING    138 + +struct icmp6_router_renum { +	struct icmp6_hdr    rr_hdr; +	uint8_t             rr_segnum; +	uint8_t             rr_flags; +	uint16_t            rr_maxdelay; +	uint32_t            rr_reserved; +}; + +#define rr_type		rr_hdr.icmp6_type +#define rr_code         rr_hdr.icmp6_code +#define rr_cksum        rr_hdr.icmp6_cksum +#define rr_seqnum       rr_hdr.icmp6_data32[0] + +#define ICMP6_RR_FLAGS_TEST             0x80 +#define ICMP6_RR_FLAGS_REQRESULT        0x40 +#define ICMP6_RR_FLAGS_FORCEAPPLY       0x20 +#define ICMP6_RR_FLAGS_SPECSITE         0x10 +#define ICMP6_RR_FLAGS_PREVDONE         0x08 + +struct rr_pco_match { +	uint8_t             rpm_code; +	uint8_t             rpm_len; +	uint8_t             rpm_ordinal; +	uint8_t             rpm_matchlen; +	uint8_t             rpm_minlen; +	uint8_t             rpm_maxlen; +	uint16_t            rpm_reserved; +	struct in6_addr     rpm_prefix; +}; + +#define RPM_PCO_ADD             1 +#define RPM_PCO_CHANGE          2 +#define RPM_PCO_SETGLOBAL       3 + +struct rr_pco_use { +	uint8_t             rpu_uselen; +	uint8_t             rpu_keeplen; +	uint8_t             rpu_ramask; +	uint8_t             rpu_raflags; +	uint32_t            rpu_vltime; +	uint32_t            rpu_pltime; +	uint32_t            rpu_flags; +	struct in6_addr     rpu_prefix; +}; + +#define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK  0x20 +#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO    0x10 + +#if __BYTE_ORDER == __BIG_ENDIAN +#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80000000 +#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40000000 +#else +#define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80 +#define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40 +#endif + +struct rr_result { +	uint16_t            rrr_flags; +	uint8_t             rrr_ordinal; +	uint8_t             rrr_matchedlen; +	uint32_t            rrr_ifid; +	struct in6_addr     rrr_prefix; +}; + +#if __BYTE_ORDER == __BIG_ENDIAN +#define ICMP6_RR_RESULT_FLAGS_OOB       0x0002 +#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0001 +#else +#define ICMP6_RR_RESULT_FLAGS_OOB       0x0200 +#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0100 +#endif + +struct nd_opt_adv_interval { +	uint8_t   nd_opt_adv_interval_type; +	uint8_t   nd_opt_adv_interval_len; +	uint16_t  nd_opt_adv_interval_reserved; +	uint32_t  nd_opt_adv_interval_ival; +}; + +struct nd_opt_home_agent_info { +	uint8_t   nd_opt_home_agent_info_type; +	uint8_t   nd_opt_home_agent_info_len; +	uint16_t  nd_opt_home_agent_info_reserved; +	uint16_t  nd_opt_home_agent_info_preference; +	uint16_t  nd_opt_home_agent_info_lifetime; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netinet/if_ether.h b/include/netinet/if_ether.h new file mode 100644 index 00000000..65a838ac --- /dev/null +++ b/include/netinet/if_ether.h @@ -0,0 +1,108 @@ +#ifndef _NETINET_IF_ETHER_H +#define _NETINET_IF_ETHER_H + +#include <stdint.h> +#include <sys/types.h> + +#define ETH_ALEN	6 +#define ETH_HLEN	14 +#define ETH_ZLEN	60 +#define ETH_DATA_LEN	1500 +#define ETH_FRAME_LEN	1514 +#define ETH_FCS_LEN	4 + +#define ETH_P_LOOP	0x0060 +#define ETH_P_PUP	0x0200 +#define ETH_P_PUPAT	0x0201 +#define ETH_P_IP	0x0800 +#define ETH_P_X25	0x0805 +#define ETH_P_ARP	0x0806 +#define	ETH_P_BPQ	0x08FF +#define ETH_P_IEEEPUP	0x0a00 +#define ETH_P_IEEEPUPAT	0x0a01 +#define ETH_P_DEC       0x6000 +#define ETH_P_DNA_DL    0x6001 +#define ETH_P_DNA_RC    0x6002 +#define ETH_P_DNA_RT    0x6003 +#define ETH_P_LAT       0x6004 +#define ETH_P_DIAG      0x6005 +#define ETH_P_CUST      0x6006 +#define ETH_P_SCA       0x6007 +#define ETH_P_TEB	0x6558 +#define ETH_P_RARP      0x8035 +#define ETH_P_ATALK	0x809B +#define ETH_P_AARP	0x80F3 +#define ETH_P_8021Q	0x8100 +#define ETH_P_IPX	0x8137 +#define ETH_P_IPV6	0x86DD +#define ETH_P_PAUSE	0x8808 +#define ETH_P_SLOW	0x8809 +#define ETH_P_WCCP	0x883E +#define ETH_P_PPP_DISC	0x8863 +#define ETH_P_PPP_SES	0x8864 +#define ETH_P_MPLS_UC	0x8847 +#define ETH_P_MPLS_MC	0x8848 +#define ETH_P_ATMMPOA	0x884c +#define ETH_P_ATMFATE	0x8884 +#define ETH_P_PAE	0x888E +#define ETH_P_AOE	0x88A2 +#define ETH_P_TIPC	0x88CA +#define ETH_P_FCOE	0x8906 +#define ETH_P_EDSA	0xDADA + +#define ETH_P_802_3	0x0001 +#define ETH_P_AX25	0x0002 +#define ETH_P_ALL	0x0003 +#define ETH_P_802_2	0x0004 +#define ETH_P_SNAP	0x0005 +#define ETH_P_DDCMP     0x0006 +#define ETH_P_WAN_PPP   0x0007 +#define ETH_P_PPP_MP    0x0008 +#define ETH_P_LOCALTALK 0x0009 +#define ETH_P_CAN	0x000C +#define ETH_P_PPPTALK	0x0010 +#define ETH_P_TR_802_2	0x0011 +#define ETH_P_MOBITEX	0x0015 +#define ETH_P_CONTROL	0x0016 +#define ETH_P_IRDA	0x0017 +#define ETH_P_ECONET	0x0018 +#define ETH_P_HDLC	0x0019 +#define ETH_P_ARCNET	0x001A +#define ETH_P_DSA	0x001B +#define ETH_P_TRAILER	0x001C +#define ETH_P_PHONET	0x00F5 + +struct ethhdr { +	uint8_t h_dest[ETH_ALEN]; +	uint8_t h_source[ETH_ALEN]; +	uint16_t h_proto; +}; + +#include <net/ethernet.h> +#include <net/if_arp.h> + +struct	ether_arp { +	struct	arphdr ea_hdr; +	uint8_t arp_sha[ETH_ALEN]; +	uint8_t arp_spa[4]; +	uint8_t arp_tha[ETH_ALEN]; +	uint8_t arp_tpa[4]; +}; +#define	arp_hrd	ea_hdr.ar_hrd +#define	arp_pro	ea_hdr.ar_pro +#define	arp_hln	ea_hdr.ar_hln +#define	arp_pln	ea_hdr.ar_pln +#define	arp_op	ea_hdr.ar_op + +#define ETHER_MAP_IP_MULTICAST(ipaddr, enaddr) \ +do { \ +	(enaddr)[0] = 0x01; \ +	(enaddr)[1] = 0x00; \ +	(enaddr)[2] = 0x5e; \ +	(enaddr)[3] = ((uint8_t *)ipaddr)[1] & 0x7f; \ +	(enaddr)[4] = ((uint8_t *)ipaddr)[2]; \ +	(enaddr)[5] = ((uint8_t *)ipaddr)[3]; \ +} while(0) + + +#endif diff --git a/include/netinet/in.h b/include/netinet/in.h new file mode 100644 index 00000000..a641f6a6 --- /dev/null +++ b/include/netinet/in.h @@ -0,0 +1,158 @@ +#ifndef	_NETINET_IN_H +#define	_NETINET_IN_H + +#define __NEED_in_addr_t +#define __NEED_in_port_t +#define __NEED_sa_family_t +#define __NEED_struct_in_addr +#define __NEED_uint8_t +#define __NEED_uint16_t +#define __NEED_uint32_t + +#include <bits/alltypes.h> + +struct sockaddr_in +{ +	sa_family_t sin_family; +	in_port_t sin_port; +	struct in_addr sin_addr; +	uint8_t sin_zero[8]; +}; + +struct in6_addr +{ +	union { +		uint8_t __s6_addr[16]; +		uint32_t __s6_addr32[4]; +	} __in6_union; +}; +#define s6_addr __in6_union.__s6_addr +#define s6_addr32 __in6_union.__s6_addr32 + +struct sockaddr_in6 +{ +	sa_family_t     sin6_family; +	in_port_t       sin6_port; +	uint32_t        sin6_flowinfo; +	struct in6_addr sin6_addr; +	uint32_t        sin6_scope_id; +}; + +struct ipv6_mreq +{ +	struct in6_addr ipv6mr_multiaddr; +	unsigned        ipv6mr_interface; +}; + +#define INADDR_ANY        ((in_addr_t) 0x00000000) +#define INADDR_BROADCAST  ((in_addr_t) 0xffffffff) +#define INADDR_NONE       ((in_addr_t) 0xffffffff) +#define INADDR_LOOPBACK   ((in_addr_t) 0x7f000001) + +#define IN6ADDR_ANY_INIT      { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } +#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } + +extern const struct in6_addr in6addr_any, in6addr_loopback; + +#undef INET_ADDRSTRLEN +#undef INET6_ADDRSTRLEN +#define INET_ADDRSTRLEN  16 +#define INET6_ADDRSTRLEN 46 + +uint32_t htonl(uint32_t); +uint16_t htons(uint16_t); +uint32_t ntohl(uint32_t); +uint16_t ntohs(uint16_t); + +#define IPPROTO_IP       0 +#define IPPROTO_ICMP     1 +#define IPPROTO_IGMP     2 +#define IPPROTO_IPIP     4 +#define IPPROTO_TCP      6 +#define IPPROTO_EGP      8 +#define IPPROTO_PUP      12 +#define IPPROTO_UDP      17 +#define IPPROTO_IDP      22 +#define IPPROTO_TP       29 +#define IPPROTO_IPV6     41 +#define IPPROTO_ROUTING  43 +#define IPPROTO_FRAGMENT 44 +#define IPPROTO_RSVP     46 +#define IPPROTO_GRE      47 +#define IPPROTO_ESP      50 +#define IPPROTO_AH       51 +#define IPPROTO_ICMPV6   58 +#define IPPROTO_NONE     59 +#define IPPROTO_DSTOPTS  60 +#define IPPROTO_MTP      92 +#define IPPROTO_ENCAP    98 +#define IPPROTO_PIM      103 +#define IPPROTO_COMP     108 +#define IPPROTO_RAW      255 + +#define IN6_IS_ADDR_UNSPECIFIED(a) \ +        (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \ +         ((uint32_t *) (a))[2] == 0 && ((uint32_t *) (a))[3] == 0) + +#define IN6_IS_ADDR_LOOPBACK(a) \ +        (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \ +         ((uint32_t *) (a))[2] == 0 && \ +         ((uint8_t *) (a))[12] == 0 && ((uint8_t *) (a))[13] == 0 && \ +         ((uint8_t *) (a))[14] == 0 && ((uint8_t *) (a))[15] == 1 ) + +#define IN6_IS_ADDR_MULTICAST(a) (((uint8_t *) (a))[0] == 0xff) + +#define IN6_IS_ADDR_LINKLOCAL(a) \ +        ((((uint8_t *) (a))[0]) == 0xfe && (((uint8_t *) (a))[1] & 0xc0) == 0x80) + +#define IN6_IS_ADDR_SITELOCAL(a) \ +        ((((uint8_t *) (a))[0]) == 0xfe && (((uint8_t *) (a))[1] & 0xc0) == 0xc0) + +#define IN6_IS_ADDR_V4MAPPED(a) \ +        (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \ +         ((uint8_t *) (a))[8] == 0 && ((uint8_t *) (a))[9] == 0 && \ +         ((uint8_t *) (a))[10] == 0xff && ((uint8_t *) (a))[11] == 0xff) + +#define IN6_IS_ADDR_V4COMPAT(a) \ +        (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \ +         ((uint32_t *) (a))[2] == 0 && ((uint8_t *) (a))[15] > 1) + +#define IN6_IS_ADDR_MC_NODELOCAL(a) \ +        (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *) (a))[1] & 0xf) == 0x1)) + +#define IN6_IS_ADDR_MC_LINKLOCAL(a) \ +        (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *) (a))[1] & 0xf) == 0x2)) + +#define IN6_IS_ADDR_MC_SITELOCAL(a) \ +        (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *) (a))[1] & 0xf) == 0x5)) + +#define IN6_IS_ADDR_MC_ORGLOCAL(a) \ +        (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *) (a))[1] & 0xf) == 0x8)) + +#define IN6_IS_ADDR_MC_GLOBAL(a) \ +        (IN6_IS_ADDR_MULTICAST(a) && ((((uint8_t *) (a))[1] & 0xf) == 0xe)) + +#include <bits/in.h> + +#if 1 /* FIXME: namespace violation */ +#define	IN_CLASSA(a)		((((in_addr_t)(a)) & 0x80000000) == 0) +#define	IN_CLASSA_NET		0xff000000 +#define	IN_CLASSA_NSHIFT	24 +#define	IN_CLASSA_HOST		(0xffffffff & ~IN_CLASSA_NET) +#define	IN_CLASSA_MAX		128 +#define	IN_CLASSB(a)		((((in_addr_t)(a)) & 0xc0000000) == 0x80000000) +#define	IN_CLASSB_NET		0xffff0000 +#define	IN_CLASSB_NSHIFT	16 +#define	IN_CLASSB_HOST		(0xffffffff & ~IN_CLASSB_NET) +#define	IN_CLASSB_MAX		65536 +#define	IN_CLASSC(a)		((((in_addr_t)(a)) & 0xe0000000) == 0xc0000000) +#define	IN_CLASSC_NET		0xffffff00 +#define	IN_CLASSC_NSHIFT	8 +#define	IN_CLASSC_HOST		(0xffffffff & ~IN_CLASSC_NET) +#define	IN_CLASSD(a)		((((in_addr_t)(a)) & 0xf0000000) == 0xe0000000) +#define	IN_MULTICAST(a)		IN_CLASSD(a) +#define	IN_EXPERIMENTAL(a)	((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000) +#define	IN_BADCLASS(a)		((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000) +#endif + +#endif diff --git a/include/netinet/ip.h b/include/netinet/ip.h new file mode 100644 index 00000000..41187414 --- /dev/null +++ b/include/netinet/ip.h @@ -0,0 +1,186 @@ +#ifndef _NETINET_IP_H +#define _NETINET_IP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <netinet/in.h> +#include <endian.h> + +struct timestamp { +	uint8_t len; +	uint8_t ptr; +#if __BYTE_ORDER == __LITTLE_ENDIAN +	unsigned int flags:4; +	unsigned int overflow:4; +#else +	unsigned int overflow:4; +	unsigned int flags:4; +#endif +	uint32_t data[9]; +  }; + +struct iphdr { +#if __BYTE_ORDER == __LITTLE_ENDIAN +	unsigned int ihl:4; +	unsigned int version:4; +#else +	unsigned int version:4; +	unsigned int ihl:4; +#endif +	uint8_t tos; +	uint16_t tot_len; +	uint16_t id; +	uint16_t frag_off; +	uint8_t ttl; +	uint8_t protocol; +	uint16_t check; +	uint32_t saddr; +	uint32_t daddr; +}; + +struct ip { +#if __BYTE_ORDER == __LITTLE_ENDIAN +	unsigned int ip_hl:4; +	unsigned int ip_v:4; +#else +	unsigned int ip_v:4; +	unsigned int ip_hl:4; +#endif +	uint8_t ip_tos; +	uint16_t ip_len; +	uint16_t ip_id; +	uint16_t ip_off; +	uint8_t ip_ttl; +	uint8_t ip_p; +	uint16_t ip_sum; +	struct in_addr ip_src, ip_dst; +}; + +#define	IP_RF 0x8000 +#define	IP_DF 0x4000 +#define	IP_MF 0x2000 +#define	IP_OFFMASK 0x1fff + +struct ip_timestamp { +	uint8_t ipt_code; +	uint8_t ipt_len; +	uint8_t ipt_ptr; +#if __BYTE_ORDER == __LITTLE_ENDIAN +	unsigned int ipt_flg:4; +	unsigned int ipt_oflw:4; +#else +	unsigned int ipt_oflw:4; +	unsigned int ipt_flg:4; +#endif +	uint32_t data[9]; +}; + +#define	IPVERSION	4 +#define	IP_MAXPACKET	65535 + +#define	IPTOS_ECN_MASK		0x03 +#define	IPTOS_ECN(x)		((x) & IPTOS_ECN_MASK) +#define	IPTOS_ECN_NOT_ECT	0x00 +#define	IPTOS_ECN_ECT1		0x01 +#define	IPTOS_ECN_ECT0		0x02 +#define	IPTOS_ECN_CE		0x03 + +#define	IPTOS_DSCP_MASK		0xfc +#define	IPTOS_DSCP(x)		((x) & IPTOS_DSCP_MASK) +#define	IPTOS_DSCP_AF11		0x28 +#define	IPTOS_DSCP_AF12		0x30 +#define	IPTOS_DSCP_AF13		0x38 +#define	IPTOS_DSCP_AF21		0x48 +#define	IPTOS_DSCP_AF22		0x50 +#define	IPTOS_DSCP_AF23		0x58 +#define	IPTOS_DSCP_AF31		0x68 +#define	IPTOS_DSCP_AF32		0x70 +#define	IPTOS_DSCP_AF33		0x78 +#define	IPTOS_DSCP_AF41		0x88 +#define	IPTOS_DSCP_AF42		0x90 +#define	IPTOS_DSCP_AF43		0x98 +#define	IPTOS_DSCP_EF		0xb8 + +#define	IPTOS_TOS_MASK		0x1E +#define	IPTOS_TOS(tos)		((tos) & IPTOS_TOS_MASK) +#define	IPTOS_LOWDELAY		0x10 +#define	IPTOS_THROUGHPUT	0x08 +#define	IPTOS_RELIABILITY	0x04 +#define	IPTOS_LOWCOST		0x02 +#define	IPTOS_MINCOST		IPTOS_LOWCOST + +#define	IPTOS_PREC_MASK			0xe0 +#define	IPTOS_PREC(tos)                ((tos) & IPTOS_PREC_MASK) +#define	IPTOS_PREC_NETCONTROL		0xe0 +#define	IPTOS_PREC_INTERNETCONTROL	0xc0 +#define	IPTOS_PREC_CRITIC_ECP		0xa0 +#define	IPTOS_PREC_FLASHOVERRIDE	0x80 +#define	IPTOS_PREC_FLASH		0x60 +#define	IPTOS_PREC_IMMEDIATE		0x40 +#define	IPTOS_PREC_PRIORITY		0x20 +#define	IPTOS_PREC_ROUTINE		0x00 + +#define	IPOPT_COPY		0x80 +#define	IPOPT_CLASS_MASK	0x60 +#define	IPOPT_NUMBER_MASK	0x1f + +#define	IPOPT_COPIED(o)		((o) & IPOPT_COPY) +#define	IPOPT_CLASS(o)		((o) & IPOPT_CLASS_MASK) +#define	IPOPT_NUMBER(o)		((o) & IPOPT_NUMBER_MASK) + +#define	IPOPT_CONTROL		0x00 +#define	IPOPT_RESERVED1		0x20 +#define	IPOPT_DEBMEAS		0x40 +#define	IPOPT_MEASUREMENT       IPOPT_DEBMEAS +#define	IPOPT_RESERVED2		0x60 + +#define	IPOPT_EOL		0 +#define	IPOPT_END		IPOPT_EOL +#define	IPOPT_NOP		1 +#define	IPOPT_NOOP		IPOPT_NOP + +#define	IPOPT_RR		7 +#define	IPOPT_TS		68 +#define	IPOPT_TIMESTAMP		IPOPT_TS +#define	IPOPT_SECURITY		130 +#define	IPOPT_SEC		IPOPT_SECURITY +#define	IPOPT_LSRR		131 +#define	IPOPT_SATID		136 +#define	IPOPT_SID		IPOPT_SATID +#define	IPOPT_SSRR		137 +#define	IPOPT_RA		148 + +#define	IPOPT_OPTVAL		0 +#define	IPOPT_OLEN		1 +#define	IPOPT_OFFSET		2 +#define	IPOPT_MINOFF		4 + +#define	MAX_IPOPTLEN		40 + +#define	IPOPT_TS_TSONLY		0 +#define	IPOPT_TS_TSANDADDR	1 +#define	IPOPT_TS_PRESPEC	3 + +#define	IPOPT_SECUR_UNCLASS	0x0000 +#define	IPOPT_SECUR_CONFID	0xf135 +#define	IPOPT_SECUR_EFTO	0x789a +#define	IPOPT_SECUR_MMMM	0xbc4d +#define	IPOPT_SECUR_RESTR	0xaf13 +#define	IPOPT_SECUR_SECRET	0xd788 +#define	IPOPT_SECUR_TOPSECRET	0x6bc5 + +#define	MAXTTL		255 +#define	IPDEFTTL	64 +#define	IPFRAGTTL	60 +#define	IPTTLDEC	1 + +#define	IP_MSS		576 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netinet/ip6.h b/include/netinet/ip6.h new file mode 100644 index 00000000..a4347a53 --- /dev/null +++ b/include/netinet/ip6.h @@ -0,0 +1,142 @@ +#ifndef _NETINET_IP6_H +#define _NETINET_IP6_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <netinet/in.h> +#include <endian.h> + +struct ip6_hdr { +	union { +		struct ip6_hdrctl { +			uint32_t ip6_un1_flow; +			uint16_t ip6_un1_plen; +			uint8_t  ip6_un1_nxt; +			uint8_t  ip6_un1_hlim; +		} ip6_un1; +		uint8_t ip6_un2_vfc; +	} ip6_ctlun; +	struct in6_addr ip6_src; +	struct in6_addr ip6_dst; +}; + +#define ip6_vfc   ip6_ctlun.ip6_un2_vfc +#define ip6_flow  ip6_ctlun.ip6_un1.ip6_un1_flow +#define ip6_plen  ip6_ctlun.ip6_un1.ip6_un1_plen +#define ip6_nxt   ip6_ctlun.ip6_un1.ip6_un1_nxt +#define ip6_hlim  ip6_ctlun.ip6_un1.ip6_un1_hlim +#define ip6_hops  ip6_ctlun.ip6_un1.ip6_un1_hlim + +struct ip6_ext { +	uint8_t  ip6e_nxt; +	uint8_t  ip6e_len; +}; + +struct ip6_hbh { +	uint8_t  ip6h_nxt; +	uint8_t  ip6h_len; +}; + +struct ip6_dest { +	uint8_t  ip6d_nxt; +	uint8_t  ip6d_len; +}; + +struct ip6_rthdr { +	uint8_t  ip6r_nxt; +	uint8_t  ip6r_len; +	uint8_t  ip6r_type; +	uint8_t  ip6r_segleft; +}; + +struct ip6_rthdr0 { +	uint8_t  ip6r0_nxt; +	uint8_t  ip6r0_len; +	uint8_t  ip6r0_type; +	uint8_t  ip6r0_segleft; +	uint8_t  ip6r0_reserved; +	uint8_t  ip6r0_slmap[3]; +	struct in6_addr ip6r0_addr[]; +}; + +struct ip6_frag { +	uint8_t   ip6f_nxt; +	uint8_t   ip6f_reserved; +	uint16_t  ip6f_offlg; +	uint32_t  ip6f_ident; +}; + +#if __BYTE_ORDER == __BIG_ENDIAN +#define IP6F_OFF_MASK       0xfff8 +#define IP6F_RESERVED_MASK  0x0006 +#define IP6F_MORE_FRAG      0x0001 +#else +#define IP6F_OFF_MASK       0xf8ff +#define IP6F_RESERVED_MASK  0x0600 +#define IP6F_MORE_FRAG      0x0100 +#endif + +struct ip6_opt { +	uint8_t  ip6o_type; +	uint8_t  ip6o_len; +}; + +#define IP6OPT_TYPE(o)		((o) & 0xc0) +#define IP6OPT_TYPE_SKIP	0x00 +#define IP6OPT_TYPE_DISCARD	0x40 +#define IP6OPT_TYPE_FORCEICMP	0x80 +#define IP6OPT_TYPE_ICMP	0xc0 +#define IP6OPT_TYPE_MUTABLE	0x20 + +#define IP6OPT_PAD1	0 +#define IP6OPT_PADN	1 + +#define IP6OPT_JUMBO		0xc2 +#define IP6OPT_NSAP_ADDR	0xc3 +#define IP6OPT_TUNNEL_LIMIT	0x04 +#define IP6OPT_ROUTER_ALERT	0x05 + +struct ip6_opt_jumbo { +	uint8_t  ip6oj_type; +	uint8_t  ip6oj_len; +	uint8_t  ip6oj_jumbo_len[4]; +}; +#define IP6OPT_JUMBO_LEN	6 + +struct ip6_opt_nsap { +	uint8_t  ip6on_type; +	uint8_t  ip6on_len; +	uint8_t  ip6on_src_nsap_len; +	uint8_t  ip6on_dst_nsap_len; +}; + +struct ip6_opt_tunnel { +	uint8_t  ip6ot_type; +	uint8_t  ip6ot_len; +	uint8_t  ip6ot_encap_limit; +}; + +struct ip6_opt_router { +	uint8_t  ip6or_type; +	uint8_t  ip6or_len; +	uint8_t  ip6or_value[2]; +}; + +#if __BYTE_ORDER == __BIG_ENDIAN +#define IP6_ALERT_MLD	0x0000 +#define IP6_ALERT_RSVP	0x0001 +#define IP6_ALERT_AN	0x0002 +#else +#define IP6_ALERT_MLD	0x0000 +#define IP6_ALERT_RSVP	0x0100 +#define IP6_ALERT_AN	0x0200 +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netinet/ip_icmp.h b/include/netinet/ip_icmp.h new file mode 100644 index 00000000..2f4a86dd --- /dev/null +++ b/include/netinet/ip_icmp.h @@ -0,0 +1,192 @@ +#ifndef _NETINET_IP_ICMP_H +#define _NETINET_IP_ICMP_H + +#include <stdint.h> +#include <netinet/in.h> +#include <netinet/ip.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct icmphdr { +	uint8_t type; +	uint8_t code; +	uint16_t checksum; +	union { +		struct { +			uint16_t id; +			uint16_t sequence; +		} echo; +		uint32_t gateway; +		struct { +			uint16_t __unused; +			uint16_t mtu; +		} frag; +	} un; +}; + +#define ICMP_ECHOREPLY		0 +#define ICMP_DEST_UNREACH	3 +#define ICMP_SOURCE_QUENCH	4 +#define ICMP_REDIRECT		5 +#define ICMP_ECHO		8 +#define ICMP_TIME_EXCEEDED	11 +#define ICMP_PARAMETERPROB	12 +#define ICMP_TIMESTAMP		13 +#define ICMP_TIMESTAMPREPLY	14 +#define ICMP_INFO_REQUEST	15 +#define ICMP_INFO_REPLY		16 +#define ICMP_ADDRESS		17 +#define ICMP_ADDRESSREPLY	18 +#define NR_ICMP_TYPES		18 + + +#define ICMP_NET_UNREACH	0 +#define ICMP_HOST_UNREACH	1 +#define ICMP_PROT_UNREACH	2 +#define ICMP_PORT_UNREACH	3 +#define ICMP_FRAG_NEEDED	4 +#define ICMP_SR_FAILED		5 +#define ICMP_NET_UNKNOWN	6 +#define ICMP_HOST_UNKNOWN	7 +#define ICMP_HOST_ISOLATED	8 +#define ICMP_NET_ANO		9 +#define ICMP_HOST_ANO		10 +#define ICMP_NET_UNR_TOS	11 +#define ICMP_HOST_UNR_TOS	12 +#define ICMP_PKT_FILTERED	13 +#define ICMP_PREC_VIOLATION	14 +#define ICMP_PREC_CUTOFF	15 +#define NR_ICMP_UNREACH		15 + +#define ICMP_REDIR_NET		0 +#define ICMP_REDIR_HOST		1 +#define ICMP_REDIR_NETTOS	2 +#define ICMP_REDIR_HOSTTOS	3 + +#define ICMP_EXC_TTL		0 +#define ICMP_EXC_FRAGTIME	1 + + +struct icmp_ra_addr { +	uint32_t ira_addr; +	uint32_t ira_preference; +}; + +struct icmp { +	uint8_t  icmp_type; +	uint8_t  icmp_code; +	uint16_t icmp_cksum; +	union { +		uint8_t ih_pptr; +		struct in_addr ih_gwaddr; +		struct ih_idseq { +			uint16_t icd_id; +			uint16_t icd_seq; +		} ih_idseq; +		uint32_t ih_void; + +		struct ih_pmtu { +			uint16_t ipm_void; +			uint16_t ipm_nextmtu; +		} ih_pmtu; + +		struct ih_rtradv { +			uint8_t irt_num_addrs; +			uint8_t irt_wpa; +			uint16_t irt_lifetime; +		} ih_rtradv; +	} icmp_hun; +	union { +		struct { +			uint32_t its_otime; +			uint32_t its_rtime; +			uint32_t its_ttime; +		} id_ts; +		struct { +			struct ip idi_ip; +		} id_ip; +		struct icmp_ra_addr id_radv; +		uint32_t   id_mask; +		uint8_t    id_data[1]; +	} icmp_dun; +}; + +#define	icmp_pptr	icmp_hun.ih_pptr +#define	icmp_gwaddr	icmp_hun.ih_gwaddr +#define	icmp_id		icmp_hun.ih_idseq.icd_id +#define	icmp_seq	icmp_hun.ih_idseq.icd_seq +#define	icmp_void	icmp_hun.ih_void +#define	icmp_pmvoid	icmp_hun.ih_pmtu.ipm_void +#define	icmp_nextmtu	icmp_hun.ih_pmtu.ipm_nextmtu +#define	icmp_num_addrs	icmp_hun.ih_rtradv.irt_num_addrs +#define	icmp_wpa	icmp_hun.ih_rtradv.irt_wpa +#define	icmp_lifetime	icmp_hun.ih_rtradv.irt_lifetime +#define	icmp_otime	icmp_dun.id_ts.its_otime +#define	icmp_rtime	icmp_dun.id_ts.its_rtime +#define	icmp_ttime	icmp_dun.id_ts.its_ttime +#define	icmp_ip		icmp_dun.id_ip.idi_ip +#define	icmp_radv	icmp_dun.id_radv +#define	icmp_mask	icmp_dun.id_mask +#define	icmp_data	icmp_dun.id_data + +#define	ICMP_MINLEN	8 +#define	ICMP_TSLEN	(8 + 3 * sizeof (n_time)) +#define	ICMP_MASKLEN	12 +#define	ICMP_ADVLENMIN	(8 + sizeof (struct ip) + 8) +#define	ICMP_ADVLEN(p)	(8 + ((p)->icmp_ip.ip_hl << 2) + 8) + +#define	ICMP_UNREACH		3 +#define	ICMP_SOURCEQUENCH	4 +#define	ICMP_ROUTERADVERT	9 +#define	ICMP_ROUTERSOLICIT	10 +#define	ICMP_TIMXCEED		11 +#define	ICMP_PARAMPROB		12 +#define	ICMP_TSTAMP		13 +#define	ICMP_TSTAMPREPLY	14 +#define	ICMP_IREQ		15 +#define	ICMP_IREQREPLY		16 +#define	ICMP_MASKREQ		17 +#define	ICMP_MASKREPLY		18 +#define	ICMP_MAXTYPE		18 + +#define	ICMP_UNREACH_NET	        0 +#define	ICMP_UNREACH_HOST	        1 +#define	ICMP_UNREACH_PROTOCOL	        2 +#define	ICMP_UNREACH_PORT	        3 +#define	ICMP_UNREACH_NEEDFRAG	        4 +#define	ICMP_UNREACH_SRCFAIL	        5 +#define	ICMP_UNREACH_NET_UNKNOWN        6 +#define	ICMP_UNREACH_HOST_UNKNOWN       7 +#define	ICMP_UNREACH_ISOLATED	        8 +#define	ICMP_UNREACH_NET_PROHIB	        9 +#define	ICMP_UNREACH_HOST_PROHIB        10 +#define	ICMP_UNREACH_TOSNET	        11 +#define	ICMP_UNREACH_TOSHOST	        12 +#define	ICMP_UNREACH_FILTER_PROHIB      13 +#define	ICMP_UNREACH_HOST_PRECEDENCE    14 +#define	ICMP_UNREACH_PRECEDENCE_CUTOFF  15 + +#define	ICMP_REDIRECT_NET	0 +#define	ICMP_REDIRECT_HOST	1 +#define	ICMP_REDIRECT_TOSNET	2 +#define	ICMP_REDIRECT_TOSHOST	3 + +#define	ICMP_TIMXCEED_INTRANS	0 +#define	ICMP_TIMXCEED_REASS	1 + +#define	ICMP_PARAMPROB_OPTABSENT 1 + +#define	ICMP_INFOTYPE(type) \ +	((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ +	(type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ +	(type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ +	(type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ +	(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netinet/tcp.h b/include/netinet/tcp.h new file mode 100644 index 00000000..ea32ca07 --- /dev/null +++ b/include/netinet/tcp.h @@ -0,0 +1,6 @@ +#ifndef _NETINET_TCP_H +#define _NETINET_TCP_H + +#include <bits/tcp.h> + +#endif diff --git a/include/netinet/udp.h b/include/netinet/udp.h new file mode 100644 index 00000000..15b91454 --- /dev/null +++ b/include/netinet/udp.h @@ -0,0 +1,35 @@ +#ifndef _NETINET_UDP_H +#define _NETINET_UDP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +struct udphdr { +	uint16_t source; +	uint16_t dest; +	uint16_t len; +	uint16_t check; +}; + +#define uh_sport source +#define uh_dport dest +#define uh_ulen len +#define uh_sum check + +#define UDP_CORK	1 +#define UDP_ENCAP	100 + +#define UDP_ENCAP_ESPINUDP_NON_IKE 1 +#define UDP_ENCAP_ESPINUDP	2 +#define UDP_ENCAP_L2TPINUDP	3 + +#define SOL_UDP            17 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/nl_types.h b/include/nl_types.h new file mode 100644 index 00000000..ca61efb6 --- /dev/null +++ b/include/nl_types.h @@ -0,0 +1,24 @@ +#ifndef _NL_TYPES_H +#define _NL_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define NL_SETD 1 +#define NL_CAT_LOCALE 1 + +#define __NEED_nl_item +#include <bits/alltypes.h> + +typedef long nl_catd; + +nl_catd catopen (const char *, int); +char *catgets (nl_catd, int, int, const char *); +int catclose (nl_catd); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/paths.h b/include/paths.h new file mode 100644 index 00000000..8a38ba7b --- /dev/null +++ b/include/paths.h @@ -0,0 +1,40 @@ +#ifndef _PATHS_H_ +#define	_PATHS_H_ + +#define	_PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin" +#define	_PATH_STDPATH "/bin:/usr/bin:/sbin:/usr/sbin" + +#define	_PATH_BSHELL	"/bin/sh" +#define	_PATH_CONSOLE	"/dev/console" +#define	_PATH_CSHELL	"/bin/csh" +#define	_PATH_DEVDB	"/var/run/dev.db" +#define	_PATH_DEVNULL	"/dev/null" +#define	_PATH_DRUM	"/dev/drum" +#define	_PATH_GSHADOW	"/etc/gshadow" +#define	_PATH_KLOG	"/proc/kmsg" +#define	_PATH_KMEM	"/dev/kmem" +#define	_PATH_LASTLOG	"/var/log/lastlog" +#define	_PATH_MAILDIR	"/var/mail" +#define	_PATH_MAN	"/usr/share/man" +#define	_PATH_MEM	"/dev/mem" +#define	_PATH_MNTTAB	"/etc/fstab" +#define	_PATH_MOUNTED	"/etc/mtab" +#define	_PATH_NOLOGIN	"/etc/nologin" +#define	_PATH_PRESERVE	"/var/lib" +#define	_PATH_RWHODIR	"/var/spool/rwho" +#define	_PATH_SENDMAIL	"/usr/sbin/sendmail" +#define	_PATH_SHADOW	"/etc/shadow" +#define	_PATH_SHELLS	"/etc/shells" +#define	_PATH_TTY	"/dev/tty" +#define	_PATH_UNIX	"/boot/vmlinux" +#define _PATH_UTMP	"/var/run/utmp" +#define	_PATH_VI	"/usr/bin/vi" +#define _PATH_WTMP	"/var/log/wtmp" + +#define	_PATH_DEV	"/dev/" +#define	_PATH_TMP	"/tmp/" +#define	_PATH_VARDB	"/var/lib/misc/" +#define	_PATH_VARRUN	"/var/run/" +#define	_PATH_VARTMP	"/var/tmp/" + +#endif diff --git a/include/poll.h b/include/poll.h new file mode 100644 index 00000000..f868ab57 --- /dev/null +++ b/include/poll.h @@ -0,0 +1,35 @@ +#ifndef	_POLL_H +#define	_POLL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define POLLIN     0x001 +#define POLLPRI    0x002 +#define POLLOUT    0x004 +#define POLLERR    0x008 +#define POLLHUP    0x010 +#define POLLNVAL   0x020 +#define POLLRDNORM 0x040 +#define POLLRDBAND 0x080 +#define POLLWRNORM 0x100 +#define POLLWRBAND 0x200 +#define POLLMSG    0x400 + +typedef unsigned int nfds_t; + +struct pollfd +{ +	int fd; +	short events; +	short revents; +}; + +int poll (struct pollfd *, nfds_t, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/pthread.h b/include/pthread.h new file mode 100644 index 00000000..ce6273d2 --- /dev/null +++ b/include/pthread.h @@ -0,0 +1,216 @@ +#ifndef _PTHREAD_H +#define _PTHREAD_H +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_time_t +#define __NEED_struct_timespec +#define __NEED_sigset_t +#define __NEED_pthread_t +#define __NEED_size_t + +#include <bits/alltypes.h> + +struct sched_param; + +typedef int pthread_once_t, pthread_key_t, pthread_spinlock_t; +typedef int pthread_mutexattr_t, pthread_condattr_t, pthread_barrierattr_t; + +typedef struct { +	size_t __guardsize; +	size_t __stacksize; +	unsigned __detach : 1; +	unsigned __pad : 31; +	int __attr[6]; +} pthread_attr_t; + +typedef struct { +	int __attr[2]; +} pthread_rwlockattr_t; + +typedef struct { +	int __type; +	int __lock; +	pthread_t __owner; +	int __pad2; +	int __waiters; +	int __pad; +} pthread_mutex_t; + +typedef struct { +	int __block; +	int __pad[11]; +} pthread_cond_t; + +typedef struct { +	int __wrlock; +	int __readers; +	int __waiters; +	int __owner; +	int __pad[4]; +} pthread_rwlock_t; + +typedef struct { +	int __count; +	int __limit; +	int __left; +	int __waiters; +	int __barrier[1]; +} pthread_barrier_t; + +#define PTHREAD_CREATE_JOINABLE 0 +#define PTHREAD_CREATE_DETACHED 1 + +#define PTHREAD_MUTEX_NORMAL 0 +#define PTHREAD_MUTEX_DEFAULT 0 +#define PTHREAD_MUTEX_RECURSIVE 1 +#define PTHREAD_MUTEX_ERRORCHECK 2 + +#define PTHREAD_MUTEX_STALLED 0 +#define PTHREAD_MUTEX_ROBUST 1 + +#define PTHREAD_PRIO_NONE 0 +#define PTHREAD_PRIO_INHERIT 1 +#define PTHREAD_PRIO_PROTECT 2 + +#define PTHREAD_INHERIT_SCHED 0 +#define PTHREAD_EXPLICIT_SCHED 1 + +#define PTHREAD_SCOPE_SYSTEM 0 +#define PTHREAD_SCOPE_PROCESS 1 + +#define PTHREAD_PROCESS_PRIVATE 0 +#define PTHREAD_PROCESS_SHARED 1 + + +#define PTHREAD_MUTEX_INITIALIZER {0} +#define PTHREAD_RWLOCK_INITIALIZER {0} +#define PTHREAD_COND_INITIALIZER {0} +#define PTHREAD_ONCE_INIT 0 + + +#define PTHREAD_CANCEL_ENABLE 0 +#define PTHREAD_CANCEL_DISABLE 1 + +#define PTHREAD_CANCEL_DEFERRED 0 +#define PTHREAD_CANCEL_ASYNCHRONOUS 1 + +#define PTHREAD_CANCELLED ((void *)-1) + + +#define PTHREAD_BARRIER_SERIAL_THREAD (-1) + + +int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *); +int pthread_detach(pthread_t); +void pthread_exit(void *); +int pthread_join(pthread_t, void **); + +pthread_t pthread_self(void); +int pthread_equal(pthread_t, pthread_t); + +int pthread_setcancelstate(int, int *); +int pthread_setcanceltype(int, int *); +void pthread_testcancel(void); +int pthread_cancel(pthread_t); + +int pthread_once(pthread_once_t *, void (*)(void)); + +int pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *); +int pthread_mutex_lock(pthread_mutex_t *); +int pthread_mutex_unlock(pthread_mutex_t *); +int pthread_mutex_trylock(pthread_mutex_t *); +int pthread_mutex_destroy(pthread_mutex_t *); + +int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *); +int pthread_cond_destroy(pthread_cond_t *); +int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); +int pthread_cond_timedwait(pthread_cond_t *, pthread_mutex_t *, const struct timespec *); +int pthread_cond_broadcast(pthread_cond_t *); +int pthread_cond_signal(pthread_cond_t *); + +int pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *); +int pthread_rwlock_destroy(pthread_rwlock_t *); +int pthread_rwlock_rdlock(pthread_rwlock_t *); +int pthread_rwlock_tryrdlock(pthread_rwlock_t *); +int pthread_rwlock_timedrdlock(pthread_rwlock_t *, const struct timespec *); +int pthread_rwlock_wrlock(pthread_rwlock_t *); +int pthread_rwlock_trywrlock(pthread_rwlock_t *); +int pthread_rwlock_timedwrlock(pthread_rwlock_t *, const struct timespec *); +int pthread_rwlock_unlock(pthread_rwlock_t *); + +int pthread_spin_init(pthread_spinlock_t *, int); +int pthread_spin_destroy(pthread_spinlock_t *); +int pthread_spin_lock(pthread_spinlock_t *); +int pthread_spin_trylock(pthread_spinlock_t *); +int pthread_spin_unlock(pthread_spinlock_t *); + +int pthread_barrier_init(pthread_barrier_t *, const pthread_barrierattr_t *, unsigned); +int pthread_barrier_destroy(pthread_barrier_t *); +int pthread_barrier_wait(pthread_barrier_t *); + +int pthread_key_create(pthread_key_t *, void (*)(void *)); +int pthread_key_delete(pthread_key_t); +void *pthread_getspecific(pthread_key_t); +int pthread_setspecific(pthread_key_t, const void *); + +int pthread_attr_init(pthread_attr_t *); +int pthread_attr_destroy(pthread_attr_t *); + +int pthread_attr_getguardsize(pthread_attr_t *, size_t *); +int pthread_attr_setguardsize(pthread_attr_t *, size_t); +int pthread_attr_getstacksize(pthread_attr_t *, size_t *); +int pthread_attr_setstacksize(pthread_attr_t *, size_t); +int pthread_attr_getdetachstate(pthread_attr_t *, int *); +int pthread_attr_setdetachstate(pthread_attr_t *, int); +int pthread_attr_getstack(pthread_attr_t *, void **, size_t *); +int pthread_attr_setstack(pthread_attr_t *, void *, size_t); +int pthread_attr_getscope(pthread_attr_t *, int *); +int pthread_attr_setscope(pthread_attr_t *, int); +int pthread_attr_getschedpolicy(pthread_attr_t *, int *); +int pthread_attr_setschedpolicy(pthread_attr_t *, int); +int pthread_attr_getschedparam(pthread_attr_t *, struct sched_param *); +int pthread_attr_setschedparam(pthread_attr_t *, const struct sched_param *); +int pthread_attr_getinheritsched(pthread_attr_t *, int *); +int pthread_attr_setinheritsched(pthread_attr_t *, int); + +int pthread_mutexattr_destroy(pthread_mutexattr_t *); +int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *, int *); +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *, int *); +int pthread_mutexattr_getpshared(const pthread_mutexattr_t *, int *); +int pthread_mutexattr_getrobust(const pthread_mutexattr_t *, int *); +int pthread_mutexattr_gettype(const pthread_mutexattr_t *, int *); +int pthread_mutexattr_init(pthread_mutexattr_t *); +int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *, int); +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *, int); +int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int); +int pthread_mutexattr_setrobust(pthread_mutexattr_t *, int); +int pthread_mutexattr_settype(pthread_mutexattr_t *, int); + +int pthread_barrierattr_destroy(pthread_barrierattr_t *); +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *, int *); +int pthread_barrierattr_init(pthread_barrierattr_t *); +int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int); + +#include <bits/pthread.h> + +int __setjmp(void *); +void __pthread_register_cancel(struct __ptcb *); +void __pthread_unregister_cancel(struct __ptcb *); +void __pthread_unwind_next(struct __ptcb *); + +#define pthread_cleanup_push(f, x) \ +do { struct __ptcb __cb; void (*__f)(void *) = (f); void *__x = (x); \ +if (__setjmp(__cb.__jb)) __f(__x), __pthread_unwind_next(&__cb); \ +__pthread_register_cancel(&__cb); { + +#define pthread_cleanup_pop(r) ; } \ +__pthread_unregister_cancel(&__cb); \ +if (r) __f(__x); } while (0) + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/pty.h b/include/pty.h new file mode 100644 index 00000000..9444e5ec --- /dev/null +++ b/include/pty.h @@ -0,0 +1,17 @@ +#ifndef	_PTY_H +#define	_PTY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <termios.h> +#include <sys/ioctl.h> + +int openpty(int *, int *, char *, const struct termios *, const struct winsize *); + +#ifdef __cplusplus +extern } +#endif + +#endif diff --git a/include/pwd.h b/include/pwd.h new file mode 100644 index 00000000..5abfbfd5 --- /dev/null +++ b/include/pwd.h @@ -0,0 +1,38 @@ +#ifndef _PWD_H +#define _PWD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t +#define __NEED_uid_t +#define __NEED_gid_t + +#include <bits/alltypes.h> + +struct passwd +{ +	char *pw_name; +	char *pw_passwd; +	uid_t pw_uid; +	gid_t pw_gid; +	char *pw_gecos; +	char *pw_dir; +	char *pw_shell; +}; + +void setpwent (void); +void endpwent (void); +struct passwd *getpwent (void); + +struct passwd *getpwuid (uid_t); +struct passwd *getpwnam (const char *); +int getpwuid_r (uid_t, struct passwd *, char *, size_t, struct passwd **); +int getpwnam_r (const char *, struct passwd *, char *, size_t, struct passwd **); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/regex.h b/include/regex.h new file mode 100644 index 00000000..3673bfa7 --- /dev/null +++ b/include/regex.h @@ -0,0 +1,59 @@ +#ifndef _REGEX_H +#define _REGEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t + +#include <bits/alltypes.h> + +typedef long regoff_t; + +typedef struct { +	size_t re_nsub; +	void *__opaque; +} regex_t; + +typedef struct { +	regoff_t rm_so; +	regoff_t rm_eo; +} regmatch_t; + +#define REG_EXTENDED    1 +#define REG_ICASE       2 +#define REG_NEWLINE     4 +#define REG_NOSUB       8 + +#define REG_NOTBOL      1 +#define REG_NOTEOL      2 + +#define REG_OK          0 +#define REG_NOMATCH     1 +#define REG_BADPAT      2 +#define REG_ECOLLATE    3 +#define REG_ECTYPE      4 +#define REG_EESCAPE     5 +#define REG_ESUBREG     6 +#define REG_EBRACK      7 +#define REG_EPAREN      8 +#define REG_EBRACE      9 +#define REG_BADBR       10 +#define REG_ERANGE      11 +#define REG_ESPACE      12 +#define REG_BADRPT      13 + +#define REG_ENOSYS      -1 + +int regcomp(regex_t *, const char *, int); +int regexec(const regex_t *, const char *, size_t, regmatch_t [], int); +void regfree(regex_t *); + +size_t regerror(int, const regex_t *, char *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/resolv.h b/include/resolv.h new file mode 100644 index 00000000..3b77fc7b --- /dev/null +++ b/include/resolv.h @@ -0,0 +1,143 @@ +#ifndef _RESOLV_H_ +#define _RESOLV_H_ + +#include <stdint.h> +#include <arpa/nameser.h> +#include <netinet/in.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAXNS			3 +#define MAXDFLSRCH		3 +#define MAXDNSRCH		6 +#define LOCALDOMAINPARTS	2 + +#define RES_TIMEOUT		5 +#define MAXRESOLVSORT		10 +#define RES_MAXNDOTS		15 +#define RES_MAXRETRANS		30 +#define RES_MAXRETRY		5 +#define RES_DFLRETRY		2 +#define RES_MAXTIME		65535 + +/* unused; purely for broken apps */ +typedef struct __res_state { +	int retrans; +	int retry; +	unsigned long options; +	int nscount; +	struct sockaddr_in nsaddr_list[MAXNS]; +# define nsaddr	nsaddr_list[0] +	unsigned short id; +	char *dnsrch[MAXDNSRCH+1]; +	char defdname[256]; +	unsigned long pfcode; +	unsigned ndots:4; +	unsigned nsort:4; +	unsigned ipv6_unavail:1; +	unsigned unused:23; +	struct { +		struct in_addr addr; +		uint32_t mask; +	} sort_list[MAXRESOLVSORT]; +	void *qhook; +	void *rhook; +	int res_h_errno; +	int _vcsock; +	unsigned _flags; +	union { +		char pad[52]; +		struct { +			uint16_t		nscount; +			uint16_t		nsmap[MAXNS]; +			int			nssocks[MAXNS]; +			uint16_t		nscount6; +			uint16_t		nsinit; +			struct sockaddr_in6	*nsaddrs[MAXNS]; +			unsigned int		_initstamp[2]; +		} _ext; +	} _u; +} *res_state; + +#define	__RES	19991006 + +#ifndef _PATH_RESCONF +#define _PATH_RESCONF        "/etc/resolv.conf" +#endif + +struct res_sym { +	int number; +	char *name; +	char *humanname; +}; + +#define	RES_F_VC	0x00000001 +#define	RES_F_CONN	0x00000002 +#define RES_F_EDNS0ERR	0x00000004 + +#define	RES_EXHAUSTIVE	0x00000001 + +#define RES_INIT	0x00000001 +#define RES_DEBUG	0x00000002 +#define RES_AAONLY	0x00000004 +#define RES_USEVC	0x00000008 +#define RES_PRIMARY	0x00000010 +#define RES_IGNTC	0x00000020 +#define RES_RECURSE	0x00000040 +#define RES_DEFNAMES	0x00000080 +#define RES_STAYOPEN	0x00000100 +#define RES_DNSRCH	0x00000200 +#define	RES_INSECURE1	0x00000400 +#define	RES_INSECURE2	0x00000800 +#define	RES_NOALIASES	0x00001000 +#define	RES_USE_INET6	0x00002000 +#define RES_ROTATE	0x00004000 +#define	RES_NOCHECKNAME	0x00008000 +#define	RES_KEEPTSIG	0x00010000 +#define	RES_BLAST	0x00020000 +#define RES_USEBSTRING	0x00040000 +#define RES_NOIP6DOTINT	0x00080000 +#define RES_USE_EDNS0	0x00100000 +#define RES_SNGLKUP	0x00200000 +#define RES_SNGLKUPREOP	0x00400000 +#define RES_USE_DNSSEC	0x00800000 + +#define RES_DEFAULT	(RES_RECURSE|RES_DEFNAMES|RES_DNSRCH|RES_NOIP6DOTINT) + +#define RES_PRF_STATS	0x00000001 +#define RES_PRF_UPDATE	0x00000002 +#define RES_PRF_CLASS   0x00000004 +#define RES_PRF_CMD	0x00000008 +#define RES_PRF_QUES	0x00000010 +#define RES_PRF_ANS	0x00000020 +#define RES_PRF_AUTH	0x00000040 +#define RES_PRF_ADD	0x00000080 +#define RES_PRF_HEAD1	0x00000100 +#define RES_PRF_HEAD2	0x00000200 +#define RES_PRF_TTLID	0x00000400 +#define RES_PRF_HEADX	0x00000800 +#define RES_PRF_QUERY	0x00001000 +#define RES_PRF_REPLY	0x00002000 +#define RES_PRF_INIT	0x00004000 + +extern struct __res_state *__res_state(void); +#define _res (*__res_state()) + +struct rrec; + +int res_init(void); +int res_query(const char *, int, int, unsigned char *, int); +int res_querydomain(const char *, const char *, int, int, unsigned char *, int); +int res_search(const char *, int, int, unsigned char *, int); +int res_mkquery(int, const char *, int, int, char *, int, struct rrec *, char *, int); +int res_send(const char *, int, char *, int); +int dn_comp(unsigned char *, unsigned char *, int, unsigned char **, unsigned char *, unsigned char **); +int dn_expand(unsigned char *, unsigned char *, unsigned char *, unsigned char *, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/sched.h b/include/sched.h new file mode 100644 index 00000000..4d8bd3db --- /dev/null +++ b/include/sched.h @@ -0,0 +1,37 @@ +#ifndef _SCHED_H +#define _SCHED_H +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_struct_timespec +#define __NEED_pid_t +#define __NEED_time_t + +#include <bits/alltypes.h> + +struct sched_param { +	int sched_priority; +	int sched_ss_low_priority; +	struct timespec sched_ss_repl_period; +	struct timespec sched_ss_init_budget; +	int sched_ss_max_repl; +}; + +int    sched_get_priority_max(int); +int    sched_get_priority_min(int); +int    sched_getparam(pid_t, struct sched_param *); +int    sched_getscheduler(pid_t); +int    sched_rr_get_interval(pid_t, struct timespec *); +int    sched_setparam(pid_t, const struct sched_param *); +int    sched_setscheduler(pid_t, int, const struct sched_param *); +int     sched_yield(void); + +#define SCHED_OTHER 0 +#define SCHED_FIFO 1 +#define SCHED_RR 2 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/search.h b/include/search.h new file mode 100644 index 00000000..9254ed0c --- /dev/null +++ b/include/search.h @@ -0,0 +1,6 @@ +#ifndef _SEARCH_H +#define _SEARCH_H + +// FIXME!!! + +#endif diff --git a/include/semaphore.h b/include/semaphore.h new file mode 100644 index 00000000..5b68986d --- /dev/null +++ b/include/semaphore.h @@ -0,0 +1,27 @@ +#ifndef _SEMAPHORE_H +#define _SEMAPHORE_H +#ifdef __cplusplus +extern "C" { +#endif + +#define SEM_FAILED ((sem_t *)0) + +typedef struct { +	long __val[4]; +} sem_t; + +int    sem_close(sem_t *); +int    sem_destroy(sem_t *); +int    sem_getvalue(sem_t *, int *); +int    sem_init(sem_t *, int, unsigned); +sem_t *sem_open(const char *, int, ...); +int    sem_post(sem_t *); +int    sem_timedwait(sem_t *, const struct timespec *); +int    sem_trywait(sem_t *); +int    sem_unlink(const char *); +int    sem_wait(sem_t *); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/setjmp.h b/include/setjmp.h new file mode 100644 index 00000000..6288c846 --- /dev/null +++ b/include/setjmp.h @@ -0,0 +1,30 @@ +#ifndef	_SETJMP_H +#define	_SETJMP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <bits/setjmp.h> +typedef unsigned long sigjmp_buf[(1024+sizeof(jmp_buf))/sizeof(long)]; + +#ifdef _GNU_SOURCE +#define jmp_buf sigjmp_buf +#endif + +int setjmp (jmp_buf); +int _setjmp (jmp_buf); +int sigsetjmp (sigjmp_buf, int); + +void longjmp (jmp_buf, int); +void _longjmp (jmp_buf, int); +void siglongjmp (sigjmp_buf, int); + +#define setjmp setjmp +#define longjmp longjmp + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/shadow.h b/include/shadow.h new file mode 100644 index 00000000..2b1be413 --- /dev/null +++ b/include/shadow.h @@ -0,0 +1,44 @@ +#ifndef _SHADOW_H +#define _SHADOW_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define	__NEED_FILE +#define __NEED_size_t + +#include <bits/alltypes.h> + +#define	SHADOW "/etc/shadow" + +struct spwd { +	char *sp_namp; +	char *sp_pwdp; +	long sp_lstchg; +	long sp_min; +	long sp_max; +	long sp_warn; +	long sp_inact; +	long sp_expire; +	unsigned long sp_flag; +}; + +void setspent(void); +void endspent(void); +struct spwd *getspent(void); +struct spwd *fgetspent(FILE *); +struct spwd *sgetspent(const char *); +int putspent(const struct spwd *, FILE *); + +struct spwd *getspnam(const char *); +int getspnam_r(const char *, struct spwd *, char *, size_t, struct spwd **); + +int lckpwdf(void); +int ulckpwdf(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/signal.h b/include/signal.h new file mode 100644 index 00000000..540236a5 --- /dev/null +++ b/include/signal.h @@ -0,0 +1,98 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t +#define __NEED_pid_t +#define __NEED_uid_t +#define __NEED_struct_timespec +#define __NEED_pthread_t +#define __NEED_time_t +#define __NEED_clock_t +#define __NEED_sigset_t +#define __NEED_siginfo_t + +#include <bits/alltypes.h> + +typedef int sig_atomic_t; + +struct sigaction +{ +	union { +		void (*sa_handler)(int); +		void (*sa_sigaction)(int, siginfo_t *, void *); +	} __sa_handler; +	sigset_t sa_mask; +	int sa_flags; +	void (*__sa_restorer)(void);	 +}; +#define sa_handler   __sa_handler.sa_handler +#define sa_sigaction __sa_handler.sa_sigaction + +typedef struct +{ +	void *ss_sp; +	int ss_flags; +	size_t ss_size; +} stack_t; + +union sigval +{ +	int sival_int; +	void *sival_ptr; +}; + +#include <bits/signal.h> + +int __libc_current_sigrtmin(void); +int __libc_current_sigrtmax(void); + +#define SIGRTMIN  (__libc_current_sigrtmin()) +#define SIGRTMAX  (__libc_current_sigrtmax()) + +void (*signal(int, void (*)(int)))(int); +void (*bsd_signal(int, void (*)(int)))(int); +int kill(pid_t, int); +int killpg(pid_t, int); +int raise(int); +int sigpause(int); + +int sigemptyset(sigset_t *); +int sigfillset(sigset_t *); +int sigaddset(sigset_t *, int); +int sigdelset(sigset_t *, int); +int sigismember(const sigset_t *, int); + +int sigprocmask(int, const sigset_t *, sigset_t *); +int sigsuspend(const sigset_t *); +int sigaction(int, const struct sigaction *, struct sigaction *); +int sigpending(sigset_t *); +int sigwait(const sigset_t *, int *); +int sigwaitinfo(const sigset_t *, siginfo_t *); +int sigtimedwait(const sigset_t *, siginfo_t *, const struct timespec *); +int sigqueue(pid_t, int, const union sigval); + +int siginterrupt(int, int); + +int sigaltstack(const stack_t *, stack_t *); + +int sighold(int); +int sigrelse(int); +int sigignore(int); +void (*sigset(int, void (*)(int)))(int); + +int pthread_sigmask(int, const sigset_t *, sigset_t *); +int pthread_kill(pthread_t, int); + +#ifdef _GNU_SOURCE +typedef int (*sighandler_t)(int); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/stdarg.h b/include/stdarg.h new file mode 100644 index 00000000..cb18778b --- /dev/null +++ b/include/stdarg.h @@ -0,0 +1,32 @@ +#ifndef _STDARG_H +#define _STDARG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_va_list + +#include <bits/alltypes.h> + +#define __VA_ALIGNED_SIZE(x) ((sizeof(x) + sizeof(int) - 1) & ~(sizeof(int) - 1)) + +#define va_start(ap, last) ((ap) = (void *)(((char *)&(last)) + __VA_ALIGNED_SIZE(last))) +#define va_end(ap) ((void)0) +#define va_copy(dest, src) ((dest) = (src)) + +#if 0 +#define va_arg(ap, type) \ +	( ((ap) = (va_list)((char *)(ap) + sizeof(type))), \ +	*(type *)(void *)((char *)(ap) - sizeof(type)) ) +#endif + +#define va_arg(ap, type) \ +	( ((ap) = (va_list)((char *)(ap) + __VA_ALIGNED_SIZE(type))), \ +	*(type *)(void *)((char *)(ap) - __VA_ALIGNED_SIZE(type)) ) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/stdbool.h b/include/stdbool.h new file mode 100644 index 00000000..3d8fbf2a --- /dev/null +++ b/include/stdbool.h @@ -0,0 +1,13 @@ +#ifndef _STDBOOL_H +#define _STDBOOL_H + +#ifndef __cplusplus + +#define true 1 +#define false 0 + +typedef _Bool bool; + +#endif + +#endif diff --git a/include/stddef.h b/include/stddef.h new file mode 100644 index 00000000..dbf5a4ae --- /dev/null +++ b/include/stddef.h @@ -0,0 +1,19 @@ +#ifndef _STDDEF_H +#define _STDDEF_H + +#undef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void*)0) +#endif + +#define __NEED_ptrdiff_t +#define __NEED_size_t +#define __NEED_wchar_t + +#include <bits/alltypes.h> + +#define offsetof(type, member) ((size_t)( (char *)&(((type *)0)->member) - (char *)0 )) + +#endif diff --git a/include/stdint.h b/include/stdint.h new file mode 100644 index 00000000..4d24fd2e --- /dev/null +++ b/include/stdint.h @@ -0,0 +1,107 @@ +#ifndef _STDINT_H +#define _STDINT_H + +#define __NEED_int8_t +#define __NEED_int16_t +#define __NEED_int32_t +#define __NEED_int64_t + +#define __NEED_uint8_t +#define __NEED_uint16_t +#define __NEED_uint32_t +#define __NEED_uint64_t + +#define __NEED_int_least8_t +#define __NEED_int_least16_t +#define __NEED_int_least32_t +#define __NEED_int_least64_t + +#define __NEED_uint_least8_t +#define __NEED_uint_least16_t +#define __NEED_uint_least32_t +#define __NEED_uint_least64_t + +#define __NEED_int_fast8_t +#define __NEED_int_fast16_t +#define __NEED_int_fast32_t +#define __NEED_int_fast64_t + +#define __NEED_uint_fast8_t +#define __NEED_uint_fast16_t +#define __NEED_uint_fast32_t +#define __NEED_uint_fast64_t + +#define __NEED_intptr_t +#define __NEED_uintptr_t +#define __NEED_intmax_t +#define __NEED_uintmax_t + +#include <bits/alltypes.h> + +#if !defined __cplusplus || defined __STDC_LIMIT_MACROS + +#define INT8_MIN   (-1-0x7f) +#define INT16_MIN  (-1-0x7fff) +#define INT32_MIN  (-1-0x7fffffff) +#define INT64_MIN  (-1-0x7fffffffffffffffLL) + +#define INT8_MAX   (0x7f) +#define INT16_MAX  (0x7fff) +#define INT32_MAX  (0x7fffffff) +#define INT64_MAX  (0x7fffffffffffffffLL) + +#define UINT8_MAX  (0xff) +#define UINT16_MAX (0xffff) +#define UINT32_MAX (0xffffffff) +#define UINT64_MAX (0xffffffffffffffffULL) + +#define INT_LEAST8_MIN   INT8_MIN +#define INT_LEAST16_MIN  INT16_MIN +#define INT_LEAST32_MIN  INT32_MIN +#define INT_LEAST64_MIN  INT64_MIN + +#define INT_LEAST8_MAX   INT8_MAX +#define INT_LEAST16_MAX  INT16_MAX +#define INT_LEAST32_MAX  INT32_MAX +#define INT_LEAST64_MAX  INT64_MAX + +#define UINT_LEAST8_MAX  UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +#undef WCHAR_MIN +#undef WCHAR_MAX +#undef WINT_MIN +#undef WINT_MAX +#define WCHAR_MIN INT32_MIN +#define WCHAR_MAX INT32_MAX +#define WINT_MIN INT32_MIN +#define WINT_MAX INT32_MAX + +#define INTMAX_MIN  INT64_MIN +#define INTMAX_MAX  INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +#include <bits/stdint.h> + +#endif + +#if !defined __cplusplus || defined __STDC_CONSTANT_MACROS + +#define INT8_C(c)  c +#define INT16_C(c) c +#define INT32_C(c) c +#define INT64_C(c) c ## LL + +#define UINT8_C(c)  c ## U +#define UINT16_C(c) c ## U +#define UINT32_C(c) c ## U +#define UINT64_C(c) c ## ULL + +#define INTMAX_C(c)  c ## LL +#define UINTMAX_C(c) c ## ULL + +#endif + +#endif diff --git a/include/stdio.h b/include/stdio.h new file mode 100644 index 00000000..b00436d9 --- /dev/null +++ b/include/stdio.h @@ -0,0 +1,144 @@ +#ifndef _STDIO_H +#define _STDIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_FILE +#define __NEED_va_list +#define __NEED_size_t +#define __NEED_ssize_t +#define __NEED_off_t + +#include <bits/alltypes.h> + +#undef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void*)0) +#endif + +#undef EOF +#define EOF (-1) + +#undef SEEK_SET +#undef SEEK_CUR +#undef SEEK_END +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define _IOFBF 0 +#define _IOLBF 1 +#define _IONBF 2 + +#include <bits/stdio.h> + +typedef union { +	char __opaque[16]; +	double __align; +} fpos_t; + +extern FILE *const stdin; +extern FILE *const stdout; +extern FILE *const stderr; + +#define stdin  (stdin) +#define stdout (stdout) +#define stderr (stderr) + +FILE *fopen(const char *, const char *); +FILE *fdopen(int, const char *); +FILE *freopen(const char *, const char *, FILE *); +int fclose(FILE *); + +FILE *popen(const char *, const char *); +int pclose(FILE *); + +int remove(const char *); +int rename(const char *, const char *); + +int fileno(FILE *); +int feof(FILE *); +int ferror(FILE *); +int fflush(FILE *); +void clearerr(FILE *); + +int fseek(FILE *, long, int); +int fseeko(FILE *, off_t, int); +long ftell(FILE *); +off_t ftello(FILE *); +void rewind(FILE *); + +int fgetpos(FILE *, fpos_t *); +int fsetpos(FILE *, const fpos_t *); + +size_t fread(void *, size_t, size_t, FILE *); +size_t fwrite(const void *, size_t, size_t, FILE *); + +int fgetc(FILE *); +int getc(FILE *); +int getchar(void); +int ungetc(int, FILE *); + +int fputc(int, FILE *); +int putc(int, FILE *); +int putchar(int); + +char *fgets(char *, int, FILE *); +char *gets(char *); + +int fputs(const char *, FILE *); +int puts(const char *); + +int printf(const char *, ...); +int fprintf(FILE *, const char *, ...); +int sprintf(char *, const char *, ...); +int snprintf(char *, size_t, const char *, ...); + +int vprintf(const char *, va_list); +int vfprintf(FILE *, const char *, va_list); +int vsprintf(char *, const char *, va_list); +int vsnprintf(char *, size_t, const char *, va_list); + +int dprintf(int, const char *, ...); +int vdprintf(int, const char *, va_list); + +int scanf(const char *, ...); +int fscanf(FILE *, const char *, ...); +int sscanf(const char *, const char *, ...); +int vscanf(const char *, va_list); +int vfscanf(FILE *, const char *, va_list); +int vsscanf(const char *, const char *, va_list); + +void perror(const char *); + +void flockfile(FILE *); +int ftrylockfile(FILE *); +void funlockfile(FILE *); +int getc_unlocked(FILE *); +int getchar_unlocked(void); +int putc_unlocked(int, FILE *); +int putchar_unlocked(int); + +int setvbuf(FILE *, char *, int, size_t); +void setbuf(FILE *, char *); + +char *tmpnam(char *); +char *tempnam(const char *, const char *); +FILE *tmpfile(void); + +char *ctermid(char *); + +ssize_t getdelim(char **, size_t *, int, FILE *); +ssize_t getline(char **, size_t *, FILE *); + +int renameat(int, const char *, int, const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/stdlib.h b/include/stdlib.h new file mode 100644 index 00000000..6dbbc9cb --- /dev/null +++ b/include/stdlib.h @@ -0,0 +1,129 @@ +#ifndef _STDLIB_H +#define _STDLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#undef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void*)0) +#endif + +#define __NEED_size_t +#define __NEED_wchar_t + +#include <bits/alltypes.h> + +int atoi (const char *); +long atol (const char *); +long long atoll (const char *); +double atof (const char *); + +float strtof (const char *, char **); +double strtod (const char *, char **); +long double strtold (const char *, char **); + +long strtol (const char *, char **, int); +unsigned long strtoul (const char *, char **, int); + +long long strtoll (const char *, char **, int); +unsigned long long strtoull (const char *, char **, int); + +char *l64a (long); +long a64l (const char *); + +long int random (void); +void srandom (unsigned int); +char *initstate (unsigned int, char *, size_t); +char *setstate (char *); + +int rand (void); +void srand (unsigned); +int rand_r (unsigned *); + +double drand48 (void); +double erand48 (unsigned short [3]); +long int lrand48 (void); +long int nrand48 (unsigned short [3]); +long mrand48 (void); +long jrand48 (unsigned short [3]); +void srand48 (long); +unsigned short *seed48 (unsigned short [3]); +void lcong48 (unsigned short [7]); + +void *malloc (size_t); +void *calloc (size_t, size_t); +void *realloc (void *, size_t); +void free (void *); +void *valloc (size_t); +int posix_memalign (void **, size_t, size_t); + +void abort (void); +int atexit (void (*) (void)); +void exit (int); +void _Exit (int); + + +char *getenv (const char *); +int putenv (char *); +int setenv (const char *, const char *, int); +int unsetenv (const char *); + + +char *mktemp (char *); +int mkstemp (char *); + +int system (const char *); + + +char *realpath (const char *, char *); + +void *bsearch (const void *, const void *, size_t, size_t, int (*)(const void *, const void *)); +void qsort (void *, size_t, size_t, int (*)(const void *, const void *)); + +int abs (int); +long labs (long); +long long llabs (long long); + +typedef struct { int quot, rem; } div_t; +extern div_t div (int, int); + +typedef struct { long quot, rem; } ldiv_t; +ldiv_t ldiv (long, long); + +typedef struct { long long quot, rem; } lldiv_t; +lldiv_t lldiv (long long, long long); + + +int mblen (const char *, size_t); +int mbtowc (wchar_t *, const char *, size_t); +int wctomb (char *, wchar_t); +size_t mbstowcs (wchar_t *, const char *, size_t); +size_t wcstombs (char *, const wchar_t *, size_t); + +int getsubopt (char **, char *const *, char **); + +void setkey (const char *); + +int posix_openpt (int); +int grantpt (int); +int unlockpt (int); +char *ptsname (int); + +#define MB_CUR_MAX 4 + +#define RAND_MAX (0x7fffffff) + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +#include <bits/wexitstatus.h> + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/string.h b/include/string.h new file mode 100644 index 00000000..f189c082 --- /dev/null +++ b/include/string.h @@ -0,0 +1,72 @@ +#ifndef	_STRING_H +#define	_STRING_H + +#ifdef __cplusplus +extern "C" { +#endif + +#undef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void*)0) +#endif + +#define __NEED_size_t +#include <bits/alltypes.h> + +void *memcpy (void *, const void *, size_t); +void *memmove (void *, const void *, size_t); +void *memccpy (void *, const void *, int, size_t); +void *memset (void *, int, size_t); +int memcmp (const void *, const void *, size_t); +void *memchr (const void *, int, size_t); + +char *strcpy (char *, const char *); +char *strncpy (char *, const char *, size_t); + +char *strcat (char *, const char *); +char *strncat (char *, const char *, size_t); + +int strcmp (const char *, const char *); +int strncmp (const char *, const char *, size_t); + +int strcoll (const char *, const char *); +size_t strxfrm (char *, const char *, size_t); + +char *strdup (const char *); + +char *strchr (const char *, int); +char *strrchr (const char *, int); + +size_t strcspn (const char *, const char *); +size_t strspn (const char *, const char *); +char *strpbrk (const char *, const char *); +char *strstr (const char *, const char *); + +char *strtok (char *, const char *); +char *strtok_r (char *, const char *, char **); + +size_t strlen (const char *); + +char *strerror (int); +int strerror_r (int, char *, size_t); + +size_t strlcat (char *, const char *, size_t); +size_t strlcpy (char *, const char *, size_t); + +char *stpcpy(char *, const char *); +char *stpncpy(char *, const char *, size_t); +size_t strnlen (const char *, size_t); + +#ifdef _GNU_SOURCE +int strcasecmp (const char *, const char *); +int strncasecmp (const char *, const char *, size_t); +char *strchrnul(const char *, int); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/strings.h b/include/strings.h new file mode 100644 index 00000000..059e3309 --- /dev/null +++ b/include/strings.h @@ -0,0 +1,36 @@ +#ifndef	_STRINGS_H +#define	_STRINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#undef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void*)0) +#endif + + +#define __NEED_size_t +#include <bits/alltypes.h> + + +int bcmp (const void *, const void *, size_t); +void bcopy (const void *, void *, size_t); +void bzero (void *, size_t); + +int ffs (int); + +char *index (const char *, int); +char *rindex (const char *, int); + +int strcasecmp (const char *, const char *); +int strncasecmp (const char *, const char *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/stropts.h b/include/stropts.h new file mode 100644 index 00000000..80776ba6 --- /dev/null +++ b/include/stropts.h @@ -0,0 +1,16 @@ +#ifndef _STROPTS_H +#define _STROPTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +// FIXME + +int ioctl (int, int, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/sys/epoll.h b/include/sys/epoll.h new file mode 100644 index 00000000..3530a9ac --- /dev/null +++ b/include/sys/epoll.h @@ -0,0 +1,61 @@ +#ifndef	_SYS_EPOLL_H +#define	_SYS_EPOLL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <sys/types.h> + +#define __NEED_sigset_t + +#include <bits/alltypes.h> + +#define EPOLL_CLOEXEC 02000000 +#define EPOLL_NONBLOCK 04000 + +enum EPOLL_EVENTS { __EPOLL_DUMMY }; +#define EPOLLIN 0x001 +#define EPOLLPRI 0x002 +#define EPOLLOUT 0x004 +#define EPOLLRDNORM 0x040 +#define EPOLLRDBAND 0x080 +#define EPOLLWRNORM 0x100 +#define EPOLLWRBAND 0x200 +#define EPOLLMSG 0x400 +#define EPOLLERR 0x008 +#define EPOLLHUP 0x010 +#define EPOLLRDHUP 0x2000 +#define EPOLLONESHOT (1U<<30) +#define EPOLLET (1U<<31) + +#define EPOLL_CTL_ADD 1 +#define EPOLL_CTL_DEL 2 +#define EPOLL_CTL_MOD 3 + +typedef union epoll_data { +	void *ptr; +	int fd; +	uint32_t u32; +	uint64_t u64; +} epoll_data_t; + +struct epoll_event { +	uint32_t events; +	epoll_data_t data; +} __attribute__ ((__packed__)); + + +int epoll_create(int); +int epoll_create1(int); +int epoll_ctl(int, int, int, struct epoll_event *); +int epoll_wait(int, struct epoll_event *, int, int); +int epoll_pwait(int, struct epoll_event *, int, int, const sigset_t *); + + +#ifdef __cplusplus +} +#endif + +#endif /* sys/epoll.h */ diff --git a/include/sys/file.h b/include/sys/file.h new file mode 100644 index 00000000..8b2eb01a --- /dev/null +++ b/include/sys/file.h @@ -0,0 +1,21 @@ +#ifndef _SYS_FILE_H +#define _SYS_FILE_H +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) + +#define LOCK_SH	1 +#define LOCK_EX	2 +#define LOCK_NB	4 +#define LOCK_UN	8 + +extern int flock(int, int); + +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/sys/ioctl.h b/include/sys/ioctl.h new file mode 100644 index 00000000..d0415b3d --- /dev/null +++ b/include/sys/ioctl.h @@ -0,0 +1,14 @@ +#ifndef	_SYS_IOCTL_H +#define	_SYS_IOCTL_H +#ifdef __cplusplus +extern "C" { +#endif + +#include <bits/ioctl.h> + +int ioctl (int, int, ...); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/sys/ipc.h b/include/sys/ipc.h new file mode 100644 index 00000000..9de9f3e7 --- /dev/null +++ b/include/sys/ipc.h @@ -0,0 +1,23 @@ +#ifndef _SYS_IPC_H +#define _SYS_IPC_H +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_uid_t +#define __NEED_gid_t +#define __NEED_mode_t +#define __NEED_key_t + +#include <bits/alltypes.h> + +#include <bits/ipc.h> + +key_t ftok (const char *, int); + +#ifdef __cplusplus +} +#endif +#endif + + diff --git a/include/sys/kd.h b/include/sys/kd.h new file mode 100644 index 00000000..793fd59f --- /dev/null +++ b/include/sys/kd.h @@ -0,0 +1,8 @@ +#ifndef _SYS_KD_H +#define _SYS_KD_H + +#define _LINUX_TYPES_H +#include <linux/kd.h> +#undef _LINUX_TYPES_H + +#endif diff --git a/include/sys/klog.h b/include/sys/klog.h new file mode 100644 index 00000000..aa66684e --- /dev/null +++ b/include/sys/klog.h @@ -0,0 +1,14 @@ +#ifndef	_SYS_KLOG_H +#define	_SYS_KLOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +int klogctl (int, char *, int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/sys/mman.h b/include/sys/mman.h new file mode 100644 index 00000000..6aede8bd --- /dev/null +++ b/include/sys/mman.h @@ -0,0 +1,37 @@ +#ifndef	_SYS_MMAN_H +#define	_SYS_MMAN_H +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_mode_t +#define __NEED_size_t +#define __NEED_off_t + +#include <bits/alltypes.h> + +#include <bits/mman.h> + +void *mmap (void *, size_t, int, int, int, off_t); +int munmap (void *, size_t); + +int mprotect (void *, size_t, int); +int msync (void *, size_t, int); + +int posix_madvise (void *, size_t, int); + +int mlock (const void *, size_t); +int munlock (const void *, size_t); +int mlockall (int); +int munlockall (void); + +/* linux extension */ +void *mremap (void *, size_t, size_t, int, ...); + +int shm_open (const char *, int, mode_t); +int shm_unlink (const char *); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/sys/mount.h b/include/sys/mount.h new file mode 100644 index 00000000..2c685f67 --- /dev/null +++ b/include/sys/mount.h @@ -0,0 +1,28 @@ +#ifndef _SYS_MOUNT_H +#define _SYS_MOUNT_H + +#define MS_RDONLY      1 +#define MS_NOSUID      2 +#define MS_NODEV       4 +#define MS_NOEXEC      8 +#define MS_SYNCHRONOUS 16 +#define MS_REMOUNT     32 +#define MS_MANDLOCK    64 +#define S_WRITE        128 +#define S_APPEND       256 +#define S_IMMUTABLE    512 +#define MS_NOATIME     1024 +#define MS_NODIRATIME  2048 +#define MS_BIND        4096 +#define MS_MOVE        8192 +#define MS_SILENT      32768 + +#define MS_MGC_VAL 0xc0ed0000 + +#define MNT_FORCE 1 + +int mount(const char *, const char *, const char *, unsigned long, const void *); +int umount(const char *); +int umount2(const char *, int); + +#endif diff --git a/include/sys/msg.h b/include/sys/msg.h new file mode 100644 index 00000000..9fc42bcd --- /dev/null +++ b/include/sys/msg.h @@ -0,0 +1,36 @@ +#ifndef _SYS_MSG_H +#define _SYS_MSG_H + +#include <sys/ipc.h> + +#define __NEED_pid_t +#define __NEED_key_t +#define __NEED_time_t +#define __NEED_size_t +#define __NEED_ssize_t + +#include <bits/alltypes.h> + +typedef unsigned long msgqnum_t; +typedef unsigned long msglen_t; + +struct msqid_ds +{ +	struct ipc_perm msg_perm; +	time_t msg_stime; +	time_t msg_rtime; +	time_t msg_ctime; +	msgqnum_t msg_qnum; +	msglen_t msg_qbytes; +	pid_t msg_lspid; +	pid_t msd_lrpid; +}; + +#define MSG_NOERROR 010000 + +int msgctl (int, int, struct msqid_ds *); +int msgget (key_t, int); +int msgrcv (int, void *, size_t, long, int); +int msgsnd (int, const void *, size_t, int); + +#endif diff --git a/include/sys/param.h b/include/sys/param.h new file mode 100644 index 00000000..ded4a16b --- /dev/null +++ b/include/sys/param.h @@ -0,0 +1,15 @@ +#undef MAXSYMLINKS +#define MAXSYMLINKS 20 + +#undef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 + +#undef MAXNAMLEN +#define MAXNAMLEN NAME_MAX + +#undef MAXPATHLEN +#define MAXPATHLEN PATH_MAX + +#include <sys/resource.h> +#include <endian.h> +#include <limits.h> diff --git a/include/sys/poll.h b/include/sys/poll.h new file mode 100644 index 00000000..779ec774 --- /dev/null +++ b/include/sys/poll.h @@ -0,0 +1 @@ +#include <poll.h> diff --git a/include/sys/prctl.h b/include/sys/prctl.h new file mode 100644 index 00000000..cd34848a --- /dev/null +++ b/include/sys/prctl.h @@ -0,0 +1,64 @@ +#ifndef _SYS_PRCTL_H +#define _SYS_PRCTL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define PR_SET_PDEATHSIG  1 +#define PR_GET_PDEATHSIG  2 +#define PR_GET_DUMPABLE   3 +#define PR_SET_DUMPABLE   4 +#define PR_GET_UNALIGN   5 +#define PR_SET_UNALIGN   6 +#define PR_UNALIGN_NOPRINT 1 +#define PR_UNALIGN_SIGBUS 2 +#define PR_GET_KEEPCAPS   7 +#define PR_SET_KEEPCAPS   8 +#define PR_GET_FPEMU  9 +#define PR_SET_FPEMU 10 +#define PR_FPEMU_NOPRINT 1 +#define PR_FPEMU_SIGFPE 2 +#define PR_GET_FPEXC 11 +#define PR_SET_FPEXC 12 +#define PR_FP_EXC_SW_ENABLE 0x80 +#define PR_FP_EXC_DIV  0x010000 +#define PR_FP_EXC_OVF  0x020000 +#define PR_FP_EXC_UND  0x040000 +#define PR_FP_EXC_RES  0x080000 +#define PR_FP_EXC_INV  0x100000 +#define PR_FP_EXC_DISABLED 0 +#define PR_FP_EXC_NONRECOV 1 +#define PR_FP_EXC_ASYNC 2 +#define PR_FP_EXC_PRECISE 3 +#define PR_GET_TIMING   13 +#define PR_SET_TIMING   14 +#define PR_TIMING_STATISTICAL  0 +#define PR_TIMING_TIMESTAMP    1 +#define PR_SET_NAME    15 +#define PR_GET_NAME    16 +#define PR_GET_ENDIAN 19 +#define PR_SET_ENDIAN 20 +#define PR_ENDIAN_BIG +#define PR_ENDIAN_LITTLE +#define PR_ENDIAN_PPC_LITTLE +#define PR_GET_SECCOMP 21 +#define PR_SET_SECCOMP 22 +#define PR_CAPBSET_READ 23 +#define PR_CAPBSET_DROP 24 +#define PR_GET_TSC 25 +#define PR_SET_TSC 26 +#define PR_TSC_ENABLE 1 +#define PR_TSC_SIGSEGV 2 +#define PR_GET_SECUREBITS 27 +#define PR_SET_SECUREBITS 28 +#define PR_SET_TIMERSLACK 29 +#define PR_GET_TIMERSLACK 30 + +int prctl (int, ...); + +#ifdef __cplusplus +extern "C" { +#endif + +#endif diff --git a/include/sys/procfs.h b/include/sys/procfs.h new file mode 100644 index 00000000..20b4847c --- /dev/null +++ b/include/sys/procfs.h @@ -0,0 +1,81 @@ +#ifndef _SYS_PROCFS_H +#define _SYS_PROCFS_H +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/time.h> +#include <sys/types.h> +#include <sys/user.h> + +typedef unsigned long elf_greg_t; +#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +#if __WORDSIZE == 32 +typedef struct user_fpregs_struct elf_fpregset_t; +typedef struct user_fpxregs_struct elf_fpxregset_t; +#else +typedef struct user_fpregs_struct elf_fpregset_t; +#endif + +struct elf_siginfo { +	int si_signo; +	int si_code; +	int si_errno; +}; + +struct elf_prstatus { +	struct elf_siginfo pr_info; +	short int pr_cursig; +	unsigned long int pr_sigpend; +	unsigned long int pr_sighold; +	pid_t pr_pid; +	pid_t pr_ppid; +	pid_t pr_pgrp; +	pid_t pr_sid; +	struct timeval pr_utime; +	struct timeval pr_stime; +	struct timeval pr_cutime; +	struct timeval pr_cstime; +	elf_gregset_t pr_reg; +	int pr_fpvalid; +}; + + +#define ELF_PRARGSZ 80 + +struct elf_prpsinfo +	{ +	char pr_state; +	char pr_sname; +	char pr_zomb; +	char pr_nice; +	unsigned long int pr_flag; +#if __WORDSIZE == 32 +	unsigned short int pr_uid; +	unsigned short int pr_gid; +#else +	unsigned int pr_uid; +	unsigned int pr_gid; +#endif +	int pr_pid, pr_ppid, pr_pgrp, pr_sid; +	char pr_fname[16]; +	char pr_psargs[ELF_PRARGSZ]; +}; + + +typedef void *psaddr_t; +typedef elf_gregset_t prgregset_t; +typedef elf_fpregset_t prfpregset_t; +typedef pid_t lwpid_t; +typedef struct elf_prstatus prstatus_t; +typedef struct elf_prpsinfo prpsinfo_t; + + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/sys/ptrace.h b/include/sys/ptrace.h new file mode 100644 index 00000000..0459d1b6 --- /dev/null +++ b/include/sys/ptrace.h @@ -0,0 +1,77 @@ +#ifndef _SYS_PTRACE_H +#define _SYS_PTRACE_H +#ifdef __cplusplus +extern "C" { +#endif + +#define PTRACE_TRACEME 0 +#define PT_TRACE_ME PTRACE_TRACEME + +#define PTRACE_PEEKTEXT 1 +#define PTRACE_PEEKDATA 2 +#define PTRACE_PEEKUSER 3 +#define PTRACE_POKETEXT 4 +#define PTRACE_POKEDATA 5 +#define PTRACE_POKEUSER 6 +#define PTRACE_CONT 7 +#define PTRACE_KILL 8 +#define PTRACE_SINGLESTEP 9 +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 +#define PTRACE_ATTACH 16 +#define PTRACE_DETACH 17 +#define PTRACE_GETFPXREGS 18 +#define PTRACE_SETFPXREGS 19 +#define PTRACE_SYSCALL 24 +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 +#define PTRACE_GETSIGINFO 0x4202 +#define PTRACE_SETSIGINFO 0x4203 + +#define PT_READ_I PTRACE_PEEKTEXT +#define PT_READ_D PTRACE_PEEKDATA +#define PT_READ_U PTRACE_PEEKUSER +#define PT_WRITE_I PTRACE_POKETEXT +#define PT_WRITE_D PTRACE_POKEDATA +#define PT_WRITE_U PTRACE_POKEUSER +#define PT_CONTINUE PTRACE_CONT +#define PT_KILL PTRACE_KILL +#define PT_STEP PTRACE_SINGLESTEP +#define PT_GETREGS PTRACE_GETREGS +#define PT_SETREGS PTRACE_SETREGS +#define PT_GETFPREGS PTRACE_GETFPREGS +#define PT_SETFPREGS PTRACE_SETFPREGS +#define PT_ATTACH PTRACE_ATTACH +#define PT_DETACH PTRACE_DETACH +#define PT_GETFPXREGS PTRACE_GETFPXREGS +#define PT_SETFPXREGS PTRACE_SETFPXREGS +#define PT_SYSCALL PTRACE_SYSCALL +#define PT_SETOPTIONS PTRACE_SETOPTIONS +#define PT_GETEVENTMSG PTRACE_GETEVENTMSG +#define PT_GETSIGINFO PTRACE_GETSIGINFO +#define PT_SETSIGINFO PTRACE_SETSIGINFO + +#define PTRACE_O_TRACESYSGOOD   0x00000001 +#define PTRACE_O_TRACEFORK      0x00000002 +#define PTRACE_O_TRACEVFORK     0x00000004 +#define PTRACE_O_TRACECLONE     0x00000008 +#define PTRACE_O_TRACEEXEC      0x00000010 +#define PTRACE_O_TRACEVFORKDONE 0x00000020 +#define PTRACE_O_TRACEEXIT      0x00000040 +#define PTRACE_O_MASK           0x0000007f + +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 +#define PTRACE_EVENT_VFORK_DONE 5 +#define PTRACE_EVENT_EXIT 6 + +long int ptrace(int, ...); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/sys/reboot.h b/include/sys/reboot.h new file mode 100644 index 00000000..26cc3088 --- /dev/null +++ b/include/sys/reboot.h @@ -0,0 +1,18 @@ +#ifndef _SYS_REBOOT_H +#define _SYS_REBOOT_H +#ifdef __cplusplus +extern "C" { +#endif + +#define RB_AUTOBOOT     0x01234567 +#define RB_HALT_SYSTEM  0xcdef0123 +#define RB_ENABLE_CAD   0x89abcdef +#define RB_DISABLE_CAD  0 +#define RB_POWER_OFF    0x4321fedc + +int reboot(int); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/sys/reg.h b/include/sys/reg.h new file mode 100644 index 00000000..ebf3fff4 --- /dev/null +++ b/include/sys/reg.h @@ -0,0 +1,9 @@ +#ifndef _SYS_USER_H +#define _SYS_USER_H + +#include <limits.h> +#include <unistd.h> + +#include <bits/reg.h> + +#endif diff --git a/include/sys/resource.h b/include/sys/resource.h new file mode 100644 index 00000000..99e383c4 --- /dev/null +++ b/include/sys/resource.h @@ -0,0 +1,74 @@ +#ifndef	_SYS_RESOURCE_H +#define	_SYS_RESOURCE_H + +#define __NEED_id_t +#define __NEED_time_t +#define __NEED_struct_timeval +#define __NEED_struct_rusage + +#include <bits/alltypes.h> + +typedef unsigned long long rlim_t; + +struct rlimit +{ +	rlim_t rlim_cur; +	rlim_t rlim_max; +}; + +struct rusage +{ +	struct timeval ru_utime; +	struct timeval ru_stime; +	/* linux extentions, but useful */ +	long	ru_maxrss; +	long	ru_ixrss; +	long	ru_idrss; +	long	ru_isrss; +	long	ru_minflt; +	long	ru_majflt; +	long	ru_nswap; +	long	ru_inblock; +	long	ru_oublock; +	long	ru_msgsnd; +	long	ru_msgrcv; +	long	ru_nsignals; +	long	ru_nvcsw; +	long	ru_nivcsw; +	/* room for more... */ +	long    __reserved[16]; +}; + +int getrlimit (int, struct rlimit *); +int setrlimit (int, const struct rlimit *); +int getrusage (int, struct rusage *); + +int getpriority (int, id_t); +int setpriority (int, id_t, int); + +#define PRIO_PROCESS 0 +#define PRIO_PGRP    1 +#define PRIO_USER    2 + +#define RUSAGE_SELF     0 +#define RUSAGE_CHILDREN 1 + +#define RLIM_INFINITY (~0ULL) +#define RLIM_SAVED_CUR RLIM_INFINITY +#define RLIM_SAVED_MAX RLIM_INFINITY + +#define RLIMIT_CPU     0 +#define RLIMIT_FSIZE   1 +#define RLIMIT_DATA    2 +#define RLIMIT_STACK   3 +#define RLIMIT_CORE    4 +#define RLIMIT_RSS     5 +#define RLIMIT_NOFILE  7 +#define RLIMIT_AS      9 +#define RLIMIT_NPROC   6 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_LOCKS   10 + + + +#endif diff --git a/include/sys/select.h b/include/sys/select.h new file mode 100644 index 00000000..c44eada4 --- /dev/null +++ b/include/sys/select.h @@ -0,0 +1,34 @@ +#ifndef _SYS_SELECT_H +#define _SYS_SELECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t +#define __NEED_time_t +#define __NEED_struct_timeval +#define __NEED_struct_timespec +#define __NEED_sigset_t + +#include <bits/alltypes.h> + +#define FD_SETSIZE 1024 + +typedef struct +{ +	unsigned long fds_bits[FD_SETSIZE / 8 / sizeof(long)]; +} fd_set; + +#define FD_ZERO(s) do { int __i; unsigned long *__b=(s)->fds_bits; for(__i=sizeof (fd_set)/sizeof (long); __i; __i--) *__b++=0; } while(0) +#define FD_SET(d, s)   ((s)->fds_bits[(d)/(8*sizeof(long))] |= (1<<((d)%(8*sizeof(long))))) +#define FD_CLR(d, s)   ((s)->fds_bits[(d)/(8*sizeof(long))] &= ~(1<<((d)%(8*sizeof(long))))) +#define FD_ISSET(d, s) ((s)->fds_bits[(d)/(8*sizeof(long))] & (1<<((d)%(8*sizeof(long))))) + +int select (int, fd_set *, fd_set *, fd_set *, struct timeval *); +int pselect (int, fd_set *, fd_set *, fd_set *, const struct timespec *, const sigset_t *); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/sys/sem.h b/include/sys/sem.h new file mode 100644 index 00000000..15d8b685 --- /dev/null +++ b/include/sys/sem.h @@ -0,0 +1,69 @@ +#ifndef _SYS_SEM_H +#define _SYS_SEM_H +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t +#include <bits/alltypes.h> + +#include <sys/ipc.h> + +#define SEM_UNDO	0x1000 +#define GETPID		11 +#define GETVAL		12 +#define GETALL		13 +#define GETNCNT		14 +#define GETZCNT		15 +#define SETVAL		16 +#define SETALL		17 + +struct semid_ds { +	struct ipc_perm sem_perm; +	long sem_otime; +	unsigned long __unused1; +	long sem_ctime; +	unsigned long __unused2; +	unsigned long sem_nsems; +	unsigned long __unused3; +	unsigned long __unused4; +}; + +#define _SEM_SEMUN_UNDEFINED 1 + +#define SEM_STAT 18 +#define SEM_INFO 19 + +struct  seminfo { +	int semmap; +	int semmni; +	int semmns; +	int semmnu; +	int semmsl; +	int semopm; +	int semume; +	int semusz; +	int semvmx; +	int semaem; +}; + +struct sembuf { +	unsigned short sem_num; +	short sem_op; +	short sem_flg; +}; + +int semctl(int, int, int, ...); +int semget(key_t, int, int); +int semop(int, struct sembuf *, size_t); + +#ifdef _GNU_SOURCE +#define __NEED_struct_timespec +#include <bits/alltypes.h> +int semtimedop(int, struct sembuf *, size_t, const struct timespec *); +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/sys/shm.h b/include/sys/shm.h new file mode 100644 index 00000000..6ebb9412 --- /dev/null +++ b/include/sys/shm.h @@ -0,0 +1,18 @@ +#ifndef _SYS_SHM_H +#define _SYS_SHM_H + +#define __NEED_time_t +#define __NEED_size_t +#define __NEED_pid_t + +#include <bits/alltypes.h> + +#include <sys/ipc.h> +#include <bits/shm.h> + +void *shmat(int, const void *, int); +int shmctl(int, int, struct shmid_ds *); +int shmdt(const void *); +int shmget(key_t, size_t, int); + +#endif diff --git a/include/sys/signalfd.h b/include/sys/signalfd.h new file mode 100644 index 00000000..895664bf --- /dev/null +++ b/include/sys/signalfd.h @@ -0,0 +1,40 @@ +#ifndef _SYS_SIGNALFD_H +#define _SYS_SIGNALFD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +#define __NEED_sigset_t + +#include <bits/alltypes.h> + +int signalfd(int, const sigset_t *, int); + +struct signalfd_siginfo { +	uint32_t  ssi_signo; +	int32_t   ssi_errno; +	int32_t   ssi_code; +	uint32_t  ssi_pid; +	uint32_t  ssi_uid; +	int32_t   ssi_fd; +	uint32_t  ssi_tid; +	uint32_t  ssi_band; +	uint32_t  ssi_overrun; +	uint32_t  ssi_trapno; +	int32_t   ssi_status; +	int32_t   ssi_int; +	uintptr_t ssi_ptr; +	uint64_t  ssi_utime; +	uint64_t  ssi_stime; +	uint64_t  ssi_addr; +	uint8_t   pad[128-12*4-sizeof(void *)-3*8]; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/sys/socket.h b/include/sys/socket.h new file mode 100644 index 00000000..78c93056 --- /dev/null +++ b/include/sys/socket.h @@ -0,0 +1,64 @@ +#ifndef	_SYS_SOCKET_H +#define	_SYS_SOCKET_H +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_socklen_t +#define __NEED_sa_family_t +#define __NEED_size_t +#define __NEED_ssize_t +#define __NEED_uid_t +#define __NEED_pid_t +#define __NEED_gid_t + +#include <bits/alltypes.h> + +#include <bits/socket.h> + +struct sockaddr +{ +	sa_family_t sa_family; +	char sa_data[14]; +}; + +struct sockaddr_storage +{ +	sa_family_t ss_family; +	long long __ss_align; +	char __ss_padding[128 - sizeof(sa_family_t) - sizeof(long long)]; +}; + +int socket (int, int, int); +int socketpair (int, int, int, int [2]); + +int shutdown (int, int); + +int bind (int, const struct sockaddr *, socklen_t); +int connect (int, const struct sockaddr *, socklen_t); +int listen (int, int); +int accept (int, struct sockaddr *, socklen_t *); + +int getsockname (int, struct sockaddr *, socklen_t *); +int getpeername (int, struct sockaddr *, socklen_t *); + +ssize_t send (int, const void *, size_t, int); +ssize_t recv (int, void *, size_t, int); +ssize_t sendto (int, const void *, size_t, int, const struct sockaddr *, socklen_t); +ssize_t recvfrom (int, void *, size_t, int, struct sockaddr *, socklen_t *); +ssize_t sendmsg (int, const struct msghdr *, int); +ssize_t recvmsg (int, struct msghdr *, int); + +int getsockopt (int, int, int, void *, socklen_t *); +int setsockopt (int, int, int, const void *, socklen_t); + +int sockatmark (int); + +#define SHUT_RD 0 +#define SHUT_WR 1 +#define SHUT_RDWR 2 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/sys/soundcard.h b/include/sys/soundcard.h new file mode 100644 index 00000000..fade986f --- /dev/null +++ b/include/sys/soundcard.h @@ -0,0 +1 @@ +#include <linux/soundcard.h> diff --git a/include/sys/stat.h b/include/sys/stat.h new file mode 100644 index 00000000..36575b0e --- /dev/null +++ b/include/sys/stat.h @@ -0,0 +1,90 @@ +#ifndef	_SYS_STAT_H +#define	_SYS_STAT_H +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_dev_t +#define __NEED_ino_t +#define __NEED_mode_t +#define __NEED_nlink_t +#define __NEED_uid_t +#define __NEED_gid_t +#define __NEED_off_t +#define __NEED_time_t +#define __NEED_blksize_t +#define __NEED_blkcnt_t + +#include <bits/alltypes.h> + +#include <bits/stat.h> + +#define S_IFMT  0170000 + +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFBLK 0060000 +#define S_IFREG 0100000 +#define S_IFIFO 0010000 +#define S_IFLNK 0120000 +#define S_IFSOCK 0140000 + +#define S_TYPEISMQ(buf)  0 +#define S_TYPEISSEM(buf) 0 +#define S_TYPEISSHM(buf) 0 +#define S_TYPEISTMO(buf) 0 + +#define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR) +#define S_ISCHR(mode)  (((mode) & S_IFMT) == S_IFCHR) +#define S_ISBLK(mode)  (((mode) & S_IFMT) == S_IFBLK) +#define S_ISREG(mode)  (((mode) & S_IFMT) == S_IFREG) +#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) +#define S_ISLNK(mode)  (((mode) & S_IFMT) == S_IFLNK) +#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) + +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +#define S_IREAD  0400 +#define S_IWRITE 0200 +#define S_IEXEC  0100 + +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXU 0700 + +#define S_IRGRP 0040 +#define S_IWGRP 0020 +#define S_IXGRP 0010 +#define S_IRWXG 0070 + +#define S_IROTH 0004 +#define S_IWOTH 0002 +#define S_IXOTH 0001 +#define S_IRWXO 0007 + + +int stat(const char *, struct stat *); +int fstat(int, struct stat *); +int lstat(const char *, struct stat *); +int fstatat(int, const char *, struct stat *, int); +int chmod(const char *, mode_t); +int fchmod(int, mode_t); +int fchmodat(int, const char *, mode_t, int); +mode_t umask(mode_t); +int mkdir(const char *, mode_t); +int mknod(const char *, mode_t, dev_t); +int mkfifo(const char *, mode_t); +int mkdirat(int, const char *, mode_t); +int mknodat(int, const char *, mode_t, dev_t); +int mkfifoat(int, const char *, mode_t); + + +#ifdef __cplusplus +} +#endif +#endif + + diff --git a/include/sys/statfs.h b/include/sys/statfs.h new file mode 100644 index 00000000..7eaa7e7c --- /dev/null +++ b/include/sys/statfs.h @@ -0,0 +1,10 @@ +#ifndef	_SYS_STATFS_H +#define	_SYS_STATFS_H + +#include <sys/statvfs.h> + +#define statfs statvfs +#define fstatfs fstatvfs +#define f_namelen f_namemax + +#endif diff --git a/include/sys/statvfs.h b/include/sys/statvfs.h new file mode 100644 index 00000000..6479be6f --- /dev/null +++ b/include/sys/statvfs.h @@ -0,0 +1,30 @@ +#ifndef	_SYS_STATVFS_H +#define	_SYS_STATVFS_H + + +#define __NEED_fsblkcnt_t +#define __NEED_fsfilcnt_t +#include <bits/alltypes.h> + +#include <bits/statfs.h> + +int statvfs (const char *, struct statvfs *); +int fstatvfs (int, struct statvfs *); + +#define ST_RDONLY 1 +#define ST_NOSUID 2 + +#if 0 +#define ST_NODEV  4 +#define ST_NOEXEC 8 +#define ST_SYNCHRONOUS 16 +#define ST_MANDLOCK    64 +#define ST_WRITE       128 +#define ST_APPEND      256 +#define ST_IMMUTABLE   512 +#define ST_NOATIME     1024 +#define ST_NODIRATIME  2048 +#endif + + +#endif diff --git a/include/sys/stropts.h b/include/sys/stropts.h new file mode 100644 index 00000000..5b5bc02f --- /dev/null +++ b/include/sys/stropts.h @@ -0,0 +1 @@ +#include <stropts.h> diff --git a/include/sys/swap.h b/include/sys/swap.h new file mode 100644 index 00000000..c5824f1d --- /dev/null +++ b/include/sys/swap.h @@ -0,0 +1,11 @@ +#ifndef _SYS_SWAP_H +#define _SYS_SWAP_H + +#define	SWAP_FLAG_PREFER        0x8000 +#define	SWAP_FLAG_PRIO_MASK     0x7fff +#define	SWAP_FLAG_PRIO_SHIFT    0 + +int swapon (const char *, int); +int swapoff (const char *); + +#endif diff --git a/include/sys/sysctl.h b/include/sys/sysctl.h new file mode 100644 index 00000000..af5ca8ba --- /dev/null +++ b/include/sys/sysctl.h @@ -0,0 +1,9 @@ +#ifndef	_SYS_SYSCTL_H +#define	_SYS_SYSCTL_H + +#define __NEED_size_t +#include <bits/alltypes.h> + +int sysctl (int *, int, void *, size_t *, void *, size_t); + +#endif diff --git a/include/sys/sysinfo.h b/include/sys/sysinfo.h new file mode 100644 index 00000000..ca52088a --- /dev/null +++ b/include/sys/sysinfo.h @@ -0,0 +1,29 @@ +#ifndef _SYS_SYSINFO_H +#define _SYS_SYSINFO_H + +/* ?? */ +#define SI_LOAD_SHIFT 16 + +struct sysinfo { +	unsigned long long uptime; +	unsigned long loads[3]; +	unsigned long procs; +	unsigned long long totalram; +	unsigned long long freeram; +	unsigned long long sharedram; +	unsigned long long bufferram; +	unsigned long long totalswap; +	unsigned long long freeswap; +	unsigned long long totalhigh; +	unsigned long long freehigh; +	unsigned long mem_unit; +	char __reserved[256]; +}; + +int sysinfo (struct sysinfo *); +int get_nprocs_conf (void); +int get_nprocs (void); +long long get_phys_pages (void); +long long get_avphys_pages (void); + +#endif diff --git a/include/sys/sysmacros.h b/include/sys/sysmacros.h new file mode 100644 index 00000000..79eba3be --- /dev/null +++ b/include/sys/sysmacros.h @@ -0,0 +1,6 @@ +#ifndef _SYSMACROS_H +#define _SYSMACROS_H + +#include <bits/sysmacros.h> + +#endif diff --git a/include/sys/time.h b/include/sys/time.h new file mode 100644 index 00000000..9b3bfb99 --- /dev/null +++ b/include/sys/time.h @@ -0,0 +1,49 @@ +#ifndef _SYS_TIME_H +#define _SYS_TIME_H +#ifdef __cplusplus +extern "C" { +#endif + +/* All symbols from select.h except pselect are required anyway... */ +#include <sys/select.h> + +#define __NEED_time_t +#define __NEED_suseconds_t +#define __NEED_timeval + +#include <bits/alltypes.h> + + + +int gettimeofday (struct timeval *, void *); + +/* extensions */ +int settimeofday (const struct timeval *, void *); +int adjtime (const struct timeval *, struct timeval *); + + +#define ITIMER_REAL    0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF    2 + +struct itimerval +{ +	struct timeval it_interval; +	struct timeval it_value; +}; + +int getitimer (int, struct itimerval *); +int setitimer (int, const struct itimerval *, struct itimerval *); +int utimes (const char *, const struct timeval [2]); + +#ifdef _GNU_SOURCE +struct timezone { +	int tz_minuteswest; +	int tz_dsttime; +}; +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/sys/times.h b/include/sys/times.h new file mode 100644 index 00000000..aca743d3 --- /dev/null +++ b/include/sys/times.h @@ -0,0 +1,17 @@ +#ifndef	_SYS_TIMES_H +#define	_SYS_TIMES_H + +#define __NEED_clock_t +#include <bits/alltypes.h> + +struct tms +{ +	clock_t tms_utime; +	clock_t tms_stime; +	clock_t tms_cutime; +	clock_t tms_cstime; +}; + +clock_t times (struct tms *); + +#endif diff --git a/include/sys/types.h b/include/sys/types.h new file mode 100644 index 00000000..8be19e6b --- /dev/null +++ b/include/sys/types.h @@ -0,0 +1,56 @@ +#ifndef	_SYS_TYPES_H +#define	_SYS_TYPES_H +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_loff_t +#define __NEED_ino_t +#define __NEED_dev_t +#define __NEED_uid_t +#define __NEED_gid_t +#define __NEED_mode_t +#define __NEED_nlink_t +#define __NEED_off_t +#define __NEED_pid_t +#define __NEED_size_t +#define __NEED_ssize_t +#define __NEED_time_t +#define __NEED_timer_t +#define __NEED_clockid_t + +#define __NEED_int8_t +#define __NEED_int16_t +#define __NEED_int32_t +#define __NEED_int64_t + +#define __NEED_u_int8_t +#define __NEED_u_int16_t +#define __NEED_u_int32_t +#define __NEED_u_int64_t + +#define __NEED_register_t + +#define __NEED_blkcnt_t +#define __NEED_fsblkcnt_t +#define __NEED_fsfilcnt_t + +#define __NEED_id_t +#define __NEED_key_t +#define __NEED_clock_t +#define __NEED_useconds_t +#define __NEED_suseconds_t +#define __NEED_blksize_t + +#include <bits/alltypes.h> + +#ifdef _GNU_SOURCE +typedef unsigned long caddr_t; +#endif + +#ifdef __cplusplus +} +#endif +#endif + + diff --git a/include/sys/ucontext.h b/include/sys/ucontext.h new file mode 100644 index 00000000..5fdbd63d --- /dev/null +++ b/include/sys/ucontext.h @@ -0,0 +1 @@ +#include <ucontext.h> diff --git a/include/sys/uio.h b/include/sys/uio.h new file mode 100644 index 00000000..7b068c0c --- /dev/null +++ b/include/sys/uio.h @@ -0,0 +1,14 @@ +#ifndef _SYS_UIO_H +#define _SYS_UIO_H + +#define __NEED_size_t +#define __NEED_ssize_t + +#include <bits/alltypes.h> + +#include <bits/uio.h> + +ssize_t readv (int, const struct iovec *, int); +ssize_t writev (int, const struct iovec *, int); + +#endif diff --git a/include/sys/un.h b/include/sys/un.h new file mode 100644 index 00000000..769dac6b --- /dev/null +++ b/include/sys/un.h @@ -0,0 +1,13 @@ +#ifndef	_SYS_UN_H +#define	_SYS_UN_H + +#define __NEED_sa_family_t +#include <bits/alltypes.h> + +struct sockaddr_un +{ +	sa_family_t sun_family; +	char sun_path[108]; +}; + +#endif diff --git a/include/sys/user.h b/include/sys/user.h new file mode 100644 index 00000000..24ac9400 --- /dev/null +++ b/include/sys/user.h @@ -0,0 +1,15 @@ +#ifndef _SYS_USER_H +#define _SYS_USER_H +#ifdef __cplusplus +extern "C" { +#endif + +#include <limits.h> +#include <unistd.h> + +#include <bits/user.h> + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/sys/utsname.h b/include/sys/utsname.h new file mode 100644 index 00000000..383e8251 --- /dev/null +++ b/include/sys/utsname.h @@ -0,0 +1,21 @@ +#ifndef	_SYS_UTSNAME_H +#define	_SYS_UTSNAME_H + +struct utsname +{ +	char sysname[65]; +	char nodename[65]; +	char release[65]; +	char version[65]; +	char machine[65]; +#ifdef _GNU_SOURCE +	char domainname[65]; +#else +	char __domainname[65]; +#endif +}; + +int uname (struct utsname *); + + +#endif diff --git a/include/sys/vfs.h b/include/sys/vfs.h new file mode 100644 index 00000000..a899db27 --- /dev/null +++ b/include/sys/vfs.h @@ -0,0 +1 @@ +#include <sys/statfs.h> diff --git a/include/sys/vt.h b/include/sys/vt.h new file mode 100644 index 00000000..834abfbc --- /dev/null +++ b/include/sys/vt.h @@ -0,0 +1 @@ +#include <linux/vt.h> diff --git a/include/sys/wait.h b/include/sys/wait.h new file mode 100644 index 00000000..a1851530 --- /dev/null +++ b/include/sys/wait.h @@ -0,0 +1,28 @@ +#ifndef	_SYS_WAIT_H +#define	_SYS_WAIT_H +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_pid_t +#define __NEED_id_t +#define __NEED_time_t +#define __NEED_struct_timeval +#define __NEED_siginfo_t +#include <bits/alltypes.h> + +typedef int idtype_t; + +pid_t wait (int *); +int waitid (idtype_t, id_t, siginfo_t *, int); +pid_t waitpid (pid_t, int *, int ); +//pid_t wait3 (int *, int, struct rusage *); +//pid_t wait4 (pid_t, int *, int, struct rusage *); + +#include <bits/wait.h> +#include <bits/wexitstatus.h> + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/syslog.h b/include/syslog.h new file mode 100644 index 00000000..119c9bcb --- /dev/null +++ b/include/syslog.h @@ -0,0 +1,54 @@ +#ifndef _SYS_SYSLOG_H +#define _SYS_SYSLOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define LOG_EMERG   0 +#define LOG_ALERT   1 +#define LOG_CRIT    2 +#define LOG_ERR     3 +#define LOG_WARNING 4 +#define LOG_NOTICE  5 +#define LOG_INFO    6 +#define LOG_DEBUG   7 + +#define LOG_MASK(p) (1<<(p)) + +#define LOG_KERN     (0<<3) +#define LOG_USER     (1<<3) +#define LOG_MAIL     (2<<3) +#define LOG_DAEMON   (3<<3) +#define LOG_AUTH     (4<<3) +#define LOG_SYSLOG   (5<<3) +#define LOG_LPR      (6<<3) +#define LOG_NEWS     (7<<3) +#define LOG_UUCP     (8<<3) +#define LOG_CRON     (9<<3) + +#define LOG_LOCAL0   (16<<3) +#define LOG_LOCAL1   (17<<3) +#define LOG_LOCAL2   (18<<3) +#define LOG_LOCAL3   (19<<3) +#define LOG_LOCAL4   (20<<3) +#define LOG_LOCAL5   (21<<3) +#define LOG_LOCAL6   (22<<3) +#define LOG_LOCAL7   (23<<3) + +#define LOG_PID    0x01 +#define LOG_CONS   0x02 +#define LOG_ODELAY 0x04 +#define LOG_NDELAY 0x08 +#define LOG_NOWAIT 0x10 + +void closelog (void); +void openlog (const char *, int, int); +int setlogmask (int); +void syslog (int, const char *, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/tar.h b/include/tar.h new file mode 100644 index 00000000..be589842 --- /dev/null +++ b/include/tar.h @@ -0,0 +1,33 @@ +#ifndef	_TAR_H +#define	_TAR_H + +#define TSUID   04000 +#define TSGID   02000 +#define TSVTX   01000 +#define TUREAD  00400 +#define TUWRITE 00200 +#define TUEXEC  00100 +#define TGREAD  00040 +#define TGWRITE 00020 +#define TGEXEC  00010 +#define TOREAD  00004 +#define TOWRITE 00002 +#define TOEXEC  00001 + +#define REGTYPE  '0' +#define AREGTYPE '\0' +#define LNKTYPE  '1' +#define SYMTYPE  '2' +#define CHRTYPE  '3' +#define BLKTYPE  '4' +#define DIRTYPE  '5' +#define FIFOTYPE '6' +#define CONTTYPE '7' + +#define TMAGIC "ustar" +#define TMAGLEN 6 + +#define TVERSION "00" +#define TVERSLEN 2 + +#endif diff --git a/include/termios.h b/include/termios.h new file mode 100644 index 00000000..4c465627 --- /dev/null +++ b/include/termios.h @@ -0,0 +1,39 @@ +#ifndef	_TERMIOS_H +#define	_TERMIOS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_pid_t + +#include <bits/alltypes.h> + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 32 + +#include <bits/termios.h> + +speed_t cfgetospeed (const struct termios *); +speed_t cfgetispeed (const struct termios *); +int cfsetospeed (struct termios *, speed_t); +int cfsetispeed (struct termios *, speed_t); + +int tcgetattr (int, struct termios *); +int tcsetattr (int, int, const struct termios *); + +int tcsendbreak (int, int); +int tcdrain (int); +int tcflush (int, int); +int tcflow (int, int); + +pid_t tcgetsid (int); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/time.h b/include/time.h new file mode 100644 index 00000000..e6cfb73d --- /dev/null +++ b/include/time.h @@ -0,0 +1,113 @@ +#ifndef	_TIME_H +#define _TIME_H + +#ifdef __cplusplus +extern "C" { +#endif + +#undef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void*)0) +#endif + + +#define __NEED_time_t +#define __NEED_struct_timespec +#define __NEED_clock_t +#define __NEED_clockid_t +#define __NEED_timer_t +#define __NEED_size_t +#define __NEED_pid_t + +#include <bits/alltypes.h> + + +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; +	long __tm_gmtoff; +	const char *__tm_zone; +}; + +struct itimerspec +{ +	struct timespec it_interval; +	struct timespec it_value; +}; + +#define CLOCKS_PER_SEC 1000000UL + +#define CLOCK_REALTIME           0 +#define CLOCK_MONOTONIC          1 +#define CLOCK_PROCESS_CPUTIME_ID 2 +#define CLOCK_THREAD_CPUTIME_ID  3 + +#define TIMER_ABSTIME 1 + + + +clock_t clock (void); +time_t time (time_t *); +double difftime (time_t, time_t); +time_t mktime (struct tm *); +size_t strftime (char *, size_t, const char *, const struct tm *); +char *strptime (const char *, const char *, struct tm *); + +struct tm *gmtime (const time_t *); +struct tm *gmtime_r (const time_t *, struct tm *); +struct tm *localtime (const time_t *); +struct tm *localtime_r (const time_t *, struct tm *); + +char *asctime (const struct tm *); +char *asctime_r (const struct tm *, char *); +char *ctime (const time_t *); +char *ctime_r (const time_t *, char *); + + +extern int daylight; +extern long timezone; +extern char *tzname[2]; + +void tzset (void); + + + +int nanosleep (const struct timespec *, struct timespec *); + + +int clock_getres (clockid_t, struct timespec *); +int clock_gettime (clockid_t, struct timespec *); +int clock_settime (clockid_t, const struct timespec *); + +int clock_nanosleep (clockid_t, int, const struct timespec *, struct timespec *); +int clock_getcpuclockid (pid_t, clockid_t *); + +/* FIXME */ +struct sigevent; +int timer_create (clockid_t, struct sigevent *, timer_t *); +int timer_delete (timer_t); + +int timer_settime (timer_t, int, const struct itimerspec *, struct itimerspec *); +int timer_gettime (timer_t, struct itimerspec *); +int timer_getoverrun (timer_t); + + +extern int getdate_err; +extern struct tm *getdate (const char *); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/include/ucontext.h b/include/ucontext.h new file mode 100644 index 00000000..db335677 --- /dev/null +++ b/include/ucontext.h @@ -0,0 +1,38 @@ +#ifndef _UCONTEXT_H +#define _UCONTEXT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include <signal.h> + +struct __fpstate { +	unsigned long __x[7]; +	unsigned char __y[80]; +	unsigned long __z; +}; + +typedef struct { +	unsigned long __gregs[19]; +	void *__fpregs; +	unsigned long __oldmask, __cr2; +} mcontext_t; + +typedef struct __ucontext { +	unsigned long uc_flags; +	struct __ucontext *uc_link; +	stack_t uc_stack; +	mcontext_t uc_mcontext; +	sigset_t uc_sigmask; +	struct __fpstate __fpregs_mem; +} ucontext_t; + +int  getcontext(ucontext_t *); +void makecontext(ucontext_t *, void (*)(void), int, ...); +int  setcontext(const ucontext_t *); +int  swapcontext(ucontext_t *, const ucontext_t *); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/ulimit.h b/include/ulimit.h new file mode 100644 index 00000000..efdcd311 --- /dev/null +++ b/include/ulimit.h @@ -0,0 +1,17 @@ +#ifndef _ULIMIT_H +#define _ULIMIT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define UL_GETFSIZE 1 +#define UL_SETFSIZE 2 + +long ulimit (int, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/unistd.h b/include/unistd.h new file mode 100644 index 00000000..5ad0704b --- /dev/null +++ b/include/unistd.h @@ -0,0 +1,464 @@ +#ifndef	_UNISTD_H +#define	_UNISTD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define STDIN_FILENO  0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#undef SEEK_SET +#undef SEEK_CUR +#undef SEEK_END +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#undef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void*)0) +#endif + +#define __NEED_size_t +#define __NEED_ssize_t +#define __NEED_uid_t +#define __NEED_gid_t +#define __NEED_off_t +#define __NEED_pid_t +#define __NEED_useconds_t +#define __NEED_intptr_t + +#include <bits/alltypes.h> + +int pipe(int [2]); +int close(int); +int dup(int); +int dup2(int, int); +off_t lseek(int, off_t, int); +int fsync(int); +void sync(void); +int fdatasync(int); + +ssize_t read(int, void *, size_t); +ssize_t write(int, const void *, size_t); +ssize_t pread(int, void *, size_t, off_t); +ssize_t pwrite(int, const void *, size_t, off_t); + +#define F_ULOCK 0 +#define F_LOCK  1 +#define F_TLOCK 2 +#define F_TEST  3 +int lockf(int, int, off_t); + +int chown(const char *, uid_t, gid_t); +int fchown(int, uid_t, gid_t); +int lchown(const char *, uid_t, gid_t); +int fchownat(int, const char *, uid_t, gid_t, int); + +int link(const char *, const char *); +int linkat(int, const char *, int, const char *, int); +int symlink(const char *, const char *); +int symlinkat(const char *, int, const char *); +int readlink(const char *, char *, size_t); +int readlinkat(int, const char *, char *, size_t); +int unlink(const char *); +int unlinkat(int, const char *, int); +int rmdir(const char *); +int truncate(const char *, off_t); +int ftruncate(int, off_t); + +#define F_OK 0 +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +int access(const char *, int); +int faccessat(int, const char *, int, int); + +int chdir(const char *); +int fchdir(int); +char *getcwd(char *, size_t); +int chroot(const char *); /* dropped */ + +unsigned alarm(unsigned); +useconds_t ualarm(useconds_t, useconds_t); +unsigned sleep(unsigned); +int usleep(useconds_t); +int pause(void); +int nice(int); + +pid_t fork(void); +pid_t vfork(void); +int execve(const char *, char *const [], char *const []); +int execv(const char *, char *const []); +int execle(const char *, ...); +int execl(const char *, ...); +int execvp(const char *, char *const []); +int execlp(const char *, ...); +void _exit(int); + +pid_t getpid(void); +pid_t getppid(void); +pid_t getpgrp(void); +pid_t getpgid(pid_t); +int setpgid(pid_t, pid_t); +int setpgrp(void); +pid_t setsid(void); +pid_t getsid(pid_t); +char *ttyname(int); +int ttyname_r(int, char *, size_t); +int isatty(int); +pid_t tcgetpgrp(int); +int tcsetpgrp(int, pid_t); + +uid_t getuid(void); +uid_t geteuid(void); +gid_t getgid(void); +gid_t getegid(void); +int getgroups(int, gid_t []); +int setuid(uid_t); +int setreuid(uid_t, uid_t); +int seteuid(uid_t); +int setgid(gid_t); +int setregid(gid_t, gid_t); +int setegid(gid_t); + +char *getlogin(void); +int getlogin_r(char *, size_t); +long gethostid(void); +int gethostname(char *, size_t); +int sethostname(const char *, size_t); +int getpagesize(void); +char *ctermid(char *); + +int vhangup(void); /* dropped */ + +int getopt(int, char * const [], const char *); +extern char *optarg; +extern int optind, opterr, optopt; + +char *crypt(const char *, const char *); +void encrypt(char *, int); + +void swab(const void *, void *, ssize_t); + +long pathconf(const char *, int); +long fpathconf(int, int); +long sysconf(int); +size_t confstr(int, char *, size_t); + +#define _XOPEN_VERSION          700 +#define _XOPEN_UNIX             1 +#define _XOPEN_ENH_I18N         1 + +#define _POSIX_VERSION          200809L +#define _POSIX2_VERSION         _POSIX_VERSION + +#define _POSIX_CHOWN_RESTRICTED 1 +#define _POSIX_IPV6             _POSIX_VERSION +#define _POSIX_JOB_CONTROL      1 +#define _POSIX_MAPPED_FILES     _POSIX_VERSION +#define _POSIX_MEMLOCK          _POSIX_VERSION +#define _POSIX_MEMLOCK_RANGE    _POSIX_VERSION +#define _POSIX_MEMORY_PROTECTION _POSIX_VERSION +#define _POSIX_NO_TRUNC         1 +#define _POSIX_RAW_SOCKETS      _POSIX_VERSION +#define _POSIX_REALTIME_SIGNALS _POSIX_VERSION +#define _POSIX_REGEXP           1 +#define _POSIX_SAVED_IDS        1 +#define _POSIX_SHELL            1 +#define _POSIX_VDISABLE         0 + +#define _POSIX_THREADS          _POSIX_VERSION +#define _POSIX_THREAD_PROCESS_SHARED _POSIX_VERSION +#define _POSIX_THREAD_SAFE_FUNCTIONS _POSIX_VERSION +#define _POSIX_TIMERS           _POSIX_VERSION +#define _POSIX_TIMEOUTS         _POSIX_VERSION +#define _POSIX_MONOTONIC_CLOCK  _POSIX_VERSION +#define _POSIX_CPUTIME          _POSIX_VERSION +#define _POSIX_CLOCK_SELECTION  _POSIX_VERSION +#define _POSIX_BARRIERS         _POSIX_VERSION +#define _POSIX_SPIN_LOCKS       _POSIX_VERSION +#define _POSIX_READER_WRITER_LOCKS _POSIX_VERSION +#define _POSIX_ASYNCHRONOUS_IO  _POSIX_VERSION +#define _POSIX_SEMAPHORES       _POSIX_VERSION + +#define _POSIX2_C_BIND          _POSIX_VERSION + +#include <bits/posix.h> + + + +#define _PC_LINK_MAX	0 +#define _PC_MAX_CANON	1 +#define _PC_MAX_INPUT	2 +#define _PC_NAME_MAX	3 +#define _PC_PATH_MAX	4 +#define _PC_PIPE_BUF	5 +#define _PC_CHOWN_RESTRICTED	6 +#define _PC_NO_TRUNC	7 +#define _PC_VDISABLE	8 +#define _PC_SYNC_IO	9 +#define _PC_ASYNC_IO	10 +#define _PC_PRIO_IO	11 +#define _PC_SOCK_MAXBUF	12 +#define _PC_FILESIZEBITS	13 +#define _PC_REC_INCR_XFER_SIZE	14 +#define _PC_REC_MAX_XFER_SIZE	15 +#define _PC_REC_MIN_XFER_SIZE	16 +#define _PC_REC_XFER_ALIGN	17 +#define _PC_ALLOC_SIZE_MIN	18 +#define _PC_SYMLINK_MAX	19 +#define _PC_2_SYMLINKS	20 + +#define _SC_ARG_MAX	0 +#define _SC_CHILD_MAX	1 +#define _SC_CLK_TCK	2 +#define _SC_NGROUPS_MAX	3 +#define _SC_OPEN_MAX	4 +#define _SC_STREAM_MAX	5 +#define _SC_TZNAME_MAX	6 +#define _SC_JOB_CONTROL	7 +#define _SC_SAVED_IDS	8 +#define _SC_REALTIME_SIGNALS	9 +#define _SC_PRIORITY_SCHEDULING	10 +#define _SC_TIMERS	11 +#define _SC_ASYNCHRONOUS_IO	12 +#define _SC_PRIORITIZED_IO	13 +#define _SC_SYNCHRONIZED_IO	14 +#define _SC_FSYNC	15 +#define _SC_MAPPED_FILES	16 +#define _SC_MEMLOCK	17 +#define _SC_MEMLOCK_RANGE	18 +#define _SC_MEMORY_PROTECTION	19 +#define _SC_MESSAGE_PASSING	20 +#define _SC_SEMAPHORES	21 +#define _SC_SHARED_MEMORY_OBJECTS	22 +#define _SC_AIO_LISTIO_MAX	23 +#define _SC_AIO_MAX	24 +#define _SC_AIO_PRIO_DELTA_MAX	25 +#define _SC_DELAYTIMER_MAX	26 +#define _SC_MQ_OPEN_MAX	27 +#define _SC_MQ_PRIO_MAX	28 +#define _SC_VERSION	29 +#define _SC_PAGE_SIZE	30 +#define _SC_PAGESIZE	30 /* !! */ +#define _SC_RTSIG_MAX	31 +#define _SC_SEM_NSEMS_MAX	32 +#define _SC_SEM_VALUE_MAX	33 +#define _SC_SIGQUEUE_MAX	34 +#define _SC_TIMER_MAX	35 +#define _SC_BC_BASE_MAX	36 +#define _SC_BC_DIM_MAX	37 +#define _SC_BC_SCALE_MAX	38 +#define _SC_BC_STRING_MAX	39 +#define _SC_COLL_WEIGHTS_MAX	40 +#define _SC_EQUIV_CLASS_MAX	41 +#define _SC_EXPR_NEST_MAX	42 +#define _SC_LINE_MAX	43 +#define _SC_RE_DUP_MAX	44 +#define _SC_CHARCLASS_NAME_MAX	45 +#define _SC_2_VERSION	46 +#define _SC_2_C_BIND	47 +#define _SC_2_C_DEV	48 +#define _SC_2_FORT_DEV	49 +#define _SC_2_FORT_RUN	50 +#define _SC_2_SW_DEV	51 +#define _SC_2_LOCALEDEF	52 +#define _SC_PII	53 +#define _SC_PII_XTI	54 +#define _SC_PII_SOCKET	55 +#define _SC_PII_INTERNET	56 +#define _SC_PII_OSI	57 +#define _SC_POLL	58 +#define _SC_SELECT	59 +#define _SC_UIO_MAXIOV	60 /* !! */ +#define _SC_IOV_MAX	60 +#define _SC_PII_INTERNET_STREAM	61 +#define _SC_PII_INTERNET_DGRAM	62 +#define _SC_PII_OSI_COTS	63 +#define _SC_PII_OSI_CLTS	64 +#define _SC_PII_OSI_M	65 +#define _SC_T_IOV_MAX	66 +#define _SC_THREADS	67 +#define _SC_THREAD_SAFE_FUNCTIONS	68 +#define _SC_GETGR_R_SIZE_MAX	69 +#define _SC_GETPW_R_SIZE_MAX	70 +#define _SC_LOGIN_NAME_MAX	71 +#define _SC_TTY_NAME_MAX	72 +#define _SC_THREAD_DESTRUCTOR_ITERATIONS	73 +#define _SC_THREAD_KEYS_MAX	74 +#define _SC_THREAD_STACK_MIN	75 +#define _SC_THREAD_THREADS_MAX	76 +#define _SC_THREAD_ATTR_STACKADDR	77 +#define _SC_THREAD_ATTR_STACKSIZE	78 +#define _SC_THREAD_PRIORITY_SCHEDULING	79 +#define _SC_THREAD_PRIO_INHERIT	80 +#define _SC_THREAD_PRIO_PROTECT	81 +#define _SC_THREAD_PROCESS_SHARED	82 +#define _SC_NPROCESSORS_CONF	83 +#define _SC_NPROCESSORS_ONLN	84 +#define _SC_PHYS_PAGES	85 +#define _SC_AVPHYS_PAGES	86 +#define _SC_ATEXIT_MAX	87 +#define _SC_PASS_MAX	88 +#define _SC_XOPEN_VERSION	89 +#define _SC_XOPEN_XCU_VERSION	90 +#define _SC_XOPEN_UNIX	91 +#define _SC_XOPEN_CRYPT	92 +#define _SC_XOPEN_ENH_I18N	93 +#define _SC_XOPEN_SHM	94 +#define _SC_2_CHAR_TERM	95 +#define _SC_2_C_VERSION	96 +#define _SC_2_UPE	97 +#define _SC_XOPEN_XPG2	98 +#define _SC_XOPEN_XPG3	99 +#define _SC_XOPEN_XPG4	100 +#define _SC_CHAR_BIT	101 +#define _SC_CHAR_MAX	102 +#define _SC_CHAR_MIN	103 +#define _SC_INT_MAX	104 +#define _SC_INT_MIN	105 +#define _SC_LONG_BIT	106 +#define _SC_WORD_BIT	107 +#define _SC_MB_LEN_MAX	108 +#define _SC_NZERO	109 +#define _SC_SSIZE_MAX	110 +#define _SC_SCHAR_MAX	111 +#define _SC_SCHAR_MIN	112 +#define _SC_SHRT_MAX	113 +#define _SC_SHRT_MIN	114 +#define _SC_UCHAR_MAX	115 +#define _SC_UINT_MAX	116 +#define _SC_ULONG_MAX	117 +#define _SC_USHRT_MAX	118 +#define _SC_NL_ARGMAX	119 +#define _SC_NL_LANGMAX	120 +#define _SC_NL_MSGMAX	121 +#define _SC_NL_NMAX	122 +#define _SC_NL_SETMAX	123 +#define _SC_NL_TEXTMAX	124 +#define _SC_XBS5_ILP32_OFF32	125 +#define _SC_XBS5_ILP32_OFFBIG	126 +#define _SC_XBS5_LP64_OFF64	127 +#define _SC_XBS5_LPBIG_OFFBIG	128 +#define _SC_XOPEN_LEGACY	129 +#define _SC_XOPEN_REALTIME	130 +#define _SC_XOPEN_REALTIME_THREADS	131 +#define _SC_ADVISORY_INFO	132 +#define _SC_BARRIERS	133 +#define _SC_BASE	134 +#define _SC_C_LANG_SUPPORT	135 +#define _SC_C_LANG_SUPPORT_R	136 +#define _SC_CLOCK_SELECTION	137 +#define _SC_CPUTIME	138 +#define _SC_THREAD_CPUTIME	139 +#define _SC_DEVICE_IO	140 +#define _SC_DEVICE_SPECIFIC	141 +#define _SC_DEVICE_SPECIFIC_R	142 +#define _SC_FD_MGMT	143 +#define _SC_FIFO	144 +#define _SC_PIPE	145 +#define _SC_FILE_ATTRIBUTES	146 +#define _SC_FILE_LOCKING	147 +#define _SC_FILE_SYSTEM	148 +#define _SC_MONOTONIC_CLOCK	149 +#define _SC_MULTI_PROCESS	150 +#define _SC_SINGLE_PROCESS	151 +#define _SC_NETWORKING	152 +#define _SC_READER_WRITER_LOCKS	153 +#define _SC_SPIN_LOCKS	154 +#define _SC_REGEXP	155 +#define _SC_REGEX_VERSION	156 +#define _SC_SHELL	157 +#define _SC_SIGNALS	158 +#define _SC_SPAWN	159 +#define _SC_SPORADIC_SERVER	160 +#define _SC_THREAD_SPORADIC_SERVER	161 +#define _SC_SYSTEM_DATABASE	162 +#define _SC_SYSTEM_DATABASE_R	163 +#define _SC_TIMEOUTS	164 +#define _SC_TYPED_MEMORY_OBJECTS	165 +#define _SC_USER_GROUPS	166 +#define _SC_USER_GROUPS_R	167 +#define _SC_2_PBS	168 +#define _SC_2_PBS_ACCOUNTING	169 +#define _SC_2_PBS_LOCATE	170 +#define _SC_2_PBS_MESSAGE	171 +#define _SC_2_PBS_TRACK	172 +#define _SC_SYMLOOP_MAX	173 +#define _SC_STREAMS	174 +#define _SC_2_PBS_CHECKPOINT	175 +#define _SC_V6_ILP32_OFF32	176 +#define _SC_V6_ILP32_OFFBIG	177 +#define _SC_V6_LP64_OFF64	178 +#define _SC_V6_LPBIG_OFFBIG	179 +#define _SC_HOST_NAME_MAX	180 +#define _SC_TRACE	181 +#define _SC_TRACE_EVENT_FILTER	182 +#define _SC_TRACE_INHERIT	183 +#define _SC_TRACE_LOG	184 + +#define _SC_IPV6	235 +#define _SC_RAW_SOCKETS	236 +#define _SC_V7_ILP32_OFF32	237 +#define _SC_V7_ILP32_OFFBIG	238 +#define _SC_V7_LP64_OFF64	239 +#define _SC_V7_LPBIG_OFFBIG	240 +#define _SC_SS_REPL_MAX	241 +#define _SC_TRACE_EVENT_NAME_MAX	242 +#define _SC_TRACE_NAME_MAX	243 +#define _SC_TRACE_SYS_MAX	244 +#define _SC_TRACE_USER_EVENT_MAX	245 +#define _SC_XOPEN_STREAMS	246 +#define _SC_THREAD_ROBUST_PRIO_INHERIT	247 +#define _SC_THREAD_ROBUST_PRIO_PROTECT	248 + +#define _CS_PATH	0 +#define _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS	1 +#define _CS_GNU_LIBC_VERSION	2 +#define _CS_GNU_LIBPTHREAD_VERSION	3 +#define _CS_POSIX_V5_WIDTH_RESTRICTED_ENVS	4 +#define _CS_POSIX_V7_WIDTH_RESTRICTED_ENVS	5 + +#define _CS_POSIX_V6_ILP32_OFF32_CFLAGS	1116 +#define _CS_POSIX_V6_ILP32_OFF32_LDFLAGS	1117 +#define _CS_POSIX_V6_ILP32_OFF32_LIBS	1118 +#define _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS	1119 +#define _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS	1120 +#define _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS	1121 +#define _CS_POSIX_V6_ILP32_OFFBIG_LIBS	1122 +#define _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS	1123 +#define _CS_POSIX_V6_LP64_OFF64_CFLAGS	1124 +#define _CS_POSIX_V6_LP64_OFF64_LDFLAGS	1125 +#define _CS_POSIX_V6_LP64_OFF64_LIBS	1126 +#define _CS_POSIX_V6_LP64_OFF64_LINTFLAGS	1127 +#define _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS	1128 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS	1129 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LIBS	1130 +#define _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS	1131 +#define _CS_POSIX_V7_ILP32_OFF32_CFLAGS	1132 +#define _CS_POSIX_V7_ILP32_OFF32_LDFLAGS	1133 +#define _CS_POSIX_V7_ILP32_OFF32_LIBS	1134 +#define _CS_POSIX_V7_ILP32_OFF32_LINTFLAGS	1135 +#define _CS_POSIX_V7_ILP32_OFFBIG_CFLAGS	1136 +#define _CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS	1137 +#define _CS_POSIX_V7_ILP32_OFFBIG_LIBS	1138 +#define _CS_POSIX_V7_ILP32_OFFBIG_LINTFLAGS	1139 +#define _CS_POSIX_V7_LP64_OFF64_CFLAGS	1140 +#define _CS_POSIX_V7_LP64_OFF64_LDFLAGS	1141 +#define _CS_POSIX_V7_LP64_OFF64_LIBS	1142 +#define _CS_POSIX_V7_LP64_OFF64_LINTFLAGS	1143 +#define _CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS	1144 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS	1145 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LIBS	1146 +#define _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS	1147 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/utime.h b/include/utime.h new file mode 100644 index 00000000..ec82e0f3 --- /dev/null +++ b/include/utime.h @@ -0,0 +1,24 @@ +#ifndef	_UTIME_H +#define	_UTIME_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_time_t + +#include <bits/alltypes.h> + +struct utimbuf +{ +	time_t actime; +	time_t modtime; +}; + +int utime (const char *, const struct utimbuf *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/utmp.h b/include/utmp.h new file mode 100644 index 00000000..f60ff883 --- /dev/null +++ b/include/utmp.h @@ -0,0 +1,23 @@ +#ifndef _UTMP_H +#define _UTMP_H + +#include <utmpx.h> + +#define ut_time ut_tv.tv_sec +#define ut_name ut_user +#define ut_exit __ut_exit +#define e_termination __e_termination +#define e_exit __e_exit +#define utmp utmpx +#define endutent endutxent +#define getutent getutxent +#define setutent setutxent +#define getutid getutxid +#define getutline getutxline +#define pututline pututxline +#define utmpname(x) (-1) + +#define _PATH_UTMP "/dev/null" +#define _PATH_WTMP "/dev/null" + +#endif diff --git a/include/utmpx.h b/include/utmpx.h new file mode 100644 index 00000000..9a2e3075 --- /dev/null +++ b/include/utmpx.h @@ -0,0 +1,52 @@ +#ifndef _UTMPX_H +#define _UTMPX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_pid_t +#define __NEED_time_t +#define __NEED_struct_timeval + +#include <bits/alltypes.h> + +struct utmpx +{ +	short ut_type; +	pid_t ut_pid; +	char ut_line[32]; +	char ut_id[4]; +	char ut_user[32]; +	char ut_host[256]; +	struct { +		short __e_termination; +		short __e_exit; +	} __ut_exit; +	long ut_session; +	struct timeval ut_tv; +	unsigned ut_addr_v6[4]; +	char __unused[20]; +}; + +void          endutxent(void); +struct utmpx *getutxent(void); +struct utmpx *getutxid(const struct utmpx *); +struct utmpx *getutxline(const struct utmpx *); +struct utmpx *pututxline(const struct utmpx *); +void          setutxent(void); + +#define EMPTY           0 +#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 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/wchar.h b/include/wchar.h new file mode 100644 index 00000000..3f325bff --- /dev/null +++ b/include/wchar.h @@ -0,0 +1,152 @@ +#ifndef _WCHAR_H +#define _WCHAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_FILE +#define __NEED_va_list +#define __NEED_size_t +#define __NEED_wchar_t +#define __NEED_wint_t +#define __NEED_wctype_t + +#include <bits/alltypes.h> + +#undef NULL +#define NULL ((void*)0) + +#undef WCHAR_MIN +#undef WCHAR_MAX +#define WCHAR_MIN (-1-0x7fffffff) +#define WCHAR_MAX (0x7fffffff) + +#undef WEOF +#define WEOF (-1) + + +typedef struct +{ +	unsigned __opaque1, __opaque2; +} mbstate_t; + +wchar_t *wcscpy (wchar_t *, const wchar_t *); +wchar_t *wcsncpy (wchar_t *, const wchar_t *, size_t); + +wchar_t *wcscat (wchar_t *, const wchar_t *); +wchar_t *wcsncat (wchar_t *, const wchar_t *, size_t); + +int wcscmp (const wchar_t *, const wchar_t *); +int wcsncmp (const wchar_t *, const wchar_t *, size_t); + +size_t wcsxfrm (wchar_t *, const wchar_t *, size_t n); + +wchar_t *wcschr (const wchar_t *, wchar_t); +wchar_t *wcsrchr (const wchar_t *, wchar_t); + +size_t wcscspn (const wchar_t *, const wchar_t *); +size_t wcsspn (const wchar_t *, const wchar_t *); +wchar_t *wcspbrk (const wchar_t *, const wchar_t *); + +wchar_t *wcstok (wchar_t *, const wchar_t *, wchar_t **); + +size_t wcslen (const wchar_t *); + +wchar_t *wcsstr (const wchar_t *, const wchar_t *); +wchar_t *wcswcs (const wchar_t *, const wchar_t *); + +wchar_t *wmemchr (const wchar_t *, wchar_t, size_t); +int wmemcmp (const wchar_t *, const wchar_t *, size_t); +wchar_t *wmemcpy (wchar_t *, const wchar_t *, size_t); +wchar_t *wmemmove (wchar_t *, const wchar_t *, size_t); +wchar_t *wmemset (wchar_t *, wchar_t, size_t); + +wint_t btowc (int); +int wctob (wint_t); + +int mbsinit (const mbstate_t *); +size_t mbrtowc (wchar_t *, const char *, size_t, mbstate_t *); +size_t wcrtomb (char *, wchar_t, mbstate_t *); + +size_t mbrlen (const char *, size_t, mbstate_t *); + +size_t mbsrtowcs (wchar_t *, const char **, size_t, mbstate_t *); +size_t wcsrtombs (char *, const wchar_t **, size_t, mbstate_t *); + +int wcwidth (wchar_t); +int wcswidth (const wchar_t *, size_t); + +float wcstof (const wchar_t *, wchar_t **); +double wcstod (const wchar_t *, wchar_t **); +long double wcstold (const wchar_t *, wchar_t **); + +long wcstol (const wchar_t *, wchar_t **, int); +unsigned long wcstoul (const wchar_t *, wchar_t **, int); + +long long wcstoll (const wchar_t *, wchar_t **, int); +unsigned long long wcstoull (const wchar_t *, wchar_t **, int); + + + +int fwide (FILE *, int); + + +int wprintf (const wchar_t *, ...); +int fwprintf (FILE *, const wchar_t *, ...); +int swprintf (wchar_t *, const wchar_t *, ...); + +int vwprintf (const wchar_t *, va_list); +int vfwprintf (FILE *, const wchar_t *, va_list); +int vswprintf (wchar_t *, const wchar_t *, va_list); + +int wscanf (const wchar_t *, ...); +int fwscanf (FILE *, const wchar_t *, ...); +int swscanf (const wchar_t *, const wchar_t *, ...); + +int vwscanf (const wchar_t *, va_list); +int vfwscanf (FILE *, const wchar_t *, va_list); +int vswscanf (const wchar_t *, const wchar_t *, va_list); + +wint_t fgetwc (FILE *); +wint_t getwc (FILE *); +wint_t getwchar (void); + +wint_t fputwc (wchar_t, FILE *); +wint_t putwc (wchar_t, FILE *); +wint_t putwchar (wchar_t); + +wchar_t *fgetws (wchar_t *, int, FILE *); +int fputws (const wchar_t *, FILE *); + +wint_t ungetwc (wint_t, FILE *); + +struct tm; +size_t wcsftime (wchar_t *, size_t, const wchar_t *, const struct tm *); + +#undef iswdigit + +int       iswalnum(wint_t); +int       iswalpha(wint_t); +int       iswblank(wint_t); +int       iswcntrl(wint_t); +int       iswdigit(wint_t); +int       iswgraph(wint_t); +int       iswlower(wint_t); +int       iswprint(wint_t); +int       iswpunct(wint_t); +int       iswspace(wint_t); +int       iswupper(wint_t); +int       iswxdigit(wint_t); +int       iswctype(wint_t, wctype_t); +wint_t    towlower(wint_t); +wint_t    towupper(wint_t); +wctype_t  wctype(const char *); + +#define iswdigit(a) ((unsigned)(a)-'0' < 10) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/wctype.h b/include/wctype.h new file mode 100644 index 00000000..8b6c9d9d --- /dev/null +++ b/include/wctype.h @@ -0,0 +1,44 @@ +#ifndef _WCTYPE_H +#define _WCTYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_wint_t +#define __NEED_wctrans_t +#define __NEED_wctype_t + +#include <bits/alltypes.h> + +#undef WEOF +#define WEOF (-1) + +#undef iswdigit + +int       iswalnum(wint_t); +int       iswalpha(wint_t); +int       iswblank(wint_t); +int       iswcntrl(wint_t); +int       iswdigit(wint_t); +int       iswgraph(wint_t); +int       iswlower(wint_t); +int       iswprint(wint_t); +int       iswpunct(wint_t); +int       iswspace(wint_t); +int       iswupper(wint_t); +int       iswxdigit(wint_t); +int       iswctype(wint_t, wctype_t); +wint_t    towctrans(wint_t, wctrans_t); +wint_t    towlower(wint_t); +wint_t    towupper(wint_t); +wctrans_t wctrans(const char *); +wctype_t  wctype(const char *); + +#define iswdigit(a) ((unsigned)((a)-L'0') < 10) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/wordexp.h b/include/wordexp.h new file mode 100644 index 00000000..91995c44 --- /dev/null +++ b/include/wordexp.h @@ -0,0 +1,40 @@ +#ifndef	_WORDEXP_H +#define	_WORDEXP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __NEED_size_t + +#include <bits/alltypes.h> + +#define WRDE_DOOFFS  1 +#define WRDE_APPEND  2 +#define WRDE_NOCMD   4 +#define WRDE_REUSE   8 +#define WRDE_SHOWERR 16 +#define WRDE_UNDEF   32 + +typedef struct +{ +	size_t we_wordc; +	char **wc_wordv; +	size_t we_offs; +} wordexp_t; + +#define WRDE_NOSYS   -1 +#define WRDE_NOSPACE 1 +#define WRDE_BADCHAR 2 +#define WRDE_BADVAL  3 +#define WRDE_CMDSUB  4 +#define WRDE_SYNTAX  5 + +int wordexp (const char *, wordexp_t *, int); +void wordfree (wordexp_t *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/conf/fpathconf.c b/src/conf/fpathconf.c new file mode 100644 index 00000000..af7e4d3b --- /dev/null +++ b/src/conf/fpathconf.c @@ -0,0 +1,35 @@ +#include <unistd.h> +#include <limits.h> +#include <errno.h> + +long fpathconf(int fd, int name) +{ +	static const short values[] = { +		[_PC_LINK_MAX] = _POSIX_LINK_MAX, +		[_PC_MAX_CANON] = _POSIX_MAX_CANON, +		[_PC_MAX_INPUT] = _POSIX_MAX_INPUT, +		[_PC_NAME_MAX] = NAME_MAX, +		[_PC_PATH_MAX] = PATH_MAX, +		[_PC_PIPE_BUF] = PIPE_BUF, +		[_PC_CHOWN_RESTRICTED] = 1, +		[_PC_NO_TRUNC] = 1, +		[_PC_VDISABLE] = 0, +		[_PC_SYNC_IO] = 0, +		[_PC_ASYNC_IO] = 0, +		[_PC_PRIO_IO] = 0, +		[_PC_SOCK_MAXBUF] = -1, +		[_PC_FILESIZEBITS] = sizeof(off_t), +		[_PC_REC_INCR_XFER_SIZE] = PAGE_SIZE, +		[_PC_REC_MAX_XFER_SIZE] = PAGE_SIZE, +		[_PC_REC_MIN_XFER_SIZE] = PAGE_SIZE, +		[_PC_REC_XFER_ALIGN] = PAGE_SIZE, +		[_PC_ALLOC_SIZE_MIN] = PAGE_SIZE, +		[_PC_SYMLINK_MAX] = SYMLINK_MAX, +		[_PC_2_SYMLINKS] = 1 +	}; +	if (name > sizeof(values)/sizeof(values[0])) { +		errno = EINVAL; +		return -1; +	} +	return values[name]; +} diff --git a/src/conf/pathconf.c b/src/conf/pathconf.c new file mode 100644 index 00000000..01e19c59 --- /dev/null +++ b/src/conf/pathconf.c @@ -0,0 +1,6 @@ +#include <unistd.h> + +long pathconf(const char *path, int name) +{ +	return fpathconf(-1, name); +} diff --git a/src/conf/sysconf.c b/src/conf/sysconf.c new file mode 100644 index 00000000..cdaeb2a6 --- /dev/null +++ b/src/conf/sysconf.c @@ -0,0 +1,222 @@ +#include <unistd.h> +#include <limits.h> +#include <errno.h> + +#define VER (-2) +#define OFLOW (-3) + +long sysconf(int name) +{ +	static const short values[] = { +		[_SC_ARG_MAX] = OFLOW, +		[_SC_CHILD_MAX] = -1, +		[_SC_CLK_TCK] = 100, +		[_SC_NGROUPS_MAX] = 32, +		[_SC_OPEN_MAX] = 1024, +		[_SC_STREAM_MAX] = -1, +		[_SC_TZNAME_MAX] = TZNAME_MAX, +		[_SC_JOB_CONTROL] = 1, +		[_SC_SAVED_IDS] = 1, +		[_SC_REALTIME_SIGNALS] = 1, +		[_SC_PRIORITY_SCHEDULING] = -1, +		[_SC_TIMERS] = VER, +		[_SC_ASYNCHRONOUS_IO] = VER, +		[_SC_PRIORITIZED_IO] = -1, +		[_SC_SYNCHRONIZED_IO] = -1, +		[_SC_FSYNC] = -1, +		[_SC_MAPPED_FILES] = VER, +		[_SC_MEMLOCK] = VER, +		[_SC_MEMLOCK_RANGE] = VER, +		[_SC_MEMORY_PROTECTION] = VER, +		[_SC_MESSAGE_PASSING] = -1, +		[_SC_SEMAPHORES] = VER, +		[_SC_SHARED_MEMORY_OBJECTS] = -1, +		[_SC_AIO_LISTIO_MAX] = -1, +		[_SC_AIO_MAX] = -1, +		[_SC_AIO_PRIO_DELTA_MAX] = 0, /* ?? */ +		[_SC_DELAYTIMER_MAX] = _POSIX_DELAYTIMER_MAX, +		[_SC_MQ_OPEN_MAX] = -1, +		[_SC_MQ_PRIO_MAX] = _POSIX_MQ_PRIO_MAX, +		[_SC_VERSION] = VER, +		[_SC_PAGE_SIZE] = PAGE_SIZE, +		[_SC_RTSIG_MAX] = 63, /* ?? */ +		[_SC_SEM_NSEMS_MAX] = _POSIX_SEM_NSEMS_MAX, +		[_SC_SEM_VALUE_MAX] = _POSIX_SEM_VALUE_MAX, +		[_SC_SIGQUEUE_MAX] = -1, +		[_SC_TIMER_MAX] = -1, +		[_SC_BC_BASE_MAX] = _POSIX2_BC_BASE_MAX, +		[_SC_BC_DIM_MAX] = _POSIX2_BC_DIM_MAX, +		[_SC_BC_SCALE_MAX] = _POSIX2_BC_SCALE_MAX, +		[_SC_BC_STRING_MAX] = _POSIX2_BC_STRING_MAX, +		[_SC_COLL_WEIGHTS_MAX] = COLL_WEIGHTS_MAX, +		[_SC_EQUIV_CLASS_MAX] = -1, /* ?? */ +		[_SC_EXPR_NEST_MAX] = -1, +		[_SC_LINE_MAX] = -1, +		[_SC_RE_DUP_MAX] = RE_DUP_MAX, +		[_SC_CHARCLASS_NAME_MAX] = -1, /* ?? */ +		[_SC_2_VERSION] = VER, +		[_SC_2_C_BIND] = VER, +		[_SC_2_C_DEV] = -1, +		[_SC_2_FORT_DEV] = -1, +		[_SC_2_FORT_RUN] = -1, +		[_SC_2_SW_DEV] = -1, +		[_SC_2_LOCALEDEF] = -1, +		[_SC_PII] = -1, /* ????????? */ +		[_SC_PII_XTI] = -1, +		[_SC_PII_SOCKET] = -1, +		[_SC_PII_INTERNET] = -1, +		[_SC_PII_OSI] = -1, +		[_SC_POLL] = 1, +		[_SC_SELECT] = 1, +		[_SC_IOV_MAX] = IOV_MAX, +		[_SC_PII_INTERNET_STREAM] = -1, +		[_SC_PII_INTERNET_DGRAM] = -1, +		[_SC_PII_OSI_COTS] = -1, +		[_SC_PII_OSI_CLTS] = -1, +		[_SC_PII_OSI_M] = -1, +		[_SC_T_IOV_MAX] = -1, +		[_SC_THREADS] = VER, +		[_SC_THREAD_SAFE_FUNCTIONS] = VER, +		[_SC_GETGR_R_SIZE_MAX] = -1, +		[_SC_GETPW_R_SIZE_MAX] = -1, +		[_SC_LOGIN_NAME_MAX] = 256, +		[_SC_TTY_NAME_MAX] = TTY_NAME_MAX, +		[_SC_THREAD_DESTRUCTOR_ITERATIONS] = _POSIX_THREAD_DESTRUCTOR_ITERATIONS, +		[_SC_THREAD_KEYS_MAX] = -1, +		[_SC_THREAD_STACK_MIN] = 2*PAGE_SIZE, +		[_SC_THREAD_THREADS_MAX] = -1, +		[_SC_THREAD_ATTR_STACKADDR] = -1, +		[_SC_THREAD_ATTR_STACKSIZE] = VER, +		[_SC_THREAD_PRIORITY_SCHEDULING] = -1, +		[_SC_THREAD_PRIO_INHERIT] = -1, +		[_SC_THREAD_PRIO_PROTECT] = -1, +		[_SC_THREAD_PROCESS_SHARED] = VER, +		[_SC_NPROCESSORS_CONF] = -1, +		[_SC_NPROCESSORS_ONLN] = -1, +		[_SC_PHYS_PAGES] = -1, +		[_SC_AVPHYS_PAGES] = -1, +		[_SC_ATEXIT_MAX] = -1, +		[_SC_PASS_MAX] = -1, +		[_SC_XOPEN_VERSION] = _XOPEN_VERSION, +		[_SC_XOPEN_XCU_VERSION] = _XOPEN_VERSION, +		[_SC_XOPEN_UNIX] = -1, +		[_SC_XOPEN_CRYPT] = -1, +		[_SC_XOPEN_ENH_I18N] = 1, +		[_SC_XOPEN_SHM] = 1, +		[_SC_2_CHAR_TERM] = -1, +		[_SC_2_C_VERSION] = -1, +		[_SC_2_UPE] = -1, +		[_SC_XOPEN_XPG2] = -1, +		[_SC_XOPEN_XPG3] = -1, +		[_SC_XOPEN_XPG4] = -1, +		[_SC_CHAR_BIT] = -1, +		[_SC_CHAR_MAX] = -1, +		[_SC_CHAR_MIN] = -1, +		[_SC_INT_MAX] = -1, +		[_SC_INT_MIN] = -1, +		[_SC_LONG_BIT] = -1, +		[_SC_WORD_BIT] = -1, +		[_SC_MB_LEN_MAX] = -1, +		[_SC_NZERO] = NZERO, +		[_SC_SSIZE_MAX] = -1, +		[_SC_SCHAR_MAX] = -1, +		[_SC_SCHAR_MIN] = -1, +		[_SC_SHRT_MAX] = -1, +		[_SC_SHRT_MIN] = -1, +		[_SC_UCHAR_MAX] = -1, +		[_SC_UINT_MAX] = -1, +		[_SC_ULONG_MAX] = -1, +		[_SC_USHRT_MAX] = -1, +		[_SC_NL_ARGMAX] = -1, +		[_SC_NL_LANGMAX] = -1, +		[_SC_NL_MSGMAX] = -1, +		[_SC_NL_NMAX] = -1, +		[_SC_NL_SETMAX] = -1, +		[_SC_NL_TEXTMAX] = -1, +		[_SC_XBS5_ILP32_OFF32] = -1, +		[_SC_XBS5_ILP32_OFFBIG] = 2*(sizeof(long)==4)-1, +		[_SC_XBS5_LP64_OFF64] = 2*(sizeof(long)==8)-1, +		[_SC_XBS5_LPBIG_OFFBIG] = 2*(sizeof(long)>=8)-1, +		[_SC_XOPEN_LEGACY] = -1, +		[_SC_XOPEN_REALTIME] = -1, +		[_SC_XOPEN_REALTIME_THREADS] = -1, +		[_SC_ADVISORY_INFO] = -1, +		[_SC_BARRIERS] = VER, +		[_SC_BASE] = -1, +		[_SC_C_LANG_SUPPORT] = -1, +		[_SC_C_LANG_SUPPORT_R] = -1, +		[_SC_CLOCK_SELECTION] = VER, +		[_SC_CPUTIME] = VER, +		[_SC_THREAD_CPUTIME] = -1, +		[_SC_DEVICE_IO] = -1, +		[_SC_DEVICE_SPECIFIC] = -1, +		[_SC_DEVICE_SPECIFIC_R] = -1, +		[_SC_FD_MGMT] = -1, +		[_SC_FIFO] = -1, +		[_SC_PIPE] = -1, +		[_SC_FILE_ATTRIBUTES] = -1, +		[_SC_FILE_LOCKING] = -1, +		[_SC_FILE_SYSTEM] = -1, +		[_SC_MONOTONIC_CLOCK] = VER, +		[_SC_MULTI_PROCESS] = -1, +		[_SC_SINGLE_PROCESS] = -1, +		[_SC_NETWORKING] = -1, +		[_SC_READER_WRITER_LOCKS] = VER, +		[_SC_SPIN_LOCKS] = VER, +		[_SC_REGEXP] = 1, +		[_SC_REGEX_VERSION] = -1, +		[_SC_SHELL] = 1, +		[_SC_SIGNALS] = -1, +		[_SC_SPAWN] = -1, +		[_SC_SPORADIC_SERVER] = -1, +		[_SC_THREAD_SPORADIC_SERVER] = -1, +		[_SC_SYSTEM_DATABASE] = -1, +		[_SC_SYSTEM_DATABASE_R] = -1, +		[_SC_TIMEOUTS] = VER, +		[_SC_TYPED_MEMORY_OBJECTS] = -1, +		[_SC_USER_GROUPS] = -1, +		[_SC_USER_GROUPS_R] = -1, +		[_SC_2_PBS] = -1, +		[_SC_2_PBS_ACCOUNTING] = -1, +		[_SC_2_PBS_LOCATE] = -1, +		[_SC_2_PBS_MESSAGE] = -1, +		[_SC_2_PBS_TRACK] = -1, +		[_SC_SYMLOOP_MAX] = SYMLOOP_MAX, +		[_SC_STREAMS] = 0, +		[_SC_2_PBS_CHECKPOINT] = -1, +		[_SC_V6_ILP32_OFF32] = -1, +		[_SC_V6_ILP32_OFFBIG] = 2*(sizeof(long)==4)-1, +		[_SC_V6_LP64_OFF64] = 2*(sizeof(long)==8)-1, +		[_SC_V6_LPBIG_OFFBIG] = 2*(sizeof(long)>=8)-1, +		[_SC_HOST_NAME_MAX] = HOST_NAME_MAX, +		[_SC_TRACE] = -1, +		[_SC_TRACE_EVENT_FILTER] = -1, +		[_SC_TRACE_INHERIT] = -1, +		[_SC_TRACE_LOG] = -1, + +		[_SC_IPV6] = VER, +		[_SC_RAW_SOCKETS] = VER, +		[_SC_V7_ILP32_OFF32] = -1, +		[_SC_V7_ILP32_OFFBIG] = 2*(sizeof(long)==4)-1, +		[_SC_V7_LP64_OFF64] = 2*(sizeof(long)==8)-1, +		[_SC_V7_LPBIG_OFFBIG] = 2*(sizeof(long)>=8)-1, +		[_SC_SS_REPL_MAX] = -1, +		[_SC_TRACE_EVENT_NAME_MAX] = -1, +		[_SC_TRACE_NAME_MAX] = -1, +		[_SC_TRACE_SYS_MAX] = -1, +		[_SC_TRACE_USER_EVENT_MAX] = -1, +		[_SC_XOPEN_STREAMS] = 0, +		[_SC_THREAD_ROBUST_PRIO_INHERIT] = -1, +		[_SC_THREAD_ROBUST_PRIO_PROTECT] = -1, +	}; +	if (name > sizeof(values)/sizeof(values[0])) { +		errno = EINVAL; +		return -1; +	} else if (values[name] == VER) { +		return _POSIX_VERSION; +	} else if (values[name] == OFLOW) { +		return ARG_MAX; +	} else { +		return values[name]; +	} +} diff --git a/src/ctype/__ctype_get_mb_cur_max.c b/src/ctype/__ctype_get_mb_cur_max.c new file mode 100644 index 00000000..42e4ee71 --- /dev/null +++ b/src/ctype/__ctype_get_mb_cur_max.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +size_t __ctype_get_mb_cur_max() +{ +	return 4; +} diff --git a/src/ctype/isalnum.c b/src/ctype/isalnum.c new file mode 100644 index 00000000..e3d2cf0b --- /dev/null +++ b/src/ctype/isalnum.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isalnum(int c) +{ +	return isalpha(c) || isdigit(c); +} diff --git a/src/ctype/isalpha.c b/src/ctype/isalpha.c new file mode 100644 index 00000000..53e115c2 --- /dev/null +++ b/src/ctype/isalpha.c @@ -0,0 +1,7 @@ +#include <ctype.h> +#undef isalpha + +int isalpha(int c) +{ +	return ((unsigned)c|32)-'a' < 26; +} diff --git a/src/ctype/isascii.c b/src/ctype/isascii.c new file mode 100644 index 00000000..3af0a10d --- /dev/null +++ b/src/ctype/isascii.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isascii(int c) +{ +	return !(c&~0x7f); +} diff --git a/src/ctype/isblank.c b/src/ctype/isblank.c new file mode 100644 index 00000000..957400b2 --- /dev/null +++ b/src/ctype/isblank.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isblank(int c) +{ +	return (c == ' ' || c == '\t'); +} diff --git a/src/ctype/iscntrl.c b/src/ctype/iscntrl.c new file mode 100644 index 00000000..92ed7f0e --- /dev/null +++ b/src/ctype/iscntrl.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int iscntrl(int c) +{ +	return (unsigned)c < 0x20 || c == 0x7f; +} diff --git a/src/ctype/isdigit.c b/src/ctype/isdigit.c new file mode 100644 index 00000000..0bc82a6d --- /dev/null +++ b/src/ctype/isdigit.c @@ -0,0 +1,7 @@ +#include <ctype.h> +#undef isdigit + +int isdigit(int c) +{ +	return (unsigned)c-'0' < 10; +} diff --git a/src/ctype/isgraph.c b/src/ctype/isgraph.c new file mode 100644 index 00000000..98979d1e --- /dev/null +++ b/src/ctype/isgraph.c @@ -0,0 +1,4 @@ +int isgraph(int c) +{ +	return (unsigned)c-0x21 < 0x5e; +} diff --git a/src/ctype/islower.c b/src/ctype/islower.c new file mode 100644 index 00000000..d72fb212 --- /dev/null +++ b/src/ctype/islower.c @@ -0,0 +1,7 @@ +#include <ctype.h> +#undef islower + +int islower(int c) +{ +	return (unsigned)c-'a' < 26; +} diff --git a/src/ctype/isprint.c b/src/ctype/isprint.c new file mode 100644 index 00000000..504e66ed --- /dev/null +++ b/src/ctype/isprint.c @@ -0,0 +1,4 @@ +int isprint(int c) +{ +	return (unsigned)c-0x20 < 0x5f; +} diff --git a/src/ctype/ispunct.c b/src/ctype/ispunct.c new file mode 100644 index 00000000..fc455352 --- /dev/null +++ b/src/ctype/ispunct.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int ispunct(int c) +{ +	return isgraph(c) && !isalnum(c); +} diff --git a/src/ctype/isspace.c b/src/ctype/isspace.c new file mode 100644 index 00000000..8e535aa1 --- /dev/null +++ b/src/ctype/isspace.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isspace(int c) +{ +	return c == ' ' || (unsigned)c-'\t' < 5; +} diff --git a/src/ctype/isupper.c b/src/ctype/isupper.c new file mode 100644 index 00000000..f09d88c5 --- /dev/null +++ b/src/ctype/isupper.c @@ -0,0 +1,7 @@ +#include <ctype.h> +#undef isupper + +int isupper(int c) +{ +	return (unsigned)c-'A' < 26; +} diff --git a/src/ctype/iswalnum.c b/src/ctype/iswalnum.c new file mode 100644 index 00000000..d3b56674 --- /dev/null +++ b/src/ctype/iswalnum.c @@ -0,0 +1,9 @@ +#include <wchar.h> +#include <wctype.h> + +#undef iswalnum + +int iswalnum(wint_t wc) +{ +	return (unsigned)wc-'0' < 10 || iswalpha(wc); +} diff --git a/src/ctype/iswalpha.c b/src/ctype/iswalpha.c new file mode 100644 index 00000000..0f031eac --- /dev/null +++ b/src/ctype/iswalpha.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswalpha(wint_t wc) +{ +	return (32U|wc)-'a'<26; +} diff --git a/src/ctype/iswblank.c b/src/ctype/iswblank.c new file mode 100644 index 00000000..bc6196f2 --- /dev/null +++ b/src/ctype/iswblank.c @@ -0,0 +1,8 @@ +#include <wchar.h> +#include <wctype.h> +#include <ctype.h> + +int iswblank(wint_t wc) +{ +	return isblank(wc); +} diff --git a/src/ctype/iswcntrl.c b/src/ctype/iswcntrl.c new file mode 100644 index 00000000..93942b08 --- /dev/null +++ b/src/ctype/iswcntrl.c @@ -0,0 +1,10 @@ +#include <wchar.h> +#include <wctype.h> + +int iswcntrl(wint_t wc) +{ +	return (unsigned)wc < 32 +	    || (unsigned)(wc-0x7f) < 33 +	    || (unsigned)(wc-0x2028) < 2 +	    || (unsigned)(wc-0xfff9) < 3; +} diff --git a/src/ctype/iswctype.c b/src/ctype/iswctype.c new file mode 100644 index 00000000..d917975b --- /dev/null +++ b/src/ctype/iswctype.c @@ -0,0 +1,63 @@ +#include <wchar.h> +#include <wctype.h> +#include <string.h> + +#define WCTYPE_ALNUM  1 +#define WCTYPE_ALPHA  2 +#define WCTYPE_BLANK  3 +#define WCTYPE_CNTRL  4 +#define WCTYPE_DIGIT  5 +#define WCTYPE_GRAPH  6 +#define WCTYPE_LOWER  7 +#define WCTYPE_PRINT  8 +#define WCTYPE_PUNCT  9 +#define WCTYPE_SPACE  10 +#define WCTYPE_UPPER  11 +#define WCTYPE_XDIGIT 12 + +int iswctype(wint_t wc, wctype_t type) +{ +	switch (type) { +	case WCTYPE_ALNUM: +		return iswalnum(wc); +	case WCTYPE_ALPHA: +		return iswalpha(wc); +	case WCTYPE_BLANK: +		return iswblank(wc); +	case WCTYPE_CNTRL: +		return iswcntrl(wc); +	case WCTYPE_DIGIT: +		return iswdigit(wc); +	case WCTYPE_GRAPH: +		return iswgraph(wc); +	case WCTYPE_LOWER: +		return iswlower(wc); +	case WCTYPE_PRINT: +		return iswprint(wc); +	case WCTYPE_PUNCT: +		return iswpunct(wc); +	case WCTYPE_SPACE: +		return iswspace(wc); +	case WCTYPE_UPPER: +		return iswupper(wc); +	case WCTYPE_XDIGIT: +		return iswxdigit(wc); +	} +	return 0; +} + +wctype_t wctype(const char *s) +{ +	int i; +	const char *p; +	/* order must match! */ +	static const char names[] = +		"alnum\0" "alpha\0" "blank\0" +		"cntrl\0" "digit\0" "graph\0" +		"lower\0" "print\0" "punct\0" +		"space\0" "upper\0" "xdigit"; +	for (i=1, p=names; *p; i++, p+=6) +		if (*s == *p && !strcmp(s, p)) +			return i; +	return 0; +} diff --git a/src/ctype/iswdigit.c b/src/ctype/iswdigit.c new file mode 100644 index 00000000..0487145f --- /dev/null +++ b/src/ctype/iswdigit.c @@ -0,0 +1,9 @@ +#include <wchar.h> +#include <wctype.h> + +#undef iswdigit + +int iswdigit(wint_t wc) +{ +	return (unsigned)wc-'0' < 10; +} diff --git a/src/ctype/iswgraph.c b/src/ctype/iswgraph.c new file mode 100644 index 00000000..fdc97853 --- /dev/null +++ b/src/ctype/iswgraph.c @@ -0,0 +1,7 @@ +#include <wctype.h> + +int iswgraph(wint_t wc) +{ +	/* ISO C defines this function as: */ +	return !iswspace(wc) && iswprint(wc); +} diff --git a/src/ctype/iswlower.c b/src/ctype/iswlower.c new file mode 100644 index 00000000..0a568e77 --- /dev/null +++ b/src/ctype/iswlower.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswlower(wint_t wc) +{ +	return towupper(wc) != wc; +} diff --git a/src/ctype/iswprint.c b/src/ctype/iswprint.c new file mode 100644 index 00000000..7717671a --- /dev/null +++ b/src/ctype/iswprint.c @@ -0,0 +1,10 @@ +#include <wctype.h> + +int iswprint(wint_t wc) +{ +	unsigned c = wc; +	/* assume any non-control, non-illegal codepoint is printable */ +	if (c>0x10ffff || c-0xd800<0x800 || (c&0xfffe)==0xfffe || iswcntrl(c)) +		return 0; +	return 1; +} diff --git a/src/ctype/iswpunct.c b/src/ctype/iswpunct.c new file mode 100644 index 00000000..1414c30c --- /dev/null +++ b/src/ctype/iswpunct.c @@ -0,0 +1,138 @@ +#include <wctype.h> +#include <inttypes.h> + +/* The below data is derived from classes (P.|Sm) plus Pattern_Syntax */ + +#define R(a,b) { (b), (b)-(a) } + +static const struct range { +	uint32_t base:20; +	uint32_t len:12; +} ranges[] = { +R(0x21, 0x2f), +R(0x3a, 0x40), +R(0x5b, 0x60), +R(0x7b, 0x7e), +R(0xa1, 0xa7), +R(0xa9, 0xa9), +R(0xab, 0xac), +R(0xae, 0xae), +R(0xb0, 0xb1), +R(0xb6, 0xb7), +R(0xbb, 0xbb), +R(0xbf, 0xbf), +R(0xd7, 0xd7), +R(0xf7, 0xf7), +R(0x37e, 0x37e), +R(0x387, 0x387), +R(0x3f6, 0x3f6), +R(0x55a, 0x55f), +R(0x589, 0x58a), +R(0x5be, 0x5be), +R(0x5c0, 0x5c0), +R(0x5c3, 0x5c3), +R(0x5c6, 0x5c6), +R(0x5f3, 0x5f4), +R(0x606, 0x60a), +R(0x60c, 0x60d), +R(0x61b, 0x61b), +R(0x61e, 0x61f), +R(0x66a, 0x66d), +R(0x6d4, 0x6d4), +R(0x700, 0x70d), +R(0x7f7, 0x7f9), +R(0x964, 0x965), +R(0x970, 0x970), +R(0xdf4, 0xdf4), +R(0xe4f, 0xe4f), +R(0xe5a, 0xe5b), +R(0xf04, 0xf12), +R(0xf3a, 0xf3d), +R(0xf85, 0xf85), +R(0xfd0, 0xfd4), +R(0x104a, 0x104f), +R(0x10fb, 0x10fb), +R(0x1361, 0x1368), +R(0x166d, 0x166e), +R(0x1680, 0x1680), +R(0x169b, 0x169c), +R(0x16eb, 0x16ed), +R(0x1735, 0x1736), +R(0x17d4, 0x17d6), +R(0x17d8, 0x17da), +R(0x1800, 0x180a), +R(0x180e, 0x180e), +R(0x1944, 0x1945), +R(0x19de, 0x19df), +R(0x1a1e, 0x1a1f), +R(0x1b5a, 0x1b60), +R(0x1c3b, 0x1c3f), +R(0x1c7e, 0x1c7f), +R(0x2010, 0x2027), +R(0x2030, 0x205e), +R(0x207a, 0x207e), +R(0x208a, 0x208e), +R(0x2140, 0x2144), +R(0x214b, 0x214b), +R(0x2190, 0x245f), +R(0x2500, 0x2775), +R(0x2794, 0x2bff), +R(0x2cf9, 0x2cfc), +R(0x2cfe, 0x2cff), +R(0x2e00, 0x2e7f), +R(0x3001, 0x3003), +R(0x3008, 0x3020), +R(0x3030, 0x3030), +R(0x303d, 0x303d), +R(0x30a0, 0x30a0), +R(0x30fb, 0x30fb), +R(0xa60d, 0xa60f), +R(0xa874, 0xa877), +R(0xa8ce, 0xa8cf), +R(0xa92e, 0xa92f), +R(0xa95f, 0xa95f), +R(0xfb29, 0xfb29), +R(0xfd3e, 0xfd3f), +R(0xfe10, 0xfe19), +R(0xfe30, 0xfe52), +R(0xfe54, 0xfe66), +R(0xfe68, 0xfe68), +R(0xfe6a, 0xfe6b), +R(0xff01, 0xff03), +R(0xff05, 0xff0f), +R(0xff1a, 0xff20), +R(0xff3b, 0xff3d), +R(0xff3f, 0xff3f), +R(0xff5b, 0xff65), +R(0xffe2, 0xffe2), +R(0xffe9, 0xffec), +R(0x10100, 0x10101), +R(0x1039f, 0x1039f), +R(0x103d0, 0x103d0), +R(0x1091f, 0x1091f), +R(0x1093f, 0x1093f), +R(0x10a50, 0x10a58), +R(0x12470, 0x12473), +R(0x1d6c1, 0x1d6c1), +R(0x1d6db, 0x1d6db), +R(0x1d6fb, 0x1d6fb), +R(0x1d715, 0x1d715), +R(0x1d735, 0x1d735), +R(0x1d74f, 0x1d74f), +R(0x1d76f, 0x1d76f), +R(0x1d789, 0x1d789), +R(0x1d7a9, 0x1d7a9), +R(0x1d7c3, 0x1d7c3), +}; + +int iswpunct(wint_t wc) +{ +	unsigned c = wc; +	int a = 0; +	int n = sizeof ranges / sizeof ranges[0]; +	do { +		n >>= 1; +		a += n+1 & (signed)(ranges[a+n].base-c)>>31; +	} while (n); +	return ranges[a].base-c <= ranges[a].len; +} diff --git a/src/ctype/iswspace.c b/src/ctype/iswspace.c new file mode 100644 index 00000000..68a17437 --- /dev/null +++ b/src/ctype/iswspace.c @@ -0,0 +1,15 @@ +#include <wchar.h> +#include <wctype.h> +#include <ctype.h> + +int iswspace(wint_t wc) +{ +	static const wchar_t spaces[] = { +		' ', '\t', '\n', '\r', 11, 12,  0x0085, +		0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, +		0x2006, 0x2008, 0x2009, 0x200a, 0x200b, +		0x2028, 0x2029, 0x2050, 0x3000, 0 +	}; +	if (wcschr(spaces, wc)) return 1; +	return 0; +} diff --git a/src/ctype/iswupper.c b/src/ctype/iswupper.c new file mode 100644 index 00000000..eae59a75 --- /dev/null +++ b/src/ctype/iswupper.c @@ -0,0 +1,6 @@ +#include <wctype.h> + +int iswupper(wint_t wc) +{ +	return towlower(wc) != wc; +} diff --git a/src/ctype/iswxdigit.c b/src/ctype/iswxdigit.c new file mode 100644 index 00000000..229a469f --- /dev/null +++ b/src/ctype/iswxdigit.c @@ -0,0 +1,7 @@ +#include <wchar.h> +#include <wctype.h> + +int iswxdigit(wint_t wc) +{ +	return (unsigned)(wc-'0') < 10 || (unsigned)((wc|32)-'a') < 6; +} diff --git a/src/ctype/isxdigit.c b/src/ctype/isxdigit.c new file mode 100644 index 00000000..ae68a3dc --- /dev/null +++ b/src/ctype/isxdigit.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isxdigit(int c) +{ +	return isdigit(c) || ((unsigned)c|32)-'a' < 6; +} diff --git a/src/ctype/toascii.c b/src/ctype/toascii.c new file mode 100644 index 00000000..f0e48e8e --- /dev/null +++ b/src/ctype/toascii.c @@ -0,0 +1,7 @@ +#include <ctype.h> + +/* nonsense function that should NEVER be used! */ +int toascii(int c) +{ +	return c & 0x7f; +} diff --git a/src/ctype/tolower.c b/src/ctype/tolower.c new file mode 100644 index 00000000..b56f3c50 --- /dev/null +++ b/src/ctype/tolower.c @@ -0,0 +1,7 @@ +#include <ctype.h> + +int tolower(int c) +{ +	if (isupper(c)) return c | 32; +	return c; +} diff --git a/src/ctype/toupper.c b/src/ctype/toupper.c new file mode 100644 index 00000000..1799f030 --- /dev/null +++ b/src/ctype/toupper.c @@ -0,0 +1,7 @@ +#include <ctype.h> + +int toupper(int c) +{ +	if (islower(c)) return c & 0x5f; +	return c; +} diff --git a/src/ctype/towctrans.c b/src/ctype/towctrans.c new file mode 100644 index 00000000..0b1eed04 --- /dev/null +++ b/src/ctype/towctrans.c @@ -0,0 +1,246 @@ +#include <wchar.h> +#include <wctype.h> +#include <stdio.h> + +#define CASEMAP(u1,u2,l) { (u1), (l)-(u1), (u2)-(u1)+1 } +#define CASELACE(u1,u2) CASEMAP((u1),(u2),(u1)+1) + +static const struct { +	unsigned short upper; +	signed char lower; +	unsigned char len; +} casemaps[] = { +	CASEMAP('A','Z','a'), +	CASEMAP(0xc0,0xde,0xe0), + +	CASELACE(0x0100,0x012e), +	CASELACE(0x0132,0x0136), +	CASELACE(0x0139,0x0147), +	CASELACE(0x014a,0x0176), +	CASELACE(0x0179,0x017d), + +	CASELACE(0x370,0x372), +	CASEMAP(0x391,0x3a1,0x3b1), +	CASEMAP(0x3a3,0x3ab,0x3c3), +	CASEMAP(0x400,0x40f,0x450), +	CASEMAP(0x410,0x42f,0x430), + +	CASELACE(0x460,0x480), +	CASELACE(0x48a,0x4be), +	CASELACE(0x4c1,0x4cd), +	CASELACE(0x4d0,0x50e), + +	CASEMAP(0x531,0x556,0x561), + +	CASELACE(0x01a0,0x01a4), +	CASELACE(0x01b3,0x01b5), +	CASELACE(0x01cd,0x01db), +	CASELACE(0x01de,0x01ee), +	CASELACE(0x01f8,0x021e), +	CASELACE(0x0222,0x0232), +	CASELACE(0x03d8,0x03ee), + +	CASELACE(0x1e00,0x1e94), +	CASELACE(0x1ea0,0x1efe), + +	CASEMAP(0x1f08,0x1f0f,0x1f00), +	CASEMAP(0x1f18,0x1f1d,0x1f10), +	CASEMAP(0x1f28,0x1f2f,0x1f20), +	CASEMAP(0x1f38,0x1f3f,0x1f30), +	CASEMAP(0x1f48,0x1f4d,0x1f40), + +	CASEMAP(0x1f68,0x1f6f,0x1f60), +	CASEMAP(0x1f88,0x1f8f,0x1f80), +	CASEMAP(0x1f98,0x1f9f,0x1f90), +	CASEMAP(0x1fa8,0x1faf,0x1fa0), +	CASEMAP(0x1fb8,0x1fb9,0x1fb0), +	CASEMAP(0x1fba,0x1fbb,0x1f70), +	CASEMAP(0x1fc8,0x1fcb,0x1f72), +	CASEMAP(0x1fd8,0x1fd9,0x1fd0), +	CASEMAP(0x1fda,0x1fdb,0x1f76), +	CASEMAP(0x1fe8,0x1fe9,0x1fe0), +	CASEMAP(0x1fea,0x1feb,0x1f7a), +	CASEMAP(0x1ff8,0x1ff9,0x1f78), +	CASEMAP(0x1ffa,0x1ffb,0x1f7c), + +	CASELACE(0x246,0x24e), +	CASELACE(0x510,0x512), +	CASEMAP(0x2160,0x216f,0x2170), +	CASEMAP(0x2c00,0x2c2e,0x2c30), +	CASELACE(0x2c67,0x2c6b), +	CASELACE(0x2c80,0x2ce2), + +	CASELACE(0xa722,0xa72e), +	CASELACE(0xa732,0xa76e), +	CASELACE(0xa779,0xa77b), +	CASELACE(0xa77e,0xa786), + +	CASEMAP(0xff21,0xff3a,0xff41), +	{ 0,0,0 } +}; + +static const unsigned short pairs[][2] = { +	{ 'I',    0x0131 }, +	{ 'S',    0x017f }, +	{ 0x0130, 'i'    }, +	{ 0x0178, 0x00ff }, +	{ 0x0181, 0x0253 }, +	{ 0x0182, 0x0183 }, +	{ 0x0184, 0x0185 }, +	{ 0x0186, 0x0254 }, +	{ 0x0187, 0x0188 }, +	{ 0x0189, 0x0256 }, +	{ 0x018a, 0x0257 }, +	{ 0x018b, 0x018c }, +	{ 0x018e, 0x01dd }, +	{ 0x018f, 0x0259 }, +	{ 0x0190, 0x025b }, +	{ 0x0191, 0x0192 }, +	{ 0x0193, 0x0260 }, +	{ 0x0194, 0x0263 }, +	{ 0x0196, 0x0269 }, +	{ 0x0197, 0x0268 }, +	{ 0x0198, 0x0199 }, +	{ 0x019c, 0x026f }, +	{ 0x019d, 0x0272 }, +	{ 0x019f, 0x0275 }, +	{ 0x01a6, 0x0280 }, +	{ 0x01a7, 0x01a8 }, +	{ 0x01a9, 0x0283 }, +	{ 0x01ac, 0x01ad }, +	{ 0x01ae, 0x0288 }, +	{ 0x01af, 0x01b0 }, +	{ 0x01b1, 0x028a }, +	{ 0x01b2, 0x028b }, +	{ 0x01b7, 0x0292 }, +	{ 0x01b8, 0x01b9 }, +	{ 0x01bc, 0x01bd }, +	{ 0x01c4, 0x01c6 }, +	{ 0x01c4, 0x01c5 }, +	{ 0x01c5, 0x01c6 }, +	{ 0x01c7, 0x01c9 }, +	{ 0x01c7, 0x01c8 }, +	{ 0x01c8, 0x01c9 }, +	{ 0x01ca, 0x01cc }, +	{ 0x01ca, 0x01cb }, +	{ 0x01cb, 0x01cc }, +	{ 0x01f1, 0x01f3 }, +	{ 0x01f1, 0x01f2 }, +	{ 0x01f2, 0x01f3 }, +	{ 0x01f4, 0x01f5 }, +	{ 0x01f6, 0x0195 }, +	{ 0x01f7, 0x01bf }, +	{ 0x0220, 0x019e }, +	{ 0x0386, 0x03ac }, +	{ 0x0388, 0x03ad }, +	{ 0x0389, 0x03ae }, +	{ 0x038a, 0x03af }, +	{ 0x038c, 0x03cc }, +	{ 0x038e, 0x03cd }, +	{ 0x038f, 0x03ce }, +	{ 0x0399, 0x0345 }, +	{ 0x0399, 0x1fbe }, +	{ 0x03a3, 0x03c2 }, +	{ 0x03f7, 0x03f8 }, +	{ 0x03fa, 0x03fb }, +	{ 0x1e60, 0x1e9b }, + +	{ 0x1f59, 0x1f51 }, +	{ 0x1f5b, 0x1f53 }, +	{ 0x1f5d, 0x1f55 }, +	{ 0x1f5f, 0x1f57 }, +	{ 0x1fbc, 0x1fb3 }, +	{ 0x1fcc, 0x1fc3 }, +	{ 0x1fec, 0x1fe5 }, +	{ 0x1ffc, 0x1ff3 }, + +	{ 0x23a, 0x2c65 }, +	{ 0x23b, 0x23c }, +	{ 0x23d, 0x19a }, +	{ 0x23e, 0x2c66 }, +	{ 0x241, 0x242 }, +	{ 0x243, 0x180 }, +	{ 0x244, 0x289 }, +	{ 0x245, 0x28c }, +	{ 0x3f4, 0x3b8 }, +	{ 0x3f9, 0x3f2 }, +	{ 0x3fd, 0x37b }, +	{ 0x3fe, 0x37c }, +	{ 0x3ff, 0x37d }, +	{ 0x4c0, 0x4cf }, + +	{ 0x2126, 0x3c9 }, +	{ 0x212a, 'k' }, +	{ 0x212b, 0xe5 }, +	{ 0x2132, 0x214e }, +	{ 0x2183, 0x2184 }, +	{ 0x2c60, 0x2c61 }, +	{ 0x2c62, 0x26b }, +	{ 0x2c63, 0x1d7d }, +	{ 0x2c64, 0x27d }, +	{ 0x2c6d, 0x251 }, +	{ 0x2c6e, 0x271 }, +	{ 0x2c6f, 0x250 }, +	{ 0x2c72, 0x2c73 }, +	{ 0x2c75, 0x2c76 }, + +	{ 0xa77d, 0x1d79 }, + +	/* bogus greek 'symbol' letters */ +	{ 0x376, 0x377 }, +	{ 0x39c, 0xb5 }, +	{ 0x392, 0x3d0 }, +	{ 0x398, 0x3d1 }, +	{ 0x3a6, 0x3d5 }, +	{ 0x3a0, 0x3d6 }, +	{ 0x39a, 0x3f0 }, +	{ 0x3a1, 0x3f1 }, +	{ 0x395, 0x3f5 }, +	{ 0x3cf, 0x3d7 }, + +	{ 0,0 } +}; + + +static wchar_t __towcase(wchar_t wc, int lower) +{ +	int i; +	int lmul = 2*lower-1; +	int lmask = lower-1; +	if ((unsigned)wc - 0x10400 < 0x50) +		return wc + lmul*0x28; +	/* no letters with case in these large ranges */ +	if (!iswalpha(wc) +	 || (unsigned)wc - 0x0600 <= 0x0fff-0x0600 +	 || (unsigned)wc - 0x2e00 <= 0xa6ff-0x2e00 +	 || (unsigned)wc - 0xa800 <= 0xfeff-0xa800) +		return wc; +	/* special case because the diff between upper/lower is too big */ +	if ((unsigned)wc - 0x10a0 < 0x26 || (unsigned)wc - 0x2d00 < 0x26) +		return wc + lmul*(0x2d00-0x10a0); +	for (i=0; casemaps[i].len; i++) { +		int base = casemaps[i].upper + (lmask & casemaps[i].lower); +		if ((unsigned)wc-base < casemaps[i].len) { +			if (casemaps[i].lower == 1) +				return wc + lower - ((wc-casemaps[i].upper)&1); +			return wc + lmul*casemaps[i].lower; +		} +	} +	for (i=0; pairs[i][1-lower]; i++) { +		if (pairs[i][1-lower] == wc) +			return pairs[i][lower]; +	} +	if ((unsigned)wc - 0x10428 + (lower<<5) + (lower<<3) < 0x28) +		return wc - 0x28 + (lower<<10) + (lower<<6); +	return wc; +} + +wint_t towupper(wint_t wc) +{ +	return __towcase(wc, 0); +} + +wint_t towlower(wint_t wc) +{ +	return __towcase(wc, 1); +} diff --git a/src/ctype/wcswidth.c b/src/ctype/wcswidth.c new file mode 100644 index 00000000..5c8a5a4d --- /dev/null +++ b/src/ctype/wcswidth.c @@ -0,0 +1,8 @@ +#include <wchar.h> + +int wcswidth(const wchar_t *wcs, size_t n) +{ +	int l=0, k=0; +	for (; n-- && *wcs && (k = wcwidth(*wcs)) >= 0; l+=k, wcs++); +	return (k < 0) ? k : l; +} diff --git a/src/ctype/wctrans.c b/src/ctype/wctrans.c new file mode 100644 index 00000000..03e9fd6a --- /dev/null +++ b/src/ctype/wctrans.c @@ -0,0 +1,16 @@ +#include <wctype.h> +#include <string.h> + +wctrans_t wctrans(const char *class) +{ +	if (!strcmp(class, "toupper")) return 1; +	if (!strcmp(class, "tolower")) return 2; +	return 0; +} + +wint_t towctrans(wint_t wc, wctrans_t trans) +{ +	if (trans == 1) return towupper(wc); +	if (trans == 2) return towlower(wc); +	return wc; +} diff --git a/src/ctype/wcwidth.c b/src/ctype/wcwidth.c new file mode 100644 index 00000000..ebc560a5 --- /dev/null +++ b/src/ctype/wcwidth.c @@ -0,0 +1,185 @@ +#include <inttypes.h> +#include <wchar.h> + +#define R(a,b,w) { (b), (w)/2, (b)-(a) } + +static const struct range { +	uint32_t base:20; +	uint32_t width:1; +	uint32_t len:11; +} ranges[] = { +	R(0x0300, 0x036F, 0), +	R(0x0483, 0x0486, 0), +	R(0x0488, 0x0489, 0), +	R(0x0591, 0x05BD, 0), +	R(0x05BF, 0x05BF, 0), +	R(0x05C1, 0x05C2, 0), +	R(0x05C4, 0x05C5, 0), +	R(0x05C7, 0x05C7, 0), +	R(0x0600, 0x0603, 0), +	R(0x0610, 0x0615, 0), +	R(0x064B, 0x065E, 0), +	R(0x0670, 0x0670, 0), +	R(0x06D6, 0x06E4, 0), +	R(0x06E7, 0x06E8, 0), +	R(0x06EA, 0x06ED, 0), +	R(0x070F, 0x070F, 0), +	R(0x0711, 0x0711, 0), +	R(0x0730, 0x074A, 0), +	R(0x07A6, 0x07B0, 0), +	R(0x07EB, 0x07F3, 0), +	R(0x0901, 0x0902, 0), +	R(0x093C, 0x093C, 0), +	R(0x0941, 0x0948, 0), +	R(0x094D, 0x094D, 0), +	R(0x0951, 0x0954, 0), +	R(0x0962, 0x0963, 0), +	R(0x0981, 0x0981, 0), +	R(0x09BC, 0x09BC, 0), +	R(0x09C1, 0x09C4, 0), +	R(0x09CD, 0x09CD, 0), +	R(0x09E2, 0x09E3, 0), +	R(0x0A01, 0x0A02, 0), +	R(0x0A3C, 0x0A3C, 0), +	R(0x0A41, 0x0A42, 0), +	R(0x0A47, 0x0A48, 0), +	R(0x0A4B, 0x0A4D, 0), +	R(0x0A70, 0x0A71, 0), +	R(0x0A81, 0x0A82, 0), +	R(0x0ABC, 0x0ABC, 0), +	R(0x0AC1, 0x0AC5, 0), +	R(0x0AC7, 0x0AC8, 0), +	R(0x0ACD, 0x0ACD, 0), +	R(0x0AE2, 0x0AE3, 0), +	R(0x0B01, 0x0B01, 0), +	R(0x0B3C, 0x0B3C, 0), +	R(0x0B3F, 0x0B3F, 0), +	R(0x0B41, 0x0B43, 0), +	R(0x0B4D, 0x0B4D, 0), +	R(0x0B56, 0x0B56, 0), +	R(0x0B82, 0x0B82, 0), +	R(0x0BC0, 0x0BC0, 0), +	R(0x0BCD, 0x0BCD, 0), +	R(0x0C3E, 0x0C40, 0), +	R(0x0C46, 0x0C48, 0), +	R(0x0C4A, 0x0C4D, 0), +	R(0x0C55, 0x0C56, 0), +	R(0x0CBC, 0x0CBC, 0), +	R(0x0CBF, 0x0CBF, 0), +	R(0x0CC6, 0x0CC6, 0), +	R(0x0CCC, 0x0CCD, 0), +	R(0x0CE2, 0x0CE3, 0), +	R(0x0D41, 0x0D43, 0), +	R(0x0D4D, 0x0D4D, 0), +	R(0x0DCA, 0x0DCA, 0), +	R(0x0DD2, 0x0DD4, 0), +	R(0x0DD6, 0x0DD6, 0), +	R(0x0E31, 0x0E31, 0), +	R(0x0E34, 0x0E3A, 0), +	R(0x0E47, 0x0E4E, 0), +	R(0x0EB1, 0x0EB1, 0), +	R(0x0EB4, 0x0EB9, 0), +	R(0x0EBB, 0x0EBC, 0), +	R(0x0EC8, 0x0ECD, 0), +	R(0x0F18, 0x0F19, 0), +	R(0x0F35, 0x0F35, 0), +	R(0x0F37, 0x0F37, 0), +	R(0x0F39, 0x0F39, 0), +	R(0x0F71, 0x0F7E, 0), +	R(0x0F80, 0x0F84, 0), +	R(0x0F86, 0x0F87, 0), +	R(0x0F90, 0x0F97, 0), +	R(0x0F99, 0x0FBC, 0), +	R(0x0FC6, 0x0FC6, 0), +	R(0x102D, 0x1030, 0), +	R(0x1032, 0x1032, 0), +	R(0x1036, 0x1037, 0), +	R(0x1039, 0x1039, 0), +	R(0x1058, 0x1059, 0), +	R(0x1100, 0x115F, 2), +	R(0x1160, 0x11FF, 0), +	R(0x135F, 0x135F, 0), +	R(0x1712, 0x1714, 0), +	R(0x1732, 0x1734, 0), +	R(0x1752, 0x1753, 0), +	R(0x1772, 0x1773, 0), +	R(0x17B4, 0x17B5, 0), +	R(0x17B7, 0x17BD, 0), +	R(0x17C6, 0x17C6, 0), +	R(0x17C9, 0x17D3, 0), +	R(0x17DD, 0x17DD, 0), +	R(0x180B, 0x180D, 0), +	R(0x18A9, 0x18A9, 0), +	R(0x1920, 0x1922, 0), +	R(0x1927, 0x1928, 0), +	R(0x1932, 0x1932, 0), +	R(0x1939, 0x193B, 0), +	R(0x1A17, 0x1A18, 0), +	R(0x1B00, 0x1B03, 0), +	R(0x1B34, 0x1B34, 0), +	R(0x1B36, 0x1B3A, 0), +	R(0x1B3C, 0x1B3C, 0), +	R(0x1B42, 0x1B42, 0), +	R(0x1B6B, 0x1B73, 0), +	R(0x1DC0, 0x1DCA, 0), +	R(0x1DFE, 0x1DFF, 0), +	R(0x200B, 0x200F, 0), +	R(0x202A, 0x202E, 0), +	R(0x2060, 0x2063, 0), +	R(0x206A, 0x206F, 0), +	R(0x20D0, 0x20EF, 0), +	R(0x2329, 0x232A, 2), +	R(0x2E80, 0x3029, 2), +	R(0x302A, 0x302F, 0), +	R(0x3030, 0x303E, 2), +	R(0x3099, 0x309A, 0), +	R(0xA806, 0xA806, 0), +	R(0xA80B, 0xA80B, 0), +	R(0xA825, 0xA826, 0), +	R(0xF900, 0xFAFF, 2), +	R(0xFB1E, 0xFB1E, 0), +	R(0xFE00, 0xFE0F, 0), +	R(0xFE20, 0xFE23, 0), +	R(0xFE30, 0xFE6F, 2), +	R(0xFEFF, 0xFEFF, 0), +	R(0xFF00, 0xFF60, 2), +	R(0xFFE0, 0xFFE6, 2), +	R(0x10A01, 0x10A03, 0), +	R(0x10A05, 0x10A06, 0), +	R(0x10A0C, 0x10A0F, 0), +	R(0x10A38, 0x10A3A, 0), +	R(0x10A3F, 0x10A3F, 0), +	R(0x1D167, 0x1D169, 0), +	R(0x1D173, 0x1D182, 0), +	R(0x1D185, 0x1D18B, 0), +	R(0x1D1AA, 0x1D1AD, 0), +	R(0x1D242, 0x1D244, 0), +	R(0xE0001, 0xE0001, 0), +	R(0xE0020, 0xE007F, 0), +	R(0xE0100, 0xE01EF, 0), +}; + +/* Note: because the len field is only 10 bits, we must special-case + * the two huge ranges of full width characters and exclude them + * from the binary search table. */ + +int wcwidth(wchar_t wc) +{ +	int a, n; +	uint32_t c = wc; + +	if (c-0x20 < 0x5f) return 1; +	if (!iswprint(c)) return wc ? -1 : 0; +	if (c-0x20000 < 0x20000) return 2; + +	/* The following code is a branchless binary search. */ +	a = 0; +	n = sizeof ranges / sizeof ranges[0]; +	do { +		n >>= 1; +		a += n+1 & (signed)(ranges[a+n].base-c)>>31; +	} while (n); +	if (ranges[a].base-c <= ranges[a].len) +		return 2*ranges[a].width; +	return 1 + (c-0x3040 < 0xd800-0x3040); +} diff --git a/src/dirent/__dirent.h b/src/dirent/__dirent.h new file mode 100644 index 00000000..07b3ee68 --- /dev/null +++ b/src/dirent/__dirent.h @@ -0,0 +1,9 @@ +struct __DIR_s +{ +	int lock; +	int fd; +	off_t tell; +	int buf_pos; +	int buf_end; +	char buf[2048]; +}; diff --git a/src/dirent/__getdents.c b/src/dirent/__getdents.c new file mode 100644 index 00000000..4195430b --- /dev/null +++ b/src/dirent/__getdents.c @@ -0,0 +1,12 @@ +#include <dirent.h> +#include "syscall.h" +#include "libc.h" + +int __getdents(int fd, struct dirent *buf, size_t len) +{ +	return syscall3(__NR_getdents64, fd, (long)buf, len); +} + +weak_alias(__getdents, getdents); + +LFS64(getdents); diff --git a/src/dirent/alphasort.c b/src/dirent/alphasort.c new file mode 100644 index 00000000..42050fb7 --- /dev/null +++ b/src/dirent/alphasort.c @@ -0,0 +1,10 @@ +#include <string.h> +#include <dirent.h> +#include "libc.h" + +int alphasort(const struct dirent **a, const struct dirent **b) +{ +	return strcoll((*a)->d_name, (*b)->d_name); +} + +LFS64(alphasort); diff --git a/src/dirent/closedir.c b/src/dirent/closedir.c new file mode 100644 index 00000000..81e9591c --- /dev/null +++ b/src/dirent/closedir.c @@ -0,0 +1,11 @@ +#include <dirent.h> +#include <unistd.h> +#include "__dirent.h" +#include "libc.h" + +int closedir(DIR *dir) +{ +	int ret = close(dir->fd); +	free(dir); +	return ret; +} diff --git a/src/dirent/dirfd.c b/src/dirent/dirfd.c new file mode 100644 index 00000000..6c860073 --- /dev/null +++ b/src/dirent/dirfd.c @@ -0,0 +1,7 @@ +#include <dirent.h> +#include "__dirent.h" + +int dirfd(DIR *d) +{ +	return d->fd; +} diff --git a/src/dirent/fdopendir.c b/src/dirent/fdopendir.c new file mode 100644 index 00000000..c4b8e61d --- /dev/null +++ b/src/dirent/fdopendir.c @@ -0,0 +1,26 @@ +#include <dirent.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include "__dirent.h" + +DIR *fdopendir(int fd) +{ +	DIR *dir; +	struct stat st; + +	if (fstat(fd, &st) < 0 || !S_ISDIR(st.st_mode)) { +		errno = ENOTDIR; +		return 0; +	} +	if (!(dir = calloc(1, sizeof *dir))) { +		return 0; +	} + +	fcntl(fd, F_SETFD, FD_CLOEXEC); +	dir->fd = fd; +	return dir; +} diff --git a/src/dirent/opendir.c b/src/dirent/opendir.c new file mode 100644 index 00000000..cefe6ce7 --- /dev/null +++ b/src/dirent/opendir.c @@ -0,0 +1,25 @@ +#define _GNU_SOURCE +#include <dirent.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include "__dirent.h" + +DIR *opendir(const char *name) +{ +	int fd; +	DIR *dir; + +	if ((fd = open(name, O_RDONLY|O_DIRECTORY)) < 0) +		return 0; +	fcntl(fd, F_SETFD, FD_CLOEXEC); +	if (!(dir = calloc(1, sizeof *dir))) { +		close(fd); +		return 0; +	} +	dir->fd = fd; +	return dir; +} diff --git a/src/dirent/readdir.c b/src/dirent/readdir.c new file mode 100644 index 00000000..1aeb25a5 --- /dev/null +++ b/src/dirent/readdir.c @@ -0,0 +1,32 @@ +#include <dirent.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdlib.h> +#include <limits.h> +#include "__dirent.h" +#include "syscall.h" +#include "libc.h" + +int __getdents(int, struct dirent *, size_t); + +struct dirent *readdir(DIR *dir) +{ +	struct dirent *de; +	 +	if (dir->buf_pos >= dir->buf_end) { +		int len = __getdents(dir->fd, (void *)dir->buf, sizeof dir->buf); +		if (len < 0) { +			dir->lock = 0; +			return NULL; +		} else if (len == 0) return 0; +		dir->buf_end = len; +		dir->buf_pos = 0; +	} +	de = (void *)(dir->buf + dir->buf_pos); +	dir->buf_pos += de->d_reclen; +	dir->tell = de->d_off; +	return de; +} + +LFS64(readdir); diff --git a/src/dirent/readdir_r.c b/src/dirent/readdir_r.c new file mode 100644 index 00000000..58f60325 --- /dev/null +++ b/src/dirent/readdir_r.c @@ -0,0 +1,30 @@ +#include <dirent.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include "__dirent.h" +#include "libc.h" + +int readdir_r(DIR *dir, struct dirent *buf, struct dirent **result) +{ +	struct dirent *de; +	int errno_save = errno; +	int ret; +	 +	LOCK(&dir->lock); +	errno = 0; +	de = readdir(dir); +	if ((ret = errno)) { +		UNLOCK(&dir->lock); +		return ret; +	} +	errno = errno_save; +	if (de) memcpy(buf, de, de->d_reclen); +	else buf = NULL; + +	UNLOCK(&dir->lock); +	*result = buf; +	return 0; +} + +LFS64_2(readdir_r, readdir64_r); diff --git a/src/dirent/rewinddir.c b/src/dirent/rewinddir.c new file mode 100644 index 00000000..c6138f7c --- /dev/null +++ b/src/dirent/rewinddir.c @@ -0,0 +1,13 @@ +#include <dirent.h> +#include <unistd.h> +#include "__dirent.h" +#include "libc.h" + +void rewinddir(DIR *dir) +{ +	LOCK(&dir->lock); +	lseek(dir->fd, 0, SEEK_SET); +	dir->buf_pos = dir->buf_end = 0; +	dir->tell = 0; +	UNLOCK(&dir->lock); +} diff --git a/src/dirent/scandir.c b/src/dirent/scandir.c new file mode 100644 index 00000000..6a0a9993 --- /dev/null +++ b/src/dirent/scandir.c @@ -0,0 +1,50 @@ +#include <dirent.h> +#include <string.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <stddef.h> +#include <libc.h> + +int scandir(const char *path, struct dirent ***res, +	int (*sel)(const struct dirent *), +	int (*cmp)(const struct dirent **, const struct dirent **)) +{ +	DIR *d = opendir(path); +	struct dirent *de, **names=0, **tmp; +	size_t cnt=0, len=0, size; +	int old_errno = errno; + +	if (!d) return -1; + +	while ((errno=0), (de = readdir(d))) { +		if (sel && !sel(de)) continue; +		if (cnt >= len) { +			len = 2*len+1; +			if (len > SIZE_MAX/sizeof *names) break; +			tmp = realloc(names, len * sizeof *names); +			if (!tmp) break; +			names = tmp; +		} +		size = offsetof(struct dirent,d_name) + strlen(de->d_name) + 1; +		names[cnt] = malloc(size); +		if (!names[cnt]) break; +		memcpy(names[cnt++], de, size); +	} + +	closedir(d); + +	if (errno) { +		old_errno = errno; +		if (names) while (cnt-->0) free(names[cnt]); +		free(names); +		errno = old_errno; +		return -1; +	} + +	if (cmp) qsort(names, cnt, sizeof *names, (int (*)(const void *, const void *))cmp); +	*res = names; +	return cnt; +} + +LFS64(scandir); diff --git a/src/dirent/seekdir.c b/src/dirent/seekdir.c new file mode 100644 index 00000000..81a0e331 --- /dev/null +++ b/src/dirent/seekdir.c @@ -0,0 +1,12 @@ +#include <dirent.h> +#include <unistd.h> +#include "__dirent.h" +#include "libc.h" + +void seekdir(DIR *dir, long off) +{ +	LOCK(&dir->lock); +	dir->tell = lseek(dir->fd, off, SEEK_SET); +	dir->buf_pos = dir->buf_end = 0; +	UNLOCK(&dir->lock); +} diff --git a/src/dirent/telldir.c b/src/dirent/telldir.c new file mode 100644 index 00000000..cf25acff --- /dev/null +++ b/src/dirent/telldir.c @@ -0,0 +1,7 @@ +#include <dirent.h> +#include "__dirent.h" + +long telldir(DIR *dir) +{ +	return dir->tell; +} diff --git a/src/env/__environ.c b/src/env/__environ.c new file mode 100644 index 00000000..d7bd5e50 --- /dev/null +++ b/src/env/__environ.c @@ -0,0 +1,7 @@ +#include "libc.h" + +#undef environ +char **___environ = 0; +weak_alias(___environ, __environ); +weak_alias(___environ, _environ); +weak_alias(___environ, environ); diff --git a/src/env/__libc_start_main.c b/src/env/__libc_start_main.c new file mode 100644 index 00000000..70af77b5 --- /dev/null +++ b/src/env/__libc_start_main.c @@ -0,0 +1,26 @@ +#include "libc.h" + +/* Any use of __environ/environ will override this symbol. */ +char **__dummy_environ = (void *)-1; +weak_alias(__dummy_environ, ___environ); + +int __libc_start_main( +	int (*main)(int, char **, char **), int argc, char **argv, +	int (*init)(int, char **, char **), void (*fini)(void), +	void (*ldso_fini)(void)) +{ +	/* Save the environment if it may be used by libc/application */ +	char **envp = argv+argc+1; +	if (___environ != (void *)-1) ___environ = envp; + +	/* Avoid writing 0 and triggering unnecessary COW */ +	if (ldso_fini) libc.ldso_fini = ldso_fini; +	if (fini) libc.fini = fini; + +	/* Execute constructors (static) linked into the application */ +	if (init) init(argc, argv, envp); + +	/* Pass control to to application */ +	exit(main(argc, argv, envp)); +	return 0; +} diff --git a/src/env/clearenv.c b/src/env/clearenv.c new file mode 100644 index 00000000..a2475ce7 --- /dev/null +++ b/src/env/clearenv.c @@ -0,0 +1,9 @@ +#include <stdlib.h> + +extern char **__environ; + +int clearenv() +{ +	__environ[0] = 0; +	return 0; +} diff --git a/src/env/getenv.c b/src/env/getenv.c new file mode 100644 index 00000000..00c1bce0 --- /dev/null +++ b/src/env/getenv.c @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include <string.h> +#include "libc.h" + +char *getenv(const char *name) +{ +	int i; +	size_t l = strlen(name); +	if (!__environ || !*name || strchr(name, '=')) return NULL; +	for (i=0; __environ[i] && (strncmp(name, __environ[i], l) +		|| __environ[i][l] != '='); i++); +	if (__environ[i]) return __environ[i] + l+1; +	return NULL; +} diff --git a/src/env/putenv.c b/src/env/putenv.c new file mode 100644 index 00000000..181a4181 --- /dev/null +++ b/src/env/putenv.c @@ -0,0 +1,59 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> + +extern char **__environ; +char **__env_map; + +int __putenv(char *s, int a) +{ +	int i=0, j=0; +	char *end = strchr(s, '='); +	size_t l = end-s+1; +	char **newenv = 0; +	char **newmap = 0; +	static char **oldenv; +	 +	if (!end || l == 1) return -1; +	for (; __environ[i] && memcmp(s, __environ[i], l); i++); +	if (a) { +		if (!__env_map) { +			__env_map = calloc(2, sizeof(char *)); +			if (__env_map) __env_map[0] = s; +		} else { +			for (; __env_map[j] && __env_map[j] != __environ[i]; j++); +			if (!__env_map[j]) { +				newmap = realloc(__env_map, sizeof(char *)*(j+2)); +				if (newmap) { +					__env_map = newmap; +					__env_map[j] = s; +					__env_map[j+1] = NULL; +				} +			} else { +				free(__env_map[j]); +			} +		} +	} +	if (!__environ[i]) { +		newenv = malloc(sizeof(char *)*(i+2)); +		if (!newenv) { +			if (a && __env_map) __env_map[j] = 0; +			return -1; +		} +		memcpy(newenv, __environ, sizeof(char *)*i); +		newenv[i] = s; +		newenv[i+1] = 0; +		__environ = newenv; +		free(oldenv); +		oldenv = __environ; +	} + +	__environ[i] = s; +	return 0; +} + +int putenv(char *s) +{ +	return __putenv(s, 0); +} diff --git a/src/env/setenv.c b/src/env/setenv.c new file mode 100644 index 00000000..03e165c8 --- /dev/null +++ b/src/env/setenv.c @@ -0,0 +1,31 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +int __putenv(char *s, int a); + +int setenv(const char *var, const char *value, int overwrite) +{ +	char *s; +	int l1, l2; + +	if (strchr(var, '=')) { +		errno = EINVAL; +		return -1; +	} +	if (!overwrite && getenv(var)) return 0; + +	l1 = strlen(var); +	l2 = strlen(value); +	s = malloc(l1+l2+2); +	memcpy(s, var, l1); +	s[l1] = '='; +	memcpy(s+l1+1, value, l2); +	s[l1+l2+1] = 0; +	if (__putenv(s, 1)) { +		free(s); +		errno = ENOMEM; +		return -1; +	} +	return 0; +} diff --git a/src/env/unsetenv.c b/src/env/unsetenv.c new file mode 100644 index 00000000..7493d970 --- /dev/null +++ b/src/env/unsetenv.c @@ -0,0 +1,32 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +extern char **__environ; +extern char **__env_map; + +int unsetenv(const char *name) +{ +	int i, j; +	size_t l = strlen(name); + +	if (!*name || strchr(name, '=')) { +		errno = EINVAL; +		return -1; +	} +again: +	for (i=0; __environ[i] && (memcmp(name, __environ[i], l) || __environ[i][l] != '='); i++); +	if (__environ[i]) { +		if (__env_map) { +			for (j=0; __env_map[j] && __env_map[j] != __environ[i]; j++); +			free (__env_map[j]); +			for (; __env_map[j]; j++) +				__env_map[j] = __env_map[j+1]; +		} +		for (; __environ[i]; i++) +			__environ[i] = __environ[i+1]; +		goto again; +	} +	return 0; +} diff --git a/src/errno/__errno_location.c b/src/errno/__errno_location.c new file mode 100644 index 00000000..0a220b63 --- /dev/null +++ b/src/errno/__errno_location.c @@ -0,0 +1,11 @@ +#include <errno.h> +#include "libc.h" + +#undef errno +int errno; + +int *__errno_location(void) +{ +	if (libc.errno_location) return libc.errno_location(); +	return &errno; +} diff --git a/src/errno/__strerror.h b/src/errno/__strerror.h new file mode 100644 index 00000000..00eaf938 --- /dev/null +++ b/src/errno/__strerror.h @@ -0,0 +1,101 @@ +/* This file is sorted such that 'errors' which represent exceptional + * conditions under which a correct program may fail come first, followed + * by messages that indicate an incorrect program or system failure. The + * macro E() along with double-inclusion is used to ensure that ordering + * of the strings remains synchronized. */ + +E(EILSEQ,       "Illegal byte sequence") +E(EDOM,         "Argument outside domain") +E(ERANGE,       "Result not representable") + +E(ENOTTY,       "Not a tty") +E(EACCES,       "Permission denied") +E(EPERM,        "Operation not permitted") +E(ENOENT,       "No such file or directory") +E(ESRCH,        "No such process") +E(EEXIST,       "File exists") + +E(EOVERFLOW,    "Value too large for defined data type") +E(ENOSPC,       "No space left on device") +E(ENOMEM,       "Out of memory") + +E(EBUSY,        "Device or resource busy") +E(EINTR,        "Interrupted system call") +E(EAGAIN,       "Operation would block") +E(ESPIPE,       "Illegal seek") + +E(EXDEV,        "Cross-device link") +E(EROFS,        "Read-only file system") +E(ENOTEMPTY,    "Directory not empty") + +E(ECONNRESET,   "Connection reset by peer") +E(ETIMEDOUT,    "Connection timed out") +E(ECONNREFUSED, "Connection refused") +E(EHOSTDOWN,    "Host is down") +E(EHOSTUNREACH, "No route to host") +E(EADDRINUSE,   "Address already in use") + +E(EPIPE,        "Broken pipe") +E(EIO,          "I/O error") +E(ENXIO,        "No such device or address") +E(ENOTBLK,      "Block device required") +E(ENODEV,       "No such device") +E(ENOTDIR,      "Not a directory") +E(EISDIR,       "Is a directory") +E(ETXTBSY,      "Text file busy") +E(ENOEXEC,      "Exec format error") + +E(EINVAL,       "Invalid argument") + +E(E2BIG,        "Argument list too long") +E(ELOOP,        "Too many levels of symbolic links") +E(ENAMETOOLONG, "Filename too long") +E(ENFILE,       "File table overflow") +E(EMFILE,       "Too many open files") +E(EBADF,        "Bad file number") +E(ECHILD,       "No child processes") +E(EFAULT,       "Bad address") +E(EFBIG,        "File too large") +E(EMLINK,       "Too many links") +E(ENOLCK,       "No record locks available") + +E(EDEADLK,      "Resource deadlock would occur") +E(ENOSYS,       "Function not supported") +E(ENOMSG,       "No message of desired type") +E(EIDRM,        "Identifier removed") +E(ENOSTR,       "Device not a stream") +E(ENODATA,      "No data available") +E(ETIME,        "Timer expired") +E(ENOSR,        "Out of streams resources") +E(ENOLINK,      "Link has been severed") +E(EPROTO,       "Protocol error") +E(EBADMSG,      "Not a data message") +E(EBADFD,       "File descriptor in bad state") +E(ENOTSOCK,     "Socket operation on non-socket") +E(EDESTADDRREQ, "Destination address required") +E(EMSGSIZE,     "Message too long") +E(EPROTOTYPE,   "Protocol wrong type for socket") +E(ENOPROTOOPT,  "Protocol not available") +E(EPROTONOSUPPORT,"Protocol not supported") +E(ESOCKTNOSUPPORT,"Socket type not supported") +E(EOPNOTSUPP,   "Operation not supported on socket") +E(EPFNOSUPPORT, "Protocol family not supported") +E(EAFNOSUPPORT, "Address family not supported by protocol") +E(EADDRNOTAVAIL,"Cannot assign requested address") +E(ENETDOWN,     "Network is down") +E(ENETUNREACH,  "Network is unreachable") +E(ENETRESET,    "Network dropped connection because of reset") +E(ECONNABORTED, "Software caused connection abort") +E(ENOBUFS,      "No buffer space available") +E(EISCONN,      "Socket is connected") +E(ENOTCONN,     "Socket is not connected") +E(ESHUTDOWN,    "Cannot send after socket shutdown") +E(EALREADY,     "Operation already in progress") +E(EINPROGRESS,  "Operation now in progress") +E(ESTALE,       "Stale NFS file handle") +E(EREMOTEIO,    "Remote I/O error") +E(EDQUOT,       "Quota exceeded") +E(ENOMEDIUM,    "No medium found") +E(EMEDIUMTYPE,  "Wrong medium type") + +E(0,            "Invalid error number") diff --git a/src/errno/strerror.c b/src/errno/strerror.c new file mode 100644 index 00000000..b8fbc6db --- /dev/null +++ b/src/errno/strerror.c @@ -0,0 +1,22 @@ +#include <errno.h> +#include <string.h> + +#define E(a,b) a, +static const unsigned char errid[] = { +#include "__strerror.h" +}; + +#undef E +#define E(a,b) b "\0" +static const char errmsg[] = +#include "__strerror.h" +; + +char *strerror(int e) +{ +	const char *s; +	int i; +	for (i=0; errid[i] && errid[i] != e; i++); +	for (s=errmsg; i; s++, i--) for (; *s; s++); +	return (char *)s; +} diff --git a/src/exit/_Exit.c b/src/exit/_Exit.c new file mode 100644 index 00000000..8ef85a8f --- /dev/null +++ b/src/exit/_Exit.c @@ -0,0 +1,9 @@ +#include <stdlib.h> +#define SYSCALL_NORETURN +#include "syscall.h" + +void _Exit(int ec) +{ +	syscall1(__NR_exit_group, ec); +	syscall1(__NR_exit, ec); +} diff --git a/src/exit/abort.c b/src/exit/abort.c new file mode 100644 index 00000000..9a1c3d40 --- /dev/null +++ b/src/exit/abort.c @@ -0,0 +1,8 @@ +#include <stdlib.h> +#include <signal.h> + +void abort(void) +{ +	raise(SIGABRT); +	for (;;); +} diff --git a/src/exit/assert.c b/src/exit/assert.c new file mode 100644 index 00000000..e87442a7 --- /dev/null +++ b/src/exit/assert.c @@ -0,0 +1,9 @@ +#include <stdio.h> +#include <stdlib.h> + +void __assert_fail(const char *expr, const char *file, int line, const char *func) +{ +	fprintf(stderr, "Assertion failed: %s (%s: %s: %d)\n", expr, file, func, line); +	fflush(NULL); +	abort(); +} diff --git a/src/exit/atexit.c b/src/exit/atexit.c new file mode 100644 index 00000000..49c060e6 --- /dev/null +++ b/src/exit/atexit.c @@ -0,0 +1,57 @@ +#include <stddef.h> +#include <stdlib.h> +#include <limits.h> +#include "libc.h" + +/* Ensure that at least 32 atexit handlers can be registered without malloc */ +#define COUNT 32 + +static struct fl +{ +	struct fl *next; +	void (*f[COUNT])(void); +} builtin, *head; + +static int run_atexit_functions(void) +{ +	int i; +	for (; head; head=head->next) { +		for (i=COUNT-1; i>=0 && !head->f[i]; i--); +		for (; i>=0; i--) head->f[i](); +	} +	return 0; +} + +int (*const __funcs_on_exit)(void) = run_atexit_functions; + +int atexit(void (*func)(void)) +{ +	static int lock; +	int i; + +	/* Hook for atexit extensions */ +	if (libc.atexit) return libc.atexit(func); + +	LOCK(&lock); + +	/* Defer initialization of head so it can be in BSS */ +	if (!head) head = &builtin; + +	/* If the current function list is full, add a new one */ +	if (head->f[COUNT-1]) { +		struct fl *new_fl = calloc(sizeof(struct fl), 1); +		if (!new_fl) { +			UNLOCK(&lock); +			return -1; +		} +		new_fl->next = head; +		head = new_fl; +	} + +	/* Append function to the list. */ +	for (i=0; i<COUNT && head->f[i]; i++); +	head->f[i] = func; + +	UNLOCK(&lock); +	return 0; +} diff --git a/src/exit/exit.c b/src/exit/exit.c new file mode 100644 index 00000000..d0c1bfc1 --- /dev/null +++ b/src/exit/exit.c @@ -0,0 +1,28 @@ +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include "libc.h" + +/* __overflow.c and atexit.c override these */ +static int (*const dummy)() = 0; +weak_alias(dummy, __funcs_on_exit); +weak_alias(dummy, __fflush_on_exit); + +void exit(int code) +{ +	static int lock; + +	/* If more than one thread calls exit, hang until _Exit ends it all */ +	LOCK(&lock); + +	/* Only do atexit & stdio flush if they were actually used */ +	if (__funcs_on_exit) __funcs_on_exit(); +	if (__fflush_on_exit) __fflush_on_exit(0); + +	/* Destructor s**t is kept separate from atexit to avoid bloat */ +	if (libc.fini) libc.fini(); +	if (libc.ldso_fini) libc.ldso_fini(); + +	_Exit(code); +	for(;;); +} diff --git a/src/fcntl/creat.c b/src/fcntl/creat.c new file mode 100644 index 00000000..be05faae --- /dev/null +++ b/src/fcntl/creat.c @@ -0,0 +1,9 @@ +#include <fcntl.h> +#include "libc.h" + +int creat(const char *filename, mode_t mode) +{ +	return open(filename, O_CREAT|O_WRONLY|O_TRUNC, mode); +} + +LFS64(creat); diff --git a/src/fcntl/fcntl.c b/src/fcntl/fcntl.c new file mode 100644 index 00000000..464dbf00 --- /dev/null +++ b/src/fcntl/fcntl.c @@ -0,0 +1,22 @@ +#include <fcntl.h> +#include <unistd.h> +#include <stdarg.h> +#include "syscall.h" +#include "libc.h" + +int fcntl(int fd, int cmd, ...) +{ +	int r; +	long arg; +	va_list ap; +	va_start(ap, cmd); +	arg = va_arg(ap, long); +	va_end(ap); +	if (cmd == F_SETFL) arg |= O_LARGEFILE; +	if (cmd == F_SETLKW) CANCELPT_BEGIN; +	r = __syscall_fcntl(fd, cmd, arg); +	if (cmd == F_SETLKW) CANCELPT_END; +	return r; +} + +LFS64(fcntl); diff --git a/src/fcntl/open.c b/src/fcntl/open.c new file mode 100644 index 00000000..4c1a591d --- /dev/null +++ b/src/fcntl/open.c @@ -0,0 +1,21 @@ +#include <fcntl.h> +#include <unistd.h> +#include <stdarg.h> +#include "syscall.h" +#include "libc.h" + +int open(const char *filename, int flags, ...) +{ +	int r; +	mode_t mode; +	va_list ap; +	va_start(ap, flags); +	mode = va_arg(ap, mode_t); +	va_end(ap); +	CANCELPT_BEGIN; +	r = __syscall_open(filename, flags, mode); +	CANCELPT_END; +	return r; +} + +LFS64(open); diff --git a/src/fcntl/openat.c b/src/fcntl/openat.c new file mode 100644 index 00000000..eefa0901 --- /dev/null +++ b/src/fcntl/openat.c @@ -0,0 +1,21 @@ +#include <fcntl.h> +#include <unistd.h> +#include <stdarg.h> +#include "syscall.h" +#include "libc.h" + +int openat(int fd, const char *filename, int flags, ...) +{ +	int r; +	mode_t mode; +	va_list ap; +	va_start(ap, flags); +	mode = va_arg(ap, mode_t); +	va_end(ap); +	CANCELPT_BEGIN; +	r = syscall4(__NR_openat, fd, (long)filename, flags|O_LARGEFILE, mode); +	CANCELPT_END; +	return r; +} + +LFS64(openat); diff --git a/src/internal/atomic.h b/src/internal/atomic.h new file mode 100644 index 00000000..a15f8c2a --- /dev/null +++ b/src/internal/atomic.h @@ -0,0 +1,110 @@ +#ifndef _INTERNAA_ATOMIC_H +#define _INTERNAA_ATOMIC_H + +#include <stdint.h> + +static inline int a_ctz_64(uint64_t x) +{ +	int r; +	__asm__( "bsf %1,%0 ; jnz 1f ; bsf %2,%0 ; addl $32,%0\n1:" +		: "=r"(r) : "r"((unsigned)x), "r"((unsigned)(x>>32)) ); +	return r; +} + + +static inline void a_and_64(volatile uint64_t *p, uint64_t v) +{ +	__asm__( "lock ; andl %1, (%0) ; lock ; andl %2, 4(%0)" +		: : "r"((long *)p), "r"((unsigned)v), "r"((unsigned)(v>>32)) ); +} + +static inline void a_or_64(volatile uint64_t *p, uint64_t v) +{ +	__asm__( "lock ; orl %1, (%0) ; lock ; orl %2, 4(%0)" +		: : "r"((long *)p), "r"((unsigned)v), "r"((unsigned)(v>>32)) ); +} + +static inline void a_store_l(volatile void *p, long x) +{ +	__asm__( "movl %1, %0" : "=m"(*(long *)p) : "r"(x) : "memory" ); +} + +static inline void a_or_l(volatile void *p, long v) +{ +	__asm__( "lock ; orl %1, %0" +		: "=m"(*(long *)p) : "r"(v) ); +} + +static inline void *a_cas_p(volatile void *p, void *t, void *s) +{ +	__asm__( "lock ; cmpxchg %3, %1" +		: "=a"(t), "=m"(*(long *)p) : "a"(t), "r"(s) ); +	return t; +} + +static inline long a_cas_l(volatile void *p, long t, long s) +{ +	__asm__( "lock ; cmpxchg %3, %1" +		: "=a"(t), "=m"(*(long *)p) : "a"(t), "r"(s) ); +	return t; +} + +static inline void *a_swap_p(void *volatile *x, void *v) +{ +	__asm__( "xchg %0, %1" : "=r"(v), "=m"(*(void **)x) : "0"(v) ); +	return v; +} +static inline long a_swap_l(volatile void *x, long v) +{ +	__asm__( "xchg %0, %1" : "=r"(v), "=m"(*(long *)x) : "0"(v) ); +	return v; +} + +static inline void a_or(volatile void *p, int v) +{ +	__asm__( "lock ; orl %1, %0" +		: "=m"(*(int *)p) : "r"(v) ); +} + +static inline void a_and(volatile void *p, int v) +{ +	__asm__( "lock ; andl %1, %0" +		: "=m"(*(int *)p) : "r"(v) ); +} + +static inline int a_swap(volatile int *x, int v) +{ +	__asm__( "xchg %0, %1" : "=r"(v), "=m"(*x) : "0"(v) ); +	return v; +} + +#define a_xchg a_swap + +static inline int a_fetch_add(volatile int *x, int v) +{ +	__asm__( "lock ; xadd %0, %1" : "=r"(v), "=m"(*x) : "0"(v) ); +	return v; +} + +static inline void a_inc(volatile int *x) +{ +	__asm__( "lock ; incl %0" : "=m"(*x) : "m"(*x) ); +} + +static inline void a_dec(volatile int *x) +{ +	__asm__( "lock ; decl %0" : "=m"(*x) : "m"(*x) ); +} + +static inline void a_store(volatile int *p, int x) +{ +	__asm__( "movl %1, %0" : "=m"(*p) : "r"(x) : "memory" ); +} + +static inline void a_spin() +{ +	__asm__ __volatile__( "pause" : : : "memory" ); +} + + +#endif diff --git a/src/internal/clone.h b/src/internal/clone.h new file mode 100644 index 00000000..cc84aeb4 --- /dev/null +++ b/src/internal/clone.h @@ -0,0 +1,22 @@ +#define CLONE_VM      0x00000100 +#define CLONE_FS      0x00000200 +#define CLONE_FILES   0x00000400 +#define CLONE_SIGHAND 0x00000800 +#define CLONE_PTRACE  0x00002000 +#define CLONE_VFORK   0x00004000 +#define CLONE_PARENT  0x00008000 +#define CLONE_THREAD  0x00010000 +#define CLONE_NEWNS   0x00020000 +#define CLONE_SYSVSEM 0x00040000 +#define CLONE_SETTLS  0x00080000 +#define CLONE_PARENT_SETTID 0x00100000 +#define CLONE_CHILD_CLEARTID 0x00200000 +#define CLONE_DETACHED 0x00400000 +#define CLONE_UNTRACED 0x00800000 +#define CLONE_CHILD_SETTID 0x01000000 +#define CLONE_NEWUTS	0x04000000 +#define CLONE_NEWIPC	0x08000000 +#define CLONE_NEWUSER	0x10000000 +#define CLONE_NEWPID	0x20000000 +#define CLONE_NEWNET	0x40000000 +#define CLONE_IO	0x80000000 diff --git a/src/internal/futex.h b/src/internal/futex.h new file mode 100644 index 00000000..c0453822 --- /dev/null +++ b/src/internal/futex.h @@ -0,0 +1,16 @@ +#ifndef _INTERNAL_FUTEX_H +#define _INTERNAL_FUTEX_H + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_FD		2 +#define FUTEX_REQUEUE		3 +#define FUTEX_CMP_REQUEUE	4 +#define FUTEX_WAKE_OP		5 +#define FUTEX_LOCK_PI		6 +#define FUTEX_UNLOCK_PI		7 +#define FUTEX_TRYLOCK_PI	8 + +int __futex(volatile int *, int, int, void *); + +#endif diff --git a/src/internal/libc.c b/src/internal/libc.c new file mode 100644 index 00000000..5e8e9d95 --- /dev/null +++ b/src/internal/libc.c @@ -0,0 +1,3 @@ +#include "libc.h" + +struct libc libc; diff --git a/src/internal/libc.h b/src/internal/libc.h new file mode 100644 index 00000000..e353f363 --- /dev/null +++ b/src/internal/libc.h @@ -0,0 +1,43 @@ +#ifndef LIBC_H +#define LIBC_H + +#include <stdlib.h> +#include <stdio.h> + +#define libc __libc +extern struct libc { +	void (*lock)(volatile int *); +	void (*cancelpt)(int); +	int (*atexit)(void (*)(void)); +	void (*fini)(void); +	void (*ldso_fini)(void); +	int *(*errno_location)(void); +	volatile int threads_minus_1; +	int (*rsyscall)(int, long, long, long, long, long, long); +	void (**tsd_keys)(void *); +} libc; + + +/* Designed to avoid any overhead in non-threaded processes */ +void __lock(volatile int *); +#define LOCK(x) (libc.threads_minus_1 ? (__lock(x),1) : ((void)(x),1)) +#define UNLOCK(x) (*(x)=0) +#define CANCELPT(x) (libc.cancelpt ? libc.cancelpt((x)),0 : (void)(x),0) +#define CANCELPT_BEGIN CANCELPT(1) +#define CANCELPT_END CANCELPT(0) + +extern char **__environ; +#define environ __environ + +#undef weak_alias +#define weak_alias(old, new) \ +	extern __typeof(old) new __attribute__((weak, alias(#old))) + +#undef LFS64_2 +//#define LFS64_2(x, y) weak_alias(x, y) +#define LFS64_2(x, y) extern __typeof(x) y + +#undef LFS64 +#define LFS64(x) LFS64_2(x, x##64) + +#endif diff --git a/src/internal/locale_impl.h b/src/internal/locale_impl.h new file mode 100644 index 00000000..c268124f --- /dev/null +++ b/src/internal/locale_impl.h @@ -0,0 +1,5 @@ +#include <locale.h> + +struct __locale { +	int dummy; +}; diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h new file mode 100644 index 00000000..b7892103 --- /dev/null +++ b/src/internal/pthread_impl.h @@ -0,0 +1,68 @@ +#ifndef _PTHREAD_IMPL_H +#define _PTHREAD_IMPL_H + +#include <pthread.h> +#include <sched.h> +#include <signal.h> +#include <unistd.h> +#include <sys/mman.h> +#include <errno.h> +#include <limits.h> +#include <inttypes.h> +#include <setjmp.h> +#include <string.h> +#include <time.h> +#include "libc.h" +#include "syscall.h" +#include "atomic.h" +#include "futex.h" + +#define pthread __pthread + +struct pthread { +	struct pthread *self, *join; +	int errno_val; +	pid_t tid, pid; +	volatile int canceldisable, cancelasync, cancelpoint, cancel; +	unsigned char *map_base; +	size_t map_size; +	void *start_arg; +	void *(*start)(void *); +	void *result; +	jmp_buf exit_jmp_buf; +	int detached; +	int exitlock; +	unsigned long tlsdesc[4]; +	struct __ptcb *cancelbuf; +	void **tsd; +	int tsd_used; +	pthread_attr_t attr; +	int *errno_ptr; +}; + +static inline struct pthread *__pthread_self() +{ +	struct pthread *self; +	__asm__ ("movl %%gs:0,%0" : "=r" (self) ); +	return self; +} + +#define SIGCANCEL 32 +#define SIGSYSCALL 33 +#define SIGTIMER  32 /* ?? */ + +int __set_thread_area(unsigned long *); +int __set_pthread_self(void *); +int __libc_sigaction(int, const struct sigaction *, struct sigaction *); +int __libc_sigprocmask(int, const sigset_t *, sigset_t *); +void __lock(volatile int *); +void __unmapself(void *, size_t); + +int __timedwait(volatile int *, int, clockid_t, const struct timespec *, int); +void __wait(volatile int *, volatile int *, int, int); +void __wake(volatile int *, int, int); + +#define DEFAULT_STACK_SIZE (16384-PAGE_SIZE) +#define DEFAULT_GUARD_SIZE PAGE_SIZE + +#endif diff --git a/src/internal/stdio_impl.h b/src/internal/stdio_impl.h new file mode 100644 index 00000000..1e9159f6 --- /dev/null +++ b/src/internal/stdio_impl.h @@ -0,0 +1,100 @@ +#ifndef _STDIO_IMPL_H +#define _STDIO_IMPL_H + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdarg.h> +#include <string.h> +#include <inttypes.h> +#include <wchar.h> +#include <unistd.h> +#include <fcntl.h> +#include <limits.h> +#include <errno.h> +#include <termios.h> +#include <sys/ioctl.h> +#include <ctype.h> +#include <sys/wait.h> +#include <math.h> +#include <float.h> +#include "syscall.h" +#include "libc.h" + +#define UNGET 4 + +#define FLOCK(f) LOCK(&f->lock) +#define FUNLOCK(f) UNLOCK(&f->lock) + +#define F_PERM 1 +#define F_NORD 4 +#define F_NOWR 8 +#define F_EOF 16 +#define F_ERR 32 + +struct __FILE_s { +	unsigned flags; +	unsigned char *rpos, *rstop; +	unsigned char *rend, *wend; +	unsigned char *wpos, *wstop; +	unsigned char *wbase; +	unsigned char *dummy01[3]; +	unsigned char *buf; +	size_t buf_size; +	FILE *prev, *next; +	int fd; +	int pipe_pid; +	long dummy2; +	short dummy3; +	char dummy4; +	signed char lbf; +	int lock; +	int lockcount; +	void *owner; +	off_t off; +	int (*flush)(FILE *); +	void **wide_data; /* must be NULL */ +	size_t (*read)(FILE *, unsigned char *, size_t); +	size_t (*write)(FILE *, const unsigned char *, size_t); +	off_t (*seek)(FILE *, off_t, int); +	int mode; +	int (*close)(FILE *); +}; + +size_t __stdio_read(FILE *, unsigned char *, size_t); +size_t __stdio_write(FILE *, const unsigned char *, size_t); +off_t __stdio_seek(FILE *, off_t, int); +int __stdio_close(FILE *); + +int __overflow(FILE *, int); +int __oflow(FILE *); +int __uflow(FILE *); +int __underflow(FILE *); + +int __fseeko(FILE *, off_t, int); +int __fseeko_unlocked(FILE *, off_t, int); +off_t __ftello(FILE *); +off_t __ftello_unlocked(FILE *); +size_t __fwritex(const unsigned char *, size_t, FILE *); +int __putc_unlocked(int, FILE *); + +FILE *__fdopen(int, const char *); + +extern struct ofl +{ +	FILE *head; +	int lock; +} __ofl; + +#define OFLLOCK() LOCK(&__ofl.lock) +#define OFLUNLOCK() UNLOCK(&__ofl.lock) +#define ofl_head (__ofl.head) + +#define feof(f) ((f)->flags & F_EOF) +#define ferror(f) ((f)->flags & F_ERR) + +/* Caller-allocated FILE * operations */ +FILE *__fopen_rb_ca(const char *, FILE *, unsigned char *, size_t); +int __fclose_ca(FILE *); + +#endif diff --git a/src/internal/syscall.c b/src/internal/syscall.c new file mode 100644 index 00000000..4f159e0b --- /dev/null +++ b/src/internal/syscall.c @@ -0,0 +1,11 @@ +#include <errno.h> +#include <unistd.h> + +long __syscall_ret(unsigned long r) +{ +	if (r >= (unsigned long)-1 - 4096) { +		errno = -(long)r; +		return -1; +	} +	return (long)r; +} diff --git a/src/internal/syscall.h b/src/internal/syscall.h new file mode 100644 index 00000000..4b3c0a73 --- /dev/null +++ b/src/internal/syscall.h @@ -0,0 +1,469 @@ +#ifndef _SYSCALL_H +#define _SYSCALL_H + +#define SYSCALL_LL(x) \ +((union { long long ll; long l[2]; }){ .ll = x }).l[0], \ +((union { long long ll; long l[2]; }){ .ll = x }).l[1] + +#define SYSCALL_SIGSET_SIZE 8 + +#if defined(SYSCALL_STANDALONE) +#include <errno.h> +static inline long __syscall_ret(unsigned long r) +{ +	if (r >= (unsigned long)-1 - 4096) { +		errno = -(long)r; +		return -1; +	} +	return (long)r; +} +#elif defined(SYSCALL_NORETURN) +static inline long __syscall_ret(unsigned long r) +{ +	for(;;); +	return 0; +} +#elif defined(SYSCALL_RETURN_ERRNO) +static inline long __syscall_ret(unsigned long r) +{ +	return -r; +} +#else +extern long __syscall_ret(unsigned long); +#endif + +#define SYSCALL0 "int $128" + +#ifdef __PIC__ +#define SYSCALL "xchgl %%ebx,%2\n\t" SYSCALL0 "\n\txchgl %%ebx,%2" +#define EBX "m" +#else +#define SYSCALL SYSCALL0 +#define EBX "b" +#endif + +static inline long syscall0(long n) +{ +	unsigned long ret; +	__asm__ __volatile__ (SYSCALL0 : "=a"(ret) : "a"(n) : "memory"); +	return __syscall_ret(ret); +} + +static inline long syscall1(long n, long a1) +{ +	unsigned long ret; +	__asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1) : "memory"); +	return __syscall_ret(ret); +} + +static inline long syscall2(long n, long a1, long a2) +{ +	unsigned long ret; +	__asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1), "c"(a2) : "memory"); +	return __syscall_ret(ret); +} + +static inline long syscall3(long n, long a1, long a2, long a3) +{ +	unsigned long ret; +	__asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1), "c"(a2), "d"(a3) : "memory"); +	return __syscall_ret(ret); +} + +static inline long syscall4(long n, long a1, long a2, long a3, long a4) +{ +	unsigned long ret; +	__asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1), "c"(a2), "d"(a3), "S"(a4) : "memory"); +	return __syscall_ret(ret); +} + +static inline long syscall5(long n, long a1, long a2, long a3, long a4, long a5) +{ +	unsigned long ret; +	__asm__ __volatile__ (SYSCALL : "=a"(ret) : "a"(n), EBX(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5) : "memory"); +	return __syscall_ret(ret); +} + +#ifdef __PIC__ +/* note: it's probably only safe to use this when a6 is on the stack */ +static inline long syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) +{ +	unsigned long ret; +	__asm__ __volatile__ ("xchgl %%ebx,%2 ; pushl %1 ; pushl %%ebp ; movl %%eax,%%ebp ; movl 4(%%esp),%%eax ; int $128 ; popl %%ebp ; popl %%ecx ; xchgl %%ebx,%2" +		: "=a"(ret) : "g"(n), EBX(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5), "a"(a6) : "memory"); +	return __syscall_ret(ret); +} +#else +static inline long syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) +{ +	unsigned long ret; +	__asm__ __volatile__ ("pushl %%ebp ; mov %1, %%ebp ; xchg %%ebp, %7 ; int $128 ; popl %%ebp" +		: "=a"(ret) : "g"(n), EBX(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5), "a"(a6) : "memory"); +	return __syscall_ret(ret); +} +#endif + +#define __NR_restart_syscall      0 +#define __NR_exit		  1 +#define __NR_fork		  2 +#define __NR_read		  3 +#define __NR_write		  4 +#define __NR_open		  5 +#define __NR_close		  6 +#define __NR_waitpid		  7 +#define __NR_creat		  8 +#define __NR_link		  9 +#define __NR_unlink		 10 +#define __NR_execve		 11 +#define __NR_chdir		 12 +#define __NR_time		 13 +#define __NR_mknod		 14 +#define __NR_chmod		 15 +#define __NR_lchown		 16 +#define __NR_break		 17 +#define __NR_oldstat		 18 +#define __NR_lseek		 19 +#define __NR_getpid		 20 +#define __NR_mount		 21 +#define __NR_umount		 22 +#define __NR_setuid		 23 +#define __NR_getuid		 24 +#define __NR_stime		 25 +#define __NR_ptrace		 26 +#define __NR_alarm		 27 +#define __NR_oldfstat		 28 +#define __NR_pause		 29 +#define __NR_utime		 30 +#define __NR_stty		 31 +#define __NR_gtty		 32 +#define __NR_access		 33 +#define __NR_nice		 34 +#define __NR_ftime		 35 +#define __NR_sync		 36 +#define __NR_kill		 37 +#define __NR_rename		 38 +#define __NR_mkdir		 39 +#define __NR_rmdir		 40 +#define __NR_dup		 41 +#define __NR_pipe		 42 +#define __NR_times		 43 +#define __NR_prof		 44 +#define __NR_brk		 45 +#define __NR_setgid		 46 +#define __NR_getgid		 47 +#define __NR_signal		 48 +#define __NR_geteuid		 49 +#define __NR_getegid		 50 +#define __NR_acct		 51 +#define __NR_umount2		 52 +#define __NR_lock		 53 +#define __NR_ioctl		 54 +#define __NR_fcntl		 55 +#define __NR_mpx		 56 +#define __NR_setpgid		 57 +#define __NR_ulimit		 58 +#define __NR_oldolduname	 59 +#define __NR_umask		 60 +#define __NR_chroot		 61 +#define __NR_ustat		 62 +#define __NR_dup2		 63 +#define __NR_getppid		 64 +#define __NR_getpgrp		 65 +#define __NR_setsid		 66 +#define __NR_sigaction		 67 +#define __NR_sgetmask		 68 +#define __NR_ssetmask		 69 +#define __NR_setreuid		 70 +#define __NR_setregid		 71 +#define __NR_sigsuspend		 72 +#define __NR_sigpending		 73 +#define __NR_sethostname	 74 +#define __NR_setrlimit		 75 +#define __NR_getrlimit		 76   /* Back compatible 2Gig limited rlimit */ +#define __NR_getrusage		 77 +#define __NR_gettimeofday	 78 +#define __NR_settimeofday	 79 +#define __NR_getgroups		 80 +#define __NR_setgroups		 81 +#define __NR_select		 82 +#define __NR_symlink		 83 +#define __NR_oldlstat		 84 +#define __NR_readlink		 85 +#define __NR_uselib		 86 +#define __NR_swapon		 87 +#define __NR_reboot		 88 +#define __NR_readdir		 89 +#define __NR_mmap		 90 +#define __NR_munmap		 91 +#define __NR_truncate		 92 +#define __NR_ftruncate		 93 +#define __NR_fchmod		 94 +#define __NR_fchown		 95 +#define __NR_getpriority	 96 +#define __NR_setpriority	 97 +#define __NR_profil		 98 +#define __NR_statfs		99 +#define __NR_fstatfs		100 +#define __NR_ioperm		101 +#define __NR_socketcall		102 +#define __NR_syslog		103 +#define __NR_setitimer		104 +#define __NR_getitimer		105 +#define __NR_stat		106 +#define __NR_lstat		107 +#define __NR_fstat		108 +#define __NR_olduname		109 +#define __NR_iopl		110 +#define __NR_vhangup		111 +#define __NR_idle		112 +#define __NR_vm86old		113 +#define __NR_wait4		114 +#define __NR_swapoff		115 +#define __NR_sysinfo		116 +#define __NR_ipc		117 +#define __NR_fsync		118 +#define __NR_sigreturn		119 +#define __NR_clone		120 +#define __NR_setdomainname	121 +#define __NR_uname		122 +#define __NR_modify_ldt		123 +#define __NR_adjtimex		124 +#define __NR_mprotect		125 +#define __NR_sigprocmask	126 +#define __NR_create_module	127 +#define __NR_init_module	128 +#define __NR_delete_module	129 +#define __NR_get_kernel_syms	130 +#define __NR_quotactl		131 +#define __NR_getpgid		132 +#define __NR_fchdir		133 +#define __NR_bdflush		134 +#define __NR_sysfs		135 +#define __NR_personality	136 +#define __NR_afs_syscall	137 +#define __NR_setfsuid		138 +#define __NR_setfsgid		139 +#define __NR__llseek		140 +#define __NR_getdents		141 +#define __NR__newselect		142 +#define __NR_flock		143 +#define __NR_msync		144 +#define __NR_readv		145 +#define __NR_writev		146 +#define __NR_getsid		147 +#define __NR_fdatasync		148 +#define __NR__sysctl		149 +#define __NR_mlock		150 +#define __NR_munlock		151 +#define __NR_mlockall		152 +#define __NR_munlockall		153 +#define __NR_sched_setparam		154 +#define __NR_sched_getparam		155 +#define __NR_sched_setscheduler		156 +#define __NR_sched_getscheduler		157 +#define __NR_sched_yield		158 +#define __NR_sched_get_priority_max	159 +#define __NR_sched_get_priority_min	160 +#define __NR_sched_rr_get_interval	161 +#define __NR_nanosleep		162 +#define __NR_mremap		163 +#define __NR_setresuid		164 +#define __NR_getresuid		165 +#define __NR_vm86		166 +#define __NR_query_module	167 +#define __NR_poll		168 +#define __NR_nfsservctl		169 +#define __NR_setresgid		170 +#define __NR_getresgid		171 +#define __NR_prctl              172 +#define __NR_rt_sigreturn	173 +#define __NR_rt_sigaction	174 +#define __NR_rt_sigprocmask	175 +#define __NR_rt_sigpending	176 +#define __NR_rt_sigtimedwait	177 +#define __NR_rt_sigqueueinfo	178 +#define __NR_rt_sigsuspend	179 +#define __NR_pread64		180 +#define __NR_pwrite64		181 +#define __NR_chown		182 +#define __NR_getcwd		183 +#define __NR_capget		184 +#define __NR_capset		185 +#define __NR_sigaltstack	186 +#define __NR_sendfile		187 +#define __NR_getpmsg		188 +#define __NR_putpmsg		189 +#define __NR_vfork		190 +#define __NR_ugetrlimit		191 +#define __NR_mmap2		192 +#define __NR_truncate64		193 +#define __NR_ftruncate64	194 +#define __NR_stat64		195 +#define __NR_lstat64		196 +#define __NR_fstat64		197 +#define __NR_lchown32		198 +#define __NR_getuid32		199 +#define __NR_getgid32		200 +#define __NR_geteuid32		201 +#define __NR_getegid32		202 +#define __NR_setreuid32		203 +#define __NR_setregid32		204 +#define __NR_getgroups32	205 +#define __NR_setgroups32	206 +#define __NR_fchown32		207 +#define __NR_setresuid32	208 +#define __NR_getresuid32	209 +#define __NR_setresgid32	210 +#define __NR_getresgid32	211 +#define __NR_chown32		212 +#define __NR_setuid32		213 +#define __NR_setgid32		214 +#define __NR_setfsuid32		215 +#define __NR_setfsgid32		216 +#define __NR_pivot_root		217 +#define __NR_mincore		218 +#define __NR_madvise		219 +#define __NR_madvise1		219 +#define __NR_getdents64		220 +#define __NR_fcntl64		221 +/* 223 is unused */ +#define __NR_gettid		224 +#define __NR_readahead		225 +#define __NR_setxattr		226 +#define __NR_lsetxattr		227 +#define __NR_fsetxattr		228 +#define __NR_getxattr		229 +#define __NR_lgetxattr		230 +#define __NR_fgetxattr		231 +#define __NR_listxattr		232 +#define __NR_llistxattr		233 +#define __NR_flistxattr		234 +#define __NR_removexattr	235 +#define __NR_lremovexattr	236 +#define __NR_fremovexattr	237 +#define __NR_tkill		238 +#define __NR_sendfile64		239 +#define __NR_futex		240 +#define __NR_sched_setaffinity	241 +#define __NR_sched_getaffinity	242 +#define __NR_set_thread_area	243 +#define __NR_get_thread_area	244 +#define __NR_io_setup		245 +#define __NR_io_destroy		246 +#define __NR_io_getevents	247 +#define __NR_io_submit		248 +#define __NR_io_cancel		249 +#define __NR_fadvise64		250 +/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */ +#define __NR_exit_group		252 +#define __NR_lookup_dcookie	253 +#define __NR_epoll_create	254 +#define __NR_epoll_ctl		255 +#define __NR_epoll_wait		256 +#define __NR_remap_file_pages	257 +#define __NR_set_tid_address	258 +#define __NR_timer_create	259 +#define __NR_timer_settime	(__NR_timer_create+1) +#define __NR_timer_gettime	(__NR_timer_create+2) +#define __NR_timer_getoverrun	(__NR_timer_create+3) +#define __NR_timer_delete	(__NR_timer_create+4) +#define __NR_clock_settime	(__NR_timer_create+5) +#define __NR_clock_gettime	(__NR_timer_create+6) +#define __NR_clock_getres	(__NR_timer_create+7) +#define __NR_clock_nanosleep	(__NR_timer_create+8) +#define __NR_statfs64		268 +#define __NR_fstatfs64		269 +#define __NR_tgkill		270 +#define __NR_utimes		271 +#define __NR_fadvise64_64	272 +#define __NR_vserver		273 +#define __NR_mbind		274 +#define __NR_get_mempolicy	275 +#define __NR_set_mempolicy	276 +#define __NR_mq_open 		277 +#define __NR_mq_unlink		(__NR_mq_open+1) +#define __NR_mq_timedsend	(__NR_mq_open+2) +#define __NR_mq_timedreceive	(__NR_mq_open+3) +#define __NR_mq_notify		(__NR_mq_open+4) +#define __NR_mq_getsetattr	(__NR_mq_open+5) +#define __NR_kexec_load		283 +#define __NR_waitid		284 +/* #define __NR_sys_setaltroot	285 */ +#define __NR_add_key		286 +#define __NR_request_key	287 +#define __NR_keyctl		288 +#define __NR_ioprio_set		289 +#define __NR_ioprio_get		290 +#define __NR_inotify_init	291 +#define __NR_inotify_add_watch	292 +#define __NR_inotify_rm_watch	293 +#define __NR_migrate_pages	294 +#define __NR_openat		295 +#define __NR_mkdirat		296 +#define __NR_mknodat		297 +#define __NR_fchownat		298 +#define __NR_futimesat		299 +#define __NR_fstatat64		300 +#define __NR_unlinkat		301 +#define __NR_renameat		302 +#define __NR_linkat		303 +#define __NR_symlinkat		304 +#define __NR_readlinkat		305 +#define __NR_fchmodat		306 +#define __NR_faccessat		307 +#define __NR_pselect6		308 +#define __NR_ppoll		309 +#define __NR_unshare		310 +#define __NR_set_robust_list	311 +#define __NR_get_robust_list	312 +#define __NR_splice		313 +#define __NR_sync_file_range	314 +#define __NR_tee		315 +#define __NR_vmsplice		316 +#define __NR_move_pages		317 +#define __NR_getcpu		318 +#define __NR_epoll_pwait	319 +#define __NR_utimensat		320 +#define __NR_signalfd		321 +#define __NR_timerfd_create	322 +#define __NR_eventfd		323 +#define __NR_fallocate		324 +#define __NR_timerfd_settime	325 +#define __NR_timerfd_gettime	326 +#define __NR_signalfd4		327 +#define __NR_eventfd2		328 +#define __NR_epoll_create1	329 +#define __NR_dup3		330 +#define __NR_pipe2		331 +#define __NR_inotify_init1	332 +#define __NR_preadv		333 +#define __NR_pwritev		334 + + +#undef O_LARGEFILE +#define O_LARGEFILE 0100000 + +/* the following are needed for iso c functions to use */ +#define __syscall_open(filename, flags, mode) syscall3(__NR_open, (long)(filename), (flags)|O_LARGEFILE, (mode)) +#define __syscall_read(fd, buf, len)          syscall3(__NR_read, (fd), (long)(buf), (len)) +#define __syscall_write(fd, buf, len)         syscall3(__NR_write, (fd), (long)(buf), (len)) +#define __syscall_close(fd)                   syscall1(__NR_close, (fd)) +#define __syscall_fcntl(fd, cmd, arg)         syscall3(__NR_fcntl64, (fd), (cmd), (long)(arg)) +#define __syscall_dup2(old, new)              syscall2(__NR_dup2, (old), (new)) +#define __syscall_unlink(path)                syscall1(__NR_unlink, (long)(path)) +#define __syscall_getpid()                    syscall0(__NR_getpid) +#define __syscall_kill(pid,sig)               syscall2(__NR_kill, (pid), (sig)) +#define __syscall_sigaction(sig,new,old)      syscall4(__NR_rt_sigaction, (sig), (long)(new), (long)(old), SYSCALL_SIGSET_SIZE) +#define __syscall_ioctl(fd,ioc,arg)           syscall3(__NR_ioctl, (fd), (ioc), (long)(arg)) +#define __syscall_exit(code)                  syscall1(__NR_exit, code) + +#define __NEED_off_t +#include <bits/alltypes.h> + +static inline off_t __syscall_lseek(int fd, off_t offset, int whence) +{ +	off_t result; +	return syscall5(__NR__llseek, fd, offset>>32, offset, (long)&result, whence) ? -1 : result; +} + +#endif diff --git a/src/internal/util.h b/src/internal/util.h new file mode 100644 index 00000000..7c7c3a17 --- /dev/null +++ b/src/internal/util.h @@ -0,0 +1,5 @@ +#ifndef _INTERNAL_UTIL_H +#define _INTERNAL_UTIL_H + + +#endif diff --git a/src/ipc/ftok.c b/src/ipc/ftok.c new file mode 100644 index 00000000..cd6002ed --- /dev/null +++ b/src/ipc/ftok.c @@ -0,0 +1,10 @@ +#include <sys/ipc.h> +#include <sys/stat.h> + +key_t ftok(const char *path, int id) +{ +	struct stat st; +	if (stat(path, &st) < 0) return -1; + +	return ((st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16) | ((id & 0xff) << 24)); +} diff --git a/src/ipc/ipc.h b/src/ipc/ipc.h new file mode 100644 index 00000000..9edd5ecf --- /dev/null +++ b/src/ipc/ipc.h @@ -0,0 +1,13 @@ +#define IPCOP_semop      1 +#define IPCOP_semget     2 +#define IPCOP_semctl     3 +#define IPCOP_msgsnd    11 +#define IPCOP_msgrcv    12 +#define IPCOP_msgget    13 +#define IPCOP_msgctl    14 +#define IPCOP_shmat     21 +#define IPCOP_shmdt     22 +#define IPCOP_shmget    23 +#define IPCOP_shmctl    24 + +#define IPC_MODERN   0x100 diff --git a/src/ipc/semctl.c b/src/ipc/semctl.c new file mode 100644 index 00000000..7ada116b --- /dev/null +++ b/src/ipc/semctl.c @@ -0,0 +1,18 @@ +#include <sys/sem.h> +#include <stdarg.h> +#include "syscall.h" +#include "ipc.h" + +int semctl(int id, int num, int cmd, ...) +{ +	long arg; +	va_list ap; +	va_start(ap, cmd); +	arg = va_arg(ap, long); +	va_end(ap); +#ifdef __NR_semctl +	return syscall4(__NR_semctl, id, num, cmd, arg); +#else +	return syscall5(__NR_ipc, IPCOP_semctl, id, num, cmd | 0x100, (long)&arg); +#endif +} diff --git a/src/ipc/semget.c b/src/ipc/semget.c new file mode 100644 index 00000000..2dcf6eac --- /dev/null +++ b/src/ipc/semget.c @@ -0,0 +1,12 @@ +#include <sys/sem.h> +#include "syscall.h" +#include "ipc.h" + +int semget(key_t key, int n, int fl) +{ +#ifdef __NR_semget +	return syscall3(__NR_semget, key, n, fl); +#else +	return syscall4(__NR_ipc, IPCOP_semget, key, n, fl); +#endif +} diff --git a/src/ipc/semop.c b/src/ipc/semop.c new file mode 100644 index 00000000..48d8a654 --- /dev/null +++ b/src/ipc/semop.c @@ -0,0 +1,12 @@ +#include <sys/sem.h> +#include "syscall.h" +#include "ipc.h" + +int semop(int id, struct sembuf *buf, size_t n) +{ +#ifdef __NR_semop +	return syscall3(__NR_semop, id, (long)buf, n); +#else +	return syscall5(__NR_ipc, IPCOP_semop, id, n, 0, (long)buf); +#endif +} diff --git a/src/ipc/shmat.c b/src/ipc/shmat.c new file mode 100644 index 00000000..ff65b6a4 --- /dev/null +++ b/src/ipc/shmat.c @@ -0,0 +1,17 @@ +#include <sys/shm.h> +#include "syscall.h" +#include "ipc.h" + +#ifdef __NR_shmat +void *shmat(int id, const void *addr, int flag) +{ +	return syscall3(__NR_shmat, id, (long)addr, flag); +} +#else +void *shmat(int id, const void *addr, int flag) +{ +	unsigned long ret; +	ret = syscall5(__NR_ipc, IPCOP_shmat, id, flag, (long)&addr, (long)addr); +	return (ret > -(unsigned long)SHMLBA) ? (void *)ret : (void *)addr; +} +#endif diff --git a/src/ipc/shmctl.c b/src/ipc/shmctl.c new file mode 100644 index 00000000..da357fa8 --- /dev/null +++ b/src/ipc/shmctl.c @@ -0,0 +1,12 @@ +#include <sys/shm.h> +#include "syscall.h" +#include "ipc.h" + +int shmctl(int id, int cmd, struct shmid_ds *buf) +{ +#ifdef __NR_shmctl +	return syscall3(__NR_shmctl, id, cmd, (long)buf); +#else +	return syscall4(__NR_ipc, IPCOP_shmctl, id, cmd | IPC_MODERN, (long)buf); +#endif +} diff --git a/src/ipc/shmdt.c b/src/ipc/shmdt.c new file mode 100644 index 00000000..e04188f9 --- /dev/null +++ b/src/ipc/shmdt.c @@ -0,0 +1,12 @@ +#include <sys/shm.h> +#include "syscall.h" +#include "ipc.h" + +int shmdt(const void *addr) +{ +#ifdef __NR_shmdt +	return syscall1(__NR_shmdt, (long)addr); +#else +	return syscall2(__NR_ipc, IPCOP_shmdt, (long)addr); +#endif +} diff --git a/src/ipc/shmget.c b/src/ipc/shmget.c new file mode 100644 index 00000000..86e254af --- /dev/null +++ b/src/ipc/shmget.c @@ -0,0 +1,12 @@ +#include <sys/shm.h> +#include "syscall.h" +#include "ipc.h" + +int shmget(key_t key, size_t size, int flag) +{ +#ifdef __NR_shmget +	return syscall3(__NR_shmget, key, size, flag); +#else +	return syscall4(__NR_ipc, IPCOP_shmget, key, size, flag); +#endif +} diff --git a/src/linux/brk.c b/src/linux/brk.c new file mode 100644 index 00000000..3c2982c6 --- /dev/null +++ b/src/linux/brk.c @@ -0,0 +1,6 @@ +#include "syscall.h" + +int brk(void *end) +{ +	return -(syscall1(__NR_brk, (long)end) == -1); +} diff --git a/src/linux/chroot.c b/src/linux/chroot.c new file mode 100644 index 00000000..b5af62dc --- /dev/null +++ b/src/linux/chroot.c @@ -0,0 +1,8 @@ +#include <unistd.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int chroot(const char *path) +{ +	return syscall1(__NR_chroot, (long)path); +} diff --git a/src/linux/daemon.c b/src/linux/daemon.c new file mode 100644 index 00000000..632d1203 --- /dev/null +++ b/src/linux/daemon.c @@ -0,0 +1,31 @@ +#include <fcntl.h> +#include <unistd.h> + +int daemon(int nochdir, int noclose) +{ +	int fd; + +	switch(fork()) { +	case 0: break; +	case -1: return -1; +	default: _exit(0); +	} + +	if (setsid() < 0) return -1; + +	switch(fork()) { +	case 0: break; +	case -1: return -1; +	default: _exit(0); +	} + +	if (!nochdir) chdir("/"); +	if (!noclose && (fd = open("/dev/null", O_RDWR)) >= 0) { +		dup2(fd, 0); +		dup2(fd, 1); +		dup2(fd, 2); +		if (fd > 2) close(fd); +	} + +	return 0; +} diff --git a/src/linux/epoll_create.c b/src/linux/epoll_create.c new file mode 100644 index 00000000..c9dea8ce --- /dev/null +++ b/src/linux/epoll_create.c @@ -0,0 +1,7 @@ +#include <sys/epoll.h> +#include "syscall.h" + +int epoll_create(int size) +{ +	return syscall1(__NR_epoll_create, size); +} diff --git a/src/linux/epoll_create1.c b/src/linux/epoll_create1.c new file mode 100644 index 00000000..2e82e995 --- /dev/null +++ b/src/linux/epoll_create1.c @@ -0,0 +1,7 @@ +#include <sys/epoll.h> +#include "syscall.h" + +int epoll_create1(int flags) +{ +	return syscall1(__NR_epoll_create1, flags); +} diff --git a/src/linux/epoll_ctl.c b/src/linux/epoll_ctl.c new file mode 100644 index 00000000..4214f407 --- /dev/null +++ b/src/linux/epoll_ctl.c @@ -0,0 +1,7 @@ +#include <sys/epoll.h> +#include "syscall.h" + +int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev) +{ +	return syscall4(__NR_epoll_ctl, fd, op, fd2, (long)ev); +} diff --git a/src/linux/epoll_pwait.c b/src/linux/epoll_pwait.c new file mode 100644 index 00000000..5aaacba6 --- /dev/null +++ b/src/linux/epoll_pwait.c @@ -0,0 +1,7 @@ +#include <sys/epoll.h> +#include "syscall.h" + +int epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to, const sigset_t *sigs) +{ +	return syscall6(__NR_epoll_pwait, fd, (long)ev, cnt, to, (long)sigs, 8); +} diff --git a/src/linux/epoll_wait.c b/src/linux/epoll_wait.c new file mode 100644 index 00000000..8a68ebdd --- /dev/null +++ b/src/linux/epoll_wait.c @@ -0,0 +1,7 @@ +#include <sys/epoll.h> +#include "syscall.h" + +int epoll_wait(int fd, struct epoll_event *ev, int cnt, int to) +{ +	return syscall4(__NR_epoll_wait, fd, (long)ev, cnt, to); +} diff --git a/src/linux/getdtablesize.c b/src/linux/getdtablesize.c new file mode 100644 index 00000000..623a6af3 --- /dev/null +++ b/src/linux/getdtablesize.c @@ -0,0 +1,9 @@ +#include <limits.h> +#include <sys/resource.h> + +int getdtablesize(void) +{ +	struct rlimit rl; +	getrlimit(RLIMIT_NOFILE, &rl); +	return rl.rlim_max < INT_MAX ? rl.rlim_max : INT_MAX; +} diff --git a/src/linux/gethostid.c b/src/linux/gethostid.c new file mode 100644 index 00000000..ea65611a --- /dev/null +++ b/src/linux/gethostid.c @@ -0,0 +1,4 @@ +long gethostid() +{ +	return 0; +} diff --git a/src/linux/getopt_long.c b/src/linux/getopt_long.c new file mode 100644 index 00000000..d80cd1b6 --- /dev/null +++ b/src/linux/getopt_long.c @@ -0,0 +1,52 @@ +#define _GNU_SOURCE +#include <stddef.h> +#include <getopt.h> +#include <stdio.h> + +static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly) +{ +	if (optind >= argc || !argv[optind] || argv[optind][0] != '-') return -1; +	if ((longonly && argv[optind][1]) || +		(argv[optind][1] == '-' && argv[optind][2])) +	{ +		int i; +		for (i=0; longopts[i].name; i++) { +			const char *name = longopts[i].name; +			char *opt = argv[optind]+1; +			if (*opt == '-') opt++; +			while (*name && *name++ == *opt++); +			if (*name || (*opt && *opt != '=')) continue; +			if (*opt == '=') { +				if (!longopts[i].has_arg) continue; +				optarg = opt+1; +			} else { +				if (longopts[i].has_arg == required_argument) { +					if (!(optarg = argv[++optind])) +						return ':'; +				} else optarg = NULL; +			} +			optind++; +			if (idx) *idx = i; +			if (longopts[i].flag) { +				*longopts[i].flag = longopts[i].val; +				return 0; +			} +			return longopts[i].val; +		} +		if (argv[optind][1] == '-') { +			optind++; +			return '?'; +		} +	} +	return getopt(argc, argv, optstring); +} + +int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx) +{ +	return __getopt_long(argc, argv, optstring, longopts, idx, 0); +} + +int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx) +{ +	return __getopt_long(argc, argv, optstring, longopts, idx, 1); +} diff --git a/src/linux/getpagesize.c b/src/linux/getpagesize.c new file mode 100644 index 00000000..5ede652b --- /dev/null +++ b/src/linux/getpagesize.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include <limits.h> + +int getpagesize(void) +{ +	return PAGE_SIZE; +} diff --git a/src/linux/getpass.c b/src/linux/getpass.c new file mode 100644 index 00000000..d439a2a5 --- /dev/null +++ b/src/linux/getpass.c @@ -0,0 +1,39 @@ +#include <stdio.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> +#include <fcntl.h> + +char *getpass(const char *prompt) +{ +	int fd; +	struct termios s, t; +	ssize_t l; +	static char password[128]; + +	if ((fd = open("/dev/tty", O_RDONLY|O_NOCTTY)) < 0) fd = 0; + +	tcgetattr(fd, &t); +	s = t; +	t.c_lflag &= ~(ECHO|ISIG); +	t.c_lflag |= ICANON; +	t.c_iflag &= ~(INLCR|IGNCR); +	t.c_iflag |= ICRNL; +	tcsetattr(fd, TCSAFLUSH, &t); +	tcdrain(fd); + +	fputs(prompt, stderr); +	fflush(stderr); + +	l = read(fd, password, sizeof password); +	if (l >= 0) { +		if (l > 0 && password[l-1] == '\n') l--; +		password[l] = 0; +	} + +	tcsetattr(fd, TCSAFLUSH, &s); + +	if (fd > 2) close(fd); + +	return password; +} diff --git a/src/linux/initgroups.c b/src/linux/initgroups.c new file mode 100644 index 00000000..ef9bc10a --- /dev/null +++ b/src/linux/initgroups.c @@ -0,0 +1,15 @@ +#include <sys/types.h> +#include <unistd.h> +#include <grp.h> +#include <limits.h> + +int getgrouplist(const char *, gid_t, gid_t *, int *); +int setgroups(size_t, const gid_t *); + +int initgroups(const char *user, gid_t gid) +{ +	gid_t groups[NGROUPS_MAX]; +	int count; +	if (getgrouplist(user, gid, groups, &count) < 0) return -1; +	return setgroups(count, groups); +} diff --git a/src/linux/klogctl.c b/src/linux/klogctl.c new file mode 100644 index 00000000..6c288aff --- /dev/null +++ b/src/linux/klogctl.c @@ -0,0 +1,7 @@ +#define SYSCALL_STANDALONE +#include "syscall.h" + +int klogctl (int type, char *buf, int len) +{ +	return syscall3(__NR_syslog, type, (long)buf, len); +} diff --git a/src/linux/mntent.c b/src/linux/mntent.c new file mode 100644 index 00000000..e3735666 --- /dev/null +++ b/src/linux/mntent.c @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <string.h> +#include <mntent.h> + +FILE *setmntent(const char *name, const char *mode) +{ +	return fopen(name, mode); +} + +int endmntent(FILE *f) +{ +	fclose(f); +	return 1; +} + +struct mntent *getmntent(FILE *f) +{ +	static char linebuf[256]; +	static struct mntent mnt; +	int cnt, n[8]; + +	mnt.mnt_freq = 0; +	mnt.mnt_passno = 0; + +	do { +		fgets(linebuf, sizeof linebuf, f); +		if (feof(f)) return NULL; +		cnt = sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", +			n, n+1, n+2, n+3, n+4, n+5, n+6, n+7, +			&mnt.mnt_freq, &mnt.mnt_passno); +	} while (cnt >= 8 && linebuf[n[0]] != '#'); + +	linebuf[n[1]] = 0; +	linebuf[n[3]] = 0; +	linebuf[n[5]] = 0; +	linebuf[n[7]] = 0; + +	mnt.mnt_fsname = linebuf+n[0]; +	mnt.mnt_dir = linebuf+n[2]; +	mnt.mnt_type = linebuf+n[4]; +	mnt.mnt_opts = linebuf+n[6]; + +	return &mnt; +} + +int addmntent(FILE *f, const struct mntent *mnt) +{ +	fseek(f, 0, SEEK_END); +	return fprintf(f, "%s\t%s\t%s\t%s\t%d\t%d\n", +		mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type, mnt->mnt_opts, +		mnt->mnt_freq, mnt->mnt_passno) < 0; +} + +char *hasmntopt(const struct mntent *mnt, const char *opt) +{ +	return strstr(mnt->mnt_opts, opt); +} diff --git a/src/linux/mount.c b/src/linux/mount.c new file mode 100644 index 00000000..61299d48 --- /dev/null +++ b/src/linux/mount.c @@ -0,0 +1,8 @@ +#include <sys/mount.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int mount(const char *special, const char *dir, const char *fstype, unsigned long flags, const void *data) +{ +	return syscall5(__NR_mount, (long)special, (long)dir, (long)fstype, flags, (long)data); +} diff --git a/src/linux/prctl.c b/src/linux/prctl.c new file mode 100644 index 00000000..d5516830 --- /dev/null +++ b/src/linux/prctl.c @@ -0,0 +1,13 @@ +#include <sys/prctl.h> +#include <stdarg.h> +#include "syscall.h" + +int prctl(int op, ...) +{ +	unsigned long x[4]; +	int i; +	va_list ap; +	va_start(ap, op); +	for (i=0; i<4; i++) x[i] = va_arg(ap, unsigned long); +	return syscall5(__NR_prctl, op, x[0], x[1], x[2], x[3]); +} diff --git a/src/linux/reboot.c b/src/linux/reboot.c new file mode 100644 index 00000000..68830d8e --- /dev/null +++ b/src/linux/reboot.c @@ -0,0 +1,8 @@ +#include <sys/reboot.h> +#include <errno.h> + +int reboot(int type) +{ +	errno = ENOSYS; +	return -1; +} diff --git a/src/linux/sbrk.c b/src/linux/sbrk.c new file mode 100644 index 00000000..56f60d1b --- /dev/null +++ b/src/linux/sbrk.c @@ -0,0 +1,7 @@ +#include <stddef.h> +#include "syscall.h" + +void *sbrk(ptrdiff_t inc) +{ +	return (void *)syscall1(__NR_brk, syscall1(__NR_brk, 0)+inc); +} diff --git a/src/linux/sendfile.c b/src/linux/sendfile.c new file mode 100644 index 00000000..bfbc40ae --- /dev/null +++ b/src/linux/sendfile.c @@ -0,0 +1,10 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +ssize_t sendfile(int out_fd, int in_fd, off_t *ofs, size_t count) +{ +	return syscall4(__NR_sendfile, out_fd, in_fd, (long)ofs, count); +} + +LFS64(sendfile); diff --git a/src/linux/setgroups.c b/src/linux/setgroups.c new file mode 100644 index 00000000..2368aa0d --- /dev/null +++ b/src/linux/setgroups.c @@ -0,0 +1,9 @@ +#include <unistd.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int setgroups(int count, const gid_t list[]) +{ +	/* this depends on our gid_t being 32bit */ +	return syscall2(__NR_setgroups32, count, (long)list); +} diff --git a/src/linux/sethostname.c b/src/linux/sethostname.c new file mode 100644 index 00000000..f61e0cb4 --- /dev/null +++ b/src/linux/sethostname.c @@ -0,0 +1,8 @@ +#include <unistd.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int sethostname(const char *name, size_t len) +{ +	return syscall2(__NR_sethostname, (long)name, len); +} diff --git a/src/linux/settimeofday.c b/src/linux/settimeofday.c new file mode 100644 index 00000000..bd7e4104 --- /dev/null +++ b/src/linux/settimeofday.c @@ -0,0 +1,7 @@ +#include <sys/time.h> +#include "syscall.h" + +int settimeofday(const struct timeval *tv, void *tz) +{ +	return syscall2(__NR_settimeofday, (long)tv, 0); +} diff --git a/src/linux/signalfd.c b/src/linux/signalfd.c new file mode 100644 index 00000000..ecda263e --- /dev/null +++ b/src/linux/signalfd.c @@ -0,0 +1,7 @@ +#include <sys/signalfd.h> +#include "syscall.h" + +int signalfd(int fd, const sigset_t *sigs, int flags) +{ +	return syscall3(__NR_signalfd, fd, (long)sigs, 8); +} diff --git a/src/linux/stime.c b/src/linux/stime.c new file mode 100644 index 00000000..ec3ba821 --- /dev/null +++ b/src/linux/stime.c @@ -0,0 +1,7 @@ +#include <sys/time.h> + +int stime(time_t *t) +{ +	struct timeval tv = { .tv_sec = *t, .tv_usec = 0 }; +	return settimeofday(&tv, (void *)0); +} diff --git a/src/linux/swapoff.c b/src/linux/swapoff.c new file mode 100644 index 00000000..f6fa794e --- /dev/null +++ b/src/linux/swapoff.c @@ -0,0 +1,8 @@ +#include <sys/swap.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int swapoff(const char *path) +{ +	return syscall1(__NR_swapoff, (long)path); +} diff --git a/src/linux/swapon.c b/src/linux/swapon.c new file mode 100644 index 00000000..13d2876b --- /dev/null +++ b/src/linux/swapon.c @@ -0,0 +1,8 @@ +#include <sys/swap.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int swapon(const char *path, int flags) +{ +	return syscall2(__NR_swapon, (long)path, flags); +} diff --git a/src/linux/sysinfo.c b/src/linux/sysinfo.c new file mode 100644 index 00000000..98669472 --- /dev/null +++ b/src/linux/sysinfo.c @@ -0,0 +1,9 @@ +#define SYSCALL_STANDALONE +#include "syscall.h" + +struct sysinfo; + +int sysinfo(struct sysinfo *info) +{ +	return syscall1(__NR_sysinfo, (long)info); +} diff --git a/src/linux/umount.c b/src/linux/umount.c new file mode 100644 index 00000000..c35f994d --- /dev/null +++ b/src/linux/umount.c @@ -0,0 +1,8 @@ +#include <sys/mount.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int umount(const char *special) +{ +	return syscall1(__NR_umount, (long)special); +} diff --git a/src/linux/umount2.c b/src/linux/umount2.c new file mode 100644 index 00000000..cab93fd0 --- /dev/null +++ b/src/linux/umount2.c @@ -0,0 +1,8 @@ +#include <sys/mount.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int umount2(const char *special, int flags) +{ +	return syscall2(__NR_umount2, (long)special, flags); +} diff --git a/src/linux/utimes.c b/src/linux/utimes.c new file mode 100644 index 00000000..99a3b2b8 --- /dev/null +++ b/src/linux/utimes.c @@ -0,0 +1,13 @@ +#include <sys/time.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +int utimes(const char *path, const struct timeval times[2]) +{ +	long ktimes[2]; +	if (times) { +		ktimes[0] = times[0].tv_sec; +		ktimes[1] = times[1].tv_sec; +	} +	return syscall2(__NR_utime, (long)path, times ? (long)ktimes : 0); +} diff --git a/src/linux/wait3.c b/src/linux/wait3.c new file mode 100644 index 00000000..dd63707c --- /dev/null +++ b/src/linux/wait3.c @@ -0,0 +1,11 @@ +#include <sys/wait.h> +#include <sys/resource.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +pid_t wait4(pid_t, int *, int, struct rusage *); + +pid_t wait3(int *status, int options, struct rusage *usage) +{ +	return wait4(-1, status, options, usage); +} diff --git a/src/linux/wait4.c b/src/linux/wait4.c new file mode 100644 index 00000000..dda942d3 --- /dev/null +++ b/src/linux/wait4.c @@ -0,0 +1,19 @@ +#include <sys/wait.h> +#include <sys/resource.h> +#include <string.h> +#define SYSCALL_STANDALONE +#include "syscall.h" + +pid_t wait4(pid_t pid, int *status, int options, struct rusage *usage) +{ +	pid_t ret = syscall4(__NR_wait4, pid, (long)status, options, (long)usage); +	/* Fixup kernel time_t... */ +	if (usage) { +		long kusage[4]; +		memcpy(kusage, usage, sizeof kusage); +		memmove((struct timeval *)usage + 2, (long *)usage + 4, sizeof *usage - 2*sizeof(struct timeval)); +		usage->ru_utime = (struct timeval){ kusage[0], kusage[1] }; +		usage->ru_stime = (struct timeval){ kusage[2], kusage[3] }; +	} +	return ret; +} diff --git a/src/locale/catclose.c b/src/locale/catclose.c new file mode 100644 index 00000000..02cd3e5c --- /dev/null +++ b/src/locale/catclose.c @@ -0,0 +1,6 @@ +#include <nl_types.h> + +int catclose (nl_catd catd) +{ +	return 0; +} diff --git a/src/locale/catgets.c b/src/locale/catgets.c new file mode 100644 index 00000000..bbee8986 --- /dev/null +++ b/src/locale/catgets.c @@ -0,0 +1,6 @@ +#include <nl_types.h> + +char *catgets (nl_catd catd, int set_id, int msg_id, const char *s) +{ +	return (char *)s; +} diff --git a/src/locale/catopen.c b/src/locale/catopen.c new file mode 100644 index 00000000..4423c4d9 --- /dev/null +++ b/src/locale/catopen.c @@ -0,0 +1,6 @@ +#include <nl_types.h> + +nl_catd catopen (const char *name, int oflag) +{ +	return (nl_catd)-1; +} diff --git a/src/locale/duplocale.c b/src/locale/duplocale.c new file mode 100644 index 00000000..dd445d46 --- /dev/null +++ b/src/locale/duplocale.c @@ -0,0 +1,11 @@ +#include <stdlib.h> +#include <string.h> +#include "locale_impl.h" + +locale_t duplocale(locale_t old) +{ +	locale_t new; +	new = calloc(1, sizeof *new); +	if (new) memcpy(new, old, sizeof *new); +	return new; +} diff --git a/src/locale/freelocale.c b/src/locale/freelocale.c new file mode 100644 index 00000000..4e089f22 --- /dev/null +++ b/src/locale/freelocale.c @@ -0,0 +1,7 @@ +#include <stdlib.h> +#include "locale_impl.h" + +void freelocale(locale_t l) +{ +	free(l); +} diff --git a/src/locale/iconv.c b/src/locale/iconv.c new file mode 100644 index 00000000..4e46c7e4 --- /dev/null +++ b/src/locale/iconv.c @@ -0,0 +1,568 @@ +#include <iconv.h> +#include <errno.h> +#include <wchar.h> +#include <string.h> +#include <stdlib.h> +#include <limits.h> +#include <stdint.h> + +#define UTF_32BE    000 +#define UTF_16LE    001 +#define UTF_16BE    002 +#define UTF_32LE    003 +#define UCS2BE      004 +#define UCS2LE      005 +#define WCHAR_T     007 + +#define US_ASCII    021 +#define UTF_8       022 +#define LATIN_9     024 +#define TIS_620     025 +#define JIS_0201    026 + +#define EUC         031 +#define EUC_TW      032 +#define SHIFT_JIS   033 +#define BIG5        034 +#define GBK         035 + +/* FIXME: these are not implemented yet + * EUC:   A1-FE A1-FE + * GBK:   81-FE 40-7E,80-FE + * Big5:  A1-FE 40-7E,A1-FE + */ + +/* Definitions of charmaps. Each charmap consists of: + * 1. Empty-string-terminated list of null-terminated aliases. + * 2. Special type code or bits per character. + * 3. Number of elided entries (128 for specials). + * 4. Character table (size determined by fields 2 and 3). */ + +static const unsigned char charmaps[] = +"utf8\0\0\022\x80" +"wchart\0\0\007\x80" + +"ucs2\0ucs2be\0\0\004\x80" +"ucs2le\0\0\005\x80" + +"utf16\0utf16be\0\0\002\x80" +"utf16le\0\0\001\x80" + +"ucs4\0ucs4be\0utf32\0utf32be\0\0\000\x80" +"ucs4le\0utf32le\0\0\003\x80" + +"ascii\0iso646\0usascii\0\0\021\x80" +"latin1\0iso88591\0\0\x09\x80" +"latin9\0iso885915\0\0\024\x80" +"tis620\0iso885911\0\0\025\x80" +"jis0201\0\0\026\x80" + +"iso88592\0\0\x0a\x21" +"\x04\x61\x1b\x14\x29\x3d\x69\x75\x0a\x2a" +"\x60\x79\x45\x56\x5e\xad\xf4\xb5\x17\x2c" +"\x05\x6d\x2b\x14\x2d\x3e\x6d\x75\x2c\x2e" +"\x61\x7d\x55\x96\x5e\xdd\xfa\xc5\x17\x55" +"\xc1\x08\x23\x10\x31\x39\x19\x74\x0c\x43" +"\xc9\x60\xb4\x8c\x46\xcd\x38\xe3\x10\x44" +"\x43\x1d\x35\x0d\x35\x50\x59\x73\x0d\x56" +"\x6e\x69\x03\x17\x37\xdd\x88\xf5\x4d\x55" +"\xe1\x88\x33\x10\x39\x3a\x1d\x74\x4e\x43" +"\xe9\x64\xb4\xce\x46\xed\xb8\xf3\x50\x44" +"\x44\x21\x35\x0f\x3d\x51\xd9\x73\x4f\x56" +"\x6f\xe9\x13\x17\x3f\xfd\x8c\x95\x2d" + +"iso88593\0\0\x0a\x21" +"\x26\x61\x3b\x0a\x29\x00\x90\x74\x0a\x2a" +"\x30\x79\xe5\x11\x4d\xad\x00\xb0\x17\x2c" +"\x27\xc9\x32\x0b\x2d\xb5\x94\x74\x0b\x2e" +"\x31\x7d\xf5\x51\x4d\xbd\x00\xc0\x17\x30" +"\xc1\x08\x03\x00\x31\x0a\x21\x74\x0c\x32" +"\xc9\x28\xb3\x0c\x33\xcd\x38\xf3\x0c\x00" +"\xd1\x48\x33\x0d\x35\x20\x59\x73\x0d\x47" +"\xd9\x68\xb3\x0d\x37\x6c\x71\xf5\x0d\x38" +"\xe1\x88\x03\x00\x39\x0b\x25\x74\x0e\x3a" +"\xe9\xa8\xb3\x0e\x3b\xed\xb8\xf3\x0e\x00" +"\xf1\xc8\x33\x0f\x3d\x21\xd9\x73\x4f\x47" +"\xf9\xe8\xb3\x0f\x3f\x6d\x75\x95\x2d" + +"iso88594\0\0\x0a\x21" +"\x04\xe1\x64\x15\x29\x28\xed\x74\x0a\x2a" +"\x60\x49\x24\x92\x59\xad\xf4\xf5\x0a\x2c" +"\x05\x6d\x7b\x15\x2d\x29\xf1\x74\x2c\x2e" +"\x61\x4d\x34\xd2\x59\x4a\xf9\xb5\x14\x40" +"\xc1\x08\x33\x0c\x31\xc5\x18\xe3\x12\x43" +"\xc9\x60\xb4\x8c\x45\xcd\x38\xa3\x12\x44" +"\x45\x31\x65\x13\x35\xd5\x58\x73\x0d\x36" +"\x72\x69\xb3\x0d\x37\x68\xa9\xf5\x4d\x40" +"\xe1\x88\x33\x0e\x39\xe5\x98\xf3\x52\x43" +"\xe9\x64\xb4\xce\x45\xed\xb8\xb3\x52\x44" +"\x46\x35\x75\x13\x3d\xf5\xd8\x73\x0f\x3e" +"\x73\xe9\xb3\x0f\x3f\x69\xad\x95\x2d" + +"iso88595\0\0\x0e\x21" +"\x01\x84\x00\x31\x40\x10\x10\x05\x84\x01" +"\x71\x40\x20\x10\x09\x84\x02\xb1\x40\x30" +"\x10\xad\x80\x03\xf1\x40\x40\x10\x11\x84" +"\x04\x31\x41\x50\x10\x15\x84\x05\x71\x41" +"\x60\x10\x19\x84\x06\xb1\x41\x70\x10\x1d" +"\x84\x07\xf1\x41\x80\x10\x21\x84\x08\x31" +"\x42\x90\x10\x25\x84\x09\x71\x42\xa0\x10" +"\x29\x84\x0a\xb1\x42\xb0\x10\x2d\x84\x0b" +"\xf1\x42\xc0\x10\x31\x84\x0c\x31\x43\xd0" +"\x10\x35\x84\x0d\x71\x43\xe0\x10\x39\x84" +"\x0e\xb1\x43\xf0\x10\x3d\x84\x0f\xf1\x43" +"\x00\x11\x41\x84\x10\x31\x44\x10\x11\x45" +"\x84\x11\x71\x44\x20\x11\x49\x84\x12\xb1" +"\x44\x30\x11\x4d\x84\x13\xf1\x44\x58\x84" +"\x51\x84\x14\x31\x45\x50\x11\x55\x84\x15" +"\x71\x45\x60\x11\x59\x84\x16\xb1\x45\x70" +"\x11\xa7\x80\x17\xf1\x45\x00" + +"iso88596\0\0\x0b\x21" +"\x00\x00\x00\x00\x48\x01\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x18\xdc\x0a\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\xc0\x86\x01\x00\x00" +"\x00\x7c\x18\x00\x21\x16\xf1\x88\x49\x5c" +"\x62\x13\x9f\x18\xc5\x29\x56\xf1\x8a\x59" +"\xdc\x62\x17\xbf\x18\xc6\x31\x96\xf1\x8c" +"\x69\x5c\x63\x1b\xdf\x18\xc7\x39\xd6\x31" +"\x00\x00\x00\x00\x00\x00\x00\xc8\x41\x16" +"\xf2\x90\x89\x5c\x64\x23\x1f\x19\xc9\x49" +"\x56\xf2\x92\x99\xdc\x64\x27\x3f\x19\xca" +"\x51\x96\x32\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00" + +"iso88597\0\0\x0e\x21" +"\x18\x60\x06\x38\x0a\xb0\x82\xaf\xa0\x29" +"\x70\x0a\xa0\x02\xa9\x80\xde\xb0\x0a\xb0" +"\x02\xad\x00\x00\x50\x01\xc2\x02\xb1\x80" +"\x2c\x30\x0b\x10\x0e\x85\x83\xe1\x70\x0b" +"\x20\x0e\x89\x83\xe2\xb0\x0b\x30\x0e\xbd" +"\x80\xe3\xf0\x38\x40\x0e\x91\x83\xe4\x30" +"\x39\x50\x0e\x95\x83\xe5\x70\x39\x60\x0e" +"\x99\x83\xe6\xb0\x39\x70\x0e\x9d\x83\xe7" +"\xf0\x39\x80\x0e\xa1\x03\x00\x30\x3a\x90" +"\x0e\xa5\x83\xe9\x70\x3a\xa0\x0e\xa9\x83" +"\xea\xb0\x3a\xb0\x0e\xad\x83\xeb\xf0\x3a" +"\xc0\x0e\xb1\x83\xec\x30\x3b\xd0\x0e\xb5" +"\x83\xed\x70\x3b\xe0\x0e\xb9\x83\xee\xb0" +"\x3b\xf0\x0e\xbd\x83\xef\xf0\x3b\x00\x0f" +"\xc1\x83\xf0\x30\x3c\x10\x0f\xc5\x83\xf1" +"\x70\x3c\x20\x0f\xc9\x83\xf2\xb0\x3c\x30" +"\x0f\xcd\x83\xf3\x00\x00\x00" + +"iso88598\0\0\x0e\x21" +"\x00\x80\x28\x30\x0a\x90\x02\xa5\x80\x29" +"\x70\x0a\xa0\x02\xa9\xc0\x35\xb0\x0a\xb0" +"\x02\xad\x80\x2b\xf0\x0a\xc0\x02\xb1\x80" +"\x2c\x30\x0b\xd0\x02\xb5\x80\x2d\x70\x0b" +"\xe0\x02\xb9\xc0\x3d\xb0\x0b\xf0\x02\xbd" +"\x80\x2f\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x70\x01" +"\x42\x17\xd1\x85\x74\x31\x5d\x50\x17\xd5" +"\x85\x75\x71\x5d\x60\x17\xd9\x85\x76\xb1" +"\x5d\x70\x17\xdd\x85\x77\xf1\x5d\x80\x17" +"\xe1\x85\x78\x31\x5e\x90\x17\xe5\x85\x79" +"\x71\x5e\xa0\x17\xe9\x85\x7a\x01\x00\x00" +"\x00\x0e\xe0\x03\x08\x00\x00" + +"iso88599\0\0\x09\x50" +"\x1e\xa3\x49\x9b\x46\xad\x9a\xb5\x6b\xd8" +"\xb2\x69\xdb\xc6\x0d\xa6\xd7\x6f\xe0\xc2" +"\x89\x1b\x47\xae\x9c\xb9\x73\xe8\xd2\xa9" +"\x5b\xc7\xae\x9d\xbb\x77\x1f\xe3\xc9\x9b" +"\x47\xaf\x9e\xbd\x7b\xf8\xf2\xe9\xdb\xc7" +"\x2f\xe6\xd7\x7f" + +"iso885910\0\0\x0e\x21" +"\x04\x81\x44\x20\x12\xa8\x04\x28\x81\x4d" +"\x70\x0a\xec\x04\x10\x01\x58\x60\x16\xf4" +"\x05\xad\x80\x5a\xa0\x14\xc0\x02\x05\xc1" +"\x44\x30\x12\xac\x04\x29\xc1\x4d\x70\x0b" +"\xf0\x04\x11\x41\x58\x70\x16\xf8\x05\x15" +"\xe0\x5a\xb0\x14\x00\x04\xc1\x80\x30\x30" +"\x0c\x10\x03\xc5\x80\x31\xe0\x12\x30\x04" +"\xc9\x00\x46\xb0\x0c\x58\x04\xcd\x80\x33" +"\xf0\x0c\x40\x03\x45\x01\x53\x30\x0d\x50" +"\x03\xd5\x80\x35\x80\x16\x60\x03\x72\x81" +"\x36\xb0\x0d\x70\x03\xdd\x80\x37\xf0\x0d" +"\x04\x04\xe1\x80\x38\x30\x0e\x90\x03\xe5" +"\x80\x39\xf0\x12\x34\x04\xe9\x40\x46\xb0" +"\x0e\x5c\x04\xed\x80\x3b\xf0\x0e\xc0\x03" +"\x46\x41\x53\x30\x0f\xd0\x03\xf5\x80\x3d" +"\x90\x16\xe0\x03\x73\x81\x3e\xb0\x0f\xf0" +"\x03\xfd\x80\x3f\x80\x13\x00" + +"iso885913\0\0\x0e\x21" +"\x1d\xa0\x28\x30\x0a\x90\x02\x1e\xa0\x29" +"\x70\x0a\x60\x03\xa9\x80\x55\xb0\x0a\xb0" +"\x02\xad\x80\x2b\x60\x0c\xc0\x02\xb1\x80" +"\x2c\x30\x0b\x70\x80\xb5\x80\x2d\x70\x0b" +"\xe0\x03\xb9\xc0\x55\xb0\x0b\xf0\x02\xbd" +"\x80\x2f\x60\x0e\x10\x04\x2e\x01\x40\x60" +"\x10\x10\x03\xc5\x00\x46\x20\x11\x30\x04" +"\xc9\x40\x5e\x60\x11\x88\x04\x36\x81\x4a" +"\xb0\x13\x80\x05\x43\x41\x51\x30\x0d\x30" +"\x05\xd5\x80\x35\x70\x0d\xc8\x05\x41\x81" +"\x56\xa0\x16\x70\x03\x7b\x41\x5f\xf0\x0d" +"\x14\x04\x2f\x41\x40\x70\x10\x90\x03\xe5" +"\x40\x46\x30\x11\x34\x04\xe9\x80\x5e\x70" +"\x11\x8c\x04\x37\xc1\x4a\xc0\x13\x84\x05" +"\x44\x81\x51\x30\x0f\x34\x05\xf5\x80\x3d" +"\x70\x0f\xcc\x05\x42\xc1\x56\xb0\x16\xf0" +"\x03\x7c\x81\x5f\x90\x01\x02" + +"iso885914\0\0\x0d\x21" +"\x02\x7e\xc0\x8f\x02\x85\xb0\x10\x14\xfc" +"\x29\x00\xf4\xa9\x40\xd0\x2f\x78\x79\xdf" +"\x0a\x5c\x01\x5e\xf0\xf0\x1f\x1e\x24\x84" +"\x04\x20\x1f\xe4\x6d\x81\x95\x0f\xf4\x57" +"\x7e\xd0\x83\xf9\x79\x4f\xe8\x0b\x7d\x98" +"\x07\x06\xc1\x40\x18\x0c\x03\x62\x50\x0c" +"\x8c\xc1\x31\x40\x06\xc9\x40\x19\x2c\x03" +"\x66\xd0\x0c\x9c\xc1\x33\xa0\x0b\xd1\x40" +"\x1a\x4c\x03\x6a\x50\x0d\xac\x81\x9a\xc7" +"\x06\xd9\x40\x1b\x6c\x03\x6e\xd0\x0d\xec" +"\xc2\x37\x00\x07\xe1\x40\x1c\x8c\x03\x72" +"\x50\x0e\xcc\xc1\x39\x40\x07\xe9\x40\x1d" +"\xac\x03\x76\xd0\x0e\xdc\xc1\x3b\xa8\x0b" +"\xf1\x40\x1e\xcc\x03\x7a\x50\x0f\xec\xc1" +"\x9a\xc7\x07\xf9\x40\x1f\xec\x03\x7e\xd0" +"\x0f\xee\xc2\x3f\x00" + +"iso885916\0\0\x0e\x21" +"\x04\x41\x41\x10\x14\xb0\x82\x1e\x20\x58" +"\x70\x0a\x84\x05\xa9\x00\x86\xb0\x0a\xe4" +"\x05\xad\x80\x5e\xb0\x17\xc0\x02\xb1\x00" +"\x43\x20\x14\xf4\x05\x1d\xa0\x2d\x70\x0b" +"\xf8\x05\x0d\x41\x86\xb0\x0b\x48\x05\x53" +"\x01\x5e\xc0\x17\x00\x03\xc1\x80\x30\x20" +"\x10\x10\x03\x06\x81\x31\x70\x0c\x20\x03" +"\xc9\x80\x32\xb0\x0c\x30\x03\xcd\x80\x33" +"\xf0\x0c\x40\x04\x43\x81\x34\x30\x0d\x50" +"\x03\x50\x81\x35\xa0\x15\xc0\x05\xd9\x80" +"\x36\xb0\x0d\x70\x03\x18\x81\x86\xf0\x0d" +"\x80\x03\xe1\x80\x38\x30\x10\x90\x03\x07" +"\x81\x39\x70\x0e\xa0\x03\xe9\x80\x3a\xb0" +"\x0e\xb0\x03\xed\x80\x3b\xf0\x0e\x44\x04" +"\x44\x81\x3c\x30\x0f\xd0\x03\x51\x81\x3d" +"\xb0\x15\xc4\x05\xf9\x80\x3e\xb0\x0f\xf0" +"\x03\x19\xc1\x86\xf0\x0f\x00" + +"windows1252\0\0\x0e\x00" +"\xac\x20\x00\xa0\x01\x4a\x06\x1e\xa0\x09" +"\x08\x02\x86\x80\xc6\x02\x0c\x08\x16\xe4" +"\x80\x52\x01\x00\xd0\x17\x00\x00\x00\x00" +"\x06\x98\x01\x72\x80\x1d\xa0\x08\x38\x01" +"\x52\x80\xdc\x82\x48\x18\x16\xe8\x80\x53" +"\x01\x00\xe0\x17\xe0\x05\xa0\x40\x28\x20" +"\x0a\x8c\x02\xa4\x40\x29\x60\x0a\x9c\x02" +"\xa8\x40\x2a\xa0\x0a\xac\x02\xac\x40\x2b" +"\xe0\x0a\xbc\x02\xb0\x40\x2c\x20\x0b\xcc" +"\x02\xb4\x40\x2d\x60\x0b\xdc\x02\xb8\x40" +"\x2e\xa0\x0b\xec\x02\xbc\x40\x2f\xe0\x0b" +"\xfc\x02\xc0\x40\x30\x20\x0c\x0c\x03\xc4" +"\x40\x31\x60\x0c\x1c\x03\xc8\x40\x32\xa0" +"\x0c\x2c\x03\xcc\x40\x33\xe0\x0c\x3c\x03" +"\xd0\x40\x34\x20\x0d\x4c\x03\xd4\x40\x35" +"\x60\x0d\x5c\x03\xd8\x40\x36\xa0\x0d\x6c" +"\x03\xdc\x40\x37\xe0\x0d\x7c\x03\xe0\x40" +"\x38\x20\x0e\x8c\x03\xe4\x40\x39\x60\x0e" +"\x9c\x03\xe8\x40\x3a\xa0\x0e\xac\x03\xec" +"\x40\x3b\xe0\x0e\xbc\x03\xf0\x40\x3c\x20" +"\x0f\xcc\x03\xf4\x40\x3d\x60\x0f\xdc\x03" +"\xf8\x40\x3e\xa0\x0f\xec\x03\xfc\x40\x3f" +"\xe0\x0f\xfc\x03" +; + + + +static int fuzzycmp(const char *a, const char *b) +{ +	for (; *a && *b; a++, b++) { +		while (*a && (*a|32U)-'a'>26 && *a-'0'>10U) a++; +		if ((*a|32U) != *b) return 1; +	} +	return *a != *b; +} + +static int find_charmap(const char *name) +{ +	const unsigned char *s; +	for (s=charmaps; *s; ) { +		if (!fuzzycmp(name, s)) { +			for (; *s; s+=strlen(s)+1); +			return s+1-charmaps; +		} +		s += strlen(s)+1; +		if (!*s) s += ((128-s[2])*s[1]+7)/8 + 3; +	} +	return -1; +} + +iconv_t iconv_open(const char *to, const char *from) +{ +	int f, t; + +	if ((t = find_charmap(to)) < 0 || (f = find_charmap(from)) < 0) { +		errno = EINVAL; +		return (iconv_t)-1; +	} + +	return (void *)(f<<16 | t); +} + +int iconv_close(iconv_t cd) +{ +	return 0; +} + +static unsigned get_16(const unsigned char *s, int e) +{ +	e &= 1; +	return s[e]<<8 | s[1-e]; +} + +static void put_16(unsigned char *s, unsigned c, int e) +{ +	e &= 1; +	s[e] = c>>8; +	s[1-e] = c; +} + +static unsigned get_32(const unsigned char *s, int e) +{ +	return s[e]+0U<<24 | s[e^1]<<16 | s[e^2]<<8 | s[e^3]; +} + +static void put_32(unsigned char *s, unsigned c, int e) +{ +	s[e^0] = c>>24; +	s[e^1] = c>>16; +	s[e^2] = c>>8; +	s[e^3] = c; +} + + + +#define GET_MAPPING(m, i, n) ( (1<<(n))-1 & ( \ +	(m)[(i)*(n)/8] >> ((n)%8*(i)%8) | \ +	(m)[(i)*(n)/8+1] << 8-((n)%8*(i)%8) | \ +	(m)[(i)*(n)/8+2] << 16-((n)%8*(i)%8)     ) ) + +static unsigned get_mapping(const unsigned char *m, unsigned c, unsigned n) +{ +	switch (n) { +	default: +	case 9:  return m[c*9/8]>>c%8 | m[c*9/8+1]<<8-c%8 & (1<<n)-1; +	case 10: return m[c*10/8]>>2*c%8 | m[c*10/8+1]<<8-2*c%8 & (1<<n)-1; +	case 11: return GET_MAPPING(m, c, 11); +	case 13: return GET_MAPPING(m, c, 13); +	case 14: return GET_MAPPING(m, c, 14); +	} +} + +/* Adapt as needed */ +#define mbrtowc_utf8 mbrtowc +#define wctomb_utf8 wctomb + +#include <stdio.h> +size_t iconv(iconv_t cd0, char **in, size_t *inb, char **out, size_t *outb) +{ +	size_t x=0; +	unsigned long cd = (unsigned long)cd0; +	unsigned to = cd & 0xffff; +	unsigned from = cd >> 16; +	const unsigned char *map = charmaps+from+2; +	const unsigned char *tomap = charmaps+to+2; +	mbstate_t st = {0}; +	wchar_t wc; +	unsigned c, d; +	size_t k, l; +	int err; +	unsigned elide = map[-1] + 128; +	unsigned toelide = tomap[-1] + 128; +	unsigned char type = map[-2]; +	unsigned char totype = tomap[-2]; + +	if (!in || !*in || !*inb) return 0; + +	for (; *inb; *in+=l, *inb-=l) { +		c = *(unsigned char *)*in; +		l = 1; +		if (type < 8 || c >= 0x80) switch (type) { +		case UTF_8: +			l = mbrtowc_utf8(&wc, *in, *inb, &st); +			if (!l) l++; +			else if (l == (size_t)-1) goto ilseq; +			else if (l == (size_t)-2) goto starved; +			c = wc; +			break; +		case LATIN_9: +			if ((unsigned)c - 0xa4 <= 0xbe - 0xa4) { +				static const unsigned char map[] = { +					0, 0x60, 0, 0x61, 0, 0, 0, 0, 0, 0, 0, +					0, 0, 0, 0, 0x7d, 0, 0, 0, 0x7e, 0, 0, 0, +					0x52, 0x53, 0x78 +				}; +				if (c == 0xa4) c = 0x20ac; +				else if (map[c-0xa5]) c = 0x100 | map[c-0xa5]; +			} +			break; +		case TIS_620: +			if (c >= 0xa1) c += 0x0e01-0xa1; +			break; +		case JIS_0201: +			if (c >= 0xa1) +				if (c <= 0xdf) c += 0xff61-0xa1; +				else goto ilseq; +			break; +		case 9: case 10: case 11: case 13: case 14: +			if (c < elide) break; +			c = get_mapping(map, c-elide, type); +			if (!c) { +		case US_ASCII: +				goto ilseq; +			} +			break; +		case WCHAR_T: +			l = sizeof(wchar_t); +			if (*inb < l) goto starved; +			c = *(wchar_t *)*in; +			if (0) { +		case UTF_32BE: +		case UTF_32LE: +			l = 4; +			if (*inb < 4) goto starved; +			c = get_32(*in, type); +			} +			if (c-0xd800u < 0x800u || c >= 0x110000u) goto ilseq; +			break; +		case UCS2BE: +		case UCS2LE: +		case UTF_16BE: +		case UTF_16LE: +			l = 2; +			if (*inb < 2) goto starved; +			c = get_16(*in, type); +			if ((unsigned)(c-0xdc00) < 0x400) goto ilseq; +			if ((unsigned)(c-0xd800) < 0x400) { +				if (type-UCS2BE < 2U) goto ilseq; +				l = 4; +				if (*inb < 4) goto starved; +				d = get_16(*in + 2, from); +				if ((unsigned)(c-0xdc00) >= 0x400) goto ilseq; +				c = ((c-0xd800)<<10) | (d-0xdc00); +			} +			break; +		} + +		switch (totype) { +		case WCHAR_T: +			if (*outb < sizeof(wchar_t)) goto toobig; +			*(wchar_t *)*out = c; +			*out += sizeof(wchar_t); +			*outb -= sizeof(wchar_t); +			break; +		case UTF_8: +			if (*outb < 4) { +				char tmp[4]; +				k = wctomb_utf8(tmp, c); +				if (*outb < k) goto toobig; +				memcpy(*out, tmp, k); +			} else k = wctomb_utf8(*out, c); +			*out += k; +			*outb -= k; +			break; +		case TIS_620: +			if (c-0xe01u <= 0xff-0xa1) +				c -= 0xe01-0xa1; +			else if (c >= 0xa1) +				goto ascii; +			goto revout; +		case JIS_0201: +			if (c-0xff61u <= 0xdf-0xa1) +				c -= 0xff61-0xa1; +			else if (c >= 0xa1) +				goto ascii; +			goto revout; +		case LATIN_9: +			if (c == 0x20ac) { +				c=0xa4; +			} else if (c-0x150u<=0x12 && (1<<c-0x150 & 0x3000c)) { +				static const unsigned char map[] = +					{ 0xa6,0xa8,0xbc,0xbd }; +				c = map[c&3]; +			} else if (c-0x178u<=0x7 && (1<<c-0x178 & 0x61)) { +				static const unsigned char map[] = +					{ 0xbe,0,0,0,0,0xb4,0xb8 }; +				c = map[c&7]; +			} else if (c>0x100 || +				c-0xa5u<=0xbeu-0xa5 +				&& (1<<c-0xa5 & 0x388800a)) +		case US_ASCII: ascii: +			if (c > 0x7f) x++, c='*'; +		case 9: case 10: case 11: case 13: case 14: +			if (*outb < 1) goto toobig; +			if (c < toelide) { +			revout: +				*(*out)++ = c; +				*outb -= 1; +				break; +			} +			for (d=0; d<256-toelide; d++) { +				if (c == get_mapping(tomap, d, totype)) { +					c = d + toelide; +					goto revout; +				} +			} +			x++; +			c = '*'; +			goto revout; +		case UCS2BE: +		case UCS2LE: +		case UTF_16BE: +		case UTF_16LE: +			if (c < 0x10000) { +				if (*outb < 2) goto toobig; +				put_16(*out, c, totype); +				*out += 2; +				*outb -= 2; +				break; +			} +			if (type-UCS2BE < 2U) goto ilseq; +			if (*outb < 4) goto toobig; +			put_16(*out, (c>>10)|0xd800, totype); +			put_16(*out + 2, (c&0x3ff)|0xdc00, totype); +			*out += 4; +			*outb -= 4; +			break; +		case UTF_32BE: +		case UTF_32LE: +			if (*outb < 4) goto toobig; +			put_32(*out, c, totype); +			*out += 4; +			*outb -= 4; +			break; +		} +	} +	return x; +ilseq: +	err = EILSEQ; +	x = -1; +	goto end; +toobig: +	err = E2BIG; +	goto end; +starved: +	err = EINVAL; +end: +	errno = err; +	return x; +} diff --git a/src/locale/intl.c b/src/locale/intl.c new file mode 100644 index 00000000..964f7da1 --- /dev/null +++ b/src/locale/intl.c @@ -0,0 +1,67 @@ +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <errno.h> + +char *gettext(const char *msgid) +{ +	return (char *) msgid; +} + +char *dgettext(const char *domainname, const char *msgid) +{ +	return (char *) msgid; +} + +char *dcgettext(const char *domainname, const char *msgid, int category) +{ +	return (char *) msgid; +} + +char *ngettext(const char *msgid1, const char *msgid2, unsigned long int n) +{ +	return (char *) ((n == 1) ? msgid1 : msgid2); +} + +char *dngettext(const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n) +{ +	return (char *) ((n == 1) ? msgid1 : msgid2); +} + +char *dcngettext(const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n, int category) +{ +	return (char *) ((n == 1) ? msgid1 : msgid2); +} + +char *textdomain(const char *domainname) +{ +	static const char default_str[] = "messages"; + +	if (domainname && *domainname && strcmp(domainname, default_str)) { +		errno = EINVAL; +		return NULL; +	} +	return (char *) default_str; +} + +char *bindtextdomain(const char *domainname, const char *dirname) +{ +	static const char dir[] = "/"; + +	if (!domainname || !*domainname +		|| (dirname && ((dirname[0] != '/') || dirname[1])) +		) { +		errno = EINVAL; +		return NULL; +	} + +	return (char *) dir; +} + +char *bind_textdomain_codeset(const char *domainname, const char *codeset) +{ +	if (!domainname || !*domainname || (codeset && strcasecmp(codeset, "UTF-8"))) { +		errno = EINVAL; +	} +	return NULL; +} diff --git a/src/locale/isalnum_l.c b/src/locale/isalnum_l.c new file mode 100644 index 00000000..b8a6eef3 --- /dev/null +++ b/src/locale/isalnum_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isalnum_l(int c, locale_t l) +{ +	return isalnum(c); +} diff --git a/src/locale/isalpha_l.c b/src/locale/isalpha_l.c new file mode 100644 index 00000000..2e1205c6 --- /dev/null +++ b/src/locale/isalpha_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isalpha_l(int c, locale_t l) +{ +	return isalpha(c); +} diff --git a/src/locale/isblank_l.c b/src/locale/isblank_l.c new file mode 100644 index 00000000..27479aa1 --- /dev/null +++ b/src/locale/isblank_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isblank_l(int c, locale_t l) +{ +	return isblank(c); +} diff --git a/src/locale/iscntrl_l.c b/src/locale/iscntrl_l.c new file mode 100644 index 00000000..ca596fa9 --- /dev/null +++ b/src/locale/iscntrl_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int iscntrl_l(int c, locale_t l) +{ +	return iscntrl(c); +} diff --git a/src/locale/isdigit_l.c b/src/locale/isdigit_l.c new file mode 100644 index 00000000..c8ae7bd3 --- /dev/null +++ b/src/locale/isdigit_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isdigit_l(int c, locale_t l) +{ +	return isdigit(c); +} diff --git a/src/locale/isgraph_l.c b/src/locale/isgraph_l.c new file mode 100644 index 00000000..713a86e6 --- /dev/null +++ b/src/locale/isgraph_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isgraph_l(int c, locale_t l) +{ +	return isgraph(c); +} diff --git a/src/locale/islower_l.c b/src/locale/islower_l.c new file mode 100644 index 00000000..25ec97a1 --- /dev/null +++ b/src/locale/islower_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int islower_l(int c, locale_t l) +{ +	return islower(c); +} diff --git a/src/locale/isprint_l.c b/src/locale/isprint_l.c new file mode 100644 index 00000000..79ef3514 --- /dev/null +++ b/src/locale/isprint_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isprint_l(int c, locale_t l) +{ +	return isprint(c); +} diff --git a/src/locale/ispunct_l.c b/src/locale/ispunct_l.c new file mode 100644 index 00000000..1c0bd046 --- /dev/null +++ b/src/locale/ispunct_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int ispunct_l(int c, locale_t l) +{ +	return ispunct(c); +} diff --git a/src/locale/isspace_l.c b/src/locale/isspace_l.c new file mode 100644 index 00000000..e1a0efed --- /dev/null +++ b/src/locale/isspace_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isspace_l(int c, locale_t l) +{ +	return isspace(c); +} diff --git a/src/locale/isupper_l.c b/src/locale/isupper_l.c new file mode 100644 index 00000000..11ba7036 --- /dev/null +++ b/src/locale/isupper_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isupper_l(int c, locale_t l) +{ +	return isupper(c); +} diff --git a/src/locale/isxdigit_l.c b/src/locale/isxdigit_l.c new file mode 100644 index 00000000..68649d09 --- /dev/null +++ b/src/locale/isxdigit_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int isxdigit_l(int c, locale_t l) +{ +	return isxdigit(c); +} diff --git a/src/locale/langinfo.c b/src/locale/langinfo.c new file mode 100644 index 00000000..f7f56012 --- /dev/null +++ b/src/locale/langinfo.c @@ -0,0 +1,58 @@ +#include <locale.h> +#include <langinfo.h> + +static const char c_time[] = +	"Sun\0" "Mon\0" "Tue\0" "Wed\0" "Thu\0" "Fri\0" "Sat\0" +	"Sunday\0" "Monday\0" "Tuesday\0" "Wednesday\0" +	"Thursday\0" "Friday\0" "Saturday\0" +	"Jan\0" "Feb\0" "Mar\0" "Apr\0" "May\0" "Jun\0" +	"Jul\0" "Aug\0" "Sep\0" "Oct\0" "Nov\0" "Dec\0" +	"January\0"   "February\0" "March\0"    "April\0" +	"May\0"       "June\0"     "July\0"     "August\0" +	"September\0" "October\0"  "November\0" "December\0" +	"AM\0" "PM\0" +	"%a %b %e %T %Y\0" +	"%m/%d/%y\0" +	"%H:%M:%S\0" +	"%I:%M:%S %p\0" +	"\0" +	"%m/%d/%y\0" +	"0123456789" +	"%a %b %e %T %Y\0" +	"%H:%M:%S"; + +static const char c_messages[] = "^[yY]\0" "^[nN]"; +static const char c_numeric[] = ".\0" ""; + +const char *__langinfo(nl_item item) +{ +	int cat = item >> 16; +	int idx = item & 65535; +	const char *str; + +	if (item == CODESET) return "UTF-8"; +	 +	switch (cat) { +	case LC_NUMERIC: +		if (idx > 1) return NULL; +		str = c_numeric; +		break; +	case LC_TIME: +		if (idx > 0x31) return NULL; +		str = c_time; +		break; +	case LC_MONETARY: +		if (idx > 0) return NULL; +		str = ""; +		break; +	case LC_MESSAGES: +		if (idx > 1) return NULL; +		str = c_messages; +		break; +	default: +		return NULL; +	} + +	for (; idx; idx--, str++) for (; *str; str++); +	return str; +} diff --git a/src/locale/localeconv.c b/src/locale/localeconv.c new file mode 100644 index 00000000..d79d1c07 --- /dev/null +++ b/src/locale/localeconv.c @@ -0,0 +1,22 @@ +#include <locale.h> +#include <string.h> +#include <stdlib.h> + +struct lconv *localeconv(void) +{ +	static struct lconv *posix_lconv; +	if (posix_lconv) return posix_lconv; +	posix_lconv = malloc(sizeof *posix_lconv); +	memset(posix_lconv, -1, sizeof *posix_lconv); +	posix_lconv->decimal_point = "."; +	posix_lconv->thousands_sep = ""; +	posix_lconv->grouping = "\xff"; +	posix_lconv->int_curr_symbol = ""; //"\xc2\xa4"; +	posix_lconv->currency_symbol = ""; +	posix_lconv->mon_decimal_point = ""; +	posix_lconv->mon_thousands_sep = ""; +	posix_lconv->mon_grouping = "\xff"; +	posix_lconv->positive_sign = ""; // "+"; +	posix_lconv->negative_sign = ""; // "-"; +	return posix_lconv; +} diff --git a/src/locale/newlocale.c b/src/locale/newlocale.c new file mode 100644 index 00000000..986e796f --- /dev/null +++ b/src/locale/newlocale.c @@ -0,0 +1,11 @@ +#include <stdlib.h> +#include <string.h> +#include "locale_impl.h" + +locale_t newlocale(int mask, const char *name, locale_t base) +{ +	if (*name && strcmp(name, "C") && strcmp(name, "POSIX")) +		return 0; +	if (!base) base = calloc(1, sizeof *base); +	return base; +} diff --git a/src/locale/nl_langinfo.c b/src/locale/nl_langinfo.c new file mode 100644 index 00000000..bb3a2c46 --- /dev/null +++ b/src/locale/nl_langinfo.c @@ -0,0 +1,13 @@ +#include <langinfo.h> + +// FIXME: other items + +char *nl_langinfo(nl_item item) +{ +	switch (item) { +	case CODESET: +		return "UTF-8"; +	default: +		return ""; +	} +} diff --git a/src/locale/setlocale.c b/src/locale/setlocale.c new file mode 100644 index 00000000..28f29b80 --- /dev/null +++ b/src/locale/setlocale.c @@ -0,0 +1,9 @@ +#include <locale.h> + +char *setlocale(int category, const char *locale) +{ +	/* Note: plain "C" would be better, but puts some broken +	 * software into legacy 8-bit-codepage mode, ignoring +	 * the standard library's multibyte encoding */ +	return "C.UTF-8"; +} diff --git a/src/locale/strcoll.c b/src/locale/strcoll.c new file mode 100644 index 00000000..30bccd62 --- /dev/null +++ b/src/locale/strcoll.c @@ -0,0 +1,6 @@ +#include <string.h> + +int strcoll(const char *l, const char *r) +{ +	return strcmp(l, r); +} diff --git a/src/locale/strxfrm.c b/src/locale/strxfrm.c new file mode 100644 index 00000000..8f123399 --- /dev/null +++ b/src/locale/strxfrm.c @@ -0,0 +1,9 @@ +#include <string.h> + +/* collate only by code points */ +size_t strxfrm(char *dest, const char *src, size_t n) +{ +	size_t l = strlen(src); +	if (n > l) strcpy(dest, src); +	return l; +} diff --git a/src/locale/tmp b/src/locale/tmp new file mode 100644 index 00000000..aa71779f --- /dev/null +++ b/src/locale/tmp @@ -0,0 +1,390 @@ +"iso88591\0\x08\x80" +"iso88592\0\x0a\x21" +"\x04\x61\x1b\x14\x29\x3d\x69\x75\x0a\x2a" +"\x60\x79\x45\x56\x5e\xad\xf4\xb5\x17\x2c" +"\x05\x6d\x2b\x14\x2d\x3e\x6d\x75\x2c\x2e" +"\x61\x7d\x55\x96\x5e\xdd\xfa\xc5\x17\x55" +"\xc1\x08\x23\x10\x31\x39\x19\x74\x0c\x43" +"\xc9\x60\xb4\x8c\x46\xcd\x38\xe3\x10\x44" +"\x43\x1d\x35\x0d\x35\x50\x59\x73\x0d\x56" +"\x6e\x69\x03\x17\x37\xdd\x88\xf5\x4d\x55" +"\xe1\x88\x33\x10\x39\x3a\x1d\x74\x4e\x43" +"\xe9\x64\xb4\xce\x46\xed\xb8\xf3\x50\x44" +"\x44\x21\x35\x0f\x3d\x51\xd9\x73\x4f\x56" +"\x6f\xe9\x13\x17\x3f\xfd\x8c\x95\x2d" +"iso88593\0\x0a0x21" +"\x26\x61\x3b\x0a\x29\x00\x90\x74\x0a\x2a" +"\x30\x79\xe5\x11\x4d\xad\x00\xb0\x17\x2c" +"\x27\xc9\x32\x0b\x2d\xb5\x94\x74\x0b\x2e" +"\x31\x7d\xf5\x51\x4d\xbd\x00\xc0\x17\x30" +"\xc1\x08\x03\x00\x31\x0a\x21\x74\x0c\x32" +"\xc9\x28\xb3\x0c\x33\xcd\x38\xf3\x0c\x00" +"\xd1\x48\x33\x0d\x35\x20\x59\x73\x0d\x47" +"\xd9\x68\xb3\x0d\x37\x6c\x71\xf5\x0d\x38" +"\xe1\x88\x03\x00\x39\x0b\x25\x74\x0e\x3a" +"\xe9\xa8\xb3\x0e\x3b\xed\xb8\xf3\x0e\x00" +"\xf1\xc8\x33\x0f\x3d\x21\xd9\x73\x4f\x47" +"\xf9\xe8\xb3\x0f\x3f\x6d\x75\x95\x2d" +"iso88594\0\x0a\x21" +"\x04\xe1\x64\x15\x29\x28\xed\x74\x0a\x2a" +"\x60\x49\x24\x92\x59\xad\xf4\xf5\x0a\x2c" +"\x05\x6d\x7b\x15\x2d\x29\xf1\x74\x2c\x2e" +"\x61\x4d\x34\xd2\x59\x4a\xf9\xb5\x14\x40" +"\xc1\x08\x33\x0c\x31\xc5\x18\xe3\x12\x43" +"\xc9\x60\xb4\x8c\x45\xcd\x38\xa3\x12\x44" +"\x45\x31\x65\x13\x35\xd5\x58\x73\x0d\x36" +"\x72\x69\xb3\x0d\x37\x68\xa9\xf5\x4d\x40" +"\xe1\x88\x33\x0e\x39\xe5\x98\xf3\x52\x43" +"\xe9\x64\xb4\xce\x45\xed\xb8\xb3\x52\x44" +"\x46\x35\x75\x13\x3d\xf5\xd8\x73\x0f\x3e" +"\x73\xe9\xb3\x0f\x3f\x69\xad\x95\x2d" +"iso88595\0\x0d\x21" +"\x01\x84\x00\x30\x40\x10\x10\x05\x84\x01" +"\x70\x40\x20\x10\x09\x84\x02\xb0\x40\x30" +"\x10\xad\x80\x03\xf0\x40\x40\x10\x11\x84" +"\x04\x30\x41\x50\x10\x15\x84\x05\x70\x41" +"\x60\x10\x19\x84\x06\xb0\x41\x70\x10\x1d" +"\x84\x07\xf0\x41\x80\x10\x21\x84\x08\x30" +"\x42\x90\x10\x25\x84\x09\x70\x42\xa0\x10" +"\x29\x84\x0a\xb0\x42\xb0\x10\x2d\x84\x0b" +"\xf0\x42\xc0\x10\x31\x84\x0c\x30\x43\xd0" +"\x10\x35\x84\x0d\x70\x43\xe0\x10\x39\x84" +"\x0e\xb0\x43\xf0\x10\x3d\x84\x0f\xf0\x43" +"\x00\x11\x41\x84\x10\x30\x44\x10\x11\x45" +"\x84\x11\x70\x44\x20\x11\x49\x84\x12\xb0" +"\x44\x30\x11\x4d\x84\x13\xf0\x44\x58\x84" +"\x51\x84\x14\x30\x45\x50\x11\x55\x84\x15" +"\x70\x45\x60\x11\x59\x84\x16\xb0\x45\x70" +"\x11\xa7\x80\x17\xf0\x45\x00" +"iso88596\0\x0b\x21" +"\x00\x00\x00\x00\x48\x01\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x18\xdc\x0a\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\xc0\x86\x00\x00\x00" +"\x00\x7c\x18\x00\x21\x16\xf1\x88\x48\x5c" +"\x62\x13\x9c\x18\xc5\x29\x56\xf1\x8a\x58" +"\xdc\x62\x17\xbc\x18\xc6\x31\x96\xf1\x8c" +"\x68\x5c\x63\x1b\xdc\x18\xc7\x39\xd6\x31" +"\x00\x00\x00\x00\x00\x00\x00\xc8\x41\x16" +"\xf2\x90\x88\x5c\x64\x23\x1c\x19\xc9\x49" +"\x56\xf2\x92\x98\xdc\x64\x27\x3c\x19\xca" +"\x51\x96\x32\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00" +"iso88597\0\x0d\x21" +"\x18\x60\x06\x30\x0a\xb0\x82\xaf\xa0\x29" +"\x70\x0a\xa0\x02\xa9\x80\xde\xb0\x0a\xb0" +"\x02\xad\x00\x00\x50\x01\xc0\x02\xb1\x80" +"\x2c\x30\x0b\x10\x0e\x85\x83\xe1\x70\x0b" +"\x20\x0e\x89\x83\xe2\xb0\x0b\x30\x0e\xbd" +"\x80\xe3\xf0\x38\x40\x0e\x91\x83\xe4\x30" +"\x39\x50\x0e\x95\x83\xe5\x70\x39\x60\x0e" +"\x99\x83\xe6\xb0\x39\x70\x0e\x9d\x83\xe7" +"\xf0\x39\x80\x0e\xa1\x03\x00\x30\x3a\x90" +"\x0e\xa5\x83\xe9\x70\x3a\xa0\x0e\xa9\x83" +"\xea\xb0\x3a\xb0\x0e\xad\x83\xeb\xf0\x3a" +"\xc0\x0e\xb1\x83\xec\x30\x3b\xd0\x0e\xb5" +"\x83\xed\x70\x3b\xe0\x0e\xb9\x83\xee\xb0" +"\x3b\xf0\x0e\xbd\x83\xef\xf0\x3b\x00\x0f" +"\xc1\x83\xf0\x30\x3c\x10\x0f\xc5\x83\xf1" +"\x70\x3c\x20\x0f\xc9\x83\xf2\xb0\x3c\x30" +"\x0f\xcd\x83\xf3\x00\x00\x00" +"iso88598\0\x0d\x21" +"\x00\x80\x28\x30\x0a\x90\x02\xa5\x80\x29" +"\x70\x0a\xa0\x02\xa9\xc0\x35\xb0\x0a\xb0" +"\x02\xad\x80\x2b\xf0\x0a\xc0\x02\xb1\x80" +"\x2c\x30\x0b\xd0\x02\xb5\x80\x2d\x70\x0b" +"\xe0\x02\xb9\xc0\x3d\xb0\x0b\xf0\x02\xbd" +"\x80\x2f\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +"\x00\x00\x00\x00\x00\x00\x00\x00\x70\x01" +"\x40\x17\xd1\x85\x74\x30\x5d\x50\x17\xd5" +"\x85\x75\x70\x5d\x60\x17\xd9\x85\x76\xb0" +"\x5d\x70\x17\xdd\x85\x77\xf0\x5d\x80\x17" +"\xe1\x85\x78\x30\x5e\x90\x17\xe5\x85\x79" +"\x70\x5e\xa0\x17\xe9\x85\x7a\x00\x00\x00" +"\x00\x0e\xe0\x03\x00\x00\x00" +"iso88599\0\x09\x50" +"\x1e\xa3\x49\x9b\x46\xad\x9a\xb5\x6b\xd8" +"\xb2\x69\xdb\xc6\x0d\xa6\xd7\x6f\xe0\xc2" +"\x89\x1b\x47\xae\x9c\xb9\x73\xe8\xd2\xa9" +"\x5b\xc7\xae\x9d\xbb\x77\x1f\xe3\xc9\x9b" +"\x47\xaf\x9e\xbd\x7b\xf8\xf2\xe9\xdb\xc7" +"\x2f\xe6\xd7\x7f" +"iso885910\0\x0d\x21" +"\x04\x81\x44\x20\x12\xa8\x04\x28\x81\x4d" +"\x70\x0a\xec\x04\x10\x01\x58\x60\x16\xf4" +"\x05\xad\x80\x5a\xa0\x14\xc0\x02\x05\xc1" +"\x44\x30\x12\xac\x04\x29\xc1\x4d\x70\x0b" +"\xf0\x04\x11\x41\x58\x70\x16\xf8\x05\x15" +"\xe0\x5a\xb0\x14\x00\x04\xc1\x80\x30\x30" +"\x0c\x10\x03\xc5\x80\x31\xe0\x12\x30\x04" +"\xc9\x00\x46\xb0\x0c\x58\x04\xcd\x80\x33" +"\xf0\x0c\x40\x03\x45\x01\x53\x30\x0d\x50" +"\x03\xd5\x80\x35\x80\x16\x60\x03\x72\x81" +"\x36\xb0\x0d\x70\x03\xdd\x80\x37\xf0\x0d" +"\x04\x04\xe1\x80\x38\x30\x0e\x90\x03\xe5" +"\x80\x39\xf0\x12\x34\x04\xe9\x40\x46\xb0" +"\x0e\x5c\x04\xed\x80\x3b\xf0\x0e\xc0\x03" +"\x46\x41\x53\x30\x0f\xd0\x03\xf5\x80\x3d" +"\x90\x16\xe0\x03\x73\x81\x3e\xb0\x0f\xf0" +"\x03\xfd\x80\x3f\x80\x13\x00" +"iso885913\0\x0d\x21" +"\x1d\xa0\x28\x30\x0a\x90\x02\x1e\xa0\x29" +"\x70\x0a\x60\x03\xa9\x80\x55\xb0\x0a\xb0" +"\x02\xad\x80\x2b\x60\x0c\xc0\x02\xb1\x80" +"\x2c\x30\x0b\x70\x80\xb5\x80\x2d\x70\x0b" +"\xe0\x03\xb9\xc0\x55\xb0\x0b\xf0\x02\xbd" +"\x80\x2f\x60\x0e\x10\x04\x2e\x01\x40\x60" +"\x10\x10\x03\xc5\x00\x46\x20\x11\x30\x04" +"\xc9\x40\x5e\x60\x11\x88\x04\x36\x81\x4a" +"\xb0\x13\x80\x05\x43\x41\x51\x30\x0d\x30" +"\x05\xd5\x80\x35\x70\x0d\xc8\x05\x41\x81" +"\x56\xa0\x16\x70\x03\x7b\x41\x5f\xf0\x0d" +"\x14\x04\x2f\x41\x40\x70\x10\x90\x03\xe5" +"\x40\x46\x30\x11\x34\x04\xe9\x80\x5e\x70" +"\x11\x8c\x04\x37\xc1\x4a\xc0\x13\x84\x05" +"\x44\x81\x51\x30\x0f\x34\x05\xf5\x80\x3d" +"\x70\x0f\xcc\x05\x42\xc1\x56\xb0\x16\xf0" +"\x03\x7c\x81\x5f\x90\x01\x00" +"iso885914\0\x0c\x21" +"\x02\x7e\xc0\x8c\x02\x85\xb0\x10\x14\xfc" +"\x29\x00\xf4\xa9\x40\xd0\x2c\x78\x79\xd0" +"\x0a\x5c\x01\x5e\xf0\xf0\x1f\x1e\x24\x84" +"\x04\x20\x10\xe4\x6c\x81\x95\x08\xf4\x57" +"\x7e\xd0\x80\xf9\x79\x40\xe8\x0a\x7d\x98" +"\x00\x06\xc1\x40\x18\x0c\x03\x62\x50\x0c" +"\x8c\xc1\x31\x40\x06\xc9\x40\x19\x2c\x03" +"\x66\xd0\x0c\x9c\xc1\x33\xa0\x0b\xd1\x40" +"\x1a\x4c\x03\x6a\x50\x0d\xac\x81\x9a\xc0" +"\x06\xd9\x40\x1b\x6c\x03\x6e\xd0\x0d\xec" +"\xc2\x37\x00\x07\xe1\x40\x1c\x8c\x03\x72" +"\x50\x0e\xcc\xc1\x39\x40\x07\xe9\x40\x1d" +"\xac\x03\x76\xd0\x0e\xdc\xc1\x3b\xa8\x0b" +"\xf1\x40\x1e\xcc\x03\x7a\x50\x0f\xec\xc1" +"\x9a\xc0\x07\xf9\x40\x1f\xec\x03\x7e\xd0" +"\x0f\xee\xc2\x3f\x00" +"iso885916\0\x0d\x21" +"\x04\x41\x41\x10\x14\xb0\x82\x1e\x20\x58" +"\x70\x0a\x84\x05\xa9\x00\x86\xb0\x0a\xe4" +"\x05\xad\x80\x5e\xb0\x17\xc0\x02\xb1\x00" +"\x43\x20\x14\xf4\x05\x1d\xa0\x2d\x70\x0b" +"\xf8\x05\x0d\x41\x86\xb0\x0b\x48\x05\x53" +"\x01\x5e\xc0\x17\x00\x03\xc1\x80\x30\x20" +"\x10\x10\x03\x06\x81\x31\x70\x0c\x20\x03" +"\xc9\x80\x32\xb0\x0c\x30\x03\xcd\x80\x33" +"\xf0\x0c\x40\x04\x43\x81\x34\x30\x0d\x50" +"\x03\x50\x81\x35\xa0\x15\xc0\x05\xd9\x80" +"\x36\xb0\x0d\x70\x03\x18\x81\x86\xf0\x0d" +"\x80\x03\xe1\x80\x38\x30\x10\x90\x03\x07" +"\x81\x39\x70\x0e\xa0\x03\xe9\x80\x3a\xb0" +"\x0e\xb0\x03\xed\x80\x3b\xf0\x0e\x44\x04" +"\x44\x81\x3c\x30\x0f\xd0\x03\x51\x81\x3d" +"\xb0\x15\xc4\x05\xf9\x80\x3e\xb0\x0f\xf0" +"\x03\x19\xc1\x86\xf0\x0f\x00" +; + + +'i','s','o','8','8','5','9','1',0, +8,128, +'i','s','o','8','8','5','9','2',0, +10, 33, +0x04, 0x61, 0x1b, 0x14, 0x29, 0x3d, 0x69, 0x75, 0x0a, 0x2a, +0x60, 0x79, 0x45, 0x56, 0x5e, 0xad, 0xf4, 0xb5, 0x17, 0x2c, +0x05, 0x6d, 0x2b, 0x14, 0x2d, 0x3e, 0x6d, 0x75, 0x2c, 0x2e, +0x61, 0x7d, 0x55, 0x96, 0x5e, 0xdd, 0xfa, 0xc5, 0x17, 0x55, +0xc1, 0x08, 0x23, 0x10, 0x31, 0x39, 0x19, 0x74, 0x0c, 0x43, +0xc9, 0x60, 0xb4, 0x8c, 0x46, 0xcd, 0x38, 0xe3, 0x10, 0x44, +0x43, 0x1d, 0x35, 0x0d, 0x35, 0x50, 0x59, 0x73, 0x0d, 0x56, +0x6e, 0x69, 0x03, 0x17, 0x37, 0xdd, 0x88, 0xf5, 0x4d, 0x55, +0xe1, 0x88, 0x33, 0x10, 0x39, 0x3a, 0x1d, 0x74, 0x4e, 0x43, +0xe9, 0x64, 0xb4, 0xce, 0x46, 0xed, 0xb8, 0xf3, 0x50, 0x44, +0x44, 0x21, 0x35, 0x0f, 0x3d, 0x51, 0xd9, 0x73, 0x4f, 0x56, +0x6f, 0xe9, 0x13, 0x17, 0x3f, 0xfd, 0x8c, 0x95, 0x2d, +'i','s','o','8','8','5','9','3',0, +10, 33, +0x26, 0x61, 0x3b, 0x0a, 0x29, 0x00, 0x90, 0x74, 0x0a, 0x2a, +0x30, 0x79, 0xe5, 0x11, 0x4d, 0xad, 0x00, 0xb0, 0x17, 0x2c, +0x27, 0xc9, 0x32, 0x0b, 0x2d, 0xb5, 0x94, 0x74, 0x0b, 0x2e, +0x31, 0x7d, 0xf5, 0x51, 0x4d, 0xbd, 0x00, 0xc0, 0x17, 0x30, +0xc1, 0x08, 0x03, 0x00, 0x31, 0x0a, 0x21, 0x74, 0x0c, 0x32, +0xc9, 0x28, 0xb3, 0x0c, 0x33, 0xcd, 0x38, 0xf3, 0x0c, 0x00, +0xd1, 0x48, 0x33, 0x0d, 0x35, 0x20, 0x59, 0x73, 0x0d, 0x47, +0xd9, 0x68, 0xb3, 0x0d, 0x37, 0x6c, 0x71, 0xf5, 0x0d, 0x38, +0xe1, 0x88, 0x03, 0x00, 0x39, 0x0b, 0x25, 0x74, 0x0e, 0x3a, +0xe9, 0xa8, 0xb3, 0x0e, 0x3b, 0xed, 0xb8, 0xf3, 0x0e, 0x00, +0xf1, 0xc8, 0x33, 0x0f, 0x3d, 0x21, 0xd9, 0x73, 0x4f, 0x47, +0xf9, 0xe8, 0xb3, 0x0f, 0x3f, 0x6d, 0x75, 0x95, 0x2d, +'i','s','o','8','8','5','9','4',0, +10, 33, +0x04, 0xe1, 0x64, 0x15, 0x29, 0x28, 0xed, 0x74, 0x0a, 0x2a, +0x60, 0x49, 0x24, 0x92, 0x59, 0xad, 0xf4, 0xf5, 0x0a, 0x2c, +0x05, 0x6d, 0x7b, 0x15, 0x2d, 0x29, 0xf1, 0x74, 0x2c, 0x2e, +0x61, 0x4d, 0x34, 0xd2, 0x59, 0x4a, 0xf9, 0xb5, 0x14, 0x40, +0xc1, 0x08, 0x33, 0x0c, 0x31, 0xc5, 0x18, 0xe3, 0x12, 0x43, +0xc9, 0x60, 0xb4, 0x8c, 0x45, 0xcd, 0x38, 0xa3, 0x12, 0x44, +0x45, 0x31, 0x65, 0x13, 0x35, 0xd5, 0x58, 0x73, 0x0d, 0x36, +0x72, 0x69, 0xb3, 0x0d, 0x37, 0x68, 0xa9, 0xf5, 0x4d, 0x40, +0xe1, 0x88, 0x33, 0x0e, 0x39, 0xe5, 0x98, 0xf3, 0x52, 0x43, +0xe9, 0x64, 0xb4, 0xce, 0x45, 0xed, 0xb8, 0xb3, 0x52, 0x44, +0x46, 0x35, 0x75, 0x13, 0x3d, 0xf5, 0xd8, 0x73, 0x0f, 0x3e, +0x73, 0xe9, 0xb3, 0x0f, 0x3f, 0x69, 0xad, 0x95, 0x2d, +'i','s','o','8','8','5','9','5',0, +14, 33, +0x01, 0x84, 0x00, 0x30, 0x40, 0x10, 0x10, 0x05, 0x84, 0x01, +0x70, 0x40, 0x20, 0x10, 0x09, 0x84, 0x02, 0xb0, 0x40, 0x30, +0x10, 0xad, 0x80, 0x03, 0xf0, 0x40, 0x40, 0x10, 0x11, 0x84, +0x04, 0x30, 0x41, 0x50, 0x10, 0x15, 0x84, 0x05, 0x70, 0x41, +0x60, 0x10, 0x19, 0x84, 0x06, 0xb0, 0x41, 0x70, 0x10, 0x1d, +0x84, 0x07, 0xf0, 0x41, 0x80, 0x10, 0x21, 0x84, 0x08, 0x30, +0x42, 0x90, 0x10, 0x25, 0x84, 0x09, 0x70, 0x42, 0xa0, 0x10, +0x29, 0x84, 0x0a, 0xb0, 0x42, 0xb0, 0x10, 0x2d, 0x84, 0x0b, +0xf0, 0x42, 0xc0, 0x10, 0x31, 0x84, 0x0c, 0x30, 0x43, 0xd0, +0x10, 0x35, 0x84, 0x0d, 0x70, 0x43, 0xe0, 0x10, 0x39, 0x84, +0x0e, 0xb0, 0x43, 0xf0, 0x10, 0x3d, 0x84, 0x0f, 0xf0, 0x43, +0x00, 0x11, 0x41, 0x84, 0x10, 0x30, 0x44, 0x10, 0x11, 0x45, +0x84, 0x11, 0x70, 0x44, 0x20, 0x11, 0x49, 0x84, 0x12, 0xb0, +0x44, 0x30, 0x11, 0x4d, 0x84, 0x13, 0xf0, 0x44, 0x58, 0x84, +0x51, 0x84, 0x14, 0x30, 0x45, 0x50, 0x11, 0x55, 0x84, 0x15, +0x70, 0x45, 0x60, 0x11, 0x59, 0x84, 0x16, 0xb0, 0x45, 0x70, +0x11, 0xa7, 0x80, 0x17, 0xf0, 0x45, 0x00, +'i','s','o','8','8','5','9','6',0, +11, 33, +0x00, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xdc, 0x0a, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x86, 0x00, 0x00, 0x00, +0x00, 0x7c, 0x18, 0x00, 0x21, 0x16, 0xf1, 0x88, 0x48, 0x5c, +0x62, 0x13, 0x9c, 0x18, 0xc5, 0x29, 0x56, 0xf1, 0x8a, 0x58, +0xdc, 0x62, 0x17, 0xbc, 0x18, 0xc6, 0x31, 0x96, 0xf1, 0x8c, +0x68, 0x5c, 0x63, 0x1b, 0xdc, 0x18, 0xc7, 0x39, 0xd6, 0x31, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x41, 0x16, +0xf2, 0x90, 0x88, 0x5c, 0x64, 0x23, 0x1c, 0x19, 0xc9, 0x49, +0x56, 0xf2, 0x92, 0x98, 0xdc, 0x64, 0x27, 0x3c, 0x19, 0xca, +0x51, 0x96, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, +'i','s','o','8','8','5','9','7',0, +14, 33, +0x18, 0x60, 0x06, 0x30, 0x0a, 0xb0, 0x82, 0xaf, 0xa0, 0x29, +0x70, 0x0a, 0xa0, 0x02, 0xa9, 0x80, 0xde, 0xb0, 0x0a, 0xb0, +0x02, 0xad, 0x00, 0x00, 0x50, 0x01, 0xc0, 0x02, 0xb1, 0x80, +0x2c, 0x30, 0x0b, 0x10, 0x0e, 0x85, 0x83, 0xe1, 0x70, 0x0b, +0x20, 0x0e, 0x89, 0x83, 0xe2, 0xb0, 0x0b, 0x30, 0x0e, 0xbd, +0x80, 0xe3, 0xf0, 0x38, 0x40, 0x0e, 0x91, 0x83, 0xe4, 0x30, +0x39, 0x50, 0x0e, 0x95, 0x83, 0xe5, 0x70, 0x39, 0x60, 0x0e, +0x99, 0x83, 0xe6, 0xb0, 0x39, 0x70, 0x0e, 0x9d, 0x83, 0xe7, +0xf0, 0x39, 0x80, 0x0e, 0xa1, 0x03, 0x00, 0x30, 0x3a, 0x90, +0x0e, 0xa5, 0x83, 0xe9, 0x70, 0x3a, 0xa0, 0x0e, 0xa9, 0x83, +0xea, 0xb0, 0x3a, 0xb0, 0x0e, 0xad, 0x83, 0xeb, 0xf0, 0x3a, +0xc0, 0x0e, 0xb1, 0x83, 0xec, 0x30, 0x3b, 0xd0, 0x0e, 0xb5, +0x83, 0xed, 0x70, 0x3b, 0xe0, 0x0e, 0xb9, 0x83, 0xee, 0xb0, +0x3b, 0xf0, 0x0e, 0xbd, 0x83, 0xef, 0xf0, 0x3b, 0x00, 0x0f, +0xc1, 0x83, 0xf0, 0x30, 0x3c, 0x10, 0x0f, 0xc5, 0x83, 0xf1, +0x70, 0x3c, 0x20, 0x0f, 0xc9, 0x83, 0xf2, 0xb0, 0x3c, 0x30, +0x0f, 0xcd, 0x83, 0xf3, 0x00, 0x00, 0x00, +'i','s','o','8','8','5','9','8',0, +14, 33, +0x00, 0x80, 0x28, 0x30, 0x0a, 0x90, 0x02, 0xa5, 0x80, 0x29, +0x70, 0x0a, 0xa0, 0x02, 0xa9, 0xc0, 0x35, 0xb0, 0x0a, 0xb0, +0x02, 0xad, 0x80, 0x2b, 0xf0, 0x0a, 0xc0, 0x02, 0xb1, 0x80, +0x2c, 0x30, 0x0b, 0xd0, 0x02, 0xb5, 0x80, 0x2d, 0x70, 0x0b, +0xe0, 0x02, 0xb9, 0xc0, 0x3d, 0xb0, 0x0b, 0xf0, 0x02, 0xbd, +0x80, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x01, +0x40, 0x17, 0xd1, 0x85, 0x74, 0x30, 0x5d, 0x50, 0x17, 0xd5, +0x85, 0x75, 0x70, 0x5d, 0x60, 0x17, 0xd9, 0x85, 0x76, 0xb0, +0x5d, 0x70, 0x17, 0xdd, 0x85, 0x77, 0xf0, 0x5d, 0x80, 0x17, +0xe1, 0x85, 0x78, 0x30, 0x5e, 0x90, 0x17, 0xe5, 0x85, 0x79, +0x70, 0x5e, 0xa0, 0x17, 0xe9, 0x85, 0x7a, 0x00, 0x00, 0x00, +0x00, 0x0e, 0xe0, 0x03, 0x00, 0x00, 0x00, +'i','s','o','8','8','5','9','9',0, +9, 80, +0x1e, 0xa3, 0x49, 0x9b, 0x46, 0xad, 0x9a, 0xb5, 0x6b, 0xd8, +0xb2, 0x69, 0xdb, 0xc6, 0x0d, 0xa6, 0xd7, 0x6f, 0xe0, 0xc2, +0x89, 0x1b, 0x47, 0xae, 0x9c, 0xb9, 0x73, 0xe8, 0xd2, 0xa9, +0x5b, 0xc7, 0xae, 0x9d, 0xbb, 0x77, 0x1f, 0xe3, 0xc9, 0x9b, +0x47, 0xaf, 0x9e, 0xbd, 0x7b, 0xf8, 0xf2, 0xe9, 0xdb, 0xc7, +0x2f, 0xe6, 0xd7, 0x7f, +'i','s','o','8','8','5','9','1','0',0, +14, 33, +0x04, 0x81, 0x44, 0x20, 0x12, 0xa8, 0x04, 0x28, 0x81, 0x4d, +0x70, 0x0a, 0xec, 0x04, 0x10, 0x01, 0x58, 0x60, 0x16, 0xf4, +0x05, 0xad, 0x80, 0x5a, 0xa0, 0x14, 0xc0, 0x02, 0x05, 0xc1, +0x44, 0x30, 0x12, 0xac, 0x04, 0x29, 0xc1, 0x4d, 0x70, 0x0b, +0xf0, 0x04, 0x11, 0x41, 0x58, 0x70, 0x16, 0xf8, 0x05, 0x15, +0xe0, 0x5a, 0xb0, 0x14, 0x00, 0x04, 0xc1, 0x80, 0x30, 0x30, +0x0c, 0x10, 0x03, 0xc5, 0x80, 0x31, 0xe0, 0x12, 0x30, 0x04, +0xc9, 0x00, 0x46, 0xb0, 0x0c, 0x58, 0x04, 0xcd, 0x80, 0x33, +0xf0, 0x0c, 0x40, 0x03, 0x45, 0x01, 0x53, 0x30, 0x0d, 0x50, +0x03, 0xd5, 0x80, 0x35, 0x80, 0x16, 0x60, 0x03, 0x72, 0x81, +0x36, 0xb0, 0x0d, 0x70, 0x03, 0xdd, 0x80, 0x37, 0xf0, 0x0d, +0x04, 0x04, 0xe1, 0x80, 0x38, 0x30, 0x0e, 0x90, 0x03, 0xe5, +0x80, 0x39, 0xf0, 0x12, 0x34, 0x04, 0xe9, 0x40, 0x46, 0xb0, +0x0e, 0x5c, 0x04, 0xed, 0x80, 0x3b, 0xf0, 0x0e, 0xc0, 0x03, +0x46, 0x41, 0x53, 0x30, 0x0f, 0xd0, 0x03, 0xf5, 0x80, 0x3d, +0x90, 0x16, 0xe0, 0x03, 0x73, 0x81, 0x3e, 0xb0, 0x0f, 0xf0, +0x03, 0xfd, 0x80, 0x3f, 0x80, 0x13, 0x00, +'i','s','o','8','8','5','9','1','3',0, +14, 33, +0x1d, 0xa0, 0x28, 0x30, 0x0a, 0x90, 0x02, 0x1e, 0xa0, 0x29, +0x70, 0x0a, 0x60, 0x03, 0xa9, 0x80, 0x55, 0xb0, 0x0a, 0xb0, +0x02, 0xad, 0x80, 0x2b, 0x60, 0x0c, 0xc0, 0x02, 0xb1, 0x80, +0x2c, 0x30, 0x0b, 0x70, 0x80, 0xb5, 0x80, 0x2d, 0x70, 0x0b, +0xe0, 0x03, 0xb9, 0xc0, 0x55, 0xb0, 0x0b, 0xf0, 0x02, 0xbd, +0x80, 0x2f, 0x60, 0x0e, 0x10, 0x04, 0x2e, 0x01, 0x40, 0x60, +0x10, 0x10, 0x03, 0xc5, 0x00, 0x46, 0x20, 0x11, 0x30, 0x04, +0xc9, 0x40, 0x5e, 0x60, 0x11, 0x88, 0x04, 0x36, 0x81, 0x4a, +0xb0, 0x13, 0x80, 0x05, 0x43, 0x41, 0x51, 0x30, 0x0d, 0x30, +0x05, 0xd5, 0x80, 0x35, 0x70, 0x0d, 0xc8, 0x05, 0x41, 0x81, +0x56, 0xa0, 0x16, 0x70, 0x03, 0x7b, 0x41, 0x5f, 0xf0, 0x0d, +0x14, 0x04, 0x2f, 0x41, 0x40, 0x70, 0x10, 0x90, 0x03, 0xe5, +0x40, 0x46, 0x30, 0x11, 0x34, 0x04, 0xe9, 0x80, 0x5e, 0x70, +0x11, 0x8c, 0x04, 0x37, 0xc1, 0x4a, 0xc0, 0x13, 0x84, 0x05, +0x44, 0x81, 0x51, 0x30, 0x0f, 0x34, 0x05, 0xf5, 0x80, 0x3d, +0x70, 0x0f, 0xcc, 0x05, 0x42, 0xc1, 0x56, 0xb0, 0x16, 0xf0, +0x03, 0x7c, 0x81, 0x5f, 0x90, 0x01, 0x00, +'i','s','o','8','8','5','9','1','4',0, +13, 33, +0x02, 0x7e, 0xc0, 0x8c, 0x02, 0x85, 0xb0, 0x10, 0x14, 0xfc, +0x29, 0x00, 0xf4, 0xa9, 0x40, 0xd0, 0x2c, 0x78, 0x79, 0xd0, +0x0a, 0x5c, 0x01, 0x5e, 0xf0, 0xf0, 0x1f, 0x1e, 0x24, 0x84, +0x04, 0x20, 0x10, 0xe4, 0x6c, 0x81, 0x95, 0x08, 0xf4, 0x57, +0x7e, 0xd0, 0x80, 0xf9, 0x79, 0x40, 0xe8, 0x0a, 0x7d, 0x98, +0x00, 0x06, 0xc1, 0x40, 0x18, 0x0c, 0x03, 0x62, 0x50, 0x0c, +0x8c, 0xc1, 0x31, 0x40, 0x06, 0xc9, 0x40, 0x19, 0x2c, 0x03, +0x66, 0xd0, 0x0c, 0x9c, 0xc1, 0x33, 0xa0, 0x0b, 0xd1, 0x40, +0x1a, 0x4c, 0x03, 0x6a, 0x50, 0x0d, 0xac, 0x81, 0x9a, 0xc0, +0x06, 0xd9, 0x40, 0x1b, 0x6c, 0x03, 0x6e, 0xd0, 0x0d, 0xec, +0xc2, 0x37, 0x00, 0x07, 0xe1, 0x40, 0x1c, 0x8c, 0x03, 0x72, +0x50, 0x0e, 0xcc, 0xc1, 0x39, 0x40, 0x07, 0xe9, 0x40, 0x1d, +0xac, 0x03, 0x76, 0xd0, 0x0e, 0xdc, 0xc1, 0x3b, 0xa8, 0x0b, +0xf1, 0x40, 0x1e, 0xcc, 0x03, 0x7a, 0x50, 0x0f, 0xec, 0xc1, +0x9a, 0xc0, 0x07, 0xf9, 0x40, 0x1f, 0xec, 0x03, 0x7e, 0xd0, +0x0f, 0xee, 0xc2, 0x3f, 0x00, +'i','s','o','8','8','5','9','1','6',0, +14, 33, +0x04, 0x41, 0x41, 0x10, 0x14, 0xb0, 0x82, 0x1e, 0x20, 0x58, +0x70, 0x0a, 0x84, 0x05, 0xa9, 0x00, 0x86, 0xb0, 0x0a, 0xe4, +0x05, 0xad, 0x80, 0x5e, 0xb0, 0x17, 0xc0, 0x02, 0xb1, 0x00, +0x43, 0x20, 0x14, 0xf4, 0x05, 0x1d, 0xa0, 0x2d, 0x70, 0x0b, +0xf8, 0x05, 0x0d, 0x41, 0x86, 0xb0, 0x0b, 0x48, 0x05, 0x53, +0x01, 0x5e, 0xc0, 0x17, 0x00, 0x03, 0xc1, 0x80, 0x30, 0x20, +0x10, 0x10, 0x03, 0x06, 0x81, 0x31, 0x70, 0x0c, 0x20, 0x03, +0xc9, 0x80, 0x32, 0xb0, 0x0c, 0x30, 0x03, 0xcd, 0x80, 0x33, +0xf0, 0x0c, 0x40, 0x04, 0x43, 0x81, 0x34, 0x30, 0x0d, 0x50, +0x03, 0x50, 0x81, 0x35, 0xa0, 0x15, 0xc0, 0x05, 0xd9, 0x80, +0x36, 0xb0, 0x0d, 0x70, 0x03, 0x18, 0x81, 0x86, 0xf0, 0x0d, +0x80, 0x03, 0xe1, 0x80, 0x38, 0x30, 0x10, 0x90, 0x03, 0x07, +0x81, 0x39, 0x70, 0x0e, 0xa0, 0x03, 0xe9, 0x80, 0x3a, 0xb0, +0x0e, 0xb0, 0x03, 0xed, 0x80, 0x3b, 0xf0, 0x0e, 0x44, 0x04, +0x44, 0x81, 0x3c, 0x30, 0x0f, 0xd0, 0x03, 0x51, 0x81, 0x3d, +0xb0, 0x15, 0xc4, 0x05, 0xf9, 0x80, 0x3e, 0xb0, 0x0f, 0xf0, +0x03, 0x19, 0xc1, 0x86, 0xf0, 0x0f, 0x00, diff --git a/src/locale/tolower_l.c b/src/locale/tolower_l.c new file mode 100644 index 00000000..ba277919 --- /dev/null +++ b/src/locale/tolower_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int tolower_l(int c, locale_t l) +{ +	return tolower(c); +} diff --git a/src/locale/toupper_l.c b/src/locale/toupper_l.c new file mode 100644 index 00000000..73f2f39b --- /dev/null +++ b/src/locale/toupper_l.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +int toupper_l(int c, locale_t l) +{ +	return toupper(c); +} diff --git a/src/locale/wcscoll.c b/src/locale/wcscoll.c new file mode 100644 index 00000000..cdbce1c2 --- /dev/null +++ b/src/locale/wcscoll.c @@ -0,0 +1,7 @@ +#include <wchar.h> + +/* FIXME: stub */ +int wcscoll(const wchar_t *l, const wchar_t *r) +{ +	return wcscmp(l, r); +} diff --git a/src/locale/wcsxfrm.c b/src/locale/wcsxfrm.c new file mode 100644 index 00000000..5f76e5a7 --- /dev/null +++ b/src/locale/wcsxfrm.c @@ -0,0 +1,12 @@ +#include <wchar.h> + +/* collate only by code points */ +size_t wcsxfrm(wchar_t *dest, const wchar_t *src, size_t n) +{ +	size_t l = wcslen(src); +	if (l >= n) { +		wmemcpy(dest, src, n-1); +		dest[n-1] = 0; +	} else wcscpy(dest, src); +	return l; +} diff --git a/src/malloc/DESIGN b/src/malloc/DESIGN new file mode 100644 index 00000000..58b0523f --- /dev/null +++ b/src/malloc/DESIGN @@ -0,0 +1,22 @@ + + +In principle, this memory allocator is roughly equivalent to Doug +Lea's dlmalloc with fine-grained locking. + + + +malloc: + +Uses a freelist binned by chunk size, with a bitmap to optimize +searching for the smallest non-empty bin which can satisfy an +allocation. If no free chunks are available, it creates a new chunk of +the requested size and attempts to merge it with any existing free +chunk immediately below the newly created chunk. + +Whether the chunk was obtained from a bin or newly created, it's +likely to be larger than the requested allocation. malloc always +finishes its work by passing the new chunk to realloc, which will +split it into two chunks and free the tail portion. + + + diff --git a/src/malloc/__brk.c b/src/malloc/__brk.c new file mode 100644 index 00000000..e3b3af31 --- /dev/null +++ b/src/malloc/__brk.c @@ -0,0 +1,7 @@ +#include <stdint.h> +#include "syscall.h" + +uintptr_t __brk(uintptr_t newbrk) +{ +	return syscall1(__NR_brk, newbrk); +} diff --git a/src/malloc/__simple_malloc.c b/src/malloc/__simple_malloc.c new file mode 100644 index 00000000..49b74c8e --- /dev/null +++ b/src/malloc/__simple_malloc.c @@ -0,0 +1,44 @@ +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> +#include <errno.h> +#include "libc.h" + +uintptr_t __brk(uintptr_t); + +#define ALIGN 16 + +void *__simple_malloc(size_t n) +{ +	static uintptr_t cur, brk; +	uintptr_t base, new; +	static int lock; +	size_t align=1; + +	if (n < SIZE_MAX - ALIGN) +		while (align<n && align<ALIGN) +			align += align; +	n = n + align - 1 & -align; + +	LOCK(&lock); +	if (!cur) cur = brk = __brk(0)+16; +	if (n > SIZE_MAX - brk) goto fail; + +	base = cur + align-1 & -align; +	if (base+n > brk) { +		new = base+n + PAGE_SIZE-1 & -PAGE_SIZE; +		if (__brk(new) != new) goto fail; +		brk = new; +	} +	cur = base+n; +	UNLOCK(&lock); + +	return (void *)base; + +fail: +	UNLOCK(&lock); +	errno = ENOMEM; +	return 0; +} + +weak_alias(__simple_malloc, malloc); diff --git a/src/malloc/calloc.c b/src/malloc/calloc.c new file mode 100644 index 00000000..9d574562 --- /dev/null +++ b/src/malloc/calloc.c @@ -0,0 +1,23 @@ +#include <stdlib.h> +#include <errno.h> +#include <string.h> + +void *calloc(size_t m, size_t n) +{ +	void *p; +	size_t *z; +	if (n && m > (size_t)-1/n) { +		errno = ENOMEM; +		return 0; +	} +	n *= m; +	p = malloc(n); +	if (!p) return 0; +	/* Only do this for non-mmapped chunks */ +	if (((size_t *)p)[-1] & 7) { +		/* Only write words that are not already zero */ +		m = (n + sizeof *z - 1)/sizeof *z; +		for (z=p; m; m--, z++) if (*z) *z=0; +	} +	return p; +} diff --git a/src/malloc/malloc.c b/src/malloc/malloc.c new file mode 100644 index 00000000..d9a30fe4 --- /dev/null +++ b/src/malloc/malloc.c @@ -0,0 +1,515 @@ +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <stdint.h> +#include <errno.h> +#include <sys/mman.h> +#include "libc.h" +#include "atomic.h" +#include "pthread_impl.h" + +uintptr_t __brk(uintptr_t); +void *__mmap(void *, size_t, int, int, int, off_t); +int __munmap(void *, size_t); +void *__mremap(void *, size_t, size_t, int, ...); +int __madvise(void *, size_t, int); + +struct chunk { +	size_t data[1]; +	struct chunk *next; +	struct chunk *prev; +}; + +struct bin { +	int lock[2]; +	struct chunk *head; +	struct chunk *tail; +}; + +static struct { +	uintptr_t brk; +	size_t *heap; +	uint64_t binmap; +	struct bin bins[64]; +	int brk_lock[2]; +	int free_lock[2]; +} mal; + + +#define SIZE_ALIGN (4*sizeof(size_t)) +#define SIZE_MASK (-SIZE_ALIGN) +#define OVERHEAD (2*sizeof(size_t)) +#define MMAP_THRESHOLD (0x1c00*SIZE_ALIGN) +#define DONTCARE 16 +#define RECLAIM 163840 + +#define CHUNK_SIZE(c) ((c)->data[0] & SIZE_MASK) +#define CHUNK_PSIZE(c) ((c)->data[-1] & SIZE_MASK) +#define PREV_CHUNK(c) ((struct chunk *)((char *)(c) - CHUNK_PSIZE(c))) +#define NEXT_CHUNK(c) ((struct chunk *)((char *)(c) + CHUNK_SIZE(c))) +#define MEM_TO_CHUNK(p) (struct chunk *)((size_t *)p - 1) +#define CHUNK_TO_MEM(c) (void *)((c)->data+1) +#define BIN_TO_CHUNK(i) (MEM_TO_CHUNK(&mal.bins[i].head)) + +#define C_INUSE  ((size_t)1) +#define C_FLAGS  ((size_t)3) +#define C_SIZE   SIZE_MASK + +#define IS_MMAPPED(c) !((c)->data[0] & (C_INUSE)) + + +/* Synchronization tools */ + +static void lock(volatile int *lk) +{ +	if (!libc.threads_minus_1) return; +	while(a_swap(lk, 1)) __wait(lk, lk+1, 1, 1); +} + +static void unlock(volatile int *lk) +{ +	if (!libc.threads_minus_1) return; +	a_store(lk, 0); +	if (lk[1]) __wake(lk, 1, 1); +} + +static void lock_bin(int i) +{ +	if (libc.threads_minus_1) +		lock(mal.bins[i].lock); +	if (!mal.bins[i].head) +		mal.bins[i].head = mal.bins[i].tail = BIN_TO_CHUNK(i); +} + +static void unlock_bin(int i) +{ +	if (!libc.threads_minus_1) return; +	unlock(mal.bins[i].lock); +} + +static int first_set(uint64_t x) +{ +#if 1 +	return a_ctz_64(x); +#else +	static const char debruijn64[64] = { +		0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, +		62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, +		63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, +		51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 +	}; +	static const char debruijn32[32] = { +		0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, +		31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14 +	}; +	if (sizeof(long) < 8) { +		uint32_t y = x; +		if (!y) { +			y = x>>32; +			return 32 + debruijn32[(y&-y)*0x076be629 >> 27]; +		} +		return debruijn32[(y&-y)*0x076be629 >> 27]; +	} +	return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58]; +#endif +} + +static int bin_index(size_t x) +{ +	x = x / SIZE_ALIGN - 1; +	if (x <= 32) return x; +	if (x > 0x1c00) return 63; +	return ((union { float v; uint32_t r; }){ x }.r>>21) - 496; +} + +static int bin_index_up(size_t x) +{ +	x = x / SIZE_ALIGN - 1; +	if (x <= 32) return x; +	return ((union { float v; uint32_t r; }){ x }.r+0x1fffff>>21) - 496; +} + +#if 0 +void __dump_heap(int x) +{ +	struct chunk *c; +	int i; +	for (c = (void *)mal.heap; CHUNK_SIZE(c); c = NEXT_CHUNK(c)) +		fprintf(stderr, "base %p size %zu (%d) flags %d/%d\n", +			c, CHUNK_SIZE(c), bin_index(CHUNK_SIZE(c)), +			c->data[0] & 15, +			NEXT_CHUNK(c)->data[-1] & 15); +	for (i=0; i<64; i++) { +		if (mal.bins[i].head != BIN_TO_CHUNK(i) && mal.bins[i].head) { +			fprintf(stderr, "bin %d: %p\n", i, mal.bins[i].head); +			if (!(mal.binmap & 1ULL<<i)) +				fprintf(stderr, "missing from binmap!\n"); +		} else if (mal.binmap & 1ULL<<i) +			fprintf(stderr, "binmap wrongly contains %d!\n", i); +	} +} +#endif + +static struct chunk *expand_heap(size_t n) +{ +	struct chunk *w; +	uintptr_t new; + +	lock(mal.brk_lock); + +	if (n > SIZE_MAX - mal.brk - 2*PAGE_SIZE) goto fail; +	new = mal.brk + n + SIZE_ALIGN + PAGE_SIZE - 1 & -PAGE_SIZE; +	n = new - mal.brk; + +	if (__brk(new) != new) goto fail; + +	w = MEM_TO_CHUNK(new); +	w->data[-1] = n | C_INUSE; +	w->data[0] = 0 | C_INUSE; + +	w = MEM_TO_CHUNK(mal.brk); +	w->data[0] = n | C_INUSE; +	mal.brk = new; +	 +	unlock(mal.brk_lock); + +	return w; +fail: +	unlock(mal.brk_lock); +	return 0; +} + +static int init_malloc() +{ +	static int init, waiters; +	int state; +	struct chunk *c; + +	if (init == 2) return 0; + +	while ((state=a_swap(&init, 1)) == 1) +		__wait(&init, &waiters, 1, 1); +	if (state) { +		a_store(&init, 2); +		return 0; +	} + +	mal.brk = __brk(0) + 2*SIZE_ALIGN-1 & -SIZE_ALIGN; + +	c = expand_heap(1); + +	if (!c) { +		a_store(&init, 0); +		if (waiters) __wake(&init, 1, 1); +		return -1; +	} + +	mal.heap = (void *)c; +	c->data[-1] = 0 | C_INUSE; +	free(CHUNK_TO_MEM(c)); + +	a_store(&init, 2); +	if (waiters) __wake(&init, -1, 1); +	return 0; +} + +static int adjust_size(size_t *n) +{ +	/* Result of pointer difference must fit in ptrdiff_t. */ +	if (*n > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE) { +		errno = ENOMEM; +		return -1; +	} +	*n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK; +	return 0; +} + +static void unbin(struct chunk *c, int i) +{ +	if (c->prev == c->next) +		a_and_64(&mal.binmap, ~(1ULL<<i)); +	c->prev->next = c->next; +	c->next->prev = c->prev; +	c->data[0] |= C_INUSE; +	NEXT_CHUNK(c)->data[-1] |= C_INUSE; +} + +static int alloc_fwd(struct chunk *c) +{ +	int i; +	size_t k; +	while (!((k=c->data[0]) & C_INUSE)) { +		i = bin_index(k); +		lock_bin(i); +		if (c->data[0] == k) { +			unbin(c, i); +			unlock_bin(i); +			return 1; +		} +		unlock_bin(i); +	} +	return 0; +} + +static int alloc_rev(struct chunk *c) +{ +	int i; +	size_t k; +	while (!((k=c->data[-1]) & C_INUSE)) { +		i = bin_index(k); +		lock_bin(i); +		if (c->data[-1] == k) { +			unbin(PREV_CHUNK(c), i); +			unlock_bin(i); +			return 1; +		} +		unlock_bin(i); +	} +	return 0; +} + + +/* pretrim - trims a chunk _prior_ to removing it from its bin. + * Must be called with i as the ideal bin for size n, j the bin + * for the _free_ chunk self, and bin j locked. */ +static int pretrim(struct chunk *self, size_t n, int i, int j) +{ +	size_t n1; +	struct chunk *next, *split; + +	/* We cannot pretrim if it would require re-binning. */ +	if (j < 40) return 0; +	if (j < i+3) { +		if (j != 63) return 0; +		n1 = CHUNK_SIZE(self); +		if (n1-n <= MMAP_THRESHOLD) return 0; +	} else { +		n1 = CHUNK_SIZE(self); +	} +	if (bin_index(n1-n) != j) return 0; + +	next = NEXT_CHUNK(self); +	split = (void *)((char *)self + n); + +	split->prev = self->prev; +	split->next = self->next; +	split->prev->next = split; +	split->next->prev = split; +	split->data[-1] = n | C_INUSE; +	split->data[0] = n1-n; +	next->data[-1] = n1-n; +	self->data[0] = n | C_INUSE; +	return 1; +} + +static void trim(struct chunk *self, size_t n) +{ +	size_t n1 = CHUNK_SIZE(self); +	struct chunk *next, *split; + +	if (n >= n1 - DONTCARE) return; + +	next = NEXT_CHUNK(self); +	split = (void *)((char *)self + n); + +	split->data[-1] = n | C_INUSE; +	split->data[0] = n1-n | C_INUSE; +	next->data[-1] = n1-n | C_INUSE; +	self->data[0] = n | C_INUSE; + +	free(CHUNK_TO_MEM(split)); +} + +void *malloc(size_t n) +{ +	struct chunk *c; +	int i, j; + +	if (!n || adjust_size(&n) < 0) return 0; + +	if (n > MMAP_THRESHOLD) { +		size_t len = n + PAGE_SIZE - 1 & -PAGE_SIZE; +		char *base = __mmap(0, len, PROT_READ|PROT_WRITE, +			MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); +		if (base == (void *)-1) return 0; +		c = (void *)(base + SIZE_ALIGN - sizeof(size_t)); +		c->data[0] = len - (SIZE_ALIGN - sizeof(size_t)); +		c->data[-1] = SIZE_ALIGN - sizeof(size_t); +		return CHUNK_TO_MEM(c); +	} + +	i = bin_index_up(n); +	for (;;) { +		uint64_t mask = mal.binmap & -(1ULL<<i); +		if (!mask) { +			init_malloc(); +			c = expand_heap(n); +			if (!c) return 0; +			if (alloc_rev(c)) { +				struct chunk *x = c; +				c = PREV_CHUNK(c); +				NEXT_CHUNK(x)->data[-1] = c->data[0] = +					x->data[0] + CHUNK_SIZE(c); +			} +			break; +		} +		j = first_set(mask); +		lock_bin(j); +		c = mal.bins[j].head; +		if (c != BIN_TO_CHUNK(j) && j == bin_index(c->data[0])) { +			if (!pretrim(c, n, i, j)) unbin(c, j); +			unlock_bin(j); +			break; +		} +		unlock_bin(j); +	} + +	/* Now patch up in case we over-allocated */ +	trim(c, n); + +	return CHUNK_TO_MEM(c); +} + +void *realloc(void *p, size_t n) +{ +	struct chunk *self, *next; +	size_t n0, n1; +	void *new; + +	if (!p) return malloc(n); +	else if (!n) return free(p), (void *)0; + +	if (adjust_size(&n) < 0) return 0; + +	self = MEM_TO_CHUNK(p); +	n1 = n0 = CHUNK_SIZE(self); + +	if (IS_MMAPPED(self)) { +		size_t extra = self->data[-1]; +		char *base = (char *)self - extra; +		size_t oldlen = n0 + extra; +		size_t newlen = n + extra; +		if (newlen < PAGE_SIZE && (new = malloc(n))) { +			memcpy(new, p, n-OVERHEAD); +			free(p); +			return new; +		} +		newlen = (newlen + PAGE_SIZE-1) & -PAGE_SIZE; +		if (oldlen == newlen) return p; +		base = __mremap(base, oldlen, newlen, MREMAP_MAYMOVE); +		if (base == (void *)-1) +			return newlen < oldlen ? p : 0; +		self = (void *)(base + extra); +		self->data[0] = newlen - extra; +		return CHUNK_TO_MEM(self); +	} + +	next = NEXT_CHUNK(self); + +	/* Merge adjacent chunks if we need more space. This is not +	 * a waste of time even if we fail to get enough space, because our +	 * subsequent call to free would otherwise have to do the merge. */ +	if (n > n1 && alloc_fwd(next)) { +		n1 += CHUNK_SIZE(next); +		next = NEXT_CHUNK(next); +	} +	/* FIXME: find what's wrong here and reenable it..? */ +	if (0 && n > n1 && alloc_rev(self)) { +		self = PREV_CHUNK(self); +		n1 += CHUNK_SIZE(self); +	} +	self->data[0] = n1 | C_INUSE; +	next->data[-1] = n1 | C_INUSE; + +	/* If we got enough space, split off the excess and return */ +	if (n <= n1) { +		//memmove(CHUNK_TO_MEM(self), p, n0-OVERHEAD); +		trim(self, n); +		return CHUNK_TO_MEM(self); +	} + +	/* As a last resort, allocate a new chunk and copy to it. */ +	new = malloc(n-OVERHEAD); +	if (!new) return 0; +	memcpy(new, p, n0-OVERHEAD); +	free(CHUNK_TO_MEM(self)); +	return new; +} + +void free(void *p) +{ +	struct chunk *self = MEM_TO_CHUNK(p); +	struct chunk *next; +	size_t final_size, new_size, size; +	int reclaim=0; +	int i; + +	if (!p) return; + +	if (IS_MMAPPED(self)) { +		size_t extra = self->data[-1]; +		char *base = (char *)self - extra; +		size_t len = CHUNK_SIZE(self) + extra; +		__munmap(base, len); +		return; +	} + +	final_size = new_size = CHUNK_SIZE(self); +	next = NEXT_CHUNK(self); + +	for (;;) { +		/* Replace middle of large chunks with fresh zero pages */ +		if (reclaim && (self->data[-1] & next->data[0] & C_INUSE)) { +			uintptr_t a = (uintptr_t)self + SIZE_ALIGN+PAGE_SIZE-1 & -PAGE_SIZE; +			uintptr_t b = (uintptr_t)next - SIZE_ALIGN & -PAGE_SIZE; +#if 1 +			__madvise((void *)a, b-a, MADV_DONTNEED); +#else +			__mmap((void *)a, b-a, PROT_READ|PROT_WRITE, +				MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0); +#endif +		} + +		if (self->data[-1] & next->data[0] & C_INUSE) { +			self->data[0] = final_size | C_INUSE; +			next->data[-1] = final_size | C_INUSE; +			i = bin_index(final_size); +			lock_bin(i); +			lock(mal.free_lock); +			if (self->data[-1] & next->data[0] & C_INUSE) +				break; +			unlock(mal.free_lock); +			unlock_bin(i); +		} + +		if (alloc_rev(self)) { +			self = PREV_CHUNK(self); +			size = CHUNK_SIZE(self); +			final_size += size; +			if (new_size+size > RECLAIM && (new_size+size^size) > size) +				reclaim = 1; +		} + +		if (alloc_fwd(next)) { +			size = CHUNK_SIZE(next); +			final_size += size; +			if (new_size+size > RECLAIM && (new_size+size^size) > size) +				reclaim = 1; +			next = NEXT_CHUNK(next); +		} +	} + +	self->data[0] = final_size; +	next->data[-1] = final_size; +	unlock(mal.free_lock); + +	self->next = BIN_TO_CHUNK(i); +	self->prev = mal.bins[i].tail; +	self->next->prev = self; +	self->prev->next = self; + +	if (!(mal.binmap & 1ULL<<i)) +		a_or_64(&mal.binmap, 1ULL<<i); + +	unlock_bin(i); +} diff --git a/src/malloc/memalign.c b/src/malloc/memalign.c new file mode 100644 index 00000000..61f456e4 --- /dev/null +++ b/src/malloc/memalign.c @@ -0,0 +1,13 @@ +#include <stdlib.h> +#include <errno.h> + +void *memalign(size_t align, size_t len) +{ +	void *mem; +	int ret; +	if ((ret = posix_memalign(&mem, align, len))) { +		errno = ret; +		return 0; +	} +	return mem; +} diff --git a/src/malloc/posix_memalign.c b/src/malloc/posix_memalign.c new file mode 100644 index 00000000..ef86260d --- /dev/null +++ b/src/malloc/posix_memalign.c @@ -0,0 +1,47 @@ +#include <stdlib.h> +#include <stdint.h> +#include <errno.h> + +/* This function should work with most dlmalloc-like chunk bookkeeping + * systems, but it's only guaranteed to work with the native implementation + * used in this library. */ + +int posix_memalign(void **res, size_t align, size_t len) +{ +	unsigned char *mem, *new, *end; +	size_t header, footer; + +	if ((align & -align) != align) return EINVAL; +	if (len > SIZE_MAX - align) return ENOMEM; + +	if (align <= 4*sizeof(size_t)) { +		if (!(mem = malloc(len))) +			return errno; +		*res = mem; +		return 0; +	} + +	if (!(mem = malloc(len + align-1))) +		return errno; + +	header = ((size_t *)mem)[-1]; +	end = mem + (header & -8); +	footer = ((size_t *)end)[-2]; +	new = (void *)((uintptr_t)mem + align-1 & -align); + +	if (!(header & 7)) { +		((size_t *)new)[-2] = ((size_t *)mem)[-2] + (new-mem); +		((size_t *)new)[-1] = ((size_t *)mem)[-1] - (new-mem); +		*res = new; +		return 0; +	} + +	((size_t *)mem)[-1] = header&7 | new-mem; +	((size_t *)new)[-2] = footer&7 | new-mem; +	((size_t *)new)[-1] = header&7 | end-new; +	((size_t *)end)[-2] = footer&7 | end-new; + +	if (new != mem) free(mem); +	*res = new; +	return 0; +} diff --git a/src/math/__fpclassify.c b/src/math/__fpclassify.c new file mode 100644 index 00000000..16051100 --- /dev/null +++ b/src/math/__fpclassify.c @@ -0,0 +1,14 @@ +#include <stdint.h> +#include <math.h> + +int __fpclassify(double __x) +{ +	union { +		double __d; +		__uint64_t __i; +	} __y = { __x }; +	int __ee = __y.__i>>52 & 0x7ff; +	if (!__ee) return __y.__i<<1 ? FP_SUBNORMAL : FP_ZERO; +	if (__ee==0x7ff) return __y.__i<<12 ? FP_NAN : FP_INFINITE; +	return FP_NORMAL; +} diff --git a/src/math/__fpclassifyf.c b/src/math/__fpclassifyf.c new file mode 100644 index 00000000..bf59d0d4 --- /dev/null +++ b/src/math/__fpclassifyf.c @@ -0,0 +1,14 @@ +#include <stdint.h> +#include <math.h> + +int __fpclassifyf(float __x) +{ +	union { +		float __f; +		__uint32_t __i; +	} __y = { __x }; +	int __ee = __y.__i>>23 & 0xff; +	if (!__ee) return __y.__i<<1 ? FP_SUBNORMAL : FP_ZERO; +	if (__ee==0xff) return __y.__i<<9 ? FP_NAN : FP_INFINITE; +	return FP_NORMAL; +} diff --git a/src/math/__fpclassifyl.c b/src/math/__fpclassifyl.c new file mode 100644 index 00000000..4f93bef1 --- /dev/null +++ b/src/math/__fpclassifyl.c @@ -0,0 +1,16 @@ +#include <stdint.h> +#include <math.h> + +/* FIXME: move this to arch-specific file */ +int __fpclassifyl(long double __x) +{ +	union { +		long double __ld; +		__uint16_t __hw[5]; +		__uint64_t __m; +	} __y = { __x }; +	int __ee = __y.__hw[4]&0x7fff; +	if (!__ee) return __y.__m ? FP_SUBNORMAL : FP_ZERO; +	if (__ee==0x7fff) return __y.__m ? FP_NAN : FP_INFINITE; +	return FP_NORMAL; +} diff --git a/src/math/e_acos.c b/src/math/e_acos.c new file mode 100644 index 00000000..e0236391 --- /dev/null +++ b/src/math/e_acos.c @@ -0,0 +1,99 @@ +/* @(#)e_acos.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* acos(x) + * Method :                   + *      acos(x)  = pi/2 - asin(x) + *      acos(-x) = pi/2 + asin(x) + * For |x|<=0.5 + *      acos(x) = pi/2 - (x + x*x^2*R(x^2))     (see asin.c) + * For x>0.5 + *      acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2))) + *              = 2asin(sqrt((1-x)/2))   + *              = 2s + 2s*z*R(z)        ...z=(1-x)/2, s=sqrt(z) + *              = 2f + (2c + 2s*z*R(z)) + *     where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term + *     for f so that f+c ~ sqrt(z). + * For x<-0.5 + *      acos(x) = pi - 2asin(sqrt((1-|x|)/2)) + *              = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z) + * + * Special cases: + *      if x is NaN, return x itself; + *      if |x|>1, return NaN with invalid signal. + * + * Function needed: sqrt + */ + +#include <math.h> +#include "math_private.h" + +static const double +one=  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +pi =  3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */ +pio2_hi =  1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ +pio2_lo =  6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +pS0 =  1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 =  2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 =  7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 =  3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 =  2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 =  7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +double +acos(double x) +{ +        double z,p,q,r,w,s,c,df; +        int32_t hx,ix; +        GET_HIGH_WORD(hx,x); +        ix = hx&0x7fffffff; +        if(ix>=0x3ff00000) {    /* |x| >= 1 */ +            uint32_t lx; +            GET_LOW_WORD(lx,x); +            if(((ix-0x3ff00000)|lx)==0) {       /* |x|==1 */ +                if(hx>0) return 0.0;            /* acos(1) = 0  */ +                else return pi+2.0*pio2_lo;     /* acos(-1)= pi */ +            } +            return (x-x)/(x-x);         /* acos(|x|>1) is NaN */ +        } +        if(ix<0x3fe00000) {     /* |x| < 0.5 */ +            if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/ +            z = x*x; +            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); +            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); +            r = p/q; +            return pio2_hi - (x - (pio2_lo-x*r)); +        } else  if (hx<0) {             /* x < -0.5 */ +            z = (one+x)*0.5; +            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); +            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); +            s = sqrt(z); +            r = p/q; +            w = r*s-pio2_lo; +            return pi - 2.0*(s+w); +        } else {                        /* x > 0.5 */ +            z = (one-x)*0.5; +            s = sqrt(z); +            df = s; +            SET_LOW_WORD(df,0); +            c  = (z-df*df)/(s+df); +            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); +            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); +            r = p/q; +            w = r*s+c; +            return 2.0*(df+w); +        } +} diff --git a/src/math/e_acosf.c b/src/math/e_acosf.c new file mode 100644 index 00000000..4c59781b --- /dev/null +++ b/src/math/e_acosf.c @@ -0,0 +1,77 @@ +/* e_acosf.c -- float version of e_acos.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +one =  1.0000000000e+00, /* 0x3F800000 */ +pi =  3.1415925026e+00, /* 0x40490fda */ +pio2_hi =  1.5707962513e+00, /* 0x3fc90fda */ +pio2_lo =  7.5497894159e-08, /* 0x33a22168 */ +pS0 =  1.6666667163e-01, /* 0x3e2aaaab */ +pS1 = -3.2556581497e-01, /* 0xbea6b090 */ +pS2 =  2.0121252537e-01, /* 0x3e4e0aa8 */ +pS3 = -4.0055535734e-02, /* 0xbd241146 */ +pS4 =  7.9153501429e-04, /* 0x3a4f7f04 */ +pS5 =  3.4793309169e-05, /* 0x3811ef08 */ +qS1 = -2.4033949375e+00, /* 0xc019d139 */ +qS2 =  2.0209457874e+00, /* 0x4001572d */ +qS3 = -6.8828397989e-01, /* 0xbf303361 */ +qS4 =  7.7038154006e-02; /* 0x3d9dc62e */ + +float +acosf(float x) +{ +        float z,p,q,r,w,s,c,df; +        int32_t hx,ix; +        GET_FLOAT_WORD(hx,x); +        ix = hx&0x7fffffff; +        if(ix==0x3f800000) {            /* |x|==1 */ +            if(hx>0) return 0.0;        /* acos(1) = 0  */ +            else return pi+(float)2.0*pio2_lo;  /* acos(-1)= pi */ +        } else if(ix>0x3f800000) {      /* |x| >= 1 */ +            return (x-x)/(x-x);         /* acos(|x|>1) is NaN */ +        } +        if(ix<0x3f000000) {     /* |x| < 0.5 */ +            if(ix<=0x23000000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/ +            z = x*x; +            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); +            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); +            r = p/q; +            return pio2_hi - (x - (pio2_lo-x*r)); +        } else  if (hx<0) {             /* x < -0.5 */ +            z = (one+x)*(float)0.5; +            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); +            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); +            s = sqrtf(z); +            r = p/q; +            w = r*s-pio2_lo; +            return pi - (float)2.0*(s+w); +        } else {                        /* x > 0.5 */ +            int32_t idf; +            z = (one-x)*(float)0.5; +            s = sqrtf(z); +            df = s; +            GET_FLOAT_WORD(idf,df); +            SET_FLOAT_WORD(df,idf&0xfffff000); +            c  = (z-df*df)/(s+df); +            p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5))))); +            q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4))); +            r = p/q; +            w = r*s+c; +            return (float)2.0*(df+w); +        } +} diff --git a/src/math/e_acosh.c b/src/math/e_acosh.c new file mode 100644 index 00000000..8b454e75 --- /dev/null +++ b/src/math/e_acosh.c @@ -0,0 +1,59 @@ + +/* @(#)e_acosh.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + * + */ + +/* acosh(x) + * Method : + *      Based on  + *              acosh(x) = log [ x + sqrt(x*x-1) ] + *      we have + *              acosh(x) := log(x)+ln2, if x is large; else + *              acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else + *              acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1. + * + * Special cases: + *      acosh(x) is NaN with signal if x<1. + *      acosh(NaN) is NaN without signal. + */ + +#include <math.h> +#include "math_private.h" + +static const double +one     = 1.0, +ln2     = 6.93147180559945286227e-01;  /* 0x3FE62E42, 0xFEFA39EF */ + +double +acosh(double x) +{ +        double t; +        int32_t hx; +        uint32_t lx; +        EXTRACT_WORDS(hx,lx,x); +        if(hx<0x3ff00000) {             /* x < 1 */ +            return (x-x)/(x-x); +        } else if(hx >=0x41b00000) {    /* x > 2**28 */ +            if(hx >=0x7ff00000) {       /* x is inf of NaN */ +                return x+x; +            } else  +                return log(x)+ln2;    /* acosh(huge)=log(2x) */ +        } else if(((hx-0x3ff00000)|lx)==0) { +            return 0.0;                 /* acosh(1) = 0 */ +        } else if (hx > 0x40000000) {   /* 2**28 > x > 2 */ +            t=x*x; +            return log(2.0*x-one/(x+sqrt(t-one))); +        } else {                        /* 1<x<2 */ +            t = x-one; +            return log1p(t+sqrt(2.0*t+t*t)); +        } +} diff --git a/src/math/e_acoshf.c b/src/math/e_acoshf.c new file mode 100644 index 00000000..b7f1df69 --- /dev/null +++ b/src/math/e_acoshf.c @@ -0,0 +1,45 @@ +/* e_acoshf.c -- float version of e_acosh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +one     = 1.0, +ln2     = 6.9314718246e-01;  /* 0x3f317218 */ + +float +acoshf(float x) +{ +        float t; +        int32_t hx; +        GET_FLOAT_WORD(hx,x); +        if(hx<0x3f800000) {             /* x < 1 */ +            return (x-x)/(x-x); +        } else if(hx >=0x4d800000) {    /* x > 2**28 */ +            if(hx >=0x7f800000) {       /* x is inf of NaN */ +                return x+x; +            } else +                return logf(x)+ln2;     /* acosh(huge)=log(2x) */ +        } else if (hx==0x3f800000) { +            return 0.0;                 /* acosh(1) = 0 */ +        } else if (hx > 0x40000000) {   /* 2**28 > x > 2 */ +            t=x*x; +            return logf((float)2.0*x-one/(x+sqrtf(t-one))); +        } else {                        /* 1<x<2 */ +            t = x-one; +            return log1pf(t+sqrtf((float)2.0*t+t*t)); +        } +} diff --git a/src/math/e_asin.c b/src/math/e_asin.c new file mode 100644 index 00000000..4bf162a1 --- /dev/null +++ b/src/math/e_asin.c @@ -0,0 +1,109 @@ + +/* @(#)e_asin.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* asin(x) + * Method :                   + *      Since  asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ... + *      we approximate asin(x) on [0,0.5] by + *              asin(x) = x + x*x^2*R(x^2) + *      where + *              R(x^2) is a rational approximation of (asin(x)-x)/x^3  + *      and its remez error is bounded by + *              |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75) + * + *      For x in [0.5,1] + *              asin(x) = pi/2-2*asin(sqrt((1-x)/2)) + *      Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2; + *      then for x>0.98 + *              asin(x) = pi/2 - 2*(s+s*z*R(z)) + *                      = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo) + *      For x<=0.98, let pio4_hi = pio2_hi/2, then + *              f = hi part of s; + *              c = sqrt(z) - f = (z-f*f)/(s+f)         ...f+c=sqrt(z) + *      and + *              asin(x) = pi/2 - 2*(s+s*z*R(z)) + *                      = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo) + *                      = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c)) + * + * Special cases: + *      if x is NaN, return x itself; + *      if |x|>1, return NaN with invalid signal. + * + */ + + +#include <math.h> +#include "math_private.h" + +static const double +one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +huge =  1.000e+300, +pio2_hi =  1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */ +pio2_lo =  6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */ +pio4_hi =  7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */ +        /* coefficient for R(x^2) */ +pS0 =  1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */ +pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */ +pS2 =  2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */ +pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */ +pS4 =  7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */ +pS5 =  3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */ +qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */ +qS2 =  2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */ +qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */ +qS4 =  7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */ + +double +asin(double x) +{ +        double t=0.0,w,p,q,c,r,s; +        int32_t hx,ix; +        GET_HIGH_WORD(hx,x); +        ix = hx&0x7fffffff; +        if(ix>= 0x3ff00000) {           /* |x|>= 1 */ +            uint32_t lx; +            GET_LOW_WORD(lx,x); +            if(((ix-0x3ff00000)|lx)==0) +                    /* asin(1)=+-pi/2 with inexact */ +                return x*pio2_hi+x*pio2_lo;      +            return (x-x)/(x-x);         /* asin(|x|>1) is NaN */    +        } else if (ix<0x3fe00000) {     /* |x|<0.5 */ +            if(ix<0x3e400000) {         /* if |x| < 2**-27 */ +                if(huge+x>one) return x;/* return x with inexact if x!=0*/ +            } else  +                t = x*x; +                p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5))))); +                q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4))); +                w = p/q; +                return x+x*w; +        } +        /* 1> |x|>= 0.5 */ +        w = one-fabs(x); +        t = w*0.5; +        p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5))))); +        q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4))); +        s = sqrt(t); +        if(ix>=0x3FEF3333) {    /* if |x| > 0.975 */ +            w = p/q; +            t = pio2_hi-(2.0*(s+s*w)-pio2_lo); +        } else { +            w  = s; +            SET_LOW_WORD(w,0); +            c  = (t-w*w)/(s+w); +            r  = p/q; +            p  = 2.0*s*r-(pio2_lo-2.0*c); +            q  = pio4_hi-2.0*w; +            t  = pio4_hi-(p-q); +        }     +        if(hx>0) return t; else return -t;     +} diff --git a/src/math/e_asinf.c b/src/math/e_asinf.c new file mode 100644 index 00000000..9c693970 --- /dev/null +++ b/src/math/e_asinf.c @@ -0,0 +1,80 @@ +/* e_asinf.c -- float version of e_asin.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +one =  1.0000000000e+00, /* 0x3F800000 */ +huge =  1.000e+30, +pio2_hi =  1.5707962513e+00, /* 0x3fc90fda */ +pio2_lo =  7.5497894159e-08, /* 0x33a22168 */ +pio4_hi =  7.8539818525e-01, /* 0x3f490fdb */ +	/* coefficient for R(x^2) */ +pS0 =  1.6666667163e-01, /* 0x3e2aaaab */ +pS1 = -3.2556581497e-01, /* 0xbea6b090 */ +pS2 =  2.0121252537e-01, /* 0x3e4e0aa8 */ +pS3 = -4.0055535734e-02, /* 0xbd241146 */ +pS4 =  7.9153501429e-04, /* 0x3a4f7f04 */ +pS5 =  3.4793309169e-05, /* 0x3811ef08 */ +qS1 = -2.4033949375e+00, /* 0xc019d139 */ +qS2 =  2.0209457874e+00, /* 0x4001572d */ +qS3 = -6.8828397989e-01, /* 0xbf303361 */ +qS4 =  7.7038154006e-02; /* 0x3d9dc62e */ + +float +asinf(float x) +{ +	float t=0.0,w,p,q,c,r,s; +	int32_t hx,ix; +	GET_FLOAT_WORD(hx,x); +	ix = hx&0x7fffffff; +	if(ix==0x3f800000) { +		/* asin(1)=+-pi/2 with inexact */ +	    return x*pio2_hi+x*pio2_lo; +	} else if(ix> 0x3f800000) {	/* |x|>= 1 */ +	    return (x-x)/(x-x);		/* asin(|x|>1) is NaN */ +	} else if (ix<0x3f000000) {	/* |x|<0.5 */ +	    if(ix<0x32000000) {		/* if |x| < 2**-27 */ +		if(huge+x>one) return x;/* return x with inexact if x!=0*/ +	    } else +		t = x*x; +		p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5))))); +		q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4))); +		w = p/q; +		return x+x*w; +	} +	/* 1> |x|>= 0.5 */ +	w = one-fabsf(x); +	t = w*(float)0.5; +	p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5))))); +	q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4))); +	s = sqrtf(t); +	if(ix>=0x3F79999A) { 	/* if |x| > 0.975 */ +	    w = p/q; +	    t = pio2_hi-((float)2.0*(s+s*w)-pio2_lo); +	} else { +	    int32_t iw; +	    w  = s; +	    GET_FLOAT_WORD(iw,w); +	    SET_FLOAT_WORD(w,iw&0xfffff000); +	    c  = (t-w*w)/(s+w); +	    r  = p/q; +	    p  = (float)2.0*s*r-(pio2_lo-(float)2.0*c); +	    q  = pio4_hi-(float)2.0*w; +	    t  = pio4_hi-(p-q); +	} +	if(hx>0) return t; else return -t; +} diff --git a/src/math/e_atan2.c b/src/math/e_atan2.c new file mode 100644 index 00000000..dd021164 --- /dev/null +++ b/src/math/e_atan2.c @@ -0,0 +1,120 @@ + +/* @(#)e_atan2.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + * + */ + +/* atan2(y,x) + * Method : + *      1. Reduce y to positive by atan2(y,x)=-atan2(-y,x). + *      2. Reduce x to positive by (if x and y are unexceptional):  + *              ARG (x+iy) = arctan(y/x)           ... if x > 0, + *              ARG (x+iy) = pi - arctan[y/(-x)]   ... if x < 0, + * + * Special cases: + * + *      ATAN2((anything), NaN ) is NaN; + *      ATAN2(NAN , (anything) ) is NaN; + *      ATAN2(+-0, +(anything but NaN)) is +-0  ; + *      ATAN2(+-0, -(anything but NaN)) is +-pi ; + *      ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2; + *      ATAN2(+-(anything but INF and NaN), +INF) is +-0 ; + *      ATAN2(+-(anything but INF and NaN), -INF) is +-pi; + *      ATAN2(+-INF,+INF ) is +-pi/4 ; + *      ATAN2(+-INF,-INF ) is +-3pi/4; + *      ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2; + * + * Constants: + * The hexadecimal values are the intended ones for the following  + * constants. The decimal values may be used, provided that the  + * compiler will convert from decimal to binary accurately enough  + * to produce the hexadecimal values shown. + */ + +#include <math.h> +#include "math_private.h" + +static const double +tiny  = 1.0e-300, +zero  = 0.0, +pi_o_4  = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */ +pi_o_2  = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */ +pi      = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */ +pi_lo   = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */ + +double +atan2(double y, double x) +{ +        double z; +        int32_t k,m,hx,hy,ix,iy; +        uint32_t lx,ly; + +        EXTRACT_WORDS(hx,lx,x); +        ix = hx&0x7fffffff; +        EXTRACT_WORDS(hy,ly,y); +        iy = hy&0x7fffffff; +        if(((ix|((lx|-lx)>>31))>0x7ff00000)|| +           ((iy|((ly|-ly)>>31))>0x7ff00000))    /* x or y is NaN */ +           return x+y; +        if(((hx-0x3ff00000)|lx)==0) return atan(y);   /* x=1.0 */ +        m = ((hy>>31)&1)|((hx>>30)&2);  /* 2*sign(x)+sign(y) */ + +    /* when y = 0 */ +        if((iy|ly)==0) { +            switch(m) { +                case 0:  +                case 1: return y;       /* atan(+-0,+anything)=+-0 */ +                case 2: return  pi+tiny;/* atan(+0,-anything) = pi */ +                case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */ +            } +        } +    /* when x = 0 */ +        if((ix|lx)==0) return (hy<0)?  -pi_o_2-tiny: pi_o_2+tiny; +             +    /* when x is INF */ +        if(ix==0x7ff00000) { +            if(iy==0x7ff00000) { +                switch(m) { +                    case 0: return  pi_o_4+tiny;/* atan(+INF,+INF) */ +                    case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */ +                    case 2: return  3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/ +                    case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/ +                } +            } else { +                switch(m) { +                    case 0: return  zero  ;     /* atan(+...,+INF) */ +                    case 1: return -zero  ;     /* atan(-...,+INF) */ +                    case 2: return  pi+tiny  ;  /* atan(+...,-INF) */ +                    case 3: return -pi-tiny  ;  /* atan(-...,-INF) */ +                } +            } +        } +    /* when y is INF */ +        if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + +    /* compute y/x */ +        k = (iy-ix)>>20; +        if(k > 60) z=pi_o_2+0.5*pi_lo;  /* |y/x| >  2**60 */ +        else if(hx<0&&k<-60) z=0.0;     /* |y|/x < -2**60 */ +        else z=atan(fabs(y/x));         /* safe to do y/x */ +        switch (m) { +            case 0: return       z  ;   /* atan(+,+) */ +            case 1: { +                      uint32_t zh; +                      GET_HIGH_WORD(zh,z); +                      SET_HIGH_WORD(z,zh ^ 0x80000000); +                    } +                    return       z  ;   /* atan(-,+) */ +            case 2: return  pi-(z-pi_lo);/* atan(+,-) */ +            default: /* case 3 */ +                    return  (z-pi_lo)-pi;/* atan(-,-) */ +        } +} diff --git a/src/math/e_atan2f.c b/src/math/e_atan2f.c new file mode 100644 index 00000000..535e10a0 --- /dev/null +++ b/src/math/e_atan2f.c @@ -0,0 +1,93 @@ +/* e_atan2f.c -- float version of e_atan2.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +tiny  = 1.0e-30, +zero  = 0.0, +pi_o_4  = 7.8539818525e-01, /* 0x3f490fdb */ +pi_o_2  = 1.5707963705e+00, /* 0x3fc90fdb */ +pi      = 3.1415927410e+00, /* 0x40490fdb */ +pi_lo   = -8.7422776573e-08; /* 0xb3bbbd2e */ + +float +atan2f(float y, float x) +{ +        float z; +        int32_t k,m,hx,hy,ix,iy; + +        GET_FLOAT_WORD(hx,x); +        ix = hx&0x7fffffff; +        GET_FLOAT_WORD(hy,y); +        iy = hy&0x7fffffff; +        if((ix>0x7f800000)|| +           (iy>0x7f800000))     /* x or y is NaN */ +           return x+y; +        if(hx==0x3f800000) return atanf(y);   /* x=1.0 */ +        m = ((hy>>31)&1)|((hx>>30)&2);  /* 2*sign(x)+sign(y) */ + +    /* when y = 0 */ +        if(iy==0) { +            switch(m) { +                case 0: +                case 1: return y;       /* atan(+-0,+anything)=+-0 */ +                case 2: return  pi+tiny;/* atan(+0,-anything) = pi */ +                case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */ +            } +        } +    /* when x = 0 */ +        if(ix==0) return (hy<0)?  -pi_o_2-tiny: pi_o_2+tiny; + +    /* when x is INF */ +        if(ix==0x7f800000) { +            if(iy==0x7f800000) { +                switch(m) { +                    case 0: return  pi_o_4+tiny;/* atan(+INF,+INF) */ +                    case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */ +                    case 2: return  (float)3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/ +                    case 3: return (float)-3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/ +                } +            } else { +                switch(m) { +                    case 0: return  zero  ;     /* atan(+...,+INF) */ +                    case 1: return -zero  ;     /* atan(-...,+INF) */ +                    case 2: return  pi+tiny  ;  /* atan(+...,-INF) */ +                    case 3: return -pi-tiny  ;  /* atan(-...,-INF) */ +                } +            } +        } +    /* when y is INF */ +        if(iy==0x7f800000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny; + +    /* compute y/x */ +        k = (iy-ix)>>23; +        if(k > 60) z=pi_o_2+(float)0.5*pi_lo;   /* |y/x| >  2**60 */ +        else if(hx<0&&k<-60) z=0.0;     /* |y|/x < -2**60 */ +        else z=atanf(fabsf(y/x));       /* safe to do y/x */ +        switch (m) { +            case 0: return       z  ;   /* atan(+,+) */ +            case 1: { +                      uint32_t zh; +                      GET_FLOAT_WORD(zh,z); +                      SET_FLOAT_WORD(z,zh ^ 0x80000000); +                    } +                    return       z  ;   /* atan(-,+) */ +            case 2: return  pi-(z-pi_lo);/* atan(+,-) */ +            default: /* case 3 */ +                    return  (z-pi_lo)-pi;/* atan(-,-) */ +        } +} diff --git a/src/math/e_atanh.c b/src/math/e_atanh.c new file mode 100644 index 00000000..45f1c966 --- /dev/null +++ b/src/math/e_atanh.c @@ -0,0 +1,59 @@ + +/* @(#)e_atanh.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + * + */ + +/* atanh(x) + * Method : + *    1.Reduced x to positive by atanh(-x) = -atanh(x) + *    2.For x>=0.5 + *                  1              2x                          x + *      atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------) + *                  2             1 - x                      1 - x + *       + *      For x<0.5 + *      atanh(x) = 0.5*log1p(2x+2x*x/(1-x)) + * + * Special cases: + *      atanh(x) is NaN if |x| > 1 with signal; + *      atanh(NaN) is that NaN with no signal; + *      atanh(+-1) is +-INF with signal. + * + */ + +#include <math.h> +#include "math_private.h" + +static const double one = 1.0, huge = 1e300; +static const double zero = 0.0; + +double +atanh(double x) +{ +        double t; +        int32_t hx,ix; +        uint32_t lx; +        EXTRACT_WORDS(hx,lx,x); +        ix = hx&0x7fffffff; +        if ((ix|((lx|(-lx))>>31))>0x3ff00000) /* |x|>1 */ +            return (x-x)/(x-x); +        if(ix==0x3ff00000)  +            return x/zero; +        if(ix<0x3e300000&&(huge+x)>zero) return x;      /* x<2**-28 */ +        SET_HIGH_WORD(x,ix); +        if(ix<0x3fe00000) {             /* x < 0.5 */ +            t = x+x; +            t = 0.5*log1p(t+t*x/(one-x)); +        } else  +            t = 0.5*log1p((x+x)/(one-x)); +        if(hx>=0) return t; else return -t; +} diff --git a/src/math/e_atanhf.c b/src/math/e_atanhf.c new file mode 100644 index 00000000..7356cfc9 --- /dev/null +++ b/src/math/e_atanhf.c @@ -0,0 +1,42 @@ +/* e_atanhf.c -- float version of e_atanh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float one = 1.0, huge = 1e30; + +static const float zero = 0.0; + +float +atanhf(float x) +{ +        float t; +        int32_t hx,ix; +        GET_FLOAT_WORD(hx,x); +        ix = hx&0x7fffffff; +        if (ix>0x3f800000)              /* |x|>1 */ +            return (x-x)/(x-x); +        if(ix==0x3f800000) +            return x/zero; +        if(ix<0x31800000&&(huge+x)>zero) return x;      /* x<2**-28 */ +        SET_FLOAT_WORD(x,ix); +        if(ix<0x3f000000) {             /* x < 0.5 */ +            t = x+x; +            t = (float)0.5*log1pf(t+t*x/(one-x)); +        } else +            t = (float)0.5*log1pf((x+x)/(one-x)); +        if(hx>=0) return t; else return -t; +} diff --git a/src/math/e_cosh.c b/src/math/e_cosh.c new file mode 100644 index 00000000..ad425bd3 --- /dev/null +++ b/src/math/e_cosh.c @@ -0,0 +1,82 @@ + +/* @(#)e_cosh.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* cosh(x) + * Method :  + * mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2 + *      1. Replace x by |x| (cosh(x) = cosh(-x)).  + *      2.  + *                                                      [ exp(x) - 1 ]^2  + *          0        <= x <= ln2/2  :  cosh(x) := 1 + ------------------- + *                                                         2*exp(x) + * + *                                                exp(x) +  1/exp(x) + *          ln2/2    <= x <= 22     :  cosh(x) := ------------------- + *                                                        2 + *          22       <= x <= lnovft :  cosh(x) := exp(x)/2  + *          lnovft   <= x <= ln2ovft:  cosh(x) := exp(x/2)/2 * exp(x/2) + *          ln2ovft  <  x           :  cosh(x) := huge*huge (overflow) + * + * Special cases: + *      cosh(x) is |x| if x is +INF, -INF, or NaN. + *      only cosh(0)=1 is exact for finite x. + */ + +#include <math.h> +#include "math_private.h" + +static const double one = 1.0, half=0.5, huge = 1.0e300; + +double +cosh(double x) +{ +        double t,w; +        int32_t ix; +        uint32_t lx; + +    /* High word of |x|. */ +        GET_HIGH_WORD(ix,x); +        ix &= 0x7fffffff; + +    /* x is INF or NaN */ +        if(ix>=0x7ff00000) return x*x;   + +    /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */ +        if(ix<0x3fd62e43) { +            t = expm1(fabs(x)); +            w = one+t; +            if (ix<0x3c800000) return w;        /* cosh(tiny) = 1 */ +            return one+(t*t)/(w+w); +        } + +    /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */ +        if (ix < 0x40360000) { +                t = exp(fabs(x)); +                return half*t+half/t; +        } + +    /* |x| in [22, log(maxdouble)] return half*exp(|x|) */ +        if (ix < 0x40862E42)  return half*exp(fabs(x)); + +    /* |x| in [log(maxdouble), overflowthresold] */ +        GET_LOW_WORD(lx,x); +        if (ix<0x408633CE || +              ((ix==0x408633ce)&&(lx<=(uint32_t)0x8fb9f87d))) { +            w = exp(half*fabs(x)); +            t = half*w; +            return t*w; +        } + +    /* |x| > overflowthresold, cosh(x) overflow */ +        return huge*huge; +} diff --git a/src/math/e_coshf.c b/src/math/e_coshf.c new file mode 100644 index 00000000..6db10885 --- /dev/null +++ b/src/math/e_coshf.c @@ -0,0 +1,59 @@ +/* e_coshf.c -- float version of e_cosh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float one = 1.0, half=0.5, huge = 1.0e30; + +float +coshf(float x) +{ +        float t,w; +        int32_t ix; + +        GET_FLOAT_WORD(ix,x); +        ix &= 0x7fffffff; + +    /* x is INF or NaN */ +        if(ix>=0x7f800000) return x*x; + +    /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */ +        if(ix<0x3eb17218) { +            t = expm1f(fabsf(x)); +            w = one+t; +            if (ix<0x24000000) return w;        /* cosh(tiny) = 1 */ +            return one+(t*t)/(w+w); +        } + +    /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */ +        if (ix < 0x41b00000) { +                t = expf(fabsf(x)); +                return half*t+half/t; +        } + +    /* |x| in [22, log(maxdouble)] return half*exp(|x|) */ +        if (ix < 0x42b17180)  return half*expf(fabsf(x)); + +    /* |x| in [log(maxdouble), overflowthresold] */ +        if (ix<=0x42b2d4fc) { +            w = expf(half*fabsf(x)); +            t = half*w; +            return t*w; +        } + +    /* |x| > overflowthresold, cosh(x) overflow */ +        return huge*huge; +} diff --git a/src/math/e_exp.c b/src/math/e_exp.c new file mode 100644 index 00000000..66107b95 --- /dev/null +++ b/src/math/e_exp.c @@ -0,0 +1,155 @@ + +/* @(#)e_exp.c 1.6 04/04/22 */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* exp(x) + * Returns the exponential of x. + * + * Method + *   1. Argument reduction: + *      Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658. + *      Given x, find r and integer k such that + * + *               x = k*ln2 + r,  |r| <= 0.5*ln2.   + * + *      Here r will be represented as r = hi-lo for better  + *      accuracy. + * + *   2. Approximation of exp(r) by a special rational function on + *      the interval [0,0.34658]: + *      Write + *          R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ... + *      We use a special Remes algorithm on [0,0.34658] to generate  + *      a polynomial of degree 5 to approximate R. The maximum error  + *      of this polynomial approximation is bounded by 2**-59. In + *      other words, + *          R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5 + *      (where z=r*r, and the values of P1 to P5 are listed below) + *      and + *          |                  5          |     -59 + *          | 2.0+P1*z+...+P5*z   -  R(z) | <= 2  + *          |                             | + *      The computation of exp(r) thus becomes + *                             2*r + *              exp(r) = 1 + ------- + *                            R - r + *                                 r*R1(r)       + *                     = 1 + r + ----------- (for better accuracy) + *                                2 - R1(r) + *      where + *                               2       4             10 + *              R1(r) = r - (P1*r  + P2*r  + ... + P5*r   ). + *       + *   3. Scale back to obtain exp(x): + *      From step 1, we have + *         exp(x) = 2^k * exp(r) + * + * Special cases: + *      exp(INF) is INF, exp(NaN) is NaN; + *      exp(-INF) is 0, and + *      for finite argument, only exp(0)=1 is exact. + * + * Accuracy: + *      according to an error analysis, the error is always less than + *      1 ulp (unit in the last place). + * + * Misc. info. + *      For IEEE double  + *          if x >  7.09782712893383973096e+02 then exp(x) overflow + *          if x < -7.45133219101941108420e+02 then exp(x) underflow + * + * Constants: + * The hexadecimal values are the intended ones for the following  + * constants. The decimal values may be used, provided that the  + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include <math.h> +#include "math_private.h" + +static const double +one     = 1.0, +halF[2] = {0.5,-0.5,}, +huge    = 1.0e+300, +twom1000= 9.33263618503218878990e-302,     /* 2**-1000=0x01700000,0*/ +o_threshold=  7.09782712893383973096e+02,  /* 0x40862E42, 0xFEFA39EF */ +u_threshold= -7.45133219101941108420e+02,  /* 0xc0874910, 0xD52D3051 */ +ln2HI[2]   ={ 6.93147180369123816490e-01,  /* 0x3fe62e42, 0xfee00000 */ +             -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */ +ln2LO[2]   ={ 1.90821492927058770002e-10,  /* 0x3dea39ef, 0x35793c76 */ +             -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */ +invln2 =  1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ +P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5   =  4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */ + + +double +exp(double x) /* default IEEE double exp */ +{ +        double y,hi=0.0,lo=0.0,c,t; +        int32_t k=0,xsb; +        uint32_t hx; + +        GET_HIGH_WORD(hx,x); +        xsb = (hx>>31)&1;               /* sign bit of x */ +        hx &= 0x7fffffff;               /* high word of |x| */ + +    /* filter out non-finite argument */ +        if(hx >= 0x40862E42) {                  /* if |x|>=709.78... */ +            if(hx>=0x7ff00000) { +                uint32_t lx; +                GET_LOW_WORD(lx,x); +                if(((hx&0xfffff)|lx)!=0) +                     return x+x;                /* NaN */ +                else return (xsb==0)? x:0.0;    /* exp(+-inf)={inf,0} */ +            } +            if(x > o_threshold) return huge*huge; /* overflow */ +            if(x < u_threshold) return twom1000*twom1000; /* underflow */ +        } + +    /* argument reduction */ +        if(hx > 0x3fd62e42) {           /* if  |x| > 0.5 ln2 */  +            if(hx < 0x3FF0A2B2) {       /* and |x| < 1.5 ln2 */ +                hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb; +            } else { +                k  = (int)(invln2*x+halF[xsb]); +                t  = k; +                hi = x - t*ln2HI[0];    /* t*ln2HI is exact here */ +                lo = t*ln2LO[0]; +            } +            x  = hi - lo; +        }  +        else if(hx < 0x3e300000)  {     /* when |x|<2**-28 */ +            if(huge+x>one) return one+x;/* trigger inexact */ +        } +        else k = 0; + +    /* x is now in primary range */ +        t  = x*x; +        c  = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); +        if(k==0)        return one-((x*c)/(c-2.0)-x);  +        else            y = one-((lo-(x*c)/(2.0-c))-hi); +        if(k >= -1021) { +            uint32_t hy; +            GET_HIGH_WORD(hy,y); +            SET_HIGH_WORD(y,hy+(k<<20));        /* add k to y's exponent */ +            return y; +        } else { +            uint32_t hy; +            GET_HIGH_WORD(hy,y); +            SET_HIGH_WORD(y,hy+((k+1000)<<20)); /* add k to y's exponent */ +            return y*twom1000; +        } +} diff --git a/src/math/e_expf.c b/src/math/e_expf.c new file mode 100644 index 00000000..99818edc --- /dev/null +++ b/src/math/e_expf.c @@ -0,0 +1,91 @@ +/* e_expf.c -- float version of e_exp.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +one     = 1.0, +halF[2] = {0.5,-0.5,}, +huge    = 1.0e+30, +twom100 = 7.8886090522e-31,      /* 2**-100=0x0d800000 */ +o_threshold=  8.8721679688e+01,  /* 0x42b17180 */ +u_threshold= -1.0397208405e+02,  /* 0xc2cff1b5 */ +ln2HI[2]   ={ 6.9313812256e-01,         /* 0x3f317180 */ +             -6.9313812256e-01,},       /* 0xbf317180 */ +ln2LO[2]   ={ 9.0580006145e-06,         /* 0x3717f7d1 */ +             -9.0580006145e-06,},       /* 0xb717f7d1 */ +invln2 =  1.4426950216e+00,             /* 0x3fb8aa3b */ +P1   =  1.6666667163e-01, /* 0x3e2aaaab */ +P2   = -2.7777778450e-03, /* 0xbb360b61 */ +P3   =  6.6137559770e-05, /* 0x388ab355 */ +P4   = -1.6533901999e-06, /* 0xb5ddea0e */ +P5   =  4.1381369442e-08; /* 0x3331bb4c */ + +float +expf(float x) /* default IEEE double exp */ +{ +        float y,hi=0.0,lo=0.0,c,t; +        int32_t k=0,xsb; +        uint32_t hx; + +        GET_FLOAT_WORD(hx,x); +        xsb = (hx>>31)&1;               /* sign bit of x */ +        hx &= 0x7fffffff;               /* high word of |x| */ + +    /* filter out non-finite argument */ +        if(hx >= 0x42b17218) {                  /* if |x|>=88.721... */ +            if(hx>0x7f800000) +                 return x+x;                    /* NaN */ +            if(hx==0x7f800000) +                return (xsb==0)? x:0.0;         /* exp(+-inf)={inf,0} */ +            if(x > o_threshold) return huge*huge; /* overflow */ +            if(x < u_threshold) return twom100*twom100; /* underflow */ +        } + +    /* argument reduction */ +        if(hx > 0x3eb17218) {           /* if  |x| > 0.5 ln2 */ +            if(hx < 0x3F851592) {       /* and |x| < 1.5 ln2 */ +                hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb; +            } else { +                k  = invln2*x+halF[xsb]; +                t  = k; +                hi = x - t*ln2HI[0];    /* t*ln2HI is exact here */ +                lo = t*ln2LO[0]; +            } +            x  = hi - lo; +        } +        else if(hx < 0x31800000)  {     /* when |x|<2**-28 */ +            if(huge+x>one) return one+x;/* trigger inexact */ +        } +        else k = 0; + +    /* x is now in primary range */ +        t  = x*x; +        c  = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); +        if(k==0)        return one-((x*c)/(c-(float)2.0)-x); +        else            y = one-((lo-(x*c)/((float)2.0-c))-hi); +        if(k >= -125) { +            uint32_t hy; +            GET_FLOAT_WORD(hy,y); +            SET_FLOAT_WORD(y,hy+(k<<23));       /* add k to y's exponent */ +            return y; +        } else { +            uint32_t hy; +            GET_FLOAT_WORD(hy,y); +            SET_FLOAT_WORD(y,hy+((k+100)<<23)); /* add k to y's exponent */ +            return y*twom100; +        } +} diff --git a/src/math/e_fmod.c b/src/math/e_fmod.c new file mode 100644 index 00000000..99afe489 --- /dev/null +++ b/src/math/e_fmod.c @@ -0,0 +1,129 @@ + +/* @(#)e_fmod.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/*  + * fmod(x,y) + * Return x mod y in exact arithmetic + * Method: shift and subtract + */ + +#include <math.h> +#include "math_private.h" + +static const double one = 1.0, Zero[] = {0.0, -0.0,}; + +double +fmod(double x, double y) +{ +        int32_t n,hx,hy,hz,ix,iy,sx,i; +        uint32_t lx,ly,lz; + +        EXTRACT_WORDS(hx,lx,x); +        EXTRACT_WORDS(hy,ly,y); +        sx = hx&0x80000000;             /* sign of x */ +        hx ^=sx;                /* |x| */ +        hy &= 0x7fffffff;       /* |y| */ + +    /* purge off exception values */ +        if((hy|ly)==0||(hx>=0x7ff00000)||       /* y=0,or x not finite */ +          ((hy|((ly|-ly)>>31))>0x7ff00000))     /* or y is NaN */ +            return (x*y)/(x*y); +        if(hx<=hy) { +            if((hx<hy)||(lx<ly)) return x;      /* |x|<|y| return x */ +            if(lx==ly)  +                return Zero[(uint32_t)sx>>31]; /* |x|=|y| return x*0*/ +        } + +    /* determine ix = ilogb(x) */ +        if(hx<0x00100000) {     /* subnormal x */ +            if(hx==0) { +                for (ix = -1043, i=lx; i>0; i<<=1) ix -=1; +            } else { +                for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1; +            } +        } else ix = (hx>>20)-1023; + +    /* determine iy = ilogb(y) */ +        if(hy<0x00100000) {     /* subnormal y */ +            if(hy==0) { +                for (iy = -1043, i=ly; i>0; i<<=1) iy -=1; +            } else { +                for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1; +            } +        } else iy = (hy>>20)-1023; + +    /* set up {hx,lx}, {hy,ly} and align y to x */ +        if(ix >= -1022)  +            hx = 0x00100000|(0x000fffff&hx); +        else {          /* subnormal x, shift x to normal */ +            n = -1022-ix; +            if(n<=31) { +                hx = (hx<<n)|(lx>>(32-n)); +                lx <<= n; +            } else { +                hx = lx<<(n-32); +                lx = 0; +            } +        } +        if(iy >= -1022)  +            hy = 0x00100000|(0x000fffff&hy); +        else {          /* subnormal y, shift y to normal */ +            n = -1022-iy; +            if(n<=31) { +                hy = (hy<<n)|(ly>>(32-n)); +                ly <<= n; +            } else { +                hy = ly<<(n-32); +                ly = 0; +            } +        } + +    /* fix point fmod */ +        n = ix - iy; +        while(n--) { +            hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; +            if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;} +            else { +                if((hz|lz)==0)          /* return sign(x)*0 */ +                    return Zero[(uint32_t)sx>>31]; +                hx = hz+hz+(lz>>31); lx = lz+lz; +            } +        } +        hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; +        if(hz>=0) {hx=hz;lx=lz;} + +    /* convert back to floating value and restore the sign */ +        if((hx|lx)==0)                  /* return sign(x)*0 */ +            return Zero[(uint32_t)sx>>31]; +        while(hx<0x00100000) {          /* normalize x */ +            hx = hx+hx+(lx>>31); lx = lx+lx; +            iy -= 1; +        } +        if(iy>= -1022) {        /* normalize output */ +            hx = ((hx-0x00100000)|((iy+1023)<<20)); +            INSERT_WORDS(x,hx|sx,lx); +        } else {                /* subnormal output */ +            n = -1022 - iy; +            if(n<=20) { +                lx = (lx>>n)|((uint32_t)hx<<(32-n)); +                hx >>= n; +            } else if (n<=31) { +                lx = (hx<<(32-n))|(lx>>n); hx = sx; +            } else { +                lx = hx>>(n-32); hx = sx; +            } +            INSERT_WORDS(x,hx|sx,lx); +            x *= one;           /* create necessary signal */ +        } +        return x;               /* exact output */ +} diff --git a/src/math/e_fmodf.c b/src/math/e_fmodf.c new file mode 100644 index 00000000..fe86cb04 --- /dev/null +++ b/src/math/e_fmodf.c @@ -0,0 +1,101 @@ +/* e_fmodf.c -- float version of e_fmod.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * fmodf(x,y) + * Return x mod y in exact arithmetic + * Method: shift and subtract + */ + +#include <math.h> +#include "math_private.h" + +static const float one = 1.0, Zero[] = {0.0, -0.0,}; + +float +fmodf(float x, float y) +{ +        int32_t n,hx,hy,hz,ix,iy,sx,i; + +        GET_FLOAT_WORD(hx,x); +        GET_FLOAT_WORD(hy,y); +        sx = hx&0x80000000;             /* sign of x */ +        hx ^=sx;                /* |x| */ +        hy &= 0x7fffffff;       /* |y| */ + +    /* purge off exception values */ +        if(hy==0||(hx>=0x7f800000)||            /* y=0,or x not finite */ +           (hy>0x7f800000))                     /* or y is NaN */ +            return (x*y)/(x*y); +        if(hx<hy) return x;                     /* |x|<|y| return x */ +        if(hx==hy) +            return Zero[(uint32_t)sx>>31];     /* |x|=|y| return x*0*/ + +    /* determine ix = ilogb(x) */ +        if(hx<0x00800000) {     /* subnormal x */ +            for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1; +        } else ix = (hx>>23)-127; + +    /* determine iy = ilogb(y) */ +        if(hy<0x00800000) {     /* subnormal y */ +            for (iy = -126,i=(hy<<8); i>=0; i<<=1) iy -=1; +        } else iy = (hy>>23)-127; + +    /* set up {hx,lx}, {hy,ly} and align y to x */ +        if(ix >= -126) +            hx = 0x00800000|(0x007fffff&hx); +        else {          /* subnormal x, shift x to normal */ +            n = -126-ix; +            hx = hx<<n; +        } +        if(iy >= -126) +            hy = 0x00800000|(0x007fffff&hy); +        else {          /* subnormal y, shift y to normal */ +            n = -126-iy; +            hy = hy<<n; +        } + +    /* fix point fmod */ +        n = ix - iy; +        while(n--) { +            hz=hx-hy; +            if(hz<0){hx = hx+hx;} +            else { +                if(hz==0)               /* return sign(x)*0 */ +                    return Zero[(uint32_t)sx>>31]; +                hx = hz+hz; +            } +        } +        hz=hx-hy; +        if(hz>=0) {hx=hz;} + +    /* convert back to floating value and restore the sign */ +        if(hx==0)                       /* return sign(x)*0 */ +            return Zero[(uint32_t)sx>>31]; +        while(hx<0x00800000) {          /* normalize x */ +            hx = hx+hx; +            iy -= 1; +        } +        if(iy>= -126) {         /* normalize output */ +            hx = ((hx-0x00800000)|((iy+127)<<23)); +            SET_FLOAT_WORD(x,hx|sx); +        } else {                /* subnormal output */ +            n = -126 - iy; +            hx >>= n; +            SET_FLOAT_WORD(x,hx|sx); +            x *= one;           /* create necessary signal */ +        } +        return x;               /* exact output */ +} diff --git a/src/math/e_hypot.c b/src/math/e_hypot.c new file mode 100644 index 00000000..e925adc3 --- /dev/null +++ b/src/math/e_hypot.c @@ -0,0 +1,121 @@ + +/* @(#)e_hypot.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* hypot(x,y) + * + * Method :                   + *      If (assume round-to-nearest) z=x*x+y*y  + *      has error less than sqrt(2)/2 ulp, than  + *      sqrt(z) has error less than 1 ulp (exercise). + * + *      So, compute sqrt(x*x+y*y) with some care as  + *      follows to get the error below 1 ulp: + * + *      Assume x>y>0; + *      (if possible, set rounding to round-to-nearest) + *      1. if x > 2y  use + *              x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y + *      where x1 = x with lower 32 bits cleared, x2 = x-x1; else + *      2. if x <= 2y use + *              t1*y1+((x-y)*(x-y)+(t1*y2+t2*y)) + *      where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1,  + *      y1= y with lower 32 bits chopped, y2 = y-y1. + *               + *      NOTE: scaling may be necessary if some argument is too  + *            large or too tiny + * + * Special cases: + *      hypot(x,y) is INF if x or y is +INF or -INF; else + *      hypot(x,y) is NAN if x or y is NAN. + * + * Accuracy: + *      hypot(x,y) returns sqrt(x^2+y^2) with error less  + *      than 1 ulps (units in the last place)  + */ + +#include <math.h> +#include "math_private.h" + +double +hypot(double x, double y) +{ +        double a=x,b=y,t1,t2,y1,y2,w; +        int32_t j,k,ha,hb; + +        GET_HIGH_WORD(ha,x); +        ha &= 0x7fffffff; +        GET_HIGH_WORD(hb,y); +        hb &= 0x7fffffff; +        if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;} +        SET_HIGH_WORD(a,ha);    /* a <- |a| */ +        SET_HIGH_WORD(b,hb);    /* b <- |b| */ +        if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */ +        k=0; +        if(ha > 0x5f300000) {   /* a>2**500 */ +           if(ha >= 0x7ff00000) {       /* Inf or NaN */ +               uint32_t low; +               w = a+b;                 /* for sNaN */ +               GET_LOW_WORD(low,a); +               if(((ha&0xfffff)|low)==0) w = a; +               GET_LOW_WORD(low,b); +               if(((hb^0x7ff00000)|low)==0) w = b; +               return w; +           } +           /* scale a and b by 2**-600 */ +           ha -= 0x25800000; hb -= 0x25800000;  k += 600; +           SET_HIGH_WORD(a,ha); +           SET_HIGH_WORD(b,hb); +        } +        if(hb < 0x20b00000) {   /* b < 2**-500 */ +            if(hb <= 0x000fffff) {      /* subnormal b or 0 */ +                uint32_t low; +                GET_LOW_WORD(low,b); +                if((hb|low)==0) return a; +                t1=0; +                SET_HIGH_WORD(t1,0x7fd00000);   /* t1=2^1022 */ +                b *= t1; +                a *= t1; +                k -= 1022; +            } else {            /* scale a and b by 2^600 */ +                ha += 0x25800000;       /* a *= 2^600 */ +                hb += 0x25800000;       /* b *= 2^600 */ +                k -= 600; +                SET_HIGH_WORD(a,ha); +                SET_HIGH_WORD(b,hb); +            } +        } +    /* medium size a and b */ +        w = a-b; +        if (w>b) { +            t1 = 0; +            SET_HIGH_WORD(t1,ha); +            t2 = a-t1; +            w  = sqrt(t1*t1-(b*(-b)-t2*(a+t1))); +        } else { +            a  = a+a; +            y1 = 0; +            SET_HIGH_WORD(y1,hb); +            y2 = b - y1; +            t1 = 0; +            SET_HIGH_WORD(t1,ha+0x00100000); +            t2 = a - t1; +            w  = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b))); +        } +        if(k!=0) { +            uint32_t high; +            t1 = 1.0; +            GET_HIGH_WORD(high,t1); +            SET_HIGH_WORD(t1,high+(k<<20)); +            return t1*w; +        } else return w; +} diff --git a/src/math/e_hypotf.c b/src/math/e_hypotf.c new file mode 100644 index 00000000..13773554 --- /dev/null +++ b/src/math/e_hypotf.c @@ -0,0 +1,79 @@ +/* e_hypotf.c -- float version of e_hypot.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +float +hypotf(float x, float y) +{ +        float a=x,b=y,t1,t2,y1,y2,w; +        int32_t j,k,ha,hb; + +        GET_FLOAT_WORD(ha,x); +        ha &= 0x7fffffff; +        GET_FLOAT_WORD(hb,y); +        hb &= 0x7fffffff; +        if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;} +        SET_FLOAT_WORD(a,ha);   /* a <- |a| */ +        SET_FLOAT_WORD(b,hb);   /* b <- |b| */ +        if((ha-hb)>0xf000000) {return a+b;} /* x/y > 2**30 */ +        k=0; +        if(ha > 0x58800000) {   /* a>2**50 */ +           if(ha >= 0x7f800000) {       /* Inf or NaN */ +               w = a+b;                 /* for sNaN */ +               if(ha == 0x7f800000) w = a; +               if(hb == 0x7f800000) w = b; +               return w; +           } +           /* scale a and b by 2**-68 */ +           ha -= 0x22000000; hb -= 0x22000000;  k += 68; +           SET_FLOAT_WORD(a,ha); +           SET_FLOAT_WORD(b,hb); +        } +        if(hb < 0x26800000) {   /* b < 2**-50 */ +            if(hb <= 0x007fffff) {      /* subnormal b or 0 */ +                if(hb==0) return a; +                SET_FLOAT_WORD(t1,0x7e800000);  /* t1=2^126 */ +                b *= t1; +                a *= t1; +                k -= 126; +            } else {            /* scale a and b by 2^68 */ +                ha += 0x22000000;       /* a *= 2^68 */ +                hb += 0x22000000;       /* b *= 2^68 */ +                k -= 68; +                SET_FLOAT_WORD(a,ha); +                SET_FLOAT_WORD(b,hb); +            } +        } +    /* medium size a and b */ +        w = a-b; +        if (w>b) { +            SET_FLOAT_WORD(t1,ha&0xfffff000); +            t2 = a-t1; +            w  = sqrtf(t1*t1-(b*(-b)-t2*(a+t1))); +        } else { +            a  = a+a; +            SET_FLOAT_WORD(y1,hb&0xfffff000); +            y2 = b - y1; +            SET_FLOAT_WORD(t1,ha+0x00800000); +            t2 = a - t1; +            w  = sqrtf(t1*y1-(w*(-w)-(t1*y2+t2*b))); +        } +        if(k!=0) { +            SET_FLOAT_WORD(t1,0x3f800000+(k<<23)); +            return t1*w; +        } else return w; +} diff --git a/src/math/e_log.c b/src/math/e_log.c new file mode 100644 index 00000000..9eb0e444 --- /dev/null +++ b/src/math/e_log.c @@ -0,0 +1,131 @@ + +/* @(#)e_log.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* log(x) + * Return the logrithm of x + * + * Method :                   + *   1. Argument Reduction: find k and f such that  + *                      x = 2^k * (1+f),  + *         where  sqrt(2)/2 < 1+f < sqrt(2) . + * + *   2. Approximation of log(1+f). + *      Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + *               = 2s + 2/3 s**3 + 2/5 s**5 + ....., + *               = 2s + s*R + *      We use a special Reme algorithm on [0,0.1716] to generate  + *      a polynomial of degree 14 to approximate R The maximum error  + *      of this polynomial approximation is bounded by 2**-58.45. In + *      other words, + *                      2      4      6      8      10      12      14 + *          R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s  +Lg6*s  +Lg7*s + *      (the values of Lg1 to Lg7 are listed in the program) + *      and + *          |      2          14          |     -58.45 + *          | Lg1*s +...+Lg7*s    -  R(z) | <= 2  + *          |                             | + *      Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + *      In order to guarantee error in log below 1ulp, we compute log + *      by + *              log(1+f) = f - s*(f - R)        (if f is not too large) + *              log(1+f) = f - (hfsq - s*(hfsq+R)).     (better accuracy) + *       + *      3. Finally,  log(x) = k*ln2 + log(1+f).   + *                          = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + *         Here ln2 is split into two floating point number:  + *                      ln2_hi + ln2_lo, + *         where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + *      log(x) is NaN with signal if x < 0 (including -INF) ;  + *      log(+INF) is +INF; log(0) is -INF with signal; + *      log(NaN) is that NaN with no signal. + * + * Accuracy: + *      according to an error analysis, the error is always less than + *      1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following  + * constants. The decimal values may be used, provided that the  + * compiler will convert from decimal to binary accurately enough  + * to produce the hexadecimal values shown. + */ + +#include <math.h> +#include "math_private.h" + +static const double +ln2_hi  =  6.93147180369123816490e-01,  /* 3fe62e42 fee00000 */ +ln2_lo  =  1.90821492927058770002e-10,  /* 3dea39ef 35793c76 */ +two54   =  1.80143985094819840000e+16,  /* 43500000 00000000 */ +Lg1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */ + +static const double zero   =  0.0; + +double +log(double x) +{ +        double hfsq,f,s,z,R,w,t1,t2,dk; +        int32_t k,hx,i,j; +        uint32_t lx; + +        EXTRACT_WORDS(hx,lx,x); + +        k=0; +        if (hx < 0x00100000) {                  /* x < 2**-1022  */ +            if (((hx&0x7fffffff)|lx)==0)  +                return -two54/zero;             /* log(+-0)=-inf */ +            if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */ +            k -= 54; x *= two54; /* subnormal number, scale up x */ +            GET_HIGH_WORD(hx,x); +        }  +        if (hx >= 0x7ff00000) return x+x; +        k += (hx>>20)-1023; +        hx &= 0x000fffff; +        i = (hx+0x95f64)&0x100000; +        SET_HIGH_WORD(x,hx|(i^0x3ff00000));     /* normalize x or x/2 */ +        k += (i>>20); +        f = x-1.0; +        if((0x000fffff&(2+hx))<3) {     /* |f| < 2**-20 */ +            if(f==zero) { if(k==0) return zero;  else {dk=(double)k; +                                 return dk*ln2_hi+dk*ln2_lo;} } +            R = f*f*(0.5-0.33333333333333333*f); +            if(k==0) return f-R; else {dk=(double)k; +                     return dk*ln2_hi-((R-dk*ln2_lo)-f);} +        } +        s = f/(2.0+f);  +        dk = (double)k; +        z = s*s; +        i = hx-0x6147a; +        w = z*z; +        j = 0x6b851-hx; +        t1= w*(Lg2+w*(Lg4+w*Lg6));  +        t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));  +        i |= j; +        R = t2+t1; +        if(i>0) { +            hfsq=0.5*f*f; +            if(k==0) return f-(hfsq-s*(hfsq+R)); else +                     return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f); +        } else { +            if(k==0) return f-s*(f-R); else +                     return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f); +        } +} diff --git a/src/math/e_log10.c b/src/math/e_log10.c new file mode 100644 index 00000000..3be179f7 --- /dev/null +++ b/src/math/e_log10.c @@ -0,0 +1,83 @@ + +/* @(#)e_log10.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* log10(x) + * Return the base 10 logarithm of x + *  + * Method : + *      Let log10_2hi = leading 40 bits of log10(2) and + *          log10_2lo = log10(2) - log10_2hi, + *          ivln10   = 1/log(10) rounded. + *      Then + *              n = ilogb(x),  + *              if(n<0)  n = n+1; + *              x = scalbn(x,-n); + *              log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x)) + * + * Note 1: + *      To guarantee log10(10**n)=n, where 10**n is normal, the rounding  + *      mode must set to Round-to-Nearest. + * Note 2: + *      [1/log(10)] rounded to 53 bits has error  .198   ulps; + *      log10 is monotonic at all binary break points. + * + * Special cases: + *      log10(x) is NaN with signal if x < 0;  + *      log10(+INF) is +INF with no signal; log10(0) is -INF with signal; + *      log10(NaN) is that NaN with no signal; + *      log10(10**N) = N  for N=0,1,...,22. + * + * Constants: + * The hexadecimal values are the intended ones for the following constants. + * The decimal values may be used, provided that the compiler will convert + * from decimal to binary accurately enough to produce the hexadecimal values + * shown. + */ + +#include <math.h> +#include "math_private.h" + +static const double +two54      =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +ivln10     =  4.34294481903251816668e-01, /* 0x3FDBCB7B, 0x1526E50E */ +log10_2hi  =  3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */ +log10_2lo  =  3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */ + +static const double zero   =  0.0; + +double +log10(double x) +{ +        double y,z; +        int32_t i,k,hx; +        uint32_t lx; + +        EXTRACT_WORDS(hx,lx,x); + +        k=0; +        if (hx < 0x00100000) {                  /* x < 2**-1022  */ +            if (((hx&0x7fffffff)|lx)==0) +                return -two54/zero;             /* log(+-0)=-inf */ +            if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */ +            k -= 54; x *= two54; /* subnormal number, scale up x */ +            GET_HIGH_WORD(hx,x); +        } +        if (hx >= 0x7ff00000) return x+x; +        k += (hx>>20)-1023; +        i  = ((uint32_t)k&0x80000000)>>31; +        hx = (hx&0x000fffff)|((0x3ff-i)<<20); +        y  = (double)(k+i); +        SET_HIGH_WORD(x,hx); +        z  = y*log10_2lo + ivln10*log(x); +        return  z+y*log10_2hi; +} diff --git a/src/math/e_log10f.c b/src/math/e_log10f.c new file mode 100644 index 00000000..8fc5c5ca --- /dev/null +++ b/src/math/e_log10f.c @@ -0,0 +1,51 @@ +/* e_log10f.c -- float version of e_log10.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +two25      =  3.3554432000e+07, /* 0x4c000000 */ +ivln10     =  4.3429449201e-01, /* 0x3ede5bd9 */ +log10_2hi  =  3.0102920532e-01, /* 0x3e9a2080 */ +log10_2lo  =  7.9034151668e-07; /* 0x355427db */ + +static const float zero   =  0.0; + +float +log10f(float x) +{ +        float y,z; +        int32_t i,k,hx; + +        GET_FLOAT_WORD(hx,x); + +        k=0; +        if (hx < 0x00800000) {                  /* x < 2**-126  */ +            if ((hx&0x7fffffff)==0) +                return -two25/zero;             /* log(+-0)=-inf */ +            if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */ +            k -= 25; x *= two25; /* subnormal number, scale up x */ +            GET_FLOAT_WORD(hx,x); +        } +        if (hx >= 0x7f800000) return x+x; +        k += (hx>>23)-127; +        i  = ((uint32_t)k&0x80000000)>>31; +        hx = (hx&0x007fffff)|((0x7f-i)<<23); +        y  = (float)(k+i); +        SET_FLOAT_WORD(x,hx); +        z  = y*log10_2lo + ivln10*logf(x); +        return  z+y*log10_2hi; +} diff --git a/src/math/e_logf.c b/src/math/e_logf.c new file mode 100644 index 00000000..46a8b8ce --- /dev/null +++ b/src/math/e_logf.c @@ -0,0 +1,81 @@ +/* e_logf.c -- float version of e_log.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +ln2_hi =   6.9313812256e-01,    /* 0x3f317180 */ +ln2_lo =   9.0580006145e-06,    /* 0x3717f7d1 */ +two25 =    3.355443200e+07,     /* 0x4c000000 */ +Lg1 = 6.6666668653e-01, /* 3F2AAAAB */ +Lg2 = 4.0000000596e-01, /* 3ECCCCCD */ +Lg3 = 2.8571429849e-01, /* 3E924925 */ +Lg4 = 2.2222198546e-01, /* 3E638E29 */ +Lg5 = 1.8183572590e-01, /* 3E3A3325 */ +Lg6 = 1.5313838422e-01, /* 3E1CD04F */ +Lg7 = 1.4798198640e-01; /* 3E178897 */ + +static const float zero   =  0.0; + +float +logf(float x) +{ +        float hfsq,f,s,z,R,w,t1,t2,dk; +        int32_t k,ix,i,j; + +        GET_FLOAT_WORD(ix,x); + +        k=0; +        if (ix < 0x00800000) {                  /* x < 2**-126  */ +            if ((ix&0x7fffffff)==0) +                return -two25/zero;             /* log(+-0)=-inf */ +            if (ix<0) return (x-x)/zero;        /* log(-#) = NaN */ +            k -= 25; x *= two25; /* subnormal number, scale up x */ +            GET_FLOAT_WORD(ix,x); +        } +        if (ix >= 0x7f800000) return x+x; +        k += (ix>>23)-127; +        ix &= 0x007fffff; +        i = (ix+(0x95f64<<3))&0x800000; +        SET_FLOAT_WORD(x,ix|(i^0x3f800000));    /* normalize x or x/2 */ +        k += (i>>23); +        f = x-(float)1.0; +        if((0x007fffff&(15+ix))<16) {   /* |f| < 2**-20 */ +            if(f==zero) { if(k==0) return zero;  else {dk=(float)k; +                                 return dk*ln2_hi+dk*ln2_lo;} } +            R = f*f*((float)0.5-(float)0.33333333333333333*f); +            if(k==0) return f-R; else {dk=(float)k; +                     return dk*ln2_hi-((R-dk*ln2_lo)-f);} +        } +        s = f/((float)2.0+f); +        dk = (float)k; +        z = s*s; +        i = ix-(0x6147a<<3); +        w = z*z; +        j = (0x6b851<<3)-ix; +        t1= w*(Lg2+w*(Lg4+w*Lg6)); +        t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); +        i |= j; +        R = t2+t1; +        if(i>0) { +            hfsq=(float)0.5*f*f; +            if(k==0) return f-(hfsq-s*(hfsq+R)); else +                     return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f); +        } else { +            if(k==0) return f-s*(f-R); else +                     return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f); +        } +} diff --git a/src/math/e_pow.c b/src/math/e_pow.c new file mode 100644 index 00000000..aad24287 --- /dev/null +++ b/src/math/e_pow.c @@ -0,0 +1,300 @@ +/* @(#)e_pow.c 1.5 04/04/22 SMI */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* pow(x,y) return x**y + * + *                    n + * Method:  Let x =  2   * (1+f) + *      1. Compute and return log2(x) in two pieces: + *              log2(x) = w1 + w2, + *         where w1 has 53-24 = 29 bit trailing zeros. + *      2. Perform y*log2(x) = n+y' by simulating muti-precision  + *         arithmetic, where |y'|<=0.5. + *      3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + *      1.  (anything) ** 0  is 1 + *      2.  (anything) ** 1  is itself + *      3.  (anything) ** NAN is NAN + *      4.  NAN ** (anything except 0) is NAN + *      5.  +-(|x| > 1) **  +INF is +INF + *      6.  +-(|x| > 1) **  -INF is +0 + *      7.  +-(|x| < 1) **  +INF is +0 + *      8.  +-(|x| < 1) **  -INF is +INF + *      9.  +-1         ** +-INF is NAN + *      10. +0 ** (+anything except 0, NAN)               is +0 + *      11. -0 ** (+anything except 0, NAN, odd integer)  is +0 + *      12. +0 ** (-anything except 0, NAN)               is +INF + *      13. -0 ** (-anything except 0, NAN, odd integer)  is +INF + *      14. -0 ** (odd integer) = -( +0 ** (odd integer) ) + *      15. +INF ** (+anything except 0,NAN) is +INF + *      16. +INF ** (-anything except 0,NAN) is +0 + *      17. -INF ** (anything)  = -0 ** (-anything) + *      18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + *      19. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + *      pow(x,y) returns x**y nearly rounded. In particular + *                      pow(integer,integer) + *      always returns the correct integer provided it is  + *      representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following  + * constants. The decimal values may be used, provided that the  + * compiler will convert from decimal to binary accurately enough  + * to produce the hexadecimal values shown. + */ + +#include <math.h> +#include "math_private.h" + +static const double +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ +dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ +zero    =  0.0, +one     =  1.0, +two     =  2.0, +two53   =  9007199254740992.0,  /* 0x43400000, 0x00000000 */ +huge    =  1.0e300, +tiny    =  1.0e-300, +        /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1  =  5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ +L2  =  4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ +L3  =  3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ +L4  =  2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ +L5  =  2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ +L6  =  2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ +P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ +P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ +P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ +P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ +P5   =  4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ +lg2  =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +lg2_h  =  6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ +lg2_l  = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ +ovt =  8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ +cp    =  9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ +cp_h  =  9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ +cp_l  = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ +ivln2    =  1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ +ivln2_h  =  1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ +ivln2_l  =  1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + +double +pow(double x, double y) +{ +        double z,ax,z_h,z_l,p_h,p_l; +        double y1,t1,t2,r,s,t,u,v,w; +        int32_t i,j,k,yisint,n; +        int32_t hx,hy,ix,iy; +        uint32_t lx,ly; + +        EXTRACT_WORDS(hx,lx,x); +        EXTRACT_WORDS(hy,ly,y); +        ix = hx&0x7fffffff;  iy = hy&0x7fffffff; + +    /* y==zero: x**0 = 1 */ +        if((iy|ly)==0) return one;       + +    /* +-NaN return x+y */ +        if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || +           iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0)))  +                return x+y;      + +    /* determine if y is an odd int when x < 0 +     * yisint = 0       ... y is not an integer +     * yisint = 1       ... y is an odd int +     * yisint = 2       ... y is an even int +     */ +        yisint  = 0; +        if(hx<0) {       +            if(iy>=0x43400000) yisint = 2; /* even integer y */ +            else if(iy>=0x3ff00000) { +                k = (iy>>20)-0x3ff;        /* exponent */ +                if(k>20) { +                    j = ly>>(52-k); +                    if((j<<(52-k))==ly) yisint = 2-(j&1); +                } else if(ly==0) { +                    j = iy>>(20-k); +                    if((j<<(20-k))==iy) yisint = 2-(j&1); +                } +            }            +        }  + +    /* special value of y */ +        if(ly==0) {      +            if (iy==0x7ff00000) {       /* y is +-inf */ +                if(((ix-0x3ff00000)|lx)==0) +                    return  y - y;      /* inf**+-1 is NaN */ +                else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */ +                    return (hy>=0)? y: zero; +                else                    /* (|x|<1)**-,+inf = inf,0 */ +                    return (hy<0)?-y: zero; +            }  +            if(iy==0x3ff00000) {        /* y is  +-1 */ +                if(hy<0) return one/x; else return x; +            } +            if(hy==0x40000000) return x*x; /* y is  2 */ +            if(hy==0x3fe00000) {        /* y is  0.5 */ +                if(hx>=0)       /* x >= +0 */ +                return sqrt(x);  +            } +        } + +        ax   = fabs(x); +    /* special value of x */ +        if(lx==0) { +            if(ix==0x7ff00000||ix==0||ix==0x3ff00000){ +                z = ax;                 /*x is +-0,+-inf,+-1*/ +                if(hy<0) z = one/z;     /* z = (1/|x|) */ +                if(hx<0) { +                    if(((ix-0x3ff00000)|yisint)==0) { +                        z = (z-z)/(z-z); /* (-1)**non-int is NaN */ +                    } else if(yisint==1)  +                        z = -z;         /* (x<0)**odd = -(|x|**odd) */ +                } +                return z; +            } +        } +     +    /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be +        n = (hx>>31)+1; +       but ANSI C says a right shift of a signed negative quantity is +       implementation defined.  */ +        n = ((uint32_t)hx>>31)-1; + +    /* (x<0)**(non-int) is NaN */ +        if((n|yisint)==0) return (x-x)/(x-x); + +        s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ +        if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */ + +    /* |y| is huge */ +        if(iy>0x41e00000) { /* if |y| > 2**31 */ +            if(iy>0x43f00000){  /* if |y| > 2**64, must o/uflow */ +                if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny; +                if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny; +            } +        /* over/underflow if x is not close to one */ +            if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny; +            if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny; +        /* now |1-x| is tiny <= 2**-20, suffice to compute  +           log(x) by x-x^2/2+x^3/3-x^4/4 */ +            t = ax-one;         /* t has 20 trailing zeros */ +            w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25)); +            u = ivln2_h*t;      /* ivln2_h has 21 sig. bits */ +            v = t*ivln2_l-w*ivln2; +            t1 = u+v; +            SET_LOW_WORD(t1,0); +            t2 = v-(t1-u); +        } else { +            double ss,s2,s_h,s_l,t_h,t_l; +            n = 0; +        /* take care subnormal number */ +            if(ix<0x00100000) +                {ax *= two53; n -= 53; GET_HIGH_WORD(ix,ax); } +            n  += ((ix)>>20)-0x3ff; +            j  = ix&0x000fffff; +        /* determine interval */ +            ix = j|0x3ff00000;          /* normalize ix */ +            if(j<=0x3988E) k=0;         /* |x|<sqrt(3/2) */ +            else if(j<0xBB67A) k=1;     /* |x|<sqrt(3)   */ +            else {k=0;n+=1;ix -= 0x00100000;} +            SET_HIGH_WORD(ax,ix); + +        /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ +            u = ax-bp[k];               /* bp[0]=1.0, bp[1]=1.5 */ +            v = one/(ax+bp[k]); +            ss = u*v; +            s_h = ss; +            SET_LOW_WORD(s_h,0); +        /* t_h=ax+bp[k] High */ +            t_h = zero; +            SET_HIGH_WORD(t_h,((ix>>1)|0x20000000)+0x00080000+(k<<18)); +            t_l = ax - (t_h-bp[k]); +            s_l = v*((u-s_h*t_h)-s_h*t_l); +        /* compute log(ax) */ +            s2 = ss*ss; +            r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); +            r += s_l*(s_h+ss); +            s2  = s_h*s_h; +            t_h = 3.0+s2+r; +            SET_LOW_WORD(t_h,0); +            t_l = r-((t_h-3.0)-s2); +        /* u+v = ss*(1+...) */ +            u = s_h*t_h; +            v = s_l*t_h+t_l*ss; +        /* 2/(3log2)*(ss+...) */ +            p_h = u+v; +            SET_LOW_WORD(p_h,0); +            p_l = v-(p_h-u); +            z_h = cp_h*p_h;             /* cp_h+cp_l = 2/(3*log2) */ +            z_l = cp_l*p_h+p_l*cp+dp_l[k]; +        /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ +            t = (double)n; +            t1 = (((z_h+z_l)+dp_h[k])+t); +            SET_LOW_WORD(t1,0); +            t2 = z_l-(((t1-t)-dp_h[k])-z_h); +        } + +    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ +        y1  = y; +        SET_LOW_WORD(y1,0); +        p_l = (y-y1)*t1+y*t2; +        p_h = y1*t1; +        z = p_l+p_h; +        EXTRACT_WORDS(j,i,z); +        if (j>=0x40900000) {                            /* z >= 1024 */ +            if(((j-0x40900000)|i)!=0)                   /* if z > 1024 */ +                return s*huge*huge;                     /* overflow */ +            else { +                if(p_l+ovt>z-p_h) return s*huge*huge;   /* overflow */ +            } +        } else if((j&0x7fffffff)>=0x4090cc00 ) {        /* z <= -1075 */ +            if(((j-0xc090cc00)|i)!=0)           /* z < -1075 */ +                return s*tiny*tiny;             /* underflow */ +            else { +                if(p_l<=z-p_h) return s*tiny*tiny;      /* underflow */ +            } +        } +    /* +     * compute 2**(p_h+p_l) +     */ +        i = j&0x7fffffff; +        k = (i>>20)-0x3ff; +        n = 0; +        if(i>0x3fe00000) {              /* if |z| > 0.5, set n = [z+0.5] */ +            n = j+(0x00100000>>(k+1)); +            k = ((n&0x7fffffff)>>20)-0x3ff;     /* new k for n */ +            t = zero; +            SET_HIGH_WORD(t,n&~(0x000fffff>>k)); +            n = ((n&0x000fffff)|0x00100000)>>(20-k); +            if(j<0) n = -n; +            p_h -= t; +        }  +        t = p_l+p_h; +        SET_LOW_WORD(t,0); +        u = t*lg2_h; +        v = (p_l-(t-p_h))*lg2+t*lg2_l; +        z = u+v; +        w = v-(z-u); +        t  = z*z; +        t1  = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); +        r  = (z*t1)/(t1-two)-(w+z*w); +        z  = one-(r-z); +        GET_HIGH_WORD(j,z); +        j += (n<<20); +        if((j>>20)<=0) z = scalbn(z,n); /* subnormal output */ +        else SET_HIGH_WORD(z,j); +        return s*z; +} diff --git a/src/math/e_powf.c b/src/math/e_powf.c new file mode 100644 index 00000000..ae61c246 --- /dev/null +++ b/src/math/e_powf.c @@ -0,0 +1,243 @@ +/* e_powf.c -- float version of e_pow.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +bp[] = {1.0, 1.5,}, +dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */ +dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */ +zero    =  0.0, +one     =  1.0, +two     =  2.0, +two24   =  16777216.0,  /* 0x4b800000 */ +huge    =  1.0e30, +tiny    =  1.0e-30, +        /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ +L1  =  6.0000002384e-01, /* 0x3f19999a */ +L2  =  4.2857143283e-01, /* 0x3edb6db7 */ +L3  =  3.3333334327e-01, /* 0x3eaaaaab */ +L4  =  2.7272811532e-01, /* 0x3e8ba305 */ +L5  =  2.3066075146e-01, /* 0x3e6c3255 */ +L6  =  2.0697501302e-01, /* 0x3e53f142 */ +P1   =  1.6666667163e-01, /* 0x3e2aaaab */ +P2   = -2.7777778450e-03, /* 0xbb360b61 */ +P3   =  6.6137559770e-05, /* 0x388ab355 */ +P4   = -1.6533901999e-06, /* 0xb5ddea0e */ +P5   =  4.1381369442e-08, /* 0x3331bb4c */ +lg2  =  6.9314718246e-01, /* 0x3f317218 */ +lg2_h  =  6.93145752e-01, /* 0x3f317200 */ +lg2_l  =  1.42860654e-06, /* 0x35bfbe8c */ +ovt =  4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */ +cp    =  9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */ +cp_h  =  9.6179199219e-01, /* 0x3f763800 =head of cp */ +cp_l  =  4.7017383622e-06, /* 0x369dc3a0 =tail of cp_h */ +ivln2    =  1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */ +ivln2_h  =  1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/ +ivln2_l  =  7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ + +float +powf(float x, float y) +{ +        float z,ax,z_h,z_l,p_h,p_l; +        float y1,t1,t2,r,s,sn,t,u,v,w; +        int32_t i,j,k,yisint,n; +        int32_t hx,hy,ix,iy,is; + +        GET_FLOAT_WORD(hx,x); +        GET_FLOAT_WORD(hy,y); +        ix = hx&0x7fffffff;  iy = hy&0x7fffffff; + +    /* y==zero: x**0 = 1 */ +        if(iy==0) return one; + +    /* +-NaN return x+y */ +        if(ix > 0x7f800000 || +           iy > 0x7f800000) +                return x+y; + +    /* determine if y is an odd int when x < 0 +     * yisint = 0       ... y is not an integer +     * yisint = 1       ... y is an odd int +     * yisint = 2       ... y is an even int +     */ +        yisint  = 0; +        if(hx<0) { +            if(iy>=0x4b800000) yisint = 2; /* even integer y */ +            else if(iy>=0x3f800000) { +                k = (iy>>23)-0x7f;         /* exponent */ +                j = iy>>(23-k); +                if((j<<(23-k))==iy) yisint = 2-(j&1); +            } +        } + +    /* special value of y */ +        if (iy==0x7f800000) {   /* y is +-inf */ +            if (ix==0x3f800000) +                return  y - y;  /* inf**+-1 is NaN */ +            else if (ix > 0x3f800000)/* (|x|>1)**+-inf = inf,0 */ +                return (hy>=0)? y: zero; +            else                        /* (|x|<1)**-,+inf = inf,0 */ +                return (hy<0)?-y: zero; +        } +        if(iy==0x3f800000) {    /* y is  +-1 */ +            if(hy<0) return one/x; else return x; +        } +        if(hy==0x40000000) return x*x; /* y is  2 */ +        if(hy==0x3f000000) {    /* y is  0.5 */ +            if(hx>=0)   /* x >= +0 */ +            return sqrtf(x); +        } + +        ax   = fabsf(x); +    /* special value of x */ +        if(ix==0x7f800000||ix==0||ix==0x3f800000){ +            z = ax;                     /*x is +-0,+-inf,+-1*/ +            if(hy<0) z = one/z; /* z = (1/|x|) */ +            if(hx<0) { +                if(((ix-0x3f800000)|yisint)==0) { +                    z = (z-z)/(z-z); /* (-1)**non-int is NaN */ +                } else if(yisint==1) +                    z = -z;             /* (x<0)**odd = -(|x|**odd) */ +            } +            return z; +        } + +        n = ((uint32_t)hx>>31)-1; + +    /* (x<0)**(non-int) is NaN */ +        if((n|yisint)==0) return (x-x)/(x-x); + +        sn = one; /* s (sign of result -ve**odd) = -1 else = 1 */ +        if((n|(yisint-1))==0) sn = -one;/* (-ve)**(odd int) */ + +    /* |y| is huge */ +        if(iy>0x4d000000) { /* if |y| > 2**27 */ +        /* over/underflow if x is not close to one */ +            if(ix<0x3f7ffff8) return (hy<0)? sn*huge*huge:sn*tiny*tiny; +            if(ix>0x3f800007) return (hy>0)? sn*huge*huge:sn*tiny*tiny; +        /* now |1-x| is tiny <= 2**-20, suffice to compute +           log(x) by x-x^2/2+x^3/3-x^4/4 */ +            t = ax-1;           /* t has 20 trailing zeros */ +            w = (t*t)*((float)0.5-t*((float)0.333333333333-t*(float)0.25)); +            u = ivln2_h*t;      /* ivln2_h has 16 sig. bits */ +            v = t*ivln2_l-w*ivln2; +            t1 = u+v; +            GET_FLOAT_WORD(is,t1); +            SET_FLOAT_WORD(t1,is&0xfffff000); +            t2 = v-(t1-u); +        } else { +            float s2,s_h,s_l,t_h,t_l; +            n = 0; +        /* take care subnormal number */ +            if(ix<0x00800000) +                {ax *= two24; n -= 24; GET_FLOAT_WORD(ix,ax); } +            n  += ((ix)>>23)-0x7f; +            j  = ix&0x007fffff; +        /* determine interval */ +            ix = j|0x3f800000;          /* normalize ix */ +            if(j<=0x1cc471) k=0;        /* |x|<sqrt(3/2) */ +            else if(j<0x5db3d7) k=1;    /* |x|<sqrt(3)   */ +            else {k=0;n+=1;ix -= 0x00800000;} +            SET_FLOAT_WORD(ax,ix); + +        /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */ +            u = ax-bp[k];               /* bp[0]=1.0, bp[1]=1.5 */ +            v = one/(ax+bp[k]); +            s = u*v; +            s_h = s; +            GET_FLOAT_WORD(is,s_h); +            SET_FLOAT_WORD(s_h,is&0xfffff000); +        /* t_h=ax+bp[k] High */ +            is = ((ix>>1)&0xfffff000)|0x20000000; +            SET_FLOAT_WORD(t_h,is+0x00400000+(k<<21)); +            t_l = ax - (t_h-bp[k]); +            s_l = v*((u-s_h*t_h)-s_h*t_l); +        /* compute log(ax) */ +            s2 = s*s; +            r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); +            r += s_l*(s_h+s); +            s2  = s_h*s_h; +            t_h = (float)3.0+s2+r; +            GET_FLOAT_WORD(is,t_h); +            SET_FLOAT_WORD(t_h,is&0xfffff000); +            t_l = r-((t_h-(float)3.0)-s2); +        /* u+v = s*(1+...) */ +            u = s_h*t_h; +            v = s_l*t_h+t_l*s; +        /* 2/(3log2)*(s+...) */ +            p_h = u+v; +            GET_FLOAT_WORD(is,p_h); +            SET_FLOAT_WORD(p_h,is&0xfffff000); +            p_l = v-(p_h-u); +            z_h = cp_h*p_h;             /* cp_h+cp_l = 2/(3*log2) */ +            z_l = cp_l*p_h+p_l*cp+dp_l[k]; +        /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ +            t = (float)n; +            t1 = (((z_h+z_l)+dp_h[k])+t); +            GET_FLOAT_WORD(is,t1); +            SET_FLOAT_WORD(t1,is&0xfffff000); +            t2 = z_l-(((t1-t)-dp_h[k])-z_h); +        } + +    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ +        GET_FLOAT_WORD(is,y); +        SET_FLOAT_WORD(y1,is&0xfffff000); +        p_l = (y-y1)*t1+y*t2; +        p_h = y1*t1; +        z = p_l+p_h; +        GET_FLOAT_WORD(j,z); +        if (j>0x43000000)                               /* if z > 128 */ +            return sn*huge*huge;                        /* overflow */ +        else if (j==0x43000000) {                       /* if z == 128 */ +            if(p_l+ovt>z-p_h) return sn*huge*huge;      /* overflow */ +        } +        else if ((j&0x7fffffff)>0x43160000)             /* z <= -150 */ +            return sn*tiny*tiny;                        /* underflow */ +        else if (j==0xc3160000){                        /* z == -150 */ +            if(p_l<=z-p_h) return sn*tiny*tiny;         /* underflow */ +        } +    /* +     * compute 2**(p_h+p_l) +     */ +        i = j&0x7fffffff; +        k = (i>>23)-0x7f; +        n = 0; +        if(i>0x3f000000) {              /* if |z| > 0.5, set n = [z+0.5] */ +            n = j+(0x00800000>>(k+1)); +            k = ((n&0x7fffffff)>>23)-0x7f;      /* new k for n */ +            SET_FLOAT_WORD(t,n&~(0x007fffff>>k)); +            n = ((n&0x007fffff)|0x00800000)>>(23-k); +            if(j<0) n = -n; +            p_h -= t; +        } +        t = p_l+p_h; +        GET_FLOAT_WORD(is,t); +        SET_FLOAT_WORD(t,is&0xffff8000); +        u = t*lg2_h; +        v = (p_l-(t-p_h))*lg2+t*lg2_l; +        z = u+v; +        w = v-(z-u); +        t  = z*z; +        t1  = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); +        r  = (z*t1)/(t1-two)-(w+z*w); +        z  = one-(r-z); +        GET_FLOAT_WORD(j,z); +        j += (n<<23); +        if((j>>23)<=0) z = scalbnf(z,n);        /* subnormal output */ +        else SET_FLOAT_WORD(z,j); +        return sn*z; +} diff --git a/src/math/e_rem_pio2.c b/src/math/e_rem_pio2.c new file mode 100644 index 00000000..9eee36ae --- /dev/null +++ b/src/math/e_rem_pio2.c @@ -0,0 +1,163 @@ + +/* @(#)e_rem_pio2.c 1.4 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + * + */ + +/* __ieee754_rem_pio2(x,y) + *  + * return the remainder of x rem pi/2 in y[0]+y[1]  + * use __kernel_rem_pio2() + */ + +#include <math.h> +#include "math_private.h" + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi  + */ +static const int32_t two_over_pi[] = { +0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,  +0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,  +0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,  +0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,  +0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,  +0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,  +0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,  +0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,  +0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,  +0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,  +0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,  +}; + +static const int32_t npio2_hw[] = { +0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C, +0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C, +0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A, +0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C, +0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB, +0x404858EB, 0x404921FB, +}; + +/* + * invpio2:  53 bits of 2/pi + * pio2_1:   first  33 bit of pi/2 + * pio2_1t:  pi/2 - pio2_1 + * pio2_2:   second 33 bit of pi/2 + * pio2_2t:  pi/2 - (pio2_1+pio2_2) + * pio2_3:   third  33 bit of pi/2 + * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3) + */ + +static const double +zero =  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ +half =  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +two24 =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +invpio2 =  6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1  =  1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ +pio2_1t =  6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ +pio2_2  =  6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */ +pio2_2t =  2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */ +pio2_3  =  2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */ +pio2_3t =  8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +int32_t __ieee754_rem_pio2(double x, double *y) +{ +        double z,w,t,r,fn; +        double tx[3]; +        int32_t e0,i,j,nx,n,ix,hx; +        uint32_t low; + +        GET_HIGH_WORD(hx,x);            /* high word of x */ +        ix = hx&0x7fffffff; +        if(ix<=0x3fe921fb)   /* |x| ~<= pi/4 , no need for reduction */ +            {y[0] = x; y[1] = 0; return 0;} +        if(ix<0x4002d97c) {  /* |x| < 3pi/4, special case with n=+-1 */ +            if(hx>0) {  +                z = x - pio2_1; +                if(ix!=0x3ff921fb) {    /* 33+53 bit pi is good enough */ +                    y[0] = z - pio2_1t; +                    y[1] = (z-y[0])-pio2_1t; +                } else {                /* near pi/2, use 33+33+53 bit pi */ +                    z -= pio2_2; +                    y[0] = z - pio2_2t; +                    y[1] = (z-y[0])-pio2_2t; +                } +                return 1; +            } else {    /* negative x */ +                z = x + pio2_1; +                if(ix!=0x3ff921fb) {    /* 33+53 bit pi is good enough */ +                    y[0] = z + pio2_1t; +                    y[1] = (z-y[0])+pio2_1t; +                } else {                /* near pi/2, use 33+33+53 bit pi */ +                    z += pio2_2; +                    y[0] = z + pio2_2t; +                    y[1] = (z-y[0])+pio2_2t; +                } +                return -1; +            } +        } +        if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */ +            t  = fabs(x); +            n  = (int32_t) (t*invpio2+half); +            fn = (double)n; +            r  = t-fn*pio2_1; +            w  = fn*pio2_1t;    /* 1st round good to 85 bit */ +            if(n<32&&ix!=npio2_hw[n-1]) {        +                y[0] = r-w;     /* quick check no cancellation */ +            } else { +                uint32_t high; +                j  = ix>>20; +                y[0] = r-w;  +                GET_HIGH_WORD(high,y[0]); +                i = j-((high>>20)&0x7ff); +                if(i>16) {  /* 2nd iteration needed, good to 118 */ +                    t  = r; +                    w  = fn*pio2_2;      +                    r  = t-w; +                    w  = fn*pio2_2t-((t-r)-w);   +                    y[0] = r-w; +                    GET_HIGH_WORD(high,y[0]); +                    i = j-((high>>20)&0x7ff); +                    if(i>49)  { /* 3rd iteration need, 151 bits acc */ +                        t  = r; /* will cover all possible cases */ +                        w  = fn*pio2_3;  +                        r  = t-w; +                        w  = fn*pio2_3t-((t-r)-w);       +                        y[0] = r-w; +                    } +                } +            } +            y[1] = (r-y[0])-w; +            if(hx<0)    {y[0] = -y[0]; y[1] = -y[1]; return -n;} +            else         return n; +        } +    /*  +     * all other (large) arguments +     */ +        if(ix>=0x7ff00000) {            /* x is inf or NaN */ +            y[0]=y[1]=x-x; return 0; +        } +    /* set z = scalbn(|x|,ilogb(x)-23) */ +        GET_LOW_WORD(low,x); +        e0      = (ix>>20)-1046;        /* e0 = ilogb(z)-23; */ +	INSERT_WORDS(z, ix - ((int32_t)(e0<<20)), low); +        for(i=0;i<2;i++) { +                tx[i] = (double)((int32_t)(z)); +                z     = (z-tx[i])*two24; +        } +        tx[2] = z; +        nx = 3; +        while(tx[nx-1]==zero) nx--;     /* skip zero term */ +        n  =  __kernel_rem_pio2(tx,y,e0,nx,2,two_over_pi); +        if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} +        return n; +} diff --git a/src/math/e_rem_pio2f.c b/src/math/e_rem_pio2f.c new file mode 100644 index 00000000..4992ea0c --- /dev/null +++ b/src/math/e_rem_pio2f.c @@ -0,0 +1,175 @@ +/* e_rem_pio2f.c -- float version of e_rem_pio2.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* __ieee754_rem_pio2f(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __kernel_rem_pio2f() + */ + +#include <math.h> +#include "math_private.h" + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + */ +static const int32_t two_over_pi[] = { +0xA2, 0xF9, 0x83, 0x6E, 0x4E, 0x44, 0x15, 0x29, 0xFC, +0x27, 0x57, 0xD1, 0xF5, 0x34, 0xDD, 0xC0, 0xDB, 0x62, +0x95, 0x99, 0x3C, 0x43, 0x90, 0x41, 0xFE, 0x51, 0x63, +0xAB, 0xDE, 0xBB, 0xC5, 0x61, 0xB7, 0x24, 0x6E, 0x3A, +0x42, 0x4D, 0xD2, 0xE0, 0x06, 0x49, 0x2E, 0xEA, 0x09, +0xD1, 0x92, 0x1C, 0xFE, 0x1D, 0xEB, 0x1C, 0xB1, 0x29, +0xA7, 0x3E, 0xE8, 0x82, 0x35, 0xF5, 0x2E, 0xBB, 0x44, +0x84, 0xE9, 0x9C, 0x70, 0x26, 0xB4, 0x5F, 0x7E, 0x41, +0x39, 0x91, 0xD6, 0x39, 0x83, 0x53, 0x39, 0xF4, 0x9C, +0x84, 0x5F, 0x8B, 0xBD, 0xF9, 0x28, 0x3B, 0x1F, 0xF8, +0x97, 0xFF, 0xDE, 0x05, 0x98, 0x0F, 0xEF, 0x2F, 0x11, +0x8B, 0x5A, 0x0A, 0x6D, 0x1F, 0x6D, 0x36, 0x7E, 0xCF, +0x27, 0xCB, 0x09, 0xB7, 0x4F, 0x46, 0x3F, 0x66, 0x9E, +0x5F, 0xEA, 0x2D, 0x75, 0x27, 0xBA, 0xC7, 0xEB, 0xE5, +0xF1, 0x7B, 0x3D, 0x07, 0x39, 0xF7, 0x8A, 0x52, 0x92, +0xEA, 0x6B, 0xFB, 0x5F, 0xB1, 0x1F, 0x8D, 0x5D, 0x08, +0x56, 0x03, 0x30, 0x46, 0xFC, 0x7B, 0x6B, 0xAB, 0xF0, +0xCF, 0xBC, 0x20, 0x9A, 0xF4, 0x36, 0x1D, 0xA9, 0xE3, +0x91, 0x61, 0x5E, 0xE6, 0x1B, 0x08, 0x65, 0x99, 0x85, +0x5F, 0x14, 0xA0, 0x68, 0x40, 0x8D, 0xFF, 0xD8, 0x80, +0x4D, 0x73, 0x27, 0x31, 0x06, 0x06, 0x15, 0x56, 0xCA, +0x73, 0xA8, 0xC9, 0x60, 0xE2, 0x7B, 0xC0, 0x8C, 0x6B, +}; + +/* This array is like the one in e_rem_pio2.c, but the numbers are +   single precision and the last 8 bits are forced to 0.  */ +static const int32_t npio2_hw[] = { +0x3fc90f00, 0x40490f00, 0x4096cb00, 0x40c90f00, 0x40fb5300, 0x4116cb00, +0x412fed00, 0x41490f00, 0x41623100, 0x417b5300, 0x418a3a00, 0x4196cb00, +0x41a35c00, 0x41afed00, 0x41bc7e00, 0x41c90f00, 0x41d5a000, 0x41e23100, +0x41eec200, 0x41fb5300, 0x4203f200, 0x420a3a00, 0x42108300, 0x4216cb00, +0x421d1400, 0x42235c00, 0x4229a500, 0x422fed00, 0x42363600, 0x423c7e00, +0x4242c700, 0x42490f00 +}; + +/* + * invpio2:  24 bits of 2/pi + * pio2_1:   first  17 bit of pi/2 + * pio2_1t:  pi/2 - pio2_1 + * pio2_2:   second 17 bit of pi/2 + * pio2_2t:  pi/2 - (pio2_1+pio2_2) + * pio2_3:   third  17 bit of pi/2 + * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3) + */ + +static const float +zero =  0.0000000000e+00, /* 0x00000000 */ +half =  5.0000000000e-01, /* 0x3f000000 */ +two8 =  2.5600000000e+02, /* 0x43800000 */ +invpio2 =  6.3661980629e-01, /* 0x3f22f984 */ +pio2_1  =  1.5707855225e+00, /* 0x3fc90f80 */ +pio2_1t =  1.0804334124e-05, /* 0x37354443 */ +pio2_2  =  1.0804273188e-05, /* 0x37354400 */ +pio2_2t =  6.0770999344e-11, /* 0x2e85a308 */ +pio2_3  =  6.0770943833e-11, /* 0x2e85a300 */ +pio2_3t =  6.1232342629e-17; /* 0x248d3132 */ + +int32_t __ieee754_rem_pio2f(float x, float *y) +{ +        float z,w,t,r,fn; +        float tx[3]; +        int32_t e0,i,j,nx,n,ix,hx; + +        GET_FLOAT_WORD(hx,x); +        ix = hx&0x7fffffff; +        if(ix<=0x3f490fd8)   /* |x| ~<= pi/4 , no need for reduction */ +            {y[0] = x; y[1] = 0; return 0;} +        if(ix<0x4016cbe4) {  /* |x| < 3pi/4, special case with n=+-1 */ +            if(hx>0) { +                z = x - pio2_1; +                if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */ +                    y[0] = z - pio2_1t; +                    y[1] = (z-y[0])-pio2_1t; +                } else {                /* near pi/2, use 24+24+24 bit pi */ +                    z -= pio2_2; +                    y[0] = z - pio2_2t; +                    y[1] = (z-y[0])-pio2_2t; +                } +                return 1; +            } else {    /* negative x */ +                z = x + pio2_1; +                if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */ +                    y[0] = z + pio2_1t; +                    y[1] = (z-y[0])+pio2_1t; +                } else {                /* near pi/2, use 24+24+24 bit pi */ +                    z += pio2_2; +                    y[0] = z + pio2_2t; +                    y[1] = (z-y[0])+pio2_2t; +                } +                return -1; +            } +        } +        if(ix<=0x43490f80) { /* |x| ~<= 2^7*(pi/2), medium size */ +            t  = fabsf(x); +            n  = (int32_t) (t*invpio2+half); +            fn = (float)n; +            r  = t-fn*pio2_1; +            w  = fn*pio2_1t;    /* 1st round good to 40 bit */ +            if(n<32&&(ix&0xffffff00)!=npio2_hw[n-1]) { +                y[0] = r-w;     /* quick check no cancellation */ +            } else { +                uint32_t high; +                j  = ix>>23; +                y[0] = r-w; +                GET_FLOAT_WORD(high,y[0]); +                i = j-((high>>23)&0xff); +                if(i>8) {  /* 2nd iteration needed, good to 57 */ +                    t  = r; +                    w  = fn*pio2_2; +                    r  = t-w; +                    w  = fn*pio2_2t-((t-r)-w); +                    y[0] = r-w; +                    GET_FLOAT_WORD(high,y[0]); +                    i = j-((high>>23)&0xff); +                    if(i>25)  { /* 3rd iteration need, 74 bits acc */ +                        t  = r; /* will cover all possible cases */ +                        w  = fn*pio2_3; +                        r  = t-w; +                        w  = fn*pio2_3t-((t-r)-w); +                        y[0] = r-w; +                    } +                } +            } +            y[1] = (r-y[0])-w; +            if(hx<0)    {y[0] = -y[0]; y[1] = -y[1]; return -n;} +            else         return n; +        } +    /* +     * all other (large) arguments +     */ +        if(ix>=0x7f800000) {            /* x is inf or NaN */ +            y[0]=y[1]=x-x; return 0; +        } +    /* set z = scalbn(|x|,ilogb(x)-7) */ +        e0      = (ix>>23)-134;         /* e0 = ilogb(z)-7; */ +        SET_FLOAT_WORD(z, ix - ((int32_t)(e0<<23))); +        for(i=0;i<2;i++) { +                tx[i] = (float)((int32_t)(z)); +                z     = (z-tx[i])*two8; +        } +        tx[2] = z; +        nx = 3; +        while(tx[nx-1]==zero) nx--;     /* skip zero term */ +        n  =  __kernel_rem_pio2f(tx,y,e0,nx,2,two_over_pi); +        if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} +        return n; +} diff --git a/src/math/e_remainder.c b/src/math/e_remainder.c new file mode 100644 index 00000000..9cb56919 --- /dev/null +++ b/src/math/e_remainder.c @@ -0,0 +1,69 @@ + +/* @(#)e_remainder.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* remainder(x,p) + * Return :                   + *      returns  x REM p  =  x - [x/p]*p as if in infinite  + *      precise arithmetic, where [x/p] is the (infinite bit)  + *      integer nearest x/p (in half way case choose the even one). + * Method :  + *      Based on fmod() return x-[x/p]chopped*p exactlp. + */ + +#include <math.h> +#include "math_private.h" + +static const double zero = 0.0; + + +double +remainder(double x, double p) +{ +        int32_t hx,hp; +        uint32_t sx,lx,lp; +        double p_half; + +        EXTRACT_WORDS(hx,lx,x); +        EXTRACT_WORDS(hp,lp,p); +        sx = hx&0x80000000; +        hp &= 0x7fffffff; +        hx &= 0x7fffffff; + +    /* purge off exception values */ +        if((hp|lp)==0) return (x*p)/(x*p);      /* p = 0 */ +        if((hx>=0x7ff00000)||                   /* x not finite */ +          ((hp>=0x7ff00000)&&                   /* p is NaN */ +          (((hp-0x7ff00000)|lp)!=0))) +            return (x*p)/(x*p); + + +        if (hp<=0x7fdfffff) x = fmod(x,p+p);  /* now x < 2p */ +        if (((hx-hp)|(lx-lp))==0) return zero*x; +        x  = fabs(x); +        p  = fabs(p); +        if (hp<0x00200000) { +            if(x+x>p) { +                x-=p; +                if(x+x>=p) x -= p; +            } +        } else { +            p_half = 0.5*p; +            if(x>p_half) { +                x-=p; +                if(x>=p_half) x -= p; +            } +        } +        GET_HIGH_WORD(hx,x); +        SET_HIGH_WORD(x,hx^sx); +        return x; +} diff --git a/src/math/e_remainderf.c b/src/math/e_remainderf.c new file mode 100644 index 00000000..c292367d --- /dev/null +++ b/src/math/e_remainderf.c @@ -0,0 +1,61 @@ +/* e_remainderf.c -- float version of e_remainder.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float zero = 0.0; + + +float +remainderf(float x, float p) +{ +        int32_t hx,hp; +        uint32_t sx; +        float p_half; + +        GET_FLOAT_WORD(hx,x); +        GET_FLOAT_WORD(hp,p); +        sx = hx&0x80000000; +        hp &= 0x7fffffff; +        hx &= 0x7fffffff; + +    /* purge off exception values */ +        if(hp==0) return (x*p)/(x*p);           /* p = 0 */ +        if((hx>=0x7f800000)||                   /* x not finite */ +          ((hp>0x7f800000)))                    /* p is NaN */ +            return (x*p)/(x*p); + + +        if (hp<=0x7effffff) x = fmodf(x,p+p); /* now x < 2p */ +        if ((hx-hp)==0) return zero*x; +        x  = fabsf(x); +        p  = fabsf(p); +        if (hp<0x01000000) { +            if(x+x>p) { +                x-=p; +                if(x+x>=p) x -= p; +            } +        } else { +            p_half = (float)0.5*p; +            if(x>p_half) { +                x-=p; +                if(x>=p_half) x -= p; +            } +        } +        GET_FLOAT_WORD(hx,x); +        SET_FLOAT_WORD(x,hx^sx); +        return x; +} diff --git a/src/math/e_scalb.c b/src/math/e_scalb.c new file mode 100644 index 00000000..cee2b44f --- /dev/null +++ b/src/math/e_scalb.c @@ -0,0 +1,35 @@ + +/* @(#)e_scalb.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* + * scalb(x, fn) is provide for + * passing various standard test suite. One  + * should use scalbn() instead. + */ + +#include <math.h> +#include "math_private.h" + +double +scalb(double x, double fn) +{ +        if (isnan(x)||isnan(fn)) return x*fn; +        if (!isfinite(fn)) { +            if(fn>0.0) return x*fn; +            else       return x/(-fn); +        } +        if (rint(fn)!=fn) return (fn-fn)/(fn-fn); +        if ( fn > 65000.0) return scalbn(x, 65000); +        if (-fn > 65000.0) return scalbn(x,-65000); +        return scalbn(x,(int)fn); +} diff --git a/src/math/e_scalbf.c b/src/math/e_scalbf.c new file mode 100644 index 00000000..de7d7f67 --- /dev/null +++ b/src/math/e_scalbf.c @@ -0,0 +1,31 @@ +/* e_scalbf.c -- float version of e_scalb.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +float +scalbf(float x, float fn) +{ +        if (isnan(x)||isnan(fn)) return x*fn; +        if (!isfinite(fn)) { +            if(fn>(float)0.0) return x*fn; +            else       return x/(-fn); +        } +        if (rintf(fn)!=fn) return (fn-fn)/(fn-fn); +        if ( fn > (float)65000.0) return scalbnf(x, 65000); +        if (-fn > (float)65000.0) return scalbnf(x,-65000); +        return scalbnf(x,(int)fn); +} diff --git a/src/math/e_sinh.c b/src/math/e_sinh.c new file mode 100644 index 00000000..3a574274 --- /dev/null +++ b/src/math/e_sinh.c @@ -0,0 +1,75 @@ + +/* @(#)e_sinh.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* sinh(x) + * Method :  + * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2 + *      1. Replace x by |x| (sinh(-x) = -sinh(x)).  + *      2.  + *                                                  E + E/(E+1) + *          0        <= x <= 22     :  sinh(x) := --------------, E=expm1(x) + *                                                      2 + * + *          22       <= x <= lnovft :  sinh(x) := exp(x)/2  + *          lnovft   <= x <= ln2ovft:  sinh(x) := exp(x/2)/2 * exp(x/2) + *          ln2ovft  <  x           :  sinh(x) := x*shuge (overflow) + * + * Special cases: + *      sinh(x) is |x| if x is +INF, -INF, or NaN. + *      only sinh(0)=0 is exact for finite x. + */ + +#include <math.h> +#include "math_private.h" + +static const double one = 1.0, shuge = 1.0e307; + +double +sinh(double x) +{ +        double t,w,h; +        int32_t ix,jx; +        uint32_t lx; + +    /* High word of |x|. */ +        GET_HIGH_WORD(jx,x); +        ix = jx&0x7fffffff; + +    /* x is INF or NaN */ +        if(ix>=0x7ff00000) return x+x;   + +        h = 0.5; +        if (jx<0) h = -h; +    /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */ +        if (ix < 0x40360000) {          /* |x|<22 */ +            if (ix<0x3e300000)          /* |x|<2**-28 */ +                if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */ +            t = expm1(fabs(x)); +            if(ix<0x3ff00000) return h*(2.0*t-t*t/(t+one)); +            return h*(t+t/(t+one)); +        } + +    /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */ +        if (ix < 0x40862E42)  return h*exp(fabs(x)); + +    /* |x| in [log(maxdouble), overflowthresold] */ +        GET_LOW_WORD(lx,x); +        if (ix<0x408633CE || ((ix==0x408633ce)&&(lx<=(uint32_t)0x8fb9f87d))) { +            w = exp(0.5*fabs(x)); +            t = h*w; +            return t*w; +        } + +    /* |x| > overflowthresold, sinh(x) overflow */ +        return x*shuge; +} diff --git a/src/math/e_sinhf.c b/src/math/e_sinhf.c new file mode 100644 index 00000000..fe60608a --- /dev/null +++ b/src/math/e_sinhf.c @@ -0,0 +1,56 @@ +/* e_sinhf.c -- float version of e_sinh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float one = 1.0, shuge = 1.0e37; + +float +sinhf(float x) +{ +        float t,w,h; +        int32_t ix,jx; + +        GET_FLOAT_WORD(jx,x); +        ix = jx&0x7fffffff; + +    /* x is INF or NaN */ +        if(ix>=0x7f800000) return x+x; + +        h = 0.5; +        if (jx<0) h = -h; +    /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */ +        if (ix < 0x41b00000) {          /* |x|<22 */ +            if (ix<0x31800000)          /* |x|<2**-28 */ +                if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */ +            t = expm1f(fabsf(x)); +            if(ix<0x3f800000) return h*((float)2.0*t-t*t/(t+one)); +            return h*(t+t/(t+one)); +        } + +    /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */ +        if (ix < 0x42b17180)  return h*expf(fabsf(x)); + +    /* |x| in [log(maxdouble), overflowthresold] */ +        if (ix<=0x42b2d4fc) { +            w = expf((float)0.5*fabsf(x)); +            t = h*w; +            return t*w; +        } + +    /* |x| > overflowthresold, sinh(x) overflow */ +        return x*shuge; +} diff --git a/src/math/e_sqrt.c b/src/math/e_sqrt.c new file mode 100644 index 00000000..2bc68747 --- /dev/null +++ b/src/math/e_sqrt.c @@ -0,0 +1,442 @@ + +/* @(#)e_sqrt.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* sqrt(x) + * Return correctly rounded sqrt. + *           ------------------------------------------ + *           |  Use the hardware sqrt if you have one | + *           ------------------------------------------ + * Method:  + *   Bit by bit method using integer arithmetic. (Slow, but portable)  + *   1. Normalization + *      Scale x to y in [1,4) with even powers of 2:  + *      find an integer k such that  1 <= (y=x*2^(2k)) < 4, then + *              sqrt(x) = 2^k * sqrt(y) + *   2. Bit by bit computation + *      Let q  = sqrt(y) truncated to i bit after binary point (q = 1), + *           i                                                   0 + *                                     i+1         2 + *          s  = 2*q , and      y  =  2   * ( y - q  ).         (1) + *           i      i            i                 i + *                                                         + *      To compute q    from q , one checks whether  + *                  i+1       i                        + * + *                            -(i+1) 2 + *                      (q + 2      ) <= y.                     (2) + *                        i + *                                                            -(i+1) + *      If (2) is false, then q   = q ; otherwise q   = q  + 2      . + *                             i+1   i             i+1   i + * + *      With some algebric manipulation, it is not difficult to see + *      that (2) is equivalent to  + *                             -(i+1) + *                      s  +  2       <= y                      (3) + *                       i                i + * + *      The advantage of (3) is that s  and y  can be computed by  + *                                    i      i + *      the following recurrence formula: + *          if (3) is false + * + *          s     =  s  ,       y    = y   ;                    (4) + *           i+1      i          i+1    i + * + *          otherwise, + *                         -i                     -(i+1) + *          s     =  s  + 2  ,  y    = y  -  s  - 2             (5) + *           i+1      i          i+1    i     i + *                               + *      One may easily use induction to prove (4) and (5).  + *      Note. Since the left hand side of (3) contain only i+2 bits, + *            it does not necessary to do a full (53-bit) comparison  + *            in (3). + *   3. Final rounding + *      After generating the 53 bits result, we compute one more bit. + *      Together with the remainder, we can decide whether the + *      result is exact, bigger than 1/2ulp, or less than 1/2ulp + *      (it will never equal to 1/2ulp). + *      The rounding mode can be detected by checking whether + *      huge + tiny is equal to huge, and whether huge - tiny is + *      equal to huge for some floating point number "huge" and "tiny". + *               + * Special cases: + *      sqrt(+-0) = +-0         ... exact + *      sqrt(inf) = inf + *      sqrt(-ve) = NaN         ... with invalid signal + *      sqrt(NaN) = NaN         ... with invalid signal for signaling NaN + * + * Other methods : see the appended file at the end of the program below. + *--------------- + */ + +#include <math.h> +#include "math_private.h" + +static  const double    one     = 1.0, tiny=1.0e-300; + +double +sqrt(double x) +{ +        double z; +        int32_t sign = (int)0x80000000; +        int32_t ix0,s0,q,m,t,i; +        uint32_t r,t1,s1,ix1,q1; + +        EXTRACT_WORDS(ix0,ix1,x); + +    /* take care of Inf and NaN */ +        if((ix0&0x7ff00000)==0x7ff00000) {                       +            return x*x+x;               /* sqrt(NaN)=NaN, sqrt(+inf)=+inf +                                           sqrt(-inf)=sNaN */ +        }  +    /* take care of zero */ +        if(ix0<=0) { +            if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */ +            else if(ix0<0) +                return (x-x)/(x-x);             /* sqrt(-ve) = sNaN */ +        } +    /* normalize x */ +        m = (ix0>>20); +        if(m==0) {                              /* subnormal x */ +            while(ix0==0) { +                m -= 21; +                ix0 |= (ix1>>11); ix1 <<= 21; +            } +            for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1; +            m -= i-1; +            ix0 |= (ix1>>(32-i)); +            ix1 <<= i; +        } +        m -= 1023;      /* unbias exponent */ +        ix0 = (ix0&0x000fffff)|0x00100000; +        if(m&1){        /* odd m, double x to make it even */ +            ix0 += ix0 + ((ix1&sign)>>31); +            ix1 += ix1; +        } +        m >>= 1;        /* m = [m/2] */ + +    /* generate sqrt(x) bit by bit */ +        ix0 += ix0 + ((ix1&sign)>>31); +        ix1 += ix1; +        q = q1 = s0 = s1 = 0;   /* [q,q1] = sqrt(x) */ +        r = 0x00200000;         /* r = moving bit from right to left */ + +        while(r!=0) { +            t = s0+r;  +            if(t<=ix0) {  +                s0   = t+r;  +                ix0 -= t;  +                q   += r;  +            }  +            ix0 += ix0 + ((ix1&sign)>>31); +            ix1 += ix1; +            r>>=1; +        } + +        r = sign; +        while(r!=0) { +            t1 = s1+r;  +            t  = s0; +            if((t<ix0)||((t==ix0)&&(t1<=ix1))) {  +                s1  = t1+r; +                if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1; +                ix0 -= t; +                if (ix1 < t1) ix0 -= 1; +                ix1 -= t1; +                q1  += r; +            } +            ix0 += ix0 + ((ix1&sign)>>31); +            ix1 += ix1; +            r>>=1; +        } + +    /* use floating add to find out rounding direction */ +        if((ix0|ix1)!=0) { +            z = one-tiny; /* trigger inexact flag */ +            if (z>=one) { +                z = one+tiny; +                if (q1==(uint32_t)0xffffffff) { q1=0; q += 1;} +                else if (z>one) { +                    if (q1==(uint32_t)0xfffffffe) q+=1; +                    q1+=2;  +                } else +                    q1 += (q1&1); +            } +        } +        ix0 = (q>>1)+0x3fe00000; +        ix1 =  q1>>1; +        if ((q&1)==1) ix1 |= sign; +        ix0 += (m <<20); +        INSERT_WORDS(z,ix0,ix1); +        return z; +} + +/* +Other methods  (use floating-point arithmetic) +------------- +(This is a copy of a drafted paper by Prof W. Kahan  +and K.C. Ng, written in May, 1986) + +        Two algorithms are given here to implement sqrt(x)  +        (IEEE double precision arithmetic) in software. +        Both supply sqrt(x) correctly rounded. The first algorithm (in +        Section A) uses newton iterations and involves four divisions. +        The second one uses reciproot iterations to avoid division, but +        requires more multiplications. Both algorithms need the ability +        to chop results of arithmetic operations instead of round them,  +        and the INEXACT flag to indicate when an arithmetic operation +        is executed exactly with no roundoff error, all part of the  +        standard (IEEE 754-1985). The ability to perform shift, add, +        subtract and logical AND operations upon 32-bit words is needed +        too, though not part of the standard. + +A.  sqrt(x) by Newton Iteration + +   (1)  Initial approximation + +        Let x0 and x1 be the leading and the trailing 32-bit words of +        a floating point number x (in IEEE double format) respectively  + +            1    11                  52                           ...widths +           ------------------------------------------------------ +        x: |s|    e     |             f                         | +           ------------------------------------------------------ +              msb    lsb  msb                                 lsb ...order + +  +             ------------------------        ------------------------ +        x0:  |s|   e    |    f1     |    x1: |          f2           | +             ------------------------        ------------------------ + +        By performing shifts and subtracts on x0 and x1 (both regarded +        as integers), we obtain an 8-bit approximation of sqrt(x) as +        follows. + +                k  := (x0>>1) + 0x1ff80000; +                y0 := k - T1[31&(k>>15)].       ... y ~ sqrt(x) to 8 bits +        Here k is a 32-bit integer and T1[] is an integer array containing +        correction terms. Now magically the floating value of y (y's +        leading 32-bit word is y0, the value of its trailing word is 0) +        approximates sqrt(x) to almost 8-bit. + +        Value of T1: +        static int T1[32]= { +        0,      1024,   3062,   5746,   9193,   13348,  18162,  23592, +        29598,  36145,  43202,  50740,  58733,  67158,  75992,  85215, +        83599,  71378,  60428,  50647,  41945,  34246,  27478,  21581, +        16499,  12183,  8588,   5674,   3403,   1742,   661,    130,}; + +    (2) Iterative refinement + +        Apply Heron's rule three times to y, we have y approximates  +        sqrt(x) to within 1 ulp (Unit in the Last Place): + +                y := (y+x/y)/2          ... almost 17 sig. bits +                y := (y+x/y)/2          ... almost 35 sig. bits +                y := y-(y-x/y)/2        ... within 1 ulp + + +        Remark 1. +            Another way to improve y to within 1 ulp is: + +                y := (y+x/y)            ... almost 17 sig. bits to 2*sqrt(x) +                y := y - 0x00100006     ... almost 18 sig. bits to sqrt(x) + +                                2 +                            (x-y )*y +                y := y + 2* ----------  ...within 1 ulp +                               2 +                             3y  + x + + +        This formula has one division fewer than the one above; however, +        it requires more multiplications and additions. Also x must be +        scaled in advance to avoid spurious overflow in evaluating the +        expression 3y*y+x. Hence it is not recommended uless division +        is slow. If division is very slow, then one should use the  +        reciproot algorithm given in section B. + +    (3) Final adjustment + +        By twiddling y's last bit it is possible to force y to be  +        correctly rounded according to the prevailing rounding mode +        as follows. Let r and i be copies of the rounding mode and +        inexact flag before entering the square root program. Also we +        use the expression y+-ulp for the next representable floating +        numbers (up and down) of y. Note that y+-ulp = either fixed +        point y+-1, or multiply y by nextafter(1,+-inf) in chopped +        mode. + +                I := FALSE;     ... reset INEXACT flag I +                R := RZ;        ... set rounding mode to round-toward-zero +                z := x/y;       ... chopped quotient, possibly inexact +                If(not I) then {        ... if the quotient is exact +                    if(z=y) { +                        I := i;  ... restore inexact flag +                        R := r;  ... restore rounded mode +                        return sqrt(x):=y. +                    } else { +                        z := z - ulp;   ... special rounding +                    } +                } +                i := TRUE;              ... sqrt(x) is inexact +                If (r=RN) then z=z+ulp  ... rounded-to-nearest +                If (r=RP) then {        ... round-toward-+inf +                    y = y+ulp; z=z+ulp; +                } +                y := y+z;               ... chopped sum +                y0:=y0-0x00100000;      ... y := y/2 is correctly rounded. +                I := i;                 ... restore inexact flag +                R := r;                 ... restore rounded mode +                return sqrt(x):=y. +                     +    (4) Special cases + +        Square root of +inf, +-0, or NaN is itself; +        Square root of a negative number is NaN with invalid signal. + + +B.  sqrt(x) by Reciproot Iteration + +   (1)  Initial approximation + +        Let x0 and x1 be the leading and the trailing 32-bit words of +        a floating point number x (in IEEE double format) respectively +        (see section A). By performing shifs and subtracts on x0 and y0, +        we obtain a 7.8-bit approximation of 1/sqrt(x) as follows. + +            k := 0x5fe80000 - (x0>>1); +            y0:= k - T2[63&(k>>14)].    ... y ~ 1/sqrt(x) to 7.8 bits + +        Here k is a 32-bit integer and T2[] is an integer array  +        containing correction terms. Now magically the floating +        value of y (y's leading 32-bit word is y0, the value of +        its trailing word y1 is set to zero) approximates 1/sqrt(x) +        to almost 7.8-bit. + +        Value of T2: +        static int T2[64]= { +        0x1500, 0x2ef8, 0x4d67, 0x6b02, 0x87be, 0xa395, 0xbe7a, 0xd866, +        0xf14a, 0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f, +        0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d, +        0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0, +        0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989, +        0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd, +        0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e, +        0x1527f,0x1334a,0x11051,0xe951, 0xbe01, 0x8e0d, 0x5924, 0x1edd,}; + +    (2) Iterative refinement + +        Apply Reciproot iteration three times to y and multiply the +        result by x to get an approximation z that matches sqrt(x) +        to about 1 ulp. To be exact, we will have  +                -1ulp < sqrt(x)-z<1.0625ulp. +         +        ... set rounding mode to Round-to-nearest +           y := y*(1.5-0.5*x*y*y)       ... almost 15 sig. bits to 1/sqrt(x) +           y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x) +        ... special arrangement for better accuracy +           z := x*y                     ... 29 bits to sqrt(x), with z*y<1 +           z := z + 0.5*z*(1-z*y)       ... about 1 ulp to sqrt(x) + +        Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that +        (a) the term z*y in the final iteration is always less than 1;  +        (b) the error in the final result is biased upward so that +                -1 ulp < sqrt(x) - z < 1.0625 ulp +            instead of |sqrt(x)-z|<1.03125ulp. + +    (3) Final adjustment + +        By twiddling y's last bit it is possible to force y to be  +        correctly rounded according to the prevailing rounding mode +        as follows. Let r and i be copies of the rounding mode and +        inexact flag before entering the square root program. Also we +        use the expression y+-ulp for the next representable floating +        numbers (up and down) of y. Note that y+-ulp = either fixed +        point y+-1, or multiply y by nextafter(1,+-inf) in chopped +        mode. + +        R := RZ;                ... set rounding mode to round-toward-zero +        switch(r) { +            case RN:            ... round-to-nearest +               if(x<= z*(z-ulp)...chopped) z = z - ulp; else +               if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp; +               break; +            case RZ:case RM:    ... round-to-zero or round-to--inf +               R:=RP;           ... reset rounding mod to round-to-+inf +               if(x<z*z ... rounded up) z = z - ulp; else +               if(x>=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp; +               break; +            case RP:            ... round-to-+inf +               if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else +               if(x>z*z ...chopped) z = z+ulp; +               break; +        } + +        Remark 3. The above comparisons can be done in fixed point. For +        example, to compare x and w=z*z chopped, it suffices to compare +        x1 and w1 (the trailing parts of x and w), regarding them as +        two's complement integers. + +        ...Is z an exact square root? +        To determine whether z is an exact square root of x, let z1 be the +        trailing part of z, and also let x0 and x1 be the leading and +        trailing parts of x. + +        If ((z1&0x03ffffff)!=0) ... not exact if trailing 26 bits of z!=0 +            I := 1;             ... Raise Inexact flag: z is not exact +        else { +            j := 1 - [(x0>>20)&1]       ... j = logb(x) mod 2 +            k := z1 >> 26;              ... get z's 25-th and 26-th  +                                            fraction bits +            I := i or (k&j) or ((k&(j+j+1))!=(x1&3)); +        } +        R:= r           ... restore rounded mode +        return sqrt(x):=z. + +        If multiplication is cheaper then the foregoing red tape, the  +        Inexact flag can be evaluated by + +            I := i; +            I := (z*z!=x) or I. + +        Note that z*z can overwrite I; this value must be sensed if it is  +        True. + +        Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be +        zero. + +                    -------------------- +                z1: |        f2        |  +                    -------------------- +                bit 31             bit 0 + +        Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd +        or even of logb(x) have the following relations: + +        ------------------------------------------------- +        bit 27,26 of z1         bit 1,0 of x1   logb(x) +        ------------------------------------------------- +        00                      00              odd and even +        01                      01              even +        10                      10              odd +        10                      00              even +        11                      01              even +        ------------------------------------------------- + +    (4) Special cases (see (4) of Section A).    +  + */ +  diff --git a/src/math/e_sqrtf.c b/src/math/e_sqrtf.c new file mode 100644 index 00000000..03a15beb --- /dev/null +++ b/src/math/e_sqrtf.c @@ -0,0 +1,85 @@ +/* e_sqrtf.c -- float version of e_sqrt.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static  const float     one     = 1.0, tiny=1.0e-30; + +float +sqrtf(float x) +{ +        float z; +        int32_t sign = (int)0x80000000; +        int32_t ix,s,q,m,t,i; +        uint32_t r; + +        GET_FLOAT_WORD(ix,x); + +    /* take care of Inf and NaN */ +        if((ix&0x7f800000)==0x7f800000) { +            return x*x+x;               /* sqrt(NaN)=NaN, sqrt(+inf)=+inf +                                           sqrt(-inf)=sNaN */ +        } +    /* take care of zero */ +        if(ix<=0) { +            if((ix&(~sign))==0) return x;/* sqrt(+-0) = +-0 */ +            else if(ix<0) +                return (x-x)/(x-x);             /* sqrt(-ve) = sNaN */ +        } +    /* normalize x */ +        m = (ix>>23); +        if(m==0) {                              /* subnormal x */ +            for(i=0;(ix&0x00800000)==0;i++) ix<<=1; +            m -= i-1; +        } +        m -= 127;       /* unbias exponent */ +        ix = (ix&0x007fffff)|0x00800000; +        if(m&1) /* odd m, double x to make it even */ +            ix += ix; +        m >>= 1;        /* m = [m/2] */ + +    /* generate sqrt(x) bit by bit */ +        ix += ix; +        q = s = 0;              /* q = sqrt(x) */ +        r = 0x01000000;         /* r = moving bit from right to left */ + +        while(r!=0) { +            t = s+r; +            if(t<=ix) { +                s    = t+r; +                ix  -= t; +                q   += r; +            } +            ix += ix; +            r>>=1; +        } + +    /* use floating add to find out rounding direction */ +        if(ix!=0) { +            z = one-tiny; /* trigger inexact flag */ +            if (z>=one) { +                z = one+tiny; +                if (z>one) +                    q += 2; +                else +                    q += (q&1); +            } +        } +        ix = (q>>1)+0x3f000000; +        ix += (m <<23); +        SET_FLOAT_WORD(z,ix); +        return z; +} diff --git a/src/math/i386/e_exp.s b/src/math/i386/e_exp.s new file mode 100644 index 00000000..d6c54a30 --- /dev/null +++ b/src/math/i386/e_exp.s @@ -0,0 +1,36 @@ +.global expf +expf: +	mov 4(%esp),%eax +	flds 4(%esp) +	shr $23,%eax +	inc %al +	jz 1f +	jmp 0f + +.global exp +exp: +	mov 8(%esp),%eax +	fldl 4(%esp) +	shl %eax +	cmp $0xffe00000,%eax +	jae 1f + +0:	fldl2e +	fmulp +	fst %st(1) +	frndint +	fst %st(2) +	fsubrp +	f2xm1 +	fld1 +	faddp +	fscale +	fstp %st(1) +	ret + +1:	fsts 4(%esp) +	cmpl $0xff800000,4(%esp) +	jnz 1f +	fstp %st(0) +	fldz +1:	ret diff --git a/src/math/i386/e_expf.s b/src/math/i386/e_expf.s new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/math/i386/e_expf.s @@ -0,0 +1 @@ + diff --git a/src/math/i386/e_log.s b/src/math/i386/e_log.s new file mode 100644 index 00000000..34b8d38d --- /dev/null +++ b/src/math/i386/e_log.s @@ -0,0 +1,6 @@ +.global log +log: +	fldln2 +	fldl 4(%esp) +	fyl2x +	ret diff --git a/src/math/i386/e_log10.s b/src/math/i386/e_log10.s new file mode 100644 index 00000000..7f48941b --- /dev/null +++ b/src/math/i386/e_log10.s @@ -0,0 +1,6 @@ +.global log10 +log10: +	fldlg2 +	fldl 4(%esp) +	fyl2x +	ret diff --git a/src/math/i386/e_log10f.s b/src/math/i386/e_log10f.s new file mode 100644 index 00000000..311486ea --- /dev/null +++ b/src/math/i386/e_log10f.s @@ -0,0 +1,6 @@ +.global log10f +log10f: +	fldlg2 +	flds 4(%esp) +	fyl2x +	ret diff --git a/src/math/i386/e_logf.s b/src/math/i386/e_logf.s new file mode 100644 index 00000000..b8beec0f --- /dev/null +++ b/src/math/i386/e_logf.s @@ -0,0 +1,6 @@ +.global logf +logf: +	fldln2 +	flds 4(%esp) +	fyl2x +	ret diff --git a/src/math/i386/e_remainder.s b/src/math/i386/e_remainder.s new file mode 100644 index 00000000..b7ff3ef8 --- /dev/null +++ b/src/math/i386/e_remainder.s @@ -0,0 +1,16 @@ +.global remainderf +remainderf: +	flds 8(%esp) +	flds 4(%esp) +	jmp 1f +	 +.global remainder +remainder: +	fldl 12(%esp) +	fldl 4(%esp) +1:	fprem1 +	fstsw %ax +	sahf +	jp 1b +	fstp %st(1) +	ret diff --git a/src/math/i386/e_remainderf.s b/src/math/i386/e_remainderf.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/e_remainderf.s diff --git a/src/math/i386/e_sqrt.s b/src/math/i386/e_sqrt.s new file mode 100644 index 00000000..11314dca --- /dev/null +++ b/src/math/i386/e_sqrt.s @@ -0,0 +1,4 @@ +.global sqrt +sqrt:	fldl 4(%esp) +	fsqrt +	ret diff --git a/src/math/i386/e_sqrtf.s b/src/math/i386/e_sqrtf.s new file mode 100644 index 00000000..015e24cd --- /dev/null +++ b/src/math/i386/e_sqrtf.s @@ -0,0 +1,4 @@ +.global sqrtf +sqrtf:	flds 4(%esp) +	fsqrt +	ret diff --git a/src/math/i386/s_ceil.s b/src/math/i386/s_ceil.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_ceil.s diff --git a/src/math/i386/s_ceilf.s b/src/math/i386/s_ceilf.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_ceilf.s diff --git a/src/math/i386/s_fabs.s b/src/math/i386/s_fabs.s new file mode 100644 index 00000000..10c70f37 --- /dev/null +++ b/src/math/i386/s_fabs.s @@ -0,0 +1,5 @@ +.global fabs +fabs: +	fldl 4(%esp) +	fabs +	ret diff --git a/src/math/i386/s_fabsf.s b/src/math/i386/s_fabsf.s new file mode 100644 index 00000000..45442699 --- /dev/null +++ b/src/math/i386/s_fabsf.s @@ -0,0 +1,5 @@ +.global fabsf +fabsf: +	flds 4(%esp) +	fabs +	ret diff --git a/src/math/i386/s_floor.s b/src/math/i386/s_floor.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_floor.s diff --git a/src/math/i386/s_floorf.s b/src/math/i386/s_floorf.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_floorf.s diff --git a/src/math/i386/s_ldexp.s b/src/math/i386/s_ldexp.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_ldexp.s diff --git a/src/math/i386/s_ldexpf.s b/src/math/i386/s_ldexpf.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_ldexpf.s diff --git a/src/math/i386/s_rint.s b/src/math/i386/s_rint.s new file mode 100644 index 00000000..5ba4ab4a --- /dev/null +++ b/src/math/i386/s_rint.s @@ -0,0 +1,5 @@ +.global rint +rint: +	fldl 4(%esp) +	frndint +	ret diff --git a/src/math/i386/s_rintf.s b/src/math/i386/s_rintf.s new file mode 100644 index 00000000..d7aacd8f --- /dev/null +++ b/src/math/i386/s_rintf.s @@ -0,0 +1,5 @@ +.global rintf +rintf: +	flds 4(%esp) +	frndint +	ret diff --git a/src/math/i386/s_scalbln.s b/src/math/i386/s_scalbln.s new file mode 100644 index 00000000..bd022b46 --- /dev/null +++ b/src/math/i386/s_scalbln.s @@ -0,0 +1,11 @@ +.global ldexp +.global scalbn +.global scalbln +ldexp: +scalbn: +scalbln: +	fildl 12(%esp) +	fldl 4(%esp) +	fscale +	fstp %st(1) +	ret diff --git a/src/math/i386/s_scalblnf.s b/src/math/i386/s_scalblnf.s new file mode 100644 index 00000000..379ec919 --- /dev/null +++ b/src/math/i386/s_scalblnf.s @@ -0,0 +1,11 @@ +.global ldexpf +.global scalbnf +.global scalblnf +ldexpf: +scalbnf: +scalblnf: +	fildl 8(%esp) +	flds 4(%esp) +	fscale +	fstp %st(1) +	ret diff --git a/src/math/i386/s_trunc.s b/src/math/i386/s_trunc.s new file mode 100644 index 00000000..0773891a --- /dev/null +++ b/src/math/i386/s_trunc.s @@ -0,0 +1,36 @@ +.global ceilf +ceilf:	flds 4(%esp) +	jmp 1f +	 +.global ceil +ceil:	fldl 4(%esp) +1:	mov $0x08fb,%edx +	jmp 0f + +.global floorf +floorf:	flds 4(%esp) +	jmp 1f + +.global floor +floor:	fldl 4(%esp) +1:	mov $0x04f7,%edx +	jmp 0f + +.global truncf +truncf:	flds 4(%esp) +	jmp 1f + +.global trunc +trunc:	fldl 4(%esp) +1:	mov $0x0cff,%edx + +0:	fstcw 4(%esp) +	mov 5(%esp),%ah +	or %dh,%ah +	and %dl,%ah +	xchg %ah,5(%esp) +	fldcw 4(%esp) +	frndint +	mov %ah,5(%esp) +	fldcw 4(%esp) +	ret diff --git a/src/math/i386/s_truncf.s b/src/math/i386/s_truncf.s new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/math/i386/s_truncf.s diff --git a/src/math/k_cos.c b/src/math/k_cos.c new file mode 100644 index 00000000..22e9841e --- /dev/null +++ b/src/math/k_cos.c @@ -0,0 +1,85 @@ + +/* @(#)k_cos.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* + * __kernel_cos( x,  y ) + * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x.  + * + * Algorithm + *      1. Since cos(-x) = cos(x), we need only to consider positive x. + *      2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0. + *      3. cos(x) is approximated by a polynomial of degree 14 on + *         [0,pi/4] + *                                       4            14 + *              cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x + *         where the remez error is + *       + *      |              2     4     6     8     10    12     14 |     -58 + *      |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  )| <= 2 + *      |                                                      |  + *  + *                     4     6     8     10    12     14  + *      4. let r = C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  , then + *             cos(x) = 1 - x*x/2 + r + *         since cos(x+y) ~ cos(x) - sin(x)*y  + *                        ~ cos(x) - x*y, + *         a correction term is necessary in cos(x) and hence + *              cos(x+y) = 1 - (x*x/2 - (r - x*y)) + *         For better accuracy when x > 0.3, let qx = |x|/4 with + *         the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125. + *         Then + *              cos(x+y) = (1-qx) - ((x*x/2-qx) - (r-x*y)). + *         Note that 1-qx and (x*x/2-qx) is EXACT here, and the + *         magnitude of the latter is at least a quarter of x*x/2, + *         thus, reducing the rounding error in the subtraction. + */ + +#include <math.h> +#include "math_private.h" + +static const double +one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +C1  =  4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */ +C2  = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */ +C3  =  2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */ +C4  = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */ +C5  =  2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */ +C6  = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */ + +double +__kernel_cos(double x, double y) +{ +        double a,hz,z,r,qx; +        int32_t ix; +        GET_HIGH_WORD(ix,x); +        ix &= 0x7fffffff;                       /* ix = |x|'s high word*/ +        if(ix<0x3e400000) {                     /* if x < 2**27 */ +            if(((int)x)==0) return one;         /* generate inexact */ +        } +        z  = x*x; +        r  = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6))))); +        if(ix < 0x3FD33333)                     /* if |x| < 0.3 */  +            return one - (0.5*z - (z*r - x*y)); +        else { +            if(ix > 0x3fe90000) {               /* x > 0.78125 */ +                qx = 0.28125; +            } else { +                INSERT_WORDS(qx,ix-0x00200000,0);       /* x/4 */ +            } +            hz = 0.5*z-qx; +            a  = one-qx; +            return a - (hz - (z*r-x*y)); +        } +} diff --git a/src/math/k_cosf.c b/src/math/k_cosf.c new file mode 100644 index 00000000..61dc3749 --- /dev/null +++ b/src/math/k_cosf.c @@ -0,0 +1,52 @@ +/* k_cosf.c -- float version of k_cos.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +one =  1.0000000000e+00, /* 0x3f800000 */ +C1  =  4.1666667908e-02, /* 0x3d2aaaab */ +C2  = -1.3888889225e-03, /* 0xbab60b61 */ +C3  =  2.4801587642e-05, /* 0x37d00d01 */ +C4  = -2.7557314297e-07, /* 0xb493f27c */ +C5  =  2.0875723372e-09, /* 0x310f74f6 */ +C6  = -1.1359647598e-11; /* 0xad47d74e */ + +float +__kernel_cosf(float x, float y) +{ +        float a,hz,z,r,qx; +        int32_t ix; +        GET_FLOAT_WORD(ix,x); +        ix &= 0x7fffffff;                       /* ix = |x|'s high word*/ +        if(ix<0x32000000) {                     /* if x < 2**27 */ +            if(((int)x)==0) return one;         /* generate inexact */ +        } +        z  = x*x; +        r  = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6))))); +        if(ix < 0x3e99999a)                     /* if |x| < 0.3 */ +            return one - ((float)0.5*z - (z*r - x*y)); +        else { +            if(ix > 0x3f480000) {               /* x > 0.78125 */ +                qx = (float)0.28125; +            } else { +                SET_FLOAT_WORD(qx,ix-0x01000000);       /* x/4 */ +            } +            hz = (float)0.5*z-qx; +            a  = one-qx; +            return a - (hz - (z*r-x*y)); +        } +} diff --git a/src/math/k_rem_pio2.c b/src/math/k_rem_pio2.c new file mode 100644 index 00000000..d993e4f2 --- /dev/null +++ b/src/math/k_rem_pio2.c @@ -0,0 +1,300 @@ + +/* @(#)k_rem_pio2.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* + * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2) + * double x[],y[]; int e0,nx,prec; int ipio2[]; + *  + * __kernel_rem_pio2 return the last three digits of N with  + *              y = x - N*pi/2 + * so that |y| < pi/2. + * + * The method is to compute the integer (mod 8) and fraction parts of  + * (2/pi)*x without doing the full multiplication. In general we + * skip the part of the product that are known to be a huge integer ( + * more accurately, = 0 mod 8 ). Thus the number of operations are + * independent of the exponent of the input. + * + * (2/pi) is represented by an array of 24-bit integers in ipio2[]. + * + * Input parameters: + *      x[]     The input value (must be positive) is broken into nx  + *              pieces of 24-bit integers in double precision format. + *              x[i] will be the i-th 24 bit of x. The scaled exponent  + *              of x[0] is given in input parameter e0 (i.e., x[0]*2^e0  + *              match x's up to 24 bits. + * + *              Example of breaking a double positive z into x[0]+x[1]+x[2]: + *                      e0 = ilogb(z)-23 + *                      z  = scalbn(z,-e0) + *              for i = 0,1,2 + *                      x[i] = floor(z) + *                      z    = (z-x[i])*2**24 + * + * + *      y[]     ouput result in an array of double precision numbers. + *              The dimension of y[] is: + *                      24-bit  precision       1 + *                      53-bit  precision       2 + *                      64-bit  precision       2 + *                      113-bit precision       3 + *              The actual value is the sum of them. Thus for 113-bit + *              precison, one may have to do something like: + * + *              long double t,w,r_head, r_tail; + *              t = (long double)y[2] + (long double)y[1]; + *              w = (long double)y[0]; + *              r_head = t+w; + *              r_tail = w - (r_head - t); + * + *      e0      The exponent of x[0] + * + *      nx      dimension of x[] + * + *      prec    an integer indicating the precision: + *                      0       24  bits (single) + *                      1       53  bits (double) + *                      2       64  bits (extended) + *                      3       113 bits (quad) + * + *      ipio2[] + *              integer array, contains the (24*i)-th to (24*i+23)-th  + *              bit of 2/pi after binary point. The corresponding  + *              floating value is + * + *                      ipio2[i] * 2^(-24(i+1)). + * + * External function: + *      double scalbn(), floor(); + * + * + * Here is the description of some local variables: + * + *      jk      jk+1 is the initial number of terms of ipio2[] needed + *              in the computation. The recommended value is 2,3,4, + *              6 for single, double, extended,and quad. + * + *      jz      local integer variable indicating the number of  + *              terms of ipio2[] used.  + * + *      jx      nx - 1 + * + *      jv      index for pointing to the suitable ipio2[] for the + *              computation. In general, we want + *                      ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 + *              is an integer. Thus + *                      e0-3-24*jv >= 0 or (e0-3)/24 >= jv + *              Hence jv = max(0,(e0-3)/24). + * + *      jp      jp+1 is the number of terms in PIo2[] needed, jp = jk. + * + *      q[]     double array with integral value, representing the + *              24-bits chunk of the product of x and 2/pi. + * + *      q0      the corresponding exponent of q[0]. Note that the + *              exponent for q[i] would be q0-24*i. + * + *      PIo2[]  double precision array, obtained by cutting pi/2 + *              into 24 bits chunks.  + * + *      f[]     ipio2[] in floating point  + * + *      iq[]    integer array by breaking up q[] in 24-bits chunk. + * + *      fq[]    final product of x*(2/pi) in fq[0],..,fq[jk] + * + *      ih      integer. If >0 it indicates q[] is >= 0.5, hence + *              it also indicates the *sign* of the result. + * + */ + + +/* + * Constants: + * The hexadecimal values are the intended ones for the following  + * constants. The decimal values may be used, provided that the  + * compiler will convert from decimal to binary accurately enough  + * to produce the hexadecimal values shown. + */ + +#include <math.h> +#include "math_private.h" + +static const int init_jk[] = {2,3,4,6}; /* initial value for jk */ + +static const double PIo2[] = { +  1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ +  7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ +  5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ +  3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ +  1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ +  1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ +  2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ +  2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +}; + +static const double                      +zero   = 0.0, +one    = 1.0, +two24   =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +twon24  =  5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */ + +        int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int32_t *ipio2) +{ +        int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; +        double z,fw,f[20],fq[20],q[20]; + +    /* initialize jk*/ +        jk = init_jk[prec]; +        jp = jk; + +    /* determine jx,jv,q0, note that 3>q0 */ +        jx =  nx-1; +        jv = (e0-3)/24; if(jv<0) jv=0; +        q0 =  e0-24*(jv+1); + +    /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ +        j = jv-jx; m = jx+jk; +        for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j]; + +    /* compute q[0],q[1],...q[jk] */ +        for (i=0;i<=jk;i++) { +            for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw; +        } + +        jz = jk; +recompute: +    /* distill q[] into iq[] reversingly */ +        for(i=0,j=jz,z=q[jz];j>0;i++,j--) { +            fw    =  (double)((int32_t)(twon24* z)); +            iq[i] =  (int32_t)(z-two24*fw); +            z     =  q[j-1]+fw; +        } + +    /* compute n */ +        z  = scalbn(z,q0);              /* actual value of z */ +        z -= 8.0*floor(z*0.125);                /* trim off integer >= 8 */ +        n  = (int32_t) z; +        z -= (double)n; +        ih = 0; +        if(q0>0) {      /* need iq[jz-1] to determine n */ +            i  = (iq[jz-1]>>(24-q0)); n += i; +            iq[jz-1] -= i<<(24-q0); +            ih = iq[jz-1]>>(23-q0); +        }  +        else if(q0==0) ih = iq[jz-1]>>23; +        else if(z>=0.5) ih=2; + +        if(ih>0) {      /* q > 0.5 */ +            n += 1; carry = 0; +            for(i=0;i<jz ;i++) {        /* compute 1-q */ +                j = iq[i]; +                if(carry==0) { +                    if(j!=0) { +                        carry = 1; iq[i] = 0x1000000- j; +                    } +                } else  iq[i] = 0xffffff - j; +            } +            if(q0>0) {          /* rare case: chance is 1 in 12 */ +                switch(q0) { +                case 1: +                   iq[jz-1] &= 0x7fffff; break; +                case 2: +                   iq[jz-1] &= 0x3fffff; break; +                } +            } +            if(ih==2) { +                z = one - z; +                if(carry!=0) z -= scalbn(one,q0); +            } +        } + +    /* check if recomputation is needed */ +        if(z==zero) { +            j = 0; +            for (i=jz-1;i>=jk;i--) j |= iq[i]; +            if(j==0) { /* need recomputation */ +                for(k=1;iq[jk-k]==0;k++);   /* k = no. of terms needed */ + +                for(i=jz+1;i<=jz+k;i++) {   /* add q[jz+1] to q[jz+k] */ +                    f[jx+i] = (double) ipio2[jv+i]; +                    for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; +                    q[i] = fw; +                } +                jz += k; +                goto recompute; +            } +        } + +    /* chop off zero terms */ +        if(z==0.0) { +            jz -= 1; q0 -= 24; +            while(iq[jz]==0) { jz--; q0-=24;} +        } else { /* break z into 24-bit if necessary */ +            z = scalbn(z,-q0); +            if(z>=two24) {  +                fw = (double)((int32_t)(twon24*z)); +                iq[jz] = (int32_t)(z-two24*fw); +                jz += 1; q0 += 24; +                iq[jz] = (int32_t) fw; +            } else iq[jz] = (int32_t) z ; +        } + +    /* convert integer "bit" chunk to floating-point value */ +        fw = scalbn(one,q0); +        for(i=jz;i>=0;i--) { +            q[i] = fw*(double)iq[i]; fw*=twon24; +        } + +    /* compute PIo2[0,...,jp]*q[jz,...,0] */ +        for(i=jz;i>=0;i--) { +            for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k]; +            fq[jz-i] = fw; +        } + +    /* compress fq[] into y[] */ +        switch(prec) { +            case 0: +                fw = 0.0; +                for (i=jz;i>=0;i--) fw += fq[i]; +                y[0] = (ih==0)? fw: -fw;  +                break; +            case 1: +            case 2: +                fw = 0.0; +                for (i=jz;i>=0;i--) fw += fq[i];  +                y[0] = (ih==0)? fw: -fw;  +                fw = fq[0]-fw; +                for (i=1;i<=jz;i++) fw += fq[i]; +                y[1] = (ih==0)? fw: -fw;  +                break; +            case 3:     /* painful */ +                for (i=jz;i>0;i--) { +                    fw      = fq[i-1]+fq[i];  +                    fq[i]  += fq[i-1]-fw; +                    fq[i-1] = fw; +                } +                for (i=jz;i>1;i--) { +                    fw      = fq[i-1]+fq[i];  +                    fq[i]  += fq[i-1]-fw; +                    fq[i-1] = fw; +                } +                for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];  +                if(ih==0) { +                    y[0] =  fq[0]; y[1] =  fq[1]; y[2] =  fw; +                } else { +                    y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; +                } +        } +        return n&7; +} diff --git a/src/math/k_rem_pio2f.c b/src/math/k_rem_pio2f.c new file mode 100644 index 00000000..b543f084 --- /dev/null +++ b/src/math/k_rem_pio2f.c @@ -0,0 +1,192 @@ +/* k_rem_pio2f.c -- float version of k_rem_pio2.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +/* In the float version, the input parameter x contains 8 bit +   integers, not 24 bit integers.  113 bit precision is not supported.  */ + +static const int init_jk[] = {4,7,9}; /* initial value for jk */ + +static const float PIo2[] = { +  1.5703125000e+00, /* 0x3fc90000 */ +  4.5776367188e-04, /* 0x39f00000 */ +  2.5987625122e-05, /* 0x37da0000 */ +  7.5437128544e-08, /* 0x33a20000 */ +  6.0026650317e-11, /* 0x2e840000 */ +  7.3896444519e-13, /* 0x2b500000 */ +  5.3845816694e-15, /* 0x27c20000 */ +  5.6378512969e-18, /* 0x22d00000 */ +  8.3009228831e-20, /* 0x1fc40000 */ +  3.2756352257e-22, /* 0x1bc60000 */ +  6.3331015649e-25, /* 0x17440000 */ +}; + +static const float +zero   = 0.0, +one    = 1.0, +two8   =  2.5600000000e+02, /* 0x43800000 */ +twon8  =  3.9062500000e-03; /* 0x3b800000 */ + +        int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const int32_t *ipio2) +{ +        int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; +        float z,fw,f[20],fq[20],q[20]; + +    /* initialize jk*/ +        jk = init_jk[prec]; +        jp = jk; + +    /* determine jx,jv,q0, note that 3>q0 */ +        jx =  nx-1; +        jv = (e0-3)/8; if(jv<0) jv=0; +        q0 =  e0-8*(jv+1); + +    /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ +        j = jv-jx; m = jx+jk; +        for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (float) ipio2[j]; + +    /* compute q[0],q[1],...q[jk] */ +        for (i=0;i<=jk;i++) { +            for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw; +        } + +        jz = jk; +recompute: +    /* distill q[] into iq[] reversingly */ +        for(i=0,j=jz,z=q[jz];j>0;i++,j--) { +            fw    =  (float)((int32_t)(twon8* z)); +            iq[i] =  (int32_t)(z-two8*fw); +            z     =  q[j-1]+fw; +        } + +    /* compute n */ +        z  = scalbnf(z,q0);             /* actual value of z */ +        z -= (float)8.0*floorf(z*(float)0.125); /* trim off integer >= 8 */ +        n  = (int32_t) z; +        z -= (float)n; +        ih = 0; +        if(q0>0) {      /* need iq[jz-1] to determine n */ +            i  = (iq[jz-1]>>(8-q0)); n += i; +            iq[jz-1] -= i<<(8-q0); +            ih = iq[jz-1]>>(7-q0); +        } +        else if(q0==0) ih = iq[jz-1]>>7; +        else if(z>=(float)0.5) ih=2; + +        if(ih>0) {      /* q > 0.5 */ +            n += 1; carry = 0; +            for(i=0;i<jz ;i++) {        /* compute 1-q */ +                j = iq[i]; +                if(carry==0) { +                    if(j!=0) { +                        carry = 1; iq[i] = 0x100- j; +                    } +                } else  iq[i] = 0xff - j; +            } +            if(q0>0) {          /* rare case: chance is 1 in 12 */ +                switch(q0) { +                case 1: +                   iq[jz-1] &= 0x7f; break; +                case 2: +                   iq[jz-1] &= 0x3f; break; +                } +            } +            if(ih==2) { +                z = one - z; +                if(carry!=0) z -= scalbnf(one,q0); +            } +        } + +    /* check if recomputation is needed */ +        if(z==zero) { +            j = 0; +            for (i=jz-1;i>=jk;i--) j |= iq[i]; +            if(j==0) { /* need recomputation */ +                for(k=1;iq[jk-k]==0;k++);   /* k = no. of terms needed */ + +                for(i=jz+1;i<=jz+k;i++) {   /* add q[jz+1] to q[jz+k] */ +                    f[jx+i] = (float) ipio2[jv+i]; +                    for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; +                    q[i] = fw; +                } +                jz += k; +                goto recompute; +            } +        } + +    /* chop off zero terms */ +        if(z==(float)0.0) { +            jz -= 1; q0 -= 8; +            while(iq[jz]==0) { jz--; q0-=8;} +        } else { /* break z into 8-bit if necessary */ +            z = scalbnf(z,-q0); +            if(z>=two8) { +                fw = (float)((int32_t)(twon8*z)); +                iq[jz] = (int32_t)(z-two8*fw); +                jz += 1; q0 += 8; +                iq[jz] = (int32_t) fw; +            } else iq[jz] = (int32_t) z ; +        } + +    /* convert integer "bit" chunk to floating-point value */ +        fw = scalbnf(one,q0); +        for(i=jz;i>=0;i--) { +            q[i] = fw*(float)iq[i]; fw*=twon8; +        } + +    /* compute PIo2[0,...,jp]*q[jz,...,0] */ +        for(i=jz;i>=0;i--) { +            for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k]; +            fq[jz-i] = fw; +        } + +    /* compress fq[] into y[] */ +        switch(prec) { +            case 0: +                fw = 0.0; +                for (i=jz;i>=0;i--) fw += fq[i]; +                y[0] = (ih==0)? fw: -fw; +                break; +            case 1: +            case 2: +                fw = 0.0; +                for (i=jz;i>=0;i--) fw += fq[i]; +                y[0] = (ih==0)? fw: -fw; +                fw = fq[0]-fw; +                for (i=1;i<=jz;i++) fw += fq[i]; +                y[1] = (ih==0)? fw: -fw; +                break; +            case 3:     /* painful */ +                for (i=jz;i>0;i--) { +                    fw      = fq[i-1]+fq[i]; +                    fq[i]  += fq[i-1]-fw; +                    fq[i-1] = fw; +                } +                for (i=jz;i>1;i--) { +                    fw      = fq[i-1]+fq[i]; +                    fq[i]  += fq[i-1]-fw; +                    fq[i-1] = fw; +                } +                for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; +                if(ih==0) { +                    y[0] =  fq[0]; y[1] =  fq[1]; y[2] =  fw; +                } else { +                    y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; +                } +        } +        return n&7; +} diff --git a/src/math/k_sin.c b/src/math/k_sin.c new file mode 100644 index 00000000..9def2589 --- /dev/null +++ b/src/math/k_sin.c @@ -0,0 +1,68 @@ + +/* @(#)k_sin.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +/* __kernel_sin( x, y, iy) + * kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input iy indicates whether y is 0. (if iy=0, y assume to be 0).  + * + * Algorithm + *      1. Since sin(-x) = -sin(x), we need only to consider positive x.  + *      2. if x < 2^-27 (hx<0x3e400000 0), return x with inexact if x!=0. + *      3. sin(x) is approximated by a polynomial of degree 13 on + *         [0,pi/4] + *                               3            13 + *              sin(x) ~ x + S1*x + ... + S6*x + *         where + *       + *      |sin(x)         2     4     6     8     10     12  |     -58 + *      |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x  +S6*x   )| <= 2 + *      |  x                                               |  + *  + *      4. sin(x+y) = sin(x) + sin'(x')*y + *                  ~ sin(x) + (1-x*x/2)*y + *         For better accuracy, let  + *                   3      2      2      2      2 + *              r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6)))) + *         then                   3    2 + *              sin(x) = x + (S1*x + (x *(r-y/2)+y)) + */ + +#include <math.h> +#include "math_private.h" + +static const double +half =  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +S1  = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */ +S2  =  8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */ +S3  = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */ +S4  =  2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */ +S5  = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */ +S6  =  1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */ + +double +__kernel_sin(double x, double y, int iy) +{ +        double z,r,v; +        int32_t ix; +        GET_HIGH_WORD(ix,x); +        ix &= 0x7fffffff;                       /* high word of x */ +        if(ix<0x3e400000)                       /* |x| < 2**-27 */ +           {if((int)x==0) return x;}            /* generate inexact */ +        z       =  x*x; +        v       =  z*x; +        r       =  S2+z*(S3+z*(S4+z*(S5+z*S6))); +        if(iy==0) return x+v*(S1+z*r); +        else      return x-((z*(half*y-v*r)-y)-v*S1); +} diff --git a/src/math/k_sinf.c b/src/math/k_sinf.c new file mode 100644 index 00000000..617f6148 --- /dev/null +++ b/src/math/k_sinf.c @@ -0,0 +1,42 @@ +/* k_sinf.c -- float version of k_sin.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +half =  5.0000000000e-01,/* 0x3f000000 */ +S1  = -1.6666667163e-01, /* 0xbe2aaaab */ +S2  =  8.3333337680e-03, /* 0x3c088889 */ +S3  = -1.9841270114e-04, /* 0xb9500d01 */ +S4  =  2.7557314297e-06, /* 0x3638ef1b */ +S5  = -2.5050759689e-08, /* 0xb2d72f34 */ +S6  =  1.5896910177e-10; /* 0x2f2ec9d3 */ + +float +__kernel_sinf(float x, float y, int iy) +{ +        float z,r,v; +        int32_t ix; +        GET_FLOAT_WORD(ix,x); +        ix &= 0x7fffffff;                       /* high word of x */ +        if(ix<0x32000000)                       /* |x| < 2**-27 */ +           {if((int)x==0) return x;}            /* generate inexact */ +        z       =  x*x; +        v       =  z*x; +        r       =  S2+z*(S3+z*(S4+z*(S5+z*S6))); +        if(iy==0) return x+v*(S1+z*r); +        else      return x-((z*(half*y-v*r)-y)-v*S1); +} diff --git a/src/math/k_tan.c b/src/math/k_tan.c new file mode 100644 index 00000000..f721ae6d --- /dev/null +++ b/src/math/k_tan.c @@ -0,0 +1,149 @@ +/* @(#)k_tan.c 1.5 04/04/22 SMI */ + +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* __kernel_tan( x, y, k ) + * kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854 + * Input x is assumed to be bounded by ~pi/4 in magnitude. + * Input y is the tail of x. + * Input k indicates whether tan (if k = 1) or -1/tan (if k = -1) is returned. + * + * Algorithm + *      1. Since tan(-x) = -tan(x), we need only to consider positive x. + *      2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0. + *      3. tan(x) is approximated by a odd polynomial of degree 27 on + *         [0,0.67434] + *                               3             27 + *              tan(x) ~ x + T1*x + ... + T13*x + *         where + * + *              |tan(x)         2     4            26   |     -59.2 + *              |----- - (1+T1*x +T2*x +.... +T13*x    )| <= 2 + *              |  x                                    | + * + *         Note: tan(x+y) = tan(x) + tan'(x)*y + *                        ~ tan(x) + (1+x*x)*y + *         Therefore, for better accuracy in computing tan(x+y), let + *                   3      2      2       2       2 + *              r = x *(T2+x *(T3+x *(...+x *(T12+x *T13)))) + *         then + *                                  3    2 + *              tan(x+y) = x + (T1*x + (x *(r+y)+y)) + * + *      4. For x in [0.67434,pi/4],  let y = pi/4 - x, then + *              tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y)) + *                     = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y))) + */ + +#include <math.h> +#include "math_private.h" +static const double xxx[] = { +                 3.33333333333334091986e-01,    /* 3FD55555, 55555563 */ +                 1.33333333333201242699e-01,    /* 3FC11111, 1110FE7A */ +                 5.39682539762260521377e-02,    /* 3FABA1BA, 1BB341FE */ +                 2.18694882948595424599e-02,    /* 3F9664F4, 8406D637 */ +                 8.86323982359930005737e-03,    /* 3F8226E3, E96E8493 */ +                 3.59207910759131235356e-03,    /* 3F6D6D22, C9560328 */ +                 1.45620945432529025516e-03,    /* 3F57DBC8, FEE08315 */ +                 5.88041240820264096874e-04,    /* 3F4344D8, F2F26501 */ +                 2.46463134818469906812e-04,    /* 3F3026F7, 1A8D1068 */ +                 7.81794442939557092300e-05,    /* 3F147E88, A03792A6 */ +                 7.14072491382608190305e-05,    /* 3F12B80F, 32F0A7E9 */ +                -1.85586374855275456654e-05,    /* BEF375CB, DB605373 */ +                 2.59073051863633712884e-05,    /* 3EFB2A70, 74BF7AD4 */ +/* one */        1.00000000000000000000e+00,    /* 3FF00000, 00000000 */ +/* pio4 */       7.85398163397448278999e-01,    /* 3FE921FB, 54442D18 */ +/* pio4lo */     3.06161699786838301793e-17     /* 3C81A626, 33145C07 */ +}; +#define one     xxx[13] +#define pio4    xxx[14] +#define pio4lo  xxx[15] +#define T       xxx +/* INDENT ON */ + +double +__kernel_tan(double x, double y, int iy) { +        double z, r, v, w, s; +        int32_t ix, hx; + +        GET_HIGH_WORD(hx,x); +        ix = hx & 0x7fffffff;                   /* high word of |x| */ +        if (ix < 0x3e300000) {                  /* x < 2**-28 */ +                if ((int) x == 0) {             /* generate inexact */ +                        uint32_t low; +                        GET_LOW_WORD(low,x); +                        if (((ix | low) | (iy + 1)) == 0) +                                return one / fabs(x); +                        else { +                                if (iy == 1) +                                        return x; +                                else {  /* compute -1 / (x+y) carefully */ +                                        double a, t; + +                                        z = w = x + y; +                                        SET_LOW_WORD(z, 0); +                                        v = y - (z - x); +                                        t = a = -one / w; +                                        SET_LOW_WORD(t, 0); +                                        s = one + t * z; +                                        return t + a * (s + t * v); +                                } +                        } +                } +        } +        if (ix >= 0x3FE59428) { /* |x| >= 0.6744 */ +                if (hx < 0) { +                        x = -x; +                        y = -y; +                } +                z = pio4 - x; +                w = pio4lo - y; +                x = z + w; +                y = 0.0; +        } +        z = x * x; +        w = z * z; +        /* +         * Break x^5*(T[1]+x^2*T[2]+...) into +         * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + +         * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) +         */ +        r = T[1] + w * (T[3] + w * (T[5] + w * (T[7] + w * (T[9] + +                w * T[11])))); +        v = z * (T[2] + w * (T[4] + w * (T[6] + w * (T[8] + w * (T[10] + +                w * T[12]))))); +        s = z * x; +        r = y + z * (s * (r + v) + y); +        r += T[0] * s; +        w = x + r; +        if (ix >= 0x3FE59428) { +                v = (double) iy; +                return (double) (1 - ((hx >> 30) & 2)) * +                        (v - 2.0 * (x - (w * w / (w + v) - r))); +        } +        if (iy == 1) +                return w; +        else { +                /* +                 * if allow error up to 2 ulp, simply return +                 * -1.0 / (x+r) here +                 */ +                /* compute -1.0 / (x+r) accurately */ +                double a, t; +                z = w; +                SET_LOW_WORD(z,0); +                v = r - (z - x);        /* z+v = r+x */ +                t = a = -1.0 / w;       /* a = -1.0/w */ +                SET_LOW_WORD(t,0); +                s = 1.0 + t * z; +                return t + a * (s + t * v); +        } +} diff --git a/src/math/k_tanf.c b/src/math/k_tanf.c new file mode 100644 index 00000000..99ede58c --- /dev/null +++ b/src/math/k_tanf.c @@ -0,0 +1,105 @@ +/* k_tanf.c -- float version of k_tan.c + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" +static const float +one   =  1.0000000000e+00, /* 0x3f800000 */ +pio4  =  7.8539812565e-01, /* 0x3f490fda */ +pio4lo=  3.7748947079e-08, /* 0x33222168 */ +T[] =  { +  3.3333334327e-01, /* 0x3eaaaaab */ +  1.3333334029e-01, /* 0x3e088889 */ +  5.3968254477e-02, /* 0x3d5d0dd1 */ +  2.1869488060e-02, /* 0x3cb327a4 */ +  8.8632395491e-03, /* 0x3c11371f */ +  3.5920790397e-03, /* 0x3b6b6916 */ +  1.4562094584e-03, /* 0x3abede48 */ +  5.8804126456e-04, /* 0x3a1a26c8 */ +  2.4646313977e-04, /* 0x398137b9 */ +  7.8179444245e-05, /* 0x38a3f445 */ +  7.1407252108e-05, /* 0x3895c07a */ + -1.8558637748e-05, /* 0xb79bae5f */ +  2.5907305826e-05, /* 0x37d95384 */ +}; + +float +__kernel_tanf(float x, float y, int iy) +{ +        float z,r,v,w,s; +        int32_t ix,hx; +        GET_FLOAT_WORD(hx,x); +        ix = hx&0x7fffffff;     /* high word of |x| */ +        if(ix<0x31800000) {                     /* x < 2**-28 */ +                if ((int) x == 0) {             /* generate inexact */ +                        if ((ix | (iy + 1)) == 0) +                                return one / fabsf(x); +                        else { +                                if (iy == 1) +                                        return x; +                                else {  /* compute -1 / (x+y) carefully */ +                                        double a, t; + +                                        z = w = x + y; +                                        GET_FLOAT_WORD(ix, z); +                                        SET_FLOAT_WORD(z, ix & 0xfffff000); +                                        v = y - (z - x); +                                        t = a = -one / w; +                                        GET_FLOAT_WORD(ix, t); +                                        SET_FLOAT_WORD(t, ix & 0xfffff000); +                                        s = one + t * z; +                                        return t + a * (s + t * v); +                                } +                        } +                } +        } +        if(ix>=0x3f2ca140) {                    /* |x|>=0.6744 */ +            if(hx<0) {x = -x; y = -y;} +            z = pio4-x; +            w = pio4lo-y; +            x = z+w; y = 0.0; +        } +        z       =  x*x; +        w       =  z*z; +    /* Break x^5*(T[1]+x^2*T[2]+...) into +     *    x^5(T[1]+x^4*T[3]+...+x^20*T[11]) + +     *    x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12])) +     */ +        r = T[1]+w*(T[3]+w*(T[5]+w*(T[7]+w*(T[9]+w*T[11])))); +        v = z*(T[2]+w*(T[4]+w*(T[6]+w*(T[8]+w*(T[10]+w*T[12]))))); +        s = z*x; +        r = y + z*(s*(r+v)+y); +        r += T[0]*s; +        w = x+r; +        if(ix>=0x3f2ca140) { +            v = (float)iy; +            return (float)(1-((hx>>30)&2))*(v-(float)2.0*(x-(w*w/(w+v)-r))); +        } +        if(iy==1) return w; +        else {          /* if allow error up to 2 ulp, +                           simply return -1.0/(x+r) here */ +     /*  compute -1.0/(x+r) accurately */ +            float a,t; +            int32_t i; +            z  = w; +            GET_FLOAT_WORD(i,z); +            SET_FLOAT_WORD(z,i&0xfffff000); +            v  = r-(z - x);     /* z+v = r+x */ +            t = a  = -(float)1.0/w;     /* a = -1.0/w */ +            GET_FLOAT_WORD(i,t); +            SET_FLOAT_WORD(t,i&0xfffff000); +            s  = (float)1.0+t*z; +            return t+a*(s+t*v); +        } +} diff --git a/src/math/math_private.h b/src/math/math_private.h new file mode 100644 index 00000000..28a6a195 --- /dev/null +++ b/src/math/math_private.h @@ -0,0 +1,143 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef _MATH_PRIVATE_H_ +#define _MATH_PRIVATE_H_ + +#include <inttypes.h> + +/* + * The original fdlibm code used statements like: + *      n0 = ((*(int*)&one)>>29)^1;             * index of high word * + *      ix0 = *(n0+(int*)&x);                   * high word of x * + *      ix1 = *((1-n0)+(int*)&x);               * low word of x * + * to dig two 32 bit words out of the 64 bit IEEE floating point + * value.  That is non-ANSI, and, moreover, the gcc instruction + * scheduler gets it wrong.  We instead use the following macros. + * Unlike the original code, we determine the endianness at compile + * time, not at run time; I don't see much benefit to selecting + * endianness at run time. + */ + +/* + * A union which permits us to convert between a double and two 32 bit + * ints. + */ + +typedef union +{ +  double value; +  uint64_t words; +} ieee_double_shape_type; + +/* Get two 32 bit ints from a double.  */ + +#define EXTRACT_WORDS(ix0,ix1,d)                                \ +do {                                                            \ +  ieee_double_shape_type ew_u;                                  \ +  ew_u.value = (d);                                             \ +  (ix0) = ew_u.words >> 32;                                     \ +  (ix1) = (uint32_t)ew_u.words;                                 \ +} while (0) + +/* Get the more significant 32 bit int from a double.  */ + +#define GET_HIGH_WORD(i,d)                                      \ +do {                                                            \ +  ieee_double_shape_type gh_u;                                  \ +  gh_u.value = (d);                                             \ +  (i) = gh_u.words >> 32;                                       \ +} while (0) + +/* Get the less significant 32 bit int from a double.  */ + +#define GET_LOW_WORD(i,d)                                       \ +do {                                                            \ +  ieee_double_shape_type gl_u;                                  \ +  gl_u.value = (d);                                             \ +  (i) = (uint32_t)gl_u.words;                                   \ +} while (0) + +/* Set a double from two 32 bit ints.  */ + +#define INSERT_WORDS(d,ix0,ix1)                                 \ +do {                                                            \ +  ieee_double_shape_type iw_u;                                  \ +  iw_u.words = ((uint64_t)(ix0) << 32) | (ix1);                 \ +  (d) = iw_u.value;                                             \ +} while (0) + +/* Set the more significant 32 bits of a double from an int.  */ + +#define SET_HIGH_WORD(d,v)                                      \ +do {                                                            \ +  ieee_double_shape_type sh_u;                                  \ +  sh_u.value = (d);                                             \ +  sh_u.words &= 0xffffffff;                                     \ +  sh_u.words |= ((uint64_t)(v) << 32);                          \ +  (d) = sh_u.value;                                             \ +} while (0) + +/* Set the less significant 32 bits of a double from an int.  */ + +#define SET_LOW_WORD(d,v)                                       \ +do {                                                            \ +  ieee_double_shape_type sl_u;                                  \ +  sl_u.value = (d);                                             \ +  sl_u.words &= 0xffffffff00000000ull;                          \ +  sl_u.words |= (uint32_t)(v);                                  \ +  (d) = sl_u.value;                                             \ +} while (0) + +/* + * A union which permits us to convert between a float and a 32 bit + * int. + */ + +typedef union +{ +  float value; +  uint32_t word; +} ieee_float_shape_type; + +/* Get a 32 bit int from a float.  */ + +#define GET_FLOAT_WORD(i,d)                                     \ +do {                                                            \ +  ieee_float_shape_type gf_u;                                   \ +  gf_u.value = (d);                                             \ +  (i) = gf_u.word;                                              \ +} while (0) + +/* Set a float from a 32 bit int.  */ + +#define SET_FLOAT_WORD(d,i)                                     \ +do {                                                            \ +  ieee_float_shape_type sf_u;                                   \ +  sf_u.word = (i);                                              \ +  (d) = sf_u.value;                                             \ +} while (0) + +/* fdlibm kernel function */ +int     __ieee754_rem_pio2(double,double*); +double  __kernel_sin(double,double,int); +double  __kernel_cos(double,double); +double  __kernel_tan(double,double,int); +int     __kernel_rem_pio2(double*,double*,int,int,int,const int*); + +/* float versions of fdlibm kernel functions */ +int     __ieee754_rem_pio2f(float,float*); +float   __kernel_sinf(float,float,int); +float   __kernel_cosf(float,float); +float   __kernel_tanf(float,float,int); +int     __kernel_rem_pio2f(float*,float*,int,int,int,const int*); + +#endif /* !_MATH_PRIVATE_H_ */ diff --git a/src/math/s_asinh.c b/src/math/s_asinh.c new file mode 100644 index 00000000..26016091 --- /dev/null +++ b/src/math/s_asinh.c @@ -0,0 +1,53 @@ +/* @(#)s_asinh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* asinh(x) + * Method : + *      Based on + *              asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ] + *      we have + *      asinh(x) := x  if  1+x*x=1, + *               := sign(x)*(log(x)+ln2)) for large |x|, else + *               := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else + *               := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2))) + */ + +#include <math.h> +#include "math_private.h" + +static const double +one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +ln2 =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ +huge=  1.00000000000000000000e+300; + +double +asinh(double x) +{ +        double t,w; +        int32_t hx,ix; +        GET_HIGH_WORD(hx,x); +        ix = hx&0x7fffffff; +        if(ix>=0x7ff00000) return x+x;  /* x is inf or NaN */ +        if(ix< 0x3e300000) {    /* |x|<2**-28 */ +            if(huge+x>one) return x;    /* return x inexact except 0 */ +        } +        if(ix>0x41b00000) {     /* |x| > 2**28 */ +            w = log(fabs(x))+ln2; +        } else if (ix>0x40000000) {     /* 2**28 > |x| > 2.0 */ +            t = fabs(x); +            w = log(2.0*t+one/(sqrt(x*x+one)+t)); +        } else {                /* 2.0 > |x| > 2**-28 */ +            t = x*x; +            w =log1p(fabs(x)+t/(one+sqrt(one+t))); +        } +        if(hx>0) return w; else return -w; +} diff --git a/src/math/s_asinhf.c b/src/math/s_asinhf.c new file mode 100644 index 00000000..04f8d072 --- /dev/null +++ b/src/math/s_asinhf.c @@ -0,0 +1,45 @@ +/* s_asinhf.c -- float version of s_asinh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +one =  1.0000000000e+00, /* 0x3F800000 */ +ln2 =  6.9314718246e-01, /* 0x3f317218 */ +huge=  1.0000000000e+30; + +float +asinhf(float x) +{ +        float t,w; +        int32_t hx,ix; +        GET_FLOAT_WORD(hx,x); +        ix = hx&0x7fffffff; +        if(ix>=0x7f800000) return x+x;  /* x is inf or NaN */ +        if(ix< 0x31800000) {    /* |x|<2**-28 */ +            if(huge+x>one) return x;    /* return x inexact except 0 */ +        } +        if(ix>0x4d800000) {     /* |x| > 2**28 */ +            w = logf(fabsf(x))+ln2; +        } else if (ix>0x40000000) {     /* 2**28 > |x| > 2.0 */ +            t = fabsf(x); +            w = logf((float)2.0*t+one/(sqrtf(x*x+one)+t)); +        } else {                /* 2.0 > |x| > 2**-28 */ +            t = x*x; +            w =log1pf(fabsf(x)+t/(one+sqrtf(one+t))); +        } +        if(hx>0) return w; else return -w; +} diff --git a/src/math/s_atan.c b/src/math/s_atan.c new file mode 100644 index 00000000..1faac024 --- /dev/null +++ b/src/math/s_atan.c @@ -0,0 +1,115 @@ +/* @(#)s_atan.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* atan(x) + * Method + *   1. Reduce x to positive by atan(x) = -atan(-x). + *   2. According to the integer k=4t+0.25 chopped, t=x, the argument + *      is further reduced to one of the following intervals and the + *      arctangent of t is evaluated by the corresponding formula: + * + *      [0,7/16]      atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...) + *      [7/16,11/16]  atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) ) + *      [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) ) + *      [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) ) + *      [39/16,INF]   atan(x) = atan(INF) + atan( -1/t ) + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include <math.h> +#include "math_private.h" + +static const double atanhi[] = { +  4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */ +  7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */ +  9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */ +  1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */ +}; + +static const double atanlo[] = { +  2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */ +  3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */ +  1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */ +  6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */ +}; + +static const double aT[] = { +  3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */ + -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */ +  1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */ + -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */ +  9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */ + -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */ +  6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */ + -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */ +  4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */ + -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */ +  1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */ +}; + +        static const double +one   = 1.0, +huge   = 1.0e300; + +double +atan(double x) +{ +        double w,s1,s2,z; +        int32_t ix,hx,id; + +        GET_HIGH_WORD(hx,x); +        ix = hx&0x7fffffff; +        if(ix>=0x44100000) {    /* if |x| >= 2^66 */ +            uint32_t low; +            GET_LOW_WORD(low,x); +            if(ix>0x7ff00000|| +                (ix==0x7ff00000&&(low!=0))) +                return x+x;             /* NaN */ +            if(hx>0) return  atanhi[3]+atanlo[3]; +            else     return -atanhi[3]-atanlo[3]; +        } if (ix < 0x3fdc0000) {        /* |x| < 0.4375 */ +            if (ix < 0x3e200000) {      /* |x| < 2^-29 */ +                if(huge+x>one) return x;        /* raise inexact */ +            } +            id = -1; +        } else { +        x = fabs(x); +        if (ix < 0x3ff30000) {          /* |x| < 1.1875 */ +            if (ix < 0x3fe60000) {      /* 7/16 <=|x|<11/16 */ +                id = 0; x = (2.0*x-one)/(2.0+x); +            } else {                    /* 11/16<=|x|< 19/16 */ +                id = 1; x  = (x-one)/(x+one); +            } +        } else { +            if (ix < 0x40038000) {      /* |x| < 2.4375 */ +                id = 2; x  = (x-1.5)/(one+1.5*x); +            } else {                    /* 2.4375 <= |x| < 2^66 */ +                id = 3; x  = -1.0/x; +            } +        }} +    /* end of argument reduction */ +        z = x*x; +        w = z*z; +    /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ +        s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10]))))); +        s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9])))); +        if (id<0) return x - x*(s1+s2); +        else { +            z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); +            return (hx<0)? -z:z; +        } +} diff --git a/src/math/s_atanf.c b/src/math/s_atanf.c new file mode 100644 index 00000000..03067e18 --- /dev/null +++ b/src/math/s_atanf.c @@ -0,0 +1,95 @@ +/* s_atanf.c -- float version of s_atan.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float atanhi[] = { +  4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ +  7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ +  9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ +  1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ +}; + +static const float atanlo[] = { +  5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ +  3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ +  3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ +  7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ +}; + +static const float aT[] = { +  3.3333334327e-01, /* 0x3eaaaaaa */ + -2.0000000298e-01, /* 0xbe4ccccd */ +  1.4285714924e-01, /* 0x3e124925 */ + -1.1111110449e-01, /* 0xbde38e38 */ +  9.0908870101e-02, /* 0x3dba2e6e */ + -7.6918758452e-02, /* 0xbd9d8795 */ +  6.6610731184e-02, /* 0x3d886b35 */ + -5.8335702866e-02, /* 0xbd6ef16b */ +  4.9768779427e-02, /* 0x3d4bda59 */ + -3.6531571299e-02, /* 0xbd15a221 */ +  1.6285819933e-02, /* 0x3c8569d7 */ +}; + +        static const float +one   = 1.0, +huge   = 1.0e30; + +float +atanf(float x) +{ +        float w,s1,s2,z; +        int32_t ix,hx,id; + +        GET_FLOAT_WORD(hx,x); +        ix = hx&0x7fffffff; +        if(ix>=0x50800000) {    /* if |x| >= 2^34 */ +            if(ix>0x7f800000) +                return x+x;             /* NaN */ +            if(hx>0) return  atanhi[3]+atanlo[3]; +            else     return -atanhi[3]-atanlo[3]; +        } if (ix < 0x3ee00000) {        /* |x| < 0.4375 */ +            if (ix < 0x31000000) {      /* |x| < 2^-29 */ +                if(huge+x>one) return x;        /* raise inexact */ +            } +            id = -1; +        } else { +        x = fabsf(x); +        if (ix < 0x3f980000) {          /* |x| < 1.1875 */ +            if (ix < 0x3f300000) {      /* 7/16 <=|x|<11/16 */ +                id = 0; x = ((float)2.0*x-one)/((float)2.0+x); +            } else {                    /* 11/16<=|x|< 19/16 */ +                id = 1; x  = (x-one)/(x+one); +            } +        } else { +            if (ix < 0x401c0000) {      /* |x| < 2.4375 */ +                id = 2; x  = (x-(float)1.5)/(one+(float)1.5*x); +            } else {                    /* 2.4375 <= |x| < 2^66 */ +                id = 3; x  = -(float)1.0/x; +            } +        }} +    /* end of argument reduction */ +        z = x*x; +        w = z*z; +    /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ +        s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10]))))); +        s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9])))); +        if (id<0) return x - x*(s1+s2); +        else { +            z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); +            return (hx<0)? -z:z; +        } +} diff --git a/src/math/s_cbrt.c b/src/math/s_cbrt.c new file mode 100644 index 00000000..8adcb191 --- /dev/null +++ b/src/math/s_cbrt.c @@ -0,0 +1,77 @@ +/* @(#)s_cbrt.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +/* cbrt(x) + * Return cube root of x + */ +static const uint32_t +        B1 = 715094163, /* B1 = (682-0.03306235651)*2**20 */ +        B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */ + +static const double +C =  5.42857142857142815906e-01, /* 19/35     = 0x3FE15F15, 0xF15F15F1 */ +D = -7.05306122448979611050e-01, /* -864/1225 = 0xBFE691DE, 0x2532C834 */ +E =  1.41428571428571436819e+00, /* 99/70     = 0x3FF6A0EA, 0x0EA0EA0F */ +F =  1.60714285714285720630e+00, /* 45/28     = 0x3FF9B6DB, 0x6DB6DB6E */ +G =  3.57142857142857150787e-01; /* 5/14      = 0x3FD6DB6D, 0xB6DB6DB7 */ + +double +cbrt(double x) +{ +        int32_t hx; +        double r,s,t=0.0,w; +        uint32_t sign; +        uint32_t high,low; + +        GET_HIGH_WORD(hx,x); +        sign=hx&0x80000000;             /* sign= sign(x) */ +        hx  ^=sign; +        if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */ +        GET_LOW_WORD(low,x); +        if((hx|low)==0) +            return(x);          /* cbrt(0) is itself */ + +        SET_HIGH_WORD(x,hx);    /* x <- |x| */ +    /* rough cbrt to 5 bits */ +        if(hx<0x00100000)               /* subnormal number */ +          {SET_HIGH_WORD(t,0x43500000); /* set t= 2**54 */ +           t*=x; GET_HIGH_WORD(high,t); SET_HIGH_WORD(t,high/3+B2); +          } +        else +          SET_HIGH_WORD(t,hx/3+B1); + + +    /* new cbrt to 23 bits, may be implemented in single precision */ +        r=t*t/x; +        s=C+r*t; +        t*=G+F/(s+E+D/s); + +    /* chopped to 20 bits and make it larger than cbrt(x) */ +        GET_HIGH_WORD(high,t); +        INSERT_WORDS(t,high+0x00000001,0); + + +    /* one step newton iteration to 53 bits with error less than 0.667 ulps */ +        s=t*t;          /* t*t is exact */ +        r=x/s; +        w=t+t; +        r=(r-t)/(w+r);  /* r-s is exact */ +        t=t+t*r; + +    /* retore the sign bit */ +        GET_HIGH_WORD(high,t); +        SET_HIGH_WORD(t,high|sign); +        return(t); +} diff --git a/src/math/s_cbrtf.c b/src/math/s_cbrtf.c new file mode 100644 index 00000000..e7b46de7 --- /dev/null +++ b/src/math/s_cbrtf.c @@ -0,0 +1,67 @@ +/* s_cbrtf.c -- float version of s_cbrt.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +/* cbrtf(x) + * Return cube root of x + */ +static const unsigned +        B1 = 709958130, /* B1 = (84+2/3-0.03306235651)*2**23 */ +        B2 = 642849266; /* B2 = (76+2/3-0.03306235651)*2**23 */ + +static const float +C =  5.4285717010e-01, /* 19/35     = 0x3f0af8b0 */ +D = -7.0530611277e-01, /* -864/1225 = 0xbf348ef1 */ +E =  1.4142856598e+00, /* 99/70     = 0x3fb50750 */ +F =  1.6071428061e+00, /* 45/28     = 0x3fcdb6db */ +G =  3.5714286566e-01; /* 5/14      = 0x3eb6db6e */ + +float +cbrtf(float x) +{ +        float r,s,t; +        int32_t hx; +        uint32_t sign; +        uint32_t high; + +        GET_FLOAT_WORD(hx,x); +        sign=hx&0x80000000;             /* sign= sign(x) */ +        hx  ^=sign; +        if(hx>=0x7f800000) return(x+x); /* cbrt(NaN,INF) is itself */ +        if(hx==0) +            return(x);          /* cbrt(0) is itself */ + +        SET_FLOAT_WORD(x,hx);   /* x <- |x| */ +    /* rough cbrt to 5 bits */ +        if(hx<0x00800000)               /* subnormal number */ +          {SET_FLOAT_WORD(t,0x4b800000); /* set t= 2**24 */ +           t*=x; GET_FLOAT_WORD(high,t); SET_FLOAT_WORD(t,high/3+B2); +          } +        else +          SET_FLOAT_WORD(t,hx/3+B1); + + +    /* new cbrt to 23 bits */ +        r=t*t/x; +        s=C+r*t; +        t*=G+F/(s+E+D/s); + +    /* retore the sign bit */ +        GET_FLOAT_WORD(high,t); +        SET_FLOAT_WORD(t,high|sign); +        return(t); +} diff --git a/src/math/s_ceil.c b/src/math/s_ceil.c new file mode 100644 index 00000000..1670cade --- /dev/null +++ b/src/math/s_ceil.c @@ -0,0 +1,68 @@ +/* @(#)s_ceil.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * ceil(x) + * Return x rounded toward -inf to integral value + * Method: + *      Bit twiddling. + * Exception: + *      Inexact flag raised if x not equal to ceil(x). + */ + +#include <math.h> +#include "math_private.h" + +static const double huge = 1.0e300; + +double +ceil(double x) +{ +        int32_t i0,i1,j0; +        uint32_t i,j; +        EXTRACT_WORDS(i0,i1,x); +        j0 = ((i0>>20)&0x7ff)-0x3ff; +        if(j0<20) { +            if(j0<0) {  /* raise inexact if x != 0 */ +                if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ +                    if(i0<0) {i0=0x80000000;i1=0;} +                    else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;} +                } +            } else { +                i = (0x000fffff)>>j0; +                if(((i0&i)|i1)==0) return x; /* x is integral */ +                if(huge+x>0.0) {        /* raise inexact flag */ +                    if(i0>0) i0 += (0x00100000)>>j0; +                    i0 &= (~i); i1=0; +                } +            } +        } else if (j0>51) { +            if(j0==0x400) return x+x;   /* inf or NaN */ +            else return x;              /* x is integral */ +        } else { +            i = ((uint32_t)(0xffffffff))>>(j0-20); +            if((i1&i)==0) return x;     /* x is integral */ +            if(huge+x>0.0) {            /* raise inexact flag */ +                if(i0>0) { +                    if(j0==20) i0+=1; +                    else { +                        j = i1 + (1<<(52-j0)); +                        if(j<i1) i0+=1; /* got a carry */ +                        i1 = j; +                    } +                } +                i1 &= (~i); +            } +        } +        INSERT_WORDS(x,i0,i1); +        return x; +} diff --git a/src/math/s_ceilf.c b/src/math/s_ceilf.c new file mode 100644 index 00000000..3615041f --- /dev/null +++ b/src/math/s_ceilf.c @@ -0,0 +1,49 @@ +/* s_ceilf.c -- float version of s_ceil.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float huge = 1.0e30; + +float +ceilf(float x) +{ +        int32_t i0,j0; +        uint32_t i; + +        GET_FLOAT_WORD(i0,x); +        j0 = ((i0>>23)&0xff)-0x7f; +        if(j0<23) { +            if(j0<0) {  /* raise inexact if x != 0 */ +                if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */ +                    if(i0<0) {i0=0x80000000;} +                    else if(i0!=0) { i0=0x3f800000;} +                } +            } else { +                i = (0x007fffff)>>j0; +                if((i0&i)==0) return x; /* x is integral */ +                if(huge+x>(float)0.0) { /* raise inexact flag */ +                    if(i0>0) i0 += (0x00800000)>>j0; +                    i0 &= (~i); +                } +            } +        } else { +            if(j0==0x80) return x+x;    /* inf or NaN */ +            else return x;              /* x is integral */ +        } +        SET_FLOAT_WORD(x,i0); +        return x; +} diff --git a/src/math/s_copysign.c b/src/math/s_copysign.c new file mode 100644 index 00000000..59d3877c --- /dev/null +++ b/src/math/s_copysign.c @@ -0,0 +1,30 @@ +/* @(#)s_copysign.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * copysign(double x, double y) + * copysign(x,y) returns a value with the magnitude of x and + * with the sign bit of y. + */ + +#include <math.h> +#include "math_private.h" + +double +copysign(double x, double y) +{ +        uint32_t hx,hy; +        GET_HIGH_WORD(hx,x); +        GET_HIGH_WORD(hy,y); +        SET_HIGH_WORD(x,(hx&0x7fffffff)|(hy&0x80000000)); +        return x; +} diff --git a/src/math/s_copysignf.c b/src/math/s_copysignf.c new file mode 100644 index 00000000..d650e8e5 --- /dev/null +++ b/src/math/s_copysignf.c @@ -0,0 +1,33 @@ +/* s_copysignf.c -- float version of s_copysign.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * copysignf(float x, float y) + * copysignf(x,y) returns a value with the magnitude of x and + * with the sign bit of y. + */ + +#include <math.h> +#include "math_private.h" + +float +copysignf(float x, float y) +{ +        uint32_t ix,iy; +        GET_FLOAT_WORD(ix,x); +        GET_FLOAT_WORD(iy,y); +        SET_FLOAT_WORD(x,(ix&0x7fffffff)|(iy&0x80000000)); +        return x; +} diff --git a/src/math/s_cos.c b/src/math/s_cos.c new file mode 100644 index 00000000..1893ab13 --- /dev/null +++ b/src/math/s_cos.c @@ -0,0 +1,74 @@ +/* @(#)s_cos.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* cos(x) + * Return cosine function of x. + * + * kernel function: + *      __kernel_sin            ... sine function on [-pi/4,pi/4] + *      __kernel_cos            ... cosine function on [-pi/4,pi/4] + *      __ieee754_rem_pio2      ... argument reduction routine + * + * Method. + *      Let S,C and T denote the sin, cos and tan respectively on + *      [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + *      in [-pi/4 , +pi/4], and let n = k mod 4. + *      We have + * + *          n        sin(x)      cos(x)        tan(x) + *     ---------------------------------------------------------- + *          0          S           C             T + *          1          C          -S            -1/T + *          2         -S          -C             T + *          3         -C           S            -1/T + *     ---------------------------------------------------------- + * + * Special cases: + *      Let trig be any of sin, cos, or tan. + *      trig(+-INF)  is NaN, with signals; + *      trig(NaN)    is that NaN; + * + * Accuracy: + *      TRIG(x) returns trig(x) nearly rounded + */ + +#include <math.h> +#include "math_private.h" + +double +cos(double x) +{ +        double y[2],z=0.0; +        int32_t n, ix; + +    /* High word of x. */ +        GET_HIGH_WORD(ix,x); + +    /* |x| ~< pi/4 */ +        ix &= 0x7fffffff; +        if(ix <= 0x3fe921fb) return __kernel_cos(x,z); + +    /* cos(Inf or NaN) is NaN */ +        else if (ix>=0x7ff00000) return x-x; + +    /* argument reduction needed */ +        else { +            n = __ieee754_rem_pio2(x,y); +            switch(n&3) { +                case 0: return  __kernel_cos(y[0],y[1]); +                case 1: return -__kernel_sin(y[0],y[1],1); +                case 2: return -__kernel_cos(y[0],y[1]); +                default: +                        return  __kernel_sin(y[0],y[1],1); +            } +        } +} diff --git a/src/math/s_cosf.c b/src/math/s_cosf.c new file mode 100644 index 00000000..14b8e98b --- /dev/null +++ b/src/math/s_cosf.c @@ -0,0 +1,47 @@ +/* s_cosf.c -- float version of s_cos.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float one=1.0; + +float +cosf(float x) +{ +        float y[2],z=0.0; +        int32_t n,ix; + +        GET_FLOAT_WORD(ix,x); + +    /* |x| ~< pi/4 */ +        ix &= 0x7fffffff; +        if(ix <= 0x3f490fd8) return __kernel_cosf(x,z); + +    /* cos(Inf or NaN) is NaN */ +        else if (ix>=0x7f800000) return x-x; + +    /* argument reduction needed */ +        else { +            n = __ieee754_rem_pio2f(x,y); +            switch(n&3) { +                case 0: return  __kernel_cosf(y[0],y[1]); +                case 1: return -__kernel_sinf(y[0],y[1],1); +                case 2: return -__kernel_cosf(y[0],y[1]); +                default: +                        return  __kernel_sinf(y[0],y[1],1); +            } +        } +} diff --git a/src/math/s_erf.c b/src/math/s_erf.c new file mode 100644 index 00000000..e321feea --- /dev/null +++ b/src/math/s_erf.c @@ -0,0 +1,298 @@ +/* @(#)s_erf.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* double erf(double x) + * double erfc(double x) + *                           x + *                    2      |\ + *     erf(x)  =  ---------  | exp(-t*t)dt + *                 sqrt(pi) \| + *                           0 + * + *     erfc(x) =  1-erf(x) + *  Note that + *              erf(-x) = -erf(x) + *              erfc(-x) = 2 - erfc(x) + * + * Method: + *      1. For |x| in [0, 0.84375] + *          erf(x)  = x + x*R(x^2) + *          erfc(x) = 1 - erf(x)           if x in [-.84375,0.25] + *                  = 0.5 + ((0.5-x)-x*R)  if x in [0.25,0.84375] + *         where R = P/Q where P is an odd poly of degree 8 and + *         Q is an odd poly of degree 10. + *                                               -57.90 + *                      | R - (erf(x)-x)/x | <= 2 + * + * + *         Remark. The formula is derived by noting + *          erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....) + *         and that + *          2/sqrt(pi) = 1.128379167095512573896158903121545171688 + *         is close to one. The interval is chosen because the fix + *         point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is + *         near 0.6174), and by some experiment, 0.84375 is chosen to + *         guarantee the error is less than one ulp for erf. + * + *      2. For |x| in [0.84375,1.25], let s = |x| - 1, and + *         c = 0.84506291151 rounded to single (24 bits) + *              erf(x)  = sign(x) * (c  + P1(s)/Q1(s)) + *              erfc(x) = (1-c)  - P1(s)/Q1(s) if x > 0 + *                        1+(c+P1(s)/Q1(s))    if x < 0 + *              |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 + *         Remark: here we use the taylor series expansion at x=1. + *              erf(1+s) = erf(1) + s*Poly(s) + *                       = 0.845.. + P1(s)/Q1(s) + *         That is, we use rational approximation to approximate + *                      erf(1+s) - (c = (single)0.84506291151) + *         Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] + *         where + *              P1(s) = degree 6 poly in s + *              Q1(s) = degree 6 poly in s + * + *      3. For x in [1.25,1/0.35(~2.857143)], + *              erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) + *              erf(x)  = 1 - erfc(x) + *         where + *              R1(z) = degree 7 poly in z, (z=1/x^2) + *              S1(z) = degree 8 poly in z + * + *      4. For x in [1/0.35,28] + *              erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 + *                      = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0 + *                      = 2.0 - tiny            (if x <= -6) + *              erf(x)  = sign(x)*(1.0 - erfc(x)) if x < 6, else + *              erf(x)  = sign(x)*(1.0 - tiny) + *         where + *              R2(z) = degree 6 poly in z, (z=1/x^2) + *              S2(z) = degree 7 poly in z + * + *      Note1: + *         To compute exp(-x*x-0.5625+R/S), let s be a single + *         precision number and s := x; then + *              -x*x = -s*s + (s-x)*(s+x) + *              exp(-x*x-0.5626+R/S) = + *                      exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S); + *      Note2: + *         Here 4 and 5 make use of the asymptotic series + *                        exp(-x*x) + *              erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) ) + *                        x*sqrt(pi) + *         We use rational approximation to approximate + *              g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625 + *         Here is the error bound for R1/S1 and R2/S2 + *              |R1/S1 - f(x)|  < 2**(-62.57) + *              |R2/S2 - f(x)|  < 2**(-61.52) + * + *      5. For inf > x >= 28 + *              erf(x)  = sign(x) *(1 - tiny)  (raise inexact) + *              erfc(x) = tiny*tiny (raise underflow) if x > 0 + *                      = 2 - tiny if x<0 + * + *      7. Special case: + *              erf(0)  = 0, erf(inf)  = 1, erf(-inf) = -1, + *              erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, + *              erfc/erf(NaN) is NaN + */ + + +#include <math.h> +#include "math_private.h" + +static const double +tiny        = 1e-300, +half=  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */ +two =  2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */ +        /* c = (float)0.84506291151 */ +erx =  8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */ +/* + * Coefficients for approximation to  erf on [0,0.84375] + */ +efx =  1.28379167095512586316e-01, /* 0x3FC06EBA, 0x8214DB69 */ +efx8=  1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */ +pp0  =  1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */ +pp1  = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */ +pp2  = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */ +pp3  = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */ +pp4  = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */ +qq1  =  3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */ +qq2  =  6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */ +qq3  =  5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */ +qq4  =  1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */ +qq5  = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */ +/* + * Coefficients for approximation to  erf  in [0.84375,1.25] + */ +pa0  = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */ +pa1  =  4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */ +pa2  = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */ +pa3  =  3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */ +pa4  = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */ +pa5  =  3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */ +pa6  = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */ +qa1  =  1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */ +qa2  =  5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */ +qa3  =  7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */ +qa4  =  1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */ +qa5  =  1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */ +qa6  =  1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */ +/* + * Coefficients for approximation to  erfc in [1.25,1/0.35] + */ +ra0  = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */ +ra1  = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */ +ra2  = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */ +ra3  = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */ +ra4  = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */ +ra5  = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */ +ra6  = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */ +ra7  = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */ +sa1  =  1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */ +sa2  =  1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */ +sa3  =  4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */ +sa4  =  6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */ +sa5  =  4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */ +sa6  =  1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */ +sa7  =  6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */ +sa8  = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */ +/* + * Coefficients for approximation to  erfc in [1/.35,28] + */ +rb0  = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */ +rb1  = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */ +rb2  = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */ +rb3  = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */ +rb4  = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */ +rb5  = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */ +rb6  = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */ +sb1  =  3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */ +sb2  =  3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */ +sb3  =  1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */ +sb4  =  3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */ +sb5  =  2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */ +sb6  =  4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */ +sb7  = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */ + +double +erf(double x) +{ +        int32_t hx,ix,i; +        double R,S,P,Q,s,y,z,r; +        GET_HIGH_WORD(hx,x); +        ix = hx&0x7fffffff; +        if(ix>=0x7ff00000) {            /* erf(nan)=nan */ +            i = ((uint32_t)hx>>31)<<1; +            return (double)(1-i)+one/x; /* erf(+-inf)=+-1 */ +        } + +        if(ix < 0x3feb0000) {           /* |x|<0.84375 */ +            if(ix < 0x3e300000) {       /* |x|<2**-28 */ +                if (ix < 0x00800000) +                    return 0.125*(8.0*x+efx8*x);  /*avoid underflow */ +                return x + efx*x; +            } +            z = x*x; +            r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); +            s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); +            y = r/s; +            return x + x*y; +        } +        if(ix < 0x3ff40000) {           /* 0.84375 <= |x| < 1.25 */ +            s = fabs(x)-one; +            P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); +            Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); +            if(hx>=0) return erx + P/Q; else return -erx - P/Q; +        } +        if (ix >= 0x40180000) {         /* inf>|x|>=6 */ +            if(hx>=0) return one-tiny; else return tiny-one; +        } +        x = fabs(x); +        s = one/(x*x); +        if(ix< 0x4006DB6E) {    /* |x| < 1/0.35 */ +            R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( +                                ra5+s*(ra6+s*ra7)))))); +            S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( +                                sa5+s*(sa6+s*(sa7+s*sa8))))))); +        } else {        /* |x| >= 1/0.35 */ +            R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( +                                rb5+s*rb6))))); +            S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( +                                sb5+s*(sb6+s*sb7)))))); +        } +        z  = x; +        SET_LOW_WORD(z,0); +        r  =  exp(-z*z-0.5625)*exp((z-x)*(z+x)+R/S); +        if(hx>=0) return one-r/x; else return  r/x-one; +} + +double +erfc(double x) +{ +        int32_t hx,ix; +        double R,S,P,Q,s,y,z,r; +        GET_HIGH_WORD(hx,x); +        ix = hx&0x7fffffff; +        if(ix>=0x7ff00000) {                    /* erfc(nan)=nan */ +                                                /* erfc(+-inf)=0,2 */ +            return (double)(((uint32_t)hx>>31)<<1)+one/x; +        } + +        if(ix < 0x3feb0000) {           /* |x|<0.84375 */ +            if(ix < 0x3c700000)         /* |x|<2**-56 */ +                return one-x; +            z = x*x; +            r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); +            s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); +            y = r/s; +            if(hx < 0x3fd00000) {       /* x<1/4 */ +                return one-(x+x*y); +            } else { +                r = x*y; +                r += (x-half); +                return half - r ; +            } +        } +        if(ix < 0x3ff40000) {           /* 0.84375 <= |x| < 1.25 */ +            s = fabs(x)-one; +            P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); +            Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); +            if(hx>=0) { +                z  = one-erx; return z - P/Q; +            } else { +                z = erx+P/Q; return one+z; +            } +        } +        if (ix < 0x403c0000) {          /* |x|<28 */ +            x = fabs(x); +            s = one/(x*x); +            if(ix< 0x4006DB6D) {        /* |x| < 1/.35 ~ 2.857143*/ +                R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( +                                ra5+s*(ra6+s*ra7)))))); +                S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( +                                sa5+s*(sa6+s*(sa7+s*sa8))))))); +            } else {                    /* |x| >= 1/.35 ~ 2.857143 */ +                if(hx<0&&ix>=0x40180000) return two-tiny;/* x < -6 */ +                R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( +                                rb5+s*rb6))))); +                S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( +                                sb5+s*(sb6+s*sb7)))))); +            } +            z  = x; +            SET_LOW_WORD(z,0); +            r  =  exp(-z*z-0.5625)* +                        exp((z-x)*(z+x)+R/S); +            if(hx>0) return r/x; else return two-r/x; +        } else { +            if(hx>0) return tiny*tiny; else return two-tiny; +        } +} diff --git a/src/math/s_erff.c b/src/math/s_erff.c new file mode 100644 index 00000000..28e2f7b3 --- /dev/null +++ b/src/math/s_erff.c @@ -0,0 +1,207 @@ +/* s_erff.c -- float version of s_erf.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +tiny        = 1e-30, +half=  5.0000000000e-01, /* 0x3F000000 */ +one =  1.0000000000e+00, /* 0x3F800000 */ +two =  2.0000000000e+00, /* 0x40000000 */ +        /* c = (subfloat)0.84506291151 */ +erx =  8.4506291151e-01, /* 0x3f58560b */ +/* + * Coefficients for approximation to  erf on [0,0.84375] + */ +efx =  1.2837916613e-01, /* 0x3e0375d4 */ +efx8=  1.0270333290e+00, /* 0x3f8375d4 */ +pp0  =  1.2837916613e-01, /* 0x3e0375d4 */ +pp1  = -3.2504209876e-01, /* 0xbea66beb */ +pp2  = -2.8481749818e-02, /* 0xbce9528f */ +pp3  = -5.7702702470e-03, /* 0xbbbd1489 */ +pp4  = -2.3763017452e-05, /* 0xb7c756b1 */ +qq1  =  3.9791721106e-01, /* 0x3ecbbbce */ +qq2  =  6.5022252500e-02, /* 0x3d852a63 */ +qq3  =  5.0813062117e-03, /* 0x3ba68116 */ +qq4  =  1.3249473704e-04, /* 0x390aee49 */ +qq5  = -3.9602282413e-06, /* 0xb684e21a */ +/* + * Coefficients for approximation to  erf  in [0.84375,1.25] + */ +pa0  = -2.3621185683e-03, /* 0xbb1acdc6 */ +pa1  =  4.1485610604e-01, /* 0x3ed46805 */ +pa2  = -3.7220788002e-01, /* 0xbebe9208 */ +pa3  =  3.1834661961e-01, /* 0x3ea2fe54 */ +pa4  = -1.1089469492e-01, /* 0xbde31cc2 */ +pa5  =  3.5478305072e-02, /* 0x3d1151b3 */ +pa6  = -2.1663755178e-03, /* 0xbb0df9c0 */ +qa1  =  1.0642088205e-01, /* 0x3dd9f331 */ +qa2  =  5.4039794207e-01, /* 0x3f0a5785 */ +qa3  =  7.1828655899e-02, /* 0x3d931ae7 */ +qa4  =  1.2617121637e-01, /* 0x3e013307 */ +qa5  =  1.3637083583e-02, /* 0x3c5f6e13 */ +qa6  =  1.1984500103e-02, /* 0x3c445aa3 */ +/* + * Coefficients for approximation to  erfc in [1.25,1/0.35] + */ +ra0  = -9.8649440333e-03, /* 0xbc21a093 */ +ra1  = -6.9385856390e-01, /* 0xbf31a0b7 */ +ra2  = -1.0558626175e+01, /* 0xc128f022 */ +ra3  = -6.2375331879e+01, /* 0xc2798057 */ +ra4  = -1.6239666748e+02, /* 0xc322658c */ +ra5  = -1.8460508728e+02, /* 0xc3389ae7 */ +ra6  = -8.1287437439e+01, /* 0xc2a2932b */ +ra7  = -9.8143291473e+00, /* 0xc11d077e */ +sa1  =  1.9651271820e+01, /* 0x419d35ce */ +sa2  =  1.3765776062e+02, /* 0x4309a863 */ +sa3  =  4.3456588745e+02, /* 0x43d9486f */ +sa4  =  6.4538726807e+02, /* 0x442158c9 */ +sa5  =  4.2900814819e+02, /* 0x43d6810b */ +sa6  =  1.0863500214e+02, /* 0x42d9451f */ +sa7  =  6.5702495575e+00, /* 0x40d23f7c */ +sa8  = -6.0424413532e-02, /* 0xbd777f97 */ +/* + * Coefficients for approximation to  erfc in [1/.35,28] + */ +rb0  = -9.8649431020e-03, /* 0xbc21a092 */ +rb1  = -7.9928326607e-01, /* 0xbf4c9dd4 */ +rb2  = -1.7757955551e+01, /* 0xc18e104b */ +rb3  = -1.6063638306e+02, /* 0xc320a2ea */ +rb4  = -6.3756646729e+02, /* 0xc41f6441 */ +rb5  = -1.0250950928e+03, /* 0xc480230b */ +rb6  = -4.8351919556e+02, /* 0xc3f1c275 */ +sb1  =  3.0338060379e+01, /* 0x41f2b459 */ +sb2  =  3.2579251099e+02, /* 0x43a2e571 */ +sb3  =  1.5367296143e+03, /* 0x44c01759 */ +sb4  =  3.1998581543e+03, /* 0x4547fdbb */ +sb5  =  2.5530502930e+03, /* 0x451f90ce */ +sb6  =  4.7452853394e+02, /* 0x43ed43a7 */ +sb7  = -2.2440952301e+01; /* 0xc1b38712 */ + +float +erff(float x) +{ +        int32_t hx,ix,i; +        float R,S,P,Q,s,y,z,r; +        GET_FLOAT_WORD(hx,x); +        ix = hx&0x7fffffff; +        if(ix>=0x7f800000) {            /* erf(nan)=nan */ +            i = ((uint32_t)hx>>31)<<1; +            return (float)(1-i)+one/x;  /* erf(+-inf)=+-1 */ +        } + +        if(ix < 0x3f580000) {           /* |x|<0.84375 */ +            if(ix < 0x31800000) {       /* |x|<2**-28 */ +                if (ix < 0x04000000) +                    /*avoid underflow */ +                    return (float)0.125*((float)8.0*x+efx8*x); +                return x + efx*x; +            } +            z = x*x; +            r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); +            s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); +            y = r/s; +            return x + x*y; +        } +        if(ix < 0x3fa00000) {           /* 0.84375 <= |x| < 1.25 */ +            s = fabsf(x)-one; +            P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); +            Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); +            if(hx>=0) return erx + P/Q; else return -erx - P/Q; +        } +        if (ix >= 0x40c00000) {         /* inf>|x|>=6 */ +            if(hx>=0) return one-tiny; else return tiny-one; +        } +        x = fabsf(x); +        s = one/(x*x); +        if(ix< 0x4036DB6E) {    /* |x| < 1/0.35 */ +            R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( +                                ra5+s*(ra6+s*ra7)))))); +            S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( +                                sa5+s*(sa6+s*(sa7+s*sa8))))))); +        } else {        /* |x| >= 1/0.35 */ +            R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( +                                rb5+s*rb6))))); +            S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( +                                sb5+s*(sb6+s*sb7)))))); +        } +        GET_FLOAT_WORD(ix,x); +        SET_FLOAT_WORD(z,ix&0xfffff000); +        r  =  expf(-z*z-(float)0.5625)*expf((z-x)*(z+x)+R/S); +        if(hx>=0) return one-r/x; else return  r/x-one; +} + +float +erfcf(float x) +{ +        int32_t hx,ix; +        float R,S,P,Q,s,y,z,r; +        GET_FLOAT_WORD(hx,x); +        ix = hx&0x7fffffff; +        if(ix>=0x7f800000) {                    /* erfc(nan)=nan */ +                                                /* erfc(+-inf)=0,2 */ +            return (float)(((uint32_t)hx>>31)<<1)+one/x; +        } + +        if(ix < 0x3f580000) {           /* |x|<0.84375 */ +            if(ix < 0x23800000)         /* |x|<2**-56 */ +                return one-x; +            z = x*x; +            r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4))); +            s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))); +            y = r/s; +            if(hx < 0x3e800000) {       /* x<1/4 */ +                return one-(x+x*y); +            } else { +                r = x*y; +                r += (x-half); +                return half - r ; +            } +        } +        if(ix < 0x3fa00000) {           /* 0.84375 <= |x| < 1.25 */ +            s = fabsf(x)-one; +            P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))); +            Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))); +            if(hx>=0) { +                z  = one-erx; return z - P/Q; +            } else { +                z = erx+P/Q; return one+z; +            } +        } +        if (ix < 0x41e00000) {          /* |x|<28 */ +            x = fabsf(x); +            s = one/(x*x); +            if(ix< 0x4036DB6D) {        /* |x| < 1/.35 ~ 2.857143*/ +                R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*( +                                ra5+s*(ra6+s*ra7)))))); +                S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*( +                                sa5+s*(sa6+s*(sa7+s*sa8))))))); +            } else {                    /* |x| >= 1/.35 ~ 2.857143 */ +                if(hx<0&&ix>=0x40c00000) return two-tiny;/* x < -6 */ +                R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*( +                                rb5+s*rb6))))); +                S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*( +                                sb5+s*(sb6+s*sb7)))))); +            } +            GET_FLOAT_WORD(ix,x); +            SET_FLOAT_WORD(z,ix&0xfffff000); +            r  =  expf(-z*z-(float)0.5625)* +                        expf((z-x)*(z+x)+R/S); +            if(hx>0) return r/x; else return two-r/x; +        } else { +            if(hx>0) return tiny*tiny; else return two-tiny; +        } +} diff --git a/src/math/s_expm1.c b/src/math/s_expm1.c new file mode 100644 index 00000000..6f1f6675 --- /dev/null +++ b/src/math/s_expm1.c @@ -0,0 +1,217 @@ +/* @(#)s_expm1.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* expm1(x) + * Returns exp(x)-1, the exponential of x minus 1. + * + * Method + *   1. Argument reduction: + *      Given x, find r and integer k such that + * + *               x = k*ln2 + r,  |r| <= 0.5*ln2 ~ 0.34658 + * + *      Here a correction term c will be computed to compensate + *      the error in r when rounded to a floating-point number. + * + *   2. Approximating expm1(r) by a special rational function on + *      the interval [0,0.34658]: + *      Since + *          r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ... + *      we define R1(r*r) by + *          r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r) + *      That is, + *          R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) + *                   = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) + *                   = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... + *      We use a special Reme algorithm on [0,0.347] to generate + *      a polynomial of degree 5 in r*r to approximate R1. The + *      maximum error of this polynomial approximation is bounded + *      by 2**-61. In other words, + *          R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 + *      where   Q1  =  -1.6666666666666567384E-2, + *              Q2  =   3.9682539681370365873E-4, + *              Q3  =  -9.9206344733435987357E-6, + *              Q4  =   2.5051361420808517002E-7, + *              Q5  =  -6.2843505682382617102E-9; + *      (where z=r*r, and the values of Q1 to Q5 are listed below) + *      with error bounded by + *          |                  5           |     -61 + *          | 1.0+Q1*z+...+Q5*z   -  R1(z) | <= 2 + *          |                              | + * + *      expm1(r) = exp(r)-1 is then computed by the following + *      specific way which minimize the accumulation rounding error: + *                             2     3 + *                            r     r    [ 3 - (R1 + R1*r/2)  ] + *            expm1(r) = r + --- + --- * [--------------------] + *                            2     2    [ 6 - r*(3 - R1*r/2) ] + * + *      To compensate the error in the argument reduction, we use + *              expm1(r+c) = expm1(r) + c + expm1(r)*c + *                         ~ expm1(r) + c + r*c + *      Thus c+r*c will be added in as the correction terms for + *      expm1(r+c). Now rearrange the term to avoid optimization + *      screw up: + *                      (      2                                    2 ) + *                      ({  ( r    [ R1 -  (3 - R1*r/2) ]  )  }    r  ) + *       expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) + *                      ({  ( 2    [ 6 - r*(3 - R1*r/2) ]  )  }    2  ) + *                      (                                             ) + * + *                 = r - E + *   3. Scale back to obtain expm1(x): + *      From step 1, we have + *         expm1(x) = either 2^k*[expm1(r)+1] - 1 + *                  = or     2^k*[expm1(r) + (1-2^-k)] + *   4. Implementation notes: + *      (A). To save one multiplication, we scale the coefficient Qi + *           to Qi*2^i, and replace z by (x^2)/2. + *      (B). To achieve maximum accuracy, we compute expm1(x) by + *        (i)   if x < -56*ln2, return -1.0, (raise inexact if x!=inf) + *        (ii)  if k=0, return r-E + *        (iii) if k=-1, return 0.5*(r-E)-0.5 + *        (iv)  if k=1 if r < -0.25, return 2*((r+0.5)- E) + *                     else          return  1.0+2.0*(r-E); + *        (v)   if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) + *        (vi)  if k <= 20, return 2^k((1-2^-k)-(E-r)), else + *        (vii) return 2^k(1-((E+2^-k)-r)) + * + * Special cases: + *      expm1(INF) is INF, expm1(NaN) is NaN; + *      expm1(-INF) is -1, and + *      for finite argument, only expm1(0)=0 is exact. + * + * Accuracy: + *      according to an error analysis, the error is always less than + *      1 ulp (unit in the last place). + * + * Misc. info. + *      For IEEE double + *          if x >  7.09782712893383973096e+02 then expm1(x) overflow + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include <math.h> +#include "math_private.h" + +static const double +one             = 1.0, +huge            = 1.0e+300, +tiny            = 1.0e-300, +o_threshold     = 7.09782712893383973096e+02,/* 0x40862E42, 0xFEFA39EF */ +ln2_hi          = 6.93147180369123816490e-01,/* 0x3fe62e42, 0xfee00000 */ +ln2_lo          = 1.90821492927058770002e-10,/* 0x3dea39ef, 0x35793c76 */ +invln2          = 1.44269504088896338700e+00,/* 0x3ff71547, 0x652b82fe */ +        /* scaled coefficients related to expm1 */ +Q1  =  -3.33333333333331316428e-02, /* BFA11111 111110F4 */ +Q2  =   1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */ +Q3  =  -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */ +Q4  =   4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */ +Q5  =  -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +double +expm1(double x) +{ +        double y,hi,lo,c=0.0,t,e,hxs,hfx,r1; +        int32_t k,xsb; +        uint32_t hx; + +        GET_HIGH_WORD(hx,x); +        xsb = hx&0x80000000;            /* sign bit of x */ +        if(xsb==0) y=x; else y= -x;     /* y = |x| */ +        hx &= 0x7fffffff;               /* high word of |x| */ + +    /* filter out huge and non-finite argument */ +        if(hx >= 0x4043687A) {                  /* if |x|>=56*ln2 */ +            if(hx >= 0x40862E42) {              /* if |x|>=709.78... */ +                if(hx>=0x7ff00000) { +                    uint32_t low; +                    GET_LOW_WORD(low,x); +                    if(((hx&0xfffff)|low)!=0) +                         return x+x;     /* NaN */ +                    else return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */ +                } +                if(x > o_threshold) return huge*huge; /* overflow */ +            } +            if(xsb!=0) { /* x < -56*ln2, return -1.0 with inexact */ +                if(x+tiny<0.0)          /* raise inexact */ +                return tiny-one;        /* return -1 */ +            } +        } + +    /* argument reduction */ +        if(hx > 0x3fd62e42) {           /* if  |x| > 0.5 ln2 */ +            if(hx < 0x3FF0A2B2) {       /* and |x| < 1.5 ln2 */ +                if(xsb==0) +                    {hi = x - ln2_hi; lo =  ln2_lo;  k =  1;} +                else +                    {hi = x + ln2_hi; lo = -ln2_lo;  k = -1;} +            } else { +                k  = invln2*x+((xsb==0)?0.5:-0.5); +                t  = k; +                hi = x - t*ln2_hi;      /* t*ln2_hi is exact here */ +                lo = t*ln2_lo; +            } +            x  = hi - lo; +            c  = (hi-x)-lo; +        } +        else if(hx < 0x3c900000) {      /* when |x|<2**-54, return x */ +            t = huge+x; /* return x with inexact flags when x!=0 */ +            return x - (t-(huge+x)); +        } +        else k = 0; + +    /* x is now in primary range */ +        hfx = 0.5*x; +        hxs = x*hfx; +        r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5)))); +        t  = 3.0-r1*hfx; +        e  = hxs*((r1-t)/(6.0 - x*t)); +        if(k==0) return x - (x*e-hxs);          /* c is 0 */ +        else { +            e  = (x*(e-c)-c); +            e -= hxs; +            if(k== -1) return 0.5*(x-e)-0.5; +            if(k==1) { +                if(x < -0.25) return -2.0*(e-(x+0.5)); +                else          return  one+2.0*(x-e); +            } +            if (k <= -2 || k>56) {   /* suffice to return exp(x)-1 */ +                uint32_t high; +                y = one-(e-x); +                GET_HIGH_WORD(high,y); +                SET_HIGH_WORD(y,high+(k<<20));  /* add k to y's exponent */ +                return y-one; +            } +            t = one; +            if(k<20) { +                uint32_t high; +                SET_HIGH_WORD(t,0x3ff00000 - (0x200000>>k));  /* t=1-2^-k */ +                y = t-(e-x); +                GET_HIGH_WORD(high,y); +                SET_HIGH_WORD(y,high+(k<<20));  /* add k to y's exponent */ +           } else { +                uint32_t high; +                SET_HIGH_WORD(t,((0x3ff-k)<<20));       /* 2^-k */ +                y = x-(e+t); +                y += one; +                GET_HIGH_WORD(high,y); +                SET_HIGH_WORD(y,high+(k<<20));  /* add k to y's exponent */ +            } +        } +        return y; +} diff --git a/src/math/s_expm1f.c b/src/math/s_expm1f.c new file mode 100644 index 00000000..b22cf0f9 --- /dev/null +++ b/src/math/s_expm1f.c @@ -0,0 +1,122 @@ +/* s_expm1f.c -- float version of s_expm1.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +one             = 1.0, +huge            = 1.0e+30, +tiny            = 1.0e-30, +o_threshold     = 8.8721679688e+01,/* 0x42b17180 */ +ln2_hi          = 6.9313812256e-01,/* 0x3f317180 */ +ln2_lo          = 9.0580006145e-06,/* 0x3717f7d1 */ +invln2          = 1.4426950216e+00,/* 0x3fb8aa3b */ +        /* scaled coefficients related to expm1 */ +Q1  =  -3.3333335072e-02, /* 0xbd088889 */ +Q2  =   1.5873016091e-03, /* 0x3ad00d01 */ +Q3  =  -7.9365076090e-05, /* 0xb8a670cd */ +Q4  =   4.0082177293e-06, /* 0x36867e54 */ +Q5  =  -2.0109921195e-07; /* 0xb457edbb */ + +float +expm1f(float x) +{ +        float y,hi,lo,c=0.0,t,e,hxs,hfx,r1; +        int32_t k,xsb; +        uint32_t hx; + +        GET_FLOAT_WORD(hx,x); +        xsb = hx&0x80000000;            /* sign bit of x */ +        if(xsb==0) y=x; else y= -x;     /* y = |x| */ +        hx &= 0x7fffffff;               /* high word of |x| */ + +    /* filter out huge and non-finite argument */ +        if(hx >= 0x4195b844) {                  /* if |x|>=27*ln2 */ +            if(hx >= 0x42b17218) {              /* if |x|>=88.721... */ +                if(hx>0x7f800000) +                    return x+x;          /* NaN */ +                if(hx==0x7f800000) +                    return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */ +                if(x > o_threshold) return huge*huge; /* overflow */ +            } +            if(xsb!=0) { /* x < -27*ln2, return -1.0 with inexact */ +                if(x+tiny<(float)0.0)   /* raise inexact */ +                return tiny-one;        /* return -1 */ +            } +        } + +    /* argument reduction */ +        if(hx > 0x3eb17218) {           /* if  |x| > 0.5 ln2 */ +            if(hx < 0x3F851592) {       /* and |x| < 1.5 ln2 */ +                if(xsb==0) +                    {hi = x - ln2_hi; lo =  ln2_lo;  k =  1;} +                else +                    {hi = x + ln2_hi; lo = -ln2_lo;  k = -1;} +            } else { +                k  = invln2*x+((xsb==0)?(float)0.5:(float)-0.5); +                t  = k; +                hi = x - t*ln2_hi;      /* t*ln2_hi is exact here */ +                lo = t*ln2_lo; +            } +            x  = hi - lo; +            c  = (hi-x)-lo; +        } +        else if(hx < 0x33000000) {      /* when |x|<2**-25, return x */ +            t = huge+x; /* return x with inexact flags when x!=0 */ +            return x - (t-(huge+x)); +        } +        else k = 0; + +    /* x is now in primary range */ +        hfx = (float)0.5*x; +        hxs = x*hfx; +        r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5)))); +        t  = (float)3.0-r1*hfx; +        e  = hxs*((r1-t)/((float)6.0 - x*t)); +        if(k==0) return x - (x*e-hxs);          /* c is 0 */ +        else { +            e  = (x*(e-c)-c); +            e -= hxs; +            if(k== -1) return (float)0.5*(x-e)-(float)0.5; +            if(k==1) { +                if(x < (float)-0.25) return -(float)2.0*(e-(x+(float)0.5)); +                else          return  one+(float)2.0*(x-e); +            } +            if (k <= -2 || k>56) {   /* suffice to return exp(x)-1 */ +                int32_t i; +                y = one-(e-x); +                GET_FLOAT_WORD(i,y); +                SET_FLOAT_WORD(y,i+(k<<23));    /* add k to y's exponent */ +                return y-one; +            } +            t = one; +            if(k<23) { +                int32_t i; +                SET_FLOAT_WORD(t,0x3f800000 - (0x1000000>>k)); /* t=1-2^-k */ +                y = t-(e-x); +                GET_FLOAT_WORD(i,y); +                SET_FLOAT_WORD(y,i+(k<<23));    /* add k to y's exponent */ +           } else { +                int32_t i; +                SET_FLOAT_WORD(t,((0x7f-k)<<23));       /* 2^-k */ +                y = x-(e+t); +                y += one; +                GET_FLOAT_WORD(i,y); +                SET_FLOAT_WORD(y,i+(k<<23));    /* add k to y's exponent */ +            } +        } +        return y; +} diff --git a/src/math/s_fabs.c b/src/math/s_fabs.c new file mode 100644 index 00000000..74433250 --- /dev/null +++ b/src/math/s_fabs.c @@ -0,0 +1,27 @@ +/* @(#)s_fabs.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * fabs(x) returns the absolute value of x. + */ + +#include <math.h> +#include "math_private.h" + +double +fabs(double x) +{ +        uint32_t high; +        GET_HIGH_WORD(high,x); +        SET_HIGH_WORD(x,high&0x7fffffff); +        return x; +} diff --git a/src/math/s_fabsf.c b/src/math/s_fabsf.c new file mode 100644 index 00000000..655d57d8 --- /dev/null +++ b/src/math/s_fabsf.c @@ -0,0 +1,30 @@ +/* s_fabsf.c -- float version of s_fabs.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * fabsf(x) returns the absolute value of x. + */ + +#include <math.h> +#include "math_private.h" + +float +fabsf(float x) +{ +        uint32_t ix; +        GET_FLOAT_WORD(ix,x); +        SET_FLOAT_WORD(x,ix&0x7fffffff); +        return x; +} diff --git a/src/math/s_floor.c b/src/math/s_floor.c new file mode 100644 index 00000000..273cf6f4 --- /dev/null +++ b/src/math/s_floor.c @@ -0,0 +1,69 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * floor(x) + * Return x rounded toward -inf to integral value + * Method: + *      Bit twiddling. + * Exception: + *      Inexact flag raised if x not equal to floor(x). + */ + +#include <math.h> +#include "math_private.h" + +static const double huge = 1.0e300; + +double +floor(double x) +{ +        int32_t i0,i1,j0; +        uint32_t i,j; +        EXTRACT_WORDS(i0,i1,x); +        j0 = ((i0>>20)&0x7ff)-0x3ff; +        if(j0<20) { +            if(j0<0) {  /* raise inexact if x != 0 */ +                if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ +                    if(i0>=0) {i0=i1=0;} +                    else if(((i0&0x7fffffff)|i1)!=0) +                        { i0=0xbff00000;i1=0;} +                } +            } else { +                i = (0x000fffff)>>j0; +                if(((i0&i)|i1)==0) return x; /* x is integral */ +                if(huge+x>0.0) {        /* raise inexact flag */ +                    if(i0<0) i0 += (0x00100000)>>j0; +                    i0 &= (~i); i1=0; +                } +            } +        } else if (j0>51) { +            if(j0==0x400) return x+x;   /* inf or NaN */ +            else return x;              /* x is integral */ +        } else { +            i = ((uint32_t)(0xffffffff))>>(j0-20); +            if((i1&i)==0) return x;     /* x is integral */ +            if(huge+x>0.0) {            /* raise inexact flag */ +                if(i0<0) { +                    if(j0==20) i0+=1; +                    else { +                        j = i1+(1<<(52-j0)); +                        if(j<i1) i0 +=1 ;       /* got a carry */ +                        i1=j; +                    } +                } +                i1 &= (~i); +            } +        } +        INSERT_WORDS(x,i0,i1); +        return x; +} diff --git a/src/math/s_floorf.c b/src/math/s_floorf.c new file mode 100644 index 00000000..1164decc --- /dev/null +++ b/src/math/s_floorf.c @@ -0,0 +1,58 @@ +/* s_floorf.c -- float version of s_floor.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * floorf(x) + * Return x rounded toward -inf to integral value + * Method: + *      Bit twiddling. + * Exception: + *      Inexact flag raised if x not equal to floorf(x). + */ + +#include <math.h> +#include "math_private.h" + +static const float huge = 1.0e30; + +float +floorf(float x) +{ +        int32_t i0,j0; +        uint32_t i; +        GET_FLOAT_WORD(i0,x); +        j0 = ((i0>>23)&0xff)-0x7f; +        if(j0<23) { +            if(j0<0) {  /* raise inexact if x != 0 */ +                if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */ +                    if(i0>=0) {i0=0;} +                    else if((i0&0x7fffffff)!=0) +                        { i0=0xbf800000;} +                } +            } else { +                i = (0x007fffff)>>j0; +                if((i0&i)==0) return x; /* x is integral */ +                if(huge+x>(float)0.0) { /* raise inexact flag */ +                    if(i0<0) i0 += (0x00800000)>>j0; +                    i0 &= (~i); +                } +            } +        } else { +            if(j0==0x80) return x+x;    /* inf or NaN */ +            else return x;              /* x is integral */ +        } +        SET_FLOAT_WORD(x,i0); +        return x; +} diff --git a/src/math/s_ilogb.c b/src/math/s_ilogb.c new file mode 100644 index 00000000..f1ac498a --- /dev/null +++ b/src/math/s_ilogb.c @@ -0,0 +1,45 @@ +/* @(#)s_ilogb.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* ilogb(double x) + * return the binary exponent of non-zero x + * ilogb(0) = FP_ILOGB0 + * ilogb(NaN) = FP_ILOGBNAN (no signal is raised) + * ilogb(inf) = INT_MAX (no signal is raised) + */ + +#include <limits.h> + +#include <math.h> +#include "math_private.h" + +int ilogb(double x) +{ +        int32_t hx,lx,ix; + +        EXTRACT_WORDS(hx,lx,x); +        hx &= 0x7fffffff; +        if(hx<0x00100000) { +            if((hx|lx)==0) +                return FP_ILOGB0; +            else                        /* subnormal x */ +                if(hx==0) { +                    for (ix = -1043; lx>0; lx<<=1) ix -=1; +                } else { +                    for (ix = -1022,hx<<=11; hx>0; hx<<=1) ix -=1; +                } +            return ix; +        } +        else if (hx<0x7ff00000) return (hx>>20)-1023; +        else if (hx>0x7ff00000 || lx!=0) return FP_ILOGBNAN; +        else return INT_MAX; +} diff --git a/src/math/s_ilogbf.c b/src/math/s_ilogbf.c new file mode 100644 index 00000000..30359fef --- /dev/null +++ b/src/math/s_ilogbf.c @@ -0,0 +1,37 @@ +/* s_ilogbf.c -- float version of s_ilogb.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <limits.h> + +#include <math.h> +#include "math_private.h" + +int ilogbf(float x) +{ +        int32_t hx,ix; + +        GET_FLOAT_WORD(hx,x); +        hx &= 0x7fffffff; +        if(hx<0x00800000) { +            if(hx==0) +                return FP_ILOGB0; +            else                        /* subnormal x */ +                for (ix = -126,hx<<=8; hx>0; hx<<=1) ix -=1; +            return ix; +        } +        else if (hx<0x7f800000) return (hx>>23)-127; +        else if (hx>0x7f800000) return FP_ILOGBNAN; +        else return INT_MAX; +} diff --git a/src/math/s_ldexp.c b/src/math/s_ldexp.c new file mode 100644 index 00000000..f4d1cd6a --- /dev/null +++ b/src/math/s_ldexp.c @@ -0,0 +1,6 @@ +#include <math.h> + +double ldexp(double x, int n) +{ +	return scalbn(x, n); +} diff --git a/src/math/s_ldexpf.c b/src/math/s_ldexpf.c new file mode 100644 index 00000000..3bad5f39 --- /dev/null +++ b/src/math/s_ldexpf.c @@ -0,0 +1,6 @@ +#include <math.h> + +float ldexpf(float x, int n) +{ +	return scalbnf(x, n); +} diff --git a/src/math/s_llrint.c b/src/math/s_llrint.c new file mode 100644 index 00000000..2b1e00d0 --- /dev/null +++ b/src/math/s_llrint.c @@ -0,0 +1,8 @@ +#include <math.h> + +// FIXME: incorrect exception behavior + +long long llrint(double x) +{ +	return rint(x); +} diff --git a/src/math/s_log1p.c b/src/math/s_log1p.c new file mode 100644 index 00000000..886d5ab1 --- /dev/null +++ b/src/math/s_log1p.c @@ -0,0 +1,157 @@ +/* @(#)s_log1p.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* double log1p(double x) + * + * Method : + *   1. Argument Reduction: find k and f such that + *                      1+x = 2^k * (1+f), + *         where  sqrt(2)/2 < 1+f < sqrt(2) . + * + *      Note. If k=0, then f=x is exact. However, if k!=0, then f + *      may not be representable exactly. In that case, a correction + *      term is need. Let u=1+x rounded. Let c = (1+x)-u, then + *      log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), + *      and add back the correction term c/u. + *      (Note: when x > 2**53, one can simply return log(x)) + * + *   2. Approximation of log1p(f). + *      Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + *               = 2s + 2/3 s**3 + 2/5 s**5 + ....., + *               = 2s + s*R + *      We use a special Reme algorithm on [0,0.1716] to generate + *      a polynomial of degree 14 to approximate R The maximum error + *      of this polynomial approximation is bounded by 2**-58.45. In + *      other words, + *                      2      4      6      8      10      12      14 + *          R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s  +Lp6*s  +Lp7*s + *      (the values of Lp1 to Lp7 are listed in the program) + *      and + *          |      2          14          |     -58.45 + *          | Lp1*s +...+Lp7*s    -  R(z) | <= 2 + *          |                             | + *      Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + *      In order to guarantee error in log below 1ulp, we compute log + *      by + *              log1p(f) = f - (hfsq - s*(hfsq+R)). + * + *      3. Finally, log1p(x) = k*ln2 + log1p(f). + *                           = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) + *         Here ln2 is split into two floating point number: + *                      ln2_hi + ln2_lo, + *         where n*ln2_hi is always exact for |n| < 2000. + * + * Special cases: + *      log1p(x) is NaN with signal if x < -1 (including -INF) ; + *      log1p(+INF) is +INF; log1p(-1) is -INF with signal; + *      log1p(NaN) is that NaN with no signal. + * + * Accuracy: + *      according to an error analysis, the error is always less than + *      1 ulp (unit in the last place). + * + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + * + * Note: Assuming log() return accurate answer, the following + *       algorithm can be used to compute log1p(x) to within a few ULP: + * + *              u = 1+x; + *              if(u==1.0) return x ; else + *                         return log(u)*(x/(u-1.0)); + * + *       See HP-15C Advanced Functions Handbook, p.193. + */ + +#include <math.h> +#include "math_private.h" + +static const double +ln2_hi  =  6.93147180369123816490e-01,  /* 3fe62e42 fee00000 */ +ln2_lo  =  1.90821492927058770002e-10,  /* 3dea39ef 35793c76 */ +two54   =  1.80143985094819840000e+16,  /* 43500000 00000000 */ +Lp1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */ +Lp2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */ +Lp3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */ +Lp4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */ +Lp5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */ +Lp6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */ +Lp7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */ + +static const double zero = 0.0; + +double +log1p(double x) +{ +        double hfsq,f=0,c=0,s,z,R,u; +        int32_t k,hx,hu=0,ax; + +        GET_HIGH_WORD(hx,x); +        ax = hx&0x7fffffff; + +        k = 1; +        if (hx < 0x3FDA827A) {                  /* x < 0.41422  */ +            if(ax>=0x3ff00000) {                /* x <= -1.0 */ +                if(x==-1.0) return -two54/zero; /* log1p(-1)=+inf */ +                else return (x-x)/(x-x);        /* log1p(x<-1)=NaN */ +            } +            if(ax<0x3e200000) {                 /* |x| < 2**-29 */ +                if(two54+x>zero                 /* raise inexact */ +                    &&ax<0x3c900000)            /* |x| < 2**-54 */ +                    return x; +                else +                    return x - x*x*0.5; +            } +            if(hx>0||hx<=((int32_t)0xbfd2bec3)) { +                k=0;f=x;hu=1;}  /* -0.2929<x<0.41422 */ +        } +        if (hx >= 0x7ff00000) return x+x; +        if(k!=0) { +            if(hx<0x43400000) { +                u  = 1.0+x; +                GET_HIGH_WORD(hu,u); +                k  = (hu>>20)-1023; +                c  = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */ +                c /= u; +            } else { +                u  = x; +                GET_HIGH_WORD(hu,u); +                k  = (hu>>20)-1023; +                c  = 0; +            } +            hu &= 0x000fffff; +            if(hu<0x6a09e) { +                SET_HIGH_WORD(u,hu|0x3ff00000); /* normalize u */ +            } else { +                k += 1; +                SET_HIGH_WORD(u,hu|0x3fe00000); /* normalize u/2 */ +                hu = (0x00100000-hu)>>2; +            } +            f = u-1.0; +        } +        hfsq=0.5*f*f; +        if(hu==0) {     /* |f| < 2**-20 */ +            if(f==zero) { if(k==0) return zero; +                          else {c += k*ln2_lo; return k*ln2_hi+c;} } +            R = hfsq*(1.0-0.66666666666666666*f); +            if(k==0) return f-R; else +                     return k*ln2_hi-((R-(k*ln2_lo+c))-f); +        } +        s = f/(2.0+f); +        z = s*s; +        R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7)))))); +        if(k==0) return f-(hfsq-s*(hfsq+R)); else +                 return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f); +} diff --git a/src/math/s_log1pf.c b/src/math/s_log1pf.c new file mode 100644 index 00000000..dcdd6bb3 --- /dev/null +++ b/src/math/s_log1pf.c @@ -0,0 +1,96 @@ +/* s_log1pf.c -- float version of s_log1p.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +ln2_hi =   6.9313812256e-01,    /* 0x3f317180 */ +ln2_lo =   9.0580006145e-06,    /* 0x3717f7d1 */ +two25 =    3.355443200e+07,     /* 0x4c000000 */ +Lp1 = 6.6666668653e-01, /* 3F2AAAAB */ +Lp2 = 4.0000000596e-01, /* 3ECCCCCD */ +Lp3 = 2.8571429849e-01, /* 3E924925 */ +Lp4 = 2.2222198546e-01, /* 3E638E29 */ +Lp5 = 1.8183572590e-01, /* 3E3A3325 */ +Lp6 = 1.5313838422e-01, /* 3E1CD04F */ +Lp7 = 1.4798198640e-01; /* 3E178897 */ + +static const float zero = 0.0; + +float +log1pf(float x) +{ +        float hfsq,f=0,c=0,s,z,R,u; +        int32_t k,hx,hu=0,ax; + +        GET_FLOAT_WORD(hx,x); +        ax = hx&0x7fffffff; + +        k = 1; +        if (hx < 0x3ed413d7) {                  /* x < 0.41422  */ +            if(ax>=0x3f800000) {                /* x <= -1.0 */ +                if(x==(float)-1.0) return -two25/zero; /* log1p(-1)=+inf */ +                else return (x-x)/(x-x);        /* log1p(x<-1)=NaN */ +            } +            if(ax<0x31000000) {                 /* |x| < 2**-29 */ +                if(two25+x>zero                 /* raise inexact */ +                    &&ax<0x24800000)            /* |x| < 2**-54 */ +                    return x; +                else +                    return x - x*x*(float)0.5; +            } +            if(hx>0||hx<=((int32_t)0xbe95f61f)) { +                k=0;f=x;hu=1;}  /* -0.2929<x<0.41422 */ +        } +        if (hx >= 0x7f800000) return x+x; +        if(k!=0) { +            if(hx<0x5a000000) { +                u  = (float)1.0+x; +                GET_FLOAT_WORD(hu,u); +                k  = (hu>>23)-127; +                /* correction term */ +                c  = (k>0)? (float)1.0-(u-x):x-(u-(float)1.0); +                c /= u; +            } else { +                u  = x; +                GET_FLOAT_WORD(hu,u); +                k  = (hu>>23)-127; +                c  = 0; +            } +            hu &= 0x007fffff; +            if(hu<0x3504f7) { +                SET_FLOAT_WORD(u,hu|0x3f800000);/* normalize u */ +            } else { +                k += 1; +                SET_FLOAT_WORD(u,hu|0x3f000000);        /* normalize u/2 */ +                hu = (0x00800000-hu)>>2; +            } +            f = u-(float)1.0; +        } +        hfsq=(float)0.5*f*f; +        if(hu==0) {     /* |f| < 2**-20 */ +            if(f==zero) { if(k==0) return zero; +                          else {c += k*ln2_lo; return k*ln2_hi+c;} } +            R = hfsq*((float)1.0-(float)0.66666666666666666*f); +            if(k==0) return f-R; else +                     return k*ln2_hi-((R-(k*ln2_lo+c))-f); +        } +        s = f/((float)2.0+f); +        z = s*s; +        R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7)))))); +        if(k==0) return f-(hfsq-s*(hfsq+R)); else +                 return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f); +} diff --git a/src/math/s_logb.c b/src/math/s_logb.c new file mode 100644 index 00000000..be399c77 --- /dev/null +++ b/src/math/s_logb.c @@ -0,0 +1,34 @@ +/* @(#)s_logb.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * double logb(x) + * IEEE 754 logb. Included to pass IEEE test suite. Not recommend. + * Use ilogb instead. + */ + +#include <math.h> +#include "math_private.h" + +double +logb(double x) +{ +        int32_t lx,ix; +        EXTRACT_WORDS(ix,lx,x); +        ix &= 0x7fffffff;                       /* high |x| */ +        if((ix|lx)==0) return -1.0/fabs(x); +        if(ix>=0x7ff00000) return x*x; +        if((ix>>=20)==0)                        /* IEEE 754 logb */ +                return -1022.0; +        else +                return (double) (ix-1023); +} diff --git a/src/math/s_logbf.c b/src/math/s_logbf.c new file mode 100644 index 00000000..747664d3 --- /dev/null +++ b/src/math/s_logbf.c @@ -0,0 +1,31 @@ +/* s_logbf.c -- float version of s_logb.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +float +logbf(float x) +{ +        int32_t ix; +        GET_FLOAT_WORD(ix,x); +        ix &= 0x7fffffff;                       /* high |x| */ +        if(ix==0) return (float)-1.0/fabsf(x); +        if(ix>=0x7f800000) return x*x; +        if((ix>>=23)==0)                        /* IEEE 754 logb */ +                return -126.0; +        else +                return (float) (ix-127); +} diff --git a/src/math/s_lrint.c b/src/math/s_lrint.c new file mode 100644 index 00000000..da8e1989 --- /dev/null +++ b/src/math/s_lrint.c @@ -0,0 +1,8 @@ +#include <math.h> + +// FIXME: incorrect exception behavior + +long lrint(double x) +{ +	return rint(x); +} diff --git a/src/math/s_lrintf.c b/src/math/s_lrintf.c new file mode 100644 index 00000000..d0b469b9 --- /dev/null +++ b/src/math/s_lrintf.c @@ -0,0 +1,8 @@ +#include <math.h> + +// FIXME: incorrect exception behavior + +long lrintf(float x) +{ +	return rintf(x); +} diff --git a/src/math/s_modf.c b/src/math/s_modf.c new file mode 100644 index 00000000..a5528d6b --- /dev/null +++ b/src/math/s_modf.c @@ -0,0 +1,71 @@ +/* @(#)s_modf.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * modf(double x, double *iptr) + * return fraction part of x, and return x's integral part in *iptr. + * Method: + *      Bit twiddling. + * + * Exception: + *      No exception. + */ + +#include <math.h> +#include "math_private.h" + +static const double one = 1.0; + +double +modf(double x, double *iptr) +{ +        int32_t i0,i1,j0; +        uint32_t i; +        EXTRACT_WORDS(i0,i1,x); +        j0 = ((i0>>20)&0x7ff)-0x3ff;    /* exponent of x */ +        if(j0<20) {                     /* integer part in high x */ +            if(j0<0) {                  /* |x|<1 */ +                INSERT_WORDS(*iptr,i0&0x80000000,0);    /* *iptr = +-0 */ +                return x; +            } else { +                i = (0x000fffff)>>j0; +                if(((i0&i)|i1)==0) {            /* x is integral */ +                    uint32_t high; +                    *iptr = x; +                    GET_HIGH_WORD(high,x); +                    INSERT_WORDS(x,high&0x80000000,0);  /* return +-0 */ +                    return x; +                } else { +                    INSERT_WORDS(*iptr,i0&(~i),0); +                    return x - *iptr; +                } +            } +        } else if (j0>51) {             /* no fraction part */ +            uint32_t high; +            *iptr = x*one; +            GET_HIGH_WORD(high,x); +            INSERT_WORDS(x,high&0x80000000,0);  /* return +-0 */ +            return x; +        } else {                        /* fraction part in low x */ +            i = ((uint32_t)(0xffffffff))>>(j0-20); +            if((i1&i)==0) {             /* x is integral */ +                uint32_t high; +                *iptr = x; +                GET_HIGH_WORD(high,x); +                INSERT_WORDS(x,high&0x80000000,0);      /* return +-0 */ +                return x; +            } else { +                INSERT_WORDS(*iptr,i0,i1&(~i)); +                return x - *iptr; +            } +        } +} diff --git a/src/math/s_modff.c b/src/math/s_modff.c new file mode 100644 index 00000000..de4dfd25 --- /dev/null +++ b/src/math/s_modff.c @@ -0,0 +1,52 @@ +/* s_modff.c -- float version of s_modf.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float one = 1.0; + +float +modff(float x, float *iptr) +{ +        int32_t i0,j0; +        uint32_t i; +        GET_FLOAT_WORD(i0,x); +        j0 = ((i0>>23)&0xff)-0x7f;      /* exponent of x */ +        if(j0<23) {                     /* integer part in x */ +            if(j0<0) {                  /* |x|<1 */ +                SET_FLOAT_WORD(*iptr,i0&0x80000000);    /* *iptr = +-0 */ +                return x; +            } else { +                i = (0x007fffff)>>j0; +                if((i0&i)==0) {                 /* x is integral */ +                    uint32_t ix; +                    *iptr = x; +                    GET_FLOAT_WORD(ix,x); +                    SET_FLOAT_WORD(x,ix&0x80000000);    /* return +-0 */ +                    return x; +                } else { +                    SET_FLOAT_WORD(*iptr,i0&(~i)); +                    return x - *iptr; +                } +            } +        } else {                        /* no fraction part */ +            uint32_t ix; +            *iptr = x*one; +            GET_FLOAT_WORD(ix,x); +            SET_FLOAT_WORD(x,ix&0x80000000);    /* return +-0 */ +            return x; +        } +} diff --git a/src/math/s_nextafter.c b/src/math/s_nextafter.c new file mode 100644 index 00000000..46d298ec --- /dev/null +++ b/src/math/s_nextafter.c @@ -0,0 +1,72 @@ +/* @(#)s_nextafter.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* IEEE functions + *      nextafter(x,y) + *      return the next machine floating-point number of x in the + *      direction toward y. + *   Special cases: + */ + +#include <math.h> +#include "math_private.h" + +double +nextafter(double x, double y) +{ +        volatile double t; +        int32_t hx,hy,ix,iy; +        uint32_t lx,ly; + +        EXTRACT_WORDS(hx,lx,x); +        EXTRACT_WORDS(hy,ly,y); +        ix = hx&0x7fffffff;             /* |x| */ +        iy = hy&0x7fffffff;             /* |y| */ + +        if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   /* x is nan */ +           ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0))     /* y is nan */ +           return x+y; +        if(x==y) return y;              /* x=y, return y */ +        if((ix|lx)==0) {                        /* x == 0 */ +            INSERT_WORDS(x,hy&0x80000000,1);    /* return +-minsubnormal */ +            t = x*x; +            if(t==x) return t; else return x;   /* raise underflow flag */ +        } +        if(hx>=0) {                             /* x > 0 */ +            if(hx>hy||((hx==hy)&&(lx>ly))) {    /* x > y, x -= ulp */ +                if(lx==0) hx -= 1; +                lx -= 1; +            } else {                            /* x < y, x += ulp */ +                lx += 1; +                if(lx==0) hx += 1; +            } +        } else {                                /* x < 0 */ +            if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */ +                if(lx==0) hx -= 1; +                lx -= 1; +            } else {                            /* x > y, x += ulp */ +                lx += 1; +                if(lx==0) hx += 1; +            } +        } +        hy = hx&0x7ff00000; +        if(hy>=0x7ff00000) return x+x;  /* overflow  */ +        if(hy<0x00100000) {             /* underflow */ +            t = x*x; +            if(t!=x) {          /* raise underflow flag */ +                INSERT_WORDS(y,hx,lx); +                return y; +            } +        } +        INSERT_WORDS(x,hx,lx); +        return x; +} diff --git a/src/math/s_nextafterf.c b/src/math/s_nextafterf.c new file mode 100644 index 00000000..7ce08838 --- /dev/null +++ b/src/math/s_nextafterf.c @@ -0,0 +1,63 @@ +/* s_nextafterf.c -- float version of s_nextafter.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +float +nextafterf(float x, float y) +{ +        volatile float t; +        int32_t hx,hy,ix,iy; + +        GET_FLOAT_WORD(hx,x); +        GET_FLOAT_WORD(hy,y); +        ix = hx&0x7fffffff;             /* |x| */ +        iy = hy&0x7fffffff;             /* |y| */ + +        if((ix>0x7f800000) ||   /* x is nan */ +           (iy>0x7f800000))     /* y is nan */ +           return x+y; +        if(x==y) return y;              /* x=y, return y */ +        if(ix==0) {                             /* x == 0 */ +            SET_FLOAT_WORD(x,(hy&0x80000000)|1);/* return +-minsubnormal */ +            t = x*x; +            if(t==x) return t; else return x;   /* raise underflow flag */ +        } +        if(hx>=0) {                             /* x > 0 */ +            if(hx>hy) {                         /* x > y, x -= ulp */ +                hx -= 1; +            } else {                            /* x < y, x += ulp */ +                hx += 1; +            } +        } else {                                /* x < 0 */ +            if(hy>=0||hx>hy){                   /* x < y, x -= ulp */ +                hx -= 1; +            } else {                            /* x > y, x += ulp */ +                hx += 1; +            } +        } +        hy = hx&0x7f800000; +        if(hy>=0x7f800000) return x+x;  /* overflow  */ +        if(hy<0x00800000) {             /* underflow */ +            t = x*x; +            if(t!=x) {          /* raise underflow flag */ +                SET_FLOAT_WORD(y,hx); +                return y; +            } +        } +        SET_FLOAT_WORD(x,hx); +        return x; +} diff --git a/src/math/s_remquo.c b/src/math/s_remquo.c new file mode 100644 index 00000000..1a2992d6 --- /dev/null +++ b/src/math/s_remquo.c @@ -0,0 +1,149 @@ +/* @(#)e_fmod.c 1.3 95/01/18 */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const double Zero[] = {0.0, -0.0,}; + +/* + * Return the IEEE remainder and set *quo to the last n bits of the + * quotient, rounded to the nearest integer.  We choose n=31 because + * we wind up computing all the integer bits of the quotient anyway as + * a side-effect of computing the remainder by the shift and subtract + * method.  In practice, this is far more bits than are needed to use + * remquo in reduction algorithms. + */ +double +remquo(double x, double y, int *quo) +{ +        int32_t n,hx,hy,hz,ix,iy,sx,i; +        uint32_t lx,ly,lz,q,sxy; + +        EXTRACT_WORDS(hx,lx,x); +        EXTRACT_WORDS(hy,ly,y); +        sxy = (hx ^ hy) & 0x80000000; +        sx = hx&0x80000000;             /* sign of x */ +        hx ^=sx;                /* |x| */ +        hy &= 0x7fffffff;       /* |y| */ + +    /* purge off exception values */ +        if((hy|ly)==0||(hx>=0x7ff00000)||       /* y=0,or x not finite */ +          ((hy|((ly|-ly)>>31))>0x7ff00000))     /* or y is NaN */ +            return (x*y)/(x*y); +        if(hx<=hy) { +            if((hx<hy)||(lx<ly)) { +                q = 0; +                goto fixup;     /* |x|<|y| return x or x-y */ +            } +            if(lx==ly) { +                *quo = 1; +                return Zero[(uint32_t)sx>>31]; /* |x|=|y| return x*0*/ +            } +        } + +    /* determine ix = ilogb(x) */ +        if(hx<0x00100000) {     /* subnormal x */ +            if(hx==0) { +                for (ix = -1043, i=lx; i>0; i<<=1) ix -=1; +            } else { +                for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1; +            } +        } else ix = (hx>>20)-1023; + +    /* determine iy = ilogb(y) */ +        if(hy<0x00100000) {     /* subnormal y */ +            if(hy==0) { +                for (iy = -1043, i=ly; i>0; i<<=1) iy -=1; +            } else { +                for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1; +            } +        } else iy = (hy>>20)-1023; + +    /* set up {hx,lx}, {hy,ly} and align y to x */ +        if(ix >= -1022)  +            hx = 0x00100000|(0x000fffff&hx); +        else {          /* subnormal x, shift x to normal */ +            n = -1022-ix; +            if(n<=31) { +                hx = (hx<<n)|(lx>>(32-n)); +                lx <<= n; +            } else { +                hx = lx<<(n-32); +                lx = 0; +            } +        } +        if(iy >= -1022)  +            hy = 0x00100000|(0x000fffff&hy); +        else {          /* subnormal y, shift y to normal */ +            n = -1022-iy; +            if(n<=31) { +                hy = (hy<<n)|(ly>>(32-n)); +                ly <<= n; +            } else { +                hy = ly<<(n-32); +                ly = 0; +            } +        } + +    /* fix point fmod */ +        n = ix - iy; +        q = 0; +        while(n--) { +            hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; +            if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;} +            else {hx = hz+hz+(lz>>31); lx = lz+lz; q++;} +            q <<= 1; +        } +        hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; +        if(hz>=0) {hx=hz;lx=lz;q++;} + +    /* convert back to floating value and restore the sign */ +        if((hx|lx)==0) {                        /* return sign(x)*0 */ +            *quo = (sxy ? -q : q); +            return Zero[(uint32_t)sx>>31]; +        } +        while(hx<0x00100000) {          /* normalize x */ +            hx = hx+hx+(lx>>31); lx = lx+lx; +            iy -= 1; +        } +        if(iy>= -1022) {        /* normalize output */ +            hx = ((hx-0x00100000)|((iy+1023)<<20)); +        } else {                /* subnormal output */ +            n = -1022 - iy; +            if(n<=20) { +                lx = (lx>>n)|((uint32_t)hx<<(32-n)); +                hx >>= n; +            } else if (n<=31) { +                lx = (hx<<(32-n))|(lx>>n); hx = sx; +            } else { +                lx = hx>>(n-32); hx = sx; +            } +        } +fixup: +        INSERT_WORDS(x,hx,lx); +        y = fabs(y); +        if (y < 0x1p-1021) { +            if (x+x>y || (x+x==y && (q & 1))) { +                q++; +                x-=y; +            } +        } else if (x>0.5*y || (x==0.5*y && (q & 1))) { +            q++; +            x-=y; +        } +        GET_HIGH_WORD(hx,x); +        SET_HIGH_WORD(x,hx^sx); +        q &= 0x7fffffff; +        *quo = (sxy ? -q : q); +        return x; +} diff --git a/src/math/s_remquof.c b/src/math/s_remquof.c new file mode 100644 index 00000000..be2a561a --- /dev/null +++ b/src/math/s_remquof.c @@ -0,0 +1,118 @@ +/* @(#)e_fmod.c 1.3 95/01/18 */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice  + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float Zero[] = {0.0, -0.0,}; + +/* + * Return the IEEE remainder and set *quo to the last n bits of the + * quotient, rounded to the nearest integer.  We choose n=31 because + * we wind up computing all the integer bits of the quotient anyway as + * a side-effect of computing the remainder by the shift and subtract + * method.  In practice, this is far more bits than are needed to use + * remquo in reduction algorithms. + */ +float +remquof(float x, float y, int *quo) +{ +        int32_t n,hx,hy,hz,ix,iy,sx,i; +        uint32_t q,sxy; + +        GET_FLOAT_WORD(hx,x); +        GET_FLOAT_WORD(hy,y); +        sxy = (hx ^ hy) & 0x80000000; +        sx = hx&0x80000000;             /* sign of x */ +        hx ^=sx;                /* |x| */ +        hy &= 0x7fffffff;       /* |y| */ + +    /* purge off exception values */ +        if(hy==0||hx>=0x7f800000||hy>0x7f800000) /* y=0,NaN;or x not finite */ +            return (x*y)/(x*y); +        if(hx<hy) { +            q = 0; +            goto fixup; /* |x|<|y| return x or x-y */ +        } else if(hx==hy) { +            *quo = 1; +            return Zero[(uint32_t)sx>>31];     /* |x|=|y| return x*0*/ +        } + +    /* determine ix = ilogb(x) */ +        if(hx<0x00800000) {     /* subnormal x */ +            for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1; +        } else ix = (hx>>23)-127; + +    /* determine iy = ilogb(y) */ +        if(hy<0x00800000) {     /* subnormal y */ +            for (iy = -126,i=(hy<<8); i>0; i<<=1) iy -=1; +        } else iy = (hy>>23)-127; + +    /* set up {hx,lx}, {hy,ly} and align y to x */ +        if(ix >= -126) +            hx = 0x00800000|(0x007fffff&hx); +        else {          /* subnormal x, shift x to normal */ +            n = -126-ix; +            hx <<= n; +        } +        if(iy >= -126) +            hy = 0x00800000|(0x007fffff&hy); +        else {          /* subnormal y, shift y to normal */ +            n = -126-iy; +            hy <<= n; +        } + +    /* fix point fmod */ +        n = ix - iy; +        q = 0; +        while(n--) { +            hz=hx-hy; +            if(hz<0) hx = hx << 1; +            else {hx = hz << 1; q++;} +            q <<= 1; +        } +        hz=hx-hy; +        if(hz>=0) {hx=hz;q++;} + +    /* convert back to floating value and restore the sign */ +        if(hx==0) {                             /* return sign(x)*0 */ +            *quo = (sxy ? -q : q); +            return Zero[(uint32_t)sx>>31]; +        } +        while(hx<0x00800000) {          /* normalize x */ +            hx <<= 1; +            iy -= 1; +        } +        if(iy>= -126) {         /* normalize output */ +            hx = ((hx-0x00800000)|((iy+127)<<23)); +        } else {                /* subnormal output */ +            n = -126 - iy; +            hx >>= n; +        } +fixup: +        SET_FLOAT_WORD(x,hx); +        y = fabsf(y); +        if (y < 0x1p-125f) { +            if (x+x>y || (x+x==y && (q & 1))) { +                q++; +                x-=y; +            } +        } else if (x>0.5f*y || (x==0.5f*y && (q & 1))) { +            q++; +            x-=y; +        } +        GET_FLOAT_WORD(hx,x); +        SET_FLOAT_WORD(x,hx^sx); +        q &= 0x7fffffff; +        *quo = (sxy ? -q : q); +        return x; +} diff --git a/src/math/s_rint.c b/src/math/s_rint.c new file mode 100644 index 00000000..aec7d3c9 --- /dev/null +++ b/src/math/s_rint.c @@ -0,0 +1,80 @@ +/* @(#)s_rint.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * rint(x) + * Return x rounded to integral value according to the prevailing + * rounding mode. + * Method: + *      Using floating addition. + * Exception: + *      Inexact flag raised if x not equal to rint(x). + */ + +#include <math.h> +#include "math_private.h" + +/* + * TWO23 is long double instead of double to avoid a bug in gcc.  Without + * this, gcc thinks that TWO23[sx]+x and w-TWO23[sx] already have double + * precision and doesn't clip them to double precision when they are + * assigned and returned. + */ +static const long double +TWO52[2]={ +  4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ + -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */ +}; + +double +rint(double x) +{ +        int32_t i0,j0,sx; +        uint32_t i,i1; +        double w,t; +        EXTRACT_WORDS(i0,i1,x); +        sx = (i0>>31)&1; +        j0 = ((i0>>20)&0x7ff)-0x3ff; +        if(j0<20) { +            if(j0<0) { +                if(((i0&0x7fffffff)|i1)==0) return x; +                i1 |= (i0&0x0fffff); +                i0 &= 0xfffe0000; +                i0 |= ((i1|-i1)>>12)&0x80000; +                SET_HIGH_WORD(x,i0); +                w = TWO52[sx]+x; +                t =  w-TWO52[sx]; +                GET_HIGH_WORD(i0,t); +                SET_HIGH_WORD(t,(i0&0x7fffffff)|(sx<<31)); +                return t; +            } else { +                i = (0x000fffff)>>j0; +                if(((i0&i)|i1)==0) return x; /* x is integral */ +                i>>=1; +                if(((i0&i)|i1)!=0) { +                    if(j0==19) i1 = 0x40000000; else +                    i0 = (i0&(~i))|((0x20000)>>j0); +                } +            } +        } else if (j0>51) { +            if(j0==0x400) return x+x;   /* inf or NaN */ +            else return x;              /* x is integral */ +        } else { +            i = ((uint32_t)(0xffffffff))>>(j0-20); +            if((i1&i)==0) return x;     /* x is integral */ +            i>>=1; +            if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20)); +        } +        INSERT_WORDS(x,i0,i1); +        w = TWO52[sx]+x; +        return w-TWO52[sx]; +} diff --git a/src/math/s_rintf.c b/src/math/s_rintf.c new file mode 100644 index 00000000..c441870d --- /dev/null +++ b/src/math/s_rintf.c @@ -0,0 +1,45 @@ +/* s_rintf.c -- float version of s_rint.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +TWO23[2]={ +  8.3886080000e+06, /* 0x4b000000 */ + -8.3886080000e+06, /* 0xcb000000 */ +}; + +float +rintf(float x) +{ +        int32_t i0,j0,sx; +        volatile float w,t;     /* volatile works around gcc bug */ +        GET_FLOAT_WORD(i0,x); +        sx = (i0>>31)&1; +        j0 = ((i0>>23)&0xff)-0x7f; +        if(j0<23) { +            if(j0<0) { +                if((i0&0x7fffffff)==0) return x; +                w = TWO23[sx]+x; +                t =  w-TWO23[sx]; +                return t; +            } +            w = TWO23[sx]+x; +            return w-TWO23[sx]; +        } +        if(j0==0x80) return x+x;        /* inf or NaN */ +        else return x;                  /* x is integral */ +} diff --git a/src/math/s_round.c b/src/math/s_round.c new file mode 100644 index 00000000..d5bea7a9 --- /dev/null +++ b/src/math/s_round.c @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2003, Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice unmodified, this list of conditions, and the following + *    disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <math.h> + +double +round(double x) +{ +	double t; + +	if (!isfinite(x)) +		return (x); + +	if (x >= 0.0) { +		t = ceil(x); +		if (t - x > 0.5) +			t -= 1.0; +		return (t); +	} else { +		t = ceil(-x); +		if (t + x > 0.5) +			t -= 1.0; +		return (-t); +	} +} diff --git a/src/math/s_roundf.c b/src/math/s_roundf.c new file mode 100644 index 00000000..c4fc3e19 --- /dev/null +++ b/src/math/s_roundf.c @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2003, Steven G. Kargl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice unmodified, this list of conditions, and the following + *    disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <math.h> + +float +roundf(float x) +{ +	float t; + +	if (!isfinite(x)) +		return (x); + +	if (x >= 0.0) { +		t = ceilf(x); +		if (t - x > 0.5) +			t -= 1.0; +		return (t); +	} else { +		t = ceilf(-x); +		if (t + x > 0.5) +			t -= 1.0; +		return (-t); +	} +} diff --git a/src/math/s_scalbln.c b/src/math/s_scalbln.c new file mode 100644 index 00000000..12b9391b --- /dev/null +++ b/src/math/s_scalbln.c @@ -0,0 +1,61 @@ +/* @(#)s_scalbn.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * scalbn (double x, int n) + * scalbn(x,n) returns x* 2**n  computed by  exponent + * manipulation rather than by actually performing an + * exponentiation or a multiplication. + */ + +#include <math.h> +#include "math_private.h" + +static const double +two54   =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +twom54  =  5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ +huge   = 1.0e+300, +tiny   = 1.0e-300; + +double +scalbln (double x, long n) +{ +        int32_t k,hx,lx; +        EXTRACT_WORDS(hx,lx,x); +        k = (hx&0x7ff00000)>>20;                /* extract exponent */ +        if (k==0) {                             /* 0 or subnormal x */ +            if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */ +            x *= two54; +            GET_HIGH_WORD(hx,x); +            k = ((hx&0x7ff00000)>>20) - 54; +            if (n< -50000) return tiny*x;       /*underflow*/ +            } +        if (k==0x7ff) return x+x;               /* NaN or Inf */ +        k = k+n; +        if (k >  0x7fe) return huge*copysign(huge,x); /* overflow  */ +        if (k > 0)                              /* normal result */ +            {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;} +        if (k <= -54) { +            if (n > 50000)      /* in case integer overflow in n+k */ +                return huge*copysign(huge,x);   /*overflow*/ +            else return tiny*copysign(tiny,x);  /*underflow*/ +        } +        k += 54;                                /* subnormal result */ +        SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); +        return x*twom54; +} + +double +scalbn (double x, int n) +{ +        return scalbln(x, n); +} diff --git a/src/math/s_scalblnf.c b/src/math/s_scalblnf.c new file mode 100644 index 00000000..21e7641c --- /dev/null +++ b/src/math/s_scalblnf.c @@ -0,0 +1,57 @@ +/* s_scalbnf.c -- float version of s_scalbn.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float +two25   =  3.355443200e+07,     /* 0x4c000000 */ +twom25  =  2.9802322388e-08,    /* 0x33000000 */ +huge   = 1.0e+30, +tiny   = 1.0e-30; + +float +scalblnf (float x, long n) +{ +        int32_t k,ix; +        GET_FLOAT_WORD(ix,x); +        k = (ix&0x7f800000)>>23;                /* extract exponent */ +        if (k==0) {                             /* 0 or subnormal x */ +            if ((ix&0x7fffffff)==0) return x; /* +-0 */ +            x *= two25; +            GET_FLOAT_WORD(ix,x); +            k = ((ix&0x7f800000)>>23) - 25; +            if (n< -50000) return tiny*x;       /*underflow*/ +            } +        if (k==0xff) return x+x;                /* NaN or Inf */ +        k = k+n; +        if (k >  0xfe) return huge*copysignf(huge,x); /* overflow  */ +        if (k > 0)                              /* normal result */ +            {SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); return x;} +        if (k <= -25) { +            if (n > 50000)      /* in case integer overflow in n+k */ +                return huge*copysignf(huge,x);  /*overflow*/ +            else return tiny*copysignf(tiny,x); /*underflow*/ +        } +        k += 25;                                /* subnormal result */ +        SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); +        return x*twom25; +} + +float +scalbnf (float x, int n) +{ +        return scalblnf(x, n); +} diff --git a/src/math/s_sin.c b/src/math/s_sin.c new file mode 100644 index 00000000..2a2774ed --- /dev/null +++ b/src/math/s_sin.c @@ -0,0 +1,74 @@ +/* @(#)s_sin.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* sin(x) + * Return sine function of x. + * + * kernel function: + *      __kernel_sin            ... sine function on [-pi/4,pi/4] + *      __kernel_cos            ... cose function on [-pi/4,pi/4] + *      __ieee754_rem_pio2      ... argument reduction routine + * + * Method. + *      Let S,C and T denote the sin, cos and tan respectively on + *      [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + *      in [-pi/4 , +pi/4], and let n = k mod 4. + *      We have + * + *          n        sin(x)      cos(x)        tan(x) + *     ---------------------------------------------------------- + *          0          S           C             T + *          1          C          -S            -1/T + *          2         -S          -C             T + *          3         -C           S            -1/T + *     ---------------------------------------------------------- + * + * Special cases: + *      Let trig be any of sin, cos, or tan. + *      trig(+-INF)  is NaN, with signals; + *      trig(NaN)    is that NaN; + * + * Accuracy: + *      TRIG(x) returns trig(x) nearly rounded + */ + +#include <math.h> +#include "math_private.h" + +double +sin(double x) +{ +        double y[2],z=0.0; +        int32_t n, ix; + +    /* High word of x. */ +        GET_HIGH_WORD(ix,x); + +    /* |x| ~< pi/4 */ +        ix &= 0x7fffffff; +        if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0); + +    /* sin(Inf or NaN) is NaN */ +        else if (ix>=0x7ff00000) return x-x; + +    /* argument reduction needed */ +        else { +            n = __ieee754_rem_pio2(x,y); +            switch(n&3) { +                case 0: return  __kernel_sin(y[0],y[1],1); +                case 1: return  __kernel_cos(y[0],y[1]); +                case 2: return -__kernel_sin(y[0],y[1],1); +                default: +                        return -__kernel_cos(y[0],y[1]); +            } +        } +} diff --git a/src/math/s_sinf.c b/src/math/s_sinf.c new file mode 100644 index 00000000..d2b8e806 --- /dev/null +++ b/src/math/s_sinf.c @@ -0,0 +1,45 @@ +/* s_sinf.c -- float version of s_sin.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +float +sinf(float x) +{ +        float y[2],z=0.0; +        int32_t n, ix; + +        GET_FLOAT_WORD(ix,x); + +    /* |x| ~< pi/4 */ +        ix &= 0x7fffffff; +        if(ix <= 0x3f490fd8) return __kernel_sinf(x,z,0); + +    /* sin(Inf or NaN) is NaN */ +        else if (ix>=0x7f800000) return x-x; + +    /* argument reduction needed */ +        else { +            n = __ieee754_rem_pio2f(x,y); +            switch(n&3) { +                case 0: return  __kernel_sinf(y[0],y[1],1); +                case 1: return  __kernel_cosf(y[0],y[1]); +                case 2: return -__kernel_sinf(y[0],y[1],1); +                default: +                        return -__kernel_cosf(y[0],y[1]); +            } +        } +} diff --git a/src/math/s_tan.c b/src/math/s_tan.c new file mode 100644 index 00000000..3333cb3d --- /dev/null +++ b/src/math/s_tan.c @@ -0,0 +1,68 @@ +/* @(#)s_tan.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* tan(x) + * Return tangent function of x. + * + * kernel function: + *      __kernel_tan            ... tangent function on [-pi/4,pi/4] + *      __ieee754_rem_pio2      ... argument reduction routine + * + * Method. + *      Let S,C and T denote the sin, cos and tan respectively on + *      [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 + *      in [-pi/4 , +pi/4], and let n = k mod 4. + *      We have + * + *          n        sin(x)      cos(x)        tan(x) + *     ---------------------------------------------------------- + *          0          S           C             T + *          1          C          -S            -1/T + *          2         -S          -C             T + *          3         -C           S            -1/T + *     ---------------------------------------------------------- + * + * Special cases: + *      Let trig be any of sin, cos, or tan. + *      trig(+-INF)  is NaN, with signals; + *      trig(NaN)    is that NaN; + * + * Accuracy: + *      TRIG(x) returns trig(x) nearly rounded + */ + +#include <math.h> +#include "math_private.h" + +double +tan(double x) +{ +        double y[2],z=0.0; +        int32_t n, ix; + +    /* High word of x. */ +        GET_HIGH_WORD(ix,x); + +    /* |x| ~< pi/4 */ +        ix &= 0x7fffffff; +        if(ix <= 0x3fe921fb) return __kernel_tan(x,z,1); + +    /* tan(Inf or NaN) is NaN */ +        else if (ix>=0x7ff00000) return x-x;            /* NaN */ + +    /* argument reduction needed */ +        else { +            n = __ieee754_rem_pio2(x,y); +            return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /*   1 -- n even +                                                        -1 -- n odd */ +        } +} diff --git a/src/math/s_tanf.c b/src/math/s_tanf.c new file mode 100644 index 00000000..660dd9c3 --- /dev/null +++ b/src/math/s_tanf.c @@ -0,0 +1,40 @@ +/* s_tanf.c -- float version of s_tan.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +float +tanf(float x) +{ +        float y[2],z=0.0; +        int32_t n, ix; + +        GET_FLOAT_WORD(ix,x); + +    /* |x| ~< pi/4 */ +        ix &= 0x7fffffff; +        if(ix <= 0x3f490fda) return __kernel_tanf(x,z,1); + +    /* tan(Inf or NaN) is NaN */ +        else if (ix>=0x7f800000) return x-x;            /* NaN */ + +    /* argument reduction needed */ +        else { +            n = __ieee754_rem_pio2f(x,y); +            return __kernel_tanf(y[0],y[1],1-((n&1)<<1)); /*   1 -- n even +                                                              -1 -- n odd */ +        } +} diff --git a/src/math/s_tanh.c b/src/math/s_tanh.c new file mode 100644 index 00000000..78b8e849 --- /dev/null +++ b/src/math/s_tanh.c @@ -0,0 +1,74 @@ +/* @(#)s_tanh.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* Tanh(x) + * Return the Hyperbolic Tangent of x + * + * Method : + *                                     x    -x + *                                    e  - e + *      0. tanh(x) is defined to be ----------- + *                                     x    -x + *                                    e  + e + *      1. reduce x to non-negative by tanh(-x) = -tanh(x). + *      2.  0      <= x <= 2**-55 : tanh(x) := x*(one+x) + *                                              -t + *          2**-55 <  x <=  1     : tanh(x) := -----; t = expm1(-2x) + *                                             t + 2 + *                                                   2 + *          1      <= x <=  22.0  : tanh(x) := 1-  ----- ; t=expm1(2x) + *                                                 t + 2 + *          22.0   <  x <= INF    : tanh(x) := 1. + * + * Special cases: + *      tanh(NaN) is NaN; + *      only tanh(0)=0 is exact for finite argument. + */ + +#include <math.h> +#include "math_private.h" + +static const double one=1.0, two=2.0, tiny = 1.0e-300; + +double +tanh(double x) +{ +        double t,z; +        int32_t jx,ix; + +    /* High word of |x|. */ +        GET_HIGH_WORD(jx,x); +        ix = jx&0x7fffffff; + +    /* x is INF or NaN */ +        if(ix>=0x7ff00000) { +            if (jx>=0) return one/x+one;    /* tanh(+-inf)=+-1 */ +            else       return one/x-one;    /* tanh(NaN) = NaN */ +        } + +    /* |x| < 22 */ +        if (ix < 0x40360000) {          /* |x|<22 */ +            if (ix<0x3c800000)          /* |x|<2**-55 */ +                return x*(one+x);       /* tanh(small) = small */ +            if (ix>=0x3ff00000) {       /* |x|>=1  */ +                t = expm1(two*fabs(x)); +                z = one - two/(t+two); +            } else { +                t = expm1(-two*fabs(x)); +                z= -t/(t+two); +            } +    /* |x| > 22, return +-1 */ +        } else { +            z = one - tiny;             /* raised inexact flag */ +        } +        return (jx>=0)? z: -z; +} diff --git a/src/math/s_tanhf.c b/src/math/s_tanhf.c new file mode 100644 index 00000000..a0820409 --- /dev/null +++ b/src/math/s_tanhf.c @@ -0,0 +1,52 @@ +/* s_tanhf.c -- float version of s_tanh.c. + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include <math.h> +#include "math_private.h" + +static const float one=1.0, two=2.0, tiny = 1.0e-30; + +float +tanhf(float x) +{ +        float t,z; +        int32_t jx,ix; + +        GET_FLOAT_WORD(jx,x); +        ix = jx&0x7fffffff; + +    /* x is INF or NaN */ +        if(ix>=0x7f800000) { +            if (jx>=0) return one/x+one;    /* tanh(+-inf)=+-1 */ +            else       return one/x-one;    /* tanh(NaN) = NaN */ +        } + +    /* |x| < 22 */ +        if (ix < 0x41b00000) {          /* |x|<22 */ +            if (ix<0x24000000)          /* |x|<2**-55 */ +                return x*(one+x);       /* tanh(small) = small */ +            if (ix>=0x3f800000) {       /* |x|>=1  */ +                t = expm1f(two*fabsf(x)); +                z = one - two/(t+two); +            } else { +                t = expm1f(-two*fabsf(x)); +                z= -t/(t+two); +            } +    /* |x| > 22, return +-1 */ +        } else { +            z = one - tiny;             /* raised inexact flag */ +        } +        return (jx>=0)? z: -z; +} diff --git a/src/math/s_trunc.c b/src/math/s_trunc.c new file mode 100644 index 00000000..02c65567 --- /dev/null +++ b/src/math/s_trunc.c @@ -0,0 +1,58 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * trunc(x) + * Return x rounded toward 0 to integral value + * Method: + *      Bit twiddling. + * Exception: + *      Inexact flag raised if x not equal to trunc(x). + */ + +#include <math.h> +#include "math_private.h" + +static const double huge = 1.0e300; + +double +trunc(double x) +{ +        int32_t i0,i1,j0; +        uint32_t i,j; +        EXTRACT_WORDS(i0,i1,x); +        j0 = ((i0>>20)&0x7ff)-0x3ff; +        if(j0<20) { +            if(j0<0) {  /* raise inexact if x != 0 */ +                if(huge+x>0.0) {/* |x|<1, so return 0*sign(x) */ +                    i0 &= 0x80000000U; +                    i1 = 0; +                } +            } else { +                i = (0x000fffff)>>j0; +                if(((i0&i)|i1)==0) return x; /* x is integral */ +                if(huge+x>0.0) {        /* raise inexact flag */ +                    i0 &= (~i); i1=0; +                } +            } +        } else if (j0>51) { +            if(j0==0x400) return x+x;   /* inf or NaN */ +            else return x;              /* x is integral */ +        } else { +            i = ((uint32_t)(0xffffffff))>>(j0-20); +            if((i1&i)==0) return x;     /* x is integral */ +            if(huge+x>0.0)              /* raise inexact flag */ +                i1 &= (~i); +        } +        INSERT_WORDS(x,i0,i1); +        return x; +} diff --git a/src/math/s_truncf.c b/src/math/s_truncf.c new file mode 100644 index 00000000..c253e62b --- /dev/null +++ b/src/math/s_truncf.c @@ -0,0 +1,50 @@ +/* @(#)s_floor.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * truncf(x) + * Return x rounded toward 0 to integral value + * Method: + *      Bit twiddling. + * Exception: + *      Inexact flag raised if x not equal to truncf(x). + */ + +#include <math.h> +#include "math_private.h" + +static const float huge = 1.0e30F; + +float +truncf(float x) +{ +        int32_t i0,j0; +        uint32_t i; +        GET_FLOAT_WORD(i0,x); +        j0 = ((i0>>23)&0xff)-0x7f; +        if(j0<23) { +            if(j0<0) {  /* raise inexact if x != 0 */ +                if(huge+x>0.0F)         /* |x|<1, so return 0*sign(x) */ +                    i0 &= 0x80000000; +            } else { +                i = (0x007fffff)>>j0; +                if((i0&i)==0) return x; /* x is integral */ +                if(huge+x>0.0F)         /* raise inexact flag */ +                    i0 &= (~i); +            } +        } else { +            if(j0==0x80) return x+x;    /* inf or NaN */ +            else return x;              /* x is integral */ +        } +        SET_FLOAT_WORD(x,i0); +        return x; +} diff --git a/src/misc/basename.c b/src/misc/basename.c new file mode 100644 index 00000000..c87e00cd --- /dev/null +++ b/src/misc/basename.c @@ -0,0 +1,12 @@ +#include <string.h> +#include <libgen.h> + +char *basename(char *s) +{ +	size_t i; +	if (!s || !*s) return "."; +	i = strlen(s)-1; +	for (; i&&s[i]=='/'; i--) s[i] = 0; +	for (; i&&s[i-1]!='/'; i--); +	return s+i; +} diff --git a/src/misc/bswap_32.c b/src/misc/bswap_32.c new file mode 100644 index 00000000..a2418ca9 --- /dev/null +++ b/src/misc/bswap_32.c @@ -0,0 +1,7 @@ +#include <endian.h> +#include <stdint.h> + +uint32_t bswap_32(uint32_t x) +{ +	return x>>24 | x>>16&0xff00 | x<<16&0xff0000 | x<<24; +} diff --git a/src/misc/bswap_64.c b/src/misc/bswap_64.c new file mode 100644 index 00000000..961300b5 --- /dev/null +++ b/src/misc/bswap_64.c @@ -0,0 +1,9 @@ +#include <endian.h> +#include <stdint.h> + +uint32_t bswap_32(uint32_t); + +uint64_t bswap_64(uint64_t x) +{ +	return bswap_32(x)+0LL<<32 | bswap_32(x>>32); +} diff --git a/src/misc/crypt.c b/src/misc/crypt.c new file mode 100644 index 00000000..42918ef0 --- /dev/null +++ b/src/misc/crypt.c @@ -0,0 +1,2578 @@ +/* + * FreeSec: libcrypt for NetBSD + * + * Copyright (c) 1994 David Burren + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of other contributors + *    may be used to endorse or promote products derived from this software + *    without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This is an original implementation of the DES and the crypt(3) interfaces + * by David Burren <davidb@werj.com.au>. + * + * An excellent reference on the underlying algorithm (and related + * algorithms) is: + * + *	B. Schneier, Applied Cryptography: protocols, algorithms, + *	and source code in C, John Wiley & Sons, 1994. + * + * Note that in that book's description of DES the lookups for the initial, + * pbox, and final permutations are inverted (this has been brought to the + * attention of the author).  A list of errata for this book has been + * posted to the sci.crypt newsgroup by the author and is available for FTP. + * + * ARCHITECTURE ASSUMPTIONS: + *	It is assumed that the 8-byte arrays passed by reference can be + *	addressed as arrays of uint32_t's (ie. the CPU is not picky about + *	alignment). + */ + +#include <stdint.h> +#include "libc.h" + +static int i64c(int i) +{ +	i &= 0x3f; +	if (i == 0) +		return '.'; +	if (i == 1) +		return '/'; +	if (i < 12) +		return ('0' - 2 + i); +	if (i < 38) +		return ('A' - 12 + i); +	return ('a' - 38 + i); +} + +/* Generated by const_des_init() (removed) */ + +static const uint8_t final_perm[64] = { +	0x39, 0x31, 0x29, 0x21, 0x19, 0x11, 0x09, 0x01, 0x3b, 0x33, 0x2b, 0x23, 0x1b, 0x13, 0x0b, 0x03, +	0x3d, 0x35, 0x2d, 0x25, 0x1d, 0x15, 0x0d, 0x05, 0x3f, 0x37, 0x2f, 0x27, 0x1f, 0x17, 0x0f, 0x07, +	0x38, 0x30, 0x28, 0x20, 0x18, 0x10, 0x08, 0x00, 0x3a, 0x32, 0x2a, 0x22, 0x1a, 0x12, 0x0a, 0x02, +	0x3c, 0x34, 0x2c, 0x24, 0x1c, 0x14, 0x0c, 0x04, 0x3e, 0x36, 0x2e, 0x26, 0x1e, 0x16, 0x0e, 0x06, +}; +static const uint8_t m_sbox[4][4096] = { +	{ +		0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7, +		0xe6, 0xef, 0xeb, 0xe2, 0xe3, 0xe8, 0xe4, 0xee, +		0xe9, 0xec, 0xe7, 0xe0, 0xe2, 0xe1, 0xed, 0xea, +		0xec, 0xe6, 0xe0, 0xe9, 0xe5, 0xeb, 0xea, 0xe5, +		0xe0, 0xed, 0xee, 0xe8, 0xe7, 0xea, 0xeb, 0xe1, +		0xea, 0xe3, 0xe4, 0xef, 0xed, 0xe4, 0xe1, 0xe2, +		0xe5, 0xeb, 0xe8, 0xe6, 0xec, 0xe7, 0xe6, 0xec, +		0xe9, 0xe0, 0xe3, 0xe5, 0xe2, 0xee, 0xef, 0xe9, +		0x0f, 0x03, 0x01, 0x0d, 0x08, 0x04, 0x0e, 0x07, +		0x06, 0x0f, 0x0b, 0x02, 0x03, 0x08, 0x04, 0x0e, +		0x09, 0x0c, 0x07, 0x00, 0x02, 0x01, 0x0d, 0x0a, +		0x0c, 0x06, 0x00, 0x09, 0x05, 0x0b, 0x0a, 0x05, +		0x00, 0x0d, 0x0e, 0x08, 0x07, 0x0a, 0x0b, 0x01, +		0x0a, 0x03, 0x04, 0x0f, 0x0d, 0x04, 0x01, 0x02, +		0x05, 0x0b, 0x08, 0x06, 0x0c, 0x07, 0x06, 0x0c, +		0x09, 0x00, 0x03, 0x05, 0x02, 0x0e, 0x0f, 0x09, +		0x4f, 0x43, 0x41, 0x4d, 0x48, 0x44, 0x4e, 0x47, +		0x46, 0x4f, 0x4b, 0x42, 0x43, 0x48, 0x44, 0x4e, +		0x49, 0x4c, 0x47, 0x40, 0x42, 0x41, 0x4d, 0x4a, +		0x4c, 0x46, 0x40, 0x49, 0x45, 0x4b, 0x4a, 0x45, +		0x40, 0x4d, 0x4e, 0x48, 0x47, 0x4a, 0x4b, 0x41, +		0x4a, 0x43, 0x44, 0x4f, 0x4d, 0x44, 0x41, 0x42, +		0x45, 0x4b, 0x48, 0x46, 0x4c, 0x47, 0x46, 0x4c, +		0x49, 0x40, 0x43, 0x45, 0x42, 0x4e, 0x4f, 0x49, +		0xff, 0xf3, 0xf1, 0xfd, 0xf8, 0xf4, 0xfe, 0xf7, +		0xf6, 0xff, 0xfb, 0xf2, 0xf3, 0xf8, 0xf4, 0xfe, +		0xf9, 0xfc, 0xf7, 0xf0, 0xf2, 0xf1, 0xfd, 0xfa, +		0xfc, 0xf6, 0xf0, 0xf9, 0xf5, 0xfb, 0xfa, 0xf5, +		0xf0, 0xfd, 0xfe, 0xf8, 0xf7, 0xfa, 0xfb, 0xf1, +		0xfa, 0xf3, 0xf4, 0xff, 0xfd, 0xf4, 0xf1, 0xf2, +		0xf5, 0xfb, 0xf8, 0xf6, 0xfc, 0xf7, 0xf6, 0xfc, +		0xf9, 0xf0, 0xf3, 0xf5, 0xf2, 0xfe, 0xff, 0xf9, +		0xdf, 0xd3, 0xd1, 0xdd, 0xd8, 0xd4, 0xde, 0xd7, +		0xd6, 0xdf, 0xdb, 0xd2, 0xd3, 0xd8, 0xd4, 0xde, +		0xd9, 0xdc, 0xd7, 0xd0, 0xd2, 0xd1, 0xdd, 0xda, +		0xdc, 0xd6, 0xd0, 0xd9, 0xd5, 0xdb, 0xda, 0xd5, +		0xd0, 0xdd, 0xde, 0xd8, 0xd7, 0xda, 0xdb, 0xd1, +		0xda, 0xd3, 0xd4, 0xdf, 0xdd, 0xd4, 0xd1, 0xd2, +		0xd5, 0xdb, 0xd8, 0xd6, 0xdc, 0xd7, 0xd6, 0xdc, +		0xd9, 0xd0, 0xd3, 0xd5, 0xd2, 0xde, 0xdf, 0xd9, +		0x7f, 0x73, 0x71, 0x7d, 0x78, 0x74, 0x7e, 0x77, +		0x76, 0x7f, 0x7b, 0x72, 0x73, 0x78, 0x74, 0x7e, +		0x79, 0x7c, 0x77, 0x70, 0x72, 0x71, 0x7d, 0x7a, +		0x7c, 0x76, 0x70, 0x79, 0x75, 0x7b, 0x7a, 0x75, +		0x70, 0x7d, 0x7e, 0x78, 0x77, 0x7a, 0x7b, 0x71, +		0x7a, 0x73, 0x74, 0x7f, 0x7d, 0x74, 0x71, 0x72, +		0x75, 0x7b, 0x78, 0x76, 0x7c, 0x77, 0x76, 0x7c, +		0x79, 0x70, 0x73, 0x75, 0x72, 0x7e, 0x7f, 0x79, +		0x1f, 0x13, 0x11, 0x1d, 0x18, 0x14, 0x1e, 0x17, +		0x16, 0x1f, 0x1b, 0x12, 0x13, 0x18, 0x14, 0x1e, +		0x19, 0x1c, 0x17, 0x10, 0x12, 0x11, 0x1d, 0x1a, +		0x1c, 0x16, 0x10, 0x19, 0x15, 0x1b, 0x1a, 0x15, +		0x10, 0x1d, 0x1e, 0x18, 0x17, 0x1a, 0x1b, 0x11, +		0x1a, 0x13, 0x14, 0x1f, 0x1d, 0x14, 0x11, 0x12, +		0x15, 0x1b, 0x18, 0x16, 0x1c, 0x17, 0x16, 0x1c, +		0x19, 0x10, 0x13, 0x15, 0x12, 0x1e, 0x1f, 0x19, +		0x4f, 0x43, 0x41, 0x4d, 0x48, 0x44, 0x4e, 0x47, +		0x46, 0x4f, 0x4b, 0x42, 0x43, 0x48, 0x44, 0x4e, +		0x49, 0x4c, 0x47, 0x40, 0x42, 0x41, 0x4d, 0x4a, +		0x4c, 0x46, 0x40, 0x49, 0x45, 0x4b, 0x4a, 0x45, +		0x40, 0x4d, 0x4e, 0x48, 0x47, 0x4a, 0x4b, 0x41, +		0x4a, 0x43, 0x44, 0x4f, 0x4d, 0x44, 0x41, 0x42, +		0x45, 0x4b, 0x48, 0x46, 0x4c, 0x47, 0x46, 0x4c, +		0x49, 0x40, 0x43, 0x45, 0x42, 0x4e, 0x4f, 0x49, +		0x2f, 0x23, 0x21, 0x2d, 0x28, 0x24, 0x2e, 0x27, +		0x26, 0x2f, 0x2b, 0x22, 0x23, 0x28, 0x24, 0x2e, +		0x29, 0x2c, 0x27, 0x20, 0x22, 0x21, 0x2d, 0x2a, +		0x2c, 0x26, 0x20, 0x29, 0x25, 0x2b, 0x2a, 0x25, +		0x20, 0x2d, 0x2e, 0x28, 0x27, 0x2a, 0x2b, 0x21, +		0x2a, 0x23, 0x24, 0x2f, 0x2d, 0x24, 0x21, 0x22, +		0x25, 0x2b, 0x28, 0x26, 0x2c, 0x27, 0x26, 0x2c, +		0x29, 0x20, 0x23, 0x25, 0x22, 0x2e, 0x2f, 0x29, +		0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7, +		0xe6, 0xef, 0xeb, 0xe2, 0xe3, 0xe8, 0xe4, 0xee, +		0xe9, 0xec, 0xe7, 0xe0, 0xe2, 0xe1, 0xed, 0xea, +		0xec, 0xe6, 0xe0, 0xe9, 0xe5, 0xeb, 0xea, 0xe5, +		0xe0, 0xed, 0xee, 0xe8, 0xe7, 0xea, 0xeb, 0xe1, +		0xea, 0xe3, 0xe4, 0xef, 0xed, 0xe4, 0xe1, 0xe2, +		0xe5, 0xeb, 0xe8, 0xe6, 0xec, 0xe7, 0xe6, 0xec, +		0xe9, 0xe0, 0xe3, 0xe5, 0xe2, 0xee, 0xef, 0xe9, +		0xff, 0xf3, 0xf1, 0xfd, 0xf8, 0xf4, 0xfe, 0xf7, +		0xf6, 0xff, 0xfb, 0xf2, 0xf3, 0xf8, 0xf4, 0xfe, +		0xf9, 0xfc, 0xf7, 0xf0, 0xf2, 0xf1, 0xfd, 0xfa, +		0xfc, 0xf6, 0xf0, 0xf9, 0xf5, 0xfb, 0xfa, 0xf5, +		0xf0, 0xfd, 0xfe, 0xf8, 0xf7, 0xfa, 0xfb, 0xf1, +		0xfa, 0xf3, 0xf4, 0xff, 0xfd, 0xf4, 0xf1, 0xf2, +		0xf5, 0xfb, 0xf8, 0xf6, 0xfc, 0xf7, 0xf6, 0xfc, +		0xf9, 0xf0, 0xf3, 0xf5, 0xf2, 0xfe, 0xff, 0xf9, +		0x2f, 0x23, 0x21, 0x2d, 0x28, 0x24, 0x2e, 0x27, +		0x26, 0x2f, 0x2b, 0x22, 0x23, 0x28, 0x24, 0x2e, +		0x29, 0x2c, 0x27, 0x20, 0x22, 0x21, 0x2d, 0x2a, +		0x2c, 0x26, 0x20, 0x29, 0x25, 0x2b, 0x2a, 0x25, +		0x20, 0x2d, 0x2e, 0x28, 0x27, 0x2a, 0x2b, 0x21, +		0x2a, 0x23, 0x24, 0x2f, 0x2d, 0x24, 0x21, 0x22, +		0x25, 0x2b, 0x28, 0x26, 0x2c, 0x27, 0x26, 0x2c, +		0x29, 0x20, 0x23, 0x25, 0x22, 0x2e, 0x2f, 0x29, +		0xbf, 0xb3, 0xb1, 0xbd, 0xb8, 0xb4, 0xbe, 0xb7, +		0xb6, 0xbf, 0xbb, 0xb2, 0xb3, 0xb8, 0xb4, 0xbe, +		0xb9, 0xbc, 0xb7, 0xb0, 0xb2, 0xb1, 0xbd, 0xba, +		0xbc, 0xb6, 0xb0, 0xb9, 0xb5, 0xbb, 0xba, 0xb5, +		0xb0, 0xbd, 0xbe, 0xb8, 0xb7, 0xba, 0xbb, 0xb1, +		0xba, 0xb3, 0xb4, 0xbf, 0xbd, 0xb4, 0xb1, 0xb2, +		0xb5, 0xbb, 0xb8, 0xb6, 0xbc, 0xb7, 0xb6, 0xbc, +		0xb9, 0xb0, 0xb3, 0xb5, 0xb2, 0xbe, 0xbf, 0xb9, +		0xdf, 0xd3, 0xd1, 0xdd, 0xd8, 0xd4, 0xde, 0xd7, +		0xd6, 0xdf, 0xdb, 0xd2, 0xd3, 0xd8, 0xd4, 0xde, +		0xd9, 0xdc, 0xd7, 0xd0, 0xd2, 0xd1, 0xdd, 0xda, +		0xdc, 0xd6, 0xd0, 0xd9, 0xd5, 0xdb, 0xda, 0xd5, +		0xd0, 0xdd, 0xde, 0xd8, 0xd7, 0xda, 0xdb, 0xd1, +		0xda, 0xd3, 0xd4, 0xdf, 0xdd, 0xd4, 0xd1, 0xd2, +		0xd5, 0xdb, 0xd8, 0xd6, 0xdc, 0xd7, 0xd6, 0xdc, +		0xd9, 0xd0, 0xd3, 0xd5, 0xd2, 0xde, 0xdf, 0xd9, +		0x8f, 0x83, 0x81, 0x8d, 0x88, 0x84, 0x8e, 0x87, +		0x86, 0x8f, 0x8b, 0x82, 0x83, 0x88, 0x84, 0x8e, +		0x89, 0x8c, 0x87, 0x80, 0x82, 0x81, 0x8d, 0x8a, +		0x8c, 0x86, 0x80, 0x89, 0x85, 0x8b, 0x8a, 0x85, +		0x80, 0x8d, 0x8e, 0x88, 0x87, 0x8a, 0x8b, 0x81, +		0x8a, 0x83, 0x84, 0x8f, 0x8d, 0x84, 0x81, 0x82, +		0x85, 0x8b, 0x88, 0x86, 0x8c, 0x87, 0x86, 0x8c, +		0x89, 0x80, 0x83, 0x85, 0x82, 0x8e, 0x8f, 0x89, +		0x1f, 0x13, 0x11, 0x1d, 0x18, 0x14, 0x1e, 0x17, +		0x16, 0x1f, 0x1b, 0x12, 0x13, 0x18, 0x14, 0x1e, +		0x19, 0x1c, 0x17, 0x10, 0x12, 0x11, 0x1d, 0x1a, +		0x1c, 0x16, 0x10, 0x19, 0x15, 0x1b, 0x1a, 0x15, +		0x10, 0x1d, 0x1e, 0x18, 0x17, 0x1a, 0x1b, 0x11, +		0x1a, 0x13, 0x14, 0x1f, 0x1d, 0x14, 0x11, 0x12, +		0x15, 0x1b, 0x18, 0x16, 0x1c, 0x17, 0x16, 0x1c, +		0x19, 0x10, 0x13, 0x15, 0x12, 0x1e, 0x1f, 0x19, +		0x3f, 0x33, 0x31, 0x3d, 0x38, 0x34, 0x3e, 0x37, +		0x36, 0x3f, 0x3b, 0x32, 0x33, 0x38, 0x34, 0x3e, +		0x39, 0x3c, 0x37, 0x30, 0x32, 0x31, 0x3d, 0x3a, +		0x3c, 0x36, 0x30, 0x39, 0x35, 0x3b, 0x3a, 0x35, +		0x30, 0x3d, 0x3e, 0x38, 0x37, 0x3a, 0x3b, 0x31, +		0x3a, 0x33, 0x34, 0x3f, 0x3d, 0x34, 0x31, 0x32, +		0x35, 0x3b, 0x38, 0x36, 0x3c, 0x37, 0x36, 0x3c, +		0x39, 0x30, 0x33, 0x35, 0x32, 0x3e, 0x3f, 0x39, +		0xaf, 0xa3, 0xa1, 0xad, 0xa8, 0xa4, 0xae, 0xa7, +		0xa6, 0xaf, 0xab, 0xa2, 0xa3, 0xa8, 0xa4, 0xae, +		0xa9, 0xac, 0xa7, 0xa0, 0xa2, 0xa1, 0xad, 0xaa, +		0xac, 0xa6, 0xa0, 0xa9, 0xa5, 0xab, 0xaa, 0xa5, +		0xa0, 0xad, 0xae, 0xa8, 0xa7, 0xaa, 0xab, 0xa1, +		0xaa, 0xa3, 0xa4, 0xaf, 0xad, 0xa4, 0xa1, 0xa2, +		0xa5, 0xab, 0xa8, 0xa6, 0xac, 0xa7, 0xa6, 0xac, +		0xa9, 0xa0, 0xa3, 0xa5, 0xa2, 0xae, 0xaf, 0xa9, +		0xaf, 0xa3, 0xa1, 0xad, 0xa8, 0xa4, 0xae, 0xa7, +		0xa6, 0xaf, 0xab, 0xa2, 0xa3, 0xa8, 0xa4, 0xae, +		0xa9, 0xac, 0xa7, 0xa0, 0xa2, 0xa1, 0xad, 0xaa, +		0xac, 0xa6, 0xa0, 0xa9, 0xa5, 0xab, 0xaa, 0xa5, +		0xa0, 0xad, 0xae, 0xa8, 0xa7, 0xaa, 0xab, 0xa1, +		0xaa, 0xa3, 0xa4, 0xaf, 0xad, 0xa4, 0xa1, 0xa2, +		0xa5, 0xab, 0xa8, 0xa6, 0xac, 0xa7, 0xa6, 0xac, +		0xa9, 0xa0, 0xa3, 0xa5, 0xa2, 0xae, 0xaf, 0xa9, +		0x6f, 0x63, 0x61, 0x6d, 0x68, 0x64, 0x6e, 0x67, +		0x66, 0x6f, 0x6b, 0x62, 0x63, 0x68, 0x64, 0x6e, +		0x69, 0x6c, 0x67, 0x60, 0x62, 0x61, 0x6d, 0x6a, +		0x6c, 0x66, 0x60, 0x69, 0x65, 0x6b, 0x6a, 0x65, +		0x60, 0x6d, 0x6e, 0x68, 0x67, 0x6a, 0x6b, 0x61, +		0x6a, 0x63, 0x64, 0x6f, 0x6d, 0x64, 0x61, 0x62, +		0x65, 0x6b, 0x68, 0x66, 0x6c, 0x67, 0x66, 0x6c, +		0x69, 0x60, 0x63, 0x65, 0x62, 0x6e, 0x6f, 0x69, +		0x6f, 0x63, 0x61, 0x6d, 0x68, 0x64, 0x6e, 0x67, +		0x66, 0x6f, 0x6b, 0x62, 0x63, 0x68, 0x64, 0x6e, +		0x69, 0x6c, 0x67, 0x60, 0x62, 0x61, 0x6d, 0x6a, +		0x6c, 0x66, 0x60, 0x69, 0x65, 0x6b, 0x6a, 0x65, +		0x60, 0x6d, 0x6e, 0x68, 0x67, 0x6a, 0x6b, 0x61, +		0x6a, 0x63, 0x64, 0x6f, 0x6d, 0x64, 0x61, 0x62, +		0x65, 0x6b, 0x68, 0x66, 0x6c, 0x67, 0x66, 0x6c, +		0x69, 0x60, 0x63, 0x65, 0x62, 0x6e, 0x6f, 0x69, +		0xcf, 0xc3, 0xc1, 0xcd, 0xc8, 0xc4, 0xce, 0xc7, +		0xc6, 0xcf, 0xcb, 0xc2, 0xc3, 0xc8, 0xc4, 0xce, +		0xc9, 0xcc, 0xc7, 0xc0, 0xc2, 0xc1, 0xcd, 0xca, +		0xcc, 0xc6, 0xc0, 0xc9, 0xc5, 0xcb, 0xca, 0xc5, +		0xc0, 0xcd, 0xce, 0xc8, 0xc7, 0xca, 0xcb, 0xc1, +		0xca, 0xc3, 0xc4, 0xcf, 0xcd, 0xc4, 0xc1, 0xc2, +		0xc5, 0xcb, 0xc8, 0xc6, 0xcc, 0xc7, 0xc6, 0xcc, +		0xc9, 0xc0, 0xc3, 0xc5, 0xc2, 0xce, 0xcf, 0xc9, +		0xcf, 0xc3, 0xc1, 0xcd, 0xc8, 0xc4, 0xce, 0xc7, +		0xc6, 0xcf, 0xcb, 0xc2, 0xc3, 0xc8, 0xc4, 0xce, +		0xc9, 0xcc, 0xc7, 0xc0, 0xc2, 0xc1, 0xcd, 0xca, +		0xcc, 0xc6, 0xc0, 0xc9, 0xc5, 0xcb, 0xca, 0xc5, +		0xc0, 0xcd, 0xce, 0xc8, 0xc7, 0xca, 0xcb, 0xc1, +		0xca, 0xc3, 0xc4, 0xcf, 0xcd, 0xc4, 0xc1, 0xc2, +		0xc5, 0xcb, 0xc8, 0xc6, 0xcc, 0xc7, 0xc6, 0xcc, +		0xc9, 0xc0, 0xc3, 0xc5, 0xc2, 0xce, 0xcf, 0xc9, +		0xbf, 0xb3, 0xb1, 0xbd, 0xb8, 0xb4, 0xbe, 0xb7, +		0xb6, 0xbf, 0xbb, 0xb2, 0xb3, 0xb8, 0xb4, 0xbe, +		0xb9, 0xbc, 0xb7, 0xb0, 0xb2, 0xb1, 0xbd, 0xba, +		0xbc, 0xb6, 0xb0, 0xb9, 0xb5, 0xbb, 0xba, 0xb5, +		0xb0, 0xbd, 0xbe, 0xb8, 0xb7, 0xba, 0xbb, 0xb1, +		0xba, 0xb3, 0xb4, 0xbf, 0xbd, 0xb4, 0xb1, 0xb2, +		0xb5, 0xbb, 0xb8, 0xb6, 0xbc, 0xb7, 0xb6, 0xbc, +		0xb9, 0xb0, 0xb3, 0xb5, 0xb2, 0xbe, 0xbf, 0xb9, +		0x5f, 0x53, 0x51, 0x5d, 0x58, 0x54, 0x5e, 0x57, +		0x56, 0x5f, 0x5b, 0x52, 0x53, 0x58, 0x54, 0x5e, +		0x59, 0x5c, 0x57, 0x50, 0x52, 0x51, 0x5d, 0x5a, +		0x5c, 0x56, 0x50, 0x59, 0x55, 0x5b, 0x5a, 0x55, +		0x50, 0x5d, 0x5e, 0x58, 0x57, 0x5a, 0x5b, 0x51, +		0x5a, 0x53, 0x54, 0x5f, 0x5d, 0x54, 0x51, 0x52, +		0x55, 0x5b, 0x58, 0x56, 0x5c, 0x57, 0x56, 0x5c, +		0x59, 0x50, 0x53, 0x55, 0x52, 0x5e, 0x5f, 0x59, +		0x9f, 0x93, 0x91, 0x9d, 0x98, 0x94, 0x9e, 0x97, +		0x96, 0x9f, 0x9b, 0x92, 0x93, 0x98, 0x94, 0x9e, +		0x99, 0x9c, 0x97, 0x90, 0x92, 0x91, 0x9d, 0x9a, +		0x9c, 0x96, 0x90, 0x99, 0x95, 0x9b, 0x9a, 0x95, +		0x90, 0x9d, 0x9e, 0x98, 0x97, 0x9a, 0x9b, 0x91, +		0x9a, 0x93, 0x94, 0x9f, 0x9d, 0x94, 0x91, 0x92, +		0x95, 0x9b, 0x98, 0x96, 0x9c, 0x97, 0x96, 0x9c, +		0x99, 0x90, 0x93, 0x95, 0x92, 0x9e, 0x9f, 0x99, +		0x9f, 0x93, 0x91, 0x9d, 0x98, 0x94, 0x9e, 0x97, +		0x96, 0x9f, 0x9b, 0x92, 0x93, 0x98, 0x94, 0x9e, +		0x99, 0x9c, 0x97, 0x90, 0x92, 0x91, 0x9d, 0x9a, +		0x9c, 0x96, 0x90, 0x99, 0x95, 0x9b, 0x9a, 0x95, +		0x90, 0x9d, 0x9e, 0x98, 0x97, 0x9a, 0x9b, 0x91, +		0x9a, 0x93, 0x94, 0x9f, 0x9d, 0x94, 0x91, 0x92, +		0x95, 0x9b, 0x98, 0x96, 0x9c, 0x97, 0x96, 0x9c, +		0x99, 0x90, 0x93, 0x95, 0x92, 0x9e, 0x9f, 0x99, +		0x5f, 0x53, 0x51, 0x5d, 0x58, 0x54, 0x5e, 0x57, +		0x56, 0x5f, 0x5b, 0x52, 0x53, 0x58, 0x54, 0x5e, +		0x59, 0x5c, 0x57, 0x50, 0x52, 0x51, 0x5d, 0x5a, +		0x5c, 0x56, 0x50, 0x59, 0x55, 0x5b, 0x5a, 0x55, +		0x50, 0x5d, 0x5e, 0x58, 0x57, 0x5a, 0x5b, 0x51, +		0x5a, 0x53, 0x54, 0x5f, 0x5d, 0x54, 0x51, 0x52, +		0x55, 0x5b, 0x58, 0x56, 0x5c, 0x57, 0x56, 0x5c, +		0x59, 0x50, 0x53, 0x55, 0x52, 0x5e, 0x5f, 0x59, +		0x0f, 0x03, 0x01, 0x0d, 0x08, 0x04, 0x0e, 0x07, +		0x06, 0x0f, 0x0b, 0x02, 0x03, 0x08, 0x04, 0x0e, +		0x09, 0x0c, 0x07, 0x00, 0x02, 0x01, 0x0d, 0x0a, +		0x0c, 0x06, 0x00, 0x09, 0x05, 0x0b, 0x0a, 0x05, +		0x00, 0x0d, 0x0e, 0x08, 0x07, 0x0a, 0x0b, 0x01, +		0x0a, 0x03, 0x04, 0x0f, 0x0d, 0x04, 0x01, 0x02, +		0x05, 0x0b, 0x08, 0x06, 0x0c, 0x07, 0x06, 0x0c, +		0x09, 0x00, 0x03, 0x05, 0x02, 0x0e, 0x0f, 0x09, +		0x3f, 0x33, 0x31, 0x3d, 0x38, 0x34, 0x3e, 0x37, +		0x36, 0x3f, 0x3b, 0x32, 0x33, 0x38, 0x34, 0x3e, +		0x39, 0x3c, 0x37, 0x30, 0x32, 0x31, 0x3d, 0x3a, +		0x3c, 0x36, 0x30, 0x39, 0x35, 0x3b, 0x3a, 0x35, +		0x30, 0x3d, 0x3e, 0x38, 0x37, 0x3a, 0x3b, 0x31, +		0x3a, 0x33, 0x34, 0x3f, 0x3d, 0x34, 0x31, 0x32, +		0x35, 0x3b, 0x38, 0x36, 0x3c, 0x37, 0x36, 0x3c, +		0x39, 0x30, 0x33, 0x35, 0x32, 0x3e, 0x3f, 0x39, +		0x7f, 0x73, 0x71, 0x7d, 0x78, 0x74, 0x7e, 0x77, +		0x76, 0x7f, 0x7b, 0x72, 0x73, 0x78, 0x74, 0x7e, +		0x79, 0x7c, 0x77, 0x70, 0x72, 0x71, 0x7d, 0x7a, +		0x7c, 0x76, 0x70, 0x79, 0x75, 0x7b, 0x7a, 0x75, +		0x70, 0x7d, 0x7e, 0x78, 0x77, 0x7a, 0x7b, 0x71, +		0x7a, 0x73, 0x74, 0x7f, 0x7d, 0x74, 0x71, 0x72, +		0x75, 0x7b, 0x78, 0x76, 0x7c, 0x77, 0x76, 0x7c, +		0x79, 0x70, 0x73, 0x75, 0x72, 0x7e, 0x7f, 0x79, +		0x8f, 0x83, 0x81, 0x8d, 0x88, 0x84, 0x8e, 0x87, +		0x86, 0x8f, 0x8b, 0x82, 0x83, 0x88, 0x84, 0x8e, +		0x89, 0x8c, 0x87, 0x80, 0x82, 0x81, 0x8d, 0x8a, +		0x8c, 0x86, 0x80, 0x89, 0x85, 0x8b, 0x8a, 0x85, +		0x80, 0x8d, 0x8e, 0x88, 0x87, 0x8a, 0x8b, 0x81, +		0x8a, 0x83, 0x84, 0x8f, 0x8d, 0x84, 0x81, 0x82, +		0x85, 0x8b, 0x88, 0x86, 0x8c, 0x87, 0x86, 0x8c, +		0x89, 0x80, 0x83, 0x85, 0x82, 0x8e, 0x8f, 0x89, +		0x4f, 0x43, 0x41, 0x4d, 0x48, 0x44, 0x4e, 0x47, +		0x46, 0x4f, 0x4b, 0x42, 0x43, 0x48, 0x44, 0x4e, +		0x49, 0x4c, 0x47, 0x40, 0x42, 0x41, 0x4d, 0x4a, +		0x4c, 0x46, 0x40, 0x49, 0x45, 0x4b, 0x4a, 0x45, +		0x40, 0x4d, 0x4e, 0x48, 0x47, 0x4a, 0x4b, 0x41, +		0x4a, 0x43, 0x44, 0x4f, 0x4d, 0x44, 0x41, 0x42, +		0x45, 0x4b, 0x48, 0x46, 0x4c, 0x47, 0x46, 0x4c, +		0x49, 0x40, 0x43, 0x45, 0x42, 0x4e, 0x4f, 0x49, +		0xff, 0xf3, 0xf1, 0xfd, 0xf8, 0xf4, 0xfe, 0xf7, +		0xf6, 0xff, 0xfb, 0xf2, 0xf3, 0xf8, 0xf4, 0xfe, +		0xf9, 0xfc, 0xf7, 0xf0, 0xf2, 0xf1, 0xfd, 0xfa, +		0xfc, 0xf6, 0xf0, 0xf9, 0xf5, 0xfb, 0xfa, 0xf5, +		0xf0, 0xfd, 0xfe, 0xf8, 0xf7, 0xfa, 0xfb, 0xf1, +		0xfa, 0xf3, 0xf4, 0xff, 0xfd, 0xf4, 0xf1, 0xf2, +		0xf5, 0xfb, 0xf8, 0xf6, 0xfc, 0xf7, 0xf6, 0xfc, +		0xf9, 0xf0, 0xf3, 0xf5, 0xf2, 0xfe, 0xff, 0xf9, +		0x1f, 0x13, 0x11, 0x1d, 0x18, 0x14, 0x1e, 0x17, +		0x16, 0x1f, 0x1b, 0x12, 0x13, 0x18, 0x14, 0x1e, +		0x19, 0x1c, 0x17, 0x10, 0x12, 0x11, 0x1d, 0x1a, +		0x1c, 0x16, 0x10, 0x19, 0x15, 0x1b, 0x1a, 0x15, +		0x10, 0x1d, 0x1e, 0x18, 0x17, 0x1a, 0x1b, 0x11, +		0x1a, 0x13, 0x14, 0x1f, 0x1d, 0x14, 0x11, 0x12, +		0x15, 0x1b, 0x18, 0x16, 0x1c, 0x17, 0x16, 0x1c, +		0x19, 0x10, 0x13, 0x15, 0x12, 0x1e, 0x1f, 0x19, +		0xcf, 0xc3, 0xc1, 0xcd, 0xc8, 0xc4, 0xce, 0xc7, +		0xc6, 0xcf, 0xcb, 0xc2, 0xc3, 0xc8, 0xc4, 0xce, +		0xc9, 0xcc, 0xc7, 0xc0, 0xc2, 0xc1, 0xcd, 0xca, +		0xcc, 0xc6, 0xc0, 0xc9, 0xc5, 0xcb, 0xca, 0xc5, +		0xc0, 0xcd, 0xce, 0xc8, 0xc7, 0xca, 0xcb, 0xc1, +		0xca, 0xc3, 0xc4, 0xcf, 0xcd, 0xc4, 0xc1, 0xc2, +		0xc5, 0xcb, 0xc8, 0xc6, 0xcc, 0xc7, 0xc6, 0xcc, +		0xc9, 0xc0, 0xc3, 0xc5, 0xc2, 0xce, 0xcf, 0xc9, +		0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7, +		0xe6, 0xef, 0xeb, 0xe2, 0xe3, 0xe8, 0xe4, 0xee, +		0xe9, 0xec, 0xe7, 0xe0, 0xe2, 0xe1, 0xed, 0xea, +		0xec, 0xe6, 0xe0, 0xe9, 0xe5, 0xeb, 0xea, 0xe5, +		0xe0, 0xed, 0xee, 0xe8, 0xe7, 0xea, 0xeb, 0xe1, +		0xea, 0xe3, 0xe4, 0xef, 0xed, 0xe4, 0xe1, 0xe2, +		0xe5, 0xeb, 0xe8, 0xe6, 0xec, 0xe7, 0xe6, 0xec, +		0xe9, 0xe0, 0xe3, 0xe5, 0xe2, 0xee, 0xef, 0xe9, +		0x8f, 0x83, 0x81, 0x8d, 0x88, 0x84, 0x8e, 0x87, +		0x86, 0x8f, 0x8b, 0x82, 0x83, 0x88, 0x84, 0x8e, +		0x89, 0x8c, 0x87, 0x80, 0x82, 0x81, 0x8d, 0x8a, +		0x8c, 0x86, 0x80, 0x89, 0x85, 0x8b, 0x8a, 0x85, +		0x80, 0x8d, 0x8e, 0x88, 0x87, 0x8a, 0x8b, 0x81, +		0x8a, 0x83, 0x84, 0x8f, 0x8d, 0x84, 0x81, 0x82, +		0x85, 0x8b, 0x88, 0x86, 0x8c, 0x87, 0x86, 0x8c, +		0x89, 0x80, 0x83, 0x85, 0x82, 0x8e, 0x8f, 0x89, +		0x8f, 0x83, 0x81, 0x8d, 0x88, 0x84, 0x8e, 0x87, +		0x86, 0x8f, 0x8b, 0x82, 0x83, 0x88, 0x84, 0x8e, +		0x89, 0x8c, 0x87, 0x80, 0x82, 0x81, 0x8d, 0x8a, +		0x8c, 0x86, 0x80, 0x89, 0x85, 0x8b, 0x8a, 0x85, +		0x80, 0x8d, 0x8e, 0x88, 0x87, 0x8a, 0x8b, 0x81, +		0x8a, 0x83, 0x84, 0x8f, 0x8d, 0x84, 0x81, 0x82, +		0x85, 0x8b, 0x88, 0x86, 0x8c, 0x87, 0x86, 0x8c, +		0x89, 0x80, 0x83, 0x85, 0x82, 0x8e, 0x8f, 0x89, +		0x2f, 0x23, 0x21, 0x2d, 0x28, 0x24, 0x2e, 0x27, +		0x26, 0x2f, 0x2b, 0x22, 0x23, 0x28, 0x24, 0x2e, +		0x29, 0x2c, 0x27, 0x20, 0x22, 0x21, 0x2d, 0x2a, +		0x2c, 0x26, 0x20, 0x29, 0x25, 0x2b, 0x2a, 0x25, +		0x20, 0x2d, 0x2e, 0x28, 0x27, 0x2a, 0x2b, 0x21, +		0x2a, 0x23, 0x24, 0x2f, 0x2d, 0x24, 0x21, 0x22, +		0x25, 0x2b, 0x28, 0x26, 0x2c, 0x27, 0x26, 0x2c, +		0x29, 0x20, 0x23, 0x25, 0x22, 0x2e, 0x2f, 0x29, +		0xdf, 0xd3, 0xd1, 0xdd, 0xd8, 0xd4, 0xde, 0xd7, +		0xd6, 0xdf, 0xdb, 0xd2, 0xd3, 0xd8, 0xd4, 0xde, +		0xd9, 0xdc, 0xd7, 0xd0, 0xd2, 0xd1, 0xdd, 0xda, +		0xdc, 0xd6, 0xd0, 0xd9, 0xd5, 0xdb, 0xda, 0xd5, +		0xd0, 0xdd, 0xde, 0xd8, 0xd7, 0xda, 0xdb, 0xd1, +		0xda, 0xd3, 0xd4, 0xdf, 0xdd, 0xd4, 0xd1, 0xd2, +		0xd5, 0xdb, 0xd8, 0xd6, 0xdc, 0xd7, 0xd6, 0xdc, +		0xd9, 0xd0, 0xd3, 0xd5, 0xd2, 0xde, 0xdf, 0xd9, +		0x4f, 0x43, 0x41, 0x4d, 0x48, 0x44, 0x4e, 0x47, +		0x46, 0x4f, 0x4b, 0x42, 0x43, 0x48, 0x44, 0x4e, +		0x49, 0x4c, 0x47, 0x40, 0x42, 0x41, 0x4d, 0x4a, +		0x4c, 0x46, 0x40, 0x49, 0x45, 0x4b, 0x4a, 0x45, +		0x40, 0x4d, 0x4e, 0x48, 0x47, 0x4a, 0x4b, 0x41, +		0x4a, 0x43, 0x44, 0x4f, 0x4d, 0x44, 0x41, 0x42, +		0x45, 0x4b, 0x48, 0x46, 0x4c, 0x47, 0x46, 0x4c, +		0x49, 0x40, 0x43, 0x45, 0x42, 0x4e, 0x4f, 0x49, +		0x6f, 0x63, 0x61, 0x6d, 0x68, 0x64, 0x6e, 0x67, +		0x66, 0x6f, 0x6b, 0x62, 0x63, 0x68, 0x64, 0x6e, +		0x69, 0x6c, 0x67, 0x60, 0x62, 0x61, 0x6d, 0x6a, +		0x6c, 0x66, 0x60, 0x69, 0x65, 0x6b, 0x6a, 0x65, +		0x60, 0x6d, 0x6e, 0x68, 0x67, 0x6a, 0x6b, 0x61, +		0x6a, 0x63, 0x64, 0x6f, 0x6d, 0x64, 0x61, 0x62, +		0x65, 0x6b, 0x68, 0x66, 0x6c, 0x67, 0x66, 0x6c, +		0x69, 0x60, 0x63, 0x65, 0x62, 0x6e, 0x6f, 0x69, +		0x9f, 0x93, 0x91, 0x9d, 0x98, 0x94, 0x9e, 0x97, +		0x96, 0x9f, 0x9b, 0x92, 0x93, 0x98, 0x94, 0x9e, +		0x99, 0x9c, 0x97, 0x90, 0x92, 0x91, 0x9d, 0x9a, +		0x9c, 0x96, 0x90, 0x99, 0x95, 0x9b, 0x9a, 0x95, +		0x90, 0x9d, 0x9e, 0x98, 0x97, 0x9a, 0x9b, 0x91, +		0x9a, 0x93, 0x94, 0x9f, 0x9d, 0x94, 0x91, 0x92, +		0x95, 0x9b, 0x98, 0x96, 0x9c, 0x97, 0x96, 0x9c, +		0x99, 0x90, 0x93, 0x95, 0x92, 0x9e, 0x9f, 0x99, +		0x2f, 0x23, 0x21, 0x2d, 0x28, 0x24, 0x2e, 0x27, +		0x26, 0x2f, 0x2b, 0x22, 0x23, 0x28, 0x24, 0x2e, +		0x29, 0x2c, 0x27, 0x20, 0x22, 0x21, 0x2d, 0x2a, +		0x2c, 0x26, 0x20, 0x29, 0x25, 0x2b, 0x2a, 0x25, +		0x20, 0x2d, 0x2e, 0x28, 0x27, 0x2a, 0x2b, 0x21, +		0x2a, 0x23, 0x24, 0x2f, 0x2d, 0x24, 0x21, 0x22, +		0x25, 0x2b, 0x28, 0x26, 0x2c, 0x27, 0x26, 0x2c, +		0x29, 0x20, 0x23, 0x25, 0x22, 0x2e, 0x2f, 0x29, +		0x1f, 0x13, 0x11, 0x1d, 0x18, 0x14, 0x1e, 0x17, +		0x16, 0x1f, 0x1b, 0x12, 0x13, 0x18, 0x14, 0x1e, +		0x19, 0x1c, 0x17, 0x10, 0x12, 0x11, 0x1d, 0x1a, +		0x1c, 0x16, 0x10, 0x19, 0x15, 0x1b, 0x1a, 0x15, +		0x10, 0x1d, 0x1e, 0x18, 0x17, 0x1a, 0x1b, 0x11, +		0x1a, 0x13, 0x14, 0x1f, 0x1d, 0x14, 0x11, 0x12, +		0x15, 0x1b, 0x18, 0x16, 0x1c, 0x17, 0x16, 0x1c, +		0x19, 0x10, 0x13, 0x15, 0x12, 0x1e, 0x1f, 0x19, +		0xbf, 0xb3, 0xb1, 0xbd, 0xb8, 0xb4, 0xbe, 0xb7, +		0xb6, 0xbf, 0xbb, 0xb2, 0xb3, 0xb8, 0xb4, 0xbe, +		0xb9, 0xbc, 0xb7, 0xb0, 0xb2, 0xb1, 0xbd, 0xba, +		0xbc, 0xb6, 0xb0, 0xb9, 0xb5, 0xbb, 0xba, 0xb5, +		0xb0, 0xbd, 0xbe, 0xb8, 0xb7, 0xba, 0xbb, 0xb1, +		0xba, 0xb3, 0xb4, 0xbf, 0xbd, 0xb4, 0xb1, 0xb2, +		0xb5, 0xbb, 0xb8, 0xb6, 0xbc, 0xb7, 0xb6, 0xbc, +		0xb9, 0xb0, 0xb3, 0xb5, 0xb2, 0xbe, 0xbf, 0xb9, +		0x7f, 0x73, 0x71, 0x7d, 0x78, 0x74, 0x7e, 0x77, +		0x76, 0x7f, 0x7b, 0x72, 0x73, 0x78, 0x74, 0x7e, +		0x79, 0x7c, 0x77, 0x70, 0x72, 0x71, 0x7d, 0x7a, +		0x7c, 0x76, 0x70, 0x79, 0x75, 0x7b, 0x7a, 0x75, +		0x70, 0x7d, 0x7e, 0x78, 0x77, 0x7a, 0x7b, 0x71, +		0x7a, 0x73, 0x74, 0x7f, 0x7d, 0x74, 0x71, 0x72, +		0x75, 0x7b, 0x78, 0x76, 0x7c, 0x77, 0x76, 0x7c, +		0x79, 0x70, 0x73, 0x75, 0x72, 0x7e, 0x7f, 0x79, +		0xff, 0xf3, 0xf1, 0xfd, 0xf8, 0xf4, 0xfe, 0xf7, +		0xf6, 0xff, 0xfb, 0xf2, 0xf3, 0xf8, 0xf4, 0xfe, +		0xf9, 0xfc, 0xf7, 0xf0, 0xf2, 0xf1, 0xfd, 0xfa, +		0xfc, 0xf6, 0xf0, 0xf9, 0xf5, 0xfb, 0xfa, 0xf5, +		0xf0, 0xfd, 0xfe, 0xf8, 0xf7, 0xfa, 0xfb, 0xf1, +		0xfa, 0xf3, 0xf4, 0xff, 0xfd, 0xf4, 0xf1, 0xf2, +		0xf5, 0xfb, 0xf8, 0xf6, 0xfc, 0xf7, 0xf6, 0xfc, +		0xf9, 0xf0, 0xf3, 0xf5, 0xf2, 0xfe, 0xff, 0xf9, +		0x5f, 0x53, 0x51, 0x5d, 0x58, 0x54, 0x5e, 0x57, +		0x56, 0x5f, 0x5b, 0x52, 0x53, 0x58, 0x54, 0x5e, +		0x59, 0x5c, 0x57, 0x50, 0x52, 0x51, 0x5d, 0x5a, +		0x5c, 0x56, 0x50, 0x59, 0x55, 0x5b, 0x5a, 0x55, +		0x50, 0x5d, 0x5e, 0x58, 0x57, 0x5a, 0x5b, 0x51, +		0x5a, 0x53, 0x54, 0x5f, 0x5d, 0x54, 0x51, 0x52, +		0x55, 0x5b, 0x58, 0x56, 0x5c, 0x57, 0x56, 0x5c, +		0x59, 0x50, 0x53, 0x55, 0x52, 0x5e, 0x5f, 0x59, +		0xcf, 0xc3, 0xc1, 0xcd, 0xc8, 0xc4, 0xce, 0xc7, +		0xc6, 0xcf, 0xcb, 0xc2, 0xc3, 0xc8, 0xc4, 0xce, +		0xc9, 0xcc, 0xc7, 0xc0, 0xc2, 0xc1, 0xcd, 0xca, +		0xcc, 0xc6, 0xc0, 0xc9, 0xc5, 0xcb, 0xca, 0xc5, +		0xc0, 0xcd, 0xce, 0xc8, 0xc7, 0xca, 0xcb, 0xc1, +		0xca, 0xc3, 0xc4, 0xcf, 0xcd, 0xc4, 0xc1, 0xc2, +		0xc5, 0xcb, 0xc8, 0xc6, 0xcc, 0xc7, 0xc6, 0xcc, +		0xc9, 0xc0, 0xc3, 0xc5, 0xc2, 0xce, 0xcf, 0xc9, +		0xbf, 0xb3, 0xb1, 0xbd, 0xb8, 0xb4, 0xbe, 0xb7, +		0xb6, 0xbf, 0xbb, 0xb2, 0xb3, 0xb8, 0xb4, 0xbe, +		0xb9, 0xbc, 0xb7, 0xb0, 0xb2, 0xb1, 0xbd, 0xba, +		0xbc, 0xb6, 0xb0, 0xb9, 0xb5, 0xbb, 0xba, 0xb5, +		0xb0, 0xbd, 0xbe, 0xb8, 0xb7, 0xba, 0xbb, 0xb1, +		0xba, 0xb3, 0xb4, 0xbf, 0xbd, 0xb4, 0xb1, 0xb2, +		0xb5, 0xbb, 0xb8, 0xb6, 0xbc, 0xb7, 0xb6, 0xbc, +		0xb9, 0xb0, 0xb3, 0xb5, 0xb2, 0xbe, 0xbf, 0xb9, +		0x9f, 0x93, 0x91, 0x9d, 0x98, 0x94, 0x9e, 0x97, +		0x96, 0x9f, 0x9b, 0x92, 0x93, 0x98, 0x94, 0x9e, +		0x99, 0x9c, 0x97, 0x90, 0x92, 0x91, 0x9d, 0x9a, +		0x9c, 0x96, 0x90, 0x99, 0x95, 0x9b, 0x9a, 0x95, +		0x90, 0x9d, 0x9e, 0x98, 0x97, 0x9a, 0x9b, 0x91, +		0x9a, 0x93, 0x94, 0x9f, 0x9d, 0x94, 0x91, 0x92, +		0x95, 0x9b, 0x98, 0x96, 0x9c, 0x97, 0x96, 0x9c, +		0x99, 0x90, 0x93, 0x95, 0x92, 0x9e, 0x9f, 0x99, +		0x3f, 0x33, 0x31, 0x3d, 0x38, 0x34, 0x3e, 0x37, +		0x36, 0x3f, 0x3b, 0x32, 0x33, 0x38, 0x34, 0x3e, +		0x39, 0x3c, 0x37, 0x30, 0x32, 0x31, 0x3d, 0x3a, +		0x3c, 0x36, 0x30, 0x39, 0x35, 0x3b, 0x3a, 0x35, +		0x30, 0x3d, 0x3e, 0x38, 0x37, 0x3a, 0x3b, 0x31, +		0x3a, 0x33, 0x34, 0x3f, 0x3d, 0x34, 0x31, 0x32, +		0x35, 0x3b, 0x38, 0x36, 0x3c, 0x37, 0x36, 0x3c, +		0x39, 0x30, 0x33, 0x35, 0x32, 0x3e, 0x3f, 0x39, +		0x7f, 0x73, 0x71, 0x7d, 0x78, 0x74, 0x7e, 0x77, +		0x76, 0x7f, 0x7b, 0x72, 0x73, 0x78, 0x74, 0x7e, +		0x79, 0x7c, 0x77, 0x70, 0x72, 0x71, 0x7d, 0x7a, +		0x7c, 0x76, 0x70, 0x79, 0x75, 0x7b, 0x7a, 0x75, +		0x70, 0x7d, 0x7e, 0x78, 0x77, 0x7a, 0x7b, 0x71, +		0x7a, 0x73, 0x74, 0x7f, 0x7d, 0x74, 0x71, 0x72, +		0x75, 0x7b, 0x78, 0x76, 0x7c, 0x77, 0x76, 0x7c, +		0x79, 0x70, 0x73, 0x75, 0x72, 0x7e, 0x7f, 0x79, +		0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7, +		0xe6, 0xef, 0xeb, 0xe2, 0xe3, 0xe8, 0xe4, 0xee, +		0xe9, 0xec, 0xe7, 0xe0, 0xe2, 0xe1, 0xed, 0xea, +		0xec, 0xe6, 0xe0, 0xe9, 0xe5, 0xeb, 0xea, 0xe5, +		0xe0, 0xed, 0xee, 0xe8, 0xe7, 0xea, 0xeb, 0xe1, +		0xea, 0xe3, 0xe4, 0xef, 0xed, 0xe4, 0xe1, 0xe2, +		0xe5, 0xeb, 0xe8, 0xe6, 0xec, 0xe7, 0xe6, 0xec, +		0xe9, 0xe0, 0xe3, 0xe5, 0xe2, 0xee, 0xef, 0xe9, +		0x3f, 0x33, 0x31, 0x3d, 0x38, 0x34, 0x3e, 0x37, +		0x36, 0x3f, 0x3b, 0x32, 0x33, 0x38, 0x34, 0x3e, +		0x39, 0x3c, 0x37, 0x30, 0x32, 0x31, 0x3d, 0x3a, +		0x3c, 0x36, 0x30, 0x39, 0x35, 0x3b, 0x3a, 0x35, +		0x30, 0x3d, 0x3e, 0x38, 0x37, 0x3a, 0x3b, 0x31, +		0x3a, 0x33, 0x34, 0x3f, 0x3d, 0x34, 0x31, 0x32, +		0x35, 0x3b, 0x38, 0x36, 0x3c, 0x37, 0x36, 0x3c, +		0x39, 0x30, 0x33, 0x35, 0x32, 0x3e, 0x3f, 0x39, +		0xaf, 0xa3, 0xa1, 0xad, 0xa8, 0xa4, 0xae, 0xa7, +		0xa6, 0xaf, 0xab, 0xa2, 0xa3, 0xa8, 0xa4, 0xae, +		0xa9, 0xac, 0xa7, 0xa0, 0xa2, 0xa1, 0xad, 0xaa, +		0xac, 0xa6, 0xa0, 0xa9, 0xa5, 0xab, 0xaa, 0xa5, +		0xa0, 0xad, 0xae, 0xa8, 0xa7, 0xaa, 0xab, 0xa1, +		0xaa, 0xa3, 0xa4, 0xaf, 0xad, 0xa4, 0xa1, 0xa2, +		0xa5, 0xab, 0xa8, 0xa6, 0xac, 0xa7, 0xa6, 0xac, +		0xa9, 0xa0, 0xa3, 0xa5, 0xa2, 0xae, 0xaf, 0xa9, +		0xaf, 0xa3, 0xa1, 0xad, 0xa8, 0xa4, 0xae, 0xa7, +		0xa6, 0xaf, 0xab, 0xa2, 0xa3, 0xa8, 0xa4, 0xae, +		0xa9, 0xac, 0xa7, 0xa0, 0xa2, 0xa1, 0xad, 0xaa, +		0xac, 0xa6, 0xa0, 0xa9, 0xa5, 0xab, 0xaa, 0xa5, +		0xa0, 0xad, 0xae, 0xa8, 0xa7, 0xaa, 0xab, 0xa1, +		0xaa, 0xa3, 0xa4, 0xaf, 0xad, 0xa4, 0xa1, 0xa2, +		0xa5, 0xab, 0xa8, 0xa6, 0xac, 0xa7, 0xa6, 0xac, +		0xa9, 0xa0, 0xa3, 0xa5, 0xa2, 0xae, 0xaf, 0xa9, +		0x0f, 0x03, 0x01, 0x0d, 0x08, 0x04, 0x0e, 0x07, +		0x06, 0x0f, 0x0b, 0x02, 0x03, 0x08, 0x04, 0x0e, +		0x09, 0x0c, 0x07, 0x00, 0x02, 0x01, 0x0d, 0x0a, +		0x0c, 0x06, 0x00, 0x09, 0x05, 0x0b, 0x0a, 0x05, +		0x00, 0x0d, 0x0e, 0x08, 0x07, 0x0a, 0x0b, 0x01, +		0x0a, 0x03, 0x04, 0x0f, 0x0d, 0x04, 0x01, 0x02, +		0x05, 0x0b, 0x08, 0x06, 0x0c, 0x07, 0x06, 0x0c, +		0x09, 0x00, 0x03, 0x05, 0x02, 0x0e, 0x0f, 0x09, +		0x5f, 0x53, 0x51, 0x5d, 0x58, 0x54, 0x5e, 0x57, +		0x56, 0x5f, 0x5b, 0x52, 0x53, 0x58, 0x54, 0x5e, +		0x59, 0x5c, 0x57, 0x50, 0x52, 0x51, 0x5d, 0x5a, +		0x5c, 0x56, 0x50, 0x59, 0x55, 0x5b, 0x5a, 0x55, +		0x50, 0x5d, 0x5e, 0x58, 0x57, 0x5a, 0x5b, 0x51, +		0x5a, 0x53, 0x54, 0x5f, 0x5d, 0x54, 0x51, 0x52, +		0x55, 0x5b, 0x58, 0x56, 0x5c, 0x57, 0x56, 0x5c, +		0x59, 0x50, 0x53, 0x55, 0x52, 0x5e, 0x5f, 0x59, +		0x6f, 0x63, 0x61, 0x6d, 0x68, 0x64, 0x6e, 0x67, +		0x66, 0x6f, 0x6b, 0x62, 0x63, 0x68, 0x64, 0x6e, +		0x69, 0x6c, 0x67, 0x60, 0x62, 0x61, 0x6d, 0x6a, +		0x6c, 0x66, 0x60, 0x69, 0x65, 0x6b, 0x6a, 0x65, +		0x60, 0x6d, 0x6e, 0x68, 0x67, 0x6a, 0x6b, 0x61, +		0x6a, 0x63, 0x64, 0x6f, 0x6d, 0x64, 0x61, 0x62, +		0x65, 0x6b, 0x68, 0x66, 0x6c, 0x67, 0x66, 0x6c, +		0x69, 0x60, 0x63, 0x65, 0x62, 0x6e, 0x6f, 0x69, +		0x0f, 0x03, 0x01, 0x0d, 0x08, 0x04, 0x0e, 0x07, +		0x06, 0x0f, 0x0b, 0x02, 0x03, 0x08, 0x04, 0x0e, +		0x09, 0x0c, 0x07, 0x00, 0x02, 0x01, 0x0d, 0x0a, +		0x0c, 0x06, 0x00, 0x09, 0x05, 0x0b, 0x0a, 0x05, +		0x00, 0x0d, 0x0e, 0x08, 0x07, 0x0a, 0x0b, 0x01, +		0x0a, 0x03, 0x04, 0x0f, 0x0d, 0x04, 0x01, 0x02, +		0x05, 0x0b, 0x08, 0x06, 0x0c, 0x07, 0x06, 0x0c, +		0x09, 0x00, 0x03, 0x05, 0x02, 0x0e, 0x0f, 0x09, +		0xdf, 0xd3, 0xd1, 0xdd, 0xd8, 0xd4, 0xde, 0xd7, +		0xd6, 0xdf, 0xdb, 0xd2, 0xd3, 0xd8, 0xd4, 0xde, +		0xd9, 0xdc, 0xd7, 0xd0, 0xd2, 0xd1, 0xdd, 0xda, +		0xdc, 0xd6, 0xd0, 0xd9, 0xd5, 0xdb, 0xda, 0xd5, +		0xd0, 0xdd, 0xde, 0xd8, 0xd7, 0xda, 0xdb, 0xd1, +		0xda, 0xd3, 0xd4, 0xdf, 0xdd, 0xd4, 0xd1, 0xd2, +		0xd5, 0xdb, 0xd8, 0xd6, 0xdc, 0xd7, 0xd6, 0xdc, +		0xd9, 0xd0, 0xd3, 0xd5, 0xd2, 0xde, 0xdf, 0xd9, +	},{ +		0xa7, 0xad, 0xad, 0xa8, 0xae, 0xab, 0xa3, 0xa5, +		0xa0, 0xa6, 0xa6, 0xaf, 0xa9, 0xa0, 0xaa, 0xa3, +		0xa1, 0xa4, 0xa2, 0xa7, 0xa8, 0xa2, 0xa5, 0xac, +		0xab, 0xa1, 0xac, 0xaa, 0xa4, 0xae, 0xaf, 0xa9, +		0xaa, 0xa3, 0xa6, 0xaf, 0xa9, 0xa0, 0xa0, 0xa6, +		0xac, 0xaa, 0xab, 0xa1, 0xa7, 0xad, 0xad, 0xa8, +		0xaf, 0xa9, 0xa1, 0xa4, 0xa3, 0xa5, 0xae, 0xab, +		0xa5, 0xac, 0xa2, 0xa7, 0xa8, 0xa2, 0xa4, 0xae, +		0xd7, 0xdd, 0xdd, 0xd8, 0xde, 0xdb, 0xd3, 0xd5, +		0xd0, 0xd6, 0xd6, 0xdf, 0xd9, 0xd0, 0xda, 0xd3, +		0xd1, 0xd4, 0xd2, 0xd7, 0xd8, 0xd2, 0xd5, 0xdc, +		0xdb, 0xd1, 0xdc, 0xda, 0xd4, 0xde, 0xdf, 0xd9, +		0xda, 0xd3, 0xd6, 0xdf, 0xd9, 0xd0, 0xd0, 0xd6, +		0xdc, 0xda, 0xdb, 0xd1, 0xd7, 0xdd, 0xdd, 0xd8, +		0xdf, 0xd9, 0xd1, 0xd4, 0xd3, 0xd5, 0xde, 0xdb, +		0xd5, 0xdc, 0xd2, 0xd7, 0xd8, 0xd2, 0xd4, 0xde, +		0x07, 0x0d, 0x0d, 0x08, 0x0e, 0x0b, 0x03, 0x05, +		0x00, 0x06, 0x06, 0x0f, 0x09, 0x00, 0x0a, 0x03, +		0x01, 0x04, 0x02, 0x07, 0x08, 0x02, 0x05, 0x0c, +		0x0b, 0x01, 0x0c, 0x0a, 0x04, 0x0e, 0x0f, 0x09, +		0x0a, 0x03, 0x06, 0x0f, 0x09, 0x00, 0x00, 0x06, +		0x0c, 0x0a, 0x0b, 0x01, 0x07, 0x0d, 0x0d, 0x08, +		0x0f, 0x09, 0x01, 0x04, 0x03, 0x05, 0x0e, 0x0b, +		0x05, 0x0c, 0x02, 0x07, 0x08, 0x02, 0x04, 0x0e, +		0x77, 0x7d, 0x7d, 0x78, 0x7e, 0x7b, 0x73, 0x75, +		0x70, 0x76, 0x76, 0x7f, 0x79, 0x70, 0x7a, 0x73, +		0x71, 0x74, 0x72, 0x77, 0x78, 0x72, 0x75, 0x7c, +		0x7b, 0x71, 0x7c, 0x7a, 0x74, 0x7e, 0x7f, 0x79, +		0x7a, 0x73, 0x76, 0x7f, 0x79, 0x70, 0x70, 0x76, +		0x7c, 0x7a, 0x7b, 0x71, 0x77, 0x7d, 0x7d, 0x78, +		0x7f, 0x79, 0x71, 0x74, 0x73, 0x75, 0x7e, 0x7b, +		0x75, 0x7c, 0x72, 0x77, 0x78, 0x72, 0x74, 0x7e, +		0x97, 0x9d, 0x9d, 0x98, 0x9e, 0x9b, 0x93, 0x95, +		0x90, 0x96, 0x96, 0x9f, 0x99, 0x90, 0x9a, 0x93, +		0x91, 0x94, 0x92, 0x97, 0x98, 0x92, 0x95, 0x9c, +		0x9b, 0x91, 0x9c, 0x9a, 0x94, 0x9e, 0x9f, 0x99, +		0x9a, 0x93, 0x96, 0x9f, 0x99, 0x90, 0x90, 0x96, +		0x9c, 0x9a, 0x9b, 0x91, 0x97, 0x9d, 0x9d, 0x98, +		0x9f, 0x99, 0x91, 0x94, 0x93, 0x95, 0x9e, 0x9b, +		0x95, 0x9c, 0x92, 0x97, 0x98, 0x92, 0x94, 0x9e, +		0x07, 0x0d, 0x0d, 0x08, 0x0e, 0x0b, 0x03, 0x05, +		0x00, 0x06, 0x06, 0x0f, 0x09, 0x00, 0x0a, 0x03, +		0x01, 0x04, 0x02, 0x07, 0x08, 0x02, 0x05, 0x0c, +		0x0b, 0x01, 0x0c, 0x0a, 0x04, 0x0e, 0x0f, 0x09, +		0x0a, 0x03, 0x06, 0x0f, 0x09, 0x00, 0x00, 0x06, +		0x0c, 0x0a, 0x0b, 0x01, 0x07, 0x0d, 0x0d, 0x08, +		0x0f, 0x09, 0x01, 0x04, 0x03, 0x05, 0x0e, 0x0b, +		0x05, 0x0c, 0x02, 0x07, 0x08, 0x02, 0x04, 0x0e, +		0xe7, 0xed, 0xed, 0xe8, 0xee, 0xeb, 0xe3, 0xe5, +		0xe0, 0xe6, 0xe6, 0xef, 0xe9, 0xe0, 0xea, 0xe3, +		0xe1, 0xe4, 0xe2, 0xe7, 0xe8, 0xe2, 0xe5, 0xec, +		0xeb, 0xe1, 0xec, 0xea, 0xe4, 0xee, 0xef, 0xe9, +		0xea, 0xe3, 0xe6, 0xef, 0xe9, 0xe0, 0xe0, 0xe6, +		0xec, 0xea, 0xeb, 0xe1, 0xe7, 0xed, 0xed, 0xe8, +		0xef, 0xe9, 0xe1, 0xe4, 0xe3, 0xe5, 0xee, 0xeb, +		0xe5, 0xec, 0xe2, 0xe7, 0xe8, 0xe2, 0xe4, 0xee, +		0x97, 0x9d, 0x9d, 0x98, 0x9e, 0x9b, 0x93, 0x95, +		0x90, 0x96, 0x96, 0x9f, 0x99, 0x90, 0x9a, 0x93, +		0x91, 0x94, 0x92, 0x97, 0x98, 0x92, 0x95, 0x9c, +		0x9b, 0x91, 0x9c, 0x9a, 0x94, 0x9e, 0x9f, 0x99, +		0x9a, 0x93, 0x96, 0x9f, 0x99, 0x90, 0x90, 0x96, +		0x9c, 0x9a, 0x9b, 0x91, 0x97, 0x9d, 0x9d, 0x98, +		0x9f, 0x99, 0x91, 0x94, 0x93, 0x95, 0x9e, 0x9b, +		0x95, 0x9c, 0x92, 0x97, 0x98, 0x92, 0x94, 0x9e, +		0x67, 0x6d, 0x6d, 0x68, 0x6e, 0x6b, 0x63, 0x65, +		0x60, 0x66, 0x66, 0x6f, 0x69, 0x60, 0x6a, 0x63, +		0x61, 0x64, 0x62, 0x67, 0x68, 0x62, 0x65, 0x6c, +		0x6b, 0x61, 0x6c, 0x6a, 0x64, 0x6e, 0x6f, 0x69, +		0x6a, 0x63, 0x66, 0x6f, 0x69, 0x60, 0x60, 0x66, +		0x6c, 0x6a, 0x6b, 0x61, 0x67, 0x6d, 0x6d, 0x68, +		0x6f, 0x69, 0x61, 0x64, 0x63, 0x65, 0x6e, 0x6b, +		0x65, 0x6c, 0x62, 0x67, 0x68, 0x62, 0x64, 0x6e, +		0x37, 0x3d, 0x3d, 0x38, 0x3e, 0x3b, 0x33, 0x35, +		0x30, 0x36, 0x36, 0x3f, 0x39, 0x30, 0x3a, 0x33, +		0x31, 0x34, 0x32, 0x37, 0x38, 0x32, 0x35, 0x3c, +		0x3b, 0x31, 0x3c, 0x3a, 0x34, 0x3e, 0x3f, 0x39, +		0x3a, 0x33, 0x36, 0x3f, 0x39, 0x30, 0x30, 0x36, +		0x3c, 0x3a, 0x3b, 0x31, 0x37, 0x3d, 0x3d, 0x38, +		0x3f, 0x39, 0x31, 0x34, 0x33, 0x35, 0x3e, 0x3b, +		0x35, 0x3c, 0x32, 0x37, 0x38, 0x32, 0x34, 0x3e, +		0x37, 0x3d, 0x3d, 0x38, 0x3e, 0x3b, 0x33, 0x35, +		0x30, 0x36, 0x36, 0x3f, 0x39, 0x30, 0x3a, 0x33, +		0x31, 0x34, 0x32, 0x37, 0x38, 0x32, 0x35, 0x3c, +		0x3b, 0x31, 0x3c, 0x3a, 0x34, 0x3e, 0x3f, 0x39, +		0x3a, 0x33, 0x36, 0x3f, 0x39, 0x30, 0x30, 0x36, +		0x3c, 0x3a, 0x3b, 0x31, 0x37, 0x3d, 0x3d, 0x38, +		0x3f, 0x39, 0x31, 0x34, 0x33, 0x35, 0x3e, 0x3b, +		0x35, 0x3c, 0x32, 0x37, 0x38, 0x32, 0x34, 0x3e, +		0x47, 0x4d, 0x4d, 0x48, 0x4e, 0x4b, 0x43, 0x45, +		0x40, 0x46, 0x46, 0x4f, 0x49, 0x40, 0x4a, 0x43, +		0x41, 0x44, 0x42, 0x47, 0x48, 0x42, 0x45, 0x4c, +		0x4b, 0x41, 0x4c, 0x4a, 0x44, 0x4e, 0x4f, 0x49, +		0x4a, 0x43, 0x46, 0x4f, 0x49, 0x40, 0x40, 0x46, +		0x4c, 0x4a, 0x4b, 0x41, 0x47, 0x4d, 0x4d, 0x48, +		0x4f, 0x49, 0x41, 0x44, 0x43, 0x45, 0x4e, 0x4b, +		0x45, 0x4c, 0x42, 0x47, 0x48, 0x42, 0x44, 0x4e, +		0xf7, 0xfd, 0xfd, 0xf8, 0xfe, 0xfb, 0xf3, 0xf5, +		0xf0, 0xf6, 0xf6, 0xff, 0xf9, 0xf0, 0xfa, 0xf3, +		0xf1, 0xf4, 0xf2, 0xf7, 0xf8, 0xf2, 0xf5, 0xfc, +		0xfb, 0xf1, 0xfc, 0xfa, 0xf4, 0xfe, 0xff, 0xf9, +		0xfa, 0xf3, 0xf6, 0xff, 0xf9, 0xf0, 0xf0, 0xf6, +		0xfc, 0xfa, 0xfb, 0xf1, 0xf7, 0xfd, 0xfd, 0xf8, +		0xff, 0xf9, 0xf1, 0xf4, 0xf3, 0xf5, 0xfe, 0xfb, +		0xf5, 0xfc, 0xf2, 0xf7, 0xf8, 0xf2, 0xf4, 0xfe, +		0x67, 0x6d, 0x6d, 0x68, 0x6e, 0x6b, 0x63, 0x65, +		0x60, 0x66, 0x66, 0x6f, 0x69, 0x60, 0x6a, 0x63, +		0x61, 0x64, 0x62, 0x67, 0x68, 0x62, 0x65, 0x6c, +		0x6b, 0x61, 0x6c, 0x6a, 0x64, 0x6e, 0x6f, 0x69, +		0x6a, 0x63, 0x66, 0x6f, 0x69, 0x60, 0x60, 0x66, +		0x6c, 0x6a, 0x6b, 0x61, 0x67, 0x6d, 0x6d, 0x68, +		0x6f, 0x69, 0x61, 0x64, 0x63, 0x65, 0x6e, 0x6b, +		0x65, 0x6c, 0x62, 0x67, 0x68, 0x62, 0x64, 0x6e, +		0x57, 0x5d, 0x5d, 0x58, 0x5e, 0x5b, 0x53, 0x55, +		0x50, 0x56, 0x56, 0x5f, 0x59, 0x50, 0x5a, 0x53, +		0x51, 0x54, 0x52, 0x57, 0x58, 0x52, 0x55, 0x5c, +		0x5b, 0x51, 0x5c, 0x5a, 0x54, 0x5e, 0x5f, 0x59, +		0x5a, 0x53, 0x56, 0x5f, 0x59, 0x50, 0x50, 0x56, +		0x5c, 0x5a, 0x5b, 0x51, 0x57, 0x5d, 0x5d, 0x58, +		0x5f, 0x59, 0x51, 0x54, 0x53, 0x55, 0x5e, 0x5b, +		0x55, 0x5c, 0x52, 0x57, 0x58, 0x52, 0x54, 0x5e, +		0xa7, 0xad, 0xad, 0xa8, 0xae, 0xab, 0xa3, 0xa5, +		0xa0, 0xa6, 0xa6, 0xaf, 0xa9, 0xa0, 0xaa, 0xa3, +		0xa1, 0xa4, 0xa2, 0xa7, 0xa8, 0xa2, 0xa5, 0xac, +		0xab, 0xa1, 0xac, 0xaa, 0xa4, 0xae, 0xaf, 0xa9, +		0xaa, 0xa3, 0xa6, 0xaf, 0xa9, 0xa0, 0xa0, 0xa6, +		0xac, 0xaa, 0xab, 0xa1, 0xa7, 0xad, 0xad, 0xa8, +		0xaf, 0xa9, 0xa1, 0xa4, 0xa3, 0xa5, 0xae, 0xab, +		0xa5, 0xac, 0xa2, 0xa7, 0xa8, 0xa2, 0xa4, 0xae, +		0x17, 0x1d, 0x1d, 0x18, 0x1e, 0x1b, 0x13, 0x15, +		0x10, 0x16, 0x16, 0x1f, 0x19, 0x10, 0x1a, 0x13, +		0x11, 0x14, 0x12, 0x17, 0x18, 0x12, 0x15, 0x1c, +		0x1b, 0x11, 0x1c, 0x1a, 0x14, 0x1e, 0x1f, 0x19, +		0x1a, 0x13, 0x16, 0x1f, 0x19, 0x10, 0x10, 0x16, +		0x1c, 0x1a, 0x1b, 0x11, 0x17, 0x1d, 0x1d, 0x18, +		0x1f, 0x19, 0x11, 0x14, 0x13, 0x15, 0x1e, 0x1b, +		0x15, 0x1c, 0x12, 0x17, 0x18, 0x12, 0x14, 0x1e, +		0x27, 0x2d, 0x2d, 0x28, 0x2e, 0x2b, 0x23, 0x25, +		0x20, 0x26, 0x26, 0x2f, 0x29, 0x20, 0x2a, 0x23, +		0x21, 0x24, 0x22, 0x27, 0x28, 0x22, 0x25, 0x2c, +		0x2b, 0x21, 0x2c, 0x2a, 0x24, 0x2e, 0x2f, 0x29, +		0x2a, 0x23, 0x26, 0x2f, 0x29, 0x20, 0x20, 0x26, +		0x2c, 0x2a, 0x2b, 0x21, 0x27, 0x2d, 0x2d, 0x28, +		0x2f, 0x29, 0x21, 0x24, 0x23, 0x25, 0x2e, 0x2b, +		0x25, 0x2c, 0x22, 0x27, 0x28, 0x22, 0x24, 0x2e, +		0xd7, 0xdd, 0xdd, 0xd8, 0xde, 0xdb, 0xd3, 0xd5, +		0xd0, 0xd6, 0xd6, 0xdf, 0xd9, 0xd0, 0xda, 0xd3, +		0xd1, 0xd4, 0xd2, 0xd7, 0xd8, 0xd2, 0xd5, 0xdc, +		0xdb, 0xd1, 0xdc, 0xda, 0xd4, 0xde, 0xdf, 0xd9, +		0xda, 0xd3, 0xd6, 0xdf, 0xd9, 0xd0, 0xd0, 0xd6, +		0xdc, 0xda, 0xdb, 0xd1, 0xd7, 0xdd, 0xdd, 0xd8, +		0xdf, 0xd9, 0xd1, 0xd4, 0xd3, 0xd5, 0xde, 0xdb, +		0xd5, 0xdc, 0xd2, 0xd7, 0xd8, 0xd2, 0xd4, 0xde, +		0x87, 0x8d, 0x8d, 0x88, 0x8e, 0x8b, 0x83, 0x85, +		0x80, 0x86, 0x86, 0x8f, 0x89, 0x80, 0x8a, 0x83, +		0x81, 0x84, 0x82, 0x87, 0x88, 0x82, 0x85, 0x8c, +		0x8b, 0x81, 0x8c, 0x8a, 0x84, 0x8e, 0x8f, 0x89, +		0x8a, 0x83, 0x86, 0x8f, 0x89, 0x80, 0x80, 0x86, +		0x8c, 0x8a, 0x8b, 0x81, 0x87, 0x8d, 0x8d, 0x88, +		0x8f, 0x89, 0x81, 0x84, 0x83, 0x85, 0x8e, 0x8b, +		0x85, 0x8c, 0x82, 0x87, 0x88, 0x82, 0x84, 0x8e, +		0xc7, 0xcd, 0xcd, 0xc8, 0xce, 0xcb, 0xc3, 0xc5, +		0xc0, 0xc6, 0xc6, 0xcf, 0xc9, 0xc0, 0xca, 0xc3, +		0xc1, 0xc4, 0xc2, 0xc7, 0xc8, 0xc2, 0xc5, 0xcc, +		0xcb, 0xc1, 0xcc, 0xca, 0xc4, 0xce, 0xcf, 0xc9, +		0xca, 0xc3, 0xc6, 0xcf, 0xc9, 0xc0, 0xc0, 0xc6, +		0xcc, 0xca, 0xcb, 0xc1, 0xc7, 0xcd, 0xcd, 0xc8, +		0xcf, 0xc9, 0xc1, 0xc4, 0xc3, 0xc5, 0xce, 0xcb, +		0xc5, 0xcc, 0xc2, 0xc7, 0xc8, 0xc2, 0xc4, 0xce, +		0x57, 0x5d, 0x5d, 0x58, 0x5e, 0x5b, 0x53, 0x55, +		0x50, 0x56, 0x56, 0x5f, 0x59, 0x50, 0x5a, 0x53, +		0x51, 0x54, 0x52, 0x57, 0x58, 0x52, 0x55, 0x5c, +		0x5b, 0x51, 0x5c, 0x5a, 0x54, 0x5e, 0x5f, 0x59, +		0x5a, 0x53, 0x56, 0x5f, 0x59, 0x50, 0x50, 0x56, +		0x5c, 0x5a, 0x5b, 0x51, 0x57, 0x5d, 0x5d, 0x58, +		0x5f, 0x59, 0x51, 0x54, 0x53, 0x55, 0x5e, 0x5b, +		0x55, 0x5c, 0x52, 0x57, 0x58, 0x52, 0x54, 0x5e, +		0x77, 0x7d, 0x7d, 0x78, 0x7e, 0x7b, 0x73, 0x75, +		0x70, 0x76, 0x76, 0x7f, 0x79, 0x70, 0x7a, 0x73, +		0x71, 0x74, 0x72, 0x77, 0x78, 0x72, 0x75, 0x7c, +		0x7b, 0x71, 0x7c, 0x7a, 0x74, 0x7e, 0x7f, 0x79, +		0x7a, 0x73, 0x76, 0x7f, 0x79, 0x70, 0x70, 0x76, +		0x7c, 0x7a, 0x7b, 0x71, 0x77, 0x7d, 0x7d, 0x78, +		0x7f, 0x79, 0x71, 0x74, 0x73, 0x75, 0x7e, 0x7b, +		0x75, 0x7c, 0x72, 0x77, 0x78, 0x72, 0x74, 0x7e, +		0xe7, 0xed, 0xed, 0xe8, 0xee, 0xeb, 0xe3, 0xe5, +		0xe0, 0xe6, 0xe6, 0xef, 0xe9, 0xe0, 0xea, 0xe3, +		0xe1, 0xe4, 0xe2, 0xe7, 0xe8, 0xe2, 0xe5, 0xec, +		0xeb, 0xe1, 0xec, 0xea, 0xe4, 0xee, 0xef, 0xe9, +		0xea, 0xe3, 0xe6, 0xef, 0xe9, 0xe0, 0xe0, 0xe6, +		0xec, 0xea, 0xeb, 0xe1, 0xe7, 0xed, 0xed, 0xe8, +		0xef, 0xe9, 0xe1, 0xe4, 0xe3, 0xe5, 0xee, 0xeb, +		0xe5, 0xec, 0xe2, 0xe7, 0xe8, 0xe2, 0xe4, 0xee, +		0xb7, 0xbd, 0xbd, 0xb8, 0xbe, 0xbb, 0xb3, 0xb5, +		0xb0, 0xb6, 0xb6, 0xbf, 0xb9, 0xb0, 0xba, 0xb3, +		0xb1, 0xb4, 0xb2, 0xb7, 0xb8, 0xb2, 0xb5, 0xbc, +		0xbb, 0xb1, 0xbc, 0xba, 0xb4, 0xbe, 0xbf, 0xb9, +		0xba, 0xb3, 0xb6, 0xbf, 0xb9, 0xb0, 0xb0, 0xb6, +		0xbc, 0xba, 0xbb, 0xb1, 0xb7, 0xbd, 0xbd, 0xb8, +		0xbf, 0xb9, 0xb1, 0xb4, 0xb3, 0xb5, 0xbe, 0xbb, +		0xb5, 0xbc, 0xb2, 0xb7, 0xb8, 0xb2, 0xb4, 0xbe, +		0xc7, 0xcd, 0xcd, 0xc8, 0xce, 0xcb, 0xc3, 0xc5, +		0xc0, 0xc6, 0xc6, 0xcf, 0xc9, 0xc0, 0xca, 0xc3, +		0xc1, 0xc4, 0xc2, 0xc7, 0xc8, 0xc2, 0xc5, 0xcc, +		0xcb, 0xc1, 0xcc, 0xca, 0xc4, 0xce, 0xcf, 0xc9, +		0xca, 0xc3, 0xc6, 0xcf, 0xc9, 0xc0, 0xc0, 0xc6, +		0xcc, 0xca, 0xcb, 0xc1, 0xc7, 0xcd, 0xcd, 0xc8, +		0xcf, 0xc9, 0xc1, 0xc4, 0xc3, 0xc5, 0xce, 0xcb, +		0xc5, 0xcc, 0xc2, 0xc7, 0xc8, 0xc2, 0xc4, 0xce, +		0x47, 0x4d, 0x4d, 0x48, 0x4e, 0x4b, 0x43, 0x45, +		0x40, 0x46, 0x46, 0x4f, 0x49, 0x40, 0x4a, 0x43, +		0x41, 0x44, 0x42, 0x47, 0x48, 0x42, 0x45, 0x4c, +		0x4b, 0x41, 0x4c, 0x4a, 0x44, 0x4e, 0x4f, 0x49, +		0x4a, 0x43, 0x46, 0x4f, 0x49, 0x40, 0x40, 0x46, +		0x4c, 0x4a, 0x4b, 0x41, 0x47, 0x4d, 0x4d, 0x48, +		0x4f, 0x49, 0x41, 0x44, 0x43, 0x45, 0x4e, 0x4b, +		0x45, 0x4c, 0x42, 0x47, 0x48, 0x42, 0x44, 0x4e, +		0xb7, 0xbd, 0xbd, 0xb8, 0xbe, 0xbb, 0xb3, 0xb5, +		0xb0, 0xb6, 0xb6, 0xbf, 0xb9, 0xb0, 0xba, 0xb3, +		0xb1, 0xb4, 0xb2, 0xb7, 0xb8, 0xb2, 0xb5, 0xbc, +		0xbb, 0xb1, 0xbc, 0xba, 0xb4, 0xbe, 0xbf, 0xb9, +		0xba, 0xb3, 0xb6, 0xbf, 0xb9, 0xb0, 0xb0, 0xb6, +		0xbc, 0xba, 0xbb, 0xb1, 0xb7, 0xbd, 0xbd, 0xb8, +		0xbf, 0xb9, 0xb1, 0xb4, 0xb3, 0xb5, 0xbe, 0xbb, +		0xb5, 0xbc, 0xb2, 0xb7, 0xb8, 0xb2, 0xb4, 0xbe, +		0x27, 0x2d, 0x2d, 0x28, 0x2e, 0x2b, 0x23, 0x25, +		0x20, 0x26, 0x26, 0x2f, 0x29, 0x20, 0x2a, 0x23, +		0x21, 0x24, 0x22, 0x27, 0x28, 0x22, 0x25, 0x2c, +		0x2b, 0x21, 0x2c, 0x2a, 0x24, 0x2e, 0x2f, 0x29, +		0x2a, 0x23, 0x26, 0x2f, 0x29, 0x20, 0x20, 0x26, +		0x2c, 0x2a, 0x2b, 0x21, 0x27, 0x2d, 0x2d, 0x28, +		0x2f, 0x29, 0x21, 0x24, 0x23, 0x25, 0x2e, 0x2b, +		0x25, 0x2c, 0x22, 0x27, 0x28, 0x22, 0x24, 0x2e, +		0xf7, 0xfd, 0xfd, 0xf8, 0xfe, 0xfb, 0xf3, 0xf5, +		0xf0, 0xf6, 0xf6, 0xff, 0xf9, 0xf0, 0xfa, 0xf3, +		0xf1, 0xf4, 0xf2, 0xf7, 0xf8, 0xf2, 0xf5, 0xfc, +		0xfb, 0xf1, 0xfc, 0xfa, 0xf4, 0xfe, 0xff, 0xf9, +		0xfa, 0xf3, 0xf6, 0xff, 0xf9, 0xf0, 0xf0, 0xf6, +		0xfc, 0xfa, 0xfb, 0xf1, 0xf7, 0xfd, 0xfd, 0xf8, +		0xff, 0xf9, 0xf1, 0xf4, 0xf3, 0xf5, 0xfe, 0xfb, +		0xf5, 0xfc, 0xf2, 0xf7, 0xf8, 0xf2, 0xf4, 0xfe, +		0x87, 0x8d, 0x8d, 0x88, 0x8e, 0x8b, 0x83, 0x85, +		0x80, 0x86, 0x86, 0x8f, 0x89, 0x80, 0x8a, 0x83, +		0x81, 0x84, 0x82, 0x87, 0x88, 0x82, 0x85, 0x8c, +		0x8b, 0x81, 0x8c, 0x8a, 0x84, 0x8e, 0x8f, 0x89, +		0x8a, 0x83, 0x86, 0x8f, 0x89, 0x80, 0x80, 0x86, +		0x8c, 0x8a, 0x8b, 0x81, 0x87, 0x8d, 0x8d, 0x88, +		0x8f, 0x89, 0x81, 0x84, 0x83, 0x85, 0x8e, 0x8b, +		0x85, 0x8c, 0x82, 0x87, 0x88, 0x82, 0x84, 0x8e, +		0x17, 0x1d, 0x1d, 0x18, 0x1e, 0x1b, 0x13, 0x15, +		0x10, 0x16, 0x16, 0x1f, 0x19, 0x10, 0x1a, 0x13, +		0x11, 0x14, 0x12, 0x17, 0x18, 0x12, 0x15, 0x1c, +		0x1b, 0x11, 0x1c, 0x1a, 0x14, 0x1e, 0x1f, 0x19, +		0x1a, 0x13, 0x16, 0x1f, 0x19, 0x10, 0x10, 0x16, +		0x1c, 0x1a, 0x1b, 0x11, 0x17, 0x1d, 0x1d, 0x18, +		0x1f, 0x19, 0x11, 0x14, 0x13, 0x15, 0x1e, 0x1b, +		0x15, 0x1c, 0x12, 0x17, 0x18, 0x12, 0x14, 0x1e, +		0xd7, 0xdd, 0xdd, 0xd8, 0xde, 0xdb, 0xd3, 0xd5, +		0xd0, 0xd6, 0xd6, 0xdf, 0xd9, 0xd0, 0xda, 0xd3, +		0xd1, 0xd4, 0xd2, 0xd7, 0xd8, 0xd2, 0xd5, 0xdc, +		0xdb, 0xd1, 0xdc, 0xda, 0xd4, 0xde, 0xdf, 0xd9, +		0xda, 0xd3, 0xd6, 0xdf, 0xd9, 0xd0, 0xd0, 0xd6, +		0xdc, 0xda, 0xdb, 0xd1, 0xd7, 0xdd, 0xdd, 0xd8, +		0xdf, 0xd9, 0xd1, 0xd4, 0xd3, 0xd5, 0xde, 0xdb, +		0xd5, 0xdc, 0xd2, 0xd7, 0xd8, 0xd2, 0xd4, 0xde, +		0x17, 0x1d, 0x1d, 0x18, 0x1e, 0x1b, 0x13, 0x15, +		0x10, 0x16, 0x16, 0x1f, 0x19, 0x10, 0x1a, 0x13, +		0x11, 0x14, 0x12, 0x17, 0x18, 0x12, 0x15, 0x1c, +		0x1b, 0x11, 0x1c, 0x1a, 0x14, 0x1e, 0x1f, 0x19, +		0x1a, 0x13, 0x16, 0x1f, 0x19, 0x10, 0x10, 0x16, +		0x1c, 0x1a, 0x1b, 0x11, 0x17, 0x1d, 0x1d, 0x18, +		0x1f, 0x19, 0x11, 0x14, 0x13, 0x15, 0x1e, 0x1b, +		0x15, 0x1c, 0x12, 0x17, 0x18, 0x12, 0x14, 0x1e, +		0x67, 0x6d, 0x6d, 0x68, 0x6e, 0x6b, 0x63, 0x65, +		0x60, 0x66, 0x66, 0x6f, 0x69, 0x60, 0x6a, 0x63, +		0x61, 0x64, 0x62, 0x67, 0x68, 0x62, 0x65, 0x6c, +		0x6b, 0x61, 0x6c, 0x6a, 0x64, 0x6e, 0x6f, 0x69, +		0x6a, 0x63, 0x66, 0x6f, 0x69, 0x60, 0x60, 0x66, +		0x6c, 0x6a, 0x6b, 0x61, 0x67, 0x6d, 0x6d, 0x68, +		0x6f, 0x69, 0x61, 0x64, 0x63, 0x65, 0x6e, 0x6b, +		0x65, 0x6c, 0x62, 0x67, 0x68, 0x62, 0x64, 0x6e, +		0xa7, 0xad, 0xad, 0xa8, 0xae, 0xab, 0xa3, 0xa5, +		0xa0, 0xa6, 0xa6, 0xaf, 0xa9, 0xa0, 0xaa, 0xa3, +		0xa1, 0xa4, 0xa2, 0xa7, 0xa8, 0xa2, 0xa5, 0xac, +		0xab, 0xa1, 0xac, 0xaa, 0xa4, 0xae, 0xaf, 0xa9, +		0xaa, 0xa3, 0xa6, 0xaf, 0xa9, 0xa0, 0xa0, 0xa6, +		0xac, 0xaa, 0xab, 0xa1, 0xa7, 0xad, 0xad, 0xa8, +		0xaf, 0xa9, 0xa1, 0xa4, 0xa3, 0xa5, 0xae, 0xab, +		0xa5, 0xac, 0xa2, 0xa7, 0xa8, 0xa2, 0xa4, 0xae, +		0x47, 0x4d, 0x4d, 0x48, 0x4e, 0x4b, 0x43, 0x45, +		0x40, 0x46, 0x46, 0x4f, 0x49, 0x40, 0x4a, 0x43, +		0x41, 0x44, 0x42, 0x47, 0x48, 0x42, 0x45, 0x4c, +		0x4b, 0x41, 0x4c, 0x4a, 0x44, 0x4e, 0x4f, 0x49, +		0x4a, 0x43, 0x46, 0x4f, 0x49, 0x40, 0x40, 0x46, +		0x4c, 0x4a, 0x4b, 0x41, 0x47, 0x4d, 0x4d, 0x48, +		0x4f, 0x49, 0x41, 0x44, 0x43, 0x45, 0x4e, 0x4b, +		0x45, 0x4c, 0x42, 0x47, 0x48, 0x42, 0x44, 0x4e, +		0xd7, 0xdd, 0xdd, 0xd8, 0xde, 0xdb, 0xd3, 0xd5, +		0xd0, 0xd6, 0xd6, 0xdf, 0xd9, 0xd0, 0xda, 0xd3, +		0xd1, 0xd4, 0xd2, 0xd7, 0xd8, 0xd2, 0xd5, 0xdc, +		0xdb, 0xd1, 0xdc, 0xda, 0xd4, 0xde, 0xdf, 0xd9, +		0xda, 0xd3, 0xd6, 0xdf, 0xd9, 0xd0, 0xd0, 0xd6, +		0xdc, 0xda, 0xdb, 0xd1, 0xd7, 0xdd, 0xdd, 0xd8, +		0xdf, 0xd9, 0xd1, 0xd4, 0xd3, 0xd5, 0xde, 0xdb, +		0xd5, 0xdc, 0xd2, 0xd7, 0xd8, 0xd2, 0xd4, 0xde, +		0x97, 0x9d, 0x9d, 0x98, 0x9e, 0x9b, 0x93, 0x95, +		0x90, 0x96, 0x96, 0x9f, 0x99, 0x90, 0x9a, 0x93, +		0x91, 0x94, 0x92, 0x97, 0x98, 0x92, 0x95, 0x9c, +		0x9b, 0x91, 0x9c, 0x9a, 0x94, 0x9e, 0x9f, 0x99, +		0x9a, 0x93, 0x96, 0x9f, 0x99, 0x90, 0x90, 0x96, +		0x9c, 0x9a, 0x9b, 0x91, 0x97, 0x9d, 0x9d, 0x98, +		0x9f, 0x99, 0x91, 0x94, 0x93, 0x95, 0x9e, 0x9b, +		0x95, 0x9c, 0x92, 0x97, 0x98, 0x92, 0x94, 0x9e, +		0x07, 0x0d, 0x0d, 0x08, 0x0e, 0x0b, 0x03, 0x05, +		0x00, 0x06, 0x06, 0x0f, 0x09, 0x00, 0x0a, 0x03, +		0x01, 0x04, 0x02, 0x07, 0x08, 0x02, 0x05, 0x0c, +		0x0b, 0x01, 0x0c, 0x0a, 0x04, 0x0e, 0x0f, 0x09, +		0x0a, 0x03, 0x06, 0x0f, 0x09, 0x00, 0x00, 0x06, +		0x0c, 0x0a, 0x0b, 0x01, 0x07, 0x0d, 0x0d, 0x08, +		0x0f, 0x09, 0x01, 0x04, 0x03, 0x05, 0x0e, 0x0b, +		0x05, 0x0c, 0x02, 0x07, 0x08, 0x02, 0x04, 0x0e, +		0x87, 0x8d, 0x8d, 0x88, 0x8e, 0x8b, 0x83, 0x85, +		0x80, 0x86, 0x86, 0x8f, 0x89, 0x80, 0x8a, 0x83, +		0x81, 0x84, 0x82, 0x87, 0x88, 0x82, 0x85, 0x8c, +		0x8b, 0x81, 0x8c, 0x8a, 0x84, 0x8e, 0x8f, 0x89, +		0x8a, 0x83, 0x86, 0x8f, 0x89, 0x80, 0x80, 0x86, +		0x8c, 0x8a, 0x8b, 0x81, 0x87, 0x8d, 0x8d, 0x88, +		0x8f, 0x89, 0x81, 0x84, 0x83, 0x85, 0x8e, 0x8b, +		0x85, 0x8c, 0x82, 0x87, 0x88, 0x82, 0x84, 0x8e, +		0x67, 0x6d, 0x6d, 0x68, 0x6e, 0x6b, 0x63, 0x65, +		0x60, 0x66, 0x66, 0x6f, 0x69, 0x60, 0x6a, 0x63, +		0x61, 0x64, 0x62, 0x67, 0x68, 0x62, 0x65, 0x6c, +		0x6b, 0x61, 0x6c, 0x6a, 0x64, 0x6e, 0x6f, 0x69, +		0x6a, 0x63, 0x66, 0x6f, 0x69, 0x60, 0x60, 0x66, +		0x6c, 0x6a, 0x6b, 0x61, 0x67, 0x6d, 0x6d, 0x68, +		0x6f, 0x69, 0x61, 0x64, 0x63, 0x65, 0x6e, 0x6b, +		0x65, 0x6c, 0x62, 0x67, 0x68, 0x62, 0x64, 0x6e, +		0xf7, 0xfd, 0xfd, 0xf8, 0xfe, 0xfb, 0xf3, 0xf5, +		0xf0, 0xf6, 0xf6, 0xff, 0xf9, 0xf0, 0xfa, 0xf3, +		0xf1, 0xf4, 0xf2, 0xf7, 0xf8, 0xf2, 0xf5, 0xfc, +		0xfb, 0xf1, 0xfc, 0xfa, 0xf4, 0xfe, 0xff, 0xf9, +		0xfa, 0xf3, 0xf6, 0xff, 0xf9, 0xf0, 0xf0, 0xf6, +		0xfc, 0xfa, 0xfb, 0xf1, 0xf7, 0xfd, 0xfd, 0xf8, +		0xff, 0xf9, 0xf1, 0xf4, 0xf3, 0xf5, 0xfe, 0xfb, +		0xf5, 0xfc, 0xf2, 0xf7, 0xf8, 0xf2, 0xf4, 0xfe, +		0x97, 0x9d, 0x9d, 0x98, 0x9e, 0x9b, 0x93, 0x95, +		0x90, 0x96, 0x96, 0x9f, 0x99, 0x90, 0x9a, 0x93, +		0x91, 0x94, 0x92, 0x97, 0x98, 0x92, 0x95, 0x9c, +		0x9b, 0x91, 0x9c, 0x9a, 0x94, 0x9e, 0x9f, 0x99, +		0x9a, 0x93, 0x96, 0x9f, 0x99, 0x90, 0x90, 0x96, +		0x9c, 0x9a, 0x9b, 0x91, 0x97, 0x9d, 0x9d, 0x98, +		0x9f, 0x99, 0x91, 0x94, 0x93, 0x95, 0x9e, 0x9b, +		0x95, 0x9c, 0x92, 0x97, 0x98, 0x92, 0x94, 0x9e, +		0x37, 0x3d, 0x3d, 0x38, 0x3e, 0x3b, 0x33, 0x35, +		0x30, 0x36, 0x36, 0x3f, 0x39, 0x30, 0x3a, 0x33, +		0x31, 0x34, 0x32, 0x37, 0x38, 0x32, 0x35, 0x3c, +		0x3b, 0x31, 0x3c, 0x3a, 0x34, 0x3e, 0x3f, 0x39, +		0x3a, 0x33, 0x36, 0x3f, 0x39, 0x30, 0x30, 0x36, +		0x3c, 0x3a, 0x3b, 0x31, 0x37, 0x3d, 0x3d, 0x38, +		0x3f, 0x39, 0x31, 0x34, 0x33, 0x35, 0x3e, 0x3b, +		0x35, 0x3c, 0x32, 0x37, 0x38, 0x32, 0x34, 0x3e, +		0x87, 0x8d, 0x8d, 0x88, 0x8e, 0x8b, 0x83, 0x85, +		0x80, 0x86, 0x86, 0x8f, 0x89, 0x80, 0x8a, 0x83, +		0x81, 0x84, 0x82, 0x87, 0x88, 0x82, 0x85, 0x8c, +		0x8b, 0x81, 0x8c, 0x8a, 0x84, 0x8e, 0x8f, 0x89, +		0x8a, 0x83, 0x86, 0x8f, 0x89, 0x80, 0x80, 0x86, +		0x8c, 0x8a, 0x8b, 0x81, 0x87, 0x8d, 0x8d, 0x88, +		0x8f, 0x89, 0x81, 0x84, 0x83, 0x85, 0x8e, 0x8b, +		0x85, 0x8c, 0x82, 0x87, 0x88, 0x82, 0x84, 0x8e, +		0x07, 0x0d, 0x0d, 0x08, 0x0e, 0x0b, 0x03, 0x05, +		0x00, 0x06, 0x06, 0x0f, 0x09, 0x00, 0x0a, 0x03, +		0x01, 0x04, 0x02, 0x07, 0x08, 0x02, 0x05, 0x0c, +		0x0b, 0x01, 0x0c, 0x0a, 0x04, 0x0e, 0x0f, 0x09, +		0x0a, 0x03, 0x06, 0x0f, 0x09, 0x00, 0x00, 0x06, +		0x0c, 0x0a, 0x0b, 0x01, 0x07, 0x0d, 0x0d, 0x08, +		0x0f, 0x09, 0x01, 0x04, 0x03, 0x05, 0x0e, 0x0b, +		0x05, 0x0c, 0x02, 0x07, 0x08, 0x02, 0x04, 0x0e, +		0x77, 0x7d, 0x7d, 0x78, 0x7e, 0x7b, 0x73, 0x75, +		0x70, 0x76, 0x76, 0x7f, 0x79, 0x70, 0x7a, 0x73, +		0x71, 0x74, 0x72, 0x77, 0x78, 0x72, 0x75, 0x7c, +		0x7b, 0x71, 0x7c, 0x7a, 0x74, 0x7e, 0x7f, 0x79, +		0x7a, 0x73, 0x76, 0x7f, 0x79, 0x70, 0x70, 0x76, +		0x7c, 0x7a, 0x7b, 0x71, 0x77, 0x7d, 0x7d, 0x78, +		0x7f, 0x79, 0x71, 0x74, 0x73, 0x75, 0x7e, 0x7b, +		0x75, 0x7c, 0x72, 0x77, 0x78, 0x72, 0x74, 0x7e, +		0xb7, 0xbd, 0xbd, 0xb8, 0xbe, 0xbb, 0xb3, 0xb5, +		0xb0, 0xb6, 0xb6, 0xbf, 0xb9, 0xb0, 0xba, 0xb3, +		0xb1, 0xb4, 0xb2, 0xb7, 0xb8, 0xb2, 0xb5, 0xbc, +		0xbb, 0xb1, 0xbc, 0xba, 0xb4, 0xbe, 0xbf, 0xb9, +		0xba, 0xb3, 0xb6, 0xbf, 0xb9, 0xb0, 0xb0, 0xb6, +		0xbc, 0xba, 0xbb, 0xb1, 0xb7, 0xbd, 0xbd, 0xb8, +		0xbf, 0xb9, 0xb1, 0xb4, 0xb3, 0xb5, 0xbe, 0xbb, +		0xb5, 0xbc, 0xb2, 0xb7, 0xb8, 0xb2, 0xb4, 0xbe, +		0x47, 0x4d, 0x4d, 0x48, 0x4e, 0x4b, 0x43, 0x45, +		0x40, 0x46, 0x46, 0x4f, 0x49, 0x40, 0x4a, 0x43, +		0x41, 0x44, 0x42, 0x47, 0x48, 0x42, 0x45, 0x4c, +		0x4b, 0x41, 0x4c, 0x4a, 0x44, 0x4e, 0x4f, 0x49, +		0x4a, 0x43, 0x46, 0x4f, 0x49, 0x40, 0x40, 0x46, +		0x4c, 0x4a, 0x4b, 0x41, 0x47, 0x4d, 0x4d, 0x48, +		0x4f, 0x49, 0x41, 0x44, 0x43, 0x45, 0x4e, 0x4b, +		0x45, 0x4c, 0x42, 0x47, 0x48, 0x42, 0x44, 0x4e, +		0x17, 0x1d, 0x1d, 0x18, 0x1e, 0x1b, 0x13, 0x15, +		0x10, 0x16, 0x16, 0x1f, 0x19, 0x10, 0x1a, 0x13, +		0x11, 0x14, 0x12, 0x17, 0x18, 0x12, 0x15, 0x1c, +		0x1b, 0x11, 0x1c, 0x1a, 0x14, 0x1e, 0x1f, 0x19, +		0x1a, 0x13, 0x16, 0x1f, 0x19, 0x10, 0x10, 0x16, +		0x1c, 0x1a, 0x1b, 0x11, 0x17, 0x1d, 0x1d, 0x18, +		0x1f, 0x19, 0x11, 0x14, 0x13, 0x15, 0x1e, 0x1b, +		0x15, 0x1c, 0x12, 0x17, 0x18, 0x12, 0x14, 0x1e, +		0xf7, 0xfd, 0xfd, 0xf8, 0xfe, 0xfb, 0xf3, 0xf5, +		0xf0, 0xf6, 0xf6, 0xff, 0xf9, 0xf0, 0xfa, 0xf3, +		0xf1, 0xf4, 0xf2, 0xf7, 0xf8, 0xf2, 0xf5, 0xfc, +		0xfb, 0xf1, 0xfc, 0xfa, 0xf4, 0xfe, 0xff, 0xf9, +		0xfa, 0xf3, 0xf6, 0xff, 0xf9, 0xf0, 0xf0, 0xf6, +		0xfc, 0xfa, 0xfb, 0xf1, 0xf7, 0xfd, 0xfd, 0xf8, +		0xff, 0xf9, 0xf1, 0xf4, 0xf3, 0xf5, 0xfe, 0xfb, +		0xf5, 0xfc, 0xf2, 0xf7, 0xf8, 0xf2, 0xf4, 0xfe, +		0x27, 0x2d, 0x2d, 0x28, 0x2e, 0x2b, 0x23, 0x25, +		0x20, 0x26, 0x26, 0x2f, 0x29, 0x20, 0x2a, 0x23, +		0x21, 0x24, 0x22, 0x27, 0x28, 0x22, 0x25, 0x2c, +		0x2b, 0x21, 0x2c, 0x2a, 0x24, 0x2e, 0x2f, 0x29, +		0x2a, 0x23, 0x26, 0x2f, 0x29, 0x20, 0x20, 0x26, +		0x2c, 0x2a, 0x2b, 0x21, 0x27, 0x2d, 0x2d, 0x28, +		0x2f, 0x29, 0x21, 0x24, 0x23, 0x25, 0x2e, 0x2b, +		0x25, 0x2c, 0x22, 0x27, 0x28, 0x22, 0x24, 0x2e, +		0xe7, 0xed, 0xed, 0xe8, 0xee, 0xeb, 0xe3, 0xe5, +		0xe0, 0xe6, 0xe6, 0xef, 0xe9, 0xe0, 0xea, 0xe3, +		0xe1, 0xe4, 0xe2, 0xe7, 0xe8, 0xe2, 0xe5, 0xec, +		0xeb, 0xe1, 0xec, 0xea, 0xe4, 0xee, 0xef, 0xe9, +		0xea, 0xe3, 0xe6, 0xef, 0xe9, 0xe0, 0xe0, 0xe6, +		0xec, 0xea, 0xeb, 0xe1, 0xe7, 0xed, 0xed, 0xe8, +		0xef, 0xe9, 0xe1, 0xe4, 0xe3, 0xe5, 0xee, 0xeb, +		0xe5, 0xec, 0xe2, 0xe7, 0xe8, 0xe2, 0xe4, 0xee, +		0xc7, 0xcd, 0xcd, 0xc8, 0xce, 0xcb, 0xc3, 0xc5, +		0xc0, 0xc6, 0xc6, 0xcf, 0xc9, 0xc0, 0xca, 0xc3, +		0xc1, 0xc4, 0xc2, 0xc7, 0xc8, 0xc2, 0xc5, 0xcc, +		0xcb, 0xc1, 0xcc, 0xca, 0xc4, 0xce, 0xcf, 0xc9, +		0xca, 0xc3, 0xc6, 0xcf, 0xc9, 0xc0, 0xc0, 0xc6, +		0xcc, 0xca, 0xcb, 0xc1, 0xc7, 0xcd, 0xcd, 0xc8, +		0xcf, 0xc9, 0xc1, 0xc4, 0xc3, 0xc5, 0xce, 0xcb, +		0xc5, 0xcc, 0xc2, 0xc7, 0xc8, 0xc2, 0xc4, 0xce, +		0x37, 0x3d, 0x3d, 0x38, 0x3e, 0x3b, 0x33, 0x35, +		0x30, 0x36, 0x36, 0x3f, 0x39, 0x30, 0x3a, 0x33, +		0x31, 0x34, 0x32, 0x37, 0x38, 0x32, 0x35, 0x3c, +		0x3b, 0x31, 0x3c, 0x3a, 0x34, 0x3e, 0x3f, 0x39, +		0x3a, 0x33, 0x36, 0x3f, 0x39, 0x30, 0x30, 0x36, +		0x3c, 0x3a, 0x3b, 0x31, 0x37, 0x3d, 0x3d, 0x38, +		0x3f, 0x39, 0x31, 0x34, 0x33, 0x35, 0x3e, 0x3b, +		0x35, 0x3c, 0x32, 0x37, 0x38, 0x32, 0x34, 0x3e, +		0x57, 0x5d, 0x5d, 0x58, 0x5e, 0x5b, 0x53, 0x55, +		0x50, 0x56, 0x56, 0x5f, 0x59, 0x50, 0x5a, 0x53, +		0x51, 0x54, 0x52, 0x57, 0x58, 0x52, 0x55, 0x5c, +		0x5b, 0x51, 0x5c, 0x5a, 0x54, 0x5e, 0x5f, 0x59, +		0x5a, 0x53, 0x56, 0x5f, 0x59, 0x50, 0x50, 0x56, +		0x5c, 0x5a, 0x5b, 0x51, 0x57, 0x5d, 0x5d, 0x58, +		0x5f, 0x59, 0x51, 0x54, 0x53, 0x55, 0x5e, 0x5b, +		0x55, 0x5c, 0x52, 0x57, 0x58, 0x52, 0x54, 0x5e, +		0xb7, 0xbd, 0xbd, 0xb8, 0xbe, 0xbb, 0xb3, 0xb5, +		0xb0, 0xb6, 0xb6, 0xbf, 0xb9, 0xb0, 0xba, 0xb3, +		0xb1, 0xb4, 0xb2, 0xb7, 0xb8, 0xb2, 0xb5, 0xbc, +		0xbb, 0xb1, 0xbc, 0xba, 0xb4, 0xbe, 0xbf, 0xb9, +		0xba, 0xb3, 0xb6, 0xbf, 0xb9, 0xb0, 0xb0, 0xb6, +		0xbc, 0xba, 0xbb, 0xb1, 0xb7, 0xbd, 0xbd, 0xb8, +		0xbf, 0xb9, 0xb1, 0xb4, 0xb3, 0xb5, 0xbe, 0xbb, +		0xb5, 0xbc, 0xb2, 0xb7, 0xb8, 0xb2, 0xb4, 0xbe, +		0xa7, 0xad, 0xad, 0xa8, 0xae, 0xab, 0xa3, 0xa5, +		0xa0, 0xa6, 0xa6, 0xaf, 0xa9, 0xa0, 0xaa, 0xa3, +		0xa1, 0xa4, 0xa2, 0xa7, 0xa8, 0xa2, 0xa5, 0xac, +		0xab, 0xa1, 0xac, 0xaa, 0xa4, 0xae, 0xaf, 0xa9, +		0xaa, 0xa3, 0xa6, 0xaf, 0xa9, 0xa0, 0xa0, 0xa6, +		0xac, 0xaa, 0xab, 0xa1, 0xa7, 0xad, 0xad, 0xa8, +		0xaf, 0xa9, 0xa1, 0xa4, 0xa3, 0xa5, 0xae, 0xab, +		0xa5, 0xac, 0xa2, 0xa7, 0xa8, 0xa2, 0xa4, 0xae, +		0x57, 0x5d, 0x5d, 0x58, 0x5e, 0x5b, 0x53, 0x55, +		0x50, 0x56, 0x56, 0x5f, 0x59, 0x50, 0x5a, 0x53, +		0x51, 0x54, 0x52, 0x57, 0x58, 0x52, 0x55, 0x5c, +		0x5b, 0x51, 0x5c, 0x5a, 0x54, 0x5e, 0x5f, 0x59, +		0x5a, 0x53, 0x56, 0x5f, 0x59, 0x50, 0x50, 0x56, +		0x5c, 0x5a, 0x5b, 0x51, 0x57, 0x5d, 0x5d, 0x58, +		0x5f, 0x59, 0x51, 0x54, 0x53, 0x55, 0x5e, 0x5b, +		0x55, 0x5c, 0x52, 0x57, 0x58, 0x52, 0x54, 0x5e, +		0xe7, 0xed, 0xed, 0xe8, 0xee, 0xeb, 0xe3, 0xe5, +		0xe0, 0xe6, 0xe6, 0xef, 0xe9, 0xe0, 0xea, 0xe3, +		0xe1, 0xe4, 0xe2, 0xe7, 0xe8, 0xe2, 0xe5, 0xec, +		0xeb, 0xe1, 0xec, 0xea, 0xe4, 0xee, 0xef, 0xe9, +		0xea, 0xe3, 0xe6, 0xef, 0xe9, 0xe0, 0xe0, 0xe6, +		0xec, 0xea, 0xeb, 0xe1, 0xe7, 0xed, 0xed, 0xe8, +		0xef, 0xe9, 0xe1, 0xe4, 0xe3, 0xe5, 0xee, 0xeb, +		0xe5, 0xec, 0xe2, 0xe7, 0xe8, 0xe2, 0xe4, 0xee, +		0x27, 0x2d, 0x2d, 0x28, 0x2e, 0x2b, 0x23, 0x25, +		0x20, 0x26, 0x26, 0x2f, 0x29, 0x20, 0x2a, 0x23, +		0x21, 0x24, 0x22, 0x27, 0x28, 0x22, 0x25, 0x2c, +		0x2b, 0x21, 0x2c, 0x2a, 0x24, 0x2e, 0x2f, 0x29, +		0x2a, 0x23, 0x26, 0x2f, 0x29, 0x20, 0x20, 0x26, +		0x2c, 0x2a, 0x2b, 0x21, 0x27, 0x2d, 0x2d, 0x28, +		0x2f, 0x29, 0x21, 0x24, 0x23, 0x25, 0x2e, 0x2b, +		0x25, 0x2c, 0x22, 0x27, 0x28, 0x22, 0x24, 0x2e, +		0x77, 0x7d, 0x7d, 0x78, 0x7e, 0x7b, 0x73, 0x75, +		0x70, 0x76, 0x76, 0x7f, 0x79, 0x70, 0x7a, 0x73, +		0x71, 0x74, 0x72, 0x77, 0x78, 0x72, 0x75, 0x7c, +		0x7b, 0x71, 0x7c, 0x7a, 0x74, 0x7e, 0x7f, 0x79, +		0x7a, 0x73, 0x76, 0x7f, 0x79, 0x70, 0x70, 0x76, +		0x7c, 0x7a, 0x7b, 0x71, 0x77, 0x7d, 0x7d, 0x78, +		0x7f, 0x79, 0x71, 0x74, 0x73, 0x75, 0x7e, 0x7b, +		0x75, 0x7c, 0x72, 0x77, 0x78, 0x72, 0x74, 0x7e, +		0xc7, 0xcd, 0xcd, 0xc8, 0xce, 0xcb, 0xc3, 0xc5, +		0xc0, 0xc6, 0xc6, 0xcf, 0xc9, 0xc0, 0xca, 0xc3, +		0xc1, 0xc4, 0xc2, 0xc7, 0xc8, 0xc2, 0xc5, 0xcc, +		0xcb, 0xc1, 0xcc, 0xca, 0xc4, 0xce, 0xcf, 0xc9, +		0xca, 0xc3, 0xc6, 0xcf, 0xc9, 0xc0, 0xc0, 0xc6, +		0xcc, 0xca, 0xcb, 0xc1, 0xc7, 0xcd, 0xcd, 0xc8, +		0xcf, 0xc9, 0xc1, 0xc4, 0xc3, 0xc5, 0xce, 0xcb, +		0xc5, 0xcc, 0xc2, 0xc7, 0xc8, 0xc2, 0xc4, 0xce, +	},{ +		0x2c, 0x2a, 0x21, 0x2f, 0x2a, 0x24, 0x2f, 0x22, +		0x29, 0x27, 0x22, 0x2c, 0x26, 0x29, 0x28, 0x25, +		0x20, 0x26, 0x2d, 0x21, 0x23, 0x2d, 0x24, 0x2e, +		0x2e, 0x20, 0x27, 0x2b, 0x25, 0x23, 0x2b, 0x28, +		0x29, 0x24, 0x2e, 0x23, 0x2f, 0x22, 0x25, 0x2c, +		0x22, 0x29, 0x28, 0x25, 0x2c, 0x2f, 0x23, 0x2a, +		0x27, 0x2b, 0x20, 0x2e, 0x24, 0x21, 0x2a, 0x27, +		0x21, 0x26, 0x2d, 0x20, 0x2b, 0x28, 0x26, 0x2d, +		0xec, 0xea, 0xe1, 0xef, 0xea, 0xe4, 0xef, 0xe2, +		0xe9, 0xe7, 0xe2, 0xec, 0xe6, 0xe9, 0xe8, 0xe5, +		0xe0, 0xe6, 0xed, 0xe1, 0xe3, 0xed, 0xe4, 0xee, +		0xee, 0xe0, 0xe7, 0xeb, 0xe5, 0xe3, 0xeb, 0xe8, +		0xe9, 0xe4, 0xee, 0xe3, 0xef, 0xe2, 0xe5, 0xec, +		0xe2, 0xe9, 0xe8, 0xe5, 0xec, 0xef, 0xe3, 0xea, +		0xe7, 0xeb, 0xe0, 0xee, 0xe4, 0xe1, 0xea, 0xe7, +		0xe1, 0xe6, 0xed, 0xe0, 0xeb, 0xe8, 0xe6, 0xed, +		0xcc, 0xca, 0xc1, 0xcf, 0xca, 0xc4, 0xcf, 0xc2, +		0xc9, 0xc7, 0xc2, 0xcc, 0xc6, 0xc9, 0xc8, 0xc5, +		0xc0, 0xc6, 0xcd, 0xc1, 0xc3, 0xcd, 0xc4, 0xce, +		0xce, 0xc0, 0xc7, 0xcb, 0xc5, 0xc3, 0xcb, 0xc8, +		0xc9, 0xc4, 0xce, 0xc3, 0xcf, 0xc2, 0xc5, 0xcc, +		0xc2, 0xc9, 0xc8, 0xc5, 0xcc, 0xcf, 0xc3, 0xca, +		0xc7, 0xcb, 0xc0, 0xce, 0xc4, 0xc1, 0xca, 0xc7, +		0xc1, 0xc6, 0xcd, 0xc0, 0xcb, 0xc8, 0xc6, 0xcd, +		0xbc, 0xba, 0xb1, 0xbf, 0xba, 0xb4, 0xbf, 0xb2, +		0xb9, 0xb7, 0xb2, 0xbc, 0xb6, 0xb9, 0xb8, 0xb5, +		0xb0, 0xb6, 0xbd, 0xb1, 0xb3, 0xbd, 0xb4, 0xbe, +		0xbe, 0xb0, 0xb7, 0xbb, 0xb5, 0xb3, 0xbb, 0xb8, +		0xb9, 0xb4, 0xbe, 0xb3, 0xbf, 0xb2, 0xb5, 0xbc, +		0xb2, 0xb9, 0xb8, 0xb5, 0xbc, 0xbf, 0xb3, 0xba, +		0xb7, 0xbb, 0xb0, 0xbe, 0xb4, 0xb1, 0xba, 0xb7, +		0xb1, 0xb6, 0xbd, 0xb0, 0xbb, 0xb8, 0xb6, 0xbd, +		0x4c, 0x4a, 0x41, 0x4f, 0x4a, 0x44, 0x4f, 0x42, +		0x49, 0x47, 0x42, 0x4c, 0x46, 0x49, 0x48, 0x45, +		0x40, 0x46, 0x4d, 0x41, 0x43, 0x4d, 0x44, 0x4e, +		0x4e, 0x40, 0x47, 0x4b, 0x45, 0x43, 0x4b, 0x48, +		0x49, 0x44, 0x4e, 0x43, 0x4f, 0x42, 0x45, 0x4c, +		0x42, 0x49, 0x48, 0x45, 0x4c, 0x4f, 0x43, 0x4a, +		0x47, 0x4b, 0x40, 0x4e, 0x44, 0x41, 0x4a, 0x47, +		0x41, 0x46, 0x4d, 0x40, 0x4b, 0x48, 0x46, 0x4d, +		0x2c, 0x2a, 0x21, 0x2f, 0x2a, 0x24, 0x2f, 0x22, +		0x29, 0x27, 0x22, 0x2c, 0x26, 0x29, 0x28, 0x25, +		0x20, 0x26, 0x2d, 0x21, 0x23, 0x2d, 0x24, 0x2e, +		0x2e, 0x20, 0x27, 0x2b, 0x25, 0x23, 0x2b, 0x28, +		0x29, 0x24, 0x2e, 0x23, 0x2f, 0x22, 0x25, 0x2c, +		0x22, 0x29, 0x28, 0x25, 0x2c, 0x2f, 0x23, 0x2a, +		0x27, 0x2b, 0x20, 0x2e, 0x24, 0x21, 0x2a, 0x27, +		0x21, 0x26, 0x2d, 0x20, 0x2b, 0x28, 0x26, 0x2d, +		0x1c, 0x1a, 0x11, 0x1f, 0x1a, 0x14, 0x1f, 0x12, +		0x19, 0x17, 0x12, 0x1c, 0x16, 0x19, 0x18, 0x15, +		0x10, 0x16, 0x1d, 0x11, 0x13, 0x1d, 0x14, 0x1e, +		0x1e, 0x10, 0x17, 0x1b, 0x15, 0x13, 0x1b, 0x18, +		0x19, 0x14, 0x1e, 0x13, 0x1f, 0x12, 0x15, 0x1c, +		0x12, 0x19, 0x18, 0x15, 0x1c, 0x1f, 0x13, 0x1a, +		0x17, 0x1b, 0x10, 0x1e, 0x14, 0x11, 0x1a, 0x17, +		0x11, 0x16, 0x1d, 0x10, 0x1b, 0x18, 0x16, 0x1d, +		0xcc, 0xca, 0xc1, 0xcf, 0xca, 0xc4, 0xcf, 0xc2, +		0xc9, 0xc7, 0xc2, 0xcc, 0xc6, 0xc9, 0xc8, 0xc5, +		0xc0, 0xc6, 0xcd, 0xc1, 0xc3, 0xcd, 0xc4, 0xce, +		0xce, 0xc0, 0xc7, 0xcb, 0xc5, 0xc3, 0xcb, 0xc8, +		0xc9, 0xc4, 0xce, 0xc3, 0xcf, 0xc2, 0xc5, 0xcc, +		0xc2, 0xc9, 0xc8, 0xc5, 0xcc, 0xcf, 0xc3, 0xca, +		0xc7, 0xcb, 0xc0, 0xce, 0xc4, 0xc1, 0xca, 0xc7, +		0xc1, 0xc6, 0xcd, 0xc0, 0xcb, 0xc8, 0xc6, 0xcd, +		0x7c, 0x7a, 0x71, 0x7f, 0x7a, 0x74, 0x7f, 0x72, +		0x79, 0x77, 0x72, 0x7c, 0x76, 0x79, 0x78, 0x75, +		0x70, 0x76, 0x7d, 0x71, 0x73, 0x7d, 0x74, 0x7e, +		0x7e, 0x70, 0x77, 0x7b, 0x75, 0x73, 0x7b, 0x78, +		0x79, 0x74, 0x7e, 0x73, 0x7f, 0x72, 0x75, 0x7c, +		0x72, 0x79, 0x78, 0x75, 0x7c, 0x7f, 0x73, 0x7a, +		0x77, 0x7b, 0x70, 0x7e, 0x74, 0x71, 0x7a, 0x77, +		0x71, 0x76, 0x7d, 0x70, 0x7b, 0x78, 0x76, 0x7d, +		0x4c, 0x4a, 0x41, 0x4f, 0x4a, 0x44, 0x4f, 0x42, +		0x49, 0x47, 0x42, 0x4c, 0x46, 0x49, 0x48, 0x45, +		0x40, 0x46, 0x4d, 0x41, 0x43, 0x4d, 0x44, 0x4e, +		0x4e, 0x40, 0x47, 0x4b, 0x45, 0x43, 0x4b, 0x48, +		0x49, 0x44, 0x4e, 0x43, 0x4f, 0x42, 0x45, 0x4c, +		0x42, 0x49, 0x48, 0x45, 0x4c, 0x4f, 0x43, 0x4a, +		0x47, 0x4b, 0x40, 0x4e, 0x44, 0x41, 0x4a, 0x47, +		0x41, 0x46, 0x4d, 0x40, 0x4b, 0x48, 0x46, 0x4d, +		0xac, 0xaa, 0xa1, 0xaf, 0xaa, 0xa4, 0xaf, 0xa2, +		0xa9, 0xa7, 0xa2, 0xac, 0xa6, 0xa9, 0xa8, 0xa5, +		0xa0, 0xa6, 0xad, 0xa1, 0xa3, 0xad, 0xa4, 0xae, +		0xae, 0xa0, 0xa7, 0xab, 0xa5, 0xa3, 0xab, 0xa8, +		0xa9, 0xa4, 0xae, 0xa3, 0xaf, 0xa2, 0xa5, 0xac, +		0xa2, 0xa9, 0xa8, 0xa5, 0xac, 0xaf, 0xa3, 0xaa, +		0xa7, 0xab, 0xa0, 0xae, 0xa4, 0xa1, 0xaa, 0xa7, +		0xa1, 0xa6, 0xad, 0xa0, 0xab, 0xa8, 0xa6, 0xad, +		0x7c, 0x7a, 0x71, 0x7f, 0x7a, 0x74, 0x7f, 0x72, +		0x79, 0x77, 0x72, 0x7c, 0x76, 0x79, 0x78, 0x75, +		0x70, 0x76, 0x7d, 0x71, 0x73, 0x7d, 0x74, 0x7e, +		0x7e, 0x70, 0x77, 0x7b, 0x75, 0x73, 0x7b, 0x78, +		0x79, 0x74, 0x7e, 0x73, 0x7f, 0x72, 0x75, 0x7c, +		0x72, 0x79, 0x78, 0x75, 0x7c, 0x7f, 0x73, 0x7a, +		0x77, 0x7b, 0x70, 0x7e, 0x74, 0x71, 0x7a, 0x77, +		0x71, 0x76, 0x7d, 0x70, 0x7b, 0x78, 0x76, 0x7d, +		0xbc, 0xba, 0xb1, 0xbf, 0xba, 0xb4, 0xbf, 0xb2, +		0xb9, 0xb7, 0xb2, 0xbc, 0xb6, 0xb9, 0xb8, 0xb5, +		0xb0, 0xb6, 0xbd, 0xb1, 0xb3, 0xbd, 0xb4, 0xbe, +		0xbe, 0xb0, 0xb7, 0xbb, 0xb5, 0xb3, 0xbb, 0xb8, +		0xb9, 0xb4, 0xbe, 0xb3, 0xbf, 0xb2, 0xb5, 0xbc, +		0xb2, 0xb9, 0xb8, 0xb5, 0xbc, 0xbf, 0xb3, 0xba, +		0xb7, 0xbb, 0xb0, 0xbe, 0xb4, 0xb1, 0xba, 0xb7, +		0xb1, 0xb6, 0xbd, 0xb0, 0xbb, 0xb8, 0xb6, 0xbd, +		0xdc, 0xda, 0xd1, 0xdf, 0xda, 0xd4, 0xdf, 0xd2, +		0xd9, 0xd7, 0xd2, 0xdc, 0xd6, 0xd9, 0xd8, 0xd5, +		0xd0, 0xd6, 0xdd, 0xd1, 0xd3, 0xdd, 0xd4, 0xde, +		0xde, 0xd0, 0xd7, 0xdb, 0xd5, 0xd3, 0xdb, 0xd8, +		0xd9, 0xd4, 0xde, 0xd3, 0xdf, 0xd2, 0xd5, 0xdc, +		0xd2, 0xd9, 0xd8, 0xd5, 0xdc, 0xdf, 0xd3, 0xda, +		0xd7, 0xdb, 0xd0, 0xde, 0xd4, 0xd1, 0xda, 0xd7, +		0xd1, 0xd6, 0xdd, 0xd0, 0xdb, 0xd8, 0xd6, 0xdd, +		0x6c, 0x6a, 0x61, 0x6f, 0x6a, 0x64, 0x6f, 0x62, +		0x69, 0x67, 0x62, 0x6c, 0x66, 0x69, 0x68, 0x65, +		0x60, 0x66, 0x6d, 0x61, 0x63, 0x6d, 0x64, 0x6e, +		0x6e, 0x60, 0x67, 0x6b, 0x65, 0x63, 0x6b, 0x68, +		0x69, 0x64, 0x6e, 0x63, 0x6f, 0x62, 0x65, 0x6c, +		0x62, 0x69, 0x68, 0x65, 0x6c, 0x6f, 0x63, 0x6a, +		0x67, 0x6b, 0x60, 0x6e, 0x64, 0x61, 0x6a, 0x67, +		0x61, 0x66, 0x6d, 0x60, 0x6b, 0x68, 0x66, 0x6d, +		0x1c, 0x1a, 0x11, 0x1f, 0x1a, 0x14, 0x1f, 0x12, +		0x19, 0x17, 0x12, 0x1c, 0x16, 0x19, 0x18, 0x15, +		0x10, 0x16, 0x1d, 0x11, 0x13, 0x1d, 0x14, 0x1e, +		0x1e, 0x10, 0x17, 0x1b, 0x15, 0x13, 0x1b, 0x18, +		0x19, 0x14, 0x1e, 0x13, 0x1f, 0x12, 0x15, 0x1c, +		0x12, 0x19, 0x18, 0x15, 0x1c, 0x1f, 0x13, 0x1a, +		0x17, 0x1b, 0x10, 0x1e, 0x14, 0x11, 0x1a, 0x17, +		0x11, 0x16, 0x1d, 0x10, 0x1b, 0x18, 0x16, 0x1d, +		0x8c, 0x8a, 0x81, 0x8f, 0x8a, 0x84, 0x8f, 0x82, +		0x89, 0x87, 0x82, 0x8c, 0x86, 0x89, 0x88, 0x85, +		0x80, 0x86, 0x8d, 0x81, 0x83, 0x8d, 0x84, 0x8e, +		0x8e, 0x80, 0x87, 0x8b, 0x85, 0x83, 0x8b, 0x88, +		0x89, 0x84, 0x8e, 0x83, 0x8f, 0x82, 0x85, 0x8c, +		0x82, 0x89, 0x88, 0x85, 0x8c, 0x8f, 0x83, 0x8a, +		0x87, 0x8b, 0x80, 0x8e, 0x84, 0x81, 0x8a, 0x87, +		0x81, 0x86, 0x8d, 0x80, 0x8b, 0x88, 0x86, 0x8d, +		0x5c, 0x5a, 0x51, 0x5f, 0x5a, 0x54, 0x5f, 0x52, +		0x59, 0x57, 0x52, 0x5c, 0x56, 0x59, 0x58, 0x55, +		0x50, 0x56, 0x5d, 0x51, 0x53, 0x5d, 0x54, 0x5e, +		0x5e, 0x50, 0x57, 0x5b, 0x55, 0x53, 0x5b, 0x58, +		0x59, 0x54, 0x5e, 0x53, 0x5f, 0x52, 0x55, 0x5c, +		0x52, 0x59, 0x58, 0x55, 0x5c, 0x5f, 0x53, 0x5a, +		0x57, 0x5b, 0x50, 0x5e, 0x54, 0x51, 0x5a, 0x57, +		0x51, 0x56, 0x5d, 0x50, 0x5b, 0x58, 0x56, 0x5d, +		0x5c, 0x5a, 0x51, 0x5f, 0x5a, 0x54, 0x5f, 0x52, +		0x59, 0x57, 0x52, 0x5c, 0x56, 0x59, 0x58, 0x55, +		0x50, 0x56, 0x5d, 0x51, 0x53, 0x5d, 0x54, 0x5e, +		0x5e, 0x50, 0x57, 0x5b, 0x55, 0x53, 0x5b, 0x58, +		0x59, 0x54, 0x5e, 0x53, 0x5f, 0x52, 0x55, 0x5c, +		0x52, 0x59, 0x58, 0x55, 0x5c, 0x5f, 0x53, 0x5a, +		0x57, 0x5b, 0x50, 0x5e, 0x54, 0x51, 0x5a, 0x57, +		0x51, 0x56, 0x5d, 0x50, 0x5b, 0x58, 0x56, 0x5d, +		0x0c, 0x0a, 0x01, 0x0f, 0x0a, 0x04, 0x0f, 0x02, +		0x09, 0x07, 0x02, 0x0c, 0x06, 0x09, 0x08, 0x05, +		0x00, 0x06, 0x0d, 0x01, 0x03, 0x0d, 0x04, 0x0e, +		0x0e, 0x00, 0x07, 0x0b, 0x05, 0x03, 0x0b, 0x08, +		0x09, 0x04, 0x0e, 0x03, 0x0f, 0x02, 0x05, 0x0c, +		0x02, 0x09, 0x08, 0x05, 0x0c, 0x0f, 0x03, 0x0a, +		0x07, 0x0b, 0x00, 0x0e, 0x04, 0x01, 0x0a, 0x07, +		0x01, 0x06, 0x0d, 0x00, 0x0b, 0x08, 0x06, 0x0d, +		0x3c, 0x3a, 0x31, 0x3f, 0x3a, 0x34, 0x3f, 0x32, +		0x39, 0x37, 0x32, 0x3c, 0x36, 0x39, 0x38, 0x35, +		0x30, 0x36, 0x3d, 0x31, 0x33, 0x3d, 0x34, 0x3e, +		0x3e, 0x30, 0x37, 0x3b, 0x35, 0x33, 0x3b, 0x38, +		0x39, 0x34, 0x3e, 0x33, 0x3f, 0x32, 0x35, 0x3c, +		0x32, 0x39, 0x38, 0x35, 0x3c, 0x3f, 0x33, 0x3a, +		0x37, 0x3b, 0x30, 0x3e, 0x34, 0x31, 0x3a, 0x37, +		0x31, 0x36, 0x3d, 0x30, 0x3b, 0x38, 0x36, 0x3d, +		0xfc, 0xfa, 0xf1, 0xff, 0xfa, 0xf4, 0xff, 0xf2, +		0xf9, 0xf7, 0xf2, 0xfc, 0xf6, 0xf9, 0xf8, 0xf5, +		0xf0, 0xf6, 0xfd, 0xf1, 0xf3, 0xfd, 0xf4, 0xfe, +		0xfe, 0xf0, 0xf7, 0xfb, 0xf5, 0xf3, 0xfb, 0xf8, +		0xf9, 0xf4, 0xfe, 0xf3, 0xff, 0xf2, 0xf5, 0xfc, +		0xf2, 0xf9, 0xf8, 0xf5, 0xfc, 0xff, 0xf3, 0xfa, +		0xf7, 0xfb, 0xf0, 0xfe, 0xf4, 0xf1, 0xfa, 0xf7, +		0xf1, 0xf6, 0xfd, 0xf0, 0xfb, 0xf8, 0xf6, 0xfd, +		0xfc, 0xfa, 0xf1, 0xff, 0xfa, 0xf4, 0xff, 0xf2, +		0xf9, 0xf7, 0xf2, 0xfc, 0xf6, 0xf9, 0xf8, 0xf5, +		0xf0, 0xf6, 0xfd, 0xf1, 0xf3, 0xfd, 0xf4, 0xfe, +		0xfe, 0xf0, 0xf7, 0xfb, 0xf5, 0xf3, 0xfb, 0xf8, +		0xf9, 0xf4, 0xfe, 0xf3, 0xff, 0xf2, 0xf5, 0xfc, +		0xf2, 0xf9, 0xf8, 0xf5, 0xfc, 0xff, 0xf3, 0xfa, +		0xf7, 0xfb, 0xf0, 0xfe, 0xf4, 0xf1, 0xfa, 0xf7, +		0xf1, 0xf6, 0xfd, 0xf0, 0xfb, 0xf8, 0xf6, 0xfd, +		0xac, 0xaa, 0xa1, 0xaf, 0xaa, 0xa4, 0xaf, 0xa2, +		0xa9, 0xa7, 0xa2, 0xac, 0xa6, 0xa9, 0xa8, 0xa5, +		0xa0, 0xa6, 0xad, 0xa1, 0xa3, 0xad, 0xa4, 0xae, +		0xae, 0xa0, 0xa7, 0xab, 0xa5, 0xa3, 0xab, 0xa8, +		0xa9, 0xa4, 0xae, 0xa3, 0xaf, 0xa2, 0xa5, 0xac, +		0xa2, 0xa9, 0xa8, 0xa5, 0xac, 0xaf, 0xa3, 0xaa, +		0xa7, 0xab, 0xa0, 0xae, 0xa4, 0xa1, 0xaa, 0xa7, +		0xa1, 0xa6, 0xad, 0xa0, 0xab, 0xa8, 0xa6, 0xad, +		0xdc, 0xda, 0xd1, 0xdf, 0xda, 0xd4, 0xdf, 0xd2, +		0xd9, 0xd7, 0xd2, 0xdc, 0xd6, 0xd9, 0xd8, 0xd5, +		0xd0, 0xd6, 0xdd, 0xd1, 0xd3, 0xdd, 0xd4, 0xde, +		0xde, 0xd0, 0xd7, 0xdb, 0xd5, 0xd3, 0xdb, 0xd8, +		0xd9, 0xd4, 0xde, 0xd3, 0xdf, 0xd2, 0xd5, 0xdc, +		0xd2, 0xd9, 0xd8, 0xd5, 0xdc, 0xdf, 0xd3, 0xda, +		0xd7, 0xdb, 0xd0, 0xde, 0xd4, 0xd1, 0xda, 0xd7, +		0xd1, 0xd6, 0xdd, 0xd0, 0xdb, 0xd8, 0xd6, 0xdd, +		0x3c, 0x3a, 0x31, 0x3f, 0x3a, 0x34, 0x3f, 0x32, +		0x39, 0x37, 0x32, 0x3c, 0x36, 0x39, 0x38, 0x35, +		0x30, 0x36, 0x3d, 0x31, 0x33, 0x3d, 0x34, 0x3e, +		0x3e, 0x30, 0x37, 0x3b, 0x35, 0x33, 0x3b, 0x38, +		0x39, 0x34, 0x3e, 0x33, 0x3f, 0x32, 0x35, 0x3c, +		0x32, 0x39, 0x38, 0x35, 0x3c, 0x3f, 0x33, 0x3a, +		0x37, 0x3b, 0x30, 0x3e, 0x34, 0x31, 0x3a, 0x37, +		0x31, 0x36, 0x3d, 0x30, 0x3b, 0x38, 0x36, 0x3d, +		0x0c, 0x0a, 0x01, 0x0f, 0x0a, 0x04, 0x0f, 0x02, +		0x09, 0x07, 0x02, 0x0c, 0x06, 0x09, 0x08, 0x05, +		0x00, 0x06, 0x0d, 0x01, 0x03, 0x0d, 0x04, 0x0e, +		0x0e, 0x00, 0x07, 0x0b, 0x05, 0x03, 0x0b, 0x08, +		0x09, 0x04, 0x0e, 0x03, 0x0f, 0x02, 0x05, 0x0c, +		0x02, 0x09, 0x08, 0x05, 0x0c, 0x0f, 0x03, 0x0a, +		0x07, 0x0b, 0x00, 0x0e, 0x04, 0x01, 0x0a, 0x07, +		0x01, 0x06, 0x0d, 0x00, 0x0b, 0x08, 0x06, 0x0d, +		0x9c, 0x9a, 0x91, 0x9f, 0x9a, 0x94, 0x9f, 0x92, +		0x99, 0x97, 0x92, 0x9c, 0x96, 0x99, 0x98, 0x95, +		0x90, 0x96, 0x9d, 0x91, 0x93, 0x9d, 0x94, 0x9e, +		0x9e, 0x90, 0x97, 0x9b, 0x95, 0x93, 0x9b, 0x98, +		0x99, 0x94, 0x9e, 0x93, 0x9f, 0x92, 0x95, 0x9c, +		0x92, 0x99, 0x98, 0x95, 0x9c, 0x9f, 0x93, 0x9a, +		0x97, 0x9b, 0x90, 0x9e, 0x94, 0x91, 0x9a, 0x97, +		0x91, 0x96, 0x9d, 0x90, 0x9b, 0x98, 0x96, 0x9d, +		0xec, 0xea, 0xe1, 0xef, 0xea, 0xe4, 0xef, 0xe2, +		0xe9, 0xe7, 0xe2, 0xec, 0xe6, 0xe9, 0xe8, 0xe5, +		0xe0, 0xe6, 0xed, 0xe1, 0xe3, 0xed, 0xe4, 0xee, +		0xee, 0xe0, 0xe7, 0xeb, 0xe5, 0xe3, 0xeb, 0xe8, +		0xe9, 0xe4, 0xee, 0xe3, 0xef, 0xe2, 0xe5, 0xec, +		0xe2, 0xe9, 0xe8, 0xe5, 0xec, 0xef, 0xe3, 0xea, +		0xe7, 0xeb, 0xe0, 0xee, 0xe4, 0xe1, 0xea, 0xe7, +		0xe1, 0xe6, 0xed, 0xe0, 0xeb, 0xe8, 0xe6, 0xed, +		0x8c, 0x8a, 0x81, 0x8f, 0x8a, 0x84, 0x8f, 0x82, +		0x89, 0x87, 0x82, 0x8c, 0x86, 0x89, 0x88, 0x85, +		0x80, 0x86, 0x8d, 0x81, 0x83, 0x8d, 0x84, 0x8e, +		0x8e, 0x80, 0x87, 0x8b, 0x85, 0x83, 0x8b, 0x88, +		0x89, 0x84, 0x8e, 0x83, 0x8f, 0x82, 0x85, 0x8c, +		0x82, 0x89, 0x88, 0x85, 0x8c, 0x8f, 0x83, 0x8a, +		0x87, 0x8b, 0x80, 0x8e, 0x84, 0x81, 0x8a, 0x87, +		0x81, 0x86, 0x8d, 0x80, 0x8b, 0x88, 0x86, 0x8d, +		0x9c, 0x9a, 0x91, 0x9f, 0x9a, 0x94, 0x9f, 0x92, +		0x99, 0x97, 0x92, 0x9c, 0x96, 0x99, 0x98, 0x95, +		0x90, 0x96, 0x9d, 0x91, 0x93, 0x9d, 0x94, 0x9e, +		0x9e, 0x90, 0x97, 0x9b, 0x95, 0x93, 0x9b, 0x98, +		0x99, 0x94, 0x9e, 0x93, 0x9f, 0x92, 0x95, 0x9c, +		0x92, 0x99, 0x98, 0x95, 0x9c, 0x9f, 0x93, 0x9a, +		0x97, 0x9b, 0x90, 0x9e, 0x94, 0x91, 0x9a, 0x97, +		0x91, 0x96, 0x9d, 0x90, 0x9b, 0x98, 0x96, 0x9d, +		0x6c, 0x6a, 0x61, 0x6f, 0x6a, 0x64, 0x6f, 0x62, +		0x69, 0x67, 0x62, 0x6c, 0x66, 0x69, 0x68, 0x65, +		0x60, 0x66, 0x6d, 0x61, 0x63, 0x6d, 0x64, 0x6e, +		0x6e, 0x60, 0x67, 0x6b, 0x65, 0x63, 0x6b, 0x68, +		0x69, 0x64, 0x6e, 0x63, 0x6f, 0x62, 0x65, 0x6c, +		0x62, 0x69, 0x68, 0x65, 0x6c, 0x6f, 0x63, 0x6a, +		0x67, 0x6b, 0x60, 0x6e, 0x64, 0x61, 0x6a, 0x67, +		0x61, 0x66, 0x6d, 0x60, 0x6b, 0x68, 0x66, 0x6d, +		0x4c, 0x4a, 0x41, 0x4f, 0x4a, 0x44, 0x4f, 0x42, +		0x49, 0x47, 0x42, 0x4c, 0x46, 0x49, 0x48, 0x45, +		0x40, 0x46, 0x4d, 0x41, 0x43, 0x4d, 0x44, 0x4e, +		0x4e, 0x40, 0x47, 0x4b, 0x45, 0x43, 0x4b, 0x48, +		0x49, 0x44, 0x4e, 0x43, 0x4f, 0x42, 0x45, 0x4c, +		0x42, 0x49, 0x48, 0x45, 0x4c, 0x4f, 0x43, 0x4a, +		0x47, 0x4b, 0x40, 0x4e, 0x44, 0x41, 0x4a, 0x47, +		0x41, 0x46, 0x4d, 0x40, 0x4b, 0x48, 0x46, 0x4d, +		0xbc, 0xba, 0xb1, 0xbf, 0xba, 0xb4, 0xbf, 0xb2, +		0xb9, 0xb7, 0xb2, 0xbc, 0xb6, 0xb9, 0xb8, 0xb5, +		0xb0, 0xb6, 0xbd, 0xb1, 0xb3, 0xbd, 0xb4, 0xbe, +		0xbe, 0xb0, 0xb7, 0xbb, 0xb5, 0xb3, 0xbb, 0xb8, +		0xb9, 0xb4, 0xbe, 0xb3, 0xbf, 0xb2, 0xb5, 0xbc, +		0xb2, 0xb9, 0xb8, 0xb5, 0xbc, 0xbf, 0xb3, 0xba, +		0xb7, 0xbb, 0xb0, 0xbe, 0xb4, 0xb1, 0xba, 0xb7, +		0xb1, 0xb6, 0xbd, 0xb0, 0xbb, 0xb8, 0xb6, 0xbd, +		0x2c, 0x2a, 0x21, 0x2f, 0x2a, 0x24, 0x2f, 0x22, +		0x29, 0x27, 0x22, 0x2c, 0x26, 0x29, 0x28, 0x25, +		0x20, 0x26, 0x2d, 0x21, 0x23, 0x2d, 0x24, 0x2e, +		0x2e, 0x20, 0x27, 0x2b, 0x25, 0x23, 0x2b, 0x28, +		0x29, 0x24, 0x2e, 0x23, 0x2f, 0x22, 0x25, 0x2c, +		0x22, 0x29, 0x28, 0x25, 0x2c, 0x2f, 0x23, 0x2a, +		0x27, 0x2b, 0x20, 0x2e, 0x24, 0x21, 0x2a, 0x27, +		0x21, 0x26, 0x2d, 0x20, 0x2b, 0x28, 0x26, 0x2d, +		0x8c, 0x8a, 0x81, 0x8f, 0x8a, 0x84, 0x8f, 0x82, +		0x89, 0x87, 0x82, 0x8c, 0x86, 0x89, 0x88, 0x85, +		0x80, 0x86, 0x8d, 0x81, 0x83, 0x8d, 0x84, 0x8e, +		0x8e, 0x80, 0x87, 0x8b, 0x85, 0x83, 0x8b, 0x88, +		0x89, 0x84, 0x8e, 0x83, 0x8f, 0x82, 0x85, 0x8c, +		0x82, 0x89, 0x88, 0x85, 0x8c, 0x8f, 0x83, 0x8a, +		0x87, 0x8b, 0x80, 0x8e, 0x84, 0x81, 0x8a, 0x87, +		0x81, 0x86, 0x8d, 0x80, 0x8b, 0x88, 0x86, 0x8d, +		0x1c, 0x1a, 0x11, 0x1f, 0x1a, 0x14, 0x1f, 0x12, +		0x19, 0x17, 0x12, 0x1c, 0x16, 0x19, 0x18, 0x15, +		0x10, 0x16, 0x1d, 0x11, 0x13, 0x1d, 0x14, 0x1e, +		0x1e, 0x10, 0x17, 0x1b, 0x15, 0x13, 0x1b, 0x18, +		0x19, 0x14, 0x1e, 0x13, 0x1f, 0x12, 0x15, 0x1c, +		0x12, 0x19, 0x18, 0x15, 0x1c, 0x1f, 0x13, 0x1a, +		0x17, 0x1b, 0x10, 0x1e, 0x14, 0x11, 0x1a, 0x17, +		0x11, 0x16, 0x1d, 0x10, 0x1b, 0x18, 0x16, 0x1d, +		0xcc, 0xca, 0xc1, 0xcf, 0xca, 0xc4, 0xcf, 0xc2, +		0xc9, 0xc7, 0xc2, 0xcc, 0xc6, 0xc9, 0xc8, 0xc5, +		0xc0, 0xc6, 0xcd, 0xc1, 0xc3, 0xcd, 0xc4, 0xce, +		0xce, 0xc0, 0xc7, 0xcb, 0xc5, 0xc3, 0xcb, 0xc8, +		0xc9, 0xc4, 0xce, 0xc3, 0xcf, 0xc2, 0xc5, 0xcc, +		0xc2, 0xc9, 0xc8, 0xc5, 0xcc, 0xcf, 0xc3, 0xca, +		0xc7, 0xcb, 0xc0, 0xce, 0xc4, 0xc1, 0xca, 0xc7, +		0xc1, 0xc6, 0xcd, 0xc0, 0xcb, 0xc8, 0xc6, 0xcd, +		0xbc, 0xba, 0xb1, 0xbf, 0xba, 0xb4, 0xbf, 0xb2, +		0xb9, 0xb7, 0xb2, 0xbc, 0xb6, 0xb9, 0xb8, 0xb5, +		0xb0, 0xb6, 0xbd, 0xb1, 0xb3, 0xbd, 0xb4, 0xbe, +		0xbe, 0xb0, 0xb7, 0xbb, 0xb5, 0xb3, 0xbb, 0xb8, +		0xb9, 0xb4, 0xbe, 0xb3, 0xbf, 0xb2, 0xb5, 0xbc, +		0xb2, 0xb9, 0xb8, 0xb5, 0xbc, 0xbf, 0xb3, 0xba, +		0xb7, 0xbb, 0xb0, 0xbe, 0xb4, 0xb1, 0xba, 0xb7, +		0xb1, 0xb6, 0xbd, 0xb0, 0xbb, 0xb8, 0xb6, 0xbd, +		0x7c, 0x7a, 0x71, 0x7f, 0x7a, 0x74, 0x7f, 0x72, +		0x79, 0x77, 0x72, 0x7c, 0x76, 0x79, 0x78, 0x75, +		0x70, 0x76, 0x7d, 0x71, 0x73, 0x7d, 0x74, 0x7e, +		0x7e, 0x70, 0x77, 0x7b, 0x75, 0x73, 0x7b, 0x78, +		0x79, 0x74, 0x7e, 0x73, 0x7f, 0x72, 0x75, 0x7c, +		0x72, 0x79, 0x78, 0x75, 0x7c, 0x7f, 0x73, 0x7a, +		0x77, 0x7b, 0x70, 0x7e, 0x74, 0x71, 0x7a, 0x77, +		0x71, 0x76, 0x7d, 0x70, 0x7b, 0x78, 0x76, 0x7d, +		0xac, 0xaa, 0xa1, 0xaf, 0xaa, 0xa4, 0xaf, 0xa2, +		0xa9, 0xa7, 0xa2, 0xac, 0xa6, 0xa9, 0xa8, 0xa5, +		0xa0, 0xa6, 0xad, 0xa1, 0xa3, 0xad, 0xa4, 0xae, +		0xae, 0xa0, 0xa7, 0xab, 0xa5, 0xa3, 0xab, 0xa8, +		0xa9, 0xa4, 0xae, 0xa3, 0xaf, 0xa2, 0xa5, 0xac, +		0xa2, 0xa9, 0xa8, 0xa5, 0xac, 0xaf, 0xa3, 0xaa, +		0xa7, 0xab, 0xa0, 0xae, 0xa4, 0xa1, 0xaa, 0xa7, +		0xa1, 0xa6, 0xad, 0xa0, 0xab, 0xa8, 0xa6, 0xad, +		0x1c, 0x1a, 0x11, 0x1f, 0x1a, 0x14, 0x1f, 0x12, +		0x19, 0x17, 0x12, 0x1c, 0x16, 0x19, 0x18, 0x15, +		0x10, 0x16, 0x1d, 0x11, 0x13, 0x1d, 0x14, 0x1e, +		0x1e, 0x10, 0x17, 0x1b, 0x15, 0x13, 0x1b, 0x18, +		0x19, 0x14, 0x1e, 0x13, 0x1f, 0x12, 0x15, 0x1c, +		0x12, 0x19, 0x18, 0x15, 0x1c, 0x1f, 0x13, 0x1a, +		0x17, 0x1b, 0x10, 0x1e, 0x14, 0x11, 0x1a, 0x17, +		0x11, 0x16, 0x1d, 0x10, 0x1b, 0x18, 0x16, 0x1d, +		0xdc, 0xda, 0xd1, 0xdf, 0xda, 0xd4, 0xdf, 0xd2, +		0xd9, 0xd7, 0xd2, 0xdc, 0xd6, 0xd9, 0xd8, 0xd5, +		0xd0, 0xd6, 0xdd, 0xd1, 0xd3, 0xdd, 0xd4, 0xde, +		0xde, 0xd0, 0xd7, 0xdb, 0xd5, 0xd3, 0xdb, 0xd8, +		0xd9, 0xd4, 0xde, 0xd3, 0xdf, 0xd2, 0xd5, 0xdc, +		0xd2, 0xd9, 0xd8, 0xd5, 0xdc, 0xdf, 0xd3, 0xda, +		0xd7, 0xdb, 0xd0, 0xde, 0xd4, 0xd1, 0xda, 0xd7, +		0xd1, 0xd6, 0xdd, 0xd0, 0xdb, 0xd8, 0xd6, 0xdd, +		0xec, 0xea, 0xe1, 0xef, 0xea, 0xe4, 0xef, 0xe2, +		0xe9, 0xe7, 0xe2, 0xec, 0xe6, 0xe9, 0xe8, 0xe5, +		0xe0, 0xe6, 0xed, 0xe1, 0xe3, 0xed, 0xe4, 0xee, +		0xee, 0xe0, 0xe7, 0xeb, 0xe5, 0xe3, 0xeb, 0xe8, +		0xe9, 0xe4, 0xee, 0xe3, 0xef, 0xe2, 0xe5, 0xec, +		0xe2, 0xe9, 0xe8, 0xe5, 0xec, 0xef, 0xe3, 0xea, +		0xe7, 0xeb, 0xe0, 0xee, 0xe4, 0xe1, 0xea, 0xe7, +		0xe1, 0xe6, 0xed, 0xe0, 0xeb, 0xe8, 0xe6, 0xed, +		0x7c, 0x7a, 0x71, 0x7f, 0x7a, 0x74, 0x7f, 0x72, +		0x79, 0x77, 0x72, 0x7c, 0x76, 0x79, 0x78, 0x75, +		0x70, 0x76, 0x7d, 0x71, 0x73, 0x7d, 0x74, 0x7e, +		0x7e, 0x70, 0x77, 0x7b, 0x75, 0x73, 0x7b, 0x78, +		0x79, 0x74, 0x7e, 0x73, 0x7f, 0x72, 0x75, 0x7c, +		0x72, 0x79, 0x78, 0x75, 0x7c, 0x7f, 0x73, 0x7a, +		0x77, 0x7b, 0x70, 0x7e, 0x74, 0x71, 0x7a, 0x77, +		0x71, 0x76, 0x7d, 0x70, 0x7b, 0x78, 0x76, 0x7d, +		0x2c, 0x2a, 0x21, 0x2f, 0x2a, 0x24, 0x2f, 0x22, +		0x29, 0x27, 0x22, 0x2c, 0x26, 0x29, 0x28, 0x25, +		0x20, 0x26, 0x2d, 0x21, 0x23, 0x2d, 0x24, 0x2e, +		0x2e, 0x20, 0x27, 0x2b, 0x25, 0x23, 0x2b, 0x28, +		0x29, 0x24, 0x2e, 0x23, 0x2f, 0x22, 0x25, 0x2c, +		0x22, 0x29, 0x28, 0x25, 0x2c, 0x2f, 0x23, 0x2a, +		0x27, 0x2b, 0x20, 0x2e, 0x24, 0x21, 0x2a, 0x27, +		0x21, 0x26, 0x2d, 0x20, 0x2b, 0x28, 0x26, 0x2d, +		0x8c, 0x8a, 0x81, 0x8f, 0x8a, 0x84, 0x8f, 0x82, +		0x89, 0x87, 0x82, 0x8c, 0x86, 0x89, 0x88, 0x85, +		0x80, 0x86, 0x8d, 0x81, 0x83, 0x8d, 0x84, 0x8e, +		0x8e, 0x80, 0x87, 0x8b, 0x85, 0x83, 0x8b, 0x88, +		0x89, 0x84, 0x8e, 0x83, 0x8f, 0x82, 0x85, 0x8c, +		0x82, 0x89, 0x88, 0x85, 0x8c, 0x8f, 0x83, 0x8a, +		0x87, 0x8b, 0x80, 0x8e, 0x84, 0x81, 0x8a, 0x87, +		0x81, 0x86, 0x8d, 0x80, 0x8b, 0x88, 0x86, 0x8d, +		0xdc, 0xda, 0xd1, 0xdf, 0xda, 0xd4, 0xdf, 0xd2, +		0xd9, 0xd7, 0xd2, 0xdc, 0xd6, 0xd9, 0xd8, 0xd5, +		0xd0, 0xd6, 0xdd, 0xd1, 0xd3, 0xdd, 0xd4, 0xde, +		0xde, 0xd0, 0xd7, 0xdb, 0xd5, 0xd3, 0xdb, 0xd8, +		0xd9, 0xd4, 0xde, 0xd3, 0xdf, 0xd2, 0xd5, 0xdc, +		0xd2, 0xd9, 0xd8, 0xd5, 0xdc, 0xdf, 0xd3, 0xda, +		0xd7, 0xdb, 0xd0, 0xde, 0xd4, 0xd1, 0xda, 0xd7, +		0xd1, 0xd6, 0xdd, 0xd0, 0xdb, 0xd8, 0xd6, 0xdd, +		0xfc, 0xfa, 0xf1, 0xff, 0xfa, 0xf4, 0xff, 0xf2, +		0xf9, 0xf7, 0xf2, 0xfc, 0xf6, 0xf9, 0xf8, 0xf5, +		0xf0, 0xf6, 0xfd, 0xf1, 0xf3, 0xfd, 0xf4, 0xfe, +		0xfe, 0xf0, 0xf7, 0xfb, 0xf5, 0xf3, 0xfb, 0xf8, +		0xf9, 0xf4, 0xfe, 0xf3, 0xff, 0xf2, 0xf5, 0xfc, +		0xf2, 0xf9, 0xf8, 0xf5, 0xfc, 0xff, 0xf3, 0xfa, +		0xf7, 0xfb, 0xf0, 0xfe, 0xf4, 0xf1, 0xfa, 0xf7, +		0xf1, 0xf6, 0xfd, 0xf0, 0xfb, 0xf8, 0xf6, 0xfd, +		0x6c, 0x6a, 0x61, 0x6f, 0x6a, 0x64, 0x6f, 0x62, +		0x69, 0x67, 0x62, 0x6c, 0x66, 0x69, 0x68, 0x65, +		0x60, 0x66, 0x6d, 0x61, 0x63, 0x6d, 0x64, 0x6e, +		0x6e, 0x60, 0x67, 0x6b, 0x65, 0x63, 0x6b, 0x68, +		0x69, 0x64, 0x6e, 0x63, 0x6f, 0x62, 0x65, 0x6c, +		0x62, 0x69, 0x68, 0x65, 0x6c, 0x6f, 0x63, 0x6a, +		0x67, 0x6b, 0x60, 0x6e, 0x64, 0x61, 0x6a, 0x67, +		0x61, 0x66, 0x6d, 0x60, 0x6b, 0x68, 0x66, 0x6d, +		0x9c, 0x9a, 0x91, 0x9f, 0x9a, 0x94, 0x9f, 0x92, +		0x99, 0x97, 0x92, 0x9c, 0x96, 0x99, 0x98, 0x95, +		0x90, 0x96, 0x9d, 0x91, 0x93, 0x9d, 0x94, 0x9e, +		0x9e, 0x90, 0x97, 0x9b, 0x95, 0x93, 0x9b, 0x98, +		0x99, 0x94, 0x9e, 0x93, 0x9f, 0x92, 0x95, 0x9c, +		0x92, 0x99, 0x98, 0x95, 0x9c, 0x9f, 0x93, 0x9a, +		0x97, 0x9b, 0x90, 0x9e, 0x94, 0x91, 0x9a, 0x97, +		0x91, 0x96, 0x9d, 0x90, 0x9b, 0x98, 0x96, 0x9d, +		0xfc, 0xfa, 0xf1, 0xff, 0xfa, 0xf4, 0xff, 0xf2, +		0xf9, 0xf7, 0xf2, 0xfc, 0xf6, 0xf9, 0xf8, 0xf5, +		0xf0, 0xf6, 0xfd, 0xf1, 0xf3, 0xfd, 0xf4, 0xfe, +		0xfe, 0xf0, 0xf7, 0xfb, 0xf5, 0xf3, 0xfb, 0xf8, +		0xf9, 0xf4, 0xfe, 0xf3, 0xff, 0xf2, 0xf5, 0xfc, +		0xf2, 0xf9, 0xf8, 0xf5, 0xfc, 0xff, 0xf3, 0xfa, +		0xf7, 0xfb, 0xf0, 0xfe, 0xf4, 0xf1, 0xfa, 0xf7, +		0xf1, 0xf6, 0xfd, 0xf0, 0xfb, 0xf8, 0xf6, 0xfd, +		0xcc, 0xca, 0xc1, 0xcf, 0xca, 0xc4, 0xcf, 0xc2, +		0xc9, 0xc7, 0xc2, 0xcc, 0xc6, 0xc9, 0xc8, 0xc5, +		0xc0, 0xc6, 0xcd, 0xc1, 0xc3, 0xcd, 0xc4, 0xce, +		0xce, 0xc0, 0xc7, 0xcb, 0xc5, 0xc3, 0xcb, 0xc8, +		0xc9, 0xc4, 0xce, 0xc3, 0xcf, 0xc2, 0xc5, 0xcc, +		0xc2, 0xc9, 0xc8, 0xc5, 0xcc, 0xcf, 0xc3, 0xca, +		0xc7, 0xcb, 0xc0, 0xce, 0xc4, 0xc1, 0xca, 0xc7, +		0xc1, 0xc6, 0xcd, 0xc0, 0xcb, 0xc8, 0xc6, 0xcd, +		0x0c, 0x0a, 0x01, 0x0f, 0x0a, 0x04, 0x0f, 0x02, +		0x09, 0x07, 0x02, 0x0c, 0x06, 0x09, 0x08, 0x05, +		0x00, 0x06, 0x0d, 0x01, 0x03, 0x0d, 0x04, 0x0e, +		0x0e, 0x00, 0x07, 0x0b, 0x05, 0x03, 0x0b, 0x08, +		0x09, 0x04, 0x0e, 0x03, 0x0f, 0x02, 0x05, 0x0c, +		0x02, 0x09, 0x08, 0x05, 0x0c, 0x0f, 0x03, 0x0a, +		0x07, 0x0b, 0x00, 0x0e, 0x04, 0x01, 0x0a, 0x07, +		0x01, 0x06, 0x0d, 0x00, 0x0b, 0x08, 0x06, 0x0d, +		0x5c, 0x5a, 0x51, 0x5f, 0x5a, 0x54, 0x5f, 0x52, +		0x59, 0x57, 0x52, 0x5c, 0x56, 0x59, 0x58, 0x55, +		0x50, 0x56, 0x5d, 0x51, 0x53, 0x5d, 0x54, 0x5e, +		0x5e, 0x50, 0x57, 0x5b, 0x55, 0x53, 0x5b, 0x58, +		0x59, 0x54, 0x5e, 0x53, 0x5f, 0x52, 0x55, 0x5c, +		0x52, 0x59, 0x58, 0x55, 0x5c, 0x5f, 0x53, 0x5a, +		0x57, 0x5b, 0x50, 0x5e, 0x54, 0x51, 0x5a, 0x57, +		0x51, 0x56, 0x5d, 0x50, 0x5b, 0x58, 0x56, 0x5d, +		0x9c, 0x9a, 0x91, 0x9f, 0x9a, 0x94, 0x9f, 0x92, +		0x99, 0x97, 0x92, 0x9c, 0x96, 0x99, 0x98, 0x95, +		0x90, 0x96, 0x9d, 0x91, 0x93, 0x9d, 0x94, 0x9e, +		0x9e, 0x90, 0x97, 0x9b, 0x95, 0x93, 0x9b, 0x98, +		0x99, 0x94, 0x9e, 0x93, 0x9f, 0x92, 0x95, 0x9c, +		0x92, 0x99, 0x98, 0x95, 0x9c, 0x9f, 0x93, 0x9a, +		0x97, 0x9b, 0x90, 0x9e, 0x94, 0x91, 0x9a, 0x97, +		0x91, 0x96, 0x9d, 0x90, 0x9b, 0x98, 0x96, 0x9d, +		0x6c, 0x6a, 0x61, 0x6f, 0x6a, 0x64, 0x6f, 0x62, +		0x69, 0x67, 0x62, 0x6c, 0x66, 0x69, 0x68, 0x65, +		0x60, 0x66, 0x6d, 0x61, 0x63, 0x6d, 0x64, 0x6e, +		0x6e, 0x60, 0x67, 0x6b, 0x65, 0x63, 0x6b, 0x68, +		0x69, 0x64, 0x6e, 0x63, 0x6f, 0x62, 0x65, 0x6c, +		0x62, 0x69, 0x68, 0x65, 0x6c, 0x6f, 0x63, 0x6a, +		0x67, 0x6b, 0x60, 0x6e, 0x64, 0x61, 0x6a, 0x67, +		0x61, 0x66, 0x6d, 0x60, 0x6b, 0x68, 0x66, 0x6d, +		0xac, 0xaa, 0xa1, 0xaf, 0xaa, 0xa4, 0xaf, 0xa2, +		0xa9, 0xa7, 0xa2, 0xac, 0xa6, 0xa9, 0xa8, 0xa5, +		0xa0, 0xa6, 0xad, 0xa1, 0xa3, 0xad, 0xa4, 0xae, +		0xae, 0xa0, 0xa7, 0xab, 0xa5, 0xa3, 0xab, 0xa8, +		0xa9, 0xa4, 0xae, 0xa3, 0xaf, 0xa2, 0xa5, 0xac, +		0xa2, 0xa9, 0xa8, 0xa5, 0xac, 0xaf, 0xa3, 0xaa, +		0xa7, 0xab, 0xa0, 0xae, 0xa4, 0xa1, 0xaa, 0xa7, +		0xa1, 0xa6, 0xad, 0xa0, 0xab, 0xa8, 0xa6, 0xad, +		0x3c, 0x3a, 0x31, 0x3f, 0x3a, 0x34, 0x3f, 0x32, +		0x39, 0x37, 0x32, 0x3c, 0x36, 0x39, 0x38, 0x35, +		0x30, 0x36, 0x3d, 0x31, 0x33, 0x3d, 0x34, 0x3e, +		0x3e, 0x30, 0x37, 0x3b, 0x35, 0x33, 0x3b, 0x38, +		0x39, 0x34, 0x3e, 0x33, 0x3f, 0x32, 0x35, 0x3c, +		0x32, 0x39, 0x38, 0x35, 0x3c, 0x3f, 0x33, 0x3a, +		0x37, 0x3b, 0x30, 0x3e, 0x34, 0x31, 0x3a, 0x37, +		0x31, 0x36, 0x3d, 0x30, 0x3b, 0x38, 0x36, 0x3d, +		0x4c, 0x4a, 0x41, 0x4f, 0x4a, 0x44, 0x4f, 0x42, +		0x49, 0x47, 0x42, 0x4c, 0x46, 0x49, 0x48, 0x45, +		0x40, 0x46, 0x4d, 0x41, 0x43, 0x4d, 0x44, 0x4e, +		0x4e, 0x40, 0x47, 0x4b, 0x45, 0x43, 0x4b, 0x48, +		0x49, 0x44, 0x4e, 0x43, 0x4f, 0x42, 0x45, 0x4c, +		0x42, 0x49, 0x48, 0x45, 0x4c, 0x4f, 0x43, 0x4a, +		0x47, 0x4b, 0x40, 0x4e, 0x44, 0x41, 0x4a, 0x47, +		0x41, 0x46, 0x4d, 0x40, 0x4b, 0x48, 0x46, 0x4d, +		0x0c, 0x0a, 0x01, 0x0f, 0x0a, 0x04, 0x0f, 0x02, +		0x09, 0x07, 0x02, 0x0c, 0x06, 0x09, 0x08, 0x05, +		0x00, 0x06, 0x0d, 0x01, 0x03, 0x0d, 0x04, 0x0e, +		0x0e, 0x00, 0x07, 0x0b, 0x05, 0x03, 0x0b, 0x08, +		0x09, 0x04, 0x0e, 0x03, 0x0f, 0x02, 0x05, 0x0c, +		0x02, 0x09, 0x08, 0x05, 0x0c, 0x0f, 0x03, 0x0a, +		0x07, 0x0b, 0x00, 0x0e, 0x04, 0x01, 0x0a, 0x07, +		0x01, 0x06, 0x0d, 0x00, 0x0b, 0x08, 0x06, 0x0d, +		0x5c, 0x5a, 0x51, 0x5f, 0x5a, 0x54, 0x5f, 0x52, +		0x59, 0x57, 0x52, 0x5c, 0x56, 0x59, 0x58, 0x55, +		0x50, 0x56, 0x5d, 0x51, 0x53, 0x5d, 0x54, 0x5e, +		0x5e, 0x50, 0x57, 0x5b, 0x55, 0x53, 0x5b, 0x58, +		0x59, 0x54, 0x5e, 0x53, 0x5f, 0x52, 0x55, 0x5c, +		0x52, 0x59, 0x58, 0x55, 0x5c, 0x5f, 0x53, 0x5a, +		0x57, 0x5b, 0x50, 0x5e, 0x54, 0x51, 0x5a, 0x57, +		0x51, 0x56, 0x5d, 0x50, 0x5b, 0x58, 0x56, 0x5d, +		0xec, 0xea, 0xe1, 0xef, 0xea, 0xe4, 0xef, 0xe2, +		0xe9, 0xe7, 0xe2, 0xec, 0xe6, 0xe9, 0xe8, 0xe5, +		0xe0, 0xe6, 0xed, 0xe1, 0xe3, 0xed, 0xe4, 0xee, +		0xee, 0xe0, 0xe7, 0xeb, 0xe5, 0xe3, 0xeb, 0xe8, +		0xe9, 0xe4, 0xee, 0xe3, 0xef, 0xe2, 0xe5, 0xec, +		0xe2, 0xe9, 0xe8, 0xe5, 0xec, 0xef, 0xe3, 0xea, +		0xe7, 0xeb, 0xe0, 0xee, 0xe4, 0xe1, 0xea, 0xe7, +		0xe1, 0xe6, 0xed, 0xe0, 0xeb, 0xe8, 0xe6, 0xed, +		0x3c, 0x3a, 0x31, 0x3f, 0x3a, 0x34, 0x3f, 0x32, +		0x39, 0x37, 0x32, 0x3c, 0x36, 0x39, 0x38, 0x35, +		0x30, 0x36, 0x3d, 0x31, 0x33, 0x3d, 0x34, 0x3e, +		0x3e, 0x30, 0x37, 0x3b, 0x35, 0x33, 0x3b, 0x38, +		0x39, 0x34, 0x3e, 0x33, 0x3f, 0x32, 0x35, 0x3c, +		0x32, 0x39, 0x38, 0x35, 0x3c, 0x3f, 0x33, 0x3a, +		0x37, 0x3b, 0x30, 0x3e, 0x34, 0x31, 0x3a, 0x37, +		0x31, 0x36, 0x3d, 0x30, 0x3b, 0x38, 0x36, 0x3d, +	},{ +		0x4d, 0x41, 0x42, 0x4f, 0x48, 0x4d, 0x44, 0x48, +		0x46, 0x4a, 0x4f, 0x43, 0x4b, 0x47, 0x41, 0x44, +		0x4a, 0x4c, 0x49, 0x45, 0x43, 0x46, 0x4e, 0x4b, +		0x45, 0x40, 0x40, 0x4e, 0x4c, 0x49, 0x47, 0x42, +		0x47, 0x42, 0x4b, 0x41, 0x44, 0x4e, 0x41, 0x47, +		0x49, 0x44, 0x4c, 0x4a, 0x4e, 0x48, 0x42, 0x4d, +		0x40, 0x4f, 0x46, 0x4c, 0x4a, 0x49, 0x4d, 0x40, +		0x4f, 0x43, 0x43, 0x45, 0x45, 0x46, 0x48, 0x4b, +		0xdd, 0xd1, 0xd2, 0xdf, 0xd8, 0xdd, 0xd4, 0xd8, +		0xd6, 0xda, 0xdf, 0xd3, 0xdb, 0xd7, 0xd1, 0xd4, +		0xda, 0xdc, 0xd9, 0xd5, 0xd3, 0xd6, 0xde, 0xdb, +		0xd5, 0xd0, 0xd0, 0xde, 0xdc, 0xd9, 0xd7, 0xd2, +		0xd7, 0xd2, 0xdb, 0xd1, 0xd4, 0xde, 0xd1, 0xd7, +		0xd9, 0xd4, 0xdc, 0xda, 0xde, 0xd8, 0xd2, 0xdd, +		0xd0, 0xdf, 0xd6, 0xdc, 0xda, 0xd9, 0xdd, 0xd0, +		0xdf, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd8, 0xdb, +		0xbd, 0xb1, 0xb2, 0xbf, 0xb8, 0xbd, 0xb4, 0xb8, +		0xb6, 0xba, 0xbf, 0xb3, 0xbb, 0xb7, 0xb1, 0xb4, +		0xba, 0xbc, 0xb9, 0xb5, 0xb3, 0xb6, 0xbe, 0xbb, +		0xb5, 0xb0, 0xb0, 0xbe, 0xbc, 0xb9, 0xb7, 0xb2, +		0xb7, 0xb2, 0xbb, 0xb1, 0xb4, 0xbe, 0xb1, 0xb7, +		0xb9, 0xb4, 0xbc, 0xba, 0xbe, 0xb8, 0xb2, 0xbd, +		0xb0, 0xbf, 0xb6, 0xbc, 0xba, 0xb9, 0xbd, 0xb0, +		0xbf, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb8, 0xbb, +		0x0d, 0x01, 0x02, 0x0f, 0x08, 0x0d, 0x04, 0x08, +		0x06, 0x0a, 0x0f, 0x03, 0x0b, 0x07, 0x01, 0x04, +		0x0a, 0x0c, 0x09, 0x05, 0x03, 0x06, 0x0e, 0x0b, +		0x05, 0x00, 0x00, 0x0e, 0x0c, 0x09, 0x07, 0x02, +		0x07, 0x02, 0x0b, 0x01, 0x04, 0x0e, 0x01, 0x07, +		0x09, 0x04, 0x0c, 0x0a, 0x0e, 0x08, 0x02, 0x0d, +		0x00, 0x0f, 0x06, 0x0c, 0x0a, 0x09, 0x0d, 0x00, +		0x0f, 0x03, 0x03, 0x05, 0x05, 0x06, 0x08, 0x0b, +		0x2d, 0x21, 0x22, 0x2f, 0x28, 0x2d, 0x24, 0x28, +		0x26, 0x2a, 0x2f, 0x23, 0x2b, 0x27, 0x21, 0x24, +		0x2a, 0x2c, 0x29, 0x25, 0x23, 0x26, 0x2e, 0x2b, +		0x25, 0x20, 0x20, 0x2e, 0x2c, 0x29, 0x27, 0x22, +		0x27, 0x22, 0x2b, 0x21, 0x24, 0x2e, 0x21, 0x27, +		0x29, 0x24, 0x2c, 0x2a, 0x2e, 0x28, 0x22, 0x2d, +		0x20, 0x2f, 0x26, 0x2c, 0x2a, 0x29, 0x2d, 0x20, +		0x2f, 0x23, 0x23, 0x25, 0x25, 0x26, 0x28, 0x2b, +		0xbd, 0xb1, 0xb2, 0xbf, 0xb8, 0xbd, 0xb4, 0xb8, +		0xb6, 0xba, 0xbf, 0xb3, 0xbb, 0xb7, 0xb1, 0xb4, +		0xba, 0xbc, 0xb9, 0xb5, 0xb3, 0xb6, 0xbe, 0xbb, +		0xb5, 0xb0, 0xb0, 0xbe, 0xbc, 0xb9, 0xb7, 0xb2, +		0xb7, 0xb2, 0xbb, 0xb1, 0xb4, 0xbe, 0xb1, 0xb7, +		0xb9, 0xb4, 0xbc, 0xba, 0xbe, 0xb8, 0xb2, 0xbd, +		0xb0, 0xbf, 0xb6, 0xbc, 0xba, 0xb9, 0xbd, 0xb0, +		0xbf, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb8, 0xbb, +		0xed, 0xe1, 0xe2, 0xef, 0xe8, 0xed, 0xe4, 0xe8, +		0xe6, 0xea, 0xef, 0xe3, 0xeb, 0xe7, 0xe1, 0xe4, +		0xea, 0xec, 0xe9, 0xe5, 0xe3, 0xe6, 0xee, 0xeb, +		0xe5, 0xe0, 0xe0, 0xee, 0xec, 0xe9, 0xe7, 0xe2, +		0xe7, 0xe2, 0xeb, 0xe1, 0xe4, 0xee, 0xe1, 0xe7, +		0xe9, 0xe4, 0xec, 0xea, 0xee, 0xe8, 0xe2, 0xed, +		0xe0, 0xef, 0xe6, 0xec, 0xea, 0xe9, 0xed, 0xe0, +		0xef, 0xe3, 0xe3, 0xe5, 0xe5, 0xe6, 0xe8, 0xeb, +		0x7d, 0x71, 0x72, 0x7f, 0x78, 0x7d, 0x74, 0x78, +		0x76, 0x7a, 0x7f, 0x73, 0x7b, 0x77, 0x71, 0x74, +		0x7a, 0x7c, 0x79, 0x75, 0x73, 0x76, 0x7e, 0x7b, +		0x75, 0x70, 0x70, 0x7e, 0x7c, 0x79, 0x77, 0x72, +		0x77, 0x72, 0x7b, 0x71, 0x74, 0x7e, 0x71, 0x77, +		0x79, 0x74, 0x7c, 0x7a, 0x7e, 0x78, 0x72, 0x7d, +		0x70, 0x7f, 0x76, 0x7c, 0x7a, 0x79, 0x7d, 0x70, +		0x7f, 0x73, 0x73, 0x75, 0x75, 0x76, 0x78, 0x7b, +		0xfd, 0xf1, 0xf2, 0xff, 0xf8, 0xfd, 0xf4, 0xf8, +		0xf6, 0xfa, 0xff, 0xf3, 0xfb, 0xf7, 0xf1, 0xf4, +		0xfa, 0xfc, 0xf9, 0xf5, 0xf3, 0xf6, 0xfe, 0xfb, +		0xf5, 0xf0, 0xf0, 0xfe, 0xfc, 0xf9, 0xf7, 0xf2, +		0xf7, 0xf2, 0xfb, 0xf1, 0xf4, 0xfe, 0xf1, 0xf7, +		0xf9, 0xf4, 0xfc, 0xfa, 0xfe, 0xf8, 0xf2, 0xfd, +		0xf0, 0xff, 0xf6, 0xfc, 0xfa, 0xf9, 0xfd, 0xf0, +		0xff, 0xf3, 0xf3, 0xf5, 0xf5, 0xf6, 0xf8, 0xfb, +		0x4d, 0x41, 0x42, 0x4f, 0x48, 0x4d, 0x44, 0x48, +		0x46, 0x4a, 0x4f, 0x43, 0x4b, 0x47, 0x41, 0x44, +		0x4a, 0x4c, 0x49, 0x45, 0x43, 0x46, 0x4e, 0x4b, +		0x45, 0x40, 0x40, 0x4e, 0x4c, 0x49, 0x47, 0x42, +		0x47, 0x42, 0x4b, 0x41, 0x44, 0x4e, 0x41, 0x47, +		0x49, 0x44, 0x4c, 0x4a, 0x4e, 0x48, 0x42, 0x4d, +		0x40, 0x4f, 0x46, 0x4c, 0x4a, 0x49, 0x4d, 0x40, +		0x4f, 0x43, 0x43, 0x45, 0x45, 0x46, 0x48, 0x4b, +		0x0d, 0x01, 0x02, 0x0f, 0x08, 0x0d, 0x04, 0x08, +		0x06, 0x0a, 0x0f, 0x03, 0x0b, 0x07, 0x01, 0x04, +		0x0a, 0x0c, 0x09, 0x05, 0x03, 0x06, 0x0e, 0x0b, +		0x05, 0x00, 0x00, 0x0e, 0x0c, 0x09, 0x07, 0x02, +		0x07, 0x02, 0x0b, 0x01, 0x04, 0x0e, 0x01, 0x07, +		0x09, 0x04, 0x0c, 0x0a, 0x0e, 0x08, 0x02, 0x0d, +		0x00, 0x0f, 0x06, 0x0c, 0x0a, 0x09, 0x0d, 0x00, +		0x0f, 0x03, 0x03, 0x05, 0x05, 0x06, 0x08, 0x0b, +		0x9d, 0x91, 0x92, 0x9f, 0x98, 0x9d, 0x94, 0x98, +		0x96, 0x9a, 0x9f, 0x93, 0x9b, 0x97, 0x91, 0x94, +		0x9a, 0x9c, 0x99, 0x95, 0x93, 0x96, 0x9e, 0x9b, +		0x95, 0x90, 0x90, 0x9e, 0x9c, 0x99, 0x97, 0x92, +		0x97, 0x92, 0x9b, 0x91, 0x94, 0x9e, 0x91, 0x97, +		0x99, 0x94, 0x9c, 0x9a, 0x9e, 0x98, 0x92, 0x9d, +		0x90, 0x9f, 0x96, 0x9c, 0x9a, 0x99, 0x9d, 0x90, +		0x9f, 0x93, 0x93, 0x95, 0x95, 0x96, 0x98, 0x9b, +		0x8d, 0x81, 0x82, 0x8f, 0x88, 0x8d, 0x84, 0x88, +		0x86, 0x8a, 0x8f, 0x83, 0x8b, 0x87, 0x81, 0x84, +		0x8a, 0x8c, 0x89, 0x85, 0x83, 0x86, 0x8e, 0x8b, +		0x85, 0x80, 0x80, 0x8e, 0x8c, 0x89, 0x87, 0x82, +		0x87, 0x82, 0x8b, 0x81, 0x84, 0x8e, 0x81, 0x87, +		0x89, 0x84, 0x8c, 0x8a, 0x8e, 0x88, 0x82, 0x8d, +		0x80, 0x8f, 0x86, 0x8c, 0x8a, 0x89, 0x8d, 0x80, +		0x8f, 0x83, 0x83, 0x85, 0x85, 0x86, 0x88, 0x8b, +		0x1d, 0x11, 0x12, 0x1f, 0x18, 0x1d, 0x14, 0x18, +		0x16, 0x1a, 0x1f, 0x13, 0x1b, 0x17, 0x11, 0x14, +		0x1a, 0x1c, 0x19, 0x15, 0x13, 0x16, 0x1e, 0x1b, +		0x15, 0x10, 0x10, 0x1e, 0x1c, 0x19, 0x17, 0x12, +		0x17, 0x12, 0x1b, 0x11, 0x14, 0x1e, 0x11, 0x17, +		0x19, 0x14, 0x1c, 0x1a, 0x1e, 0x18, 0x12, 0x1d, +		0x10, 0x1f, 0x16, 0x1c, 0x1a, 0x19, 0x1d, 0x10, +		0x1f, 0x13, 0x13, 0x15, 0x15, 0x16, 0x18, 0x1b, +		0xdd, 0xd1, 0xd2, 0xdf, 0xd8, 0xdd, 0xd4, 0xd8, +		0xd6, 0xda, 0xdf, 0xd3, 0xdb, 0xd7, 0xd1, 0xd4, +		0xda, 0xdc, 0xd9, 0xd5, 0xd3, 0xd6, 0xde, 0xdb, +		0xd5, 0xd0, 0xd0, 0xde, 0xdc, 0xd9, 0xd7, 0xd2, +		0xd7, 0xd2, 0xdb, 0xd1, 0xd4, 0xde, 0xd1, 0xd7, +		0xd9, 0xd4, 0xdc, 0xda, 0xde, 0xd8, 0xd2, 0xdd, +		0xd0, 0xdf, 0xd6, 0xdc, 0xda, 0xd9, 0xdd, 0xd0, +		0xdf, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd8, 0xdb, +		0xad, 0xa1, 0xa2, 0xaf, 0xa8, 0xad, 0xa4, 0xa8, +		0xa6, 0xaa, 0xaf, 0xa3, 0xab, 0xa7, 0xa1, 0xa4, +		0xaa, 0xac, 0xa9, 0xa5, 0xa3, 0xa6, 0xae, 0xab, +		0xa5, 0xa0, 0xa0, 0xae, 0xac, 0xa9, 0xa7, 0xa2, +		0xa7, 0xa2, 0xab, 0xa1, 0xa4, 0xae, 0xa1, 0xa7, +		0xa9, 0xa4, 0xac, 0xaa, 0xae, 0xa8, 0xa2, 0xad, +		0xa0, 0xaf, 0xa6, 0xac, 0xaa, 0xa9, 0xad, 0xa0, +		0xaf, 0xa3, 0xa3, 0xa5, 0xa5, 0xa6, 0xa8, 0xab, +		0x3d, 0x31, 0x32, 0x3f, 0x38, 0x3d, 0x34, 0x38, +		0x36, 0x3a, 0x3f, 0x33, 0x3b, 0x37, 0x31, 0x34, +		0x3a, 0x3c, 0x39, 0x35, 0x33, 0x36, 0x3e, 0x3b, +		0x35, 0x30, 0x30, 0x3e, 0x3c, 0x39, 0x37, 0x32, +		0x37, 0x32, 0x3b, 0x31, 0x34, 0x3e, 0x31, 0x37, +		0x39, 0x34, 0x3c, 0x3a, 0x3e, 0x38, 0x32, 0x3d, +		0x30, 0x3f, 0x36, 0x3c, 0x3a, 0x39, 0x3d, 0x30, +		0x3f, 0x33, 0x33, 0x35, 0x35, 0x36, 0x38, 0x3b, +		0xed, 0xe1, 0xe2, 0xef, 0xe8, 0xed, 0xe4, 0xe8, +		0xe6, 0xea, 0xef, 0xe3, 0xeb, 0xe7, 0xe1, 0xe4, +		0xea, 0xec, 0xe9, 0xe5, 0xe3, 0xe6, 0xee, 0xeb, +		0xe5, 0xe0, 0xe0, 0xee, 0xec, 0xe9, 0xe7, 0xe2, +		0xe7, 0xe2, 0xeb, 0xe1, 0xe4, 0xee, 0xe1, 0xe7, +		0xe9, 0xe4, 0xec, 0xea, 0xee, 0xe8, 0xe2, 0xed, +		0xe0, 0xef, 0xe6, 0xec, 0xea, 0xe9, 0xed, 0xe0, +		0xef, 0xe3, 0xe3, 0xe5, 0xe5, 0xe6, 0xe8, 0xeb, +		0xcd, 0xc1, 0xc2, 0xcf, 0xc8, 0xcd, 0xc4, 0xc8, +		0xc6, 0xca, 0xcf, 0xc3, 0xcb, 0xc7, 0xc1, 0xc4, +		0xca, 0xcc, 0xc9, 0xc5, 0xc3, 0xc6, 0xce, 0xcb, +		0xc5, 0xc0, 0xc0, 0xce, 0xcc, 0xc9, 0xc7, 0xc2, +		0xc7, 0xc2, 0xcb, 0xc1, 0xc4, 0xce, 0xc1, 0xc7, +		0xc9, 0xc4, 0xcc, 0xca, 0xce, 0xc8, 0xc2, 0xcd, +		0xc0, 0xcf, 0xc6, 0xcc, 0xca, 0xc9, 0xcd, 0xc0, +		0xcf, 0xc3, 0xc3, 0xc5, 0xc5, 0xc6, 0xc8, 0xcb, +		0x3d, 0x31, 0x32, 0x3f, 0x38, 0x3d, 0x34, 0x38, +		0x36, 0x3a, 0x3f, 0x33, 0x3b, 0x37, 0x31, 0x34, +		0x3a, 0x3c, 0x39, 0x35, 0x33, 0x36, 0x3e, 0x3b, +		0x35, 0x30, 0x30, 0x3e, 0x3c, 0x39, 0x37, 0x32, +		0x37, 0x32, 0x3b, 0x31, 0x34, 0x3e, 0x31, 0x37, +		0x39, 0x34, 0x3c, 0x3a, 0x3e, 0x38, 0x32, 0x3d, +		0x30, 0x3f, 0x36, 0x3c, 0x3a, 0x39, 0x3d, 0x30, +		0x3f, 0x33, 0x33, 0x35, 0x35, 0x36, 0x38, 0x3b, +		0x9d, 0x91, 0x92, 0x9f, 0x98, 0x9d, 0x94, 0x98, +		0x96, 0x9a, 0x9f, 0x93, 0x9b, 0x97, 0x91, 0x94, +		0x9a, 0x9c, 0x99, 0x95, 0x93, 0x96, 0x9e, 0x9b, +		0x95, 0x90, 0x90, 0x9e, 0x9c, 0x99, 0x97, 0x92, +		0x97, 0x92, 0x9b, 0x91, 0x94, 0x9e, 0x91, 0x97, +		0x99, 0x94, 0x9c, 0x9a, 0x9e, 0x98, 0x92, 0x9d, +		0x90, 0x9f, 0x96, 0x9c, 0x9a, 0x99, 0x9d, 0x90, +		0x9f, 0x93, 0x93, 0x95, 0x95, 0x96, 0x98, 0x9b, +		0x5d, 0x51, 0x52, 0x5f, 0x58, 0x5d, 0x54, 0x58, +		0x56, 0x5a, 0x5f, 0x53, 0x5b, 0x57, 0x51, 0x54, +		0x5a, 0x5c, 0x59, 0x55, 0x53, 0x56, 0x5e, 0x5b, +		0x55, 0x50, 0x50, 0x5e, 0x5c, 0x59, 0x57, 0x52, +		0x57, 0x52, 0x5b, 0x51, 0x54, 0x5e, 0x51, 0x57, +		0x59, 0x54, 0x5c, 0x5a, 0x5e, 0x58, 0x52, 0x5d, +		0x50, 0x5f, 0x56, 0x5c, 0x5a, 0x59, 0x5d, 0x50, +		0x5f, 0x53, 0x53, 0x55, 0x55, 0x56, 0x58, 0x5b, +		0x7d, 0x71, 0x72, 0x7f, 0x78, 0x7d, 0x74, 0x78, +		0x76, 0x7a, 0x7f, 0x73, 0x7b, 0x77, 0x71, 0x74, +		0x7a, 0x7c, 0x79, 0x75, 0x73, 0x76, 0x7e, 0x7b, +		0x75, 0x70, 0x70, 0x7e, 0x7c, 0x79, 0x77, 0x72, +		0x77, 0x72, 0x7b, 0x71, 0x74, 0x7e, 0x71, 0x77, +		0x79, 0x74, 0x7c, 0x7a, 0x7e, 0x78, 0x72, 0x7d, +		0x70, 0x7f, 0x76, 0x7c, 0x7a, 0x79, 0x7d, 0x70, +		0x7f, 0x73, 0x73, 0x75, 0x75, 0x76, 0x78, 0x7b, +		0xcd, 0xc1, 0xc2, 0xcf, 0xc8, 0xcd, 0xc4, 0xc8, +		0xc6, 0xca, 0xcf, 0xc3, 0xcb, 0xc7, 0xc1, 0xc4, +		0xca, 0xcc, 0xc9, 0xc5, 0xc3, 0xc6, 0xce, 0xcb, +		0xc5, 0xc0, 0xc0, 0xce, 0xcc, 0xc9, 0xc7, 0xc2, +		0xc7, 0xc2, 0xcb, 0xc1, 0xc4, 0xce, 0xc1, 0xc7, +		0xc9, 0xc4, 0xcc, 0xca, 0xce, 0xc8, 0xc2, 0xcd, +		0xc0, 0xcf, 0xc6, 0xcc, 0xca, 0xc9, 0xcd, 0xc0, +		0xcf, 0xc3, 0xc3, 0xc5, 0xc5, 0xc6, 0xc8, 0xcb, +		0x5d, 0x51, 0x52, 0x5f, 0x58, 0x5d, 0x54, 0x58, +		0x56, 0x5a, 0x5f, 0x53, 0x5b, 0x57, 0x51, 0x54, +		0x5a, 0x5c, 0x59, 0x55, 0x53, 0x56, 0x5e, 0x5b, +		0x55, 0x50, 0x50, 0x5e, 0x5c, 0x59, 0x57, 0x52, +		0x57, 0x52, 0x5b, 0x51, 0x54, 0x5e, 0x51, 0x57, +		0x59, 0x54, 0x5c, 0x5a, 0x5e, 0x58, 0x52, 0x5d, +		0x50, 0x5f, 0x56, 0x5c, 0x5a, 0x59, 0x5d, 0x50, +		0x5f, 0x53, 0x53, 0x55, 0x55, 0x56, 0x58, 0x5b, +		0x2d, 0x21, 0x22, 0x2f, 0x28, 0x2d, 0x24, 0x28, +		0x26, 0x2a, 0x2f, 0x23, 0x2b, 0x27, 0x21, 0x24, +		0x2a, 0x2c, 0x29, 0x25, 0x23, 0x26, 0x2e, 0x2b, +		0x25, 0x20, 0x20, 0x2e, 0x2c, 0x29, 0x27, 0x22, +		0x27, 0x22, 0x2b, 0x21, 0x24, 0x2e, 0x21, 0x27, +		0x29, 0x24, 0x2c, 0x2a, 0x2e, 0x28, 0x22, 0x2d, +		0x20, 0x2f, 0x26, 0x2c, 0x2a, 0x29, 0x2d, 0x20, +		0x2f, 0x23, 0x23, 0x25, 0x25, 0x26, 0x28, 0x2b, +		0xad, 0xa1, 0xa2, 0xaf, 0xa8, 0xad, 0xa4, 0xa8, +		0xa6, 0xaa, 0xaf, 0xa3, 0xab, 0xa7, 0xa1, 0xa4, +		0xaa, 0xac, 0xa9, 0xa5, 0xa3, 0xa6, 0xae, 0xab, +		0xa5, 0xa0, 0xa0, 0xae, 0xac, 0xa9, 0xa7, 0xa2, +		0xa7, 0xa2, 0xab, 0xa1, 0xa4, 0xae, 0xa1, 0xa7, +		0xa9, 0xa4, 0xac, 0xaa, 0xae, 0xa8, 0xa2, 0xad, +		0xa0, 0xaf, 0xa6, 0xac, 0xaa, 0xa9, 0xad, 0xa0, +		0xaf, 0xa3, 0xa3, 0xa5, 0xa5, 0xa6, 0xa8, 0xab, +		0xfd, 0xf1, 0xf2, 0xff, 0xf8, 0xfd, 0xf4, 0xf8, +		0xf6, 0xfa, 0xff, 0xf3, 0xfb, 0xf7, 0xf1, 0xf4, +		0xfa, 0xfc, 0xf9, 0xf5, 0xf3, 0xf6, 0xfe, 0xfb, +		0xf5, 0xf0, 0xf0, 0xfe, 0xfc, 0xf9, 0xf7, 0xf2, +		0xf7, 0xf2, 0xfb, 0xf1, 0xf4, 0xfe, 0xf1, 0xf7, +		0xf9, 0xf4, 0xfc, 0xfa, 0xfe, 0xf8, 0xf2, 0xfd, +		0xf0, 0xff, 0xf6, 0xfc, 0xfa, 0xf9, 0xfd, 0xf0, +		0xff, 0xf3, 0xf3, 0xf5, 0xf5, 0xf6, 0xf8, 0xfb, +		0x6d, 0x61, 0x62, 0x6f, 0x68, 0x6d, 0x64, 0x68, +		0x66, 0x6a, 0x6f, 0x63, 0x6b, 0x67, 0x61, 0x64, +		0x6a, 0x6c, 0x69, 0x65, 0x63, 0x66, 0x6e, 0x6b, +		0x65, 0x60, 0x60, 0x6e, 0x6c, 0x69, 0x67, 0x62, +		0x67, 0x62, 0x6b, 0x61, 0x64, 0x6e, 0x61, 0x67, +		0x69, 0x64, 0x6c, 0x6a, 0x6e, 0x68, 0x62, 0x6d, +		0x60, 0x6f, 0x66, 0x6c, 0x6a, 0x69, 0x6d, 0x60, +		0x6f, 0x63, 0x63, 0x65, 0x65, 0x66, 0x68, 0x6b, +		0x8d, 0x81, 0x82, 0x8f, 0x88, 0x8d, 0x84, 0x88, +		0x86, 0x8a, 0x8f, 0x83, 0x8b, 0x87, 0x81, 0x84, +		0x8a, 0x8c, 0x89, 0x85, 0x83, 0x86, 0x8e, 0x8b, +		0x85, 0x80, 0x80, 0x8e, 0x8c, 0x89, 0x87, 0x82, +		0x87, 0x82, 0x8b, 0x81, 0x84, 0x8e, 0x81, 0x87, +		0x89, 0x84, 0x8c, 0x8a, 0x8e, 0x88, 0x82, 0x8d, +		0x80, 0x8f, 0x86, 0x8c, 0x8a, 0x89, 0x8d, 0x80, +		0x8f, 0x83, 0x83, 0x85, 0x85, 0x86, 0x88, 0x8b, +		0x1d, 0x11, 0x12, 0x1f, 0x18, 0x1d, 0x14, 0x18, +		0x16, 0x1a, 0x1f, 0x13, 0x1b, 0x17, 0x11, 0x14, +		0x1a, 0x1c, 0x19, 0x15, 0x13, 0x16, 0x1e, 0x1b, +		0x15, 0x10, 0x10, 0x1e, 0x1c, 0x19, 0x17, 0x12, +		0x17, 0x12, 0x1b, 0x11, 0x14, 0x1e, 0x11, 0x17, +		0x19, 0x14, 0x1c, 0x1a, 0x1e, 0x18, 0x12, 0x1d, +		0x10, 0x1f, 0x16, 0x1c, 0x1a, 0x19, 0x1d, 0x10, +		0x1f, 0x13, 0x13, 0x15, 0x15, 0x16, 0x18, 0x1b, +		0x6d, 0x61, 0x62, 0x6f, 0x68, 0x6d, 0x64, 0x68, +		0x66, 0x6a, 0x6f, 0x63, 0x6b, 0x67, 0x61, 0x64, +		0x6a, 0x6c, 0x69, 0x65, 0x63, 0x66, 0x6e, 0x6b, +		0x65, 0x60, 0x60, 0x6e, 0x6c, 0x69, 0x67, 0x62, +		0x67, 0x62, 0x6b, 0x61, 0x64, 0x6e, 0x61, 0x67, +		0x69, 0x64, 0x6c, 0x6a, 0x6e, 0x68, 0x62, 0x6d, +		0x60, 0x6f, 0x66, 0x6c, 0x6a, 0x69, 0x6d, 0x60, +		0x6f, 0x63, 0x63, 0x65, 0x65, 0x66, 0x68, 0x6b, +		0x1d, 0x11, 0x12, 0x1f, 0x18, 0x1d, 0x14, 0x18, +		0x16, 0x1a, 0x1f, 0x13, 0x1b, 0x17, 0x11, 0x14, +		0x1a, 0x1c, 0x19, 0x15, 0x13, 0x16, 0x1e, 0x1b, +		0x15, 0x10, 0x10, 0x1e, 0x1c, 0x19, 0x17, 0x12, +		0x17, 0x12, 0x1b, 0x11, 0x14, 0x1e, 0x11, 0x17, +		0x19, 0x14, 0x1c, 0x1a, 0x1e, 0x18, 0x12, 0x1d, +		0x10, 0x1f, 0x16, 0x1c, 0x1a, 0x19, 0x1d, 0x10, +		0x1f, 0x13, 0x13, 0x15, 0x15, 0x16, 0x18, 0x1b, +		0x6d, 0x61, 0x62, 0x6f, 0x68, 0x6d, 0x64, 0x68, +		0x66, 0x6a, 0x6f, 0x63, 0x6b, 0x67, 0x61, 0x64, +		0x6a, 0x6c, 0x69, 0x65, 0x63, 0x66, 0x6e, 0x6b, +		0x65, 0x60, 0x60, 0x6e, 0x6c, 0x69, 0x67, 0x62, +		0x67, 0x62, 0x6b, 0x61, 0x64, 0x6e, 0x61, 0x67, +		0x69, 0x64, 0x6c, 0x6a, 0x6e, 0x68, 0x62, 0x6d, +		0x60, 0x6f, 0x66, 0x6c, 0x6a, 0x69, 0x6d, 0x60, +		0x6f, 0x63, 0x63, 0x65, 0x65, 0x66, 0x68, 0x6b, +		0x4d, 0x41, 0x42, 0x4f, 0x48, 0x4d, 0x44, 0x48, +		0x46, 0x4a, 0x4f, 0x43, 0x4b, 0x47, 0x41, 0x44, +		0x4a, 0x4c, 0x49, 0x45, 0x43, 0x46, 0x4e, 0x4b, +		0x45, 0x40, 0x40, 0x4e, 0x4c, 0x49, 0x47, 0x42, +		0x47, 0x42, 0x4b, 0x41, 0x44, 0x4e, 0x41, 0x47, +		0x49, 0x44, 0x4c, 0x4a, 0x4e, 0x48, 0x42, 0x4d, +		0x40, 0x4f, 0x46, 0x4c, 0x4a, 0x49, 0x4d, 0x40, +		0x4f, 0x43, 0x43, 0x45, 0x45, 0x46, 0x48, 0x4b, +		0xbd, 0xb1, 0xb2, 0xbf, 0xb8, 0xbd, 0xb4, 0xb8, +		0xb6, 0xba, 0xbf, 0xb3, 0xbb, 0xb7, 0xb1, 0xb4, +		0xba, 0xbc, 0xb9, 0xb5, 0xb3, 0xb6, 0xbe, 0xbb, +		0xb5, 0xb0, 0xb0, 0xbe, 0xbc, 0xb9, 0xb7, 0xb2, +		0xb7, 0xb2, 0xbb, 0xb1, 0xb4, 0xbe, 0xb1, 0xb7, +		0xb9, 0xb4, 0xbc, 0xba, 0xbe, 0xb8, 0xb2, 0xbd, +		0xb0, 0xbf, 0xb6, 0xbc, 0xba, 0xb9, 0xbd, 0xb0, +		0xbf, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb8, 0xbb, +		0xbd, 0xb1, 0xb2, 0xbf, 0xb8, 0xbd, 0xb4, 0xb8, +		0xb6, 0xba, 0xbf, 0xb3, 0xbb, 0xb7, 0xb1, 0xb4, +		0xba, 0xbc, 0xb9, 0xb5, 0xb3, 0xb6, 0xbe, 0xbb, +		0xb5, 0xb0, 0xb0, 0xbe, 0xbc, 0xb9, 0xb7, 0xb2, +		0xb7, 0xb2, 0xbb, 0xb1, 0xb4, 0xbe, 0xb1, 0xb7, +		0xb9, 0xb4, 0xbc, 0xba, 0xbe, 0xb8, 0xb2, 0xbd, +		0xb0, 0xbf, 0xb6, 0xbc, 0xba, 0xb9, 0xbd, 0xb0, +		0xbf, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb8, 0xbb, +		0xdd, 0xd1, 0xd2, 0xdf, 0xd8, 0xdd, 0xd4, 0xd8, +		0xd6, 0xda, 0xdf, 0xd3, 0xdb, 0xd7, 0xd1, 0xd4, +		0xda, 0xdc, 0xd9, 0xd5, 0xd3, 0xd6, 0xde, 0xdb, +		0xd5, 0xd0, 0xd0, 0xde, 0xdc, 0xd9, 0xd7, 0xd2, +		0xd7, 0xd2, 0xdb, 0xd1, 0xd4, 0xde, 0xd1, 0xd7, +		0xd9, 0xd4, 0xdc, 0xda, 0xde, 0xd8, 0xd2, 0xdd, +		0xd0, 0xdf, 0xd6, 0xdc, 0xda, 0xd9, 0xdd, 0xd0, +		0xdf, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd8, 0xdb, +		0xdd, 0xd1, 0xd2, 0xdf, 0xd8, 0xdd, 0xd4, 0xd8, +		0xd6, 0xda, 0xdf, 0xd3, 0xdb, 0xd7, 0xd1, 0xd4, +		0xda, 0xdc, 0xd9, 0xd5, 0xd3, 0xd6, 0xde, 0xdb, +		0xd5, 0xd0, 0xd0, 0xde, 0xdc, 0xd9, 0xd7, 0xd2, +		0xd7, 0xd2, 0xdb, 0xd1, 0xd4, 0xde, 0xd1, 0xd7, +		0xd9, 0xd4, 0xdc, 0xda, 0xde, 0xd8, 0xd2, 0xdd, +		0xd0, 0xdf, 0xd6, 0xdc, 0xda, 0xd9, 0xdd, 0xd0, +		0xdf, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd8, 0xdb, +		0x8d, 0x81, 0x82, 0x8f, 0x88, 0x8d, 0x84, 0x88, +		0x86, 0x8a, 0x8f, 0x83, 0x8b, 0x87, 0x81, 0x84, +		0x8a, 0x8c, 0x89, 0x85, 0x83, 0x86, 0x8e, 0x8b, +		0x85, 0x80, 0x80, 0x8e, 0x8c, 0x89, 0x87, 0x82, +		0x87, 0x82, 0x8b, 0x81, 0x84, 0x8e, 0x81, 0x87, +		0x89, 0x84, 0x8c, 0x8a, 0x8e, 0x88, 0x82, 0x8d, +		0x80, 0x8f, 0x86, 0x8c, 0x8a, 0x89, 0x8d, 0x80, +		0x8f, 0x83, 0x83, 0x85, 0x85, 0x86, 0x88, 0x8b, +		0xcd, 0xc1, 0xc2, 0xcf, 0xc8, 0xcd, 0xc4, 0xc8, +		0xc6, 0xca, 0xcf, 0xc3, 0xcb, 0xc7, 0xc1, 0xc4, +		0xca, 0xcc, 0xc9, 0xc5, 0xc3, 0xc6, 0xce, 0xcb, +		0xc5, 0xc0, 0xc0, 0xce, 0xcc, 0xc9, 0xc7, 0xc2, +		0xc7, 0xc2, 0xcb, 0xc1, 0xc4, 0xce, 0xc1, 0xc7, +		0xc9, 0xc4, 0xcc, 0xca, 0xce, 0xc8, 0xc2, 0xcd, +		0xc0, 0xcf, 0xc6, 0xcc, 0xca, 0xc9, 0xcd, 0xc0, +		0xcf, 0xc3, 0xc3, 0xc5, 0xc5, 0xc6, 0xc8, 0xcb, +		0x1d, 0x11, 0x12, 0x1f, 0x18, 0x1d, 0x14, 0x18, +		0x16, 0x1a, 0x1f, 0x13, 0x1b, 0x17, 0x11, 0x14, +		0x1a, 0x1c, 0x19, 0x15, 0x13, 0x16, 0x1e, 0x1b, +		0x15, 0x10, 0x10, 0x1e, 0x1c, 0x19, 0x17, 0x12, +		0x17, 0x12, 0x1b, 0x11, 0x14, 0x1e, 0x11, 0x17, +		0x19, 0x14, 0x1c, 0x1a, 0x1e, 0x18, 0x12, 0x1d, +		0x10, 0x1f, 0x16, 0x1c, 0x1a, 0x19, 0x1d, 0x10, +		0x1f, 0x13, 0x13, 0x15, 0x15, 0x16, 0x18, 0x1b, +		0x3d, 0x31, 0x32, 0x3f, 0x38, 0x3d, 0x34, 0x38, +		0x36, 0x3a, 0x3f, 0x33, 0x3b, 0x37, 0x31, 0x34, +		0x3a, 0x3c, 0x39, 0x35, 0x33, 0x36, 0x3e, 0x3b, +		0x35, 0x30, 0x30, 0x3e, 0x3c, 0x39, 0x37, 0x32, +		0x37, 0x32, 0x3b, 0x31, 0x34, 0x3e, 0x31, 0x37, +		0x39, 0x34, 0x3c, 0x3a, 0x3e, 0x38, 0x32, 0x3d, +		0x30, 0x3f, 0x36, 0x3c, 0x3a, 0x39, 0x3d, 0x30, +		0x3f, 0x33, 0x33, 0x35, 0x35, 0x36, 0x38, 0x3b, +		0x4d, 0x41, 0x42, 0x4f, 0x48, 0x4d, 0x44, 0x48, +		0x46, 0x4a, 0x4f, 0x43, 0x4b, 0x47, 0x41, 0x44, +		0x4a, 0x4c, 0x49, 0x45, 0x43, 0x46, 0x4e, 0x4b, +		0x45, 0x40, 0x40, 0x4e, 0x4c, 0x49, 0x47, 0x42, +		0x47, 0x42, 0x4b, 0x41, 0x44, 0x4e, 0x41, 0x47, +		0x49, 0x44, 0x4c, 0x4a, 0x4e, 0x48, 0x42, 0x4d, +		0x40, 0x4f, 0x46, 0x4c, 0x4a, 0x49, 0x4d, 0x40, +		0x4f, 0x43, 0x43, 0x45, 0x45, 0x46, 0x48, 0x4b, +		0x7d, 0x71, 0x72, 0x7f, 0x78, 0x7d, 0x74, 0x78, +		0x76, 0x7a, 0x7f, 0x73, 0x7b, 0x77, 0x71, 0x74, +		0x7a, 0x7c, 0x79, 0x75, 0x73, 0x76, 0x7e, 0x7b, +		0x75, 0x70, 0x70, 0x7e, 0x7c, 0x79, 0x77, 0x72, +		0x77, 0x72, 0x7b, 0x71, 0x74, 0x7e, 0x71, 0x77, +		0x79, 0x74, 0x7c, 0x7a, 0x7e, 0x78, 0x72, 0x7d, +		0x70, 0x7f, 0x76, 0x7c, 0x7a, 0x79, 0x7d, 0x70, +		0x7f, 0x73, 0x73, 0x75, 0x75, 0x76, 0x78, 0x7b, +		0xad, 0xa1, 0xa2, 0xaf, 0xa8, 0xad, 0xa4, 0xa8, +		0xa6, 0xaa, 0xaf, 0xa3, 0xab, 0xa7, 0xa1, 0xa4, +		0xaa, 0xac, 0xa9, 0xa5, 0xa3, 0xa6, 0xae, 0xab, +		0xa5, 0xa0, 0xa0, 0xae, 0xac, 0xa9, 0xa7, 0xa2, +		0xa7, 0xa2, 0xab, 0xa1, 0xa4, 0xae, 0xa1, 0xa7, +		0xa9, 0xa4, 0xac, 0xaa, 0xae, 0xa8, 0xa2, 0xad, +		0xa0, 0xaf, 0xa6, 0xac, 0xaa, 0xa9, 0xad, 0xa0, +		0xaf, 0xa3, 0xa3, 0xa5, 0xa5, 0xa6, 0xa8, 0xab, +		0xed, 0xe1, 0xe2, 0xef, 0xe8, 0xed, 0xe4, 0xe8, +		0xe6, 0xea, 0xef, 0xe3, 0xeb, 0xe7, 0xe1, 0xe4, +		0xea, 0xec, 0xe9, 0xe5, 0xe3, 0xe6, 0xee, 0xeb, +		0xe5, 0xe0, 0xe0, 0xee, 0xec, 0xe9, 0xe7, 0xe2, +		0xe7, 0xe2, 0xeb, 0xe1, 0xe4, 0xee, 0xe1, 0xe7, +		0xe9, 0xe4, 0xec, 0xea, 0xee, 0xe8, 0xe2, 0xed, +		0xe0, 0xef, 0xe6, 0xec, 0xea, 0xe9, 0xed, 0xe0, +		0xef, 0xe3, 0xe3, 0xe5, 0xe5, 0xe6, 0xe8, 0xeb, +		0x7d, 0x71, 0x72, 0x7f, 0x78, 0x7d, 0x74, 0x78, +		0x76, 0x7a, 0x7f, 0x73, 0x7b, 0x77, 0x71, 0x74, +		0x7a, 0x7c, 0x79, 0x75, 0x73, 0x76, 0x7e, 0x7b, +		0x75, 0x70, 0x70, 0x7e, 0x7c, 0x79, 0x77, 0x72, +		0x77, 0x72, 0x7b, 0x71, 0x74, 0x7e, 0x71, 0x77, +		0x79, 0x74, 0x7c, 0x7a, 0x7e, 0x78, 0x72, 0x7d, +		0x70, 0x7f, 0x76, 0x7c, 0x7a, 0x79, 0x7d, 0x70, +		0x7f, 0x73, 0x73, 0x75, 0x75, 0x76, 0x78, 0x7b, +		0xad, 0xa1, 0xa2, 0xaf, 0xa8, 0xad, 0xa4, 0xa8, +		0xa6, 0xaa, 0xaf, 0xa3, 0xab, 0xa7, 0xa1, 0xa4, +		0xaa, 0xac, 0xa9, 0xa5, 0xa3, 0xa6, 0xae, 0xab, +		0xa5, 0xa0, 0xa0, 0xae, 0xac, 0xa9, 0xa7, 0xa2, +		0xa7, 0xa2, 0xab, 0xa1, 0xa4, 0xae, 0xa1, 0xa7, +		0xa9, 0xa4, 0xac, 0xaa, 0xae, 0xa8, 0xa2, 0xad, +		0xa0, 0xaf, 0xa6, 0xac, 0xaa, 0xa9, 0xad, 0xa0, +		0xaf, 0xa3, 0xa3, 0xa5, 0xa5, 0xa6, 0xa8, 0xab, +		0x9d, 0x91, 0x92, 0x9f, 0x98, 0x9d, 0x94, 0x98, +		0x96, 0x9a, 0x9f, 0x93, 0x9b, 0x97, 0x91, 0x94, +		0x9a, 0x9c, 0x99, 0x95, 0x93, 0x96, 0x9e, 0x9b, +		0x95, 0x90, 0x90, 0x9e, 0x9c, 0x99, 0x97, 0x92, +		0x97, 0x92, 0x9b, 0x91, 0x94, 0x9e, 0x91, 0x97, +		0x99, 0x94, 0x9c, 0x9a, 0x9e, 0x98, 0x92, 0x9d, +		0x90, 0x9f, 0x96, 0x9c, 0x9a, 0x99, 0x9d, 0x90, +		0x9f, 0x93, 0x93, 0x95, 0x95, 0x96, 0x98, 0x9b, +		0xfd, 0xf1, 0xf2, 0xff, 0xf8, 0xfd, 0xf4, 0xf8, +		0xf6, 0xfa, 0xff, 0xf3, 0xfb, 0xf7, 0xf1, 0xf4, +		0xfa, 0xfc, 0xf9, 0xf5, 0xf3, 0xf6, 0xfe, 0xfb, +		0xf5, 0xf0, 0xf0, 0xfe, 0xfc, 0xf9, 0xf7, 0xf2, +		0xf7, 0xf2, 0xfb, 0xf1, 0xf4, 0xfe, 0xf1, 0xf7, +		0xf9, 0xf4, 0xfc, 0xfa, 0xfe, 0xf8, 0xf2, 0xfd, +		0xf0, 0xff, 0xf6, 0xfc, 0xfa, 0xf9, 0xfd, 0xf0, +		0xff, 0xf3, 0xf3, 0xf5, 0xf5, 0xf6, 0xf8, 0xfb, +		0x5d, 0x51, 0x52, 0x5f, 0x58, 0x5d, 0x54, 0x58, +		0x56, 0x5a, 0x5f, 0x53, 0x5b, 0x57, 0x51, 0x54, +		0x5a, 0x5c, 0x59, 0x55, 0x53, 0x56, 0x5e, 0x5b, +		0x55, 0x50, 0x50, 0x5e, 0x5c, 0x59, 0x57, 0x52, +		0x57, 0x52, 0x5b, 0x51, 0x54, 0x5e, 0x51, 0x57, +		0x59, 0x54, 0x5c, 0x5a, 0x5e, 0x58, 0x52, 0x5d, +		0x50, 0x5f, 0x56, 0x5c, 0x5a, 0x59, 0x5d, 0x50, +		0x5f, 0x53, 0x53, 0x55, 0x55, 0x56, 0x58, 0x5b, +		0x6d, 0x61, 0x62, 0x6f, 0x68, 0x6d, 0x64, 0x68, +		0x66, 0x6a, 0x6f, 0x63, 0x6b, 0x67, 0x61, 0x64, +		0x6a, 0x6c, 0x69, 0x65, 0x63, 0x66, 0x6e, 0x6b, +		0x65, 0x60, 0x60, 0x6e, 0x6c, 0x69, 0x67, 0x62, +		0x67, 0x62, 0x6b, 0x61, 0x64, 0x6e, 0x61, 0x67, +		0x69, 0x64, 0x6c, 0x6a, 0x6e, 0x68, 0x62, 0x6d, +		0x60, 0x6f, 0x66, 0x6c, 0x6a, 0x69, 0x6d, 0x60, +		0x6f, 0x63, 0x63, 0x65, 0x65, 0x66, 0x68, 0x6b, +		0x0d, 0x01, 0x02, 0x0f, 0x08, 0x0d, 0x04, 0x08, +		0x06, 0x0a, 0x0f, 0x03, 0x0b, 0x07, 0x01, 0x04, +		0x0a, 0x0c, 0x09, 0x05, 0x03, 0x06, 0x0e, 0x0b, +		0x05, 0x00, 0x00, 0x0e, 0x0c, 0x09, 0x07, 0x02, +		0x07, 0x02, 0x0b, 0x01, 0x04, 0x0e, 0x01, 0x07, +		0x09, 0x04, 0x0c, 0x0a, 0x0e, 0x08, 0x02, 0x0d, +		0x00, 0x0f, 0x06, 0x0c, 0x0a, 0x09, 0x0d, 0x00, +		0x0f, 0x03, 0x03, 0x05, 0x05, 0x06, 0x08, 0x0b, +		0x8d, 0x81, 0x82, 0x8f, 0x88, 0x8d, 0x84, 0x88, +		0x86, 0x8a, 0x8f, 0x83, 0x8b, 0x87, 0x81, 0x84, +		0x8a, 0x8c, 0x89, 0x85, 0x83, 0x86, 0x8e, 0x8b, +		0x85, 0x80, 0x80, 0x8e, 0x8c, 0x89, 0x87, 0x82, +		0x87, 0x82, 0x8b, 0x81, 0x84, 0x8e, 0x81, 0x87, +		0x89, 0x84, 0x8c, 0x8a, 0x8e, 0x88, 0x82, 0x8d, +		0x80, 0x8f, 0x86, 0x8c, 0x8a, 0x89, 0x8d, 0x80, +		0x8f, 0x83, 0x83, 0x85, 0x85, 0x86, 0x88, 0x8b, +		0xfd, 0xf1, 0xf2, 0xff, 0xf8, 0xfd, 0xf4, 0xf8, +		0xf6, 0xfa, 0xff, 0xf3, 0xfb, 0xf7, 0xf1, 0xf4, +		0xfa, 0xfc, 0xf9, 0xf5, 0xf3, 0xf6, 0xfe, 0xfb, +		0xf5, 0xf0, 0xf0, 0xfe, 0xfc, 0xf9, 0xf7, 0xf2, +		0xf7, 0xf2, 0xfb, 0xf1, 0xf4, 0xfe, 0xf1, 0xf7, +		0xf9, 0xf4, 0xfc, 0xfa, 0xfe, 0xf8, 0xf2, 0xfd, +		0xf0, 0xff, 0xf6, 0xfc, 0xfa, 0xf9, 0xfd, 0xf0, +		0xff, 0xf3, 0xf3, 0xf5, 0xf5, 0xf6, 0xf8, 0xfb, +		0x0d, 0x01, 0x02, 0x0f, 0x08, 0x0d, 0x04, 0x08, +		0x06, 0x0a, 0x0f, 0x03, 0x0b, 0x07, 0x01, 0x04, +		0x0a, 0x0c, 0x09, 0x05, 0x03, 0x06, 0x0e, 0x0b, +		0x05, 0x00, 0x00, 0x0e, 0x0c, 0x09, 0x07, 0x02, +		0x07, 0x02, 0x0b, 0x01, 0x04, 0x0e, 0x01, 0x07, +		0x09, 0x04, 0x0c, 0x0a, 0x0e, 0x08, 0x02, 0x0d, +		0x00, 0x0f, 0x06, 0x0c, 0x0a, 0x09, 0x0d, 0x00, +		0x0f, 0x03, 0x03, 0x05, 0x05, 0x06, 0x08, 0x0b, +		0xed, 0xe1, 0xe2, 0xef, 0xe8, 0xed, 0xe4, 0xe8, +		0xe6, 0xea, 0xef, 0xe3, 0xeb, 0xe7, 0xe1, 0xe4, +		0xea, 0xec, 0xe9, 0xe5, 0xe3, 0xe6, 0xee, 0xeb, +		0xe5, 0xe0, 0xe0, 0xee, 0xec, 0xe9, 0xe7, 0xe2, +		0xe7, 0xe2, 0xeb, 0xe1, 0xe4, 0xee, 0xe1, 0xe7, +		0xe9, 0xe4, 0xec, 0xea, 0xee, 0xe8, 0xe2, 0xed, +		0xe0, 0xef, 0xe6, 0xec, 0xea, 0xe9, 0xed, 0xe0, +		0xef, 0xe3, 0xe3, 0xe5, 0xe5, 0xe6, 0xe8, 0xeb, +		0x5d, 0x51, 0x52, 0x5f, 0x58, 0x5d, 0x54, 0x58, +		0x56, 0x5a, 0x5f, 0x53, 0x5b, 0x57, 0x51, 0x54, +		0x5a, 0x5c, 0x59, 0x55, 0x53, 0x56, 0x5e, 0x5b, +		0x55, 0x50, 0x50, 0x5e, 0x5c, 0x59, 0x57, 0x52, +		0x57, 0x52, 0x5b, 0x51, 0x54, 0x5e, 0x51, 0x57, +		0x59, 0x54, 0x5c, 0x5a, 0x5e, 0x58, 0x52, 0x5d, +		0x50, 0x5f, 0x56, 0x5c, 0x5a, 0x59, 0x5d, 0x50, +		0x5f, 0x53, 0x53, 0x55, 0x55, 0x56, 0x58, 0x5b, +		0x2d, 0x21, 0x22, 0x2f, 0x28, 0x2d, 0x24, 0x28, +		0x26, 0x2a, 0x2f, 0x23, 0x2b, 0x27, 0x21, 0x24, +		0x2a, 0x2c, 0x29, 0x25, 0x23, 0x26, 0x2e, 0x2b, +		0x25, 0x20, 0x20, 0x2e, 0x2c, 0x29, 0x27, 0x22, +		0x27, 0x22, 0x2b, 0x21, 0x24, 0x2e, 0x21, 0x27, +		0x29, 0x24, 0x2c, 0x2a, 0x2e, 0x28, 0x22, 0x2d, +		0x20, 0x2f, 0x26, 0x2c, 0x2a, 0x29, 0x2d, 0x20, +		0x2f, 0x23, 0x23, 0x25, 0x25, 0x26, 0x28, 0x2b, +		0x9d, 0x91, 0x92, 0x9f, 0x98, 0x9d, 0x94, 0x98, +		0x96, 0x9a, 0x9f, 0x93, 0x9b, 0x97, 0x91, 0x94, +		0x9a, 0x9c, 0x99, 0x95, 0x93, 0x96, 0x9e, 0x9b, +		0x95, 0x90, 0x90, 0x9e, 0x9c, 0x99, 0x97, 0x92, +		0x97, 0x92, 0x9b, 0x91, 0x94, 0x9e, 0x91, 0x97, +		0x99, 0x94, 0x9c, 0x9a, 0x9e, 0x98, 0x92, 0x9d, +		0x90, 0x9f, 0x96, 0x9c, 0x9a, 0x99, 0x9d, 0x90, +		0x9f, 0x93, 0x93, 0x95, 0x95, 0x96, 0x98, 0x9b, +		0x3d, 0x31, 0x32, 0x3f, 0x38, 0x3d, 0x34, 0x38, +		0x36, 0x3a, 0x3f, 0x33, 0x3b, 0x37, 0x31, 0x34, +		0x3a, 0x3c, 0x39, 0x35, 0x33, 0x36, 0x3e, 0x3b, +		0x35, 0x30, 0x30, 0x3e, 0x3c, 0x39, 0x37, 0x32, +		0x37, 0x32, 0x3b, 0x31, 0x34, 0x3e, 0x31, 0x37, +		0x39, 0x34, 0x3c, 0x3a, 0x3e, 0x38, 0x32, 0x3d, +		0x30, 0x3f, 0x36, 0x3c, 0x3a, 0x39, 0x3d, 0x30, +		0x3f, 0x33, 0x33, 0x35, 0x35, 0x36, 0x38, 0x3b, +		0x2d, 0x21, 0x22, 0x2f, 0x28, 0x2d, 0x24, 0x28, +		0x26, 0x2a, 0x2f, 0x23, 0x2b, 0x27, 0x21, 0x24, +		0x2a, 0x2c, 0x29, 0x25, 0x23, 0x26, 0x2e, 0x2b, +		0x25, 0x20, 0x20, 0x2e, 0x2c, 0x29, 0x27, 0x22, +		0x27, 0x22, 0x2b, 0x21, 0x24, 0x2e, 0x21, 0x27, +		0x29, 0x24, 0x2c, 0x2a, 0x2e, 0x28, 0x22, 0x2d, +		0x20, 0x2f, 0x26, 0x2c, 0x2a, 0x29, 0x2d, 0x20, +		0x2f, 0x23, 0x23, 0x25, 0x25, 0x26, 0x28, 0x2b, +		0xcd, 0xc1, 0xc2, 0xcf, 0xc8, 0xcd, 0xc4, 0xc8, +		0xc6, 0xca, 0xcf, 0xc3, 0xcb, 0xc7, 0xc1, 0xc4, +		0xca, 0xcc, 0xc9, 0xc5, 0xc3, 0xc6, 0xce, 0xcb, +		0xc5, 0xc0, 0xc0, 0xce, 0xcc, 0xc9, 0xc7, 0xc2, +		0xc7, 0xc2, 0xcb, 0xc1, 0xc4, 0xce, 0xc1, 0xc7, +		0xc9, 0xc4, 0xcc, 0xca, 0xce, 0xc8, 0xc2, 0xcd, +		0xc0, 0xcf, 0xc6, 0xcc, 0xca, 0xc9, 0xcd, 0xc0, +		0xcf, 0xc3, 0xc3, 0xc5, 0xc5, 0xc6, 0xc8, 0xcb, +	}, +}; + +static const uint8_t key_perm[56] = { +	57, 49, 41, 33, 25, 17,  9,  1, 58, 50, 42, 34, 26, 18, +	10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36, +	63, 55, 47, 39, 31, 23, 15,  7, 62, 54, 46, 38, 30, 22, +	14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4 +}; + +static const uint8_t key_shifts[16] = { +	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 +}; + +static const uint8_t comp_perm[48] = { +	14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10, +	23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2, +	41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, +	44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 +}; + +static const uint8_t pbox[32] = { +	16,  7, 20, 21, 29, 12, 28, 17,  1, 15, 23, 26,  5, 18, 31, 10, +	 2,  8, 24, 14, 32, 27,  3,  9, 19, 13, 30,  6, 22, 11,  4, 25 +}; + +static int +ascii_to_bin(char ch) +{ +	if (ch > 'z') +		return 0; +	if (ch >= 'a') +		return (ch - 'a' + 38); +	if (ch > 'Z') +		return 0; +	if (ch >= 'A') +		return (ch - 'A' + 12); +	if (ch > '9') +		return 0; +	if (ch >= '.') +		return (ch - '.'); +	return 0; +} + + + +struct des_ctx { +	uint32_t saltbits; /* referenced 5 times */ +	uint8_t	un_pbox[32]; /* 2 times */ +	uint8_t	inv_comp_perm[56]; /* 3 times */ +	uint8_t	inv_key_perm[64]; /* 3 times */ +	uint32_t en_keysl[16], en_keysr[16]; /* 2 times each */ +	uint32_t fp_maskl[8][256], fp_maskr[8][256]; /* 9 times each */ +	uint32_t key_perm_maskl[8][128], key_perm_maskr[8][128]; /* 9 times */ +	uint32_t comp_maskl[8][128], comp_maskr[8][128]; /* 9 times each */ +	uint32_t psbox[4][256]; /* 5 times */ +}; +#define D (*ctx) +#define saltbits        (D.saltbits       ) +#define old_salt        (D.old_salt       ) +#define old_rawkey0     (D.old_rawkey0    ) +#define old_rawkey1     (D.old_rawkey1    ) +#define un_pbox         (D.un_pbox        ) +#define inv_comp_perm   (D.inv_comp_perm  ) +#define inv_key_perm    (D.inv_key_perm   ) +#define en_keysl        (D.en_keysl       ) +#define en_keysr        (D.en_keysr       ) +#define de_keysl        (D.de_keysl       ) +#define de_keysr        (D.de_keysr       ) +#define ip_maskl        (D.ip_maskl       ) +#define ip_maskr        (D.ip_maskr       ) +#define fp_maskl        (D.fp_maskl       ) +#define fp_maskr        (D.fp_maskr       ) +#define key_perm_maskl  (D.key_perm_maskl ) +#define key_perm_maskr  (D.key_perm_maskr ) +#define comp_maskl      (D.comp_maskl     ) +#define comp_maskr      (D.comp_maskr     ) +#define psbox           (D.psbox          ) + +static struct des_ctx *des_init(struct des_ctx *ctx) +{ +	int i, j, b, k, inbit, obit; +	uint32_t p; + +	saltbits = 0; + +	/* Initialise the inverted key permutation. */ +	for (i = 0; i < 64; i++) { +		inv_key_perm[i] = 255; +	} + +	/* +	 * Invert the key permutation and initialise the inverted key +	 * compression permutation. +	 */ +	for (i = 0; i < 56; i++) { +		inv_key_perm[key_perm[i] - 1] = (uint8_t)i; +		inv_comp_perm[i] = 255; +	} + +	/* Invert the key compression permutation. */ +	for (i = 0; i < 48; i++) { +		inv_comp_perm[comp_perm[i] - 1] = (uint8_t)i; +	} + +	/* +	 * Set up the OR-mask arrays for the initial and final permutations, +	 * and for the key initial and compression permutations. +	 */ +	for (k = 0; k < 8; k++) { +		uint32_t il, ir; +		uint32_t fl, fr; +		for (i = 0; i < 256; i++) { +			fl = 0; +			fr = 0; +			for (j = 0; j < 8; j++) { +				inbit = 8 * k + j; +				if (i & (0x80>>j)) { +					obit = final_perm[inbit]; +					if (obit < 32) +						fl |= 0x80000000UL >> obit; +					else +						fr |= 0x80000000UL >> obit-32; +				} +			} +			fp_maskl[k][i] = fl; +			fp_maskr[k][i] = fr; +		} +		for (i = 0; i < 128; i++) { +			il = 0; +			ir = 0; +			for (j = 0; j < 7; j++) { +				inbit = 8 * k + j; +				if (i & (0x80 >> j + 1)) { +					obit = inv_key_perm[inbit]; +					if (obit == 255) +						continue; +					if (obit < 28) +						il |= 0x8000000UL >> obit; +					else +						ir |= 0x8000000UL >> obit-28; +				} +			} +			key_perm_maskl[k][i] = il; +			key_perm_maskr[k][i] = ir; +			il = 0; +			ir = 0; +			for (j = 0; j < 7; j++) { +				inbit = 7 * k + j; +				if (i & (0x80 >> j + 1)) { +					obit = inv_comp_perm[inbit]; +					if (obit == 255) +						continue; +					if (obit < 24) +						il |= 0x800000UL >> obit; +					else +						ir |= 0x800000UL >> obit-24; +				} +			} +			comp_maskl[k][i] = il; +			comp_maskr[k][i] = ir; +		} +	} + +	/* +	 * Invert the P-box permutation, and convert into OR-masks for +	 * handling the output of the S-box arrays setup above. +	 */ +	for (i = 0; i < 32; i++) +		un_pbox[pbox[i] - 1] = (uint8_t)i; + +	for (b = 0; b < 4; b++) { +		for (i = 0; i < 256; i++) { +			p = 0; +			for (j = 0; j < 8; j++) { +				if (i & (0x80 >> j)) +					p |= 0x80000000>>un_pbox[8 * b + j]; +			} +			psbox[b][i] = p; +		} +	} + +	return ctx; +} + + +static void setup_salt(struct des_ctx *ctx, uint32_t salt) +{ +	uint32_t obit, saltbit; +	int i; + +	saltbits = 0; +	saltbit = 1; +	obit = 0x800000; +	for (i = 0; i < 24; i++) { +		if (salt & saltbit) +			saltbits |= obit; +		saltbit <<= 1; +		obit >>= 1; +	} +} + +static void des_setkey(struct des_ctx *ctx, const unsigned char *key) +{ +	uint32_t k0, k1, rawkey0, rawkey1; +	int shifts, round; + +	rawkey0 = key[0]<<24 | key[1]<<16 | key[2]<<8 | key[3]; +	rawkey1 = key[4]<<24 | key[5]<<16 | key[6]<<8 | key[7]; + +	/* +	 * Do key permutation and split into two 28-bit subkeys. +	 */ +	k0 = key_perm_maskl[0][rawkey0 >> 25] +	   | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f] +	   | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f] +	   | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f] +	   | key_perm_maskl[4][rawkey1 >> 25] +	   | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f] +	   | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f] +	   | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f]; +	k1 = key_perm_maskr[0][rawkey0 >> 25] +	   | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f] +	   | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f] +	   | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f] +	   | key_perm_maskr[4][rawkey1 >> 25] +	   | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f] +	   | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f] +	   | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f]; +	/* +	 * Rotate subkeys and do compression permutation. +	 */ +	shifts = 0; +	for (round = 0; round < 16; round++) { +		uint32_t t0, t1; + +		shifts += key_shifts[round]; + +		t0 = (k0 << shifts) | (k0 >> (28 - shifts)); +		t1 = (k1 << shifts) | (k1 >> (28 - shifts)); + +		en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f] +				| comp_maskl[1][(t0 >> 14) & 0x7f] +				| comp_maskl[2][(t0 >> 7) & 0x7f] +				| comp_maskl[3][t0 & 0x7f] +				| comp_maskl[4][(t1 >> 21) & 0x7f] +				| comp_maskl[5][(t1 >> 14) & 0x7f] +				| comp_maskl[6][(t1 >> 7) & 0x7f] +				| comp_maskl[7][t1 & 0x7f]; + +		en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f] +				| comp_maskr[1][(t0 >> 14) & 0x7f] +				| comp_maskr[2][(t0 >> 7) & 0x7f] +				| comp_maskr[3][t0 & 0x7f] +				| comp_maskr[4][(t1 >> 21) & 0x7f] +				| comp_maskr[5][(t1 >> 14) & 0x7f] +				| comp_maskr[6][(t1 >> 7) & 0x7f] +				| comp_maskr[7][t1 & 0x7f]; +	} +} + + +static void do_des(struct des_ctx *ctx, uint32_t *l_out, uint32_t *r_out, int count) +{ +	uint32_t l, r, *kl, *kr; +	uint32_t f = f; /* silence gcc */ +	uint32_t r48l, r48r; +	int round; + +	/* Do initial permutation (IP). */ +	l = r = 0; + +	do { +		/* Do each round. */ +		kl = en_keysl; +		kr = en_keysr; +		round = 16; +		do { +			/* Expand R to 48 bits (simulate the E-box). */ +			r48l	= ((r & 0x00000001) << 23) +				| ((r & 0xf8000000) >> 9) +				| ((r & 0x1f800000) >> 11) +				| ((r & 0x01f80000) >> 13) +				| ((r & 0x001f8000) >> 15); + +			r48r	= ((r & 0x0001f800) << 7) +				| ((r & 0x00001f80) << 5) +				| ((r & 0x000001f8) << 3) +				| ((r & 0x0000001f) << 1) +				| ((r & 0x80000000) >> 31); +			/* +			 * Do salting for crypt() and friends, and +			 * XOR with the permuted key. +			 */ +			f = (r48l ^ r48r) & saltbits; +			r48l ^= f ^ *kl++; +			r48r ^= f ^ *kr++; +			/* +			 * Do sbox lookups (which shrink it back to 32 bits) +			 * and do the pbox permutation at the same time. +			 */ +			f = psbox[0][m_sbox[0][r48l >> 12]] +			  | psbox[1][m_sbox[1][r48l & 0xfff]] +			  | psbox[2][m_sbox[2][r48r >> 12]] +			  | psbox[3][m_sbox[3][r48r & 0xfff]]; +			/* Now that we've permuted things, complete f(). */ +			f ^= l; +			l = r; +			r = f; +		} while (--round); +		r = l; +		l = f; +	} while (--count); + +	/* Do final permutation (inverse of IP). */ +	*l_out	= fp_maskl[0][l >> 24] +		| fp_maskl[1][(l >> 16) & 0xff] +		| fp_maskl[2][(l >> 8) & 0xff] +		| fp_maskl[3][l & 0xff] +		| fp_maskl[4][r >> 24] +		| fp_maskl[5][(r >> 16) & 0xff] +		| fp_maskl[6][(r >> 8) & 0xff] +		| fp_maskl[7][r & 0xff]; +	*r_out	= fp_maskr[0][l >> 24] +		| fp_maskr[1][(l >> 16) & 0xff] +		| fp_maskr[2][(l >> 8) & 0xff] +		| fp_maskr[3][l & 0xff] +		| fp_maskr[4][r >> 24] +		| fp_maskr[5][(r >> 16) & 0xff] +		| fp_maskr[6][(r >> 8) & 0xff] +		| fp_maskr[7][r & 0xff]; +} + +#define DES_OUT_BUFSIZE 21 + +static void +to64_msb_first(char *s, unsigned v) +{ +	*s++ = i64c(v >> 18); /* bits 23..18 */ +	*s++ = i64c(v >> 12); /* bits 17..12 */ +	*s++ = i64c(v >> 6); /* bits 11..6 */ +	*s   = i64c(v); /* bits 5..0 */ +} + +static char * +des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE], +		const unsigned char *key, const unsigned char *setting) +{ +	uint32_t salt, r0, r1, keybuf[2]; +	uint8_t *q; + +	/* +	 * Copy the key, shifting each character up by one bit +	 * and padding with zeros. +	 */ +	q = (uint8_t *)keybuf; +	while (q - (uint8_t *)keybuf != 8) { +		*q = *key << 1; +		if (*q) +			key++; +		q++; +	} +	des_setkey(ctx, (char *)keybuf); + +	/* +	 * setting - 2 bytes of salt +	 * key - up to 8 characters +	 */ +	salt = (ascii_to_bin(setting[1]) << 6) +	     |  ascii_to_bin(setting[0]); + +	output[0] = setting[0]; +	/* +	 * If the encrypted password that the salt was extracted from +	 * is only 1 character long, the salt will be corrupted.  We +	 * need to ensure that the output string doesn't have an extra +	 * NUL in it! +	 */ +	output[1] = setting[1] ? setting[1] : output[0]; + +	setup_salt(ctx, salt); +	/* Do it. */ +	do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */); + +	/* Now encode the result. */ +	/* Each call takes low-order 24 bits and stores 4 chars */ +	/* bits 31..8 of r0 */ +	to64_msb_first(output + 2, (r0 >> 8)); +	/* bits 7..0 of r0 and 31..16 of r1 */ +	to64_msb_first(output + 6, (r0 << 16) | (r1 >> 16)); +	/* bits 15..0 of r1 and two zero bits (plus extra zero byte) */ +	to64_msb_first(output + 10, (r1 << 8)); +	/* extra zero byte is encoded as '.', fixing it */ +	output[13] = '\0'; + +	return output; +} + +#undef C +#undef init_perm +#undef final_perm +#undef m_sbox +#undef D +#undef const_ctx +#undef saltbits +#undef old_salt +#undef old_rawkey0 +#undef old_rawkey1 +#undef un_pbox +#undef inv_comp_perm +#undef inv_key_perm +#undef en_keysl +#undef en_keysr +#undef de_keysl +#undef de_keysr +#undef ip_maskl +#undef ip_maskr +#undef fp_maskl +#undef fp_maskr +#undef key_perm_maskl +#undef key_perm_maskr +#undef comp_maskl +#undef comp_maskr +#undef psbox + +struct crypt_data; + +char *__crypt_r(const char *clear, const char *salt, struct crypt_data *data) +{ +	struct des_ctx des_ctx = { 0 }; + +#if 0 +	/* MD5 or SHA? */ +	if (salt[0] == '$' && salt[1] && salt[2] == '$') { +		if (salt[1] == '1') +			return md5_crypt((char *)data, clear, salt); +	} +#endif + +	des_init(&des_ctx); +	return des_crypt(&des_ctx, (char *)data, clear, salt); +} + +weak_alias(__crypt_r, crypt_r); + +char *crypt(const char *clear, const char *salt) +{ +	static char buf[128]; +	return __crypt_r(clear, salt, (void *)buf); +} diff --git a/src/misc/cuserid.c b/src/misc/cuserid.c new file mode 100644 index 00000000..8ad0b9f3 --- /dev/null +++ b/src/misc/cuserid.c @@ -0,0 +1,13 @@ +#include <pwd.h> +#include <stdio.h> +#include <unistd.h> + +char *cuserid(char *buf) +{ +	struct passwd pw, *ppw; +	long pwb[256]; +	if (getpwuid_r(geteuid(), &pw, (void *)pwb, sizeof pwb, &ppw)) +		return 0; +	snprintf(buf, L_cuserid, "%s", pw.pw_name); +	return buf; +} diff --git a/src/misc/dirname.c b/src/misc/dirname.c new file mode 100644 index 00000000..8f70dbb1 --- /dev/null +++ b/src/misc/dirname.c @@ -0,0 +1,15 @@ +#include <string.h> +#include <libgen.h> + +char *dirname(char *s) +{ +	size_t i; +	if (!s || !*s || !strchr(s, '/')) return "."; +	i = strlen(s)-1; +	for (; i&&s[i]=='/'; i--); +	for (; i&&s[i-1]!='/'; i--); +	for (; i&&s[i-1]=='/'; i--); +	if (!i && *s=='/') i++; +	s[i] = 0; +	return s; +} diff --git a/src/misc/ffs.c b/src/misc/ffs.c new file mode 100644 index 00000000..2f7cb321 --- /dev/null +++ b/src/misc/ffs.c @@ -0,0 +1,9 @@ +#include <strings.h> + +int ffs(int i) +{ +	unsigned int j = i; +	for (i=1; j && !(j&1); j>>=1, i++); +	if (j) return i; +	return 0; +} diff --git a/src/misc/ftw.c b/src/misc/ftw.c new file mode 100644 index 00000000..de01e39c --- /dev/null +++ b/src/misc/ftw.c @@ -0,0 +1,9 @@ +#include <ftw.h> +#include "libc.h" + +int ftw(const char *path, int (*fn)(const char *, const struct stat *, int), int fd_limit) +{ +	return nftw(path, (void *)fn, fd_limit, FTW_PHYS); +} + +LFS64(ftw); diff --git a/src/misc/getdomainname.c b/src/misc/getdomainname.c new file mode 100644 index 00000000..7eb113d7 --- /dev/null +++ b/src/misc/getdomainname.c @@ -0,0 +1,9 @@ +#include <unistd.h> +#include <sys/utsname.h> +#include <string.h> + +int getdomainname(char *name, size_t len) +{ +	*name = 0; +	return 0; +} diff --git a/src/misc/getgrouplist.c b/src/misc/getgrouplist.c new file mode 100644 index 00000000..88f273d7 --- /dev/null +++ b/src/misc/getgrouplist.c @@ -0,0 +1,11 @@ +#include <grp.h> + +/* FIXME */ + +int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups) +{ +	if (*ngroups<1) return -1; +	*groups = gid; +	*ngroups = 1; +	return 0; +} diff --git a/src/misc/getopt.c b/src/misc/getopt.c new file mode 100644 index 00000000..abf0e847 --- /dev/null +++ b/src/misc/getopt.c @@ -0,0 +1,63 @@ +#include <unistd.h> +#include <wchar.h> +#include <string.h> +#include <limits.h> +#include <stdlib.h> + +char *optarg; +int optind=1, opterr=1, optopt; +static int optpos; + +int getopt(int argc, char * const argv[], const char *optstring) +{ +	int i; +	wchar_t c, d; +	int k, l; +	char *optchar; + +	if (optind >= argc || !argv[optind] || argv[optind][0] != '-' || !argv[optind][1]) +		return -1; +	if (argv[optind][1] == '-' && !argv[optind][2]) +		return optind++, -1; + +	if (!optpos) optpos++; +	if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) { +		k = 1; +		c = 0xfffd; /* replacement char */ +	} +	optchar = argv[optind]+optpos; +	optopt = c; +	optpos += k; + +	if (!argv[optind][optpos]) { +		optind++; +		optpos = 0; +	} + +	for (i=0; (l = mbtowc(&d, optstring+i, MB_LEN_MAX)) && d!=c; i+=l>0?l:1); + +	if (d != c) { +		if (optstring[0] != ':' && opterr) { +			write(2, argv[0], strlen(argv[0])); +			write(2, ": illegal option: ", 18); +			write(2, optchar, k); +			write(2, "\n", 1); +		} +		return '?'; +	} +	if (optstring[i+1] == ':') { +		if (optind >= argc) { +			if (optstring[0] == ':') return ':'; +			if (opterr) { +				write(2, argv[0], strlen(argv[0])); +				write(2, ": option requires an argument: ", 31); +				write(2, optchar, k); +				write(2, "\n", 1); +			} +			return '?'; +		} +		optarg = argv[optind++] + optpos; +		optpos = 0; +	} +	return c; +} diff --git a/src/misc/getpriority.c b/src/misc/getpriority.c new file mode 100644 index 00000000..2fb26b2b --- /dev/null +++ b/src/misc/getpriority.c @@ -0,0 +1,9 @@ +#include <sys/resource.h> +#include "syscall.h" + +int getpriority(int which, id_t who) +{ +	int ret = syscall2(__NR_getpriority, which, who); +	if (ret < 0) return ret; +	return 20-ret; +} diff --git a/src/misc/getrlimit.c b/src/misc/getrlimit.c new file mode 100644 index 00000000..db25943b --- /dev/null +++ b/src/misc/getrlimit.c @@ -0,0 +1,15 @@ +#include <sys/resource.h> +#include "syscall.h" +#include "libc.h" + +int getrlimit(int resource, struct rlimit *rlim) +{ +	long k_rlim[2]; +	if (syscall2(__NR_ugetrlimit, resource, (long)k_rlim) < 0) +		return -1; +	rlim->rlim_cur = k_rlim[0]; +	rlim->rlim_max = k_rlim[1]; +	return 0; +} + +LFS64(getrlimit); diff --git a/src/misc/getrusage.c b/src/misc/getrusage.c new file mode 100644 index 00000000..1b8850f9 --- /dev/null +++ b/src/misc/getrusage.c @@ -0,0 +1,20 @@ +#include <sys/resource.h> +#include <string.h> +#include "syscall.h" + +/* this is a huge hack to make up for the kernel's stupid 32bit time_t + * without having to recopy the whole rusage structure ourselves.. */ + +int getrusage(int who, struct rusage *ru) +{ +	struct { long tv_sec, tv_usec; } ktv[2]; +	char *fakeaddr = ((char *)ru + sizeof(struct timeval [2]) - sizeof ktv); +	if (syscall2(__NR_getrusage, who, (long)fakeaddr) < 0) +		return -1; +	memcpy(ktv, fakeaddr, sizeof ktv); +	ru->ru_utime.tv_sec  = ktv[0].tv_sec; +	ru->ru_utime.tv_usec = ktv[0].tv_usec; +	ru->ru_stime.tv_sec  = ktv[1].tv_sec; +	ru->ru_stime.tv_usec = ktv[1].tv_usec; +	return 0; +} diff --git a/src/misc/getsubopt.c b/src/misc/getsubopt.c new file mode 100644 index 00000000..dac9bf9e --- /dev/null +++ b/src/misc/getsubopt.c @@ -0,0 +1,23 @@ +#include <stdlib.h> +#include <string.h> + +int getsubopt(char **opt, char *const *keys, char **val) +{ +	char *s = *opt; +	int i; + +	*val = NULL; +	*opt = strchr(s, ','); +	if (*opt) *(*opt)++ = 0; +	else *opt = s + strlen(s); + +	for (i=0; keys[i]; i++) { +		size_t l = strlen(keys[i]); +		if (strncmp(keys[i], s, l)) continue; +		if (s[l] == '=') +			*val = s + l; +		else if (s[l]) continue; +		return i; +	} +	return -1; +} diff --git a/src/misc/ioctl.c b/src/misc/ioctl.c new file mode 100644 index 00000000..808b7c9c --- /dev/null +++ b/src/misc/ioctl.c @@ -0,0 +1,13 @@ +#include <sys/ioctl.h> +#include <stdarg.h> +#include "syscall.h" + +int ioctl(int fd, int req, ...) +{ +	void *arg; +	va_list ap; +	va_start(ap, req); +	arg = va_arg(ap, void *); +	va_end(ap); +	return syscall3(__NR_ioctl, fd, req, (long)arg); +} diff --git a/src/misc/lockf.c b/src/misc/lockf.c new file mode 100644 index 00000000..d8f82efd --- /dev/null +++ b/src/misc/lockf.c @@ -0,0 +1,33 @@ +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include "libc.h" + +int lockf(int fd, int op, off_t size) +{ +	struct flock l = { +		.l_type = F_WRLCK, +		.l_whence = SEEK_CUR, +		.l_len = size, +	}; +	switch (op) { +	case F_TEST: +		l.l_type = F_RDLCK; +		if (fcntl(fd, F_GETLK, &l) < 0) +			return -1; +		if (l.l_type == F_UNLCK || l.l_pid == getpid()) +			return 0; +		errno = EACCES; +		return -1; +	case F_ULOCK: +		l.l_type = F_UNLCK; +	case F_TLOCK: +		return fcntl(fd, F_SETLK, &l); +	case F_LOCK: +		return fcntl(fd, F_SETLKW, &l); +	} +	errno = EINVAL; +	return -1; +} + +LFS64(lockf); diff --git a/src/misc/nftw.c b/src/misc/nftw.c new file mode 100644 index 00000000..1b94ac15 --- /dev/null +++ b/src/misc/nftw.c @@ -0,0 +1,121 @@ +#include <ftw.h> +#include <dirent.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <limits.h> +#include "libc.h" + +struct history +{ +	struct history *chain; +	dev_t dev; +	ino_t ino; +	int level; +	int base; +}; + +#undef dirfd +#define dirfd(d) (*(int *)d) + +static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, struct FTW *), int fd_limit, int flags, struct history *h) +{ +	size_t l = strlen(path), j = l && path[l-1]=='/' ? l-1 : l; +	struct stat st; +	struct history new; +	int type; +	int r; +	struct FTW lev; +	char *name; + +	if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) { +		if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st)) +			type = FTW_SLN; +		else if (errno != EACCES) return -1; +		else type = FTW_NS; +	} else if (S_ISDIR(st.st_mode)) { +		if (access(path, R_OK) < 0) type = FTW_DNR; +		else if (flags & FTW_DEPTH) type = FTW_DP; +		else type = FTW_D; +	} else if (S_ISLNK(st.st_mode)) { +		if (flags & FTW_PHYS) type = FTW_SL; +		else type = FTW_SLN; +	} else { +		type = FTW_F; +	} + +	if ((flags & FTW_MOUNT) && h +	 && (st.st_dev != h->dev || st.st_ino != h->ino)) +		return 0; +	 +	new.chain = h; +	new.dev = st.st_dev; +	new.ino = st.st_ino; +	new.level = h ? h->level+1 : 0; +	new.base = l+1; +	 +	lev.level = new.level; +	lev.base = h ? h->base : (name=strrchr(path, '/')) ? name-path : 0; + +	if (!(flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev))) +		return r; + +	for (; h; h = h->chain) +		if (h->dev == st.st_dev && h->ino == st.st_ino) +			return 0; + +	if ((type == FTW_D || type == FTW_DP) && fd_limit) { +		DIR *d = opendir(path); +		if (d) { +			struct dirent *de; +			while ((de = readdir(d))) { +				if (de->d_name[0] == '.' +				 && (!de->d_name[1] +				  || (de->d_name[1]=='.' +				   && !de->d_name[2]))) continue; +				if (strlen(de->d_name) >= PATH_MAX-l) { +					errno = ENAMETOOLONG; +					closedir(d); +					return -1; +				} +				path[j]='/'; +				strcpy(path+j+1, de->d_name); +				if ((r=do_nftw(path, fn, fd_limit-1, flags, &new))) { +					closedir(d); +					return r; +				} +			} +			closedir(d); +		} else if (errno != EACCES) { +			return -1; +		} +	} + +	path[l] = 0; +	if ((flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev))) +		return r; + +	return 0; +} + +int nftw(const char *path, int (*fn)(const char *, const struct stat *, int, struct FTW *), int fd_limit, int flags) +{ +	size_t l; +	char pathbuf[PATH_MAX+1]; + +	if (fd_limit <= 0) return 0; + +	l = strlen(path); +	if (l > PATH_MAX) { +		errno = ENAMETOOLONG; +		return -1; +	} +	memcpy(pathbuf, path, l+1); +	 +	return do_nftw(pathbuf, fn, fd_limit, flags, NULL); +} + +LFS64(nftw); diff --git a/src/misc/openpty.c b/src/misc/openpty.c new file mode 100644 index 00000000..0b4eb221 --- /dev/null +++ b/src/misc/openpty.c @@ -0,0 +1,33 @@ +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <pty.h> +#include <stdio.h> + +/* Nonstandard, but vastly superior to the standard functions */ + +int openpty(int *m, int *s, char *name, const struct termios *tio, const struct winsize *ws) +{ +	int n=0; +	char buf[20]; + +	*m = open("/dev/ptmx", O_RDWR|O_NOCTTY); +	if (!*m) return -1; + +	if (ioctl(*m, TIOCSPTLCK, &n) || ioctl (*m, TIOCGPTN, &n)) { +		close(*m); +		return -1; +	} + +	if (!name) name = buf; +	snprintf(name, sizeof buf, "/dev/pts/%d", n); +	if ((*s = open(name, O_RDWR|O_NOCTTY)) < 0) { +		close(*m); +		return -1; +	} + +	if (tio) tcsetattr(*s, TCSANOW, tio); +	if (ws) ioctl(*s, TIOCSWINSZ, ws); + +	return 0; +} diff --git a/src/misc/pty.c b/src/misc/pty.c new file mode 100644 index 00000000..0d25a836 --- /dev/null +++ b/src/misc/pty.c @@ -0,0 +1,35 @@ +#include <stdlib.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <fcntl.h> + +int posix_openpt(int flags) +{ +	return open("/dev/ptmx", flags); +} + +int grantpt(int fd) +{ +	return 0; +} + +int unlockpt(int fd) +{ +	int unlock = 0; +	return ioctl(fd, TIOCSPTLCK, &unlock); +} + +char *ptsname(int fd) +{ +	static char buf[9 + sizeof(int)*3 + 1]; +	char *s = buf+sizeof(buf)-1; +	int pty; +	if (ioctl (fd, TIOCGPTN, &pty)) +		return NULL; +	if (pty) for (; pty; pty/=10) *--s = '0' + pty%10; +	else *--s = '0'; +	s -= 9; +        s[0] = '/'; s[1] = 'd'; s[2] = 'e'; s[3] = 'v'; +	s[4] = '/'; s[5] = 'p'; s[6] = 't'; s[7] = 's'; s[8] = '/'; +	return s; +} diff --git a/src/misc/realpath.c b/src/misc/realpath.c new file mode 100644 index 00000000..f6b55495 --- /dev/null +++ b/src/misc/realpath.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +char *realpath(const char *filename, char *resolved) +{ +	return 0; +} diff --git a/src/misc/sched_yield.c b/src/misc/sched_yield.c new file mode 100644 index 00000000..8a68519e --- /dev/null +++ b/src/misc/sched_yield.c @@ -0,0 +1,10 @@ +#include <sched.h> +#include "syscall.h" +#include "libc.h" + +int __yield() +{ +	return syscall0(__NR_sched_yield); +} + +weak_alias(__yield, sched_yield); diff --git a/src/misc/setpriority.c b/src/misc/setpriority.c new file mode 100644 index 00000000..26da4b83 --- /dev/null +++ b/src/misc/setpriority.c @@ -0,0 +1,7 @@ +#include <sys/resource.h> +#include "syscall.h" + +int setpriority(int which, id_t who, int prio) +{ +	return syscall3(__NR_getpriority, which, who, prio); +} diff --git a/src/misc/setrlimit.c b/src/misc/setrlimit.c new file mode 100644 index 00000000..7fdfc4e5 --- /dev/null +++ b/src/misc/setrlimit.c @@ -0,0 +1,11 @@ +#include <sys/resource.h> +#include "syscall.h" +#include "libc.h" + +int setrlimit(int resource, const struct rlimit *rlim) +{ +	long k_rlim[2] = { rlim->rlim_cur, rlim->rlim_max }; +	return syscall2(__NR_setrlimit, resource, (long)k_rlim); +} + +LFS64(setrlimit); diff --git a/src/misc/syslog.c b/src/misc/syslog.c new file mode 100644 index 00000000..4809d2da --- /dev/null +++ b/src/misc/syslog.c @@ -0,0 +1,115 @@ +#include <stdarg.h> +#include <sys/socket.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <syslog.h> +#include <time.h> +#include <signal.h> +#include <string.h> +#include "libc.h" + +static int lock; +static const char *log_ident; +static int log_opt; +static int log_facility = LOG_USER; +static int log_mask = 0xff; +static FILE *log_f; + +int setlogmask(int maskpri) +{ +	int old = log_mask; +	if (maskpri) log_mask = maskpri; +	return old; +} + +static const struct { +	short sun_family; +	char sun_path[9]; +} log_addr = { +	AF_UNIX, +	"/dev/log" +}; + +void closelog(void) +{ +	LOCK(&lock); +	if (log_f) fclose(log_f); +	log_f = NULL; +	UNLOCK(&lock); +} + +static void __openlog(const char *ident, int opt, int facility) +{ +	int fd; + +	log_ident = ident; +	log_opt = opt; +	log_facility = facility; + +	if (!(opt & LOG_NDELAY) || log_f) return; + +	fd = socket(AF_UNIX, SOCK_STREAM, 0); +	fcntl(fd, F_SETFD, FD_CLOEXEC); +	if (connect(fd, (void *)&log_addr, sizeof(short) + sizeof "/dev/log") < 0) +		close(fd); +	else log_f = fdopen(fd, "wb"); +} + +void openlog(const char *ident, int opt, int facility) +{ +	LOCK(&lock); +	__openlog(ident, opt, facility); +	UNLOCK(&lock); +} + +void syslog(int priority, const char *message, ...) +{ +	struct sigaction sa; +	va_list ap; +	char timebuf[16]; +	time_t now; +	struct tm tm; +	//const char *fmt, *ident, *sep; +	//int i; + +	if (!(log_mask & LOG_MASK(priority&7)) || (priority&~0x3ff)) return; + +	LOCK(&lock); + +	if (!log_f) __openlog(log_ident, log_opt | LOG_NDELAY, log_facility); +	if (!log_f) { +		UNLOCK(&lock); +		return; +	} + +	memset(&sa, 0, sizeof sa); +	sa.sa_handler = SIG_IGN; +	if (sigaction(SIGPIPE, &sa, &sa) < 0) { +		// we must abandon logging or we might cause SIGPIPE +		UNLOCK(&lock); +		return; +	} + +	now = time(NULL); +	gmtime_r(&now, &tm); +	strftime(timebuf, sizeof timebuf, "%b %e %T", &tm); + +	fprintf(log_f, "<%d>%s ", priority, timebuf); +	if (log_ident) fprintf(log_f, "%s", log_ident); +	if (log_opt & LOG_PID) fprintf(log_f, "[%d]", getpid()); +	if (log_ident) fprintf(log_f, ": "); + +	va_start(ap, message); +	vfprintf(log_f, message, ap); +	va_end(ap); +	fputc(0, log_f); +	fflush(log_f); + +	// Note: LOG_CONS is not supported because it is annoying!! +	// syslogd will send messages to console if it deems them appropriate! + +	sigaction(SIGPIPE, &sa, NULL); + +	UNLOCK(&lock); +} diff --git a/src/misc/uname.c b/src/misc/uname.c new file mode 100644 index 00000000..fbe86643 --- /dev/null +++ b/src/misc/uname.c @@ -0,0 +1,8 @@ +#include <sys/utsname.h> +#include <string.h> +#include "syscall.h" + +int uname(struct utsname *uts) +{ +	return syscall1(__NR_uname, (long)uts); +} diff --git a/src/mman/madvise.c b/src/mman/madvise.c new file mode 100644 index 00000000..f03647ca --- /dev/null +++ b/src/mman/madvise.c @@ -0,0 +1,10 @@ +#include <sys/mman.h> +#include "syscall.h" +#include "libc.h" + +int __madvise(void *addr, size_t len, int advice) +{ +	return syscall3(__NR_madvise, (long)addr, len, advice); +} + +weak_alias(__madvise, madvise); diff --git a/src/mman/mlock.c b/src/mman/mlock.c new file mode 100644 index 00000000..3c7c653c --- /dev/null +++ b/src/mman/mlock.c @@ -0,0 +1,7 @@ +#include <sys/mman.h> +#include "syscall.h" + +int mlock(const void *addr, size_t len) +{ +	return syscall2(__NR_mlock, (long)addr, len); +} diff --git a/src/mman/mlockall.c b/src/mman/mlockall.c new file mode 100644 index 00000000..782fc9db --- /dev/null +++ b/src/mman/mlockall.c @@ -0,0 +1,7 @@ +#include <sys/mman.h> +#include "syscall.h" + +int mlockall(int flags) +{ +	return syscall1(__NR_mlockall, flags); +} diff --git a/src/mman/mmap.c b/src/mman/mmap.c new file mode 100644 index 00000000..93c76582 --- /dev/null +++ b/src/mman/mmap.c @@ -0,0 +1,18 @@ +#include <unistd.h> +#include <sys/mman.h> +#include <errno.h> +#include <limits.h> +#include "syscall.h" +#include "libc.h" + +void *__mmap(void *start, size_t len, int prot, int flags, int fd, off_t off) +{ +	if (sizeof(off_t) > sizeof(long)) +		if (((long)off & 0xfff) | ((long)((unsigned long long)off>>(12 + 8*(sizeof(off_t)-sizeof(long)))))) +			start = (void *)-1; +	return (void *)syscall6(__NR_mmap2, (long)start, len, prot, flags, fd, off>>12); +} + +weak_alias(__mmap, mmap); + +LFS64(mmap); diff --git a/src/mman/mprotect.c b/src/mman/mprotect.c new file mode 100644 index 00000000..11d5e231 --- /dev/null +++ b/src/mman/mprotect.c @@ -0,0 +1,7 @@ +#include <sys/mman.h> +#include "syscall.h" + +int mprotect(void *addr, size_t len, int prot) +{ +	return syscall3(__NR_mprotect, (long)addr, len, prot); +} diff --git a/src/mman/mremap.c b/src/mman/mremap.c new file mode 100644 index 00000000..78491ef4 --- /dev/null +++ b/src/mman/mremap.c @@ -0,0 +1,19 @@ +#include <unistd.h> +#include <sys/mman.h> +#include <stdarg.h> +#include "syscall.h" +#include "libc.h" + +void *__mremap(void *old_addr, size_t old_len, size_t new_len, int flags, ...) +{ +	va_list ap; +	void *new_addr; +	 +	va_start(ap, flags); +	new_addr = va_arg(ap, void *); +	va_end(ap); + +	return (void *)syscall5(__NR_mremap, (long)old_addr, old_len, new_len, flags, (long)new_addr); +} + +weak_alias(__mremap, mremap); diff --git a/src/mman/msync.c b/src/mman/msync.c new file mode 100644 index 00000000..e0926470 --- /dev/null +++ b/src/mman/msync.c @@ -0,0 +1,8 @@ +#include <unistd.h> +#include <sys/mman.h> +#include "syscall.h" + +int msync(void *start, size_t len, int flags) +{ +	return syscall3(__NR_msync, (long)start, len, flags); +} diff --git a/src/mman/munlock.c b/src/mman/munlock.c new file mode 100644 index 00000000..0db59815 --- /dev/null +++ b/src/mman/munlock.c @@ -0,0 +1,7 @@ +#include <sys/mman.h> +#include "syscall.h" + +int munlock(const void *addr, size_t len) +{ +	return syscall2(__NR_munlock, (long)addr, len); +} diff --git a/src/mman/munlockall.c b/src/mman/munlockall.c new file mode 100644 index 00000000..ce3e86cc --- /dev/null +++ b/src/mman/munlockall.c @@ -0,0 +1,7 @@ +#include <sys/mman.h> +#include "syscall.h" + +int munlockall(void) +{ +	return syscall0(__NR_munlockall); +} diff --git a/src/mman/munmap.c b/src/mman/munmap.c new file mode 100644 index 00000000..c9661cda --- /dev/null +++ b/src/mman/munmap.c @@ -0,0 +1,11 @@ +#include <unistd.h> +#include <sys/mman.h> +#include "syscall.h" +#include "libc.h" + +int __munmap(void *start, size_t len) +{ +	return syscall2(__NR_munmap, (long)start, len); +} + +weak_alias(__munmap, munmap); diff --git a/src/mman/posix_madvise.c b/src/mman/posix_madvise.c new file mode 100644 index 00000000..4727ad75 --- /dev/null +++ b/src/mman/posix_madvise.c @@ -0,0 +1,6 @@ +#include <sys/mman.h> + +int posix_madvise(void *addr, size_t len, int advice) +{ +	return 0; +} diff --git a/src/multibyte/btowc.c b/src/multibyte/btowc.c new file mode 100644 index 00000000..9d2c3b16 --- /dev/null +++ b/src/multibyte/btowc.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include <wchar.h> + +wint_t btowc(int c) +{ +	return c<128U ? c : EOF; +} diff --git a/src/multibyte/decode.c b/src/multibyte/decode.c new file mode 100644 index 00000000..8d3d3c0b --- /dev/null +++ b/src/multibyte/decode.c @@ -0,0 +1,47 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> + +#include "internal.h" + +/* Decodes UTF-8 byte-by-byte. The c argument must be initialized to 0 + * to begin decoding; when finished it will contain the Unicode scalar + * value decoded. Return value is 1 if finished, 0 if in-progress, and + * -1 if an invalid sequence was encountered. After an invalid sequence, + * the state (in c) automatically resets to 0 if a continuation byte was + * expected to facilitate a calling idiom of immediately retrying a + * failed decode call after processing the invalid sequence. If the + * second try fails, the byte is invalid as a starter as well. + * + * A trivial usage idiom is: + *       while (src<end && (n=decode(dst, *src))>=0) 1[dst+=n]=0, src++; + */ + +int decode(unsigned *c, unsigned b) +{ +	if (!*c) { +		if (b < 0x80) { +			*c = b; +			return 1; +		} else if (b-SA >= SB-SA) { +			*c = FAILSTATE; +			return -1; +		} +		*c = bittab[b-SA]; +		return 0; +	} + +	if (OOB(*c,b)) { +		*c = 0; +		return -1; +	} +	*c = *c<<6 | b-0x80; +	return !(*c&(1U<<31)); +} diff --git a/src/multibyte/internal.c b/src/multibyte/internal.c new file mode 100644 index 00000000..e9b938dd --- /dev/null +++ b/src/multibyte/internal.c @@ -0,0 +1,60 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <inttypes.h> + +#include "internal.h" + +#define C(x) ( x<2 ? -1 : ( R(0x80,0xc0) | x ) ) +#define D(x) C((x+16)) +#define E(x) ( ( x==0 ? R(0xa0,0xc0) : \ +                 x==0xd ? R(0x80,0xa0) : \ +                 R(0x80,0xc0) ) \ +             | ( R(0x80,0xc0) >> 6 ) \ +             | x ) +#ifdef I_FAILED_TO_RTFM_RFC3629 +#define F0(x) (( x==0 ? R(0x90,0xc0) : \ +                 R(0x80,0xc0) ) \ +             | ( R(0x80,0xc0) >> 6 ) \ +             | ( R(0x80,0xc0) >> 12 ) \ +             | x ) +#define F8(x) (( x==0 ? R(0xa0,0xc0) : \ +                 R(0x80,0xc0) ) \ +             | ( R(0x80,0xc0) >> 6 ) \ +             | ( R(0x80,0xc0) >> 12 ) \ +             | ( R(0x80,0xc0) >> 18 ) \ +             | x ) +#define FC(x) (( x==0 ? R(0x88,0xc0) : \ +                 R(0x80,0xc0) ) \ +             | ( R(0x80,0xc0) >> 6 ) \ +             | ( R(0x80,0xc0) >> 12 ) \ +             | ( R(0x80,0xc0) >> 18 ) \ +             | ( R(0x80,0xc0) >> 24 ) \ +             | x ) +#define F(x) ( x<8 ? F0(x) : x<12 ? F8((x&3)) : x<14 ? FC((x&1)) : -1 ) +#else +#define F(x) ( ( x>=5 ? 0 : \ +                 x==0 ? R(0x90,0xc0) : \ +                 x==4 ? R(0x80,0xa0) : \ +                 R(0x80,0xc0) ) \ +             | ( R(0x80,0xc0) >> 6 ) \ +             | ( R(0x80,0xc0) >> 12 ) \ +             | x ) +#endif + +const uint32_t bittab[] = { +	              C(0x2),C(0x3),C(0x4),C(0x5),C(0x6),C(0x7), +	C(0x8),C(0x9),C(0xa),C(0xb),C(0xc),C(0xd),C(0xe),C(0xf), +	D(0x0),D(0x1),D(0x2),D(0x3),D(0x4),D(0x5),D(0x6),D(0x7), +	D(0x8),D(0x9),D(0xa),D(0xb),D(0xc),D(0xd),D(0xe),D(0xf), +	E(0x0),E(0x1),E(0x2),E(0x3),E(0x4),E(0x5),E(0x6),E(0x7), +	E(0x8),E(0x9),E(0xa),E(0xb),E(0xc),E(0xd),E(0xe),E(0xf), +	F(0x0),F(0x1),F(0x2),F(0x3),F(0x4), +#ifdef I_FAILED_TO_RTFM_RFC3629 +	                                   F(0x5),F(0x6),F(0x7), +	F(0x8),F(0x9),F(0xa),F(0xb),F(0xc),F(0xd) +#endif +}; diff --git a/src/multibyte/internal.h b/src/multibyte/internal.h new file mode 100644 index 00000000..427519a2 --- /dev/null +++ b/src/multibyte/internal.h @@ -0,0 +1,61 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#define LIBC +#ifndef LIBC +/* rename functions not to conflict with libc */ +#ifndef myprefix +#define myprefix fsmu8_ +#endif +#define concat2(a,b) a ## b +#define concat(a,b) concat2(a,b) +#define prefix(b) concat(myprefix,b) + +#undef mblen +#undef mbrlen +#undef mbrtowc +#undef mbsinit +#undef mbsnrtowcs +#undef mbsrtowcs +#undef wcrtomb +#undef wcsrtombs +#undef wcstombs +#undef wctomb +#define mblen prefix(mblen) +#define mbrlen prefix(mbrlen) +#define mbrtowc prefix(mbrtowc) +#define mbsinit prefix(mbsinit) +#define mbsnrtowcs prefix(mbsnrtowcs) +#define mbsrtowcs prefix(mbsrtowcs) +#define mbstowcs prefix(mbstowcs) +#define wcrtomb prefix(wcrtomb) +#define wcsnrtombs prefix(wcsnrtombs) +#define wcsrtombs prefix(wcsrtombs) +#define wcstombs prefix(wcstombs) +#define wctomb prefix(wctomb) + +#define bittab prefix(bittab) +#else +#define bittab __fsmu8 +#endif + +extern const uint32_t bittab[]; + +/* Upper 6 state bits are a negative integer offset to bound-check next byte */ +/*    equivalent to: ( (b-0x80) | (b+offset) ) & ~0x3f      */ +#define OOB(c,b) (((((b)>>3)-0x10)|(((b)>>3)+((int32_t)(c)>>26))) & ~7) + +/* Interval [a,b). Either a must be 80 or b must be c0, lower 3 bits clear. */ +#define R(a,b) ((uint32_t)((a==0x80 ? 0x40-b : -a) << 23)) +#define FAILSTATE R(0x80,0x80) + +#ifdef I_FAILED_TO_RTFM_RFC3629 +#define SA 0xc2 +#define SB 0xfe +#else +#define SA 0xc2 +#define SB 0xf5 +#endif diff --git a/src/multibyte/mblen.c b/src/multibyte/mblen.c new file mode 100644 index 00000000..26d35649 --- /dev/null +++ b/src/multibyte/mblen.c @@ -0,0 +1,17 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> + +#include "internal.h" + +int mblen(const char *s, size_t n) +{ +	return mbtowc(0, s, n); +} diff --git a/src/multibyte/mbrlen.c b/src/multibyte/mbrlen.c new file mode 100644 index 00000000..c9a9f033 --- /dev/null +++ b/src/multibyte/mbrlen.c @@ -0,0 +1,18 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> + +#include "internal.h" + +size_t mbrlen(const char *s, size_t n, mbstate_t *st) +{ +	static unsigned internal; +	return mbrtowc(0, s, n, st ? st : (mbstate_t *)&internal); +} diff --git a/src/multibyte/mbrtowc.c b/src/multibyte/mbrtowc.c new file mode 100644 index 00000000..09badebe --- /dev/null +++ b/src/multibyte/mbrtowc.c @@ -0,0 +1,58 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> + +#include "internal.h" + +size_t mbrtowc(wchar_t *wc, const char *src, size_t n, mbstate_t *st) +{ +	static unsigned internal_state; +	unsigned c; +	const unsigned char *s = src; +	const unsigned N = n; + +	if (!st) st = (void *)&internal_state; +	c = *(unsigned *)st; +	 +	if (!s) { +		s = ""; +		wc = (void *)&wc; +		n = 1; +	} else if (!wc) wc = (void *)&wc; + +	if (!n) return -2; +	if (!c) { +		if ((unsigned)*s < 0x80) return !!(*wc = *s); +		if ((unsigned)*s-SA > SB-SA) goto ilseq; +		c = bittab[*s++-SA]; n--; +	} + +	if (n) { +		if (OOB(c,*s)) goto ilseq; +loop: +		c = c<<6 | *s++-0x80; n--; +		if (!(c&(1U<<31))) { +			*(unsigned *)st = 0; +			*wc = c; +			return N-n; +		} +		if (n) { +			if ((unsigned)*s-0x80 >= 0x40) goto ilseq; +			goto loop; +		} +	} + +	*(unsigned *)st = c; +	return -2; +ilseq: +	*(unsigned *)st = FAILSTATE; +	errno = EILSEQ; +	return -1; +} diff --git a/src/multibyte/mbsinit.c b/src/multibyte/mbsinit.c new file mode 100644 index 00000000..d307e5a7 --- /dev/null +++ b/src/multibyte/mbsinit.c @@ -0,0 +1,17 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> + +#include "internal.h" + +int mbsinit(const mbstate_t *st) +{ +	return !*(unsigned *)st; +} diff --git a/src/multibyte/mbsnrtowcs.c b/src/multibyte/mbsnrtowcs.c new file mode 100644 index 00000000..c6f0207f --- /dev/null +++ b/src/multibyte/mbsnrtowcs.c @@ -0,0 +1,61 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> +#include <stdio.h> + +#include "internal.h" + +size_t mbsnrtowcs(wchar_t *wcs, const char **src, size_t n, size_t wn, mbstate_t *st) +{ +	size_t l, cnt=0, n2; +	wchar_t *ws, wbuf[256]; +	const char *s = *src; + +	if (!wcs) ws = wbuf, wn = sizeof wbuf / sizeof *wbuf; +	else ws = wcs; + +	/* making sure output buffer size is at most n/4 will ensure +	 * that mbsrtowcs never reads more than n input bytes. thus +	 * we can use mbsrtowcs as long as it's practical.. */ + +	while ( s && wn && ( (n2=n/4)>=wn || n2>32 ) ) { +		if (n2>=wn) n2=wn; +		n -= n2; +		l = mbsrtowcs(ws, &s, n2, st); +		if (!(l+1)) { +			cnt = l; +			wn = 0; +			break; +		} +		if (ws != wbuf) { +			ws += l; +			wn -= l; +		} +		cnt += l; +	} +	if (s) while (wn && n) { +		l = mbrtowc(ws, s, n, st); +		if (l+2<=2) { +			if (!(l+1)) { +				cnt = l; +				break; +			} +			/* have to roll back partial character */ +			*(unsigned *)st = 0; +			break; +		} +		s += l; n -= l; +		/* safe - this loop runs fewer than sizeof(wbuf)/8 times */ +		ws++; wn--; +		cnt++; +	} +	if (wcs) *src = s; +	return cnt; +} diff --git a/src/multibyte/mbsrtowcs.c b/src/multibyte/mbsrtowcs.c new file mode 100644 index 00000000..e2b43480 --- /dev/null +++ b/src/multibyte/mbsrtowcs.c @@ -0,0 +1,121 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> + +#include "internal.h" + +size_t mbsrtowcs(wchar_t *ws, const char **src, size_t wn, mbstate_t *st) +{ +	unsigned c; +	const unsigned char *s = *src; +	const wchar_t *wsorig = ws; + +	if (!st) st = (void *)&c, c = 0; +	else c = *(unsigned *)st; + +	if (c) { +		*(unsigned *)st = 0; +		if (!ws) { +			wn = 0; +			goto resume0; +		} +		goto resume; +	} + +	if (!ws) for (wn=0;;) { +		if ((unsigned)*s-SA >= SB-SA) { +			while (((unsigned)s&3) && (unsigned)*s-1<0x7f) s++, wn++; +			while (!(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) s+=4, wn+=4; +			while ((unsigned)*s-1<0x7f) s++, wn++; +			if (!*s) return wn; +			if ((unsigned)*s-SA >= SB-SA) goto ilseq2; +		} +		c = bittab[*s++-SA]; +		do { +resume0: +			if (OOB(c,*s)) goto ilseq2; s++; +			c <<= 6; if (!(c&(1U<<31))) break; +#ifdef I_FAILED_TO_RTFM_RFC3629 +			if ((unsigned)*s++-0x80 >= 0x40) goto ilseq2; +			c <<= 6; if (!(c&(1U<<31))) break; +			if ((unsigned)*s++-0x80 >= 0x40) goto ilseq2; +			c <<= 6; if (!(c&(1U<<31))) break; +#endif +			if ((unsigned)*s++-0x80 >= 0x40) goto ilseq2; +			c <<= 6; if (!(c&(1U<<31))) break; +			if ((unsigned)*s++-0x80 >= 0x40) goto ilseq2; +		} while (0); +		wn++; c = 0; +	} + +	while (wn) { +		if ((unsigned)*s-SA >= SB-SA) { +			if (wn >= 7) { +				while (((unsigned)s&3) && (unsigned)*s-1<0x7f) { +					*ws++ = *s++; +					wn--; +				} +				while (wn>=4 && !(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) { +					*ws++ = *s++; +					*ws++ = *s++; +					*ws++ = *s++; +					*ws++ = *s++; +					wn -= 4; +				} +			} +			while (wn && (unsigned)*s-1<0x7f) { +				*ws++ = *s++; +				wn--; +			} +			if (!wn) break; +			if (!*s) { +				*ws = 0; +				*src = 0; +				return ws-wsorig; +			} +			if ((unsigned)*s-SA >= SB-SA) goto ilseq; +		} +		c = bittab[*s++-SA]; +		do { +resume: +			if (OOB(c,*s)) goto ilseq; +			c = (c<<6) | *s++-0x80; +			if (!(c&(1U<<31))) break; + +#ifdef I_FAILED_TO_RTFM_RFC3629 +			if ((unsigned)*s-0x80 >= 0x40) goto ilseq; +			c = (c<<6) | *s++-0x80; +			if (!(c&(1U<<31))) break; + +			if ((unsigned)*s-0x80 >= 0x40) goto ilseq; +			c = (c<<6) | *s++-0x80; +			if (!(c&(1U<<31))) break; +#endif + +			if ((unsigned)*s-0x80 >= 0x40) goto ilseq; +			c = (c<<6) | *s++-0x80; +			if (!(c&(1U<<31))) break; + +			if ((unsigned)*s-0x80 >= 0x40) goto ilseq; +			c = (c<<6) | *s++-0x80; +		} while (0); + +		*ws++ = c; wn--; c = 0; +	} +	*src = s; +	return ws-wsorig; +ilseq: +	*src = s; +ilseq2: +	/* enter permanently failing state */ +	*(unsigned *)st = FAILSTATE; +	errno = EILSEQ; +	return -1; +} diff --git a/src/multibyte/mbstowcs.c b/src/multibyte/mbstowcs.c new file mode 100644 index 00000000..23e1d925 --- /dev/null +++ b/src/multibyte/mbstowcs.c @@ -0,0 +1,18 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> + +#include "internal.h" + +size_t mbstowcs(wchar_t *ws, const char *s, size_t wn) +{ +	mbstate_t st = { 0 }; +	return mbsrtowcs(ws, (void*)&s, wn, &st); +} diff --git a/src/multibyte/mbtowc.c b/src/multibyte/mbtowc.c new file mode 100644 index 00000000..bdcaeb3c --- /dev/null +++ b/src/multibyte/mbtowc.c @@ -0,0 +1,19 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> + +#include "internal.h" + +int mbtowc(wchar_t *wc, const char *s, size_t n) +{ +	mbstate_t st = { 0 }; +	n = mbrtowc(wc, s, n, &st); +	return n+2 ? n : -1; +} diff --git a/src/multibyte/wcrtomb.c b/src/multibyte/wcrtomb.c new file mode 100644 index 00000000..36180c8f --- /dev/null +++ b/src/multibyte/wcrtomb.c @@ -0,0 +1,38 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> + +#include "internal.h" + +size_t wcrtomb(char *s, wchar_t wc, mbstate_t *st) +{ +	if (!s) return 1; +	if ((unsigned)wc < 0x80) { +		*s = wc; +		return 1; +	} else if ((unsigned)wc < 0x800) { +		*s++ = 0xc0 | (wc>>6); +		*s = 0x80 | (wc&0x3f); +		return 2; +	} else if ((unsigned)wc < 0xd800 || (unsigned)wc-0xe000 < 0x2000) { +		*s++ = 0xe0 | (wc>>12); +		*s++ = 0x80 | ((wc>>6)&0x3f); +		*s = 0x80 | (wc&0x3f); +		return 3; +	} else if ((unsigned)wc-0x10000 < 0x100000) { +		*s++ = 0xf0 | (wc>>18); +		*s++ = 0x80 | ((wc>>12)&0x3f); +		*s++ = 0x80 | ((wc>>6)&0x3f); +		*s = 0x80 | (wc&0x3f); +		return 4; +	} +	errno = EILSEQ; +	return -1; +} diff --git a/src/multibyte/wcsnrtombs.c b/src/multibyte/wcsnrtombs.c new file mode 100644 index 00000000..666f6f3f --- /dev/null +++ b/src/multibyte/wcsnrtombs.c @@ -0,0 +1,51 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> + +#include "internal.h" + +size_t wcsnrtombs(char *dst, const wchar_t **wcs, size_t wn, size_t n, mbstate_t *st) +{ +	size_t l, cnt=0, n2; +	char *s, buf[256]; +	const wchar_t *ws = *wcs; + +	if (!dst) s = buf, n = sizeof buf; +	else s = dst; + +	while ( n && ( (n2=wn)>=n || n2>32 ) ) { +		if (n2>=n) n2=n; +		wn -= n2; +		l = wcsrtombs(s, &ws, n2, 0); +		if (!(l+1)) { +			cnt = l; +			n = 0; +			break; +		} +		if (s != buf) { +			s += l; +			n -= l; +		} +		cnt += l; +	} +	while (n && wn) { +		l = wcrtomb(s, *ws, 0); +		if (!(l+1)) { +			cnt = l; +			break; +		} +		ws++; wn--; +		/* safe - this loop runs fewer than sizeof(buf) times */ +		s+=l; n-=l; +		cnt++; +	} +	if (dst) *wcs = ws; +	return cnt; +} diff --git a/src/multibyte/wcsrtombs.c b/src/multibyte/wcsrtombs.c new file mode 100644 index 00000000..3c48d65b --- /dev/null +++ b/src/multibyte/wcsrtombs.c @@ -0,0 +1,58 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> + +#include "internal.h" + +size_t wcsrtombs(char *s, const wchar_t **ws, size_t n, mbstate_t *st) +{ +	const wchar_t *ws2; +	char buf[4]; +	size_t N = n, l; +	if (!s) { +		for (n=0, ws2=*ws; *ws2; ws2++) { +			if (*ws2 >= 0x80) { +				l = wcrtomb(buf, *ws2, 0); +				if (!(l+1)) return -1; +				n += l; +			} else n++; +		} +		return n; +	} +	while (n>=4 && **ws) { +		if (**ws >= 0x80) { +			l = wcrtomb(s, **ws, 0); +			if (!(l+1)) return -1; +			s += l; +			n -= l; +		} else { +			*s++ = **ws; +			n--; +		} +		(*ws)++; +	} +	while (n && **ws) { +		if (**ws >= 0x80) { +			l = wcrtomb(buf, **ws, 0); +			if (!(l+1)) return -1; +			if (l>n) return N-n; +			wcrtomb(s, **ws, 0); +			s += l; +			n -= l; +		} else { +			*s++ = **ws; +			n--; +		} +		(*ws)++; +	} +	if (n) *s = 0; +	*ws = 0; +	return N-n; +} diff --git a/src/multibyte/wcstombs.c b/src/multibyte/wcstombs.c new file mode 100644 index 00000000..b9c1b18a --- /dev/null +++ b/src/multibyte/wcstombs.c @@ -0,0 +1,17 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> + +#include "internal.h" + +size_t wcstombs(char *s, const wchar_t *ws, size_t n) +{ +	return wcsrtombs(s, &ws, n, 0); +} diff --git a/src/multibyte/wctob.c b/src/multibyte/wctob.c new file mode 100644 index 00000000..d6353ee1 --- /dev/null +++ b/src/multibyte/wctob.c @@ -0,0 +1,8 @@ +#include <stdio.h> +#include <wchar.h> + +int wctob(wint_t c) +{ +	if (c < 128U) return c; +	return EOF; +} diff --git a/src/multibyte/wctomb.c b/src/multibyte/wctomb.c new file mode 100644 index 00000000..6910ef37 --- /dev/null +++ b/src/multibyte/wctomb.c @@ -0,0 +1,18 @@ +/*  + * This code was written by Rich Felker in 2010; no copyright is claimed. + * This code is in the public domain. Attribution is appreciated but + * unnecessary. + */ + +#include <stdlib.h> +#include <inttypes.h> +#include <wchar.h> +#include <errno.h> + +#include "internal.h" + +int wctomb(char *s, wchar_t wc) +{ +	if (!s) return 0; +	return wcrtomb(s, wc, 0); +} diff --git a/src/network/__dns.c b/src/network/__dns.c new file mode 100644 index 00000000..73ec422d --- /dev/null +++ b/src/network/__dns.c @@ -0,0 +1,267 @@ +#include <stdint.h> +#include <netdb.h> +#include <stdio.h> +#include <fcntl.h> +#include <limits.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <time.h> +#include <ctype.h> +#include <unistd.h> +#include "__dns.h" +#include "stdio_impl.h" + +#define TIMEOUT 5 +#define RETRY 1 +#define PACKET_MAX 512 +#define PTR_MAX (64 + sizeof ".in-addr.arpa") + +int __dns_doqueries(unsigned char *dest, const char *name, int *rr, int rrcnt) +{ +	time_t t0 = time(0); +	int fd; +	FILE *f, _f; +	unsigned char _buf[64]; +	char line[64], *s, *z; +	union { +		struct sockaddr_in sin; +		struct sockaddr_in6 sin6; +	} sa = {0}, ns[3] = {{0}}; +	socklen_t sl; +	int nns; +	int family; +	unsigned char q[280] = "", *r = dest; +	int ql; +	int rlen; +	int got = 0, failed = 0; +	int errcode = EAI_AGAIN; +	int i, j; +	struct timeval tv; +	fd_set fds; +	int id; + +	/* Construct query template - RR and ID will be filled later */ +	if (strlen(name)-1 >= 254U) return -1; +	q[2] = q[5] = 1; +	strcpy(q+13, name); +	for (i=13; q[i]; i=j+1) { +		for (j=i; q[j] && q[j] != '.'; j++); +		if (j-i-1u > 62u) return -1; +		q[i-1] = j-i; +	} +	q[i+3] = 1; +	ql = i+4; + +	/* Make a reasonably unpredictable id */ +	gettimeofday(&tv, 0); +	id = tv.tv_usec + tv.tv_usec/256 & 0xffff; + +	/* Get nameservers from resolv.conf, fallback to localhost */ +	f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf); +	if (f) for (nns=0; nns<3 && fgets(line, sizeof line, f); ) { +		if (strncmp(line, "nameserver", 10) || !isspace(line[10])) +			continue; +		for (s=line+11; isspace(*s); s++); +		for (z=s; *z && !isspace(*z); z++); +		*z=0; +		if (__ipparse(ns+nns, family, s) < 0) continue; +		ns[nns].sin.sin_port = htons(53); +		family = ns[nns++].sin.sin_family; +		sl = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin; +	} +	if (f) __fclose_ca(f); +	if (!nns) { +		ns[0].sin.sin_family = AF_INET; +		ns[0].sin.sin_port = htons(53); +		nns=1; +		sl = sizeof sa.sin; +	} + +	/* Get local address and open/bind a socket */ +	sa.sin.sin_family = family; +	fd = socket(family, SOCK_DGRAM, 0); +	if (bind(fd, (void *)&sa, sl) < 0) { +		close(fd); +		return -1; +	} +	/* Nonblocking to work around Linux UDP select bug */ +	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); + +	/* Loop until we timeout; break early on success */ +	for (; time(0)-t0 < TIMEOUT; ) { + +		/* Query all configured namservers in parallel */ +		for (i=0; i<rrcnt; i++) if (rr[i]) for (j=0; j<nns; j++) { +			q[0] = id+i >> 8; +			q[1] = id+i; +			q[ql-3] = rr[i]; +			sendto(fd, q, ql, MSG_NOSIGNAL, (void *)&ns[j], sl); +		} + +		/* Wait for a response, or until time to retry */ +		FD_ZERO(&fds); +		FD_SET(fd, &fds); +		tv.tv_sec = RETRY; +		tv.tv_usec = 0; +		if (select(fd+1, &fds, 0, 0, &tv) <= 0) continue; + +		/* Process any and all replies */ +		while (got+failed < rrcnt && (rlen = recvfrom(fd, r, 512, 0, +			(void *)&sa, (socklen_t[1]){sl})) >= 2) +		{ +			/* Ignore replies from addresses we didn't send to */ +			for (i=0; i<nns; i++) if (!memcmp(ns+i, &sa, sl)) break; +			if (i==nns) continue; + +			/* Compute index of the query from id */ +			i = r[0]*256+r[1] - id & 0xffff; +			if ((unsigned)i >= rrcnt || !rr[i]) continue; + +			/* Interpret the result code */ +			switch (r[3] & 15) { +			case 0: +				got++; +				break; +			case 3: +				if (1) errcode = EAI_NONAME; else +			default: +				errcode = EAI_FAIL; +				failed++; +			} + +			/* Mark this record as answered */ +			rr[i] = 0; +			r += 512; +		} + +		/* Check to see if we have answers to all queries */ +		if (got+failed == rrcnt) break; +	} +	close(fd); + +	/* Return the number of results, or an error code if none */ +	if (got) return got; +	return errcode; +} + +static void mkptr4(char *s, const unsigned char *ip) +{ +	sprintf(s, "%d.%d.%d.%d.in-addr.arpa", +		ip[3], ip[2], ip[1], ip[0]); +} + +static void mkptr6(char *s, const unsigned char *ip) +{ +	static const char xdigits[] = "0123456789abcdef"; +	int i; +	for (i=15; i>=0; i--) { +		*s++ = xdigits[ip[i]&15]; *s++ = '.'; +		*s++ = xdigits[ip[i]>>4]; *s++ = '.'; +	} +	strcpy(s, "ip6.arpa"); +} + +int __dns_query(unsigned char *r, const void *a, int family, int ptr) +{ +	char buf[PTR_MAX]; +	int rr[2], rrcnt = 1; + +	if (ptr) { +		if (family == AF_INET6) mkptr6(buf, a); +		else mkptr4(buf, a); +		rr[0] = RR_PTR; +		a = buf; +	} else if (family == AF_INET6) { +		rr[0] = RR_AAAA; +	} else { +		rr[0] = RR_A; +		if (family != AF_INET) rr[rrcnt++] = RR_AAAA; +	} + +	return __dns_doqueries(r, a, rr, rrcnt); +} + + +#define BITOP(a,b,op) \ + ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a)))) + +static int decname(char *s, const unsigned char *b, const unsigned char *p) +{ +	/* Remember jump destinations to detect loops and abort */ +	size_t seen[PACKET_MAX/8/sizeof(size_t)] = { 0 }; +	char *sz = s + HOST_NAME_MAX; +	const unsigned char *pz = b+512; +	for (;;) { +		if (p>=pz) return -1; +		else if (*p&0xc0) { +			int j = (p[0]&1) | p[1]; +			if (BITOP(seen, j, &)) return -1; +			BITOP(seen, j, |=); +			p = b + j; +		} else if (*p) { +			if (p+*p+1>=pz || s+*p>=sz) return -1; +			memcpy(s, p+1, *p); +			s += *p+1; +			p += *p+1; +			s[-1] = *p ? '.' : 0; +		} else return 0; +	} +} + +int __dns_get_rr(void *dest, size_t stride, size_t maxlen, size_t limit, const unsigned char *r, int rr, int dec) +{ +	int qdcount, ancount; +	const unsigned char *p; +	char tmp[256]; +	int found = 0; +	int len; + +	if ((r[3]&15)) return 0; +	p = r+12; +	qdcount = r[4]*256 + r[5]; +	ancount = r[6]*256 + r[7]; +	if (qdcount+ancount > 64) return -1; +	while (qdcount--) { +		while (p-r < 512 && *p-1U < 127) p++; +		if (*p>193 || (*p==193 && p[1]>254) || p>r+506) +			return -1; +		p += 5 + !!*p; +	} +	while (ancount--) { +		while (p-r < 512 && *p-1U < 127) p++; +		if (*p>193 || (*p==193 && p[1]>254) || p>r+506) +			return -1; +		p += 1 + !!*p; +		len = p[8]*256 + p[9]; +		if (p+len > r+512) return -1; +		if (p[1]==rr && len <= maxlen) { +			if (dec && decname(tmp, r, p+10)<0) return -1; +			if (dest && limit) { +				if (dec) strcpy(dest, tmp); +				else memcpy(dest, p+10, len); +				dest = (char *)dest + stride; +				limit--; +			} +			found++; +		} +		p += 10 + len; +	} +	return found; +} + +int __dns_count_addrs(const unsigned char *r, int cnt) +{ +	int found=0, res, i; +	static const int p[2][2] = { { 4, RR_A }, { 16, RR_AAAA } }; + +	while (cnt--) for (i=0; i<2; i++) { +		res = __dns_get_rr(0, 0, p[i][0], -1, r, p[i][1], 0); +		if (res < 0) return res; +		found += res; +		r += 512; +	} +	return found; +} diff --git a/src/network/__dns.h b/src/network/__dns.h new file mode 100644 index 00000000..9a3f7402 --- /dev/null +++ b/src/network/__dns.h @@ -0,0 +1,14 @@ +#include <stddef.h> + +#define RR_A 1 +#define RR_CNAME 5 +#define RR_PTR 12 +#define RR_AAAA 28 + +int __dns_count_addrs(const unsigned char *, int); +int __dns_get_rr(void *, size_t, size_t, size_t, const unsigned char *, int, int); + +int __dns_query(unsigned char *, const void *, int, int); +int __ipparse(void *, int, const char *); + +int __dns_doqueries(unsigned char *, const char *, int *, int); diff --git a/src/network/__ipparse.c b/src/network/__ipparse.c new file mode 100644 index 00000000..ca9e5890 --- /dev/null +++ b/src/network/__ipparse.c @@ -0,0 +1,40 @@ +#include <string.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include "__dns.h" +#include <stdio.h> + +int __ipparse(void *dest, int family, const char *s) +{ +	unsigned char *d = dest; +	unsigned long a[16] = { 0 }; +	const char *z; +	int i; + +	if (family == AF_INET6) goto not_v4; + +	for (i=0; i<4 && *s; i++) { +		a[i] = strtoul(s, (char **)&z, 0); +		if (z==s || (*z && *z != '.')) goto not_v4; +		s=z+1; +	} +	switch (i) { +	case 0: +		a[1] = a[0] & 0xffffff; +		a[0] >>= 24; +	case 1: +		a[2] = a[1] & 0xffff; +		a[1] >>= 16; +	case 2: +		a[3] = a[2] & 0xff; +		a[2] >>= 8; +	} +	((struct sockaddr_in *)d)->sin_family = AF_INET; +	d = (void *)&((struct sockaddr_in *)d)->sin_addr; +	for (i=0; i<4; i++) d[i] = a[i]; +	return 0; + +not_v4: +	return -1; +} diff --git a/src/network/accept.c b/src/network/accept.c new file mode 100644 index 00000000..83704096 --- /dev/null +++ b/src/network/accept.c @@ -0,0 +1,14 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" +#include "libc.h" + +int accept(int fd, struct sockaddr *addr, socklen_t *len) +{ +	unsigned long args[] = { fd, (unsigned long)addr, (unsigned long)len }; +	int ret; +	CANCELPT_BEGIN; +	ret = syscall2(__NR_socketcall, SYS_ACCEPT, (long)args); +	CANCELPT_END; +	return ret; +} diff --git a/src/network/bind.c b/src/network/bind.c new file mode 100644 index 00000000..3bef382c --- /dev/null +++ b/src/network/bind.c @@ -0,0 +1,9 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" + +int bind(int fd, const struct sockaddr *addr, socklen_t len) +{ +	unsigned long args[] = { fd, (unsigned long)addr, len }; +	return syscall2(__NR_socketcall, SYS_BIND, (long)args); +} diff --git a/src/network/connect.c b/src/network/connect.c new file mode 100644 index 00000000..6074122e --- /dev/null +++ b/src/network/connect.c @@ -0,0 +1,14 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" +#include "libc.h" + +int connect(int fd, const struct sockaddr *addr, socklen_t len) +{ +	unsigned long args[] = { fd, (unsigned long)addr, len }; +	int ret; +	CANCELPT_BEGIN; +	ret = syscall2(__NR_socketcall, SYS_CONNECT, (long)args); +	CANCELPT_END; +	return ret; +} diff --git a/src/network/dn_expand.c b/src/network/dn_expand.c new file mode 100644 index 00000000..01b449bb --- /dev/null +++ b/src/network/dn_expand.c @@ -0,0 +1,28 @@ +#include <resolv.h> +#include <string.h> + +#define BITOP(a,b,op) \ + ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a)))) + +int dn_expand(unsigned char *b, unsigned char *pz, unsigned char *p, unsigned char *s, int outlen) +{ +	/* Remember jump destinations to detect loops and abort */ +	size_t seen[512/8/sizeof(size_t)] = { 0 }; +	unsigned char *sz = s + outlen; +	if (pz-b > 512) return -1; +	for (;;) { +		if (p>=pz) return -1; +		else if (*p&0xc0) { +			int j = (p[0]&1) | p[1]; +			if (BITOP(seen, j, &)) return -1; +			BITOP(seen, j, |=); +			p = b + j; +		} else if (*p) { +			if (p+*p+1>=pz || s+*p>=sz) return -1; +			memcpy(s, p+1, *p); +			s += *p+1; +			p += *p+1; +			s[-1] = *p ? '.' : 0; +		} else return 0; +	} +} diff --git a/src/network/ent.c b/src/network/ent.c new file mode 100644 index 00000000..4c2f24b5 --- /dev/null +++ b/src/network/ent.c @@ -0,0 +1,26 @@ +#include "libc.h" + +void sethostent(int x) +{ +} + +void *gethostent() +{ +	return 0; +} + +void endhostent(void) +{ +} + +weak_alias(sethostent, setnetent); +weak_alias(gethostent, getnetent); +weak_alias(endhostent, endnetent); + +weak_alias(sethostent, setservent); +weak_alias(gethostent, getservent); +weak_alias(endhostent, endservent); + +weak_alias(sethostent, setprotoent); +weak_alias(gethostent, getprotoent); +weak_alias(endhostent, endprotoent); diff --git a/src/network/freeaddrinfo.c b/src/network/freeaddrinfo.c new file mode 100644 index 00000000..df3798ae --- /dev/null +++ b/src/network/freeaddrinfo.c @@ -0,0 +1,7 @@ +#include <stdlib.h> +#include <netdb.h> + +void freeaddrinfo(struct addrinfo *p) +{ +	free(p); +} diff --git a/src/network/gai_strerror.c b/src/network/gai_strerror.c new file mode 100644 index 00000000..ea00bed7 --- /dev/null +++ b/src/network/gai_strerror.c @@ -0,0 +1,21 @@ +#include <netdb.h> + +static const char msgs[] = +	"Invalid flags\0" +	"Name does not resolve\0" +	"Try again\0" +	"Non-recoverable error\0" +	"Unrecognized address family or invalid length\0" +	"Unrecognized socket type\0" +	"Unrecognized service\0" +	"Out of memory\0" +	"System error\0" +	"Overflow\0" +	"\0Unknown error"; + +const char *gai_strerror(int ecode) +{ +	const char *s; +	for (s=msgs, ecode++; ecode && *s; ecode++, s++) for (; *s; s++); +	return *s ? s : s+1; +} diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c new file mode 100644 index 00000000..90e85f6a --- /dev/null +++ b/src/network/getaddrinfo.c @@ -0,0 +1,224 @@ +#include <stdlib.h> +#include <stdio.h> +#include <netdb.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include "__dns.h" +#include "stdio_impl.h" + +static int is_valid(const char *host) +{ +	const unsigned char *s; +	if (strlen(host)-1 > 254 || mbstowcs(0, host, 0) > 255) return 0; +	for (s=host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++); +	return !*s; +} + +#if 0 +static int have_af(int family) +{ +	struct sockaddr_in6 sin6 = { .sin6_family = family }; +	socklen_t sl = family == AF_INET +		? sizeof(struct sockaddr_in) +		: sizeof(struct sockaddr_in6); +	int sock = socket(family, SOCK_STREAM, 0); +	int have = !bind(sock, (void *)&sin6, sl); +	close(sock); +	return have; +} +#endif + +#include <stdlib.h> +#include <netdb.h> + +union sa { +	struct sockaddr_in sin; +	struct sockaddr_in6 sin6; +}; + +struct aibuf { +	struct addrinfo ai; +	union sa sa; +}; + +/* Extra slots needed for storing canonical name */ +#define EXTRA ((256+sizeof(struct aibuf)-1)/sizeof(struct aibuf)) + +int getaddrinfo(const char *host, const char *serv, const struct addrinfo *hint, struct addrinfo **res) +{ +	int flags = hint ? hint->ai_flags : 0; +	int family = hint ? hint->ai_family : AF_UNSPEC; +	int type = hint ? hint->ai_socktype : 0; +	int proto = hint ? hint->ai_protocol : 0; +	unsigned long port = 0; +	struct aibuf *buf; +	union sa sa = {{0}}; +	unsigned char reply[1024]; +	int i, j; +	//char hostbuf[256]; +	char line[512]; +	FILE *f, _f; +	unsigned char _buf[64]; +	char *z; +	int result; +	int cnt; + +	if (host && strlen(host)>255) return EAI_NONAME; +	if (serv && strlen(serv)>32) return EAI_SERVICE; + +	if (type && !proto) +		proto = type==SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; +	if (!type && proto) +		type = proto==IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; + +	if (serv) { +		port = strtoul(serv, &z, 0); +		if (!*z && port > 65535) return EAI_SERVICE; +		if (!port) { +			if (flags & AI_NUMERICSERV) return EAI_SERVICE; + +			//f = fopen("/etc/services", "rb"); +			return EAI_SERVICE; +		} +		port = htons(port); +	} + +	if (!host) { +		if (family == AF_UNSPEC) family = AF_INET; +		buf = calloc(sizeof *buf, 1+EXTRA); +		if (!buf) return EAI_MEMORY; +		buf->ai.ai_protocol = proto; +		buf->ai.ai_socktype = type; +		buf->ai.ai_addr = (void *)&buf->sa; +		buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin; +		buf->ai.ai_family = family; +		buf->sa.sin.sin_family = family; +		buf->sa.sin.sin_port = port; +		if (!(flags & AI_PASSIVE)) { +			if (family == AF_INET) { +				0[(uint8_t*)&buf->sa.sin.sin_addr.s_addr]=127; +				3[(uint8_t*)&buf->sa.sin.sin_addr.s_addr]=1; +			} else buf[0].sa.sin6.sin6_addr.s6_addr[15] = 1; +		} +		*res = &buf->ai; +		return 0; +	} + +	/* Try as a numeric address */ +	if (__ipparse(&sa, family, host) >= 0) { +		buf = calloc(sizeof *buf, 1+EXTRA); +		if (!buf) return EAI_MEMORY; +		family = sa.sin.sin_family; +		buf->ai.ai_protocol = proto; +		buf->ai.ai_socktype = type; +		buf->ai.ai_addr = (void *)&buf->sa; +		buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin; +		buf->ai.ai_family = family; +		buf->sa = sa; +		buf->sa.sin.sin_port = port; +		*res = &buf->ai; +		return 0; +	} + +	if (flags & AI_NUMERICHOST) return EAI_NONAME; + +	f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); +	if (f) while (fgets(line, sizeof line, f)) { +		char *p; +		size_t l = strlen(host); + +		if ((p=strchr(line, '#'))) *p++='\n', *p=0; +		for(p=line+1; (p=strstr(p, host)) && +			(!isspace(p[-1]) || !isspace(p[l])); p++); +		if (!p) continue; +		__fclose_ca(f); + +		/* Isolate IP address to parse */ +		for (p=line; *p && !isspace(*p); p++); +		*p++ = 0; +		if (__ipparse(&sa, family, line) < 0) return EAI_NONAME; + +		/* Allocate and fill result buffer */ +		buf = calloc(sizeof *buf, 1+EXTRA); +		if (!buf) return EAI_MEMORY; +		family = sa.sin.sin_family; +		buf->ai.ai_protocol = proto; +		buf->ai.ai_socktype = type; +		buf->ai.ai_addr = (void *)&buf->sa; +		buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin; +		buf->ai.ai_family = family; +		buf->sa = sa; +		buf->sa.sin.sin_port = port; + +		/* Extract first name as canonical name */ +		for (; *p && isspace(*p); p++); +		buf->ai.ai_canonname = (void *)(buf+1); +		snprintf(buf->ai.ai_canonname, 256, "%s", p); +		for (p=buf->ai.ai_canonname; *p && !isspace(*p); p++); +		*p = 0; +		if (!is_valid(buf->ai.ai_canonname)) +			buf->ai.ai_canonname = 0; + +		*res = &buf->ai; +		return 0; +	} +	if (f) __fclose_ca(f); + +#if 0 +	f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf); +	if (f) while (fgets(line, sizeof line, f)) { +		if (!isspace(line[10]) || (strncmp(line, "search", 6) +			&& strncmp(line, "domain", 6))) continue; +	} +	if (f) __fclose_ca(f); +#endif + +	/* Perform one or more DNS queries for host */ +	memset(reply, 0, sizeof reply); +	result = __dns_query(reply, host, family, 0); +	if (result < 0) return result; + +	cnt = __dns_count_addrs(reply, result); +	if (cnt <= 0) return EAI_NONAME; + +	buf = calloc(sizeof *buf, cnt+EXTRA); +	if (!buf) return EAI_MEMORY; + +	i = 0; +	if (family != AF_INET6) { +		j = __dns_get_rr(&buf[i].sa.sin.sin_addr, sizeof *buf, 4, cnt-i, reply, RR_A, 0); +		while (j--) buf[i++].sa.sin.sin_family = AF_INET; +	} +	if (family != AF_INET) { +		j = __dns_get_rr(&buf[i].sa.sin6.sin6_addr, sizeof *buf, 16, cnt-i, reply, RR_AAAA, 0); +		while (j--) buf[i++].sa.sin.sin_family = AF_INET6; +	} +	if (result>1) { +		j = __dns_get_rr(&buf[i].sa.sin.sin_addr, sizeof *buf, 4, cnt-i, reply+512, RR_A, 0); +		while (j--) buf[i++].sa.sin.sin_family = AF_INET; +		j = __dns_get_rr(&buf[i].sa.sin6.sin6_addr, sizeof *buf, 16, cnt-i, reply+512, RR_AAAA, 0); +		while (j--) buf[i++].sa.sin.sin_family = AF_INET6; +	} + +	if (__dns_get_rr((void *)&buf[cnt], 0, 256, 1, reply, RR_CNAME, 1) < 0) +		strcpy((void *)&buf[cnt], host); + +	for (i=0; i<cnt; i++) { +		buf[i].ai.ai_protocol = proto; +		buf[i].ai.ai_socktype = type; +		buf[i].ai.ai_addr = (void *)&buf[i].sa; +		buf[i].ai.ai_addrlen = buf[i].sa.sin.sin_family==AF_INET6 +			? sizeof sa.sin6 : sizeof sa.sin; +		buf[i].ai.ai_family = buf[i].sa.sin.sin_family; +		buf[i].sa.sin.sin_port = port; +		buf[i].ai.ai_next = &buf[i+1].ai; +		buf[i].ai.ai_canonname = (void *)&buf[cnt]; +	} +	buf[cnt-1].ai.ai_next = 0; +	*res = &buf->ai; + +	return 0; +} diff --git a/src/network/gethostbyaddr.c b/src/network/gethostbyaddr.c new file mode 100644 index 00000000..51e1c569 --- /dev/null +++ b/src/network/gethostbyaddr.c @@ -0,0 +1,15 @@ +#define _GNU_SOURCE + +#include <netdb.h> +#include <string.h> +#include <netinet/in.h> + +struct hostent *gethostbyaddr(const void *a, socklen_t l, int af) +{ +	static struct hostent h; +	static long buf[512/sizeof(long)]; +	struct hostent *res; +	if (gethostbyaddr_r(a, l, af, &h, +		(void *)buf, sizeof buf, &res, &h_errno)) return 0; +	return &h; +} diff --git a/src/network/gethostbyaddr_r.c b/src/network/gethostbyaddr_r.c new file mode 100644 index 00000000..cdb1d503 --- /dev/null +++ b/src/network/gethostbyaddr_r.c @@ -0,0 +1,71 @@ +#define _GNU_SOURCE + +#include <sys/socket.h> +#include <netdb.h> +#include <string.h> +#include <netinet/in.h> +#include <errno.h> +#include <inttypes.h> + +int gethostbyaddr_r(const void *a, socklen_t l, int af, +	struct hostent *h, char *buf, size_t buflen, +	struct hostent **res, int *err) +{ +	union { +		struct sockaddr_in sin; +		struct sockaddr_in6 sin6; +	} sa = { .sin.sin_family = af }; +	socklen_t sl = af==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin; +	int i; + +	/* Load address argument into sockaddr structure */ +	if (af==AF_INET6 && l==16) memcpy(&sa.sin6.sin6_addr, a, 16); +	else if (af==AF_INET && l==4) memcpy(&sa.sin.sin_addr, a, 4); +	else { +		*err = NO_RECOVERY; +		return -1; +	} + +	/* Align buffer and check for space for pointers and ip address */ +	i = (uintptr_t)buf & sizeof(char *)-1; +	if (!i) i = sizeof(char *); +	if (buflen <= 5*sizeof(char *)-i + l) { +		errno = ERANGE; +		return -1; +	} +	buf += sizeof(char *)-i; +	buflen -= 5*sizeof(char *)-i + l; + +	h->h_addr_list = (void *)buf; +	buf += 2*sizeof(char *); +	h->h_aliases = (void *)buf; +	buf += 2*sizeof(char *); + +	h->h_addr_list[0] = buf; +	memcpy(h->h_addr_list[0], a, l); +	buf += l; +	h->h_addr_list[1] = 0; +	h->h_aliases[0] = buf; +	h->h_aliases[1] = 0; + +	switch (getnameinfo((void *)&sa, sl, buf, buflen, 0, 0, 0)) { +	case EAI_AGAIN: +		*err = TRY_AGAIN; +		return -1; +	case EAI_OVERFLOW: +		errno = ERANGE; +	default: +	case EAI_MEMORY: +	case EAI_SYSTEM: +	case EAI_FAIL: +		*err = NO_RECOVERY; +		return -1; +	case 0: +		break; +	} + +	h->h_addrtype = af; +	h->h_name = h->h_aliases[0]; +	*res = h; +	return 0; +} diff --git a/src/network/gethostbyname.c b/src/network/gethostbyname.c new file mode 100644 index 00000000..5088a51e --- /dev/null +++ b/src/network/gethostbyname.c @@ -0,0 +1,63 @@ +#define _GNU_SOURCE + +#include <sys/socket.h> +#include <netdb.h> +#include <string.h> +#include <netinet/in.h> + +struct hostent *gethostbyname(const char *name) +{ +	return gethostbyname2(name, AF_INET); +} + +#if 0 +struct hostent *gethostbyname(const char *name) +{ +	static struct hostent h; +	static char *h_aliases[3]; +	static char h_canon[256]; +	static char *h_addr_list[10]; +	static char h_addr_data[10][4]; +	static const struct addrinfo hint = { +		.ai_family = AF_INET, .ai_flags = AI_CANONNAME +	}; +	struct addrinfo *ai, *p; +	int i; + +	switch (getaddrinfo(name, 0, &hint, &ai)) { +	case EAI_NONAME: +		h_errno = HOST_NOT_FOUND; +		break; +	case EAI_AGAIN: +		h_errno = TRY_AGAIN; +		break; +	case EAI_FAIL: +		h_errno = NO_RECOVERY; +		break; +	default: +	case EAI_MEMORY: +	case EAI_SYSTEM: +		h_errno = NO_DATA; +		break; +	case 0: +		break; +	} + +	strcpy(h_canon, ai->ai_canonname); +	h.h_name = h_canon; +	h.h_aliases = h_aliases; +	h.h_aliases[0] = h_canon; +	h.h_aliases[1] = strcmp(h_canon, name) ? (char *)name : 0; +	h.h_length = 4; +	h.h_addr_list = h_addr_list; +	for (i=0, p=ai; i<sizeof h_addr_data/4 && p; i++, p=p->ai_next) { +		h.h_addr_list[i] = h_addr_data[i]; +		memcpy(h.h_addr_list[i], +			&((struct sockaddr_in *)p->ai_addr)->sin_addr, 4); +	} +	h.h_addr_list[i] = 0; +	h.h_addrtype = AF_INET; +	freeaddrinfo(ai); +	return &h; +} +#endif diff --git a/src/network/gethostbyname2.c b/src/network/gethostbyname2.c new file mode 100644 index 00000000..9fbe2647 --- /dev/null +++ b/src/network/gethostbyname2.c @@ -0,0 +1,16 @@ +#define _GNU_SOURCE + +#include <sys/socket.h> +#include <netdb.h> +#include <string.h> +#include <netinet/in.h> + +struct hostent *gethostbyname2(const char *name, int af) +{ +	static struct hostent h; +	static long buf[512/sizeof(long)]; +	struct hostent *res; +	if (gethostbyname2_r(name, af, &h, +		(void *)buf, sizeof buf, &res, &h_errno)) return 0; +	return &h; +} diff --git a/src/network/gethostbyname2_r.c b/src/network/gethostbyname2_r.c new file mode 100644 index 00000000..c2ed75b4 --- /dev/null +++ b/src/network/gethostbyname2_r.c @@ -0,0 +1,99 @@ +#define _GNU_SOURCE + +#include <sys/socket.h> +#include <netdb.h> +#include <string.h> +#include <netinet/in.h> +#include <errno.h> +#include <inttypes.h> + +int gethostbyname2_r(const char *name, int af, +	struct hostent *h, char *buf, size_t buflen, +	struct hostent **res, int *err) +{ +	struct addrinfo hint = { +		.ai_family = af==AF_INET6 ? af : AF_INET, +		.ai_flags = AI_CANONNAME +	}; +	struct addrinfo *ai, *p; +	int i; +	size_t need; +	const char *canon; + +	af = hint.ai_family; + +	/* Align buffer */ +	i = (uintptr_t)buf & sizeof(char *)-1; +	if (i) { +		if (buflen < sizeof(char *)-i) { +			errno = ERANGE; +			return -1; +		} +		buf += sizeof(char *)-i; +		buflen -= sizeof(char *)-i; +	} + +	getaddrinfo(name, 0, &hint, &ai); +	switch (getaddrinfo(name, 0, &hint, &ai)) { +	case EAI_NONAME: +		*err = HOST_NOT_FOUND; +		return -1; +	case EAI_AGAIN: +		*err = TRY_AGAIN; +		return -1; +	default: +	case EAI_MEMORY: +	case EAI_SYSTEM: +	case EAI_FAIL: +		*err = NO_RECOVERY; +		return -1; +	case 0: +		break; +	} + +	h->h_addrtype = af; +	h->h_length = af==AF_INET6 ? 16 : 4; + +	canon = ai->ai_canonname ? ai->ai_canonname : name; +	need = 4*sizeof(char *); +	for (i=0, p=ai; p; i++, p=p->ai_next) +		need += sizeof(char *) + h->h_length; +	need += strlen(name)+1; +	need += strlen(canon)+1; + +	if (need > buflen) { +		freeaddrinfo(ai); +		errno = ERANGE; +		return -1; +	} + +	h->h_aliases = (void *)buf; +	buf += 3*sizeof(char *); +	h->h_addr_list = (void *)buf; +	buf += (i+1)*sizeof(char *); + +	h->h_name = h->h_aliases[0] = buf; +	strcpy(h->h_name, canon); +	buf += strlen(h->h_name)+1; + +	if (strcmp(h->h_name, name)) { +		h->h_aliases[1] = buf; +		strcpy(h->h_aliases[1], name); +		buf += strlen(h->h_aliases[1])+1; +	} else h->h_aliases[1] = 0; + +	h->h_aliases[2] = 0; + +	for (i=0, p=ai; p; i++, p=p->ai_next) { +		h->h_addr_list[i] = (void *)buf; +		buf += h->h_length; +		memcpy(h->h_addr_list[i], +			&((struct sockaddr_in *)p->ai_addr)->sin_addr, +			h->h_length); +	} +	h->h_addr_list[i] = 0; + +	*res = h; +	freeaddrinfo(ai); +	return 0; +} diff --git a/src/network/gethostbyname_r.c b/src/network/gethostbyname_r.c new file mode 100644 index 00000000..cd872541 --- /dev/null +++ b/src/network/gethostbyname_r.c @@ -0,0 +1,11 @@ +#define _GNU_SOURCE + +#include <sys/socket.h> +#include <netdb.h> + +int gethostbyname_r(const char *name, +	struct hostent *h, char *buf, size_t buflen, +	struct hostent **res, int *err) +{ +	return gethostbyname2_r(name, AF_INET, h, buf, buflen, res, err); +} diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c new file mode 100644 index 00000000..0763ca88 --- /dev/null +++ b/src/network/getnameinfo.c @@ -0,0 +1,54 @@ +#include <netdb.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "__dns.h" + +int getnameinfo(const struct sockaddr *sa, socklen_t sl, +	char *node, socklen_t nodelen, +	char *serv, socklen_t servlen, +	int flags) +{ +	char buf[256]; +	unsigned char reply[512]; +	int af = sa->sa_family; +	unsigned char *a; + +	switch (af) { +	case AF_INET: +		a = (void *)&((struct sockaddr_in *)sa)->sin_addr; +		if (sl != sizeof(struct sockaddr_in)) return EAI_FAMILY; +		break; +	case AF_INET6: +		a = (void *)&((struct sockaddr_in6 *)sa)->sin6_addr; +		if (sl != sizeof(struct sockaddr_in6)) return EAI_FAMILY; +		break; +	default: +		return EAI_FAMILY; +	} + +	if (node && nodelen) { +		if ((flags & NI_NUMERICHOST) +			|| __dns_query(reply, a, af, 1) <= 0 +			|| __dns_get_rr(buf, 0, 256, 1, reply, RR_PTR, 1) <= 0) +		{ +			if (flags & NI_NAMEREQD) return EAI_NONAME; +			inet_ntop(af, a, buf, sizeof buf); +		} +		if (strlen(buf) >= nodelen) return EAI_OVERFLOW; +		strcpy(node, buf); +	} + +	if (serv && servlen) { +		if (snprintf(buf, sizeof buf, "%d", +			ntohs(((struct sockaddr_in *)sa)->sin_port))>=servlen) +			return EAI_OVERFLOW; +		strcpy(serv, buf); +	} + +	return 0; +} diff --git a/src/network/getpeername.c b/src/network/getpeername.c new file mode 100644 index 00000000..7ecbe375 --- /dev/null +++ b/src/network/getpeername.c @@ -0,0 +1,9 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" + +int getpeername(int fd, struct sockaddr *addr, socklen_t *len) +{ +	unsigned long args[] = { fd, (unsigned long)addr, (unsigned long)len }; +	return syscall2(__NR_socketcall, SYS_GETPEERNAME, (long)args); +} diff --git a/src/network/getservbyname.c b/src/network/getservbyname.c new file mode 100644 index 00000000..0b00ce11 --- /dev/null +++ b/src/network/getservbyname.c @@ -0,0 +1,12 @@ +#define _GNU_SOURCE +#include <netdb.h> + +struct servent *getservbyname(const char *name, const char *prots) +{ +	static struct servent se; +	static long buf[32/sizeof(long)]; +	struct servent *res; +	if (getservbyname_r(name, prots, &se, (void *)buf, sizeof buf, &res)) +		return 0; +	return &se; +} diff --git a/src/network/getservbyname_r.c b/src/network/getservbyname_r.c new file mode 100644 index 00000000..5c025150 --- /dev/null +++ b/src/network/getservbyname_r.c @@ -0,0 +1,41 @@ +#define _GNU_SOURCE +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <inttypes.h> +#include <errno.h> +#include <string.h> + +int getservbyname_r(const char *name, const char *prots, +	struct servent *se, char *buf, size_t buflen, struct servent **res) +{ +	struct addrinfo *ai, hint = { .ai_family = AF_INET }; +	int i; + +	/* Align buffer */ +	i = (uintptr_t)buf & sizeof(char *)-1; +	if (!i) i = sizeof(char *); +	if (buflen < 3*sizeof(char *)-i) { +		errno = ERANGE; +		return -1; +	} +	buf += sizeof(char *)-i; +	buflen -= sizeof(char *)-i; + +	if (!strcmp(prots, "tcp")) hint.ai_protocol = IPPROTO_TCP; +	else if (!strcmp(prots, "udp")) hint.ai_protocol = IPPROTO_UDP; +	else return -1; + +	if (getaddrinfo(0, name, &hint, &ai) < 0) return -1; + +	se->s_name = (char *)name; +	se->s_aliases = (void *)buf; +	se->s_aliases[0] = se->s_name; +	se->s_aliases[1] = 0; +	se->s_port = ((struct sockaddr_in *)ai->ai_addr)->sin_port; +	se->s_proto = (char *)prots; + +	freeaddrinfo(ai); +	*res = se; +	return 0; +} diff --git a/src/network/getservbyport.c b/src/network/getservbyport.c new file mode 100644 index 00000000..c9ecbb11 --- /dev/null +++ b/src/network/getservbyport.c @@ -0,0 +1,12 @@ +#define _GNU_SOURCE +#include <netdb.h> + +struct servent *getservbyport(int port, const char *prots) +{ +	static struct servent se; +	static long buf[32/sizeof(long)]; +	struct servent *res; +	if (getservbyport_r(port, prots, &se, (void *)buf, sizeof buf, &res)) +		return 0; +	return &se; +} diff --git a/src/network/getservbyport_r.c b/src/network/getservbyport_r.c new file mode 100644 index 00000000..004a6168 --- /dev/null +++ b/src/network/getservbyport_r.c @@ -0,0 +1,43 @@ +#define _GNU_SOURCE +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <inttypes.h> +#include <errno.h> +#include <string.h> + +int getservbyport_r(int port, const char *prots, +	struct servent *se, char *buf, size_t buflen, struct servent **res) +{ +	int i; +	struct sockaddr_in sin = { +		.sin_family = AF_INET, +		.sin_port = port, +	}; + +	/* Align buffer */ +	i = (uintptr_t)buf & sizeof(char *)-1; +	if (!i) i = sizeof(char *); +	if (buflen < 3*sizeof(char *)-i) { +		errno = ERANGE; +		return -1; +	} +	buf += sizeof(char *)-i; +	buflen -= sizeof(char *)-i; + +	if (strcmp(prots, "tcp") && strcmp(prots, "udp")) return -1; + +	se->s_port = port; +	se->s_proto = (char *)prots; +	se->s_aliases = (void *)buf; +	buf += 2*sizeof(char *); +	buflen -= 2*sizeof(char *); +	se->s_aliases[1] = 0; +	se->s_aliases[0] = se->s_name = buf; + +	if (getnameinfo((void *)&sin, sizeof sin, 0, 0, buf, buflen,  +		strcmp(prots, "udp") ? 0 : NI_DGRAM) < 0) return -1; + +	*res = se; +	return 0; +} diff --git a/src/network/getsockname.c b/src/network/getsockname.c new file mode 100644 index 00000000..4b1002f8 --- /dev/null +++ b/src/network/getsockname.c @@ -0,0 +1,9 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" + +int getsockname(int fd, struct sockaddr *addr, socklen_t *len) +{ +	unsigned long args[] = { fd, (unsigned long)addr, (unsigned long)len }; +	return syscall2(__NR_socketcall, SYS_GETSOCKNAME, (long)args); +} diff --git a/src/network/getsockopt.c b/src/network/getsockopt.c new file mode 100644 index 00000000..8c818863 --- /dev/null +++ b/src/network/getsockopt.c @@ -0,0 +1,13 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" + +int getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) +{ +	unsigned long args[] = { +		fd, level, optname, +		(unsigned long)optval, +		(unsigned long)optlen +	}; +	return syscall2(__NR_socketcall, SYS_GETSOCKOPT, (long)args); +} diff --git a/src/network/h_errno.c b/src/network/h_errno.c new file mode 100644 index 00000000..73ead046 --- /dev/null +++ b/src/network/h_errno.c @@ -0,0 +1 @@ +int h_errno; diff --git a/src/network/hstrerror.c b/src/network/hstrerror.c new file mode 100644 index 00000000..b7a6ab6c --- /dev/null +++ b/src/network/hstrerror.c @@ -0,0 +1,16 @@ +#define _GNU_SOURCE +#include <netdb.h> + +static const char msgs[] = +	"Host not found\0" +	"Try again\0" +	"Non-recoverable error\0" +	"Address not available\0" +	"\0Unknown error"; + +const char *hstrerror(int ecode) +{ +	const char *s; +	for (s=msgs, ecode--; ecode && *s; ecode--, s++) for (; *s; s++); +	return *s ? s : s+1; +} diff --git a/src/network/htonl.c b/src/network/htonl.c new file mode 100644 index 00000000..b21dace0 --- /dev/null +++ b/src/network/htonl.c @@ -0,0 +1,10 @@ +#include <netinet/in.h> + +uint32_t htonl(uint32_t n) +{ +	union { +		uint8_t b[4]; +		uint32_t i; +	} u = { { n>>24, n>>16, n>>8, n } }; +	return u.i; +} diff --git a/src/network/htons.c b/src/network/htons.c new file mode 100644 index 00000000..522504a5 --- /dev/null +++ b/src/network/htons.c @@ -0,0 +1,10 @@ +#include <netinet/in.h> + +uint16_t htons(uint16_t n) +{ +	union { +		uint8_t b[2]; +		uint16_t s; +	} u = { { n>>8, n } }; +	return u.s; +} diff --git a/src/network/in6addr_any.c b/src/network/in6addr_any.c new file mode 100644 index 00000000..995387fa --- /dev/null +++ b/src/network/in6addr_any.c @@ -0,0 +1,3 @@ +#include <netinet/in.h> + +const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; diff --git a/src/network/in6addr_loopback.c b/src/network/in6addr_loopback.c new file mode 100644 index 00000000..b96005b8 --- /dev/null +++ b/src/network/in6addr_loopback.c @@ -0,0 +1,3 @@ +#include <netinet/in.h> + +const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; diff --git a/src/network/inet_addr.c b/src/network/inet_addr.c new file mode 100644 index 00000000..84137281 --- /dev/null +++ b/src/network/inet_addr.c @@ -0,0 +1,11 @@ +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "__dns.h" + +in_addr_t inet_addr(const char *p) +{ +	struct sockaddr_in sin; +	if (__ipparse(&sin, AF_INET, p)) return -1; +	return sin.sin_addr.s_addr; +} diff --git a/src/network/inet_aton.c b/src/network/inet_aton.c new file mode 100644 index 00000000..ea4ee165 --- /dev/null +++ b/src/network/inet_aton.c @@ -0,0 +1,7 @@ +#include <sys/socket.h> +#include <arpa/inet.h> + +int inet_aton(const char *cp, struct in_addr *inp) +{ +	return inet_pton(AF_INET, cp, (void *)inp) > 0; +} diff --git a/src/network/inet_ntoa.c b/src/network/inet_ntoa.c new file mode 100644 index 00000000..71411e0b --- /dev/null +++ b/src/network/inet_ntoa.c @@ -0,0 +1,10 @@ +#include <arpa/inet.h> +#include <stdio.h> + +char *inet_ntoa(struct in_addr in) +{ +	static char buf[16]; +	unsigned char *a = (void *)∈ +	snprintf(buf, sizeof buf, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); +	return buf; +} diff --git a/src/network/inet_ntop.c b/src/network/inet_ntop.c new file mode 100644 index 00000000..3e8a6db0 --- /dev/null +++ b/src/network/inet_ntop.c @@ -0,0 +1,48 @@ +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +const char *inet_ntop(int af, const void *a0, char *s, socklen_t l) +{ +	const unsigned char *a = a0; +	int i, j, max, best; +	char buf[100]; + +	switch (af) { +	case AF_INET: +		if (snprintf(s, l, "%d.%d.%d.%d", a[0],a[1],a[2],a[3]) < l) +			return s; +		break; +	case AF_INET6: +		memset(buf, 'x', sizeof buf); +		buf[sizeof buf-1]=0; +		snprintf(buf, sizeof buf,  +			"%.0x%x:%.0x%x:%.0x%x:%.0x%x:%.0x%x:%.0x%x:%.0x%x:%.0x%x", +			a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7], +			a[8],a[9],a[10],a[11],a[12],a[13],a[14],a[15]); +		/* Replace longest /(^0|:)[:0]{2,}/ with "::" */ +		for (i=best=0, max=2; buf[i]; i++) { +			if (i && buf[i] != ':') continue; +			j = strspn(buf+i, ":0"); +			if (j>max) best=i, max=j; +		} +		if (max>2) { +			buf[best] = buf[best+1] = ':'; +			strcpy(buf+best+2, buf+best+max); +		} +		if (strlen(buf) < l) { +			strcpy(s, buf); +			return s; +		} +		break; +	default: +		errno = EAFNOSUPPORT; +		return 0; +	} +	errno = ENOSPC; +	return 0; +} diff --git a/src/network/inet_pton.c b/src/network/inet_pton.c new file mode 100644 index 00000000..349c4025 --- /dev/null +++ b/src/network/inet_pton.c @@ -0,0 +1,31 @@ +#include <sys/socket.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include "__dns.h" + +int inet_pton(int af, const char *s, void *a0) +{ +	unsigned char *a = a0; +	const char *z; +	unsigned long x; +	int i; + +	/* Reimplement this because inet_pton cannot accept special v4 forms */ +	if (af==AF_INET) { +		for (i=0; i<4 && *s; i++) { +			a[i] = x = strtoul(s, (char **)&z, 10); +			if (!isdigit(*s) || z==s || (*z && *z != '.') || x>255) +				return 0; +			s=z+1; +		} +		return 0; +	} else if (af==AF_INET6) { +		return !__ipparse(a, AF_INET6, s); +	} + +	errno = EAFNOSUPPORT; +	return 0; +} diff --git a/src/network/listen.c b/src/network/listen.c new file mode 100644 index 00000000..7c8c1a8a --- /dev/null +++ b/src/network/listen.c @@ -0,0 +1,9 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" + +int listen(int fd, int backlog) +{ +	unsigned long args[] = { fd, backlog }; +	return syscall2(__NR_socketcall, SYS_LISTEN, (long)args); +} diff --git a/src/network/ntohl.c b/src/network/ntohl.c new file mode 100644 index 00000000..64379196 --- /dev/null +++ b/src/network/ntohl.c @@ -0,0 +1,10 @@ +#include <netinet/in.h> + +uint32_t ntohl(uint32_t n) +{ +	union { +		uint32_t i; +		uint8_t b[4]; +	} u = { n }; +	return (u.b[0]<<24) | (u.b[1]<<16) | (u.b[2]<<8) | u.b[3]; +} diff --git a/src/network/ntohs.c b/src/network/ntohs.c new file mode 100644 index 00000000..3544a479 --- /dev/null +++ b/src/network/ntohs.c @@ -0,0 +1,10 @@ +#include <netinet/in.h> + +uint16_t ntohs(uint16_t n) +{ +	union { +		uint16_t s; +		uint8_t b[2]; +	} u = { n }; +	return (u.b[0]<<8) | u.b[1]; +} diff --git a/src/network/proto.c b/src/network/proto.c new file mode 100644 index 00000000..8c25c53a --- /dev/null +++ b/src/network/proto.c @@ -0,0 +1,58 @@ +#include <netdb.h> +#include <stdio.h> +#include <string.h> + +/* do we really need all these?? */ + +static int idx; +static const unsigned char protos[][6] = { +	"\000ip", +	"\001icmp", +	"\002igmp", +	"\003ggp", +	"\006tcp", +	"\014pup", +	"\021udp", +	"\026idp", +	"\377raw" +	"\0\0" +}; + +void endprotoent(void) +{ +	idx = 0; +} + +void setprotoent(int stayopen) +{ +	idx = 0; +} + +struct protoent *getprotoent(void) +{ +	static struct protoent p; +	static const char *aliases; +	if (!protos[idx][1]) return NULL; +	p.p_proto = protos[idx][0]; +	p.p_name = (char *)protos[idx++]+1; +	p.p_aliases = (char **)&aliases; +	return &p; +} + +struct protoent *getprotobyname(const char *name) +{ +	struct protoent *p; +	endprotoent(); +	do p = getprotoent(); +	while (p && strcmp(name, p->p_name)); +	return p; +} + +struct protoent *getprotobynumber(int num) +{ +	struct protoent *p; +	endprotoent(); +	do p = getprotoent(); +	while (p && p->p_proto != num); +	return p; +} diff --git a/src/network/recv.c b/src/network/recv.c new file mode 100644 index 00000000..521a4b19 --- /dev/null +++ b/src/network/recv.c @@ -0,0 +1,14 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" +#include "libc.h" + +ssize_t recv(int fd, void *buf, size_t len, int flags) +{ +	unsigned long args[] = { fd, (unsigned long)buf, len, flags }; +	ssize_t r; +	CANCELPT_BEGIN; +	r = syscall2(__NR_socketcall, SYS_RECV, (long)args); +	CANCELPT_END; +	return r; +} diff --git a/src/network/recvfrom.c b/src/network/recvfrom.c new file mode 100644 index 00000000..df50114b --- /dev/null +++ b/src/network/recvfrom.c @@ -0,0 +1,17 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" +#include "libc.h" + +ssize_t recvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *alen) +{ +	unsigned long args[] = { +		fd, (unsigned long)buf, len, flags, +		(unsigned long)addr, (unsigned long)alen +	}; +	ssize_t r; +	CANCELPT_BEGIN; +	r = syscall2(__NR_socketcall, SYS_RECVFROM, (long)args); +	CANCELPT_END; +	return r; +} diff --git a/src/network/recvmsg.c b/src/network/recvmsg.c new file mode 100644 index 00000000..ead16f9c --- /dev/null +++ b/src/network/recvmsg.c @@ -0,0 +1,14 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" +#include "libc.h" + +ssize_t recvmsg(int fd, struct msghdr *msg, int flags) +{ +	unsigned long args[] = { fd, (unsigned long)msg, flags }; +	ssize_t r; +	CANCELPT_BEGIN; +	r = syscall2(__NR_socketcall, SYS_RECVMSG, (long)args); +	CANCELPT_END; +	return r; +} diff --git a/src/network/res_init.c b/src/network/res_init.c new file mode 100644 index 00000000..cbd5b155 --- /dev/null +++ b/src/network/res_init.c @@ -0,0 +1,4 @@ +int res_init() +{ +	return 0; +} diff --git a/src/network/res_query.c b/src/network/res_query.c new file mode 100644 index 00000000..4ebeb102 --- /dev/null +++ b/src/network/res_query.c @@ -0,0 +1,20 @@ +#include <netdb.h> +#include "__dns.h" + +int res_query(const char *name, int class, int type, unsigned char *dest, int len) +{ +	if (class != 1 || len < 512) +		return -1; +	switch(__dns_doqueries(dest, name, &type, 1)) { +	case EAI_NONAME: +		h_errno = HOST_NOT_FOUND; +		return -1; +	case EAI_AGAIN: +		h_errno = TRY_AGAIN; +		return -1; +	case EAI_FAIL: +		h_errno = NO_RECOVERY; +		return -1; +	} +	return 512; +} diff --git a/src/network/send.c b/src/network/send.c new file mode 100644 index 00000000..d72fb03c --- /dev/null +++ b/src/network/send.c @@ -0,0 +1,14 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" +#include "libc.h" + +ssize_t send(int fd, const void *buf, size_t len, int flags) +{ +	unsigned long args[] = { fd, (unsigned long)buf, len, flags }; +	ssize_t r; +	CANCELPT_BEGIN; +	r = syscall2(__NR_socketcall, SYS_SEND, (long)args); +	CANCELPT_END; +	return r; +} diff --git a/src/network/sendmsg.c b/src/network/sendmsg.c new file mode 100644 index 00000000..ea2fe482 --- /dev/null +++ b/src/network/sendmsg.c @@ -0,0 +1,14 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" +#include "libc.h" + +ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) +{ +	unsigned long args[] = { fd, (unsigned long)msg, flags }; +	ssize_t r; +	CANCELPT_BEGIN; +	r = syscall2(__NR_socketcall, SYS_SENDMSG, (long)args); +	CANCELPT_END; +	return r; +} diff --git a/src/network/sendto.c b/src/network/sendto.c new file mode 100644 index 00000000..5d224b0b --- /dev/null +++ b/src/network/sendto.c @@ -0,0 +1,17 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" +#include "libc.h" + +ssize_t sendto(int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t alen) +{ +	unsigned long args[] = { +		fd, (unsigned long)buf, len, flags, +		(unsigned long)addr, alen +	}; +	ssize_t r; +	CANCELPT_BEGIN; +	r = syscall2(__NR_socketcall, SYS_SENDTO, (long)args); +	CANCELPT_END; +	return r; +} diff --git a/src/network/serv.c b/src/network/serv.c new file mode 100644 index 00000000..5ade6ad1 --- /dev/null +++ b/src/network/serv.c @@ -0,0 +1,16 @@ +#include <netdb.h> +#include <stdio.h> +#include <string.h> + +void endservent(void) +{ +} + +void setservent(int stayopen) +{ +} + +struct servent *getservent(void) +{ +	return 0; +} diff --git a/src/network/setsockopt.c b/src/network/setsockopt.c new file mode 100644 index 00000000..b50303b8 --- /dev/null +++ b/src/network/setsockopt.c @@ -0,0 +1,9 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" + +int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) +{ +	unsigned long args[] = { fd, level, optname, (unsigned long)optval, optlen }; +	return syscall2(__NR_socketcall, SYS_SETSOCKOPT, (long)args); +} diff --git a/src/network/shutdown.c b/src/network/shutdown.c new file mode 100644 index 00000000..91950c8a --- /dev/null +++ b/src/network/shutdown.c @@ -0,0 +1,9 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" + +int shutdown(int fd, int how) +{ +	unsigned long args[] = { fd, how }; +	return syscall2(__NR_socketcall, SYS_SHUTDOWN, (long)args); +} diff --git a/src/network/sockatmark.c b/src/network/sockatmark.c new file mode 100644 index 00000000..5328a855 --- /dev/null +++ b/src/network/sockatmark.c @@ -0,0 +1,11 @@ +#include <sys/socket.h> +#include <sys/ioctl.h> +#include "socketcall.h" + +int sockatmark(int s) +{ +	int ret; +	if (ioctl(s, SIOCATMARK, &ret) < 0) +		return -1; +	return ret; +} diff --git a/src/network/socket.c b/src/network/socket.c new file mode 100644 index 00000000..afaeb411 --- /dev/null +++ b/src/network/socket.c @@ -0,0 +1,9 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" + +int socket(int domain, int type, int protocol) +{ +	unsigned long args[] = { domain, type, protocol }; +	return syscall2(__NR_socketcall, SYS_SOCKET, (long)args); +} diff --git a/src/network/socketcall.h b/src/network/socketcall.h new file mode 100644 index 00000000..9ae98587 --- /dev/null +++ b/src/network/socketcall.h @@ -0,0 +1,24 @@ +#define SYS_SOCKET      1 +#define SYS_BIND        2 +#define SYS_CONNECT     3 +#define SYS_LISTEN      4 +#define SYS_ACCEPT      5 +#define SYS_GETSOCKNAME 6 +#define SYS_GETPEERNAME 7 +#define SYS_SOCKETPAIR  8 +#define SYS_SEND        9 +#define SYS_RECV        10 +#define SYS_SENDTO      11 +#define SYS_RECVFROM    12 +#define SYS_SHUTDOWN    13 +#define SYS_SETSOCKOPT  14 +#define SYS_GETSOCKOPT  15 +#define SYS_SENDMSG     16 +#define SYS_RECVMSG     17 + +#define FIOSETOWN       0x8901 +#define SIOCSPGRP       0x8902 +#define FIOGETOWN       0x8903 +#define SIOCGPGRP       0x8904 +#define SIOCATMARK      0x8905 +#define SIOCGSTAMP      0x8906 diff --git a/src/network/socketpair.c b/src/network/socketpair.c new file mode 100644 index 00000000..65a47fd9 --- /dev/null +++ b/src/network/socketpair.c @@ -0,0 +1,9 @@ +#include <sys/socket.h> +#include "syscall.h" +#include "socketcall.h" + +int socketpair(int domain, int type, int protocol, int fd[2]) +{ +	unsigned long args[] = { domain, type, protocol, (unsigned long)fd }; +	return syscall2(__NR_socketcall, SYS_SOCKETPAIR, (long)args); +} diff --git a/src/passwd/getgr_r.c b/src/passwd/getgr_r.c new file mode 100644 index 00000000..5b1333e3 --- /dev/null +++ b/src/passwd/getgr_r.c @@ -0,0 +1,53 @@ +#include "pwf.h" + +#define FIX(x) (gr->gr_##x = gr->gr_##x-line+buf) + +static int getgr_r(const char *name, gid_t gid, struct group *gr, char *buf, size_t size, struct group **res) +{ +	FILE *f; +	char *line = 0; +	size_t len = 0; +	char **mem = 0; +	size_t nmem = 0; +	int rv = 0; +	size_t i; + +	f = fopen("/etc/group", "rb"); +	if (!f) return errno; + +	*res = 0; +	while (__getgrent_a(f, gr, &line, &len, &mem, &nmem)) { +		if (name && !strcmp(name, gr->gr_name) +		|| !name && gr->gr_gid == gid) { +			if (size < len + nmem*sizeof(char *) + 32) { +				rv = ERANGE; +				break; +			} +			*res = gr; +			buf += (16-(uintptr_t)buf)%16; +			gr->gr_mem = (void *)buf; +			buf += nmem*sizeof(char *); +			memcpy(buf, line, len); +			FIX(name); +			FIX(passwd); +			for (i=0; mem[i]; i++) +				gr->gr_mem[i] = mem[i]-line+buf; +			gr->gr_mem[i] = 0; +			break; +		} +	} + 	free(mem); + 	free(line); +	fclose(f); +	return rv; +} + +int getgrnam_r(const char *name, struct group *gr, char *buf, size_t size, struct group **res) +{ +	return getgr_r(name, 0, gr, buf, size, res); +} + +int getgruid_r(gid_t gid, struct group *gr, char *buf, size_t size, struct group **res) +{ +	return getgr_r(0, gid, gr, buf, size, res); +} diff --git a/src/passwd/getgrent.c b/src/passwd/getgrent.c new file mode 100644 index 00000000..e9d25eba --- /dev/null +++ b/src/passwd/getgrent.c @@ -0,0 +1,39 @@ +#include "pwf.h" + +static FILE *f; + +void setgrent() +{ +	if (f) fclose(f); +	f = 0; +} + +weak_alias(setgrent, endgrent); + +struct group *getgrent() +{ +	static char *line, **mem; +	static struct group gr; +	size_t size=0, nmem=0; +	if (!f) f = fopen("/etc/group", "rb"); +	if (!f) return 0; +	return __getgrent_a(f, &gr, &line, &size, &mem, &nmem); +} + +struct group *getgrgid(gid_t gid) +{ +	struct group *gr; +	setgrent(); +	while ((gr=getgrent()) && gr->gr_gid != gid); +	endgrent(); +	return gr; +} + +struct group *getgrnam(const char *name) +{ +	struct group *gr; +	setgrent(); +	while ((gr=getgrent()) && strcmp(gr->gr_name, name)); +	endgrent(); +	return gr; +} diff --git a/src/passwd/getgrent_a.c b/src/passwd/getgrent_a.c new file mode 100644 index 00000000..ccb51d52 --- /dev/null +++ b/src/passwd/getgrent_a.c @@ -0,0 +1,46 @@ +#include "pwf.h" + +struct group *__getgrent_a(FILE *f, struct group *gr, char **line, size_t *size, char ***mem, size_t *nmem) +{ +	ssize_t l; +	char *s, *mems; +	size_t i; + +	for (;;) { +		if ((l=getline(line, size, f)) < 0) { +			free(*line); +			*line = 0; +			return 0; +		} +		line[0][l-1] = 0; + +		s = line[0]; +		gr->gr_name = s++; +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; gr->gr_passwd = s; +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; gr->gr_gid = atoi(s); +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; mems = s; +		break; +	} + +	for (*nmem=!!*s; *s; s++) +		if (*s==',') ++*nmem; +	free(*mem); +	*mem = calloc(sizeof(char *), *nmem+1); +	if (!*mem) { +		free(*line); +		*line = 0; +		return 0; +	} +	mem[0][0] = mems; +	for (s=mems, i=0; *s; s++) +		if (*s==',') *s++ = 0, mem[0][++i] = s; +	mem[0][++i] = 0; +	gr->gr_mem = *mem; +	return gr; +} diff --git a/src/passwd/getpw_r.c b/src/passwd/getpw_r.c new file mode 100644 index 00000000..7b331e8a --- /dev/null +++ b/src/passwd/getpw_r.c @@ -0,0 +1,46 @@ +#include "pwf.h" + +#define FIX(x) (pw->pw_##x = pw->pw_##x-line+buf) + +static int getpw_r(const char *name, uid_t uid, struct passwd *pw, char *buf, size_t size, struct passwd **res) +{ +	FILE *f; +	char *line = 0; +	size_t len = 0; +	int rv = 0; + +	f = fopen("/etc/passwd", "rb"); +	if (!f) return errno; + +	*res = 0; +	while (__getpwent_a(f, pw, &line, &len)) { +		if (name && !strcmp(name, pw->pw_name) +		|| !name && pw->pw_uid == uid) { +			if (size < len) { +				rv = ERANGE; +				break; +			} +			*res = pw; +			memcpy(buf, line, len); +			FIX(name); +			FIX(passwd); +			FIX(gecos); +			FIX(dir); +			FIX(shell); +			break; +		} +	} + 	free(line); +	fclose(f); +	return rv; +} + +int getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t size, struct passwd **res) +{ +	return getpw_r(name, 0, pw, buf, size, res); +} + +int getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t size, struct passwd **res) +{ +	return getpw_r(0, uid, pw, buf, size, res); +} diff --git a/src/passwd/getpwent.c b/src/passwd/getpwent.c new file mode 100644 index 00000000..dabd411a --- /dev/null +++ b/src/passwd/getpwent.c @@ -0,0 +1,39 @@ +#include "pwf.h" + +static FILE *f; + +void setpwent() +{ +	if (f) fclose(f); +	f = 0; +} + +weak_alias(setpwent, endpwent); + +struct passwd *getpwent() +{ +	static char *line; +	static struct passwd pw; +	size_t size=0; +	if (!f) f = fopen("/etc/passwd", "rb"); +	if (!f) return 0; +	return __getpwent_a(f, &pw, &line, &size); +} + +struct passwd *getpwuid(uid_t uid) +{ +	struct passwd *pw; +	setpwent(); +	while ((pw=getpwent()) && pw->pw_uid != uid); +	endpwent(); +	return pw; +} + +struct passwd *getpwnam(const char *name) +{ +	struct passwd *pw; +	setpwent(); +	while ((pw=getpwent()) && strcmp(pw->pw_name, name)); +	endpwent(); +	return pw; +} diff --git a/src/passwd/getpwent_a.c b/src/passwd/getpwent_a.c new file mode 100644 index 00000000..aaf84edd --- /dev/null +++ b/src/passwd/getpwent_a.c @@ -0,0 +1,37 @@ +#include "pwf.h" + +struct passwd *__getpwent_a(FILE *f, struct passwd *pw, char **line, size_t *size) +{ +	ssize_t l; +	char *s; +	for (;;) { +		if ((l=getline(line, size, f)) < 0) { +			free(*line); +			*line = 0; +			return 0; +		} +		line[0][l-1] = 0; + +		s = line[0]; +		pw->pw_name = s++; +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; pw->pw_passwd = s; +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; pw->pw_uid = atoi(s); +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; pw->pw_gid = atoi(s); +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; pw->pw_gecos = s; +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; pw->pw_dir = s; +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; pw->pw_shell = s; +		return pw; +	} +} diff --git a/src/passwd/getspent.c b/src/passwd/getspent.c new file mode 100644 index 00000000..8574a480 --- /dev/null +++ b/src/passwd/getspent.c @@ -0,0 +1,14 @@ +#include "pwf.h" + +void setspent() +{ +} + +void endspent() +{ +} + +struct spwd *getspent() +{ +	return 0; +} diff --git a/src/passwd/getspnam.c b/src/passwd/getspnam.c new file mode 100644 index 00000000..041f8965 --- /dev/null +++ b/src/passwd/getspnam.c @@ -0,0 +1,17 @@ +#include "pwf.h" + +#define LINE_LIM 256 + +struct spwd *getspnam(const char *name) +{ +	static struct spwd sp; +	static char *line; +	struct spwd *res; +	int e; + +	if (!line) line = malloc(LINE_LIM); +	if (!line) return 0; +	e = getspnam_r(name, &sp, line, LINE_LIM, &res); +	if (e) errno = e; +	return res; +} diff --git a/src/passwd/getspnam_r.c b/src/passwd/getspnam_r.c new file mode 100644 index 00000000..1dd39ce0 --- /dev/null +++ b/src/passwd/getspnam_r.c @@ -0,0 +1,89 @@ +#include <fcntl.h> +#include <unistd.h> +#include "pwf.h" + +/* This implementation support Openwall-style TCB passwords in place of + * traditional shadow, if the appropriate directories and files exist. + * Thus, it is careful to avoid following symlinks or blocking on fifos + * which a malicious user might create in place of his or her TCB shadow + * file. It also avoids any allocation to prevent memory-exhaustion + * attacks via huge TCB shadow files. */ + +int getspnam_r(const char *name, struct spwd *sp, char *buf, size_t size, struct spwd **res) +{ +	char path[20+NAME_MAX]; +	FILE *f = 0; +	int rv = 0; +	int fd; +	size_t k, l = strlen(name); +	char *s; +	int skip = 0; + +	*res = 0; + +	/* Disallow potentially-malicious user names */ +	if (*name=='.' || strchr(name, '/') || !l) +		return EINVAL; + +	/* Buffer size must at least be able to hold name, plus some.. */ +	if (size < l+100) return ERANGE; + +	/* Protect against truncation */ +	if (snprintf(path, sizeof path, "/etc/tcb/%s/shadow", name) >= sizeof path) +		return EINVAL; + +	fd = open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK); +	if (fd >= 0) { +		f = fdopen(fd, "rb"); +		if (!f) { +			close(fd); +			return errno; +		} +	} else { +		f = fopen("/etc/shadow", "rb"); +		if (!f) return errno; +	} + +	while (fgets(buf, size, f) && (k=strlen(buf))>0) { +		if (skip || strncmp(name, buf, l)) { +			skip = buf[k-1] != '\n'; +			continue; +		} +		if (buf[k-1] != '\n') { +			rv = ERANGE; +			break; +		} +		buf[k-1] = 0; + +		s = buf; +		sp->sp_namp = s; +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; sp->sp_pwdp = s; +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; sp->sp_lstchg = atol(s); +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; sp->sp_min = atol(s); +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; sp->sp_max = atol(s); +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; sp->sp_warn = atol(s); +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; sp->sp_inact = atol(s); +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; sp->sp_expire = atol(s); +		if (!(s = strchr(s, ':'))) continue; + +		*s++ = 0; sp->sp_flag = atol(s); +		*res = sp; +		break; +	} +	fclose(f); +	return rv; +} diff --git a/src/passwd/lckpwdf.c b/src/passwd/lckpwdf.c new file mode 100644 index 00000000..2feda617 --- /dev/null +++ b/src/passwd/lckpwdf.c @@ -0,0 +1,11 @@ +#include <shadow.h> + +int lckpwdf() +{ +	return 0; +} + +int ulckpwdf() +{ +	return 0; +} diff --git a/src/passwd/pwf.h b/src/passwd/pwf.h new file mode 100644 index 00000000..0a76ef80 --- /dev/null +++ b/src/passwd/pwf.h @@ -0,0 +1,13 @@ +#include <pwd.h> +#include <grp.h> +#include <shadow.h> +#include <stdio.h> +#include <errno.h> +#include <stdint.h> +#include <string.h> +#include <limits.h> +#include "libc.h" + +struct passwd *__getpwent_a(FILE *f, struct passwd *pw, char **line, size_t *size); +struct spwd *__getspent_a(FILE *f, struct spwd *sp, char **line, size_t *size); +struct group *__getgrent_a(FILE *f, struct group *gr, char **line, size_t *size, char ***mem, size_t *nmem); diff --git a/src/prng/__rand48_step.c b/src/prng/__rand48_step.c new file mode 100644 index 00000000..755b4f2f --- /dev/null +++ b/src/prng/__rand48_step.c @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include <inttypes.h> + +uint64_t __rand48_step(unsigned short *xi, unsigned short *lc) +{ +	uint64_t a, x; +	x = xi[0] | xi[1]<<16 | xi[2]+0ULL<<32; +	a = lc[0] | lc[1]<<16 | lc[2]+0ULL<<32; +	x = a*x + lc[3]; +	xi[0] = x; +	xi[1] = x>>16; +	xi[2] = x>>32; +	return x & 0xffffffffffffull; +} diff --git a/src/prng/__seed48.c b/src/prng/__seed48.c new file mode 100644 index 00000000..05a4539e --- /dev/null +++ b/src/prng/__seed48.c @@ -0,0 +1 @@ +unsigned short __seed48[7] = { 0, 0, 0, 0xe66d, 0xdeec, 0x5, 0xb }; diff --git a/src/prng/drand48.c b/src/prng/drand48.c new file mode 100644 index 00000000..d808353c --- /dev/null +++ b/src/prng/drand48.c @@ -0,0 +1,19 @@ +#include <stdlib.h> +#include <inttypes.h> + +uint64_t __rand48_step(unsigned short *xi, unsigned short *lc); +extern unsigned short __seed48[7]; + +double erand48(unsigned short s[3]) +{ +	union { +		uint64_t u; +		double f; +	} x = { 0x3ff0000000000000ULL | __rand48_step(s, __seed48+3)<<4 }; +	return x.f - 1.0; +} + +double drand48(void) +{ +	return erand48(__seed48); +} diff --git a/src/prng/lcong48.c b/src/prng/lcong48.c new file mode 100644 index 00000000..32b27d42 --- /dev/null +++ b/src/prng/lcong48.c @@ -0,0 +1,9 @@ +#include <stdlib.h> +#include <string.h> + +extern unsigned short __seed48[7]; + +void lcong48(unsigned short p[7]) +{ +	memcpy(__seed48, p, sizeof __seed48); +} diff --git a/src/prng/lrand48.c b/src/prng/lrand48.c new file mode 100644 index 00000000..a3c4e4e2 --- /dev/null +++ b/src/prng/lrand48.c @@ -0,0 +1,15 @@ +#include <stdlib.h> +#include <inttypes.h> + +uint64_t __rand48_step(unsigned short *xi, unsigned short *lc); +extern unsigned short __seed48[7]; + +long nrand48(unsigned short s[3]) +{ +	return __rand48_step(s, __seed48+3) >> 17; +} + +long lrand48(void) +{ +	return nrand48(__seed48); +} diff --git a/src/prng/mrand48.c b/src/prng/mrand48.c new file mode 100644 index 00000000..ee650fc3 --- /dev/null +++ b/src/prng/mrand48.c @@ -0,0 +1,15 @@ +#include <stdlib.h> +#include <inttypes.h> + +uint64_t __rand48_step(unsigned short *xi, unsigned short *lc); +extern unsigned short __seed48[7]; + +long jrand48(unsigned short s[3]) +{ +	return __rand48_step(s, __seed48+3) >> 16; +} + +long mrand48(void) +{ +	return jrand48(__seed48); +} diff --git a/src/prng/rand.c b/src/prng/rand.c new file mode 100644 index 00000000..e3ce6347 --- /dev/null +++ b/src/prng/rand.c @@ -0,0 +1,13 @@ +#include <stdlib.h> + +static unsigned seed; + +void srand(unsigned s) +{ +	seed = s-1; +} + +int rand(void) +{ +	return (seed = (seed+1) * 1103515245 + 12345 - 1)+1 & 0x7fffffff; +} diff --git a/src/prng/rand_r.c b/src/prng/rand_r.c new file mode 100644 index 00000000..e96cfba9 --- /dev/null +++ b/src/prng/rand_r.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +int rand_r(unsigned *seed) +{ +	return (*seed = *seed * 1103515245 + 12345) & 0x7fffffff; +} diff --git a/src/prng/random.c b/src/prng/random.c new file mode 100644 index 00000000..e6b7fd1f --- /dev/null +++ b/src/prng/random.c @@ -0,0 +1,8 @@ +#include <stdlib.h> + +/* FIXME */ + +long random() +{ +	return rand(); +} diff --git a/src/prng/seed48.c b/src/prng/seed48.c new file mode 100644 index 00000000..e0699c09 --- /dev/null +++ b/src/prng/seed48.c @@ -0,0 +1,12 @@ +#include <stdlib.h> +#include <string.h> + +extern unsigned short __seed48[7]; + +unsigned short *seed48(unsigned short *s) +{ +	static unsigned short p[3]; +	memcpy(p, __seed48, sizeof p); +	memcpy(__seed48, s, sizeof p); +	return p; +} diff --git a/src/prng/srand48.c b/src/prng/srand48.c new file mode 100644 index 00000000..0a56f6a0 --- /dev/null +++ b/src/prng/srand48.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +void srand48(long seed) +{ +	seed48((unsigned short [3]){ 0x330e, seed, seed>>16 }); +} diff --git a/src/prng/srandom.c b/src/prng/srandom.c new file mode 100644 index 00000000..77f4dcbd --- /dev/null +++ b/src/prng/srandom.c @@ -0,0 +1,8 @@ +#include <stdlib.h> + +/* FIXME */ + +void srandom(unsigned seed) +{ +	return srand(seed); +} diff --git a/src/process/execl.c b/src/process/execl.c new file mode 100644 index 00000000..4c6eaa94 --- /dev/null +++ b/src/process/execl.c @@ -0,0 +1,20 @@ +#include <unistd.h> +#include <stdarg.h> + +int execl(const char *path, ...) +{ +	int argc; +	va_list ap; +	va_start(ap, path); +	for (argc=0; va_arg(ap, const char *); argc++); +	va_end(ap); +	{ +		int i; +		char *argv[argc+1]; +		va_start(ap, path); +		for (i=0; i<argc; i++) +			argv[i] = va_arg(ap, char *); +		argv[i] = NULL; +		return execv(path, argv); +	} +} diff --git a/src/process/execle.c b/src/process/execle.c new file mode 100644 index 00000000..37f629d9 --- /dev/null +++ b/src/process/execle.c @@ -0,0 +1,22 @@ +#include <unistd.h> +#include <stdarg.h> + +int execle(const char *path, ...) +{ +	int argc; +	va_list ap; +	va_start(ap, path); +	for (argc=0; va_arg(ap, const char *); argc++); +	va_end(ap); +	{ +		int i; +		char *argv[argc+1]; +		char **envp; +		va_start(ap, path); +		for (i=0; i<argc; i++) +			argv[i] = va_arg(ap, char *); +		argv[i] = NULL; +		envp = va_arg(ap, char **); +		return execve(path, argv, envp); +	} +} diff --git a/src/process/execlp.c b/src/process/execlp.c new file mode 100644 index 00000000..33fb0f7f --- /dev/null +++ b/src/process/execlp.c @@ -0,0 +1,20 @@ +#include <unistd.h> +#include <stdarg.h> + +int execlp(const char *file, ...) +{ +	int argc; +	va_list ap; +	va_start(ap, file); +	for (argc=0; va_arg(ap, const char *); argc++); +	va_end(ap); +	{ +		int i; +		char *argv[argc+1]; +		va_start(ap, file); +		for (i=0; i<argc; i++) +			argv[i] = va_arg(ap, char *); +		argv[i] = NULL; +		return execvp(file, argv); +	} +} diff --git a/src/process/execv.c b/src/process/execv.c new file mode 100644 index 00000000..2ac0dec0 --- /dev/null +++ b/src/process/execv.c @@ -0,0 +1,8 @@ +#include <unistd.h> + +extern char **__environ; + +int execv(const char *path, char *const argv[]) +{ +	return execve(path, argv, __environ); +} diff --git a/src/process/execve.c b/src/process/execve.c new file mode 100644 index 00000000..2a0b62d6 --- /dev/null +++ b/src/process/execve.c @@ -0,0 +1,8 @@ +#include <unistd.h> +#include "syscall.h" + +int execve(const char *path, char *const argv[], char *const envp[]) +{ +	/* do we need to use environ if envp is null? */ +	return syscall3(__NR_execve, (long)path, (long)argv, (long)envp); +} diff --git a/src/process/execvp.c b/src/process/execvp.c new file mode 100644 index 00000000..d799ddae --- /dev/null +++ b/src/process/execvp.c @@ -0,0 +1,34 @@ +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +extern char **__environ; + +int execvp(const char *file, char *const argv[]) +{ +	const char *p, *z, *path = getenv("PATH"); +	int l; + +	if (strchr(file, '/')) +		return execve(file, argv, __environ); + +	/* FIXME: integer overflows */ +	if (!path) path = "/usr/local/bin:/bin:/usr/bin"; +	l = strlen(file) + strlen(path) + 2; + +	for(p=path; p && *p; p=z) { +		char b[l]; +		z = strchr(p, ':'); +		if (z) { +			memcpy(b, p, z-p); +			b[z++-p] = 0; +		} else strcpy(b, p); +		strcat(b, "/"); +		strcat(b, file); +		if (!access(b, X_OK)) +			return execve(b, argv, __environ); +	} +	errno = ENOENT; +	return -1; +} diff --git a/src/process/fork.c b/src/process/fork.c new file mode 100644 index 00000000..1213f0f5 --- /dev/null +++ b/src/process/fork.c @@ -0,0 +1,9 @@ +#include <unistd.h> +#include "syscall.h" + +/* FIXME: add support for atfork stupidity */ + +pid_t fork(void) +{ +	return syscall0(__NR_fork); +} diff --git a/src/process/system.c b/src/process/system.c new file mode 100644 index 00000000..0f1c07b5 --- /dev/null +++ b/src/process/system.c @@ -0,0 +1,45 @@ +#include <unistd.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/wait.h> +#include <errno.h> + +int system(const char *cmd) +{ +	pid_t pid; +	sigset_t old, new; +	struct sigaction sa, oldint, oldquit; +	int status; + +	if (!cmd) return 1; + +	sa.sa_handler = SIG_IGN; +	sigemptyset(&sa.sa_mask); +	sa.sa_flags = 0; + +	sigaction(SIGINT, &sa, &oldint); +	sigaction(SIGQUIT, &sa, &oldquit); +	sigaddset(&sa.sa_mask, SIGCHLD); +	sigprocmask(SIG_BLOCK, &new, &old); + +	pid = fork(); +	if (pid <= 0) { +		sigaction(SIGINT, &oldint, NULL); +		sigaction(SIGQUIT, &oldquit, NULL); +		sigprocmask(SIG_SETMASK, &old, NULL); +		if (pid == 0) { +			execl("/bin/sh", "sh", "-c", cmd, (char *)0); +			_exit(127); +		} +		return -1; +	} +	while (waitpid(pid, &status, 0) == -1) +		if (errno != EINTR) { +			status = -1; +			break; +		} +	sigaction(SIGINT, &oldint, NULL); +	sigaction(SIGQUIT, &oldquit, NULL); +	sigprocmask(SIG_SETMASK, &old, NULL); +	return status; +} diff --git a/src/process/vfork.c b/src/process/vfork.c new file mode 100644 index 00000000..32a7a6ed --- /dev/null +++ b/src/process/vfork.c @@ -0,0 +1,8 @@ +#include <unistd.h> +#include "syscall.h" + +pid_t vfork(void) +{ +	/* vfork syscall cannot be made from C code */ +	return syscall0(__NR_fork); +} diff --git a/src/process/wait.c b/src/process/wait.c new file mode 100644 index 00000000..34da102d --- /dev/null +++ b/src/process/wait.c @@ -0,0 +1,6 @@ +#include <sys/wait.h> + +pid_t wait(int *status) +{ +	return waitpid((pid_t)-1, status, 0); +} diff --git a/src/process/waitid.c b/src/process/waitid.c new file mode 100644 index 00000000..0ec0d55c --- /dev/null +++ b/src/process/waitid.c @@ -0,0 +1,7 @@ +#include <sys/wait.h> +#include "syscall.h" + +int waitid(idtype_t type, id_t id, siginfo_t *info, int options) +{ +	return syscall5(__NR_waitid, type, id, (long)info, options, 0); +} diff --git a/src/process/waitpid.c b/src/process/waitpid.c new file mode 100644 index 00000000..0ddcd15a --- /dev/null +++ b/src/process/waitpid.c @@ -0,0 +1,7 @@ +#include <sys/wait.h> +#include "syscall.h" + +pid_t waitpid(pid_t pid, int *status, int options) +{ +	return syscall4(__NR_wait4, pid, (long)status, options, 0); +} diff --git a/src/regex/fnmatch.c b/src/regex/fnmatch.c new file mode 100644 index 00000000..5f2fccdb --- /dev/null +++ b/src/regex/fnmatch.c @@ -0,0 +1,150 @@ +#include <fnmatch.h> +#include <wctype.h> +#include <string.h> +#include <wchar.h> +#include <stdlib.h> +#include <limits.h> + +static int next(const char **s) +{ +	wchar_t c; +	int l = mbtowc(&c, *s, MB_LEN_MAX); +	/* hack to allow literal matches of invalid byte sequences */ +	if (l < 0) return (unsigned char)*(*s)++ - 0x100; +	*s += l; +	return c; +} + +#define BRACKET_ERROR  -0x100 +#define BRACKET_NOCHAR -0x101 + +static int bracket_next(const char **s) +{ +	int c; +	int type; +	if (**s == '[') { +		type = *(*s+1); +		if (type == '.' || type == '=') { +			*s += 2; +			c = next(s); +			if (c <= 0) return BRACKET_ERROR; +			if (**s == type && *(*s+1) == ']') { +				*s += 2; +				return c; +			} +			for (; **s && (**s != type || *(*s+1) != ']'); (*s)++); +			if (!**s) return BRACKET_ERROR; +			*s += 2; +			return BRACKET_NOCHAR; +		} +	} +	c = next(s); +	if (c <= 0) return BRACKET_ERROR; +	return c; +} + +#define __FNM_CONT 0x8000 + +int fnmatch(const char *p, const char *s, int flags) +{ +	int c, d, k; +	int not; +	int match; +	int first; +	int no_slash = (flags & FNM_PATHNAME) ? '/' : 0; +	int no_period = (flags & FNM_PERIOD) && !(flags & __FNM_CONT) ? '.' : 0x100; + +	flags |= __FNM_CONT; + +	while ((c = *p++)) { +		switch (c) { +		case '?': +			k = next(&s); +			if (!k || k == no_period || k == no_slash) +				return FNM_NOMATCH; +			break; +		case '\\': +			if (!(flags & FNM_NOESCAPE)) { +				c = *p++; +				goto literal; +			} +			if (*s++ != c) return FNM_NOMATCH; +			break; +		case '*': +			for (; *p == '*'; p++); +			if (*p && !*s) return FNM_NOMATCH; +			if (*s == no_period) +				return FNM_NOMATCH; +			if (!*p && (!no_slash || !strchr(s, no_slash))) +				return 0; +			for (; *s; s++) +				if (!fnmatch(p, s, flags)) +					return 0; +				else if (*s == no_slash) +					break; +			return FNM_NOMATCH; +		case '[': +			not = (*p == '!' || *p == '^'); +			if (not) p++; +			k = next(&s); +			if (!k || k == no_slash || k == no_period) +				return FNM_NOMATCH; +			match = 0; +			first = 1; +			for (;;) { +				if (!*p) return FNM_NOMATCH; +				if (*p == ']' && !first) break; +				first = 0; +				if (*p == '[' && *(p+1) == ':') { +					const char *z; +					p += 2; +					for (z=p; *z && (*z != ':' || *(z+1) != ']'); z++); +					if (!*z || z-p > 32) { /* FIXME: symbolic const? */ +						return FNM_NOMATCH; +					} else { +						char class[z-p+1]; +						memcpy(class, p, z-p); +						class[z-p] = 0; +						if (iswctype(k, wctype(class))) +							match = 1; +					} +					p = z+2; +					continue; +				} +				c = bracket_next(&p); +				if (c == BRACKET_ERROR) +					return FNM_NOMATCH; +				if (c == BRACKET_NOCHAR) +					continue; +				if (*p == '-' && *(p+1) != ']') { +					p++; +					d = bracket_next(&p); +					if (d == BRACKET_ERROR) +						return FNM_NOMATCH; +					if (d == BRACKET_NOCHAR) +						continue; +					if (k >= c && k <= d) +						match = 1; +					continue; +				} +				if (k == c) match = 1; +			} +			p++; +			if (not == match) +				return FNM_NOMATCH; +			break; +		default: +		literal: +			if (*s++ != c) +				return FNM_NOMATCH; +			if (c == no_slash && (flags & FNM_PERIOD)) { +				no_period = '.'; +				continue; +			} +			break; +		} +		no_period = 0x100; +	} +	if (*s) return FNM_NOMATCH; +	return 0; +} diff --git a/src/regex/glob.c b/src/regex/glob.c new file mode 100644 index 00000000..9a70f0bc --- /dev/null +++ b/src/regex/glob.c @@ -0,0 +1,238 @@ +#include <glob.h> +#include <fnmatch.h> +#include <sys/stat.h> +#include <dirent.h> +#include <limits.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <stddef.h> +#include <unistd.h> +#include <stdio.h> +#include "libc.h" + +struct match +{ +	struct match *next; +	char name[1]; +}; + +static int is_literal(const char *p, int useesc) +{ +	int bracket = 0; +	for (; *p; p++) { +		switch (*p) { +		case '\\': +			if (!useesc) break; +		case '?': +		case '*': +			return 0; +		case '[': +			bracket = 1; +			break; +		case ']': +			if (bracket) return 0; +			break; +		} +	} +	return 1; +} + +static int append(struct match **tail, const char *name, size_t len, int mark) +{ +	struct match *new = malloc(sizeof(struct match) + len + 1); +	if (!new) return -1; +	(*tail)->next = new; +	new->next = NULL; +	strcpy(new->name, name); +	if (mark) strcat(new->name, "/"); +	*tail = new; +	return 0; +} + +static int match_in_dir(const char *d, const char *p, int flags, int (*errfunc)(const char *path, int err), struct match **tail) +{ +	DIR *dir; +	long long de_buf[(sizeof(struct dirent) + NAME_MAX + sizeof(long long))/sizeof(long long)]; +	struct dirent *de; +	char pat[strlen(p)+1]; +	char *p2; +	size_t l = strlen(d); +	int literal; +	int fnm_flags= ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) | FNM_PERIOD; +	int error; + +	if ((p2 = strchr(p, '/'))) { +		strcpy(pat, p); +		pat[p2-p] = 0; +		for (; *p2 == '/'; p2++); +		p = pat; +	} +	literal = is_literal(p, !(flags & GLOB_NOESCAPE)); +	if (*d == '/' && !*(d+1)) l = 0; + +	/* rely on opendir failing for nondirectory objects */ +	dir = opendir(*d ? d : "."); +	error = errno; +	if (!dir) { +		/* this is not an error -- we let opendir call stat for us */ +		if (error == ENOTDIR) return 0; +		if (error == EACCES && !*p) { +			struct stat st; +			if (!stat(d, &st) && S_ISDIR(st.st_mode)) { +				if (append(tail, d, l, l)) +					return GLOB_NOSPACE; +				return 0; +			} +		} +		if (errfunc(d, error) || (flags & GLOB_ERR)) +			return GLOB_ABORTED; +		return 0; +	} +	if (!*p) { +		error = append(tail, d, l, l) ? GLOB_NOSPACE : 0; +		closedir(dir); +		return error; +	} +	while (!(error = readdir_r(dir, (void *)de_buf, &de)) && de) { +		char namebuf[l+de->d_reclen+2], *name = namebuf; +		if (!literal && fnmatch(p, de->d_name, fnm_flags)) +			continue; +		if (literal && strcmp(p, de->d_name)) +			continue; +		if (p2 && de->d_type && !S_ISDIR(de->d_type<<12) && !S_ISLNK(de->d_type<<12)) +			continue; +		if (*d) { +			memcpy(name, d, l); +			name[l] = '/'; +			strcpy(name+l+1, de->d_name); +		} else { +			name = de->d_name; +		} +		if (p2) { +			if ((error = match_in_dir(name, p2, flags, errfunc, tail))) { +				closedir(dir); +				return error; +			} +		} else { +			int mark = 0; +			if (flags & GLOB_MARK) { +				if (de->d_type) +					mark = S_ISDIR(de->d_type<<12); +				else { +					struct stat st; +					stat(name, &st); +					mark = S_ISDIR(st.st_mode); +				} +			} +			if (append(tail, name, l+de->d_reclen+1, mark)) { +				closedir(dir); +				return GLOB_NOSPACE; +			} +		} +	} +	closedir(dir); +	if (error && (errfunc(d, error) || (flags & GLOB_ERR))) +		return GLOB_ABORTED; +	return 0; +} + +static int ignore_err(const char *path, int err) +{ +	return 0; +} + +static void freelist(struct match *head) +{ +	struct match *match, *next; +	for (match=head->next; match; match=next) { +		next = match->next; +		free(match); +	} +} + +static int sort(const void *a, const void *b) +{ +	return strcmp(*(const char **)a, *(const char **)b); +} + +int glob(const char *pat, int flags, int (*errfunc)(const char *path, int err), glob_t *g) +{ +	const char *p=pat, *d; +	struct match head = { .next = NULL }, *tail = &head; +	size_t cnt, i; +	size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0; +	int error = 0; +	 +	if (*p == '/') { +		for (; *p == '/'; p++); +		d = "/"; +	} else { +		d = ""; +	} + +	if (!errfunc) errfunc = ignore_err; + +	if (!(flags & GLOB_APPEND)) { +		g->gl_offs = offs; +		g->gl_pathc = 0; +		g->gl_pathv = NULL; +	} + +	if (*p) error = match_in_dir(d, p, flags, errfunc, &tail); +	if (error == GLOB_NOSPACE) { +		freelist(&head); +		return error; +	} +	 +	for (cnt=0, tail=head.next; tail; tail=tail->next, cnt++); +	if (!cnt) { +		if (flags & GLOB_NOCHECK) { +			tail = &head; +			if (append(&tail, pat, strlen(pat), 0)) +				return GLOB_NOSPACE; +			cnt++; +		} else +			return GLOB_NOMATCH; +	} + +	if (flags & GLOB_APPEND) { +		char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *)); +		if (!pathv) { +			freelist(&head); +			return GLOB_NOSPACE; +		} +		g->gl_pathv = pathv; +		offs += g->gl_pathc; +	} else { +		g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *)); +		if (!g->gl_pathv) { +			freelist(&head); +			return GLOB_NOSPACE; +		} +		for (i=0; i<offs; i++) +			g->gl_pathv[i] = NULL; +	} +	for (i=0, tail=head.next; i<cnt; tail=tail->next, i++) +		g->gl_pathv[offs + i] = tail->name; +	g->gl_pathv[offs + i] = NULL; +	g->gl_pathc += cnt; + +	if (!(flags & GLOB_NOSORT)) +		qsort(g->gl_pathv+offs, cnt, sizeof(char *), sort); +	 +	return error; +} + +void globfree(glob_t *g) +{ +	size_t i; +	for (i=0; i<g->gl_pathc; i++) +		free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name)); +	free(g->gl_pathv); +	g->gl_pathc = 0; +	g->gl_pathv = NULL; +} + +LFS64(glob); +LFS64(globfree); diff --git a/src/regex/regcomp.c b/src/regex/regcomp.c new file mode 100644 index 00000000..3307942e --- /dev/null +++ b/src/regex/regcomp.c @@ -0,0 +1,3362 @@ +/* +  regcomp.c - TRE POSIX compatible regex compilation functions. + +  Copyright (c) 2001-2006 Ville Laurikari <vl@iki.fi> + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 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 +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + +*/ + +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <regex.h> +#include <limits.h> +#include <stdint.h> + +#include "tre.h" + +#include <assert.h> + +/*********************************************************************** + from tre-ast.c and tre-ast.h +***********************************************************************/ + +/* The different AST node types. */ +typedef enum { +  LITERAL, +  CATENATION, +  ITERATION, +  UNION +} tre_ast_type_t; + +/* Special subtypes of TRE_LITERAL. */ +#define EMPTY	  -1   /* Empty leaf (denotes empty string). */ +#define ASSERTION -2   /* Assertion leaf. */ +#define TAG	  -3   /* Tag leaf. */ +#define BACKREF	  -4   /* Back reference leaf. */ + +#define IS_SPECIAL(x)	((x)->code_min < 0) +#define IS_EMPTY(x)	((x)->code_min == EMPTY) +#define IS_ASSERTION(x) ((x)->code_min == ASSERTION) +#define IS_TAG(x)	((x)->code_min == TAG) +#define IS_BACKREF(x)	((x)->code_min == BACKREF) + +/* Taken from tre-compile.h */ +typedef struct { +  int position; +  int code_min; +  int code_max; +  int *tags; +  int assertions; +  tre_ctype_t class; +  tre_ctype_t *neg_classes; +  int backref; +} tre_pos_and_tags_t; + +/* A generic AST node.  All AST nodes consist of this node on the top +   level with `obj' pointing to the actual content. */ +typedef struct { +  tre_ast_type_t type;   /* Type of the node. */ +  void *obj;             /* Pointer to actual node. */ +  int nullable; +  int submatch_id; +  int num_submatches; +  int num_tags; +  tre_pos_and_tags_t *firstpos; +  tre_pos_and_tags_t *lastpos; +} tre_ast_node_t; + + +/* A "literal" node.  These are created for assertions, back references, +   tags, matching parameter settings, and all expressions that match one +   character. */ +typedef struct { +  long code_min; +  long code_max; +  int position; +  tre_ctype_t class; +  tre_ctype_t *neg_classes; +} tre_literal_t; + +/* A "catenation" node.	 These are created when two regexps are concatenated. +   If there are more than one subexpressions in sequence, the `left' part +   holds all but the last, and `right' part holds the last subexpression +   (catenation is left associative). */ +typedef struct { +  tre_ast_node_t *left; +  tre_ast_node_t *right; +} tre_catenation_t; + +/* An "iteration" node.	 These are created for the "*", "+", "?", and "{m,n}" +   operators. */ +typedef struct { +  /* Subexpression to match. */ +  tre_ast_node_t *arg; +  /* Minimum number of consecutive matches. */ +  int min; +  /* Maximum number of consecutive matches. */ +  int max; +} tre_iteration_t; + +/* An "union" node.  These are created for the "|" operator. */ +typedef struct { +  tre_ast_node_t *left; +  tre_ast_node_t *right; +} tre_union_t; + +static tre_ast_node_t * +tre_ast_new_node(tre_mem_t mem, tre_ast_type_t type, size_t size) +{ +  tre_ast_node_t *node; + +  node = tre_mem_calloc(mem, sizeof(*node)); +  if (!node) +    return NULL; +  node->obj = tre_mem_calloc(mem, size); +  if (!node->obj) +    return NULL; +  node->type = type; +  node->nullable = -1; +  node->submatch_id = -1; + +  return node; +} + +static tre_ast_node_t * +tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position) +{ +  tre_ast_node_t *node; +  tre_literal_t *lit; + +  node = tre_ast_new_node(mem, LITERAL, sizeof(tre_literal_t)); +  if (!node) +    return NULL; +  lit = node->obj; +  lit->code_min = code_min; +  lit->code_max = code_max; +  lit->position = position; + +  return node; +} + +static tre_ast_node_t * +tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max) +{ +  tre_ast_node_t *node; +  tre_iteration_t *iter; + +  node = tre_ast_new_node(mem, ITERATION, sizeof(tre_iteration_t)); +  if (!node) +    return NULL; +  iter = node->obj; +  iter->arg = arg; +  iter->min = min; +  iter->max = max; +  node->num_submatches = arg->num_submatches; + +  return node; +} + +static tre_ast_node_t * +tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right) +{ +  tre_ast_node_t *node; + +  node = tre_ast_new_node(mem, UNION, sizeof(tre_union_t)); +  if (node == NULL) +    return NULL; +  ((tre_union_t *)node->obj)->left = left; +  ((tre_union_t *)node->obj)->right = right; +  node->num_submatches = left->num_submatches + right->num_submatches; + +  return node; +} + +static tre_ast_node_t * +tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left, +		       tre_ast_node_t *right) +{ +  tre_ast_node_t *node; + +  node = tre_ast_new_node(mem, CATENATION, sizeof(tre_catenation_t)); +  if (node == NULL) +    return NULL; +  ((tre_catenation_t *)node->obj)->left = left; +  ((tre_catenation_t *)node->obj)->right = right; +  node->num_submatches = left->num_submatches + right->num_submatches; + +  return node; +} + +/*********************************************************************** + from tre-stack.c and tre-stack.h +***********************************************************************/ + +/* Just to save some typing. */ +#define STACK_PUSH(s, value)						      \ +  do									      \ +    {									      \ +      status = tre_stack_push(s, (void *)(value));			      \ +    }									      \ +  while (0) + +#define STACK_PUSHX(s, value)						      \ +  {									      \ +    status = tre_stack_push(s, (void *)(value));			      \ +    if (status != REG_OK)						      \ +      break;								      \ +  } + +#define STACK_PUSHR(s, value)						      \ +  {									      \ +    reg_errcode_t status;						      \ +    status = tre_stack_push(s, (void *)(value));			      \ +    if (status != REG_OK)						      \ +      return status;							      \ +  } + +typedef struct tre_stack_rec { +  int size; +  int max_size; +  int increment; +  int ptr; +  void **stack; +} tre_stack_t; + + +static tre_stack_t * +tre_stack_new(int size, int max_size, int increment) +{ +  tre_stack_t *s; + +  s = xmalloc(sizeof(*s)); +  if (s != NULL) +    { +      s->stack = xmalloc(sizeof(*s->stack) * size); +      if (s->stack == NULL) +	{ +	  xfree(s); +	  return NULL; +	} +      s->size = size; +      s->max_size = max_size; +      s->increment = increment; +      s->ptr = 0; +    } +  return s; +} + +static void +tre_stack_destroy(tre_stack_t *s) +{ +  xfree(s->stack); +  xfree(s); +} + +static int +tre_stack_num_objects(tre_stack_t *s) +{ +  return s->ptr; +} + +static reg_errcode_t +tre_stack_push(tre_stack_t *s, void *value) +{ +  if (s->ptr < s->size) +    { +      s->stack[s->ptr] = value; +      s->ptr++; +    } +  else +    { +      if (s->size >= s->max_size) +	{ +	  DPRINT(("tre_stack_push: stack full\n")); +	  return REG_ESPACE; +	} +      else +	{ +	  void **new_buffer; +	  int new_size; +	  DPRINT(("tre_stack_push: trying to realloc more space\n")); +	  new_size = s->size + s->increment; +	  if (new_size > s->max_size) +	    new_size = s->max_size; +	  new_buffer = xrealloc(s->stack, sizeof(*new_buffer) * new_size); +	  if (new_buffer == NULL) +	    { +	      DPRINT(("tre_stack_push: realloc failed.\n")); +	      return REG_ESPACE; +	    } +	  DPRINT(("tre_stack_push: realloc succeeded.\n")); +	  assert(new_size > s->size); +	  s->size = new_size; +	  s->stack = new_buffer; +	  tre_stack_push(s, value); +	} +    } +  return REG_OK; +} + +static void * +tre_stack_pop(tre_stack_t *s) +{ +  return s->stack[--s->ptr]; +} + + +/*********************************************************************** + from tre-parse.c and tre-parse.h +***********************************************************************/ + +/* Parse context. */ +typedef struct { +  /* Memory allocator.	The AST is allocated using this. */ +  tre_mem_t mem; +  /* Stack used for keeping track of regexp syntax. */ +  tre_stack_t *stack; +  /* The parse result. */ +  tre_ast_node_t *result; +  /* The regexp to parse and its length. */ +  const tre_char_t *re; +  /* The first character of the entire regexp. */ +  const tre_char_t *re_start; +  /* The first character after the end of the regexp. */ +  const tre_char_t *re_end; +  int len; +  /* Current submatch ID. */ +  int submatch_id; +  /* Current position (number of literal). */ +  int position; +  /* The highest back reference or -1 if none seen so far. */ +  int max_backref; +  /* Compilation flags. */ +  int cflags; +  /* If this flag is set the top-level submatch is not captured. */ +  int nofirstsub; +} tre_parse_ctx_t; + +static reg_errcode_t +tre_new_item(tre_mem_t mem, int min, int max, int *i, int *max_i, +	 tre_ast_node_t ***items) +{ +  reg_errcode_t status; +  tre_ast_node_t **array = *items; +  /* Allocate more space if necessary. */ +  if (*i >= *max_i) +    { +      tre_ast_node_t **new_items; +      DPRINT(("out of array space, i = %d\n", *i)); +      /* If the array is already 1024 items large, give up -- there's +	 probably an error in the regexp (e.g. not a '\0' terminated +	 string and missing ']') */ +      if (*max_i > 1024) +	return REG_ESPACE; +      *max_i *= 2; +      new_items = xrealloc(array, sizeof(*items) * *max_i); +      if (new_items == NULL) +	return REG_ESPACE; +      *items = array = new_items; +    } +  array[*i] = tre_ast_new_literal(mem, min, max, -1); +  status = array[*i] == NULL ? REG_ESPACE : REG_OK; +  (*i)++; +  return status; +} + + +/* Expands a character class to character ranges. */ +static reg_errcode_t +tre_expand_ctype(tre_mem_t mem, tre_ctype_t class, tre_ast_node_t ***items, +		 int *i, int *max_i, int cflags) +{ +  reg_errcode_t status = REG_OK; +  tre_cint_t c; +  int j, min = -1, max = 0; +  assert(TRE_MB_CUR_MAX == 1); + +  DPRINT(("  expanding class to character ranges\n")); +  for (j = 0; (j < 256) && (status == REG_OK); j++) +    { +      c = j; +      if (tre_isctype(c, class) +	  || ((cflags & REG_ICASE) +	      && (tre_isctype(tre_tolower(c), class) +		  || tre_isctype(tre_toupper(c), class)))) +{ +	  if (min < 0) +	    min = c; +	  max = c; +	} +      else if (min >= 0) +	{ +	  DPRINT(("  range %c (%d) to %c (%d)\n", min, min, max, max)); +	  status = tre_new_item(mem, min, max, i, max_i, items); +	  min = -1; +	} +    } +  if (min >= 0 && status == REG_OK) +    status = tre_new_item(mem, min, max, i, max_i, items); +  return status; +} + + +static int +tre_compare_items(const void *a, const void *b) +{ +  tre_ast_node_t *node_a = *(tre_ast_node_t **)a; +  tre_ast_node_t *node_b = *(tre_ast_node_t **)b; +  tre_literal_t *l_a = node_a->obj, *l_b = node_b->obj; +  int a_min = l_a->code_min, b_min = l_b->code_min; + +  if (a_min < b_min) +    return -1; +  else if (a_min > b_min) +    return 1; +  else +    return 0; +} + +/* Maximum number of character classes that can occur in a negated bracket +   expression.	*/ +#define MAX_NEG_CLASSES 64 + +/* Maximum length of character class names. */ +#define MAX_CLASS_NAME + +static reg_errcode_t +tre_parse_bracket_items(tre_parse_ctx_t *ctx, int negate, +			tre_ctype_t neg_classes[], int *num_neg_classes, +			tre_ast_node_t ***items, int *num_items, +			int *items_size) +{ +  const tre_char_t *re = ctx->re; +  reg_errcode_t status = REG_OK; +  tre_ctype_t class = (tre_ctype_t)0; +  int i = *num_items; +  int max_i = *items_size; +  int skip; + +  /* Build an array of the items in the bracket expression. */ +  while (status == REG_OK) +    { +      skip = 0; +      if (re == ctx->re_end) +	{ +	  status = REG_EBRACK; +	} +      else if (*re == ']' && re > ctx->re) +	{ +	  DPRINT(("tre_parse_bracket:	done: '%.*" STRF "'\n", +		  ctx->re_end - re, re)); +	  re++; +	  break; +	} +      else +	{ +	  tre_cint_t min = 0, max = 0; + +	  class = (tre_ctype_t)0; +	  if (re + 2 < ctx->re_end +	      && *(re + 1) == '-' && *(re + 2) != ']') +	    { +	      DPRINT(("tre_parse_bracket:  range: '%.*" STRF "'\n", +		      ctx->re_end - re, re)); +	      min = *re; +	      max = *(re + 2); +	      re += 3; +	      /* XXX - Should use collation order instead of encoding values +		 in character ranges. */ +	      if (min > max) +		status = REG_ERANGE; +	    } +	  else if (re + 1 < ctx->re_end +		   && *re == '[' && *(re + 1) == '.') +	    status = REG_ECOLLATE; +	  else if (re + 1 < ctx->re_end +		   && *re == '[' && *(re + 1) == '=') +	    status = REG_ECOLLATE; +	  else if (re + 1 < ctx->re_end +		   && *re == '[' && *(re + 1) == ':') +	    { +	      char tmp_str[64]; +	      const tre_char_t *endptr = re + 2; +	      int len; +	      DPRINT(("tre_parse_bracket:  class: '%.*" STRF "'\n", +		      ctx->re_end - re, re)); +	      while (endptr < ctx->re_end && *endptr != ':') +		endptr++; +	      if (endptr != ctx->re_end) +		{ +		  len = MIN(endptr - re - 2, 63); +#ifdef TRE_WCHAR +		  { +		    tre_char_t tmp_wcs[64]; +		    wcsncpy(tmp_wcs, re + 2, len); +		    tmp_wcs[len] = '\0'; +#if defined HAVE_WCSRTOMBS +		    { +		      mbstate_t state; +		      const tre_char_t *src = tmp_wcs; +		      memset(&state, '\0', sizeof(state)); +		      len = wcsrtombs(tmp_str, &src, sizeof(tmp_str), &state); +		    } +#elif defined HAVE_WCSTOMBS +		    len = wcstombs(tmp_str, tmp_wcs, 63); +#endif /* defined HAVE_WCSTOMBS */ +		  } +#else /* !TRE_WCHAR */ +		  strncpy(tmp_str, re + 2, len); +#endif /* !TRE_WCHAR */ +		  tmp_str[len] = '\0'; +		  DPRINT(("  class name: %s\n", tmp_str)); +		  class = tre_ctype(tmp_str); +		  if (!class) +		    status = REG_ECTYPE; +		  /* Optimize character classes for 8 bit character sets. */ +		  if (status == REG_OK && TRE_MB_CUR_MAX == 1) +		    { +		      status = tre_expand_ctype(ctx->mem, class, items, +						&i, &max_i, ctx->cflags); +		      class = (tre_ctype_t)0; +		      skip = 1; +		    } +		  re = endptr + 2; +		} +	      else +		status = REG_ECTYPE; +	      min = 0; +	      max = TRE_CHAR_MAX; +	    } +	  else +	    { +	      DPRINT(("tre_parse_bracket:   char: '%.*" STRF "'\n", +		      ctx->re_end - re, re)); +	      if (*re == '-' && *(re + 1) != ']' +		  && ctx->re != re) +		/* Two ranges are not allowed to share and endpoint. */ +		status = REG_ERANGE; +	      min = max = *re++; +	    } + +	  if (status != REG_OK) +	    break; + +	  if (class && negate) +	    if (*num_neg_classes >= MAX_NEG_CLASSES) +	      status = REG_ESPACE; +	    else +	      neg_classes[(*num_neg_classes)++] = class; +	  else if (!skip) +	    { +	      status = tre_new_item(ctx->mem, min, max, &i, &max_i, items); +	      if (status != REG_OK) +		break; +	      ((tre_literal_t*)((*items)[i-1])->obj)->class = class; +	    } + +	  /* Add opposite-case counterpoints if REG_ICASE is present. +	     This is broken if there are more than two "same" characters. */ +	  if (ctx->cflags & REG_ICASE && !class && status == REG_OK && !skip) +	    { +	      int cmin, ccurr; + +	      DPRINT(("adding opposite-case counterpoints\n")); +	      while (min <= max) +		{ +		  if (tre_islower(min)) +		    { +		      cmin = ccurr = tre_toupper(min++); +		      while (tre_islower(min) && tre_toupper(min) == ccurr + 1 +			     && min <= max) +			ccurr = tre_toupper(min++); +		      status = tre_new_item(ctx->mem, cmin, ccurr, +					    &i, &max_i, items); +		    } +		  else if (tre_isupper(min)) +		    { +		      cmin = ccurr = tre_tolower(min++); +		      while (tre_isupper(min) && tre_tolower(min) == ccurr + 1 +			     && min <= max) +			ccurr = tre_tolower(min++); +		      status = tre_new_item(ctx->mem, cmin, ccurr, +					    &i, &max_i, items); +		    } +		  else min++; +		  if (status != REG_OK) +		    break; +		} +	      if (status != REG_OK) +		break; +	    } +	} +    } +  *num_items = i; +  *items_size = max_i; +  ctx->re = re; +  return status; +} + +static reg_errcode_t +tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result) +{ +  tre_ast_node_t *node = NULL; +  int negate = 0; +  reg_errcode_t status = REG_OK; +  tre_ast_node_t **items, *u, *n; +  int i = 0, j, max_i = 32, curr_max, curr_min; +  tre_ctype_t neg_classes[MAX_NEG_CLASSES]; +  int num_neg_classes = 0; + +  /* Start off with an array of `max_i' elements. */ +  items = xmalloc(sizeof(*items) * max_i); +  if (items == NULL) +    return REG_ESPACE; + +  if (*ctx->re == '^') +    { +      DPRINT(("tre_parse_bracket: negate: '%.*" STRF "'\n", +	      ctx->re_end - ctx->re, ctx->re)); +      negate = 1; +      ctx->re++; +    } + +  status = tre_parse_bracket_items(ctx, negate, neg_classes, &num_neg_classes, +				   &items, &i, &max_i); + +  if (status != REG_OK) +    goto parse_bracket_done; + +  /* Sort the array if we need to negate it. */ +  if (negate) +    qsort(items, i, sizeof(*items), tre_compare_items); + +  curr_max = curr_min = 0; +  /* Build a union of the items in the array, negated if necessary. */ +  for (j = 0; j < i && status == REG_OK; j++) +    { +      int min, max; +      tre_literal_t *l = items[j]->obj; +      min = l->code_min; +      max = l->code_max; + +      DPRINT(("item: %d - %d, class %ld, curr_max = %d\n", +	      (int)l->code_min, (int)l->code_max, (long)l->class, curr_max)); + +      if (negate) +	{ +	  if (min < curr_max) +	    { +	      /* Overlap. */ +	      curr_max = MAX(max + 1, curr_max); +	      DPRINT(("overlap, curr_max = %d\n", curr_max)); +	      l = NULL; +	    } +	  else +	    { +	      /* No overlap. */ +	      curr_max = min - 1; +	      if (curr_max >= curr_min) +		{ +		  DPRINT(("no overlap\n")); +		  l->code_min = curr_min; +		  l->code_max = curr_max; +		} +	      else +		{ +		  DPRINT(("no overlap, zero room\n")); +		  l = NULL; +		} +	      curr_min = curr_max = max + 1; +	    } +	} + +      if (l != NULL) +	{ +	  int k; +	  DPRINT(("creating %d - %d\n", (int)l->code_min, (int)l->code_max)); +	  l->position = ctx->position; +	  if (num_neg_classes > 0) +	    { +	      l->neg_classes = tre_mem_alloc(ctx->mem, +					     (sizeof(l->neg_classes) +					      * (num_neg_classes + 1))); +	      if (l->neg_classes == NULL) +		{ +		  status = REG_ESPACE; +		  break; +		} +	      for (k = 0; k < num_neg_classes; k++) +		l->neg_classes[k] = neg_classes[k]; +	      l->neg_classes[k] = (tre_ctype_t)0; +	    } +	  else +	    l->neg_classes = NULL; +	  if (node == NULL) +	    node = items[j]; +	  else +	    { +	      u = tre_ast_new_union(ctx->mem, node, items[j]); +	      if (u == NULL) +		status = REG_ESPACE; +	      node = u; +	    } +	} +    } + +  if (status != REG_OK) +    goto parse_bracket_done; + +  if (negate) +    { +      int k; +      DPRINT(("final: creating %d - %d\n", curr_min, (int)TRE_CHAR_MAX)); +      n = tre_ast_new_literal(ctx->mem, curr_min, TRE_CHAR_MAX, ctx->position); +      if (n == NULL) +	status = REG_ESPACE; +      else +	{ +	  tre_literal_t *l = n->obj; +	  if (num_neg_classes > 0) +	    { +	      l->neg_classes = tre_mem_alloc(ctx->mem, +					     (sizeof(l->neg_classes) +					      * (num_neg_classes + 1))); +	      if (l->neg_classes == NULL) +		{ +		  status = REG_ESPACE; +		  goto parse_bracket_done; +		} +	      for (k = 0; k < num_neg_classes; k++) +		l->neg_classes[k] = neg_classes[k]; +	      l->neg_classes[k] = (tre_ctype_t)0; +	    } +	  else +	    l->neg_classes = NULL; +	  if (node == NULL) +	    node = n; +	  else +	    { +	      u = tre_ast_new_union(ctx->mem, node, n); +	      if (u == NULL) +		status = REG_ESPACE; +	      node = u; +	    } +	} +    } + +  if (status != REG_OK) +    goto parse_bracket_done; + +#ifdef TRE_DEBUG +  tre_ast_print(node); +#endif /* TRE_DEBUG */ + + parse_bracket_done: +  xfree(items); +  ctx->position++; +  *result = node; +  return status; +} + + +/* Parses a positive decimal integer.  Returns -1 if the string does not +   contain a valid number. */ +static int +tre_parse_int(const tre_char_t **regex, const tre_char_t *regex_end) +{ +  int num = -1; +  const tre_char_t *r = *regex; +  while (r < regex_end && *r >= '0' && *r <= '9') +    { +      if (num < 0) +	num = 0; +      num = num * 10 + *r - '0'; +      r++; +    } +  *regex = r; +  return num; +} + + +static reg_errcode_t +tre_parse_bound(tre_parse_ctx_t *ctx, tre_ast_node_t **result) +{ +  int min, max; +  const tre_char_t *r = ctx->re; +  const tre_char_t *start; +  int counts_set = 0; + +  /* Parse number (minimum repetition count). */ +  min = -1; +  if (r < ctx->re_end && *r >= '0' && *r <= '9') { +    DPRINT(("tre_parse:	  min count: '%.*" STRF "'\n", ctx->re_end - r, r)); +    min = tre_parse_int(&r, ctx->re_end); +  } + +  /* Parse comma and second number (maximum repetition count). */ +  max = min; +  if (r < ctx->re_end && *r == ',') +    { +      r++; +      DPRINT(("tre_parse:   max count: '%.*" STRF "'\n", ctx->re_end - r, r)); +      max = tre_parse_int(&r, ctx->re_end); +    } + +  /* Check that the repeat counts are sane. */ +  if ((max >= 0 && min > max) || max > RE_DUP_MAX) +    return REG_BADBR; + + +  /* +   '{' +     optionally followed immediately by a number == minimum repcount +     optionally followed by , then a number == maximum repcount +  */ + + +  do { +    int done; +    start = r; + +    /* Parse count limit settings */ +    done = 0; +    if (!counts_set) +      while (r + 1 < ctx->re_end && !done) +	{ +	  switch (*r) +	    { +	    case ',': +	      r++; +	      break; +	    case ' ': +	      r++; +	      break; +	    case '}': +	      done = 1; +	      break; +	    default: +	      done = 1; +	      break; +	    } +	} +  } while (start != r); + +  /* Missing }. */ +  if (r >= ctx->re_end) +    return REG_EBRACE; + +  /* Empty contents of {}. */ +  if (r == ctx->re) +    return REG_BADBR; + +  /* Parse the ending '}' or '\}'.*/ +  if (ctx->cflags & REG_EXTENDED) +    { +      if (r >= ctx->re_end || *r != '}') +	return REG_BADBR; +      r++; +    } +  else +    { +      if (r + 1 >= ctx->re_end +	  || *r != '\\' +	  || *(r + 1) != '}') +	return REG_BADBR; +      r += 2; +    } + + +  /* Create the AST node(s). */ +  if (min == 0 && max == 0) +    { +      *result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); +      if (*result == NULL) +	return REG_ESPACE; +    } +  else +    { +      if (min < 0 && max < 0) +	/* Only approximate parameters set, no repetitions. */ +	min = max = 1; + +      *result = tre_ast_new_iter(ctx->mem, *result, min, max); +      if (!*result) +	return REG_ESPACE; +    } + +  ctx->re = r; +  return REG_OK; +} + +typedef enum { +  PARSE_RE = 0, +  PARSE_ATOM, +  PARSE_MARK_FOR_SUBMATCH, +  PARSE_BRANCH, +  PARSE_PIECE, +  PARSE_CATENATION, +  PARSE_POST_CATENATION, +  PARSE_UNION, +  PARSE_POST_UNION, +  PARSE_POSTFIX, +  PARSE_RESTORE_CFLAGS +} tre_parse_re_stack_symbol_t; + + +static reg_errcode_t +tre_parse(tre_parse_ctx_t *ctx) +{ +  tre_ast_node_t *result = NULL; +  tre_parse_re_stack_symbol_t symbol; +  reg_errcode_t status = REG_OK; +  tre_stack_t *stack = ctx->stack; +  int bottom = tre_stack_num_objects(stack); +  int depth = 0; + +  DPRINT(("tre_parse: parsing '%.*" STRF "', len = %d\n", +	  ctx->len, ctx->re, ctx->len)); + +  if (!ctx->nofirstsub) +    { +      STACK_PUSH(stack, ctx->re); +      STACK_PUSH(stack, ctx->submatch_id); +      STACK_PUSH(stack, PARSE_MARK_FOR_SUBMATCH); +      ctx->submatch_id++; +    } +  STACK_PUSH(stack, PARSE_RE); +  ctx->re_start = ctx->re; +  ctx->re_end = ctx->re + ctx->len; + + +  /* The following is basically just a recursive descent parser.  I use +     an explicit stack instead of recursive functions mostly because of +     two reasons: compatibility with systems which have an overflowable +     call stack, and efficiency (both in lines of code and speed).  */ +  while (tre_stack_num_objects(stack) > bottom && status == REG_OK) +    { +      if (status != REG_OK) +	break; +      symbol = (tre_parse_re_stack_symbol_t)tre_stack_pop(stack); +      switch (symbol) +	{ +	case PARSE_RE: +	  /* Parse a full regexp.  A regexp is one or more branches, +	     separated by the union operator `|'. */ +	  if (ctx->cflags & REG_EXTENDED) +	    STACK_PUSHX(stack, PARSE_UNION); +	  STACK_PUSHX(stack, PARSE_BRANCH); +	  break; + +	case PARSE_BRANCH: +	  /* Parse a branch.  A branch is one or more pieces, concatenated. +	     A piece is an atom possibly followed by a postfix operator. */ +	  STACK_PUSHX(stack, PARSE_CATENATION); +	  STACK_PUSHX(stack, PARSE_PIECE); +	  break; + +	case PARSE_PIECE: +	  /* Parse a piece.  A piece is an atom possibly followed by one +	     or more postfix operators. */ +	  STACK_PUSHX(stack, PARSE_POSTFIX); +	  STACK_PUSHX(stack, PARSE_ATOM); +	  break; + +	case PARSE_CATENATION: +	  /* If the expression has not ended, parse another piece. */ +	  { +	    tre_char_t c; +	    if (ctx->re >= ctx->re_end) +	      break; +	    c = *ctx->re; +	    if (ctx->cflags & REG_EXTENDED && c == '|') +	      break; +	    if ((ctx->cflags & REG_EXTENDED +	         && c == ')' && depth > 0) +	        || (!(ctx->cflags & REG_EXTENDED) +		    && (c == '\\' +		        && *(ctx->re + 1) == ')'))) +	      { +	        if (!(ctx->cflags & REG_EXTENDED) && depth == 0) +	          status = REG_EPAREN; +	        DPRINT(("tre_parse:	  group end: '%.*" STRF "'\n", +		        ctx->re_end - ctx->re, ctx->re)); +	        depth--; +	        if (!(ctx->cflags & REG_EXTENDED)) +	          ctx->re += 2; +	        break; +	      } + +	    /* Left associative concatenation. */ +	    STACK_PUSHX(stack, PARSE_CATENATION); +	    STACK_PUSHX(stack, result); +	    STACK_PUSHX(stack, PARSE_POST_CATENATION); +	    STACK_PUSHX(stack, PARSE_PIECE); +	    break; +	  } + +	case PARSE_POST_CATENATION: +	  { +	    tre_ast_node_t *tree = tre_stack_pop(stack); +	    tre_ast_node_t *tmp_node; +	    tmp_node = tre_ast_new_catenation(ctx->mem, tree, result); +	    if (!tmp_node) +	      return REG_ESPACE; +	    result = tmp_node; +	    break; +	  } + +	case PARSE_UNION: +	  if (ctx->re >= ctx->re_end) +	    break; +	  switch (*ctx->re) +	    { +	    case '|': +	      DPRINT(("tre_parse:	union: '%.*" STRF "'\n", +		      ctx->re_end - ctx->re, ctx->re)); +	      STACK_PUSHX(stack, PARSE_UNION); +	      STACK_PUSHX(stack, result); +	      STACK_PUSHX(stack, PARSE_POST_UNION); +	      STACK_PUSHX(stack, PARSE_BRANCH); +	      ctx->re++; +	      break; + +	    case ')': +	      ctx->re++; +	      break; + +	    default: +	      break; +	    } +	  break; + +	case PARSE_POST_UNION: +	  { +	    tre_ast_node_t *tmp_node; +	    tre_ast_node_t *tree = tre_stack_pop(stack); +	    tmp_node = tre_ast_new_union(ctx->mem, tree, result); +	    if (!tmp_node) +	      return REG_ESPACE; +	    result = tmp_node; +	    break; +	  } + +	case PARSE_POSTFIX: +	  /* Parse postfix operators. */ +	  if (ctx->re >= ctx->re_end) +	    break; +	  switch (*ctx->re) +	    { +	    case '+': +	    case '?': +	      if (!(ctx->cflags & REG_EXTENDED)) +	        break; +	    case '*': +	      { +		tre_ast_node_t *tmp_node; +		int rep_min = 0; +		int rep_max = -1; +		if (*ctx->re == '+') +		  rep_min = 1; +		if (*ctx->re == '?') +		  rep_max = 1; + +		ctx->re++; +		tmp_node = tre_ast_new_iter(ctx->mem, result, rep_min, rep_max); +		if (tmp_node == NULL) +		  return REG_ESPACE; +		result = tmp_node; +		STACK_PUSHX(stack, PARSE_POSTFIX); +		break; +	      } + +	    case '\\': +	      /* "\{" is special without REG_EXTENDED */ +	      if (!(ctx->cflags & REG_EXTENDED) +		  && ctx->re + 1 < ctx->re_end +		  && *(ctx->re + 1) == '{') +		{ +		  ctx->re++; +		  goto parse_brace; +		} +	      else +		break; + +	    case '{': +	      /* "{" is literal without REG_EXTENDED */ +	      if (!(ctx->cflags & REG_EXTENDED)) +		break; + +	    parse_brace: +	      DPRINT(("tre_parse:	bound: '%.*" STRF "'\n", +		      ctx->re_end - ctx->re, ctx->re)); +	      ctx->re++; + +	      status = tre_parse_bound(ctx, &result); +	      if (status != REG_OK) +		return status; +	      STACK_PUSHX(stack, PARSE_POSTFIX); +	      break; +	    } +	  break; + +	case PARSE_ATOM: +	  /* Parse an atom.  An atom is a regular expression enclosed in `()', +	     an empty set of `()', a bracket expression, `.', `^', `$', +	     a `\' followed by a character, or a single character. */ + +	  /* End of regexp? (empty string). */ +	  if (ctx->re >= ctx->re_end) +	    goto parse_literal; + +	  switch (*ctx->re) +	    { +	    case '(':  /* parenthesized subexpression */ + +	      if (ctx->cflags & REG_EXTENDED +		  || (ctx->re > ctx->re_start +		      && *(ctx->re - 1) == '\\')) +		{ +		  depth++; +		    { +		      DPRINT(("tre_parse: group begin: '%.*" STRF +			      "', submatch %d\n", +			      ctx->re_end - ctx->re, ctx->re, +			      ctx->submatch_id)); +		      ctx->re++; +		      /* First parse a whole RE, then mark the resulting tree +			 for submatching. */ +		      STACK_PUSHX(stack, ctx->submatch_id); +		      STACK_PUSHX(stack, PARSE_MARK_FOR_SUBMATCH); +		      STACK_PUSHX(stack, PARSE_RE); +		      ctx->submatch_id++; +		    } +		} +	      else +		goto parse_literal; +	      break; + +	    case ')':  /* end of current subexpression */ +	      if ((ctx->cflags & REG_EXTENDED && depth > 0) +		  || (ctx->re > ctx->re_start +		      && *(ctx->re - 1) == '\\')) +		{ +		  DPRINT(("tre_parse:	    empty: '%.*" STRF "'\n", +			  ctx->re_end - ctx->re, ctx->re)); +		  /* We were expecting an atom, but instead the current +		     subexpression was closed.	POSIX leaves the meaning of +		     this to be implementation-defined.	 We interpret this as +		     an empty expression (which matches an empty string).  */ +		  result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); +		  if (result == NULL) +		    return REG_ESPACE; +		  if (!(ctx->cflags & REG_EXTENDED)) +		    ctx->re--; +		} +	      else +		goto parse_literal; +	      break; + +	    case '[': /* bracket expression */ +	      DPRINT(("tre_parse:     bracket: '%.*" STRF "'\n", +		      ctx->re_end - ctx->re, ctx->re)); +	      ctx->re++; +	      status = tre_parse_bracket(ctx, &result); +	      if (status != REG_OK) +		return status; +	      break; + +	    case '\\': +	      /* If this is "\(" or "\)" chew off the backslash and +		 try again. */ +	      if (!(ctx->cflags & REG_EXTENDED) +		  && ctx->re + 1 < ctx->re_end +		  && (*(ctx->re + 1) == '(' +		      || *(ctx->re + 1) == ')')) +		{ +		  ctx->re++; +		  STACK_PUSHX(stack, PARSE_ATOM); +		  break; +		} + +	      if (ctx->re + 1 >= ctx->re_end) +		/* Trailing backslash. */ +		return REG_EESCAPE; + +	      DPRINT(("tre_parse:  bleep: '%.*" STRF "'\n", +		      ctx->re_end - ctx->re, ctx->re)); +	      ctx->re++; +	      switch (*ctx->re) +		{ +		default: +		  if (!(ctx->cflags & REG_EXTENDED) && tre_isdigit(*ctx->re)) +		    { +		      /* Back reference. */ +		      int val = *ctx->re - '0'; +		      DPRINT(("tre_parse:     backref: '%.*" STRF "'\n", +			      ctx->re_end - ctx->re + 1, ctx->re - 1)); +		      result = tre_ast_new_literal(ctx->mem, BACKREF, val, +						   ctx->position); +		      if (result == NULL) +			return REG_ESPACE; +		      ctx->position++; +		      ctx->max_backref = MAX(val, ctx->max_backref); +		      ctx->re++; +		    } +		  else +		    { +		      /* Escaped character. */ +		      DPRINT(("tre_parse:     escaped: '%.*" STRF "'\n", +			      ctx->re_end - ctx->re + 1, ctx->re - 1)); +		      result = tre_ast_new_literal(ctx->mem, *ctx->re, *ctx->re, +						   ctx->position); +		      ctx->position++; +		      ctx->re++; +		    } +		  break; +		} +	      if (result == NULL) +		return REG_ESPACE; +	      break; + +	    case '.':	 /* the any-symbol */ +	      DPRINT(("tre_parse:	  any: '%.*" STRF "'\n", +		      ctx->re_end - ctx->re, ctx->re)); +	      if (ctx->cflags & REG_NEWLINE) +		{ +		  tre_ast_node_t *tmp1; +		  tre_ast_node_t *tmp2; +		  tmp1 = tre_ast_new_literal(ctx->mem, 0, '\n' - 1, +					     ctx->position); +		  if (!tmp1) +		    return REG_ESPACE; +		  tmp2 = tre_ast_new_literal(ctx->mem, '\n' + 1, TRE_CHAR_MAX, +					     ctx->position + 1); +		  if (!tmp2) +		    return REG_ESPACE; +		  result = tre_ast_new_union(ctx->mem, tmp1, tmp2); +		  if (!result) +		    return REG_ESPACE; +		  ctx->position += 2; +		} +	      else +		{ +		  result = tre_ast_new_literal(ctx->mem, 0, TRE_CHAR_MAX, +					       ctx->position); +		  if (!result) +		    return REG_ESPACE; +		  ctx->position++; +		} +	      ctx->re++; +	      break; + +	    case '^':	 /* beginning of line assertion */ +	      /* '^' has a special meaning everywhere in EREs, and in the +		 beginning of the RE and after \( is BREs. */ +	      if (ctx->cflags & REG_EXTENDED +		  || (ctx->re - 2 >= ctx->re_start +		      && *(ctx->re - 2) == '\\' +		      && *(ctx->re - 1) == '(') +		  || ctx->re == ctx->re_start) +		{ +		  DPRINT(("tre_parse:	      BOL: '%.*" STRF "'\n", +			  ctx->re_end - ctx->re, ctx->re)); +		  result = tre_ast_new_literal(ctx->mem, ASSERTION, +					       ASSERT_AT_BOL, -1); +		  if (result == NULL) +		    return REG_ESPACE; +		  ctx->re++; +		} +	      else +		goto parse_literal; +	      break; + +	    case '$':	 /* end of line assertion. */ +	      /* '$' is special everywhere in EREs, and in the end of the +		 string and before \) is BREs. */ +	      if (ctx->cflags & REG_EXTENDED +		  || (ctx->re + 2 < ctx->re_end +		      && *(ctx->re + 1) == '\\' +		      && *(ctx->re + 2) == ')') +		  || ctx->re + 1 == ctx->re_end) +		{ +		  DPRINT(("tre_parse:	      EOL: '%.*" STRF "'\n", +			  ctx->re_end - ctx->re, ctx->re)); +		  result = tre_ast_new_literal(ctx->mem, ASSERTION, +					       ASSERT_AT_EOL, -1); +		  if (result == NULL) +		    return REG_ESPACE; +		  ctx->re++; +		} +	      else +		goto parse_literal; +	      break; + +	    default: +	    parse_literal: + +	      /* We are expecting an atom.  If the subexpression (or the whole +		 regexp ends here, we interpret it as an empty expression +		 (which matches an empty string).  */ +	      if ( +		  (ctx->re >= ctx->re_end +		   || *ctx->re == '*' +		   || (ctx->cflags & REG_EXTENDED +		       && (*ctx->re == '|' +			   || *ctx->re == '{' +			   || *ctx->re == '+' +			   || *ctx->re == '?')) +		   /* Test for "\)" in BRE mode. */ +		   || (!(ctx->cflags & REG_EXTENDED) +		       && ctx->re + 1 < ctx->re_end +		       && *ctx->re == '\\' +		       && *(ctx->re + 1) == '{'))) +		{ +		  DPRINT(("tre_parse:	    empty: '%.*" STRF "'\n", +			  ctx->re_end - ctx->re, ctx->re)); +		  result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); +		  if (!result) +		    return REG_ESPACE; +		  break; +		} + +	      DPRINT(("tre_parse:     literal: '%.*" STRF "'\n", +		      ctx->re_end - ctx->re, ctx->re)); +	      /* Note that we can't use an tre_isalpha() test here, since there +		 may be characters which are alphabetic but neither upper or +		 lower case. */ +	      if (ctx->cflags & REG_ICASE +		  && (tre_isupper(*ctx->re) || tre_islower(*ctx->re))) +		{ +		  tre_ast_node_t *tmp1; +		  tre_ast_node_t *tmp2; + +		  /* XXX - Can there be more than one opposite-case +		     counterpoints for some character in some locale?  Or +		     more than two characters which all should be regarded +		     the same character if case is ignored?  If yes, there +		     does not seem to be a portable way to detect it.  I guess +		     that at least for multi-character collating elements there +		     could be several opposite-case counterpoints, but they +		     cannot be supported portably anyway. */ +		  tmp1 = tre_ast_new_literal(ctx->mem, tre_toupper(*ctx->re), +					     tre_toupper(*ctx->re), +					     ctx->position); +		  if (!tmp1) +		    return REG_ESPACE; +		  tmp2 = tre_ast_new_literal(ctx->mem, tre_tolower(*ctx->re), +					     tre_tolower(*ctx->re), +					     ctx->position); +		  if (!tmp2) +		    return REG_ESPACE; +		  result = tre_ast_new_union(ctx->mem, tmp1, tmp2); +		  if (!result) +		    return REG_ESPACE; +		} +	      else +		{ +		  result = tre_ast_new_literal(ctx->mem, *ctx->re, *ctx->re, +					       ctx->position); +		  if (!result) +		    return REG_ESPACE; +		} +	      ctx->position++; +	      ctx->re++; +	      break; +	    } +	  break; + +	case PARSE_MARK_FOR_SUBMATCH: +	  { +	    int submatch_id = (int)tre_stack_pop(stack); + +	    if (result->submatch_id >= 0) +	      { +		tre_ast_node_t *n, *tmp_node; +		n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1); +		if (n == NULL) +		  return REG_ESPACE; +		tmp_node = tre_ast_new_catenation(ctx->mem, n, result); +		if (tmp_node == NULL) +		  return REG_ESPACE; +		tmp_node->num_submatches = result->num_submatches; +		result = tmp_node; +	      } +	    result->submatch_id = submatch_id; +	    result->num_submatches++; +	    break; +	  } + +	case PARSE_RESTORE_CFLAGS: +	  ctx->cflags = (int)tre_stack_pop(stack); +	  break; +	} +    } + +  /* Check for missing closing parentheses. */ +  if (depth > 0) +    return REG_EPAREN; + +  if (status == REG_OK) +    ctx->result = result; + +  return status; +} + + +/*********************************************************************** + from tre-compile.c +***********************************************************************/ + +/* +  Algorithms to setup tags so that submatch addressing can be done. +*/ + + +/* Inserts a catenation node to the root of the tree given in `node'. +   As the left child a new tag with number `tag_id' to `node' is added, +   and the right child is the old root. */ +/*              OR                  */ +/* Inserts a catenation node to the root of the tree given in `node'. +   As the right child a new tag with number `tag_id' to `node' is added, +   and the left child is the old root. */ +static reg_errcode_t +tre_add_tag(tre_mem_t mem, tre_ast_node_t *node, int tag_id, int right) +{ +  tre_catenation_t *c; +  tre_ast_node_t *child_tag, *child_old; + +  DPRINT(("add_tag_%s: tag %d\n", right ? "right" : "left", tag_id)); + +  c = tre_mem_alloc(mem, sizeof(*c)); +  if (c == NULL) +    return REG_ESPACE; +  child_tag = tre_ast_new_literal(mem, TAG, tag_id, -1); +  if (child_tag == NULL) +    return REG_ESPACE; +  child_old = tre_mem_alloc(mem, sizeof(tre_ast_node_t)); +  if (child_old == NULL) +    return REG_ESPACE; + +  child_old->obj = node->obj; +  child_old->type = node->type; +  child_old->nullable = -1; +  child_old->submatch_id = -1; +  child_old->firstpos = NULL; +  child_old->lastpos = NULL; +  child_old->num_tags = 0; +  node->obj = c; +  node->type = CATENATION; + +  c->right = c->left = child_old; +  if (right) c->right = child_tag; +  else c->left = child_tag; + +  return REG_OK; +} + +typedef enum { +  ADDTAGS_RECURSE, +  ADDTAGS_AFTER_ITERATION, +  ADDTAGS_AFTER_UNION_LEFT, +  ADDTAGS_AFTER_UNION_RIGHT, +  ADDTAGS_AFTER_CAT_LEFT, +  ADDTAGS_AFTER_CAT_RIGHT, +  ADDTAGS_SET_SUBMATCH_END +} tre_addtags_symbol_t; + + +typedef struct { +  int tag; +  int next_tag; +} tre_tag_states_t; + +/* Adds tags to appropriate locations in the parse tree in `tree', so that +   subexpressions marked for submatch addressing can be traced. */ +static reg_errcode_t +tre_add_tags(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree, +	     tre_tnfa_t *tnfa) +{ +  reg_errcode_t status = REG_OK; +  tre_addtags_symbol_t symbol; +  tre_ast_node_t *node = tree; /* Tree node we are currently looking at. */ +  int bottom = tre_stack_num_objects(stack); +  /* True for first pass (counting number of needed tags) */ +  int first_pass = (mem == NULL || tnfa == NULL); +  int *regset, *orig_regset; +  int num_tags = 0; /* Total number of tags. */ +  int tag = 0;	    /* The tag that is to be added next. */ +  int next_tag = 1; /* Next tag to use after this one. */ +  int *parents;	    /* Stack of submatches the current submatch is +		       contained in. */ +  tre_tag_states_t *saved_states; + +  tre_tag_direction_t direction = TRE_TAG_MINIMIZE; +  if (!first_pass) +      tnfa->end_tag = 0; + +  regset = xmalloc(sizeof(*regset) * ((tnfa->num_submatches + 1) * 2)); +  if (regset == NULL) +    return REG_ESPACE; +  regset[0] = -1; +  orig_regset = regset; + +  parents = xmalloc(sizeof(*parents) * (tnfa->num_submatches + 1)); +  if (parents == NULL) +    { +      xfree(regset); +      return REG_ESPACE; +    } +  parents[0] = -1; + +  saved_states = xmalloc(sizeof(*saved_states) * (tnfa->num_submatches + 1)); +  if (saved_states == NULL) +    { +      xfree(regset); +      xfree(parents); +      return REG_ESPACE; +    } +  else +    { +      unsigned int i; +      for (i = 0; i <= tnfa->num_submatches; i++) +	saved_states[i].tag = -1; +    } + +  STACK_PUSH(stack, node); +  STACK_PUSH(stack, ADDTAGS_RECURSE); + +  while (tre_stack_num_objects(stack) > bottom) +    { +      if (status != REG_OK) +	break; + +      symbol = (tre_addtags_symbol_t)tre_stack_pop(stack); +      switch (symbol) +	{ + +	case ADDTAGS_SET_SUBMATCH_END: +	  { +	    int id = (int)tre_stack_pop(stack); +	    int i; + +	    /* Add end of this submatch to regset. */ +	    for (i = 0; regset[i] >= 0; i++); +	    regset[i] = id * 2 + 1; +	    regset[i + 1] = -1; + +	    /* Pop this submatch from the parents stack. */ +	    for (i = 0; parents[i] >= 0; i++); +	    parents[i - 1] = -1; +	    break; +	  } + +	case ADDTAGS_RECURSE: +	  node = tre_stack_pop(stack); + +	  if (node->submatch_id >= 0) +	    { +	      int id = node->submatch_id; +	      int i; + + +	      /* Add start of this submatch to regset. */ +	      for (i = 0; regset[i] >= 0; i++); +	      regset[i] = id * 2; +	      regset[i + 1] = -1; + +	      if (!first_pass) +		{ +		  for (i = 0; parents[i] >= 0; i++); +		  tnfa->submatch_data[id].parents = NULL; +		  if (i > 0) +		    { +		      int *p = xmalloc(sizeof(*p) * (i + 1)); +		      if (p == NULL) +			{ +			  status = REG_ESPACE; +			  break; +			} +		      assert(tnfa->submatch_data[id].parents == NULL); +		      tnfa->submatch_data[id].parents = p; +		      for (i = 0; parents[i] >= 0; i++) +			p[i] = parents[i]; +		      p[i] = -1; +		    } +		} + +	      /* Add end of this submatch to regset after processing this +		 node. */ +	      STACK_PUSHX(stack, node->submatch_id); +	      STACK_PUSHX(stack, ADDTAGS_SET_SUBMATCH_END); +	    } + +	  switch (node->type) +	    { +	    case LITERAL: +	      { +		tre_literal_t *lit = node->obj; + +		if (!IS_SPECIAL(lit) || IS_BACKREF(lit)) +		  { +		    int i; +		    DPRINT(("Literal %d-%d\n", +			    (int)lit->code_min, (int)lit->code_max)); +		    if (regset[0] >= 0) +		      { +			/* Regset is not empty, so add a tag before the +			   literal or backref. */ +			if (!first_pass) +			  { +			    status = tre_add_tag(mem, node, tag, 0 /*left*/); +			    tnfa->tag_directions[tag] = direction; +			    /* Go through the regset and set submatch data for +			       submatches that are using this tag. */ +			    for (i = 0; regset[i] >= 0; i++) +			      { +				int id = regset[i] >> 1; +				int start = !(regset[i] & 1); +				DPRINT(("  Using tag %d for %s offset of " +					"submatch %d\n", tag, +					start ? "start" : "end", id)); +				if (start) +				  tnfa->submatch_data[id].so_tag = tag; +				else +				  tnfa->submatch_data[id].eo_tag = tag; +			      } +			  } +			else +			  { +			    DPRINT(("  num_tags = 1\n")); +			    node->num_tags = 1; +			  } + +			DPRINT(("  num_tags++\n")); +			regset[0] = -1; +			tag = next_tag; +			num_tags++; +			next_tag++; +		      } +		  } +		else +		  { +		    assert(!IS_TAG(lit)); +		  } +		break; +	      } +	    case CATENATION: +	      { +		tre_catenation_t *cat = node->obj; +		tre_ast_node_t *left = cat->left; +		tre_ast_node_t *right = cat->right; +		int reserved_tag = -1; +		DPRINT(("Catenation, next_tag = %d\n", next_tag)); + + +		/* After processing right child. */ +		STACK_PUSHX(stack, node); +		STACK_PUSHX(stack, ADDTAGS_AFTER_CAT_RIGHT); + +		/* Process right child. */ +		STACK_PUSHX(stack, right); +		STACK_PUSHX(stack, ADDTAGS_RECURSE); + +		/* After processing left child. */ +		STACK_PUSHX(stack, next_tag + left->num_tags); +		DPRINT(("  Pushing %d for after left\n", +			next_tag + left->num_tags)); +		if (left->num_tags > 0 && right->num_tags > 0) +		  { +		    /* Reserve the next tag to the right child. */ +		    DPRINT(("  Reserving next_tag %d to right child\n", +			    next_tag)); +		    reserved_tag = next_tag; +		    next_tag++; +		  } +		STACK_PUSHX(stack, reserved_tag); +		STACK_PUSHX(stack, ADDTAGS_AFTER_CAT_LEFT); + +		/* Process left child. */ +		STACK_PUSHX(stack, left); +		STACK_PUSHX(stack, ADDTAGS_RECURSE); + +		} +	      break; +	    case ITERATION: +	      { +		tre_iteration_t *iter = node->obj; +		DPRINT(("Iteration\n")); + +		if (first_pass) +		  { +		    STACK_PUSHX(stack, regset[0] >= 0); +		  } +		else +		  { +		    STACK_PUSHX(stack, tag); +		  } +		STACK_PUSHX(stack, node); +		STACK_PUSHX(stack, ADDTAGS_AFTER_ITERATION); + +		STACK_PUSHX(stack, iter->arg); +		STACK_PUSHX(stack, ADDTAGS_RECURSE); + +		/* Regset is not empty, so add a tag here. */ +		if (regset[0] >= 0) +		  { +		    if (!first_pass) +		      { +			int i; +			status = tre_add_tag(mem, node, tag, 0 /*left*/); +			tnfa->tag_directions[tag] = direction; +			/* Go through the regset and set submatch data for +			   submatches that are using this tag. */ +			for (i = 0; regset[i] >= 0; i++) +			  { +			    int id = regset[i] >> 1; +			    int start = !(regset[i] & 1); +			    DPRINT(("  Using tag %d for %s offset of " +				    "submatch %d\n", tag, +				    start ? "start" : "end", id)); +			    if (start) +			      tnfa->submatch_data[id].so_tag = tag; +			    else +			      tnfa->submatch_data[id].eo_tag = tag; +			  } +		      } + +		    DPRINT(("  num_tags++\n")); +		    regset[0] = -1; +		    tag = next_tag; +		    num_tags++; +		    next_tag++; +		  } +		direction = TRE_TAG_MINIMIZE; +	      } +	      break; +	    case UNION: +	      { +		tre_union_t *uni = node->obj; +		tre_ast_node_t *left = uni->left; +		tre_ast_node_t *right = uni->right; +		int left_tag; +		int right_tag; + +		if (regset[0] >= 0) +		  { +		    left_tag = next_tag; +		    right_tag = next_tag + 1; +		  } +		else +		  { +		    left_tag = tag; +		    right_tag = next_tag; +		  } + +		DPRINT(("Union\n")); + +		/* After processing right child. */ +		STACK_PUSHX(stack, right_tag); +		STACK_PUSHX(stack, left_tag); +		STACK_PUSHX(stack, regset); +		STACK_PUSHX(stack, regset[0] >= 0); +		STACK_PUSHX(stack, node); +		STACK_PUSHX(stack, right); +		STACK_PUSHX(stack, left); +		STACK_PUSHX(stack, ADDTAGS_AFTER_UNION_RIGHT); + +		/* Process right child. */ +		STACK_PUSHX(stack, right); +		STACK_PUSHX(stack, ADDTAGS_RECURSE); + +		/* After processing left child. */ +		STACK_PUSHX(stack, ADDTAGS_AFTER_UNION_LEFT); + +		/* Process left child. */ +		STACK_PUSHX(stack, left); +		STACK_PUSHX(stack, ADDTAGS_RECURSE); + +		/* Regset is not empty, so add a tag here. */ +		if (regset[0] >= 0) +		  { +		    if (!first_pass) +		      { +			int i; +			status = tre_add_tag(mem, node, tag, 0 /*left*/); +			tnfa->tag_directions[tag] = direction; +			/* Go through the regset and set submatch data for +			   submatches that are using this tag. */ +			for (i = 0; regset[i] >= 0; i++) +			  { +			    int id = regset[i] >> 1; +			    int start = !(regset[i] & 1); +			    DPRINT(("  Using tag %d for %s offset of " +				    "submatch %d\n", tag, +				    start ? "start" : "end", id)); +			    if (start) +			      tnfa->submatch_data[id].so_tag = tag; +			    else +			      tnfa->submatch_data[id].eo_tag = tag; +			  } +		      } + +		    DPRINT(("  num_tags++\n")); +		    regset[0] = -1; +		    tag = next_tag; +		    num_tags++; +		    next_tag++; +		  } + +		if (node->num_submatches > 0) +		  { +		    /* The next two tags are reserved for markers. */ +		    next_tag++; +		    tag = next_tag; +		    next_tag++; +		  } + +		break; +	      } +	    } + +	  if (node->submatch_id >= 0) +	    { +	      int i; +	      /* Push this submatch on the parents stack. */ +	      for (i = 0; parents[i] >= 0; i++); +	      parents[i] = node->submatch_id; +	      parents[i + 1] = -1; +	    } + +	  break; /* end case: ADDTAGS_RECURSE */ + +	case ADDTAGS_AFTER_ITERATION: +	  { +	    int enter_tag; +	    node = tre_stack_pop(stack); +	    if (first_pass) +		node->num_tags = ((tre_iteration_t *)node->obj)->arg->num_tags +		  + (int)tre_stack_pop(stack); +	    else +		enter_tag = (int)tre_stack_pop(stack); + +	    DPRINT(("After iteration\n")); +	    direction = TRE_TAG_MAXIMIZE; +	    break; +	  } + +	case ADDTAGS_AFTER_CAT_LEFT: +	  { +	    int new_tag = (int)tre_stack_pop(stack); +	    next_tag = (int)tre_stack_pop(stack); +	    DPRINT(("After cat left, tag = %d, next_tag = %d\n", +		    tag, next_tag)); +	    if (new_tag >= 0) +	      { +		DPRINT(("  Setting tag to %d\n", new_tag)); +		tag = new_tag; +	      } +	    break; +	  } + +	case ADDTAGS_AFTER_CAT_RIGHT: +	  DPRINT(("After cat right\n")); +	  node = tre_stack_pop(stack); +	  if (first_pass) +	    node->num_tags = ((tre_catenation_t *)node->obj)->left->num_tags +	      + ((tre_catenation_t *)node->obj)->right->num_tags; +	  break; + +	case ADDTAGS_AFTER_UNION_LEFT: +	  DPRINT(("After union left\n")); +	  /* Lift the bottom of the `regset' array so that when processing +	     the right operand the items currently in the array are +	     invisible.	 The original bottom was saved at ADDTAGS_UNION and +	     will be restored at ADDTAGS_AFTER_UNION_RIGHT below. */ +	  while (*regset >= 0) +	    regset++; +	  break; + +	case ADDTAGS_AFTER_UNION_RIGHT: +	  { +	    int added_tags, tag_left, tag_right; +	    tre_ast_node_t *left = tre_stack_pop(stack); +	    tre_ast_node_t *right = tre_stack_pop(stack); +	    DPRINT(("After union right\n")); +	    node = tre_stack_pop(stack); +	    added_tags = (int)tre_stack_pop(stack); +	    if (first_pass) +	      { +		node->num_tags = ((tre_union_t *)node->obj)->left->num_tags +		  + ((tre_union_t *)node->obj)->right->num_tags + added_tags +		  + ((node->num_submatches > 0) ? 2 : 0); +	      } +	    regset = tre_stack_pop(stack); +	    tag_left = (int)tre_stack_pop(stack); +	    tag_right = (int)tre_stack_pop(stack); + +	    /* Add tags after both children, the left child gets a smaller +	       tag than the right child.  This guarantees that we prefer +	       the left child over the right child. */ +	    /* XXX - This is not always necessary (if the children have +	       tags which must be seen for every match of that child). */ +	    /* XXX - Check if this is the only place where tre_add_tag_right +	       is used.	 If so, use tre_add_tag_left (putting the tag before +	       the child as opposed after the child) and throw away +	       tre_add_tag_right. */ +	    if (node->num_submatches > 0) +	      { +		if (!first_pass) +		  { +		    status = tre_add_tag(mem, left, tag_left, 1 /*right*/); +		    tnfa->tag_directions[tag] = TRE_TAG_MAXIMIZE; +		    status = tre_add_tag(mem, right, tag_right, 1 /*right*/); +		    tnfa->tag_directions[tag] = TRE_TAG_MAXIMIZE; +		  } +		DPRINT(("  num_tags += 2\n")); +		num_tags += 2; +	      } +	    direction = TRE_TAG_MAXIMIZE; +	    break; +	  } + +	default: +	  assert(0); +	  break; + +	} /* end switch(symbol) */ +    } /* end while(tre_stack_num_objects(stack) > bottom) */ + +  if (!first_pass) +    { +      int i; +      /* Go through the regset and set submatch data for +	 submatches that are using this tag. */ +      for (i = 0; regset[i] >= 0; i++) +	{ +	  int id = regset[i] >> 1; +	  int start = !(regset[i] & 1); +	  DPRINT(("  Using tag %d for %s offset of " +		  "submatch %d\n", num_tags, +		  start ? "start" : "end", id)); +	  if (start) +	    tnfa->submatch_data[id].so_tag = num_tags; +	  else +	    tnfa->submatch_data[id].eo_tag = num_tags; +	} +    } + +  DPRINT(("tre_add_tags: %s complete.  Number of tags %d.\n", +	  first_pass? "First pass" : "Second pass", num_tags)); + +  assert(tree->num_tags == num_tags); +  tnfa->end_tag = num_tags; +  tnfa->num_tags = num_tags; +  xfree(orig_regset); +  xfree(parents); +  xfree(saved_states); +  return status; +} + + + +/* +  AST to TNFA compilation routines. +*/ + +typedef enum { +  COPY_RECURSE, +  COPY_SET_RESULT_PTR +} tre_copyast_symbol_t; + +/* Flags for tre_copy_ast(). */ +#define COPY_REMOVE_TAGS	 1 +#define COPY_MAXIMIZE_FIRST_TAG	 2 + +static reg_errcode_t +tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, +	     int flags, int *pos_add, tre_tag_direction_t *tag_directions, +	     tre_ast_node_t **copy, int *max_pos) +{ +  reg_errcode_t status = REG_OK; +  int bottom = tre_stack_num_objects(stack); +  int num_copied = 0; +  int first_tag = 1; +  tre_ast_node_t **result = copy; +  tre_copyast_symbol_t symbol; + +  STACK_PUSH(stack, ast); +  STACK_PUSH(stack, COPY_RECURSE); + +  while (status == REG_OK && tre_stack_num_objects(stack) > bottom) +    { +      tre_ast_node_t *node; +      if (status != REG_OK) +	break; + +      symbol = (tre_copyast_symbol_t)tre_stack_pop(stack); +      switch (symbol) +	{ +	case COPY_SET_RESULT_PTR: +	  result = tre_stack_pop(stack); +	  break; +	case COPY_RECURSE: +	  node = tre_stack_pop(stack); +	  switch (node->type) +	    { +	    case LITERAL: +	      { +		tre_literal_t *lit = node->obj; +		int pos = lit->position; +		int min = lit->code_min; +		int max = lit->code_max; +		if (!IS_SPECIAL(lit) || IS_BACKREF(lit)) +		  { +		    /* XXX - e.g. [ab] has only one position but two +		       nodes, so we are creating holes in the state space +		       here.  Not fatal, just wastes memory. */ +		    pos += *pos_add; +		    num_copied++; +		  } +		else if (IS_TAG(lit) && (flags & COPY_REMOVE_TAGS)) +		  { +		    /* Change this tag to empty. */ +		    min = EMPTY; +		    max = pos = -1; +		  } +		else if (IS_TAG(lit) && (flags & COPY_MAXIMIZE_FIRST_TAG) +			 && first_tag) +		  { +		    /* Maximize the first tag. */ +		    tag_directions[max] = TRE_TAG_MAXIMIZE; +		    first_tag = 0; +		  } +		*result = tre_ast_new_literal(mem, min, max, pos); +		if (*result == NULL) +		  status = REG_ESPACE; + +		if (pos > *max_pos) +		  *max_pos = pos; +		break; +	      } +	    case UNION: +	      { +		tre_union_t *uni = node->obj; +		tre_union_t *copy; +		*result = tre_ast_new_union(mem, uni->left, uni->right); +		if (*result == NULL) +		  { +		    status = REG_ESPACE; +		    break; +		  } +		copy = (*result)->obj; +		result = ©->left; +		STACK_PUSHX(stack, uni->right); +		STACK_PUSHX(stack, COPY_RECURSE); +		STACK_PUSHX(stack, ©->right); +		STACK_PUSHX(stack, COPY_SET_RESULT_PTR); +		STACK_PUSHX(stack, uni->left); +		STACK_PUSHX(stack, COPY_RECURSE); +		break; +	      } +	    case CATENATION: +	      { +		tre_catenation_t *cat = node->obj; +		tre_catenation_t *copy; +		*result = tre_ast_new_catenation(mem, cat->left, cat->right); +		if (*result == NULL) +		  { +		    status = REG_ESPACE; +		    break; +		  } +		copy = (*result)->obj; +		copy->left = NULL; +		copy->right = NULL; +		result = ©->left; + +		STACK_PUSHX(stack, cat->right); +		STACK_PUSHX(stack, COPY_RECURSE); +		STACK_PUSHX(stack, ©->right); +		STACK_PUSHX(stack, COPY_SET_RESULT_PTR); +		STACK_PUSHX(stack, cat->left); +		STACK_PUSHX(stack, COPY_RECURSE); +		break; +	      } +	    case ITERATION: +	      { +		tre_iteration_t *iter = node->obj; +		STACK_PUSHX(stack, iter->arg); +		STACK_PUSHX(stack, COPY_RECURSE); +		*result = tre_ast_new_iter(mem, iter->arg, iter->min, iter->max); +		if (*result == NULL) +		  { +		    status = REG_ESPACE; +		    break; +		  } +		iter = (*result)->obj; +		result = &iter->arg; +		break; +	      } +	    default: +	      assert(0); +	      break; +	    } +	  break; +	} +    } +  *pos_add += num_copied; +  return status; +} + +typedef enum { +  EXPAND_RECURSE, +  EXPAND_AFTER_ITER +} tre_expand_ast_symbol_t; + +/* Expands each iteration node that has a finite nonzero minimum or maximum +   iteration count to a catenated sequence of copies of the node. */ +static reg_errcode_t +tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast, +	       int *position, tre_tag_direction_t *tag_directions, +	       int *max_depth) +{ +  reg_errcode_t status = REG_OK; +  int bottom = tre_stack_num_objects(stack); +  int pos_add = 0; +  int pos_add_total = 0; +  int max_pos = 0; +  /* Approximate parameter nesting level. */ +  int iter_depth = 0; + +  STACK_PUSHR(stack, ast); +  STACK_PUSHR(stack, EXPAND_RECURSE); +  while (status == REG_OK && tre_stack_num_objects(stack) > bottom) +    { +      tre_ast_node_t *node; +      tre_expand_ast_symbol_t symbol; + +      if (status != REG_OK) +	break; + +      DPRINT(("pos_add %d\n", pos_add)); + +      symbol = (tre_expand_ast_symbol_t)tre_stack_pop(stack); +      node = tre_stack_pop(stack); +      switch (symbol) +	{ +	case EXPAND_RECURSE: +	  switch (node->type) +	    { +	    case LITERAL: +	      { +		tre_literal_t *lit= node->obj; +		if (!IS_SPECIAL(lit) || IS_BACKREF(lit)) +		  { +		    lit->position += pos_add; +		    if (lit->position > max_pos) +		      max_pos = lit->position; +		  } +		break; +	      } +	    case UNION: +	      { +		tre_union_t *uni = node->obj; +		STACK_PUSHX(stack, uni->right); +		STACK_PUSHX(stack, EXPAND_RECURSE); +		STACK_PUSHX(stack, uni->left); +		STACK_PUSHX(stack, EXPAND_RECURSE); +		break; +	      } +	    case CATENATION: +	      { +		tre_catenation_t *cat = node->obj; +		STACK_PUSHX(stack, cat->right); +		STACK_PUSHX(stack, EXPAND_RECURSE); +		STACK_PUSHX(stack, cat->left); +		STACK_PUSHX(stack, EXPAND_RECURSE); +		break; +	      } +	    case ITERATION: +	      { +		tre_iteration_t *iter = node->obj; +		STACK_PUSHX(stack, pos_add); +		STACK_PUSHX(stack, node); +		STACK_PUSHX(stack, EXPAND_AFTER_ITER); +		STACK_PUSHX(stack, iter->arg); +		STACK_PUSHX(stack, EXPAND_RECURSE); +		/* If we are going to expand this node at EXPAND_AFTER_ITER +		   then don't increase the `pos' fields of the nodes now, it +		   will get done when expanding. */ +		if (iter->min > 1 || iter->max > 1) +		  pos_add = 0; +		iter_depth++; +		DPRINT(("iter\n")); +		break; +	      } +	    default: +	      assert(0); +	      break; +	    } +	  break; +	case EXPAND_AFTER_ITER: +	  { +	    tre_iteration_t *iter = node->obj; +	    int pos_add_last; +	    pos_add = (int)tre_stack_pop(stack); +	    pos_add_last = pos_add; +	    if (iter->min > 1 || iter->max > 1) +	      { +		tre_ast_node_t *seq1 = NULL, *seq2 = NULL; +		int i; +		int pos_add_save = pos_add; + +		/* Create a catenated sequence of copies of the node. */ +		for (i = 0; i < iter->min; i++) +		  { +		    tre_ast_node_t *copy; +		    /* Remove tags from all but the last copy. */ +		    int flags = ((i + 1 < iter->min) +				 ? COPY_REMOVE_TAGS +				 : COPY_MAXIMIZE_FIRST_TAG); +		    DPRINT(("  pos_add %d\n", pos_add)); +		    pos_add_save = pos_add; +		    status = tre_copy_ast(mem, stack, iter->arg, flags, +					  &pos_add, tag_directions, ©, +					  &max_pos); +		    if (status != REG_OK) +		      return status; +		    if (seq1 != NULL) +		      seq1 = tre_ast_new_catenation(mem, seq1, copy); +		    else +		      seq1 = copy; +		    if (seq1 == NULL) +		      return REG_ESPACE; +		  } + +		if (iter->max == -1) +		  { +		    /* No upper limit. */ +		    pos_add_save = pos_add; +		    status = tre_copy_ast(mem, stack, iter->arg, 0, +					  &pos_add, NULL, &seq2, &max_pos); +		    if (status != REG_OK) +		      return status; +		    seq2 = tre_ast_new_iter(mem, seq2, 0, -1); +		    if (seq2 == NULL) +		      return REG_ESPACE; +		  } +		else +		  { +		    for (i = iter->min; i < iter->max; i++) +		      { +			tre_ast_node_t *tmp, *copy; +			pos_add_save = pos_add; +			status = tre_copy_ast(mem, stack, iter->arg, 0, +					      &pos_add, NULL, ©, &max_pos); +			if (status != REG_OK) +			  return status; +			if (seq2 != NULL) +			  seq2 = tre_ast_new_catenation(mem, copy, seq2); +			else +			  seq2 = copy; +			if (seq2 == NULL) +			  return REG_ESPACE; +			tmp = tre_ast_new_literal(mem, EMPTY, -1, -1); +			if (tmp == NULL) +			  return REG_ESPACE; +			seq2 = tre_ast_new_union(mem, tmp, seq2); +			if (seq2 == NULL) +			  return REG_ESPACE; +		      } +		  } + +		pos_add = pos_add_save; +		if (seq1 == NULL) +		  seq1 = seq2; +		else if (seq2 != NULL) +		  seq1 = tre_ast_new_catenation(mem, seq1, seq2); +		if (seq1 == NULL) +		  return REG_ESPACE; +		node->obj = seq1->obj; +		node->type = seq1->type; +	      } + +	    iter_depth--; +	    pos_add_total += pos_add - pos_add_last; +	    if (iter_depth == 0) +	      pos_add = pos_add_total; + +	    break; +	  } +	default: +	  assert(0); +	  break; +	} +    } + +  *position += pos_add_total; + +  /* `max_pos' should never be larger than `*position' if the above +     code works, but just an extra safeguard let's make sure +     `*position' is set large enough so enough memory will be +     allocated for the transition table. */ +  if (max_pos > *position) +    *position = max_pos; + +#ifdef TRE_DEBUG +  DPRINT(("Expanded AST:\n")); +  tre_ast_print(ast); +  DPRINT(("*position %d, max_pos %d\n", *position, max_pos)); +#endif + +  return status; +} + +static tre_pos_and_tags_t * +tre_set_empty(tre_mem_t mem) +{ +  tre_pos_and_tags_t *new_set; + +  new_set = tre_mem_calloc(mem, sizeof(*new_set)); +  if (new_set == NULL) +    return NULL; + +  new_set[0].position = -1; +  new_set[0].code_min = -1; +  new_set[0].code_max = -1; + +  return new_set; +} + +static tre_pos_and_tags_t * +tre_set_one(tre_mem_t mem, int position, int code_min, int code_max, +	    tre_ctype_t class, tre_ctype_t *neg_classes, int backref) +{ +  tre_pos_and_tags_t *new_set; + +  new_set = tre_mem_calloc(mem, sizeof(*new_set) * 2); +  if (new_set == NULL) +    return NULL; + +  new_set[0].position = position; +  new_set[0].code_min = code_min; +  new_set[0].code_max = code_max; +  new_set[0].class = class; +  new_set[0].neg_classes = neg_classes; +  new_set[0].backref = backref; +  new_set[1].position = -1; +  new_set[1].code_min = -1; +  new_set[1].code_max = -1; + +  return new_set; +} + +static tre_pos_and_tags_t * +tre_set_union(tre_mem_t mem, tre_pos_and_tags_t *set1, tre_pos_and_tags_t *set2, +	      int *tags, int assertions) +{ +  int s1, s2, i, j; +  tre_pos_and_tags_t *new_set; +  int *new_tags; +  int num_tags; + +  for (num_tags = 0; tags != NULL && tags[num_tags] >= 0; num_tags++); +  for (s1 = 0; set1[s1].position >= 0; s1++); +  for (s2 = 0; set2[s2].position >= 0; s2++); +  new_set = tre_mem_calloc(mem, sizeof(*new_set) * (s1 + s2 + 1)); +  if (!new_set ) +    return NULL; + +  for (s1 = 0; set1[s1].position >= 0; s1++) +    { +      new_set[s1].position = set1[s1].position; +      new_set[s1].code_min = set1[s1].code_min; +      new_set[s1].code_max = set1[s1].code_max; +      new_set[s1].assertions = set1[s1].assertions | assertions; +      new_set[s1].class = set1[s1].class; +      new_set[s1].neg_classes = set1[s1].neg_classes; +      new_set[s1].backref = set1[s1].backref; +      if (set1[s1].tags == NULL && tags == NULL) +	new_set[s1].tags = NULL; +      else +	{ +	  for (i = 0; set1[s1].tags != NULL && set1[s1].tags[i] >= 0; i++); +	  new_tags = tre_mem_alloc(mem, (sizeof(*new_tags) +					 * (i + num_tags + 1))); +	  if (new_tags == NULL) +	    return NULL; +	  for (j = 0; j < i; j++) +	    new_tags[j] = set1[s1].tags[j]; +	  for (i = 0; i < num_tags; i++) +	    new_tags[j + i] = tags[i]; +	  new_tags[j + i] = -1; +	  new_set[s1].tags = new_tags; +	} +    } + +  for (s2 = 0; set2[s2].position >= 0; s2++) +    { +      new_set[s1 + s2].position = set2[s2].position; +      new_set[s1 + s2].code_min = set2[s2].code_min; +      new_set[s1 + s2].code_max = set2[s2].code_max; +      /* XXX - why not | assertions here as well? */ +      new_set[s1 + s2].assertions = set2[s2].assertions; +      new_set[s1 + s2].class = set2[s2].class; +      new_set[s1 + s2].neg_classes = set2[s2].neg_classes; +      new_set[s1 + s2].backref = set2[s2].backref; +      if (set2[s2].tags == NULL) +	new_set[s1 + s2].tags = NULL; +      else +	{ +	  for (i = 0; set2[s2].tags[i] >= 0; i++); +	  new_tags = tre_mem_alloc(mem, sizeof(*new_tags) * (i + 1)); +	  if (new_tags == NULL) +	    return NULL; +	  for (j = 0; j < i; j++) +	    new_tags[j] = set2[s2].tags[j]; +	  new_tags[j] = -1; +	  new_set[s1 + s2].tags = new_tags; +	} +    } +  new_set[s1 + s2].position = -1; +  return new_set; +} + +/* Finds the empty path through `node' which is the one that should be +   taken according to POSIX.2 rules, and adds the tags on that path to +   `tags'.   `tags' may be NULL.  If `num_tags_seen' is not NULL, it is +   set to the number of tags seen on the path. */ +static reg_errcode_t +tre_match_empty(tre_stack_t *stack, tre_ast_node_t *node, int *tags, +		int *assertions, int *num_tags_seen) +{ +  tre_literal_t *lit; +  tre_union_t *uni; +  tre_catenation_t *cat; +  tre_iteration_t *iter; +  int i; +  int bottom = tre_stack_num_objects(stack); +  reg_errcode_t status = REG_OK; +  if (num_tags_seen) +    *num_tags_seen = 0; + +  status = tre_stack_push(stack, node); + +  /* Walk through the tree recursively. */ +  while (status == REG_OK && tre_stack_num_objects(stack) > bottom) +    { +      node = tre_stack_pop(stack); + +      switch (node->type) +	{ +	case LITERAL: +	  lit = (tre_literal_t *)node->obj; +	  switch (lit->code_min) +	    { +	    case TAG: +	      if (lit->code_max >= 0) +		{ +		  if (tags != NULL) +		    { +		      /* Add the tag to `tags'. */ +		      for (i = 0; tags[i] >= 0; i++) +			if (tags[i] == lit->code_max) +			  break; +		      if (tags[i] < 0) +			{ +			  tags[i] = lit->code_max; +			  tags[i + 1] = -1; +			} +		    } +		  if (num_tags_seen) +		    (*num_tags_seen)++; +		} +	      break; +	    case ASSERTION: +	      assert(lit->code_max >= 1 +		     || lit->code_max <= ASSERT_LAST); +	      if (assertions != NULL) +		*assertions |= lit->code_max; +	      break; +	    case EMPTY: +	      break; +	    default: +	      assert(0); +	      break; +	    } +	  break; + +	case UNION: +	  /* Subexpressions starting earlier take priority over ones +	     starting later, so we prefer the left subexpression over the +	     right subexpression. */ +	  uni = (tre_union_t *)node->obj; +	  if (uni->left->nullable) +	    STACK_PUSHX(stack, uni->left) +	  else if (uni->right->nullable) +	    STACK_PUSHX(stack, uni->right) +	  else +	    assert(0); +	  break; + +	case CATENATION: +	  /* The path must go through both children. */ +	  cat = (tre_catenation_t *)node->obj; +	  assert(cat->left->nullable); +	  assert(cat->right->nullable); +	  STACK_PUSHX(stack, cat->left); +	  STACK_PUSHX(stack, cat->right); +	  break; + +	case ITERATION: +	  /* A match with an empty string is preferred over no match at +	     all, so we go through the argument if possible. */ +	  iter = (tre_iteration_t *)node->obj; +	  if (iter->arg->nullable) +	    STACK_PUSHX(stack, iter->arg); +	  break; + +	default: +	  assert(0); +	  break; +	} +    } + +  return status; +} + + +typedef enum { +  NFL_RECURSE, +  NFL_POST_UNION, +  NFL_POST_CATENATION, +  NFL_POST_ITERATION +} tre_nfl_stack_symbol_t; + + +/* Computes and fills in the fields `nullable', `firstpos', and `lastpos' for +   the nodes of the AST `tree'. */ +static reg_errcode_t +tre_compute_nfl(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree) +{ +  int bottom = tre_stack_num_objects(stack); + +  STACK_PUSHR(stack, tree); +  STACK_PUSHR(stack, NFL_RECURSE); + +  while (tre_stack_num_objects(stack) > bottom) +    { +      tre_nfl_stack_symbol_t symbol; +      tre_ast_node_t *node; + +      symbol = (tre_nfl_stack_symbol_t) tre_stack_pop(stack); +      node = tre_stack_pop(stack); +      switch (symbol) +	{ +	case NFL_RECURSE: +	  switch (node->type) +	    { +	    case LITERAL: +	      { +		tre_literal_t *lit = (tre_literal_t *)node->obj; +		if (IS_BACKREF(lit)) +		  { +		    /* Back references: nullable = false, firstpos = {i}, +		       lastpos = {i}. */ +		    node->nullable = 0; +		    node->firstpos = tre_set_one(mem, lit->position, 0, +					     TRE_CHAR_MAX, 0, NULL, -1); +		    if (!node->firstpos) +		      return REG_ESPACE; +		    node->lastpos = tre_set_one(mem, lit->position, 0, +						TRE_CHAR_MAX, 0, NULL, +						lit->code_max); +		    if (!node->lastpos) +		      return REG_ESPACE; +		  } +		else if (lit->code_min < 0) +		  { +		    /* Tags, empty strings and zero width assertions: +		       nullable = true, firstpos = {}, and lastpos = {}. */ +		    node->nullable = 1; +		    node->firstpos = tre_set_empty(mem); +		    if (!node->firstpos) +		      return REG_ESPACE; +		    node->lastpos = tre_set_empty(mem); +		    if (!node->lastpos) +		      return REG_ESPACE; +		  } +		else +		  { +		    /* Literal at position i: nullable = false, firstpos = {i}, +		       lastpos = {i}. */ +		    node->nullable = 0; +		    node->firstpos = +		      tre_set_one(mem, lit->position, lit->code_min, +				  lit->code_max, 0, NULL, -1); +		    if (!node->firstpos) +		      return REG_ESPACE; +		    node->lastpos = tre_set_one(mem, lit->position, +						lit->code_min, lit->code_max, +						lit->class, lit->neg_classes, +						-1); +		    if (!node->lastpos) +		      return REG_ESPACE; +		  } +		break; +	      } + +	    case UNION: +	      /* Compute the attributes for the two subtrees, and after that +		 for this node. */ +	      STACK_PUSHR(stack, node); +	      STACK_PUSHR(stack, NFL_POST_UNION); +	      STACK_PUSHR(stack, ((tre_union_t *)node->obj)->right); +	      STACK_PUSHR(stack, NFL_RECURSE); +	      STACK_PUSHR(stack, ((tre_union_t *)node->obj)->left); +	      STACK_PUSHR(stack, NFL_RECURSE); +	      break; + +	    case CATENATION: +	      /* Compute the attributes for the two subtrees, and after that +		 for this node. */ +	      STACK_PUSHR(stack, node); +	      STACK_PUSHR(stack, NFL_POST_CATENATION); +	      STACK_PUSHR(stack, ((tre_catenation_t *)node->obj)->right); +	      STACK_PUSHR(stack, NFL_RECURSE); +	      STACK_PUSHR(stack, ((tre_catenation_t *)node->obj)->left); +	      STACK_PUSHR(stack, NFL_RECURSE); +	      break; + +	    case ITERATION: +	      /* Compute the attributes for the subtree, and after that for +		 this node. */ +	      STACK_PUSHR(stack, node); +	      STACK_PUSHR(stack, NFL_POST_ITERATION); +	      STACK_PUSHR(stack, ((tre_iteration_t *)node->obj)->arg); +	      STACK_PUSHR(stack, NFL_RECURSE); +	      break; +	    } +	  break; /* end case: NFL_RECURSE */ + +	case NFL_POST_UNION: +	  { +	    tre_union_t *uni = (tre_union_t *)node->obj; +	    node->nullable = uni->left->nullable || uni->right->nullable; +	    node->firstpos = tre_set_union(mem, uni->left->firstpos, +					   uni->right->firstpos, NULL, 0); +	    if (!node->firstpos) +	      return REG_ESPACE; +	    node->lastpos = tre_set_union(mem, uni->left->lastpos, +					  uni->right->lastpos, NULL, 0); +	    if (!node->lastpos) +	      return REG_ESPACE; +	    break; +	  } + +	case NFL_POST_ITERATION: +	  { +	    tre_iteration_t *iter = (tre_iteration_t *)node->obj; + +	    if (iter->min == 0 || iter->arg->nullable) +	      node->nullable = 1; +	    else +	      node->nullable = 0; +	    node->firstpos = iter->arg->firstpos; +	    node->lastpos = iter->arg->lastpos; +	    break; +	  } + +	case NFL_POST_CATENATION: +	  { +	    int num_tags, *tags, assertions; +	    reg_errcode_t status; +	    tre_catenation_t *cat = node->obj; +	    node->nullable = cat->left->nullable && cat->right->nullable; + +	    /* Compute firstpos. */ +	    if (cat->left->nullable) +	      { +		/* The left side matches the empty string.  Make a first pass +		   with tre_match_empty() to get the number of tags. */ +		status = tre_match_empty(stack, cat->left, +					 NULL, NULL, &num_tags); +		if (status != REG_OK) +		  return status; +		/* Allocate arrays for the tags and parameters. */ +		tags = xmalloc(sizeof(*tags) * (num_tags + 1)); +		if (!tags) +		  return REG_ESPACE; +		tags[0] = -1; +		assertions = 0; +		/* Second pass with tre_mach_empty() to get the list of +		   tags. */ +		status = tre_match_empty(stack, cat->left, tags, +					 &assertions, NULL); +		if (status != REG_OK) +		  { +		    xfree(tags); +		    return status; +		  } +		node->firstpos = +		  tre_set_union(mem, cat->right->firstpos, cat->left->firstpos, +				tags, assertions); +		xfree(tags); +		if (!node->firstpos) +		  return REG_ESPACE; +	      } +	    else +	      { +		node->firstpos = cat->left->firstpos; +	      } + +	    /* Compute lastpos. */ +	    if (cat->right->nullable) +	      { +		/* The right side matches the empty string.  Make a first pass +		   with tre_match_empty() to get the number of tags. */ +		status = tre_match_empty(stack, cat->right, +					 NULL, NULL, &num_tags); +		if (status != REG_OK) +		  return status; +		/* Allocate arrays for the tags and parameters. */ +		tags = xmalloc(sizeof(int) * (num_tags + 1)); +		if (!tags) +		  return REG_ESPACE; +		tags[0] = -1; +		assertions = 0; +		/* Second pass with tre_mach_empty() to get the list of +		   tags. */ +		status = tre_match_empty(stack, cat->right, tags, +					 &assertions, NULL); +		if (status != REG_OK) +		  { +		    xfree(tags); +		    return status; +		  } +		node->lastpos = +		  tre_set_union(mem, cat->left->lastpos, cat->right->lastpos, +				tags, assertions); +		xfree(tags); +		if (!node->lastpos) +		  return REG_ESPACE; +	      } +	    else +	      { +		node->lastpos = cat->right->lastpos; +	      } +	    break; +	  } + +	default: +	  assert(0); +	  break; +	} +    } + +  return REG_OK; +} + + +/* Adds a transition from each position in `p1' to each position in `p2'. */ +static reg_errcode_t +tre_make_trans(tre_pos_and_tags_t *p1, tre_pos_and_tags_t *p2, +	       tre_tnfa_transition_t *transitions, +	       int *counts, int *offs) +{ +  tre_pos_and_tags_t *orig_p2 = p2; +  tre_tnfa_transition_t *trans; +  int i, j, k, l, dup, prev_p2_pos; + +  if (transitions != NULL) +    while (p1->position >= 0) +      { +	p2 = orig_p2; +	prev_p2_pos = -1; +	while (p2->position >= 0) +	  { +	    /* Optimization: if this position was already handled, skip it. */ +	    if (p2->position == prev_p2_pos) +	      { +		p2++; +		continue; +	      } +	    prev_p2_pos = p2->position; +	    /* Set `trans' to point to the next unused transition from +	       position `p1->position'. */ +	    trans = transitions + offs[p1->position]; +	    while (trans->state != NULL) +	      { +#if 0 +		/* If we find a previous transition from `p1->position' to +		   `p2->position', it is overwritten.  This can happen only +		   if there are nested loops in the regexp, like in "((a)*)*". +		   In POSIX.2 repetition using the outer loop is always +		   preferred over using the inner loop.	 Therefore the +		   transition for the inner loop is useless and can be thrown +		   away. */ +		/* XXX - The same position is used for all nodes in a bracket +		   expression, so this optimization cannot be used (it will +		   break bracket expressions) unless I figure out a way to +		   detect it here. */ +		if (trans->state_id == p2->position) +		  { +		    DPRINT(("*")); +		    break; +		  } +#endif +		trans++; +	      } + +	    if (trans->state == NULL) +	      (trans + 1)->state = NULL; +	    /* Use the character ranges, assertions, etc. from `p1' for +	       the transition from `p1' to `p2'. */ +	    trans->code_min = p1->code_min; +	    trans->code_max = p1->code_max; +	    trans->state = transitions + offs[p2->position]; +	    trans->state_id = p2->position; +	    trans->assertions = p1->assertions | p2->assertions +	      | (p1->class ? ASSERT_CHAR_CLASS : 0) +	      | (p1->neg_classes != NULL ? ASSERT_CHAR_CLASS_NEG : 0); +	    if (p1->backref >= 0) +	      { +		assert((trans->assertions & ASSERT_CHAR_CLASS) == 0); +		assert(p2->backref < 0); +		trans->u.backref = p1->backref; +		trans->assertions |= ASSERT_BACKREF; +	      } +	    else +	      trans->u.class = p1->class; +	    if (p1->neg_classes != NULL) +	      { +		for (i = 0; p1->neg_classes[i] != (tre_ctype_t)0; i++); +		trans->neg_classes = +		  xmalloc(sizeof(*trans->neg_classes) * (i + 1)); +		if (trans->neg_classes == NULL) +		  return REG_ESPACE; +		for (i = 0; p1->neg_classes[i] != (tre_ctype_t)0; i++) +		  trans->neg_classes[i] = p1->neg_classes[i]; +		trans->neg_classes[i] = (tre_ctype_t)0; +	      } +	    else +	      trans->neg_classes = NULL; + +	    /* Find out how many tags this transition has. */ +	    i = 0; +	    if (p1->tags != NULL) +	      while(p1->tags[i] >= 0) +		i++; +	    j = 0; +	    if (p2->tags != NULL) +	      while(p2->tags[j] >= 0) +		j++; + +	    /* If we are overwriting a transition, free the old tag array. */ +	    if (trans->tags != NULL) +	      xfree(trans->tags); +	    trans->tags = NULL; + +	    /* If there were any tags, allocate an array and fill it. */ +	    if (i + j > 0) +	      { +		trans->tags = xmalloc(sizeof(*trans->tags) * (i + j + 1)); +		if (!trans->tags) +		  return REG_ESPACE; +		i = 0; +		if (p1->tags != NULL) +		  while(p1->tags[i] >= 0) +		    { +		      trans->tags[i] = p1->tags[i]; +		      i++; +		    } +		l = i; +		j = 0; +		if (p2->tags != NULL) +		  while (p2->tags[j] >= 0) +		    { +		      /* Don't add duplicates. */ +		      dup = 0; +		      for (k = 0; k < i; k++) +			if (trans->tags[k] == p2->tags[j]) +			  { +			    dup = 1; +			    break; +			  } +		      if (!dup) +			trans->tags[l++] = p2->tags[j]; +		      j++; +		    } +		trans->tags[l] = -1; +	      } + + +#ifdef TRE_DEBUG +	    { +	      int *tags; + +	      DPRINT(("	 %2d -> %2d on %3d", p1->position, p2->position, +		      p1->code_min)); +	      if (p1->code_max != p1->code_min) +		DPRINT(("-%3d", p1->code_max)); +	      tags = trans->tags; +	      if (tags) +		{ +		  DPRINT((", tags [")); +		  while (*tags >= 0) +		    { +		      DPRINT(("%d", *tags)); +		      tags++; +		      if (*tags >= 0) +			DPRINT((",")); +		    } +		  DPRINT(("]")); +		} +	      if (trans->assertions) +		DPRINT((", assert %d", trans->assertions)); +	      if (trans->assertions & ASSERT_BACKREF) +		DPRINT((", backref %d", trans->u.backref)); +	      else if (trans->class) +		DPRINT((", class %ld", (long)trans->class)); +	      if (trans->neg_classes) +		DPRINT((", neg_classes %p", trans->neg_classes)); +	      DPRINT(("\n")); +	    } +#endif /* TRE_DEBUG */ +	    p2++; +	  } +	p1++; +      } +  else +    /* Compute a maximum limit for the number of transitions leaving +       from each state. */ +    while (p1->position >= 0) +      { +	p2 = orig_p2; +	while (p2->position >= 0) +	  { +	    counts[p1->position]++; +	    p2++; +	  } +	p1++; +      } +  return REG_OK; +} + +/* Converts the syntax tree to a TNFA.	All the transitions in the TNFA are +   labelled with one character range (there are no transitions on empty +   strings).  The TNFA takes O(n^2) space in the worst case, `n' is size of +   the regexp. */ +static reg_errcode_t +tre_ast_to_tnfa(tre_ast_node_t *node, tre_tnfa_transition_t *transitions, +		int *counts, int *offs) +{ +  tre_union_t *uni; +  tre_catenation_t *cat; +  tre_iteration_t *iter; +  reg_errcode_t errcode = REG_OK; + +  /* XXX - recurse using a stack!. */ +  switch (node->type) +    { +    case LITERAL: +      break; +    case UNION: +      uni = (tre_union_t *)node->obj; +      errcode = tre_ast_to_tnfa(uni->left, transitions, counts, offs); +      if (errcode != REG_OK) +	return errcode; +      errcode = tre_ast_to_tnfa(uni->right, transitions, counts, offs); +      break; + +    case CATENATION: +      cat = (tre_catenation_t *)node->obj; +      /* Add a transition from each position in cat->left->lastpos +	 to each position in cat->right->firstpos. */ +      errcode = tre_make_trans(cat->left->lastpos, cat->right->firstpos, +			       transitions, counts, offs); +      if (errcode != REG_OK) +	return errcode; +      errcode = tre_ast_to_tnfa(cat->left, transitions, counts, offs); +      if (errcode != REG_OK) +	return errcode; +      errcode = tre_ast_to_tnfa(cat->right, transitions, counts, offs); +      break; + +    case ITERATION: +      iter = (tre_iteration_t *)node->obj; +      assert(iter->max == -1 || iter->max == 1); + +      if (iter->max == -1) +	{ +	  assert(iter->min == 0 || iter->min == 1); +	  /* Add a transition from each last position in the iterated +	     expression to each first position. */ +	  errcode = tre_make_trans(iter->arg->lastpos, iter->arg->firstpos, +				   transitions, counts, offs); +	  if (errcode != REG_OK) +	    return errcode; +	} +      errcode = tre_ast_to_tnfa(iter->arg, transitions, counts, offs); +      break; +    } +  return errcode; +} + + +static void +tre_free(regex_t *preg) +{ +  tre_tnfa_t *tnfa; +  unsigned int i; +  tre_tnfa_transition_t *trans; + +  tnfa = (void *)preg->TRE_REGEX_T_FIELD; +  if (!tnfa) +    return; + +  for (i = 0; i < tnfa->num_transitions; i++) +    if (tnfa->transitions[i].state) +      { +	if (tnfa->transitions[i].tags) +	  xfree(tnfa->transitions[i].tags); +	if (tnfa->transitions[i].neg_classes) +	  xfree(tnfa->transitions[i].neg_classes); +      } +  if (tnfa->transitions) +    xfree(tnfa->transitions); + +  if (tnfa->initial) +    { +      for (trans = tnfa->initial; trans->state; trans++) +	{ +	  if (trans->tags) +	    xfree(trans->tags); +	} +      xfree(tnfa->initial); +    } + +  if (tnfa->submatch_data) +    { +      for (i = 0; i < tnfa->num_submatches; i++) +	if (tnfa->submatch_data[i].parents) +	  xfree(tnfa->submatch_data[i].parents); +      xfree(tnfa->submatch_data); +    } + +  if (tnfa->tag_directions) +    xfree(tnfa->tag_directions); +  xfree(tnfa); +} + + +#define ERROR_EXIT(err)		  \ +  do				  \ +    {				  \ +      errcode = err;		  \ +      if (1) goto error_exit;	  \ +    }				  \ + while (0) + + +static int +tre_compile(regex_t *preg, const tre_char_t *regex, size_t n, int cflags) +{ +  tre_stack_t *stack; +  tre_ast_node_t *tree, *tmp_ast_l, *tmp_ast_r; +  tre_pos_and_tags_t *p; +  int *counts = NULL, *offs = NULL; +  int i, add = 0; +  tre_tnfa_transition_t *transitions, *initial; +  tre_tnfa_t *tnfa = NULL; +  tre_submatch_data_t *submatch_data; +  tre_tag_direction_t *tag_directions = NULL; +  reg_errcode_t errcode; +  tre_mem_t mem; + +  /* Parse context. */ +  tre_parse_ctx_t parse_ctx; + +  /* Allocate a stack used throughout the compilation process for various +     purposes. */ +  stack = tre_stack_new(512, 10240, 128); +  if (!stack) +    return REG_ESPACE; +  /* Allocate a fast memory allocator. */ +  mem = tre_mem_new(); +  if (!mem) +    { +      tre_stack_destroy(stack); +      return REG_ESPACE; +    } + +  /* Parse the regexp. */ +  memset(&parse_ctx, 0, sizeof(parse_ctx)); +  parse_ctx.mem = mem; +  parse_ctx.stack = stack; +  parse_ctx.re = regex; +  parse_ctx.len = n; +  parse_ctx.cflags = cflags; +  parse_ctx.max_backref = -1; +  DPRINT(("tre_compile: parsing '%.*" STRF "'\n", n, regex)); +  errcode = tre_parse(&parse_ctx); +  if (errcode != REG_OK) +    ERROR_EXIT(errcode); +  preg->re_nsub = parse_ctx.submatch_id - 1; +  tree = parse_ctx.result; + +#ifdef TRE_DEBUG +  tre_ast_print(tree); +#endif /* TRE_DEBUG */ + +  /* Referring to nonexistent subexpressions is illegal. */ +  if (parse_ctx.max_backref > (int)preg->re_nsub) +    ERROR_EXIT(REG_ESUBREG); + +  /* Allocate the TNFA struct. */ +  tnfa = xcalloc(1, sizeof(tre_tnfa_t)); +  if (tnfa == NULL) +    ERROR_EXIT(REG_ESPACE); +  tnfa->have_backrefs = parse_ctx.max_backref >= 0; +  tnfa->num_submatches = parse_ctx.submatch_id; + +  /* Set up tags for submatch addressing.  If REG_NOSUB is set and the +     regexp does not have back references, this can be skipped. */ +  if (tnfa->have_backrefs || !(cflags & REG_NOSUB)) +    { +      DPRINT(("tre_compile: setting up tags\n")); + +      /* Figure out how many tags we will need. */ +      errcode = tre_add_tags(NULL, stack, tree, tnfa); +      if (errcode != REG_OK) +	ERROR_EXIT(errcode); +#ifdef TRE_DEBUG +      tre_ast_print(tree); +#endif /* TRE_DEBUG */ + +      if (tnfa->num_tags > 0) +	{ +	  tag_directions = xmalloc(sizeof(*tag_directions) +				   * (tnfa->num_tags + 1)); +	  if (tag_directions == NULL) +	    ERROR_EXIT(REG_ESPACE); +	  tnfa->tag_directions = tag_directions; +	  memset(tag_directions, -1, +		 sizeof(*tag_directions) * (tnfa->num_tags + 1)); +	} + +      submatch_data = xcalloc(parse_ctx.submatch_id, sizeof(*submatch_data)); +      if (submatch_data == NULL) +	ERROR_EXIT(REG_ESPACE); +      tnfa->submatch_data = submatch_data; + +      errcode = tre_add_tags(mem, stack, tree, tnfa); +      if (errcode != REG_OK) +	ERROR_EXIT(errcode); + +#ifdef TRE_DEBUG +      for (i = 0; i < parse_ctx.submatch_id; i++) +	DPRINT(("pmatch[%d] = {t%d, t%d}\n", +		i, submatch_data[i].so_tag, submatch_data[i].eo_tag)); +      for (i = 0; i < tnfa->num_tags; i++) +	DPRINT(("t%d is %s\n", i, +		tag_directions[i] == TRE_TAG_MINIMIZE ? +		"minimized" : "maximized")); +#endif /* TRE_DEBUG */ +    } + +  /* Expand iteration nodes. */ +  errcode = tre_expand_ast(mem, stack, tree, &parse_ctx.position, +			   tag_directions, NULL); +  if (errcode != REG_OK) +    ERROR_EXIT(errcode); + +  /* Add a dummy node for the final state. +     XXX - For certain patterns this dummy node can be optimized away, +	   for example "a*" or "ab*".	Figure out a simple way to detect +	   this possibility. */ +  tmp_ast_l = tree; +  tmp_ast_r = tre_ast_new_literal(mem, 0, 0, parse_ctx.position++); +  if (tmp_ast_r == NULL) +    ERROR_EXIT(REG_ESPACE); + +  tree = tre_ast_new_catenation(mem, tmp_ast_l, tmp_ast_r); +  if (tree == NULL) +    ERROR_EXIT(REG_ESPACE); + +#ifdef TRE_DEBUG +  tre_ast_print(tree); +  DPRINT(("Number of states: %d\n", parse_ctx.position)); +#endif /* TRE_DEBUG */ + +  errcode = tre_compute_nfl(mem, stack, tree); +  if (errcode != REG_OK) +    ERROR_EXIT(errcode); + +  counts = xmalloc(sizeof(int) * parse_ctx.position); +  if (counts == NULL) +    ERROR_EXIT(REG_ESPACE); + +  offs = xmalloc(sizeof(int) * parse_ctx.position); +  if (offs == NULL) +    ERROR_EXIT(REG_ESPACE); + +  for (i = 0; i < parse_ctx.position; i++) +    counts[i] = 0; +  tre_ast_to_tnfa(tree, NULL, counts, NULL); + +  add = 0; +  for (i = 0; i < parse_ctx.position; i++) +    { +      offs[i] = add; +      add += counts[i] + 1; +      counts[i] = 0; +    } +  transitions = xcalloc(add + 1, sizeof(*transitions)); +  if (transitions == NULL) +    ERROR_EXIT(REG_ESPACE); +  tnfa->transitions = transitions; +  tnfa->num_transitions = add; + +  DPRINT(("Converting to TNFA:\n")); +  errcode = tre_ast_to_tnfa(tree, transitions, counts, offs); +  if (errcode != REG_OK) +    ERROR_EXIT(errcode); + +  p = tree->firstpos; +  i = 0; +  while (p->position >= 0) +    { +      i++; + +#ifdef TRE_DEBUG +      { +	int *tags; +	DPRINT(("initial: %d", p->position)); +	tags = p->tags; +	if (tags != NULL) +	  { +	    if (*tags >= 0) +	      DPRINT(("/")); +	    while (*tags >= 0) +	      { +		DPRINT(("%d", *tags)); +		tags++; +		if (*tags >= 0) +		  DPRINT((",")); +	      } +	  } +	DPRINT((", assert %d", p->assertions)); +	DPRINT(("\n")); +      } +#endif /* TRE_DEBUG */ + +      p++; +    } + +  initial = xcalloc(i + 1, sizeof(tre_tnfa_transition_t)); +  if (initial == NULL) +    ERROR_EXIT(REG_ESPACE); +  tnfa->initial = initial; + +  i = 0; +  for (p = tree->firstpos; p->position >= 0; p++) +    { +      initial[i].state = transitions + offs[p->position]; +      initial[i].state_id = p->position; +      initial[i].tags = NULL; +      /* Copy the arrays p->tags, they are allocated +	 from a tre_mem object. */ +      if (p->tags) +	{ +	  int j; +	  for (j = 0; p->tags[j] >= 0; j++); +	  initial[i].tags = xmalloc(sizeof(*p->tags) * (j + 1)); +	  if (!initial[i].tags) +	    ERROR_EXIT(REG_ESPACE); +	  memcpy(initial[i].tags, p->tags, sizeof(*p->tags) * (j + 1)); +	} +      initial[i].assertions = p->assertions; +      i++; +    } +  initial[i].state = NULL; + +  tnfa->num_transitions = add; +  tnfa->final = transitions + offs[tree->lastpos[0].position]; +  tnfa->num_states = parse_ctx.position; +  tnfa->cflags = cflags; + +  DPRINT(("final state %p\n", (void *)tnfa->final)); + +  tre_mem_destroy(mem); +  tre_stack_destroy(stack); +  xfree(counts); +  xfree(offs); + +  preg->TRE_REGEX_T_FIELD = (void *)tnfa; +  return REG_OK; + + error_exit: +  /* Free everything that was allocated and return the error code. */ +  tre_mem_destroy(mem); +  if (stack != NULL) +    tre_stack_destroy(stack); +  if (counts != NULL) +    xfree(counts); +  if (offs != NULL) +    xfree(offs); +  preg->TRE_REGEX_T_FIELD = (void *)tnfa; +  tre_free(preg); +  return errcode; +} + + +/*********************************************************************** + from regcomp.c +***********************************************************************/ + +int +regcomp(regex_t *preg, const char *regex, int cflags) +{ +  int ret; +  tre_char_t *wregex; +  size_t n = strlen(regex); + +  if (n+1 > SIZE_MAX/sizeof(tre_char_t)) +    return REG_ESPACE; +  wregex = xmalloc(sizeof(tre_char_t) * (n + 1)); +  if (wregex == NULL) +    return REG_ESPACE; + +  n = mbstowcs(wregex, regex, n+1); +  if (n == (size_t)-1) { +    xfree(wregex); +    return REG_BADPAT; +  } + +  ret = tre_compile(preg, wregex, n, cflags); +  xfree(wregex); + +  return ret; +} + +void +regfree(regex_t *preg) +{ +  tre_free(preg); +} + +/* EOF */ diff --git a/src/regex/regerror.c b/src/regex/regerror.c new file mode 100644 index 00000000..39d70b2a --- /dev/null +++ b/src/regex/regerror.c @@ -0,0 +1,75 @@ +/* +  regerror.c - POSIX regerror() implementation for TRE. + +  Copyright (c) 2001-2006 Ville Laurikari <vl@iki.fi>. + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 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 +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + +*/ + +#include <string.h> +#include <regex.h> + +/* Error message strings for error codes listed in `regex.h'.  This list +   needs to be in sync with the codes listed there, naturally. */ + +/* Converted to single string by Rich Felker to remove the need for + * data relocations at runtime, 27 Feb 2006. */ + +static const char tre_error_messages[] = { +  "No error\0" +  "No match\0" +  "Invalid regexp\0" +  "Unknown collating element\0" +  "Unknown character class name\0" +  "Trailing backslash\0" +  "Invalid back reference\0" +  "Missing ']'\0" +  "Missing ')'\0" +  "Missing '}'\0" +  "Invalid contents of {}\0" +  "Invalid character range\0" +  "Out of memory\0" +  "XXX\0" +}; + +size_t +regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) +{ +  const char *err; +  size_t err_len; + +  if (errcode >= 0 && errcode <= REG_BADRPT) +    for (err=tre_error_messages; errcode; errcode--, err+=strlen(err)+1); +  else +    err = "Unknown error"; + +  err_len = strlen(err) + 1; +  if (errbuf_size > 0 && errbuf != NULL) +    { +      if (err_len > errbuf_size) +	{ +	  memcpy(errbuf, err, errbuf_size - 1); +	  errbuf[errbuf_size - 1] = '\0'; +	} +      else +	{ +	  strcpy(errbuf, err); +	} +    } +  return err_len; +} + +/* EOF */ diff --git a/src/regex/regexec.c b/src/regex/regexec.c new file mode 100644 index 00000000..0c3d2834 --- /dev/null +++ b/src/regex/regexec.c @@ -0,0 +1,1107 @@ +/* +  regexec.c - TRE POSIX compatible matching functions (and more). + +  Copyright (c) 2001-2006 Ville Laurikari <vl@iki.fi>. + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 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 +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + +*/ + +#include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include <wctype.h> +#include <limits.h> + +#include <regex.h> + +#include "tre.h" + +#include <assert.h> + +static void +tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags, +		const tre_tnfa_t *tnfa, int *tags, int match_eo); + +/*********************************************************************** + from tre-match-utils.h +***********************************************************************/ + +#define GET_NEXT_WCHAR() do {                                                 \ +    prev_c = next_c; pos += pos_add_next;                                     \ +    if ((pos_add_next = mbtowc(&next_c, str_byte, MB_LEN_MAX)) <= 0) {        \ +        if (pos_add_next < 0) return REG_NOMATCH;                             \ +        else pos_add_next++;                                                  \ +    }                                                                         \ +    str_byte += pos_add_next;                                                 \ +  } while (0) + +#define CHECK_ASSERTIONS(assertions)					      \ +  (((assertions & ASSERT_AT_BOL)					      \ +    && (pos > 0 || reg_notbol)						      \ +    && (prev_c != L'\n' || !reg_newline))				      \ +   || ((assertions & ASSERT_AT_EOL)					      \ +       && (next_c != L'\0' || reg_noteol)				      \ +       && (next_c != L'\n' || !reg_newline))) + +/* Returns 1 if `t1' wins `t2', 0 otherwise. */ +static int +tre_tag_order(int num_tags, tre_tag_direction_t *tag_directions, +	      int *t1, int *t2) +{ +  int i; +  for (i = 0; i < num_tags; i++) +    { +      if (tag_directions[i] == TRE_TAG_MINIMIZE) +	{ +	  if (t1[i] < t2[i]) +	    return 1; +	  if (t1[i] > t2[i]) +	    return 0; +	} +      else +	{ +	  if (t1[i] > t2[i]) +	    return 1; +	  if (t1[i] < t2[i]) +	    return 0; +	} +    } +  /*  assert(0);*/ +  return 0; +} + +static int +tre_neg_char_classes_match(tre_ctype_t *classes, tre_cint_t wc, int icase) +{ +  DPRINT(("neg_char_classes_test: %p, %d, %d\n", classes, wc, icase)); +  while (*classes != (tre_ctype_t)0) +    if ((!icase && tre_isctype(wc, *classes)) +	|| (icase && (tre_isctype(tre_toupper(wc), *classes) +		      || tre_isctype(tre_tolower(wc), *classes)))) +      return 1; /* Match. */ +    else +      classes++; +  return 0; /* No match. */ +} + + +/*********************************************************************** + from tre-match-parallel.c +***********************************************************************/ + +/* +  This algorithm searches for matches basically by reading characters +  in the searched string one by one, starting at the beginning.	 All +  matching paths in the TNFA are traversed in parallel.	 When two or +  more paths reach the same state, exactly one is chosen according to +  tag ordering rules; if returning submatches is not required it does +  not matter which path is chosen. + +  The worst case time required for finding the leftmost and longest +  match, or determining that there is no match, is always linearly +  dependent on the length of the text being searched. + +  This algorithm cannot handle TNFAs with back referencing nodes. +  See `tre-match-backtrack.c'. +*/ + + +typedef struct { +  tre_tnfa_transition_t *state; +  int *tags; +} tre_tnfa_reach_t; + +typedef struct { +  int pos; +  int **tags; +} tre_reach_pos_t; + + +#ifdef TRE_DEBUG +static void +tre_print_reach(const tre_tnfa_t *tnfa, tre_tnfa_reach_t *reach, int num_tags) +{ +  int i; + +  while (reach->state != NULL) +    { +      DPRINT((" %p", (void *)reach->state)); +      if (num_tags > 0) +	{ +	  DPRINT(("/")); +	  for (i = 0; i < num_tags; i++) +	    { +	      DPRINT(("%d:%d", i, reach->tags[i])); +	      if (i < (num_tags-1)) +		DPRINT((",")); +	    } +	} +      reach++; +    } +  DPRINT(("\n")); + +} +#endif /* TRE_DEBUG */ + +static reg_errcode_t +tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string, int len, +		      int *match_tags, int eflags, int *match_end_ofs) +{ +  /* State variables required by GET_NEXT_WCHAR. */ +  tre_char_t prev_c = 0, next_c = 0; +  const char *str_byte = string; +  int pos = -1; +  int pos_add_next = 1; +#ifdef TRE_MBSTATE +  mbstate_t mbstate; +#endif /* TRE_MBSTATE */ +  int reg_notbol = eflags & REG_NOTBOL; +  int reg_noteol = eflags & REG_NOTEOL; +  int reg_newline = tnfa->cflags & REG_NEWLINE; + +  char *buf; +  tre_tnfa_transition_t *trans_i; +  tre_tnfa_reach_t *reach, *reach_next, *reach_i, *reach_next_i; +  tre_reach_pos_t *reach_pos; +  int *tag_i; +  int num_tags, i; + +  int match_eo = -1;	   /* end offset of match (-1 if no match found yet) */ +  int new_match = 0; +  int *tmp_tags = NULL; +  int *tmp_iptr; + +#ifdef TRE_MBSTATE +  memset(&mbstate, '\0', sizeof(mbstate)); +#endif /* TRE_MBSTATE */ + +  if (!match_tags) +    num_tags = 0; +  else +    num_tags = tnfa->num_tags; + +  /* Allocate memory for temporary data required for matching.	This needs to +     be done for every matching operation to be thread safe.  This allocates +     everything in a single large block from the stack frame using alloca() +     or with malloc() if alloca is unavailable. */ +  { +    int tbytes, rbytes, pbytes, xbytes, total_bytes; +    char *tmp_buf; +    /* Compute the length of the block we need. */ +    tbytes = sizeof(*tmp_tags) * num_tags; +    rbytes = sizeof(*reach_next) * (tnfa->num_states + 1); +    pbytes = sizeof(*reach_pos) * tnfa->num_states; +    xbytes = sizeof(int) * num_tags; +    total_bytes = +      (sizeof(long) - 1) * 4 /* for alignment paddings */ +      + (rbytes + xbytes * tnfa->num_states) * 2 + tbytes + pbytes; + +    /* Allocate the memory. */ +#ifdef TRE_USE_ALLOCA +    buf = alloca(total_bytes); +#else /* !TRE_USE_ALLOCA */ +    buf = xmalloc(total_bytes); +#endif /* !TRE_USE_ALLOCA */ +    if (buf == NULL) +      return REG_ESPACE; +    memset(buf, 0, total_bytes); + +    /* Get the various pointers within tmp_buf (properly aligned). */ +    tmp_tags = (void *)buf; +    tmp_buf = buf + tbytes; +    tmp_buf += ALIGN(tmp_buf, long); +    reach_next = (void *)tmp_buf; +    tmp_buf += rbytes; +    tmp_buf += ALIGN(tmp_buf, long); +    reach = (void *)tmp_buf; +    tmp_buf += rbytes; +    tmp_buf += ALIGN(tmp_buf, long); +    reach_pos = (void *)tmp_buf; +    tmp_buf += pbytes; +    tmp_buf += ALIGN(tmp_buf, long); +    for (i = 0; i < tnfa->num_states; i++) +      { +	reach[i].tags = (void *)tmp_buf; +	tmp_buf += xbytes; +	reach_next[i].tags = (void *)tmp_buf; +	tmp_buf += xbytes; +      } +  } + +  for (i = 0; i < tnfa->num_states; i++) +    reach_pos[i].pos = -1; + +  GET_NEXT_WCHAR(); +  pos = 0; + +  DPRINT(("length: %d\n", len)); +  DPRINT(("pos:chr/code | states and tags\n")); +  DPRINT(("-------------+------------------------------------------------\n")); + +  reach_next_i = reach_next; +  while (1) +    { +      /* If no match found yet, add the initial states to `reach_next'. */ +      if (match_eo < 0) +	{ +	  DPRINT((" init >")); +	  trans_i = tnfa->initial; +	  while (trans_i->state != NULL) +	    { +	      if (reach_pos[trans_i->state_id].pos < pos) +		{ +		  if (trans_i->assertions +		      && CHECK_ASSERTIONS(trans_i->assertions)) +		    { +		      DPRINT(("assertion failed\n")); +		      trans_i++; +		      continue; +		    } + +		  DPRINT((" %p", (void *)trans_i->state)); +		  reach_next_i->state = trans_i->state; +		  for (i = 0; i < num_tags; i++) +		    reach_next_i->tags[i] = -1; +		  tag_i = trans_i->tags; +		  if (tag_i) +		    while (*tag_i >= 0) +		      { +			if (*tag_i < num_tags) +			  reach_next_i->tags[*tag_i] = pos; +			tag_i++; +		      } +		  if (reach_next_i->state == tnfa->final) +		    { +		      DPRINT(("	 found empty match\n")); +		      match_eo = pos; +		      new_match = 1; +		      for (i = 0; i < num_tags; i++) +			match_tags[i] = reach_next_i->tags[i]; +		    } +		  reach_pos[trans_i->state_id].pos = pos; +		  reach_pos[trans_i->state_id].tags = &reach_next_i->tags; +		  reach_next_i++; +		} +	      trans_i++; +	    } +	  DPRINT(("\n")); +	  reach_next_i->state = NULL; +	} +      else +	{ +	  if (num_tags == 0 || reach_next_i == reach_next) +	    /* We have found a match. */ +	    break; +	} + +      /* Check for end of string. */ +      if (!next_c) break; + +      GET_NEXT_WCHAR(); + +#ifdef TRE_DEBUG +      DPRINT(("%3d:%2lc/%05d |", pos - 1, (tre_cint_t)prev_c, (int)prev_c)); +      tre_print_reach(tnfa, reach_next, num_tags); +      DPRINT(("%3d:%2lc/%05d |", pos, (tre_cint_t)next_c, (int)next_c)); +      tre_print_reach(tnfa, reach_next, num_tags); +#endif /* TRE_DEBUG */ + +      /* Swap `reach' and `reach_next'. */ +      reach_i = reach; +      reach = reach_next; +      reach_next = reach_i; + +      /* For each state in `reach' see if there is a transition leaving with +	 the current input symbol to a state not yet in `reach_next', and +	 add the destination states to `reach_next'. */ +      reach_next_i = reach_next; +      for (reach_i = reach; reach_i->state; reach_i++) +	{ +	  for (trans_i = reach_i->state; trans_i->state; trans_i++) +	    { +	      /* Does this transition match the input symbol? */ +	      if (trans_i->code_min <= prev_c && +		  trans_i->code_max >= prev_c) +		{ +		  if (trans_i->assertions +		      && (CHECK_ASSERTIONS(trans_i->assertions) +			  /* Handle character class transitions. */ +			  || ((trans_i->assertions & ASSERT_CHAR_CLASS) +			      && !(tnfa->cflags & REG_ICASE) +			      && !tre_isctype((tre_cint_t)prev_c, +					      trans_i->u.class)) +			  || ((trans_i->assertions & ASSERT_CHAR_CLASS) +			      && (tnfa->cflags & REG_ICASE) +			      && (!tre_isctype(tre_tolower((tre_cint_t)prev_c), +					       trans_i->u.class) +				  && !tre_isctype(tre_toupper((tre_cint_t)prev_c), +						  trans_i->u.class))) +			  || ((trans_i->assertions & ASSERT_CHAR_CLASS_NEG) +			      && tre_neg_char_classes_match(trans_i->neg_classes, +							    (tre_cint_t)prev_c, +							    tnfa->cflags & REG_ICASE)))) +		    { +		      DPRINT(("assertion failed\n")); +		      continue; +		    } + +		  /* Compute the tags after this transition. */ +		  for (i = 0; i < num_tags; i++) +		    tmp_tags[i] = reach_i->tags[i]; +		  tag_i = trans_i->tags; +		  if (tag_i != NULL) +		    while (*tag_i >= 0) +		      { +			if (*tag_i < num_tags) +			  tmp_tags[*tag_i] = pos; +			tag_i++; +		      } + +		  if (reach_pos[trans_i->state_id].pos < pos) +		    { +		      /* Found an unvisited node. */ +		      reach_next_i->state = trans_i->state; +		      tmp_iptr = reach_next_i->tags; +		      reach_next_i->tags = tmp_tags; +		      tmp_tags = tmp_iptr; +		      reach_pos[trans_i->state_id].pos = pos; +		      reach_pos[trans_i->state_id].tags = &reach_next_i->tags; + +		      if (reach_next_i->state == tnfa->final +			  && (match_eo == -1 +			      || (num_tags > 0 +				  && reach_next_i->tags[0] <= match_tags[0]))) +			{ +			  DPRINT(("  found match %p\n", trans_i->state)); +			  match_eo = pos; +			  new_match = 1; +			  for (i = 0; i < num_tags; i++) +			    match_tags[i] = reach_next_i->tags[i]; +			} +		      reach_next_i++; + +		    } +		  else +		    { +		      assert(reach_pos[trans_i->state_id].pos == pos); +		      /* Another path has also reached this state.  We choose +			 the winner by examining the tag values for both +			 paths. */ +		      if (tre_tag_order(num_tags, tnfa->tag_directions, +					tmp_tags, +					*reach_pos[trans_i->state_id].tags)) +			{ +			  /* The new path wins. */ +			  tmp_iptr = *reach_pos[trans_i->state_id].tags; +			  *reach_pos[trans_i->state_id].tags = tmp_tags; +			  if (trans_i->state == tnfa->final) +			    { +			      DPRINT(("	 found better match\n")); +			      match_eo = pos; +			      new_match = 1; +			      for (i = 0; i < num_tags; i++) +				match_tags[i] = tmp_tags[i]; +			    } +			  tmp_tags = tmp_iptr; +			} +		    } +		} +	    } +	} +      reach_next_i->state = NULL; +    } + +  DPRINT(("match end offset = %d\n", match_eo)); + +#ifndef TRE_USE_ALLOCA +  if (buf) +    xfree(buf); +#endif /* !TRE_USE_ALLOCA */ + +  *match_end_ofs = match_eo; +  return match_eo >= 0 ? REG_OK : REG_NOMATCH; +} + + +/*********************************************************************** + from tre-match-backtrack.c +***********************************************************************/ + +/* +  This matcher is for regexps that use back referencing.  Regexp matching +  with back referencing is an NP-complete problem on the number of back +  references.  The easiest way to match them is to use a backtracking +  routine which basically goes through all possible paths in the TNFA +  and chooses the one which results in the best (leftmost and longest) +  match.  This can be spectacularly expensive and may run out of stack +  space, but there really is no better known generic algorithm.	 Quoting +  Henry Spencer from comp.compilers: +  <URL: http://compilers.iecc.com/comparch/article/93-03-102> + +    POSIX.2 REs require longest match, which is really exciting to +    implement since the obsolete ("basic") variant also includes +    \<digit>.  I haven't found a better way of tackling this than doing +    a preliminary match using a DFA (or simulation) on a modified RE +    that just replicates subREs for \<digit>, and then doing a +    backtracking match to determine whether the subRE matches were +    right.  This can be rather slow, but I console myself with the +    thought that people who use \<digit> deserve very slow execution. +    (Pun unintentional but very appropriate.) + +*/ + +typedef struct { +  int pos; +  const char *str_byte; +  tre_tnfa_transition_t *state; +  int state_id; +  int next_c; +  int *tags; +#ifdef TRE_MBSTATE +  mbstate_t mbstate; +#endif /* TRE_MBSTATE */ +} tre_backtrack_item_t; + +typedef struct tre_backtrack_struct { +  tre_backtrack_item_t item; +  struct tre_backtrack_struct *prev; +  struct tre_backtrack_struct *next; +} *tre_backtrack_t; + +#ifdef TRE_MBSTATE +#define BT_STACK_MBSTATE_IN  stack->item.mbstate = (mbstate) +#define BT_STACK_MBSTATE_OUT (mbstate) = stack->item.mbstate +#else /* !TRE_MBSTATE */ +#define BT_STACK_MBSTATE_IN +#define BT_STACK_MBSTATE_OUT +#endif /* !TRE_MBSTATE */ + + +#ifdef TRE_USE_ALLOCA +#define tre_bt_mem_new		  tre_mem_newa +#define tre_bt_mem_alloc	  tre_mem_alloca +#define tre_bt_mem_destroy(obj)	  do { } while (0) +#else /* !TRE_USE_ALLOCA */ +#define tre_bt_mem_new		  tre_mem_new +#define tre_bt_mem_alloc	  tre_mem_alloc +#define tre_bt_mem_destroy	  tre_mem_destroy +#endif /* !TRE_USE_ALLOCA */ + + +#define BT_STACK_PUSH(_pos, _str_byte, _str_wide, _state, _state_id, _next_c, _tags, _mbstate) \ +  do									      \ +    {									      \ +      int i;								      \ +      if (!stack->next)							      \ +	{								      \ +	  tre_backtrack_t s;						      \ +	  s = tre_bt_mem_alloc(mem, sizeof(*s));			      \ +	  if (!s)							      \ +	    {								      \ +	      tre_bt_mem_destroy(mem);					      \ +	      if (tags)							      \ +		xfree(tags);						      \ +	      if (pmatch)						      \ +		xfree(pmatch);						      \ +	      if (states_seen)						      \ +		xfree(states_seen);					      \ +	      return REG_ESPACE;					      \ +	    }								      \ +	  s->prev = stack;						      \ +	  s->next = NULL;						      \ +	  s->item.tags = tre_bt_mem_alloc(mem,				      \ +					  sizeof(*tags) * tnfa->num_tags);    \ +	  if (!s->item.tags)						      \ +	    {								      \ +	      tre_bt_mem_destroy(mem);					      \ +	      if (tags)							      \ +		xfree(tags);						      \ +	      if (pmatch)						      \ +		xfree(pmatch);						      \ +	      if (states_seen)						      \ +		xfree(states_seen);					      \ +	      return REG_ESPACE;					      \ +	    }								      \ +	  stack->next = s;						      \ +	  stack = s;							      \ +	}								      \ +      else								      \ +	stack = stack->next;						      \ +      stack->item.pos = (_pos);						      \ +      stack->item.str_byte = (_str_byte);				      \ +      stack->item.state = (_state);					      \ +      stack->item.state_id = (_state_id);				      \ +      stack->item.next_c = (_next_c);					      \ +      for (i = 0; i < tnfa->num_tags; i++)				      \ +	stack->item.tags[i] = (_tags)[i];				      \ +      BT_STACK_MBSTATE_IN;						      \ +    }									      \ +  while (0) + +#define BT_STACK_POP()							      \ +  do									      \ +    {									      \ +      int i;								      \ +      assert(stack->prev);						      \ +      pos = stack->item.pos;						      \ +      str_byte = stack->item.str_byte;					      \ +      state = stack->item.state;					      \ +      next_c = stack->item.next_c;					      \ +      for (i = 0; i < tnfa->num_tags; i++)				      \ +	tags[i] = stack->item.tags[i];					      \ +      BT_STACK_MBSTATE_OUT;						      \ +      stack = stack->prev;						      \ +    }									      \ +  while (0) + +#undef MIN +#define MIN(a, b) ((a) <= (b) ? (a) : (b)) + +static reg_errcode_t +tre_tnfa_run_backtrack(const tre_tnfa_t *tnfa, const void *string, +		       int len, int *match_tags, +		       int eflags, int *match_end_ofs) +{ +  /* State variables required by GET_NEXT_WCHAR. */ +  tre_char_t prev_c = 0, next_c = 0; +  const char *str_byte = string; +  int pos = 0; +  int pos_add_next = 1; +#ifdef TRE_MBSTATE +  mbstate_t mbstate; +#endif /* TRE_MBSTATE */ +  int reg_notbol = eflags & REG_NOTBOL; +  int reg_noteol = eflags & REG_NOTEOL; +  int reg_newline = tnfa->cflags & REG_NEWLINE; + +  /* These are used to remember the necessary values of the above +     variables to return to the position where the current search +     started from. */ +  int next_c_start; +  const char *str_byte_start; +  int pos_start = -1; +#ifdef TRE_MBSTATE +  mbstate_t mbstate_start; +#endif /* TRE_MBSTATE */ + +  /* Compilation flags for this regexp. */ +  int cflags = tnfa->cflags; + +  /* End offset of best match so far, or -1 if no match found yet. */ +  int match_eo = -1; +  /* Tag arrays. */ +  int *next_tags, *tags = NULL; +  /* Current TNFA state. */ +  tre_tnfa_transition_t *state; +  int *states_seen = NULL; + +  /* Memory allocator to for allocating the backtracking stack. */ +  tre_mem_t mem = tre_bt_mem_new(); + +  /* The backtracking stack. */ +  tre_backtrack_t stack; + +  tre_tnfa_transition_t *trans_i; +  regmatch_t *pmatch = NULL; +  int ret; + +#ifdef TRE_MBSTATE +  memset(&mbstate, '\0', sizeof(mbstate)); +#endif /* TRE_MBSTATE */ + +  if (!mem) +    return REG_ESPACE; +  stack = tre_bt_mem_alloc(mem, sizeof(*stack)); +  if (!stack) +    { +      ret = REG_ESPACE; +      goto error_exit; +    } +  stack->prev = NULL; +  stack->next = NULL; + +#ifdef TRE_USE_ALLOCA +  tags = alloca(sizeof(*tags) * tnfa->num_tags); +  pmatch = alloca(sizeof(*pmatch) * tnfa->num_submatches); +  states_seen = alloca(sizeof(*states_seen) * tnfa->num_states); +#else /* !TRE_USE_ALLOCA */ +  tags = xmalloc(sizeof(*tags) * tnfa->num_tags); +  if (!tags) +    { +      ret = REG_ESPACE; +      goto error_exit; +    } +  pmatch = xmalloc(sizeof(*pmatch) * tnfa->num_submatches); +  if (!pmatch) +    { +      ret = REG_ESPACE; +      goto error_exit; +    } +  states_seen = xmalloc(sizeof(*states_seen) * tnfa->num_states); +  if (!states_seen) +    { +      ret = REG_ESPACE; +      goto error_exit; +    } +#endif /* !TRE_USE_ALLOCA */ + + retry: +  { +    int i; +    for (i = 0; i < tnfa->num_tags; i++) +      { +	tags[i] = -1; +	if (match_tags) +	  match_tags[i] = -1; +      } +    for (i = 0; i < tnfa->num_states; i++) +      states_seen[i] = 0; +  } + +  state = NULL; +  pos = pos_start; +  GET_NEXT_WCHAR(); +  pos_start = pos; +  next_c_start = next_c; +  str_byte_start = str_byte; +#ifdef TRE_MBSTATE +  mbstate_start = mbstate; +#endif /* TRE_MBSTATE */ + +  /* Handle initial states. */ +  next_tags = NULL; +  for (trans_i = tnfa->initial; trans_i->state; trans_i++) +    { +      DPRINT(("> init %p, prev_c %lc\n", trans_i->state, (tre_cint_t)prev_c)); +      if (trans_i->assertions && CHECK_ASSERTIONS(trans_i->assertions)) +	{ +	  DPRINT(("assert failed\n")); +	  continue; +	} +      if (state == NULL) +	{ +	  /* Start from this state. */ +	  state = trans_i->state; +	  next_tags = trans_i->tags; +	} +      else +	{ +	  /* Backtrack to this state. */ +	  DPRINT(("saving state %d for backtracking\n", trans_i->state_id)); +	  BT_STACK_PUSH(pos, str_byte, str_wide, trans_i->state, +			trans_i->state_id, next_c, tags, mbstate); +	  { +	    int *tmp = trans_i->tags; +	    if (tmp) +	      while (*tmp >= 0) +		stack->item.tags[*tmp++] = pos; +	  } +	} +    } + +  if (next_tags) +    for (; *next_tags >= 0; next_tags++) +      tags[*next_tags] = pos; + + +  DPRINT(("entering match loop, pos %d, str_byte %p\n", pos, str_byte)); +  DPRINT(("pos:chr/code | state and tags\n")); +  DPRINT(("-------------+------------------------------------------------\n")); + +  if (state == NULL) +    goto backtrack; + +  while (1) +    { +      tre_tnfa_transition_t *trans_i, *next_state; +      int empty_br_match; + +      DPRINT(("start loop\n")); +      if (state == tnfa->final) +	{ +	  DPRINT(("  match found, %d %d\n", match_eo, pos)); +	  if (match_eo < pos +	      || (match_eo == pos +		  && match_tags +		  && tre_tag_order(tnfa->num_tags, tnfa->tag_directions, +				   tags, match_tags))) +	    { +	      int i; +	      /* This match wins the previous match. */ +	      DPRINT(("	 win previous\n")); +	      match_eo = pos; +	      if (match_tags) +		for (i = 0; i < tnfa->num_tags; i++) +		  match_tags[i] = tags[i]; +	    } +	  /* Our TNFAs never have transitions leaving from the final state, +	     so we jump right to backtracking. */ +	  goto backtrack; +	} + +#ifdef TRE_DEBUG +      DPRINT(("%3d:%2lc/%05d | %p ", pos, (tre_cint_t)next_c, (int)next_c, +	      state)); +      { +	int i; +	for (i = 0; i < tnfa->num_tags; i++) +	  DPRINT(("%d%s", tags[i], i < tnfa->num_tags - 1 ? ", " : "")); +	DPRINT(("\n")); +      } +#endif /* TRE_DEBUG */ + +      /* Go to the next character in the input string. */ +      empty_br_match = 0; +      trans_i = state; +      if (trans_i->state && trans_i->assertions & ASSERT_BACKREF) +	{ +	  /* This is a back reference state.  All transitions leaving from +	     this state have the same back reference "assertion".  Instead +	     of reading the next character, we match the back reference. */ +	  int so, eo, bt = trans_i->u.backref; +	  int bt_len; +	  int result; + +	  DPRINT(("  should match back reference %d\n", bt)); +	  /* Get the substring we need to match against.  Remember to +	     turn off REG_NOSUB temporarily. */ +	  tre_fill_pmatch(bt + 1, pmatch, tnfa->cflags & !REG_NOSUB, +			  tnfa, tags, pos); +	  so = pmatch[bt].rm_so; +	  eo = pmatch[bt].rm_eo; +	  bt_len = eo - so; + +	  if (len < 0) +	    { +	      result = strncmp((char*)string + so, str_byte - 1, bt_len); +	    } +	  else if (len - pos < bt_len) +	    result = 1; +	  else +	    result = memcmp((char*)string + so, str_byte - 1, bt_len); + +	  /* We can ignore multibyte characters here because the backref +	     string is already aligned at character boundaries. */ +	  if (result == 0) +	    { +	      /* Back reference matched.  Check for infinite loop. */ +	      if (bt_len == 0) +		empty_br_match = 1; +	      if (empty_br_match && states_seen[trans_i->state_id]) +		{ +		  DPRINT(("  avoid loop\n")); +		  goto backtrack; +		} + +	      states_seen[trans_i->state_id] = empty_br_match; + +	      /* Advance in input string and resync `prev_c', `next_c' +		 and pos. */ +	      DPRINT(("	 back reference matched\n")); +	      str_byte += bt_len - 1; +	      pos += bt_len - 1; +	      GET_NEXT_WCHAR(); +	      DPRINT(("	 pos now %d\n", pos)); +	    } +	  else +	    { +	      DPRINT(("	 back reference did not match\n")); +	      goto backtrack; +	    } +	} +      else +	{ +	  /* Check for end of string. */ +	  if (len < 0) +	    { +	      if (next_c == L'\0') +		goto backtrack; +	    } +	  else +	    { +	      if (pos >= len) +		goto backtrack; +	    } + +	  /* Read the next character. */ +	  GET_NEXT_WCHAR(); +	} + +      next_state = NULL; +      for (trans_i = state; trans_i->state; trans_i++) +	{ +	  DPRINT(("  transition %d-%d (%c-%c) %d to %d\n", +		  trans_i->code_min, trans_i->code_max, +		  trans_i->code_min, trans_i->code_max, +		  trans_i->assertions, trans_i->state_id)); +	  if (trans_i->code_min <= prev_c && trans_i->code_max >= prev_c) +	    { +	      if (trans_i->assertions +		  && (CHECK_ASSERTIONS(trans_i->assertions) +		      /* Handle character class transitions. */ +		      || ((trans_i->assertions & ASSERT_CHAR_CLASS) +			  && !(cflags & REG_ICASE) +			  && !tre_isctype((tre_cint_t)prev_c, trans_i->u.class)) +		      || ((trans_i->assertions & ASSERT_CHAR_CLASS) +			  && (cflags & REG_ICASE) +			  && (!tre_isctype(tre_tolower((tre_cint_t)prev_c), +					   trans_i->u.class) +			      && !tre_isctype(tre_toupper((tre_cint_t)prev_c), +					      trans_i->u.class))) +		      || ((trans_i->assertions & ASSERT_CHAR_CLASS_NEG) +			  && tre_neg_char_classes_match(trans_i->neg_classes, +							(tre_cint_t)prev_c, +							cflags & REG_ICASE)))) +		{ +		  DPRINT(("  assertion failed\n")); +		  continue; +		} + +	      if (next_state == NULL) +		{ +		  /* First matching transition. */ +		  DPRINT(("  Next state is %d\n", trans_i->state_id)); +		  next_state = trans_i->state; +		  next_tags = trans_i->tags; +		} +	      else +		{ +		  /* Second mathing transition.	 We may need to backtrack here +		     to take this transition instead of the first one, so we +		     push this transition in the backtracking stack so we can +		     jump back here if needed. */ +		  DPRINT(("  saving state %d for backtracking\n", +			  trans_i->state_id)); +		  BT_STACK_PUSH(pos, str_byte, str_wide, trans_i->state, +				trans_i->state_id, next_c, tags, mbstate); +		  { +		    int *tmp; +		    for (tmp = trans_i->tags; tmp && *tmp >= 0; tmp++) +		      stack->item.tags[*tmp] = pos; +		  } +#if 0 /* XXX - it's important not to look at all transitions here to keep +	 the stack small! */ +		  break; +#endif +		} +	    } +	} + +      if (next_state != NULL) +	{ +	  /* Matching transitions were found.  Take the first one. */ +	  state = next_state; + +	  /* Update the tag values. */ +	  if (next_tags) +	    while (*next_tags >= 0) +	      tags[*next_tags++] = pos; +	} +      else +	{ +	backtrack: +	  /* A matching transition was not found.  Try to backtrack. */ +	  if (stack->prev) +	    { +	      DPRINT(("	 backtracking\n")); +	      if (stack->item.state->assertions && ASSERT_BACKREF) +		{ +		  DPRINT(("  states_seen[%d] = 0\n", +			  stack->item.state_id)); +		  states_seen[stack->item.state_id] = 0; +		} + +	      BT_STACK_POP(); +	    } +	  else if (match_eo < 0) +	    { +	      /* Try starting from a later position in the input string. */ +	      /* Check for end of string. */ +	      if (len < 0) +		{ +		  if (next_c == L'\0') +		    { +		      DPRINT(("end of string.\n")); +		      break; +		    } +		} +	      else +		{ +		  if (pos >= len) +		    { +		      DPRINT(("end of string.\n")); +		      break; +		    } +		} +	      DPRINT(("restarting from next start position\n")); +	      next_c = next_c_start; +#ifdef TRE_MBSTATE +	      mbstate = mbstate_start; +#endif /* TRE_MBSTATE */ +	      str_byte = str_byte_start; +	      goto retry; +	    } +	  else +	    { +	      DPRINT(("finished\n")); +	      break; +	    } +	} +    } + +  ret = match_eo >= 0 ? REG_OK : REG_NOMATCH; +  *match_end_ofs = match_eo; + + error_exit: +  tre_bt_mem_destroy(mem); +#ifndef TRE_USE_ALLOCA +  if (tags) +    xfree(tags); +  if (pmatch) +    xfree(pmatch); +  if (states_seen) +    xfree(states_seen); +#endif /* !TRE_USE_ALLOCA */ + +  return ret; +} + + +/*********************************************************************** + from regexec.c +***********************************************************************/ + +/* Fills the POSIX.2 regmatch_t array according to the TNFA tag and match +   endpoint values. */ +static void +tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags, +		const tre_tnfa_t *tnfa, int *tags, int match_eo) +{ +  tre_submatch_data_t *submatch_data; +  unsigned int i, j; +  int *parents; + +  i = 0; +  if (match_eo >= 0 && !(cflags & REG_NOSUB)) +    { +      /* Construct submatch offsets from the tags. */ +      DPRINT(("end tag = t%d = %d\n", tnfa->end_tag, match_eo)); +      submatch_data = tnfa->submatch_data; +      while (i < tnfa->num_submatches && i < nmatch) +	{ +	  if (submatch_data[i].so_tag == tnfa->end_tag) +	    pmatch[i].rm_so = match_eo; +	  else +	    pmatch[i].rm_so = tags[submatch_data[i].so_tag]; + +	  if (submatch_data[i].eo_tag == tnfa->end_tag) +	    pmatch[i].rm_eo = match_eo; +	  else +	    pmatch[i].rm_eo = tags[submatch_data[i].eo_tag]; + +	  /* If either of the endpoints were not used, this submatch +	     was not part of the match. */ +	  if (pmatch[i].rm_so == -1 || pmatch[i].rm_eo == -1) +	    pmatch[i].rm_so = pmatch[i].rm_eo = -1; + +	  DPRINT(("pmatch[%d] = {t%d = %d, t%d = %d}\n", i, +		  submatch_data[i].so_tag, pmatch[i].rm_so, +		  submatch_data[i].eo_tag, pmatch[i].rm_eo)); +	  i++; +	} +      /* Reset all submatches that are not within all of their parent +	 submatches. */ +      i = 0; +      while (i < tnfa->num_submatches && i < nmatch) +	{ +	  if (pmatch[i].rm_eo == -1) +	    assert(pmatch[i].rm_so == -1); +	  assert(pmatch[i].rm_so <= pmatch[i].rm_eo); + +	  parents = submatch_data[i].parents; +	  if (parents != NULL) +	    for (j = 0; parents[j] >= 0; j++) +	      { +		DPRINT(("pmatch[%d] parent %d\n", i, parents[j])); +		if (pmatch[i].rm_so < pmatch[parents[j]].rm_so +		    || pmatch[i].rm_eo > pmatch[parents[j]].rm_eo) +		  pmatch[i].rm_so = pmatch[i].rm_eo = -1; +	      } +	  i++; +	} +    } + +  while (i < nmatch) +    { +      pmatch[i].rm_so = -1; +      pmatch[i].rm_eo = -1; +      i++; +    } +} + + +/* +  Wrapper functions for POSIX compatible regexp matching. +*/ + +static int +tre_match(const tre_tnfa_t *tnfa, const void *string, size_t len, +	  size_t nmatch, regmatch_t pmatch[], int eflags) +{ +  reg_errcode_t status; +  int *tags = NULL, eo; +  if (tnfa->num_tags > 0 && nmatch > 0) +    { +#ifdef TRE_USE_ALLOCA +      tags = alloca(sizeof(*tags) * tnfa->num_tags); +#else /* !TRE_USE_ALLOCA */ +      tags = xmalloc(sizeof(*tags) * tnfa->num_tags); +#endif /* !TRE_USE_ALLOCA */ +      if (tags == NULL) +	return REG_ESPACE; +    } + +  /* Dispatch to the appropriate matcher. */ +  if (tnfa->have_backrefs) +    { +      /* The regex has back references, use the backtracking matcher. */ +      status = tre_tnfa_run_backtrack(tnfa, string, len, tags, eflags, &eo); +    } +  else +    { +      /* Exact matching, no back references, use the parallel matcher. */ +      status = tre_tnfa_run_parallel(tnfa, string, len, tags, eflags, &eo); +    } + +  if (status == REG_OK) +    /* A match was found, so fill the submatch registers. */ +    tre_fill_pmatch(nmatch, pmatch, tnfa->cflags, tnfa, tags, eo); +#ifndef TRE_USE_ALLOCA +  if (tags) +    xfree(tags); +#endif /* !TRE_USE_ALLOCA */ +  return status; +} + +int +regexec(const regex_t *preg, const char *str, +	size_t nmatch, regmatch_t pmatch[], int eflags) +{ +  return tre_match((void *)preg->TRE_REGEX_T_FIELD, str, -1, +                   nmatch, pmatch, eflags); +} + +/* EOF */ diff --git a/src/regex/tre-mem.c b/src/regex/tre-mem.c new file mode 100644 index 00000000..d7bdd3db --- /dev/null +++ b/src/regex/tre-mem.c @@ -0,0 +1,163 @@ +/* +  tre-mem.c - TRE memory allocator + +  Copyright (c) 2001-2006 Ville Laurikari <vl@iki.fi> + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 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 +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + +*/ + +/* +  This memory allocator is for allocating small memory blocks efficiently +  in terms of memory overhead and execution speed.  The allocated blocks +  cannot be freed individually, only all at once.  There can be multiple +  allocators, though. +*/ + +#include <stdlib.h> +#include <string.h> + +#include "tre.h" + + +/* Returns a new memory allocator or NULL if out of memory. */ +tre_mem_t +tre_mem_new_impl(int provided, void *provided_block) +{ +  tre_mem_t mem; +  if (provided) +    { +      mem = provided_block; +      memset(mem, 0, sizeof(*mem)); +    } +  else +    mem = xcalloc(1, sizeof(*mem)); +  if (mem == NULL) +    return NULL; +  return mem; +} + + +/* Frees the memory allocator and all memory allocated with it. */ +void +tre_mem_destroy(tre_mem_t mem) +{ +  tre_list_t *tmp, *l = mem->blocks; + +  while (l != NULL) +    { +      xfree(l->data); +      tmp = l->next; +      xfree(l); +      l = tmp; +    } +  xfree(mem); +} + + +/* Allocates a block of `size' bytes from `mem'.  Returns a pointer to the +   allocated block or NULL if an underlying malloc() failed. */ +void * +tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block, +		   int zero, size_t size) +{ +  void *ptr; + +  if (mem->failed) +    { +      DPRINT(("tre_mem_alloc: oops, called after failure?!\n")); +      return NULL; +    } + +#ifdef MALLOC_DEBUGGING +  if (!provided) +    { +      ptr = xmalloc(1); +      if (ptr == NULL) +	{ +	  DPRINT(("tre_mem_alloc: xmalloc forced failure\n")); +	  mem->failed = 1; +	  return NULL; +	} +      xfree(ptr); +    } +#endif /* MALLOC_DEBUGGING */ + +  if (mem->n < size) +    { +      /* We need more memory than is available in the current block. +	 Allocate a new block. */ +      tre_list_t *l; +      if (provided) +	{ +	  DPRINT(("tre_mem_alloc: using provided block\n")); +	  if (provided_block == NULL) +	    { +	      DPRINT(("tre_mem_alloc: provided block was NULL\n")); +	      mem->failed = 1; +	      return NULL; +	    } +	  mem->ptr = provided_block; +	  mem->n = TRE_MEM_BLOCK_SIZE; +	} +      else +	{ +	  int block_size; +	  if (size * 8 > TRE_MEM_BLOCK_SIZE) +	    block_size = size * 8; +	  else +	    block_size = TRE_MEM_BLOCK_SIZE; +	  DPRINT(("tre_mem_alloc: allocating new %d byte block\n", +		  block_size)); +	  l = xmalloc(sizeof(*l)); +	  if (l == NULL) +	    { +	      mem->failed = 1; +	      return NULL; +	    } +	  l->data = xmalloc(block_size); +	  if (l->data == NULL) +	    { +	      xfree(l); +	      mem->failed = 1; +	      return NULL; +	    } +	  l->next = NULL; +	  if (mem->current != NULL) +	    mem->current->next = l; +	  if (mem->blocks == NULL) +	    mem->blocks = l; +	  mem->current = l; +	  mem->ptr = l->data; +	  mem->n = block_size; +	} +    } + +  /* Make sure the next pointer will be aligned. */ +  size += ALIGN(mem->ptr + size, long); + +  /* Allocate from current block. */ +  ptr = mem->ptr; +  mem->ptr += size; +  mem->n -= size; + +  /* Set to zero if needed. */ +  if (zero) +    memset(ptr, 0, size); + +  return ptr; +} + +/* EOF */ diff --git a/src/regex/tre.h b/src/regex/tre.h new file mode 100644 index 00000000..bfd171f4 --- /dev/null +++ b/src/regex/tre.h @@ -0,0 +1,269 @@ +/* +  tre-internal.h - TRE internal definitions + +  Copyright (c) 2001-2006 Ville Laurikari <vl@iki.fi>. + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 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 +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + +*/ + +#include <regex.h> +#include <wchar.h> +#include <wctype.h> + +#define TRE_MULTIBYTE 1 +#undef  TRE_MBSTATE +#define TRE_WCHAR 1 +#define TRE_USE_SYSTEM_WCTYPE 1 +#define HAVE_WCSTOMBS 1 +#define TRE_MB_CUR_MAX MB_CUR_MAX + +#define NDEBUG + +#define TRE_REGEX_T_FIELD __opaque +typedef int reg_errcode_t; + +typedef wchar_t tre_char_t; + + +#ifdef TRE_DEBUG +#include <stdio.h> +#define DPRINT(msg) do {printf msg; fflush(stdout);} while(0) +#else /* !TRE_DEBUG */ +#define DPRINT(msg) do { } while(0) +#endif /* !TRE_DEBUG */ + +#define elementsof(x)	( sizeof(x) / sizeof(x[0]) ) + +#if 1 +int __mbtowc(wchar_t *, const char *); +#define tre_mbrtowc(pwc, s, n, ps) (__mbtowc((pwc), (s))) +#else +#define tre_mbrtowc(pwc, s, n, ps) (mbtowc((pwc), (s), (n))) +#endif + +/* Wide characters. */ +typedef wint_t tre_cint_t; +#define TRE_CHAR_MAX WCHAR_MAX + +#ifdef TRE_MULTIBYTE +#define TRE_MB_CUR_MAX MB_CUR_MAX +#else /* !TRE_MULTIBYTE */ +#define TRE_MB_CUR_MAX 1 +#endif /* !TRE_MULTIBYTE */ + +#define tre_isalnum iswalnum +#define tre_isalpha iswalpha +#define tre_isblank iswblank +#define tre_iscntrl iswcntrl +#define tre_isdigit iswdigit +#define tre_isgraph iswgraph +#define tre_islower iswlower +#define tre_isprint iswprint +#define tre_ispunct iswpunct +#define tre_isspace iswspace +#define tre_isupper iswupper +#define tre_isxdigit iswxdigit + +#define tre_tolower towlower +#define tre_toupper towupper +#define tre_strlen  wcslen + +/* Use system provided iswctype() and wctype(). */ +typedef wctype_t tre_ctype_t; +#define tre_isctype iswctype +#define tre_ctype   wctype + +/* Returns number of bytes to add to (char *)ptr to make it +   properly aligned for the type. */ +#define ALIGN(ptr, type) \ +  ((((long)ptr) % sizeof(type)) \ +   ? (sizeof(type) - (((long)ptr) % sizeof(type))) \ +   : 0) + +#undef MAX +#undef MIN +#define MAX(a, b) (((a) >= (b)) ? (a) : (b)) +#define MIN(a, b) (((a) <= (b)) ? (a) : (b)) + +/* Define STRF to the correct printf formatter for strings. */ +#define STRF "ls" + +/* TNFA transition type. A TNFA state is an array of transitions, +   the terminator is a transition with NULL `state'. */ +typedef struct tnfa_transition tre_tnfa_transition_t; + +struct tnfa_transition { +  /* Range of accepted characters. */ +  tre_cint_t code_min; +  tre_cint_t code_max; +  /* Pointer to the destination state. */ +  tre_tnfa_transition_t *state; +  /* ID number of the destination state. */ +  int state_id; +  /* -1 terminated array of tags (or NULL). */ +  int *tags; +  /* Assertion bitmap. */ +  int assertions; +  /* Assertion parameters. */ +  union { +    /* Character class assertion. */ +    tre_ctype_t class; +    /* Back reference assertion. */ +    int backref; +  } u; +  /* Negative character class assertions. */ +  tre_ctype_t *neg_classes; +}; + + +/* Assertions. */ +#define ASSERT_AT_BOL		  1   /* Beginning of line. */ +#define ASSERT_AT_EOL		  2   /* End of line. */ +#define ASSERT_CHAR_CLASS	  4   /* Character class in `class'. */ +#define ASSERT_CHAR_CLASS_NEG	  8   /* Character classes in `neg_classes'. */ +#define ASSERT_AT_BOW		 16   /* Beginning of word. */ +#define ASSERT_AT_EOW		 32   /* End of word. */ +#define ASSERT_AT_WB		 64   /* Word boundary. */ +#define ASSERT_AT_WB_NEG	128   /* Not a word boundary. */ +#define ASSERT_BACKREF		256   /* A back reference in `backref'. */ +#define ASSERT_LAST		256 + +/* Tag directions. */ +typedef enum { +  TRE_TAG_MINIMIZE = 0, +  TRE_TAG_MAXIMIZE = 1 +} tre_tag_direction_t; + +/* Instructions to compute submatch register values from tag values +   after a successful match.  */ +struct tre_submatch_data { +  /* Tag that gives the value for rm_so (submatch start offset). */ +  int so_tag; +  /* Tag that gives the value for rm_eo (submatch end offset). */ +  int eo_tag; +  /* List of submatches this submatch is contained in. */ +  int *parents; +}; + +typedef struct tre_submatch_data tre_submatch_data_t; + + +/* TNFA definition. */ +typedef struct tnfa tre_tnfa_t; + +struct tnfa { +  tre_tnfa_transition_t *transitions; +  unsigned int num_transitions; +  tre_tnfa_transition_t *initial; +  tre_tnfa_transition_t *final; +  tre_submatch_data_t *submatch_data; +  unsigned int num_submatches; +  tre_tag_direction_t *tag_directions; +  int num_tags; +  int end_tag; +  int num_states; +  int cflags; +  int have_backrefs; +}; + +#if 0 +static int +tre_compile(regex_t *preg, const tre_char_t *regex, size_t n, int cflags); + +static void +tre_free(regex_t *preg); + +static void +tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags, +		const tre_tnfa_t *tnfa, int *tags, int match_eo); + +static reg_errcode_t +tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string, int len, +		      tre_str_type_t type, int *match_tags, int eflags, +		      int *match_end_ofs); + +static reg_errcode_t +tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string, int len, +		      tre_str_type_t type, int *match_tags, int eflags, +		      int *match_end_ofs); + +static reg_errcode_t +tre_tnfa_run_backtrack(const tre_tnfa_t *tnfa, const void *string, +		       int len, tre_str_type_t type, int *match_tags, +		       int eflags, int *match_end_ofs); +#endif + +/* from tre-mem.h: */ + +#define TRE_MEM_BLOCK_SIZE 1024 + +typedef struct tre_list { +  void *data; +  struct tre_list *next; +} tre_list_t; + +typedef struct tre_mem_struct { +  tre_list_t *blocks; +  tre_list_t *current; +  char *ptr; +  size_t n; +  int failed; +  void **provided; +} *tre_mem_t; + +#define tre_mem_new_impl   __tre_mem_new_impl +#define tre_mem_alloc_impl __tre_mem_alloc_impl +#define tre_mem_destroy    __tre_mem_destroy + +tre_mem_t tre_mem_new_impl(int provided, void *provided_block); +void *tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block, +			 int zero, size_t size); + +/* Returns a new memory allocator or NULL if out of memory. */ +#define tre_mem_new()  tre_mem_new_impl(0, NULL) + +/* Allocates a block of `size' bytes from `mem'.  Returns a pointer to the +   allocated block or NULL if an underlying malloc() failed. */ +#define tre_mem_alloc(mem, size) tre_mem_alloc_impl(mem, 0, NULL, 0, size) + +/* Allocates a block of `size' bytes from `mem'.  Returns a pointer to the +   allocated block or NULL if an underlying malloc() failed.  The memory +   is set to zero. */ +#define tre_mem_calloc(mem, size) tre_mem_alloc_impl(mem, 0, NULL, 1, size) + +#ifdef TRE_USE_ALLOCA +/* alloca() versions.  Like above, but memory is allocated with alloca() +   instead of malloc(). */ + +#define tre_mem_newa() \ +  tre_mem_new_impl(1, alloca(sizeof(struct tre_mem_struct))) + +#define tre_mem_alloca(mem, size)					      \ +  ((mem)->n >= (size)							      \ +   ? tre_mem_alloc_impl((mem), 1, NULL, 0, (size))			      \ +   : tre_mem_alloc_impl((mem), 1, alloca(TRE_MEM_BLOCK_SIZE), 0, (size))) +#endif /* TRE_USE_ALLOCA */ + + +/* Frees the memory allocator and all memory allocated with it. */ +void tre_mem_destroy(tre_mem_t mem); + +#define xmalloc malloc +#define xcalloc calloc +#define xfree free +#define xrealloc realloc + +/* EOF */ diff --git a/src/select/poll.c b/src/select/poll.c new file mode 100644 index 00000000..e92943e1 --- /dev/null +++ b/src/select/poll.c @@ -0,0 +1,12 @@ +#include <poll.h> +#include "syscall.h" +#include "libc.h" + +int poll(struct pollfd *fds, nfds_t n, int timeout) +{ +	int r; +	CANCELPT_BEGIN; +	r = syscall3(__NR_poll, (long)fds, n, timeout); +	CANCELPT_END; +	return r; +} diff --git a/src/select/pselect.c b/src/select/pselect.c new file mode 100644 index 00000000..795c5b0d --- /dev/null +++ b/src/select/pselect.c @@ -0,0 +1,15 @@ +#include <sys/select.h> +#include "syscall.h" +#include "libc.h" + +int pselect(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, const struct timespec *ts, const sigset_t *mask) +{ +	int r; +	long data[2] = { (long)mask, 8 }; +	struct timespec ts_tmp; +	if (ts) ts_tmp = *ts; +	CANCELPT_BEGIN; +	r = syscall6(__NR_pselect6, n, (long)rfds, (long)wfds, (long)efds, ts ? (long)&ts_tmp : 0, (long)data); +	CANCELPT_END; +	return r; +} diff --git a/src/select/select.c b/src/select/select.c new file mode 100644 index 00000000..a604d094 --- /dev/null +++ b/src/select/select.c @@ -0,0 +1,12 @@ +#include <sys/select.h> +#include "syscall.h" +#include "libc.h" + +int select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv) +{ +	int r; +	CANCELPT_BEGIN; +	r = syscall5(__NR__newselect, n, (long)rfds, (long)wfds, (long)efds, (long)tv); +	CANCELPT_END; +	return r; +} diff --git a/src/setjmp/i386/longjmp.s b/src/setjmp/i386/longjmp.s new file mode 100644 index 00000000..c1a956c3 --- /dev/null +++ b/src/setjmp/i386/longjmp.s @@ -0,0 +1,22 @@ +.global _longjmp +.global longjmp +.type _longjmp,%function +.type longjmp,%function +_longjmp: +longjmp: +	movl  4(%esp),%edx +	movl  8(%esp),%eax +	testl    %eax,%eax +	jnz .L0 +	incl     %eax +.L0: +	movl   (%edx),%ebx +	movl  4(%edx),%esi +	movl  8(%edx),%edi +	movl 12(%edx),%ebp +	movl 16(%edx),%ecx +	movl     %ecx,%esp +	movl 20(%edx),%ecx +	jmp *%ecx +.size _longjmp,.-_longjmp +.size longjmp,.-longjmp diff --git a/src/setjmp/i386/setjmp.s b/src/setjmp/i386/setjmp.s new file mode 100644 index 00000000..6c078b10 --- /dev/null +++ b/src/setjmp/i386/setjmp.s @@ -0,0 +1,23 @@ +.global __setjmp +.global _setjmp +.global setjmp +.type __setjmp,%function +.type _setjmp,%function +.type setjmp,%function +__setjmp: +_setjmp: +setjmp: +	movl 4(%esp), %eax +	movl    %ebx, (%eax) +	movl    %esi, 4(%eax) +	movl    %edi, 8(%eax) +	movl    %ebp, 12(%eax) +	leal 4(%esp), %ecx +	movl    %ecx, 16(%eax) +	movl  (%esp), %ecx +	movl    %ecx, 20(%eax) +	xorl    %eax, %eax +	ret +.size __setjmp,.-__setjmp +.size _setjmp,.-_setjmp +.size setjmp,.-setjmp diff --git a/src/setjmp/longjmp.c b/src/setjmp/longjmp.c new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/setjmp/longjmp.c diff --git a/src/setjmp/setjmp.c b/src/setjmp/setjmp.c new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/setjmp/setjmp.c diff --git a/src/signal/bsd_signal.c b/src/signal/bsd_signal.c new file mode 100644 index 00000000..0b9a6855 --- /dev/null +++ b/src/signal/bsd_signal.c @@ -0,0 +1,6 @@ +#include <signal.h> + +void (*bsd_signal(int sig, void (*func)(int)))(int) +{ +	return signal(sig, func); +} diff --git a/src/signal/getitimer.c b/src/signal/getitimer.c new file mode 100644 index 00000000..222d113e --- /dev/null +++ b/src/signal/getitimer.c @@ -0,0 +1,12 @@ +#include <sys/time.h> +#include "syscall.h" + +int getitimer(int which, struct itimerval *old) +{ +	int ret; +	long kold[4]; + +	if (!(ret = syscall2(__NR_getitimer, which, (long)&kold))) +		*old = (struct itimerval){ { kold[0], kold[1] }, { kold[2], kold[3] } }; +	return ret; +} diff --git a/src/signal/i386/sigsetjmp.s b/src/signal/i386/sigsetjmp.s new file mode 100644 index 00000000..0e7eefb0 --- /dev/null +++ b/src/signal/i386/sigsetjmp.s @@ -0,0 +1,13 @@ +.global sigsetjmp +sigsetjmp: +	mov 4(%esp),%eax +	mov 8(%esp),%ecx +	mov %ecx,24(%eax) +	jecxz 1f +	add $28,%eax +	push %eax +	push $0 +	push $2 +	call sigprocmask +	add $12,%esp +1:	jmp setjmp diff --git a/src/signal/kill.c b/src/signal/kill.c new file mode 100644 index 00000000..cc4b51e1 --- /dev/null +++ b/src/signal/kill.c @@ -0,0 +1,7 @@ +#include <signal.h> +#include "syscall.h" + +int kill(pid_t pid, int sig) +{ +	return syscall2(__NR_kill, pid, sig); +} diff --git a/src/signal/killpg.c b/src/signal/killpg.c new file mode 100644 index 00000000..315ed447 --- /dev/null +++ b/src/signal/killpg.c @@ -0,0 +1,11 @@ +#include <signal.h> +#include <errno.h> + +int killpg(pid_t pgid, int sig) +{ +	if (pgid < 0) { +		errno = EINVAL; +		return -1; +	} +	return kill(-pgid, sig); +} diff --git a/src/signal/raise.c b/src/signal/raise.c new file mode 100644 index 00000000..52f8b428 --- /dev/null +++ b/src/signal/raise.c @@ -0,0 +1,7 @@ +#include <signal.h> +#include "syscall.h" + +int raise(int sig) +{ +	return __syscall_kill(__syscall_getpid(), sig); +} diff --git a/src/signal/setitimer.c b/src/signal/setitimer.c new file mode 100644 index 00000000..cacab036 --- /dev/null +++ b/src/signal/setitimer.c @@ -0,0 +1,15 @@ +#include <sys/time.h> +#include "syscall.h" + +int setitimer(int which, const struct itimerval *new, struct itimerval *old) +{ +	int ret; +	long knew[4] = { +		new->it_interval.tv_sec, new->it_interval.tv_usec, +		new->it_value.tv_sec, new->it_value.tv_usec +	}, kold[4]; + +	if (!(ret = syscall3(__NR_setitimer, which, (long)&knew, old ? (long)&kold : 0)) && old) +		*old = (struct itimerval){ { kold[0], kold[1] }, { kold[2], kold[3] } }; +	return ret; +} diff --git a/src/signal/sigaction.c b/src/signal/sigaction.c new file mode 100644 index 00000000..4acd1730 --- /dev/null +++ b/src/signal/sigaction.c @@ -0,0 +1,48 @@ +#include <stdlib.h> +#include <signal.h> +#include <errno.h> +#include "syscall.h" +#include "pthread_impl.h" + +static void restorer() +{ +	syscall0(__NR_rt_sigreturn); +} + +int __libc_sigaction(int sig, const struct sigaction *sa, struct sigaction *old) +{ +	struct { +		void *handler; +		unsigned long flags; +		void (*restorer)(void); +		sigset_t mask; +	} ksa, kold; +	long pksa=0, pkold=0; +	if (sa) { +		ksa.handler = sa->sa_handler; +		ksa.flags = sa->sa_flags; +		ksa.restorer = restorer; +		ksa.mask = sa->sa_mask; +		pksa = (long)&ksa; +	} +	if (old) pkold = (long)&kold; +	if (syscall4(__NR_rt_sigaction, sig, pksa, pkold, 8)) +		return -1; +	if (old) { +		old->sa_handler = kold.handler; +		old->sa_flags = kold.flags; +		old->sa_mask = kold.mask; +	} +	return 0; +} + +int __sigaction(int sig, const struct sigaction *sa, struct sigaction *old) +{ +	if (sig == SIGCANCEL || sig == SIGSYSCALL) { +		errno = EINVAL; +		return -1; +	} +	return __libc_sigaction(sig, sa, old); +} + +weak_alias(__sigaction, sigaction); diff --git a/src/signal/sigaddset.c b/src/signal/sigaddset.c new file mode 100644 index 00000000..23e655db --- /dev/null +++ b/src/signal/sigaddset.c @@ -0,0 +1,13 @@ +#include <signal.h> +#include <errno.h> + +int sigaddset(sigset_t *set, int sig) +{ +	unsigned s = sig-1; +	if (s >= 8*sizeof(sigset_t)) { +		errno = EINVAL; +		return -1; +	} +	set->__bits[s/8/sizeof *set->__bits] |= 1UL<<(s&8*sizeof *set->__bits-1); +	return 0; +} diff --git a/src/signal/sigaltstack.c b/src/signal/sigaltstack.c new file mode 100644 index 00000000..3cc2d456 --- /dev/null +++ b/src/signal/sigaltstack.c @@ -0,0 +1,8 @@ +#include <signal.h> +#include "syscall.h" + +int sigaltstack(const stack_t *ss, stack_t *old) +{ +	/* depends on kernel struct matching */ +	return syscall2(__NR_sigaltstack, (long)ss, (long)old); +} diff --git a/src/signal/sigdelset.c b/src/signal/sigdelset.c new file mode 100644 index 00000000..14042fb8 --- /dev/null +++ b/src/signal/sigdelset.c @@ -0,0 +1,13 @@ +#include <signal.h> +#include <errno.h> + +int sigdelset(sigset_t *set, int sig) +{ +	unsigned s = sig-1; +	if (s >= 8*sizeof(sigset_t)) { +		errno = EINVAL; +		return -1; +	} +	set->__bits[s/8/sizeof *set->__bits] &=~(1UL<<(s&8*sizeof *set->__bits-1)); +	return 0; +} diff --git a/src/signal/sigemptyset.c b/src/signal/sigemptyset.c new file mode 100644 index 00000000..91f77adf --- /dev/null +++ b/src/signal/sigemptyset.c @@ -0,0 +1,8 @@ +#include <signal.h> +#include <string.h> + +int sigemptyset(sigset_t *set) +{ +	memset(set, 0, sizeof *set); +	return 0; +} diff --git a/src/signal/sigfillset.c b/src/signal/sigfillset.c new file mode 100644 index 00000000..fab50a52 --- /dev/null +++ b/src/signal/sigfillset.c @@ -0,0 +1,8 @@ +#include <signal.h> +#include <string.h> + +int sigfillset(sigset_t *set) +{ +	memset(set, -1, sizeof *set); +	return 0; +} diff --git a/src/signal/sighold.c b/src/signal/sighold.c new file mode 100644 index 00000000..5b0f6b18 --- /dev/null +++ b/src/signal/sighold.c @@ -0,0 +1,11 @@ +#include <signal.h> +#include <stdlib.h> + +int sighold(int sig) +{ +	sigset_t mask; + +	sigemptyset(&mask); +	if (sigaddset(&mask, sig) < 0) return -1; +	return sigprocmask(SIG_BLOCK, &mask, NULL); +} diff --git a/src/signal/sigignore.c b/src/signal/sigignore.c new file mode 100644 index 00000000..98dff61e --- /dev/null +++ b/src/signal/sigignore.c @@ -0,0 +1,12 @@ +#include <signal.h> +#include <stdlib.h> + +int sigignore(int sig) +{ +	struct sigaction sa; + +	sigemptyset(&sa.sa_mask); +	sa.sa_handler = SIG_IGN; +	sa.sa_flags = 0; +	return sigaction(sig, &sa, NULL); +} diff --git a/src/signal/siginterrupt.c b/src/signal/siginterrupt.c new file mode 100644 index 00000000..60b34054 --- /dev/null +++ b/src/signal/siginterrupt.c @@ -0,0 +1,13 @@ +#include <stdlib.h> +#include <signal.h> + +int siginterrupt(int sig, int flag) +{ +	struct sigaction sa; + +	sigaction(sig, NULL, &sa); +	if (flag) sa.sa_flags &= ~SA_RESTART; +	else sa.sa_flags |= SA_RESTART; + +	return sigaction(sig, &sa, NULL); +} diff --git a/src/signal/sigismember.c b/src/signal/sigismember.c new file mode 100644 index 00000000..afd29e52 --- /dev/null +++ b/src/signal/sigismember.c @@ -0,0 +1,12 @@ +#include <signal.h> +#include <errno.h> + +int sigismember(const sigset_t *set, int sig) +{ +	unsigned s = sig-1; +	if (s >= 8*sizeof(sigset_t)) { +		errno = EINVAL; +		return -1; +	} +	return !!(set->__bits[s/8/sizeof *set->__bits] & 1UL<<(s&8*sizeof *set->__bits-1)); +} diff --git a/src/signal/siglongjmp.c b/src/signal/siglongjmp.c new file mode 100644 index 00000000..33ac30ea --- /dev/null +++ b/src/signal/siglongjmp.c @@ -0,0 +1,12 @@ +#include <setjmp.h> +#include <signal.h> +#include <stdlib.h> + +void siglongjmp(sigjmp_buf buf, int ret) +{ +	long *flag = buf + sizeof(jmp_buf)/sizeof(long); +	sigset_t *mask = (void *)(flag + 1); +	if (*flag) +		sigprocmask (SIG_SETMASK, mask, NULL); +	longjmp((void *)buf, ret); +} diff --git a/src/signal/signal.c b/src/signal/signal.c new file mode 100644 index 00000000..08902760 --- /dev/null +++ b/src/signal/signal.c @@ -0,0 +1,13 @@ +#include <signal.h> +#include <stddef.h> +#include "syscall.h" + +int __sigaction(int, const struct sigaction *, struct sigaction *); + +void (*signal(int sig, void (*func)(int)))(int) +{ +	struct sigaction sa = { .sa_handler = func, .sa_flags = SA_RESTART }; +	if (__sigaction(sig, &sa, &sa) < 0) +		return SIG_ERR; +	return sa.sa_handler; +} diff --git a/src/signal/sigpause.c b/src/signal/sigpause.c new file mode 100644 index 00000000..263c00f5 --- /dev/null +++ b/src/signal/sigpause.c @@ -0,0 +1,11 @@ +#include <signal.h> +#include <stdlib.h> + +int sigpause(int sig) +{ +	sigset_t mask; + +	if (sigprocmask(0, NULL, &mask) < 0 || sigdelset(&mask, sig) < 0) +		return -1; +	return sigsuspend(&mask); +} diff --git a/src/signal/sigpending.c b/src/signal/sigpending.c new file mode 100644 index 00000000..7deda256 --- /dev/null +++ b/src/signal/sigpending.c @@ -0,0 +1,7 @@ +#include <signal.h> +#include "syscall.h" + +int sigpending(sigset_t *set) +{ +	return syscall2(__NR_rt_sigpending, (long)set, SYSCALL_SIGSET_SIZE); +} diff --git a/src/signal/sigprocmask.c b/src/signal/sigprocmask.c new file mode 100644 index 00000000..e89f8765 --- /dev/null +++ b/src/signal/sigprocmask.c @@ -0,0 +1,23 @@ +#include <signal.h> +#include "syscall.h" +#include "libc.h" + +int __libc_sigprocmask(int how, const sigset_t *set, sigset_t *old) +{ +	return syscall4(__NR_rt_sigprocmask, how, (long)set, (long)old, 8); +} + +int __sigprocmask(int how, const sigset_t *set, sigset_t *old) +{ +	sigset_t tmp; +	/* Quickly mask out bits 32 and 33 (thread control signals) */ +	if (0 && how != SIG_UNBLOCK && (set->__bits[4/sizeof *set->__bits] & 3UL<<(32&8*sizeof *set->__bits-1))) { +		tmp = *set; +		set = &tmp; +		tmp.__bits[4/sizeof *set->__bits] &= ~(3UL<<(32&8*sizeof *set->__bits-1)); +	} +	return __libc_sigprocmask(how, set, old); +} + +weak_alias(__sigprocmask, sigprocmask); +weak_alias(__sigprocmask, pthread_sigmask); diff --git a/src/signal/sigqueue.c b/src/signal/sigqueue.c new file mode 100644 index 00000000..ce3abf6c --- /dev/null +++ b/src/signal/sigqueue.c @@ -0,0 +1,14 @@ +#include <signal.h> +#include <string.h> +#include <unistd.h> +#include "syscall.h" + +int sigqueue(pid_t pid, int sig, const union sigval value) +{ +	siginfo_t si = { +		.si_signo = sig, +		.si_code = -1, +		.si_value = value, +	}; +	return syscall3(__NR_rt_sigqueueinfo, pid, sig, (long)&si); +} diff --git a/src/signal/sigrelse.c b/src/signal/sigrelse.c new file mode 100644 index 00000000..b0b3024b --- /dev/null +++ b/src/signal/sigrelse.c @@ -0,0 +1,11 @@ +#include <signal.h> +#include <stdlib.h> + +int sigrelse(int sig) +{ +	sigset_t mask; + +	sigemptyset(&mask); +	if (sigaddset(&mask, sig) < 0) return -1; +	return sigprocmask(SIG_UNBLOCK, &mask, NULL); +} diff --git a/src/signal/sigrtmax.c b/src/signal/sigrtmax.c new file mode 100644 index 00000000..0ef29873 --- /dev/null +++ b/src/signal/sigrtmax.c @@ -0,0 +1,4 @@ +int __libc_current_sigrtmax() +{ +	return 64; +} diff --git a/src/signal/sigrtmin.c b/src/signal/sigrtmin.c new file mode 100644 index 00000000..7ad06d22 --- /dev/null +++ b/src/signal/sigrtmin.c @@ -0,0 +1,4 @@ +int __libc_current_sigrtmin() +{ +	return 34; +} diff --git a/src/signal/sigset.c b/src/signal/sigset.c new file mode 100644 index 00000000..1b6b38fd --- /dev/null +++ b/src/signal/sigset.c @@ -0,0 +1,28 @@ +#include <signal.h> +#include <stdlib.h> + +void (*sigset(int sig, void (*handler)(int)))(int) +{ +	struct sigaction sa, sa_old; +	sigset_t mask; + +	sigemptyset(&mask); +	if (sigaddset(&mask, sig) < 0) +		return SIG_ERR; +	 +	if (handler == SIG_HOLD) { +		if (sigaction(sig, NULL, &sa_old) < 0) +			return SIG_ERR; +		if (sigprocmask(SIG_BLOCK, &mask, &mask) < 0) +			return SIG_ERR; +	} else { +		sa.sa_handler = handler; +		sa.sa_flags = 0; +		sigemptyset(&sa.sa_mask); +		if (sigaction(sig, &sa, &sa_old) < 0) +			return SIG_ERR; +		if (sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0) +			return SIG_ERR; +	} +	return sigismember(&mask, sig) ? SIG_HOLD : sa_old.sa_handler; +} diff --git a/src/signal/sigsetjmp.c b/src/signal/sigsetjmp.c new file mode 100644 index 00000000..a6667a27 --- /dev/null +++ b/src/signal/sigsetjmp.c @@ -0,0 +1,17 @@ +#include <setjmp.h> +#include <signal.h> +#include <stdlib.h> + +/* !!! This function will not work unless the compiler performs + * tail call optimization. Machine-specific asm versions should + * be created instead even though the workaround (tail call) + * is entirely non-machine-specific... */ + +int sigsetjmp(sigjmp_buf buf, int save) +{ +	long *flag = buf + sizeof(jmp_buf)/sizeof(long); +	sigset_t *mask = (void *)(flag + 1); +	if ((*flag = save)) +		sigprocmask (SIG_SETMASK, NULL, mask); +	return setjmp((void *)buf); +} diff --git a/src/signal/sigsuspend.c b/src/signal/sigsuspend.c new file mode 100644 index 00000000..1acdab06 --- /dev/null +++ b/src/signal/sigsuspend.c @@ -0,0 +1,7 @@ +#include <signal.h> +#include "syscall.h" + +int sigsuspend(const sigset_t *mask) +{ +	return syscall2(__NR_rt_sigsuspend, (long)mask, sizeof(sigset_t)); +} diff --git a/src/signal/sigtimedwait.c b/src/signal/sigtimedwait.c new file mode 100644 index 00000000..155185de --- /dev/null +++ b/src/signal/sigtimedwait.c @@ -0,0 +1,12 @@ +#include <signal.h> +#include "syscall.h" + +int sigtimedwait(const sigset_t *mask, siginfo_t *si, const struct timespec *timeout) +{ +	long k_timeout[2]; +	if (timeout) { +		k_timeout[0] = timeout->tv_sec; +		k_timeout[1] = timeout->tv_nsec; +	} +	return syscall4(__NR_rt_sigtimedwait, (long)mask, (long)si, timeout ? (long)k_timeout : 0, SYSCALL_SIGSET_SIZE); +} diff --git a/src/signal/sigwait.c b/src/signal/sigwait.c new file mode 100644 index 00000000..9569d6b0 --- /dev/null +++ b/src/signal/sigwait.c @@ -0,0 +1,11 @@ +#include <signal.h> +#include <stddef.h> + +int sigwait(const sigset_t *mask, int *sig) +{ +	siginfo_t si; +	if (sigtimedwait(mask, &si, NULL) < 0) +		return -1; +	*sig = si.si_signo; +	return 0; +} diff --git a/src/signal/sigwaitinfo.c b/src/signal/sigwaitinfo.c new file mode 100644 index 00000000..e79feb91 --- /dev/null +++ b/src/signal/sigwaitinfo.c @@ -0,0 +1,7 @@ +#include <signal.h> +#include <stddef.h> + +int sigwaitinfo(const sigset_t *mask, siginfo_t *si) +{ +	return sigtimedwait(mask, si, NULL); +} diff --git a/src/stat/chmod.c b/src/stat/chmod.c new file mode 100644 index 00000000..cb310fec --- /dev/null +++ b/src/stat/chmod.c @@ -0,0 +1,7 @@ +#include <sys/stat.h> +#include "syscall.h" + +int chmod(const char *path, mode_t mode) +{ +	return syscall2(__NR_chmod, (long)path, mode); +} diff --git a/src/stat/fchmod.c b/src/stat/fchmod.c new file mode 100644 index 00000000..91897383 --- /dev/null +++ b/src/stat/fchmod.c @@ -0,0 +1,7 @@ +#include <sys/stat.h> +#include "syscall.h" + +int fchmod(int fd, mode_t mode) +{ +	return syscall2(__NR_fchmod, fd, mode); +} diff --git a/src/stat/fchmodat.c b/src/stat/fchmodat.c new file mode 100644 index 00000000..f4f22b2c --- /dev/null +++ b/src/stat/fchmodat.c @@ -0,0 +1,7 @@ +#include <sys/stat.h> +#include "syscall.h" + +int fchmodat(int fd, const char *path, mode_t mode, int flag) +{ +	return syscall4(__NR_fchmodat, fd, (long)path, mode, flag); +} diff --git a/src/stat/fstat.c b/src/stat/fstat.c new file mode 100644 index 00000000..5f643301 --- /dev/null +++ b/src/stat/fstat.c @@ -0,0 +1,10 @@ +#include <sys/stat.h> +#include "syscall.h" +#include "libc.h" + +int fstat(int fd, struct stat *buf) +{ +	return syscall2(__NR_fstat64, fd, (long)buf); +} + +LFS64(fstat); diff --git a/src/stat/fstatat.c b/src/stat/fstatat.c new file mode 100644 index 00000000..22bc2934 --- /dev/null +++ b/src/stat/fstatat.c @@ -0,0 +1,10 @@ +#include <sys/stat.h> +#include "syscall.h" +#include "libc.h" + +int fstatat(int fd, const char *path, struct stat *buf, int flag) +{ +	return syscall4(__NR_fstatat64, fd, (long)path, (long)buf, flag); +} + +LFS64(fstatat); diff --git a/src/stat/fstatvfs.c b/src/stat/fstatvfs.c new file mode 100644 index 00000000..83bd7486 --- /dev/null +++ b/src/stat/fstatvfs.c @@ -0,0 +1,13 @@ +#include <sys/statvfs.h> +#include "syscall.h" +#include "libc.h" + +int fstatvfs(int fd, struct statvfs *buf) +{ +	return syscall2(__NR_fstatfs64, fd, (long)buf); +} + +weak_alias(fstatvfs, fstatfs); + +LFS64(fstatvfs); +LFS64(fstatfs); diff --git a/src/stat/lstat.c b/src/stat/lstat.c new file mode 100644 index 00000000..afdb5538 --- /dev/null +++ b/src/stat/lstat.c @@ -0,0 +1,10 @@ +#include <sys/stat.h> +#include "syscall.h" +#include "libc.h" + +int lstat(const char *path, struct stat *buf) +{ +	return syscall2(__NR_lstat64, (long)path, (long)buf); +} + +LFS64(lstat); diff --git a/src/stat/mkdir.c b/src/stat/mkdir.c new file mode 100644 index 00000000..8295cad5 --- /dev/null +++ b/src/stat/mkdir.c @@ -0,0 +1,7 @@ +#include <sys/stat.h> +#include "syscall.h" + +int mkdir(const char *path, mode_t mode) +{ +	return syscall2(__NR_mkdir, (long)path, mode); +} diff --git a/src/stat/mkdirat.c b/src/stat/mkdirat.c new file mode 100644 index 00000000..1fb38250 --- /dev/null +++ b/src/stat/mkdirat.c @@ -0,0 +1,7 @@ +#include <sys/stat.h> +#include "syscall.h" + +int mkdirat(int fd, const char *path, mode_t mode) +{ +	return syscall3(__NR_mkdirat, fd, (long)path, mode); +} diff --git a/src/stat/mkfifo.c b/src/stat/mkfifo.c new file mode 100644 index 00000000..60efcf73 --- /dev/null +++ b/src/stat/mkfifo.c @@ -0,0 +1,6 @@ +#include <sys/stat.h> + +int mkfifo(const char *path, mode_t mode) +{ +	return mknod(path, mode | S_IFIFO, 0); +} diff --git a/src/stat/mkfifoat.c b/src/stat/mkfifoat.c new file mode 100644 index 00000000..d3a1f970 --- /dev/null +++ b/src/stat/mkfifoat.c @@ -0,0 +1,6 @@ +#include <sys/stat.h> + +int mkfifoat(int fd, const char *path, mode_t mode) +{ +	return mknodat(fd, path, mode | S_IFIFO, 0); +} diff --git a/src/stat/mknod.c b/src/stat/mknod.c new file mode 100644 index 00000000..0123eeef --- /dev/null +++ b/src/stat/mknod.c @@ -0,0 +1,10 @@ +#include <sys/stat.h> +#include "syscall.h" + +int mknod(const char *path, mode_t mode, dev_t dev) +{ +	/* since dev_t is system-specific anyway we defer to the idiotic +	 * legacy-compatible bitfield mapping of the type.. at least we've +	 * made it large enough to leave space for future expansion.. */ +	return syscall3(__NR_mknod, (long)path, mode, dev & 0xffff); +} diff --git a/src/stat/mknodat.c b/src/stat/mknodat.c new file mode 100644 index 00000000..b5687e47 --- /dev/null +++ b/src/stat/mknodat.c @@ -0,0 +1,7 @@ +#include <sys/stat.h> +#include "syscall.h" + +int mknodat(int fd, const char *path, mode_t mode, dev_t dev) +{ +	return syscall4(__NR_mknodat, fd, (long)path, mode, dev & 0xffff); +} diff --git a/src/stat/stat.c b/src/stat/stat.c new file mode 100644 index 00000000..67640cc1 --- /dev/null +++ b/src/stat/stat.c @@ -0,0 +1,10 @@ +#include <sys/stat.h> +#include "syscall.h" +#include "libc.h" + +int stat(const char *path, struct stat *buf) +{ +	return syscall2(__NR_stat64, (long)path, (long)buf); +} + +LFS64(stat); diff --git a/src/stat/statvfs.c b/src/stat/statvfs.c new file mode 100644 index 00000000..55a05d52 --- /dev/null +++ b/src/stat/statvfs.c @@ -0,0 +1,13 @@ +#include <sys/statvfs.h> +#include "syscall.h" +#include "libc.h" + +int statvfs(const char *path, struct statvfs *buf) +{ +	return syscall2(__NR_statfs64, (long)path, (long)buf); +} + +weak_alias(statvfs, statfs); + +LFS64(statvfs); +LFS64(statfs); diff --git a/src/stat/umask.c b/src/stat/umask.c new file mode 100644 index 00000000..49cb48a6 --- /dev/null +++ b/src/stat/umask.c @@ -0,0 +1,7 @@ +#include <sys/stat.h> +#include "syscall.h" + +mode_t umask(mode_t mode) +{ +	return syscall1(__NR_umask, mode); +} diff --git a/src/stdio/__fclose_ca.c b/src/stdio/__fclose_ca.c new file mode 100644 index 00000000..e0b12a15 --- /dev/null +++ b/src/stdio/__fclose_ca.c @@ -0,0 +1,6 @@ +#include "stdio_impl.h" + +int __fclose_ca(FILE *f) +{ +	return f->close(f); +} diff --git a/src/stdio/__fdopen.c b/src/stdio/__fdopen.c new file mode 100644 index 00000000..6ad7c57d --- /dev/null +++ b/src/stdio/__fdopen.c @@ -0,0 +1,52 @@ +#include "stdio_impl.h" + +FILE *__fdopen(int fd, const char *mode) +{ +	FILE *f; +	struct termios tio; +	int plus = !!strchr(mode, '+'); + +	/* Check for valid initial mode character */ +	if (!strchr("rwa", *mode)) return 0; + +	/* Allocate FILE+buffer or fail */ +	if (!(f=malloc(sizeof *f + UNGET + BUFSIZ))) return 0; + +	/* Zero-fill only the struct, not the buffer */ +	memset(f, 0, sizeof *f); + +	/* Impose mode restrictions */ +	if (!plus) f->flags = (*mode == 'r') ? F_NOWR : F_NORD; + +	/* Set append mode on fd if opened for append */ +	if (*mode == 'a') { +		int flags = __syscall_fcntl(fd, F_GETFL, 0); +		__syscall_fcntl(fd, F_SETFL, flags | O_APPEND); +	} + +	f->fd = fd; +	f->buf = (unsigned char *)f + sizeof *f + UNGET; +	f->buf_size = BUFSIZ; + +	/* Activate line buffered mode for terminals */ +	f->lbf = EOF; +	if (!(f->flags & F_NOWR) && !__syscall_ioctl(fd, TCGETS, &tio)) +		f->lbf = '\n'; + +	/* Initialize op ptrs. No problem if some are unneeded. */ +	f->read = __stdio_read; +	f->write = __stdio_write; +	f->seek = __stdio_seek; +	f->close = __stdio_close; + +	/* Add new FILE to open file list */ +	OFLLOCK(); +	f->next = ofl_head; +	if (ofl_head) ofl_head->prev = f; +	ofl_head = f; +	OFLUNLOCK(); + +	return f; +} + +weak_alias(__fdopen, fdopen); diff --git a/src/stdio/__fopen_rb_ca.c b/src/stdio/__fopen_rb_ca.c new file mode 100644 index 00000000..57d9b73c --- /dev/null +++ b/src/stdio/__fopen_rb_ca.c @@ -0,0 +1,18 @@ +#include "stdio_impl.h" + +FILE *__fopen_rb_ca(const char *filename, FILE *f, unsigned char *buf, size_t len) +{ +	memset(f, 0, sizeof *f); + +	f->fd = __syscall_open(filename, O_RDONLY, 0); +	if (f->fd < 0) return 0; + +	f->flags = F_NOWR | F_PERM; +	f->buf = buf + UNGET; +	f->buf_size = len - UNGET; +	f->read = __stdio_read; +	f->seek = __stdio_seek; +	f->close = __stdio_close; + +	return f; +} diff --git a/src/stdio/__fpending.c b/src/stdio/__fpending.c new file mode 100644 index 00000000..a4334e23 --- /dev/null +++ b/src/stdio/__fpending.c @@ -0,0 +1,6 @@ +#include "stdio_impl.h" + +size_t __fpending(FILE *f) +{ +	return f->wend ? f->wpos - f->wbase : 0; +} diff --git a/src/stdio/__ofl.c b/src/stdio/__ofl.c new file mode 100644 index 00000000..7d9652c8 --- /dev/null +++ b/src/stdio/__ofl.c @@ -0,0 +1,3 @@ +#include "stdio_impl.h" + +struct ofl __ofl; diff --git a/src/stdio/__overflow.c b/src/stdio/__overflow.c new file mode 100644 index 00000000..e35104de --- /dev/null +++ b/src/stdio/__overflow.c @@ -0,0 +1,52 @@ +#include "stdio_impl.h" + +static int overflow(FILE *f, int c) +{ +	/* Initialize if we're not already writing */ +	if (!f->wend) { +		/* Fail if we're in error state or unwritable. */ +		if (f->flags & (F_ERR|F_NOWR)) return EOF; + +		/* Set byte orientation -1,0=>-1; 1=>1 */ +		f->mode |= f->mode-1; + +		/* Clear read buffer (easier than summoning nasal demons) */ +		f->rpos = f->rend = f->rstop = 0; + +		/* Activate write through the buffer */ +		f->wpos = f->wbase = f->buf; +		f->wend = f->buf + f->buf_size; +		f->wstop = (f->lbf < 0) ? f->wend - 1 : 0; +	} + +	/* Buffer can always hold at least 1 byte... */ +	if (c != EOF) { +		*f->wpos++ = c; +		if (f->wpos <= f->wstop && c != f->lbf) return c; +	} +	/* ...since if the next call fails, buffer is empty. */ +	if (f->write(f, f->wbase, f->wpos - f->wbase) < 0) { +		f->flags |= F_ERR; +		f->wpos = f->wbase = f->wend = f->wstop = 0; +		return EOF; +	} + +	/* Buffer is empty so reset position to beginning */ +	f->wpos = f->wbase; + +	return c; +} + +int __overflow(FILE *f, int c) +{ +	return overflow(f, c & 0xff); +} + +int __oflow(FILE *f) +{ +	overflow(f, EOF); +	return (f->flags & F_ERR) ? EOF : 0; +} + +/* Link flush-on-exit code iff any stdio write functions are linked. */ +int (*const __fflush_on_exit)(FILE *) = fflush; diff --git a/src/stdio/__scanf.c b/src/stdio/__scanf.c new file mode 100644 index 00000000..185615d3 --- /dev/null +++ b/src/stdio/__scanf.c @@ -0,0 +1,487 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <ctype.h> +#include <wchar.h> +#include <wctype.h> +#include <limits.h> +#include <string.h> +#include <errno.h> +#include <math.h> +#include <float.h> + +#include "__scanf.h" + +static int read(rctx_t *r) +{ +	if (--r->w < 0) return r->w = -1; +	if (r->u) r->u = 0; +	else r->read(r); +	return r->c; +} + +static void unread(rctx_t *r) +{ +	//if (r->u || r->w < 0) return; +	if (r->w < 0) return; +	r->w++; +	r->u = 1; +} + +#define SIZE_hh -2 +#define SIZE_h  -1 +#define SIZE_def 0 +#define SIZE_l   1 +#define SIZE_ll  2 +#define SIZE_L   3 + +static void store_int(void *dest, int size, int neg, unsigned long long i) +{ +	if (!dest) return; +	if (neg) i = -i; +	switch (size) { +	case SIZE_hh: +		*(char *)dest = i; +		break; +	case SIZE_h: +		*(short *)dest = i; +		break; +	case SIZE_def: +		*(int *)dest = i; +		break; +	case SIZE_l: +		*(long *)dest = i; +		break; +	case SIZE_ll: +		*(long long *)dest = i; +		break; +	} +} + +static void *arg_n(va_list ap, unsigned int n) +{ +	void *p; +	unsigned int i; +	va_list ap2; +	va_copy(ap2, ap); +	for (i=n; i>1; i--) va_arg(ap2, void *); +	p = va_arg(ap2, void *); +	va_end(ap2); +	return p; +} + +int __scanf(rctx_t *r, const wchar_t *fmt, va_list ap) +{ +	int mode=0; +	int width; +	int size; +	const wchar_t *p, *z; +	int c, l, t, m; +	long long dummy; +	char *s; +	wchar_t *wcs; +	mbstate_t st; +	int wide = r->wide; +	void *dest=NULL; +	int invert; +	unsigned long long i=0; +	int neg=0; +	int matches=0; +	long double f; +	int (*is_space)(int) = r->is_space; + +	for (p=fmt; *p; ) { +		if (is_space(*p)) { +			do p++; while (is_space(*p)); +			do r->w=1; while (is_space(read(r))); +			unread(r); +			continue; +		} else if (*p != '%' || p[1] == '%') { +			if (*p == '%') p++; +			r->w = 1; +			if (*p++ != read(r)) +				goto match_fail; +			continue; +		} +		p++; +		if (mode != 1) { +			for (z=p; isdigit(*z); z++); +			if (*z != '$' && *z != '*') { +				if (mode == 0) mode = 1; +				else goto fmt_fail; +			} else if (*z != '*') { +				int pos = 0; +				mode = 2; +				for (; p<z; p++) { +					pos = 10*pos + *p - '0'; +				} +				p++; +				if (!pos) goto fmt_fail; +				dest = arg_n(ap, pos); +			} +		} +		if (*p == '*') { +			dest = NULL; +			p++; +		} else if (mode == 1) { +			dest = va_arg(ap, void *); +		} +		 +		if (!*p) goto fmt_fail; + +		width = 0; +		for (; isdigit(*p); p++) { +			width = 10*width + *p - '0'; +		} + +		size = 0; +		switch (*p++) { +		case 0: +			goto fmt_fail; +		case 'h': +			if (*p == 'h') p++, size = SIZE_hh; +			else size = SIZE_h; +			break; +		case 'l': +			if (*p == 'l') p++, size = SIZE_ll; +			else size = SIZE_l; +			break; +		case 'j': +			size = SIZE_ll; +			break; +		case 'z': +		case 't': +			size = SIZE_l; +			break; +		case 'L': +			size = SIZE_L; +			break; +		case 'd': case 'i': case 'o': case 'u': case 'x': +		case 'a': case 'e': case 'f': case 'g': +		case 'A': case 'E': case 'F': case 'G': case 'X': +		case 's': case 'c': case '[': +		case 'S': case 'C': +		case 'p': case 'n': +			p--; +			break; +		default: +			goto fmt_fail; +		} + +		t = *p++; + +		switch (t) { +		case 'C': +		case 'c': +			if (width < 1) width = 1; +		case 's': +			if (size == SIZE_l) t &= ~0x20; +		case 'd': case 'i': case 'o': case 'u': case 'x': +		case 'a': case 'e': case 'f': case 'g': +		case 'A': case 'E': case 'F': case 'G': case 'X': +		case '[': case 'S': +		case 'p': case 'n': +			if (width < 1) width = INT_MAX; +			break; +		default: +			goto fmt_fail; +		} + +		r->w = width; + +		if (t != 'n') { +			if (read(r) < 0) goto input_fail; +			unread(r); +		} + +		switch (t) { +		case 'n': +			store_int(dest, size, 0, r->l - r->u); +			/* do not increment match count, etc! */ +			continue; +		case 'C': +			wcs = dest ? dest : (void *)&dummy; +			st = (mbstate_t){ 0 }; +			while ((c=read(r)) >= 0) { +				if (wide) { +					if (dest) *wcs++ = c; +				} else { +					char ch = c; +					switch (mbrtowc(wcs, &ch, 1, &st)) { +					case -1: +						goto enc_fail; +					case -2: +						break; +					default: +						if (dest) wcs++; +					} +				} +			} +			if (r->w > 0) goto match_fail; +			break; +		case 'c': +			s = dest ? dest : (void *)&dummy; +			while ((c=read(r)) >= 0) { +				if (wide) { +					if ((l=wctomb(s, c)) < 0) +						goto enc_fail; +					if (dest) s += l; +				} else { +					if (dest) *s++ = c; +				} +			} +			if (r->w > 0) goto match_fail; +			break; +		case '[': +			wcs = dest ? dest : (void *)&dummy; +			s = dest ? dest : (void *)&dummy; +			if (!wide && size == SIZE_l) st = (mbstate_t){ 0 }; + +			if (*p == '^') p++, invert = 1; +			else invert = 0; + +			if (wide) { +				for (m=0; (c=read(r)) >= 0; m=1) { +					for (z=p; *z && *z != c && (*z != ']' || z==p); z++); +					if (!*z) goto fmt_fail; +					if (*z == c && (*z != ']' || z==p)) { +						if (invert) break; +					} else { +						if (!invert) break; +					} +					if (size == SIZE_l) { +						if (dest) *wcs++ = c; +					} else { +						if ((l=wctomb(s, c)) < 0) +							goto enc_fail; +						if (dest) s += l; +					} +				} +				for (p++; *p && *p != ']'; p++); +				p++; +			} else { +				unsigned char scanset[257]; +				memset(scanset, invert, sizeof scanset); +				scanset[0] = 0; +				for (z=p; *z && (*z != ']' || z==p); z++) +					scanset[1+*z] = 1-invert; +				if (!*z) goto fmt_fail; +				p=z+1; +				c=0; +				for (m=0; scanset[(c=read(r))+1]; m=1) { +					if (size == SIZE_l) { +						char ch = c; +						switch (mbrtowc(wcs, &ch, 1, &st)) { +						case -1: +							goto enc_fail; +						case -2: +							break; +						default: +							if (dest) wcs++; +						} +					} else { +						if (dest) *s++ = c; +					} +				} +			} +			if (!m) goto match_fail; +			if (dest) { +				if (size == SIZE_l) *wcs++ = 0; +				else *s++ = 0; +			} +			break; +		default: +			/* read unlimited number of spaces, then reset width */ +			do r->w = 1; while (is_space(c = read(r))); +			if (c < 0) goto input_fail; +			unread(r); +			r->w = width; +		} + +		switch (t) { +		case 'p': +		case 'X': +			t = 'x'; +		case 'd': +		case 'i': +		case 'o': +		case 'u': +		case 'x': +			i = m = neg = 0; +			if ((c=read(r)) == '-') neg=1; +			else if (c != '+') unread(r); +			switch (t) { +			case 'i': +			case 'x': +				if ((c=read(r)) != '0') { +					if (t == 'i') t = 'd'; +					unread(r); +					break; +				} +				if (((c=read(r))|0x20) != 'x') { +					if (t == 'i') { +						t = 'o'; +						/* lone 0 is valid octal */ +						if ((unsigned)(c-'0') >= 8) { +							m = 1; +							goto int_finish; +						} +					} +					unread(r); +					break; +				} +				t = 'x'; +			} +		} +		 +		switch (t) { +		case 'd': +		case 'u': +			for (m=0; isdigit(c=read(r)); m=1) +				i = 10*i + c-'0'; +			goto int_finish; +		case 'o': +			for (m=0; (unsigned)(c=read(r))-'0' < 8; m=1) +				i = (i<<3) + c-'0'; +			goto int_finish; +		case 'x': +			for (m=0; ; m=1) { +				if (isdigit(c=read(r))) { +					i = (i<<4) + c-'0'; +				} else if ((unsigned)(c|0x20)-'a' < 6) { +					i = (i<<4) + (c|0x20)-'a'+10; +				} else break; +			} +		int_finish: +			if (!m) goto match_fail; +			store_int(dest, size, neg, i); +			break; +		case 'a': +		case 'e': +		case 'f': +		case 'g': +			f = 0.0; +			neg = m = 0; +			if ((c=read(r)) == '-') neg=1; +			else if (c != '+') unread(r); +			/* FIXME: check for INF/NAN strings here */ +			if (read(r)=='0' && (m=1, (read(r)|0x20) == 'x')) +				goto hexfloat; +			else unread(r); +			for (; isdigit(c=read(r)); m=1) +				f = 10.0 * f + (c-'0'); +			if (c=='.') { +				double mag = 10.0; +				for (; isdigit(c=read(r)); mag*=10.0) +					f += (c-'0')/mag; +			} +			if ((c|0x20)=='e') { +				int ex=0, en=0; +				m = 0; +				if ((c=read(r))=='-') en=1; +				else if (c!='+') unread(r); +				for (; isdigit(c=read(r)); m=1) +					if (ex < LDBL_MAX_10_EXP) +						ex = 10 * ex + (c-'0'); +				if (ex > LDBL_MAX_10_EXP) +					f = en ? 0 : INFINITY; +				else { +					if (en) while (ex--) f/=10.0; +					else while (ex--) f*=10.0; +				} +			} +			goto writefloat; +hexfloat: +			m = 0; +			for (; isxdigit(c=read(r)); m=1) +				if (isdigit(c)) f = 16.0*f + (c-'0'); +				else f = 16.0*f + ((c|32)-'a'+10); +			if (c=='.') { +				double mag = 1/16.0; +				for (; isxdigit(c=read(r)); mag*=1/16.0) +					if (isdigit(c)) f += (c-'0')*mag; +					else f += ((c|32)-'a'+10)*mag; +			} +			if ((c|0x20)=='p') { +				int ex=0, en=0; +				m = 0; +				if ((c=read(r))=='-') en=1; +				else if (c!='+') unread(r); +				for (; isdigit(c=read(r)); m=1) +					if (ex < LDBL_MAX_EXP) +						ex = 10 * ex + (c-'0'); +				if (ex > LDBL_MAX_EXP) +					f = en ? 0 : INFINITY; +				else { +					if (en) while (ex--) f*=0.5; +					else while (ex--) f*=2.0; +				} +			} +writefloat: +			if (!m) goto match_fail; +			if (neg) f *= -1.0; +			if (dest) switch (size) { +			case SIZE_def: +				*(float *)dest = f; +				break; +			case SIZE_l: +				*(double *)dest = f; +				break; +			case SIZE_L: +				*(long double *)dest = f; +				break; +			} +			break; +		case 'S': +			wcs = dest ? dest : (void *)&dummy; +			st = (mbstate_t){ 0 }; +			while((c=read(r)) >= 0) { +				if (wide) { +					if (is_space(c)) break; +					if (dest) *wcs++ = c; +				} else { +					char ch = c; +					if (is_space(c)) break; +					switch (mbrtowc(wcs, &ch, 1, &st)) { +					case -1: +						goto enc_fail; +					case -2: +						break; +					default: +						if (dest) wcs++; +					} +				} +			} +			if (dest) *wcs++ = 0; +			break; +		case 's': +			s = dest ? dest : (void *)&dummy; +			while((c=read(r)) >= 0) { +				if (wide) { +					if (is_space(c)) break; +					if ((l=wctomb(s, c)) < 0) +						goto enc_fail; +					if (dest) s += l; +				} else { +					if (is_space(c)) break; +					if (dest) *s++ = c; +				} +			} +			if (dest) *s++ = 0; +			break; +		} + +		/* unread will do nothing if field width was exhausted */ +		unread(r); +		if (dest) matches++; +	} +	return matches; +enc_fail: +	errno = EILSEQ; +fmt_fail: +input_fail: +	if (!matches) matches--; +match_fail: +	unread(r); +	return matches; +} diff --git a/src/stdio/__scanf.h b/src/stdio/__scanf.h new file mode 100644 index 00000000..e549b979 --- /dev/null +++ b/src/stdio/__scanf.h @@ -0,0 +1,16 @@ +#include <wchar.h> + +typedef struct rctx +{ +	void (*read)(struct rctx *); +	void *opaque; +	int wide; +	int (*is_space)(); +	int l; +	int e; +	int c; +	int u; +	int w; +} rctx_t; + +int __scanf(rctx_t *, const wchar_t *, va_list); diff --git a/src/stdio/__stdio_close.c b/src/stdio/__stdio_close.c new file mode 100644 index 00000000..24fef33f --- /dev/null +++ b/src/stdio/__stdio_close.c @@ -0,0 +1,6 @@ +#include "stdio_impl.h" + +int __stdio_close(FILE *f) +{ +	return __syscall_close(f->fd); +} diff --git a/src/stdio/__stdio_read.c b/src/stdio/__stdio_read.c new file mode 100644 index 00000000..ee7e1258 --- /dev/null +++ b/src/stdio/__stdio_read.c @@ -0,0 +1,6 @@ +#include "stdio_impl.h" + +size_t __stdio_read(FILE *f, unsigned char *buf, size_t len) +{ +	return __syscall_read(f->fd, buf, len); +} diff --git a/src/stdio/__stdio_seek.c b/src/stdio/__stdio_seek.c new file mode 100644 index 00000000..fdb9fe7f --- /dev/null +++ b/src/stdio/__stdio_seek.c @@ -0,0 +1,15 @@ +#include "stdio_impl.h" + +static off_t retneg1(FILE *f, off_t off, int whence) +{ +	return -1; +} + +off_t __stdio_seek(FILE *f, off_t off, int whence) +{ +	off_t ret = __syscall_lseek(f->fd, off, whence); +	/* Detect unseekable files and optimize future failures out */ +	if (ret < 0 && off == 0 && whence == SEEK_CUR) +		f->seek = retneg1; +	return ret; +} diff --git a/src/stdio/__stdio_write.c b/src/stdio/__stdio_write.c new file mode 100644 index 00000000..78545626 --- /dev/null +++ b/src/stdio/__stdio_write.c @@ -0,0 +1,9 @@ +#include "stdio_impl.h" + +size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len) +{ +	const unsigned char *stop = buf+len; +	ssize_t cnt = 1; +	for (; buf<stop && (cnt=__syscall_write(f->fd, buf, len))>0; buf+=cnt); +	return len-(stop-buf); +} diff --git a/src/stdio/__uflow.c b/src/stdio/__uflow.c new file mode 100644 index 00000000..5a51d610 --- /dev/null +++ b/src/stdio/__uflow.c @@ -0,0 +1,7 @@ +#include "stdio_impl.h" + +int __uflow(FILE *f) +{ +	if (__underflow(f) < 0) return EOF; +	else return *f->rpos++; +} diff --git a/src/stdio/__underflow.c b/src/stdio/__underflow.c new file mode 100644 index 00000000..b769f4e4 --- /dev/null +++ b/src/stdio/__underflow.c @@ -0,0 +1,38 @@ +#include "stdio_impl.h" + +int __underflow(FILE *f) +{ +	ssize_t cnt; + +	/* Read from buffer (Do we ever get called when this is true??) */ +	if (f->rpos < f->rstop) return *f->rpos; + +	/* Initialize if we're not already reading */ +	if (!f->rstop) { +		/* Fail immediately if unreadable, eof, or error state. */ +		if (f->flags & (F_EOF|F_ERR|F_NORD)) return EOF; + +		/* Set byte orientation -1,0=>-1; 1=>1 */ +		f->mode |= f->mode-1; + +		/* Flush any unwritten output; fail on error. */ +		if (f->wpos > f->buf && __oflow(f)) return EOF; + +		/* Disallow writes to buffer. */ +		f->wstop = 0; +	} + +	/* Perform the underlying read operation */ +	if ((cnt=f->read(f, f->buf, f->buf_size)) + 1 <= 1) { +		/* Set flags and leave read mode */ +		f->flags |= F_EOF | (cnt & F_ERR); +		f->rpos = f->rend = f->rstop = 0; +		return EOF; +	} + +	/* Setup buffer pointers for reading from buffer */ +	f->rpos = f->buf; +	f->rend = f->rstop = f->buf + cnt; + +	return *f->rpos; +} diff --git a/src/stdio/asprintf.c b/src/stdio/asprintf.c new file mode 100644 index 00000000..79e59c2d --- /dev/null +++ b/src/stdio/asprintf.c @@ -0,0 +1,14 @@ +#include <stdio.h> +#include <stdarg.h> + +int vasprintf(char **, const char *, va_list); + +int asprintf(char **s, const char *fmt, ...) +{ +	int ret; +	va_list ap; +	va_start(ap, fmt); +	ret = vasprintf(s, fmt, ap); +	va_end(ap); +	return ret; +} diff --git a/src/stdio/clearerr.c b/src/stdio/clearerr.c new file mode 100644 index 00000000..3bf94d30 --- /dev/null +++ b/src/stdio/clearerr.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +void clearerr(FILE *f) +{ +	FLOCK(f); +	f->flags &= ~(F_EOF|F_ERR); +	FUNLOCK(f); +} + +weak_alias(clearerr, clearerr_unlocked); diff --git a/src/stdio/dprintf.c b/src/stdio/dprintf.c new file mode 100644 index 00000000..fa28322f --- /dev/null +++ b/src/stdio/dprintf.c @@ -0,0 +1,12 @@ +#include <stdio.h> +#include <stdarg.h> + +int dprintf(int fd, const char *fmt, ...) +{ +	int ret; +	va_list ap; +	va_start(ap, fmt); +	ret = vdprintf(fd, fmt, ap); +	va_end(ap); +	return ret; +} diff --git a/src/stdio/fclose.c b/src/stdio/fclose.c new file mode 100644 index 00000000..26bc37e8 --- /dev/null +++ b/src/stdio/fclose.c @@ -0,0 +1,21 @@ +#include "stdio_impl.h" + +int fclose(FILE *f) +{ +	int r; +	int perm = f->flags & F_PERM; + +	if (!perm) { +		OFLLOCK(); +		if (f->prev) f->prev->next = f->next; +		if (f->next) f->next->prev = f->prev; +		if (ofl_head == f) ofl_head = f->next; +		OFLUNLOCK(); +	} + +	r = fflush(f) | f->close(f); + +	if (!perm) free(f); +	 +	return r; +} diff --git a/src/stdio/feof.c b/src/stdio/feof.c new file mode 100644 index 00000000..f2b739b5 --- /dev/null +++ b/src/stdio/feof.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +#undef feof + +int feof(FILE *f) +{ +	return !!(f->flags & F_EOF); +} + +weak_alias(feof, feof_unlocked); diff --git a/src/stdio/ferror.c b/src/stdio/ferror.c new file mode 100644 index 00000000..f535fbed --- /dev/null +++ b/src/stdio/ferror.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +#undef ferror + +int ferror(FILE *f) +{ +	return !!(f->flags & F_ERR); +} + +weak_alias(ferror, ferror_unlocked); diff --git a/src/stdio/fflush.c b/src/stdio/fflush.c new file mode 100644 index 00000000..cf3f5b0e --- /dev/null +++ b/src/stdio/fflush.c @@ -0,0 +1,50 @@ +#include "stdio_impl.h" + +static int __fflush_unlocked(FILE *f) +{ +	/* If writing, flush output. */ +	if (f->wpos > f->buf && __oflow(f)) return -1; + +	/* If reading, sync position, per POSIX */ +	if (f->rpos < f->rend) f->seek(f, f->rpos-f->rend, SEEK_CUR); +	f->rpos = f->rend; + +	/* Hook for special behavior on flush */ +	if (f->flush) f->flush(f); + +	return (f->flags & F_ERR) ? EOF : 0; +} + +/* stdout.c will override this if linked */ +static FILE *const __dummy = 0; +weak_alias(__dummy, __stdout_to_flush); + +int fflush(FILE *f) +{ +	int r; +	FILE *next; + +	if (f) { +		FLOCK(f); +		r = __fflush_unlocked(f); +		FUNLOCK(f); +		return r; +	} + +	r = __stdout_to_flush ? fflush(__stdout_to_flush) : 0; + +	OFLLOCK(); +	for (f=ofl_head; f; f=next) { +		FLOCK(f); +		OFLUNLOCK(); +		r |= __fflush_unlocked(f); +		OFLLOCK(); +		next = f->next; +		FUNLOCK(f); +	} +	OFLUNLOCK(); +	 +	return r; +} + +weak_alias(__fflush_unlocked, fflush_unlocked); diff --git a/src/stdio/fgetc.c b/src/stdio/fgetc.c new file mode 100644 index 00000000..3a7f1e30 --- /dev/null +++ b/src/stdio/fgetc.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +int fgetc(FILE *f) +{ +	int c; +	FLOCK(f); +	c = f->rpos < f->rstop ? *f->rpos++ : __uflow(f); +	FUNLOCK(f); +	return c; +} diff --git a/src/stdio/fgetpos.c b/src/stdio/fgetpos.c new file mode 100644 index 00000000..5b663d1e --- /dev/null +++ b/src/stdio/fgetpos.c @@ -0,0 +1,11 @@ +#include "stdio_impl.h" + +int fgetpos(FILE *f, fpos_t *pos) +{ +	off_t off = __ftello(f); +	if (off < 0) return -1; +	*(off_t *)pos = off; +	return 0; +} + +LFS64(fgetpos); diff --git a/src/stdio/fgets.c b/src/stdio/fgets.c new file mode 100644 index 00000000..7939303e --- /dev/null +++ b/src/stdio/fgets.c @@ -0,0 +1,34 @@ +#include "stdio_impl.h" + +#define MIN(a,b) ((a)<(b) ? (a) : (b)) + +char *fgets(char *s, int n, FILE *f) +{ +	char *p = s; +	unsigned char *z; +	size_t k; + +	if (!n--) return 0; + +	FLOCK(f); + +	while (n && !feof(f)) { +		z = memchr(f->rpos, '\n', f->rend - f->rpos); +		k = z ? z - f->rpos + 1 : f->rend - f->rpos; +		k = MIN(k, n); +		memcpy(p, f->rpos, k); +		f->rpos += k; +		p += k; +		n -= k; +		if (z) break; +		__underflow(f); +	} +	*p = 0; +	if (ferror(f)) p = s; + +	FUNLOCK(f); + +	return (p == s) ? 0 : s; +} + +weak_alias(fgets, fgets_unlocked); diff --git a/src/stdio/fgetwc.c b/src/stdio/fgetwc.c new file mode 100644 index 00000000..c990545f --- /dev/null +++ b/src/stdio/fgetwc.c @@ -0,0 +1,51 @@ +#include "stdio_impl.h" + +wint_t __fgetwc_unlocked(FILE *f) +{ +	mbstate_t st = { 0 }; +	wchar_t wc; +	int c; +	unsigned char b; +	size_t l; + +	f->mode |= f->mode+1; + +	/* Convert character from buffer if possible */ +	if (f->rpos < f->rend) { +		l = mbrtowc(&wc, f->rpos, f->rend - f->rpos, &st); +		if (l+2 >= 2) { +			f->rpos += l + !l; /* l==0 means 1 byte, null */ +			return wc; +		} +		if (l == -1) { +			f->rpos++; +			return WEOF; +		} +	} else l = -2; + +	/* Convert character byte-by-byte from __uflow */ +	while (l == -2) { +		b = c = __uflow(f); +		if (c < 0) { +			if (!mbsinit(&st)) errno = EILSEQ; +			return WEOF; +		} +		l = mbrtowc(&wc, &b, 1, &st); +		if (l == -1) return WEOF; +	} + +	FUNLOCK(f); +	return wc; +} + +wint_t fgetwc(FILE *f) +{ +	wint_t c; +	FLOCK(f); +	c = __fgetwc_unlocked(f); +	FUNLOCK(f); +	return c; +} + +weak_alias(__fgetwc_unlocked, fgetwc_unlocked); +weak_alias(__fgetwc_unlocked, getwc_unlocked); diff --git a/src/stdio/fgetws.c b/src/stdio/fgetws.c new file mode 100644 index 00000000..2e76b565 --- /dev/null +++ b/src/stdio/fgetws.c @@ -0,0 +1,27 @@ +#include "stdio_impl.h" + +wint_t __fgetwc_unlocked(FILE *); + +wchar_t *fgetws(wchar_t *s, int n, FILE *f) +{ +	wchar_t *p = s; + +	if (!n--) return s; + +	FLOCK(f); + +	for (; n; n--) { +		wint_t c = __fgetwc_unlocked(f); +		if (c == WEOF) break; +		*p++ = c; +		if (c == '\n') break; +	} +	*p = 0; +	if (ferror(f)) p = s; + +	FUNLOCK(f); + +	return (p == s) ? NULL : s; +} + +weak_alias(fgetws, fgetws_unlocked); diff --git a/src/stdio/fileno.c b/src/stdio/fileno.c new file mode 100644 index 00000000..9ffb26d5 --- /dev/null +++ b/src/stdio/fileno.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" + +int fileno(FILE *f) +{ +	return f->fd; +} + +weak_alias(fileno, fileno_unlocked); diff --git a/src/stdio/fmemopen.c b/src/stdio/fmemopen.c new file mode 100644 index 00000000..77a60746 --- /dev/null +++ b/src/stdio/fmemopen.c @@ -0,0 +1,16 @@ +#if 0 +#include "stdio_impl.h" + +static ssize_t mread(FILE *f, unsigned char *buf, size_t len) +{ +	memcpy(buf,  +} + +FILE *fmemopen(void *buf, size_t size, const char *mode) +{ +	FILE *f = calloc(sizeof(FILE), 1); +	if (!f) return 0; +	 +	// +} +#endif diff --git a/src/stdio/fopen.c b/src/stdio/fopen.c new file mode 100644 index 00000000..670cf5f3 --- /dev/null +++ b/src/stdio/fopen.c @@ -0,0 +1,34 @@ +#include "stdio_impl.h" + +FILE *fopen(const char *filename, const char *mode) +{ +	FILE *f; +	int fd; +	int flags; +	int plus = !!strchr(mode, '+'); + +	/* Check for valid initial mode character */ +	if (!strchr("rwa", *mode)) { +		errno = EINVAL; +		return 0; +	} + +	/* Compute the flags to pass to open() */ +	if (plus) flags = O_RDWR; +	else if (*mode == 'r') flags = O_RDONLY; +	else flags = O_WRONLY; +	if (*mode != 'r') flags |= O_CREAT; +	if (*mode == 'w') flags |= O_TRUNC; +	if (*mode == 'a') flags |= O_APPEND; + +	fd = __syscall_open(filename, flags, 0666); +	if (fd < 0) return 0; + +	f = __fdopen(fd, mode); +	if (f) return f; + +	__syscall_close(fd); +	return 0; +} + +LFS64(fopen); diff --git a/src/stdio/fprintf.c b/src/stdio/fprintf.c new file mode 100644 index 00000000..a220cc10 --- /dev/null +++ b/src/stdio/fprintf.c @@ -0,0 +1,12 @@ +#include <stdio.h> +#include <stdarg.h> + +int fprintf(FILE *f, const char *fmt, ...) +{ +	int ret; +	va_list ap; +	va_start(ap, fmt); +	ret = vfprintf(f, fmt, ap); +	va_end(ap); +	return ret; +} diff --git a/src/stdio/fputc.c b/src/stdio/fputc.c new file mode 100644 index 00000000..ec859385 --- /dev/null +++ b/src/stdio/fputc.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +int fputc(int c, FILE *f) +{ +	FLOCK(f); +	if (c != f->lbf && f->wpos + 1 < f->wend) *f->wpos++ = c; +	else c = __overflow(f, c); +	FUNLOCK(f); +	return c; +} diff --git a/src/stdio/fputs.c b/src/stdio/fputs.c new file mode 100644 index 00000000..e6bdb204 --- /dev/null +++ b/src/stdio/fputs.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +int fputs(const char *s, FILE *f) +{ +	size_t l = strlen(s); +	if (!l) return 0; +	return (int)fwrite(s, l, 1, f) - 1; +} + +weak_alias(fputs, fputs_unlocked); diff --git a/src/stdio/fputwc.c b/src/stdio/fputwc.c new file mode 100644 index 00000000..b48bb74d --- /dev/null +++ b/src/stdio/fputwc.c @@ -0,0 +1,33 @@ +#include "stdio_impl.h" + +wint_t __fputwc_unlocked(wchar_t c, FILE *f) +{ +	char mbc[MB_LEN_MAX]; +	int l; + +	f->mode |= f->mode+1; + +	if (isascii(c)) { +		if (c != f->lbf && f->wpos + 1 < f->wend) *f->wpos++ = c; +		else c = __overflow(f, c); +	} else if (f->wpos + MB_LEN_MAX < f->wend) { +		l = wctomb(f->wpos, c); +		if (l < 0) c = WEOF; +		else f->wpos += l; +	} else { +		l = wctomb(mbc, c); +		if (l < 0 || __fwritex(mbc, l, f) < l) c = WEOF; +	} +	return c; +} + +wint_t fputwc(wchar_t c, FILE *f) +{ +	FLOCK(f); +	c = __fputwc_unlocked(c, f); +	FUNLOCK(f); +	return 0; +} + +weak_alias(__fputwc_unlocked, fputwc_unlocked); +weak_alias(__fputwc_unlocked, putwc_unlocked); diff --git a/src/stdio/fputws.c b/src/stdio/fputws.c new file mode 100644 index 00000000..9057853b --- /dev/null +++ b/src/stdio/fputws.c @@ -0,0 +1,23 @@ +#include "stdio_impl.h" + +int fputws(const wchar_t *ws, FILE *f) +{ +	unsigned char buf[BUFSIZ]; +	size_t l=0; + +	FLOCK(f); + +	f->mode |= f->mode+1; + +	while (ws && (l = wcsrtombs(buf, (void*)&ws, sizeof buf, 0))+1 > 1) +		if (__fwritex(buf, l, f) < l) { +			FUNLOCK(f); +			return -1; +		} + +	FUNLOCK(f); + +	return l; /* 0 or -1 */ +} + +weak_alias(fputws, fputws_unlocked); diff --git a/src/stdio/fread.c b/src/stdio/fread.c new file mode 100644 index 00000000..0fa0b2aa --- /dev/null +++ b/src/stdio/fread.c @@ -0,0 +1,49 @@ +#include "stdio_impl.h" + +#define MIN(a,b) ((a)<(b) ? (a) : (b)) + +size_t fread(void *destv, size_t size, size_t nmemb, FILE *f) +{ +	unsigned char *dest = destv; +	size_t len = size*nmemb, l = len, k; + +	/* Never touch the file if length is zero.. */ +	if (!l) return 0; + +	FLOCK(f); + +	for (;;) { +		/* First exhaust the buffer. */ +		k = MIN(f->rend - f->rpos, l); +		memcpy(dest, f->rpos, k); +		f->rpos += k; +		dest += k; +		l -= k; + +		/* Stop on EOF or errors */ +		if (f->flags & (F_EOF|F_ERR|F_NORD)) goto eof; + +		/* Done? Or going unbuffered? */ +		if (!l || l > f->buf_size/2) break; + +		/* Otherwise, refill & read thru buffer. */ +		__underflow(f); +	} + +	/* Read the remainder directly */ +	for (; l; l-=k, dest+=k) { +		k = f->read(f, dest, l); +		if (k+1<=1) { +			f->flags |= F_EOF | (F_ERR & k); +			goto eof; +		} +	} + +	FUNLOCK(f); +	return nmemb; +eof: +	FUNLOCK(f); +	return (len-l)/size; +} + +weak_alias(fread, fread_unlocked); diff --git a/src/stdio/freopen.c b/src/stdio/freopen.c new file mode 100644 index 00000000..8d3af9fc --- /dev/null +++ b/src/stdio/freopen.c @@ -0,0 +1,47 @@ +#include "stdio_impl.h" + +/* The basic idea of this implementation is to open a new FILE, + * hack the necessary parts of the new FILE into the old one, then + * close the new FILE. */ + +/* Locking is not necessary because, in the event of failure, the stream + * passed to freopen is invalid as soon as freopen is called. */ + +FILE *freopen(const char *filename, const char *mode, FILE *f) +{ +	int fl; +	FILE *f2; + +	fflush(f); + +	if (!filename) { +		f2 = fopen("/dev/null", mode); +		if (!f2) goto fail; +		fl = __syscall_fcntl(f2->fd, F_GETFL, 0); +		if (fl < 0 || __syscall_fcntl(f->fd, F_SETFL, fl) < 0) +			goto fail2; +	} else { +		f2 = fopen(filename, mode); +		if (!f2) goto fail; +		if (__syscall_dup2(f2->fd, f->fd) < 0) +			goto fail2; +	} + +	f->flags = (f->flags & F_PERM) | f2->flags; +	f->read = f2->read; +	f->write = f2->write; +	f->seek = f2->seek; +	f->close = f2->close; +	f->flush = f2->flush; + +	fclose(f2); +	return f; + +fail2: +	fclose(f2); +fail: +	fclose(f); +	return NULL; +} + +LFS64(freopen); diff --git a/src/stdio/fscanf.c b/src/stdio/fscanf.c new file mode 100644 index 00000000..51fc9b30 --- /dev/null +++ b/src/stdio/fscanf.c @@ -0,0 +1,12 @@ +#include <stdio.h> +#include <stdarg.h> + +int fscanf(FILE *f, const char *fmt, ...) +{ +	int ret; +	va_list ap; +	va_start(ap, fmt); +	ret = vfscanf(f, fmt, ap); +	va_end(ap); +	return ret; +} diff --git a/src/stdio/fseek.c b/src/stdio/fseek.c new file mode 100644 index 00000000..bfaad375 --- /dev/null +++ b/src/stdio/fseek.c @@ -0,0 +1,38 @@ +#include "stdio_impl.h" + +int __fseeko_unlocked(FILE *f, off_t off, int whence) +{ +	/* Adjust relative offset for unread data in buffer, if any. */ +	if (whence == SEEK_CUR) off -= f->rend - f->rpos; + +	/* If writing, flush output. */ +	if (f->wpos > f->buf && __oflow(f)) return -1; + +	/* Perform the underlying seek operation. */ +	if (f->seek(f, off, whence) < 0) return -1; + +	/* If seek succeeded, file is seekable and we discard read buffer. */ +	f->rpos = f->rend = f->rstop = 0; +	f->flags &= ~F_EOF; +	 +	FUNLOCK(f);	 +	return 0; +} + +int __fseeko(FILE *f, off_t off, int whence) +{ +	int result; +	FLOCK(f); +	result = __fseeko_unlocked(f, off, whence); +	FUNLOCK(f); +	return result; +} + +int fseek(FILE *f, long off, int whence) +{ +	return __fseeko(f, off, whence); +} + +weak_alias(__fseeko, fseeko); + +LFS64(fseeko); diff --git a/src/stdio/fsetpos.c b/src/stdio/fsetpos.c new file mode 100644 index 00000000..5d76c8cd --- /dev/null +++ b/src/stdio/fsetpos.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" + +int fsetpos(FILE *f, const fpos_t *pos) +{ +	return __fseeko(f, *(const off_t *)pos, SEEK_SET); +} + +LFS64(fsetpos); diff --git a/src/stdio/ftell.c b/src/stdio/ftell.c new file mode 100644 index 00000000..aa1f5381 --- /dev/null +++ b/src/stdio/ftell.c @@ -0,0 +1,35 @@ +#include "stdio_impl.h" + +off_t __ftello_unlocked(FILE *f) +{ +	off_t pos = f->seek(f, 0, SEEK_CUR); +	if (pos < 0) { +		FUNLOCK(f); +		return pos; +	} +	/* Adjust for data in buffer. */ +	return pos - (f->rend - f->rpos) + (f->wpos - f->wbase); +} + +off_t __ftello(FILE *f) +{ +	off_t pos; +	FLOCK(f); +	pos = __ftello_unlocked(f); +	FUNLOCK(f); +	return pos; +} + +long ftell(FILE *f) +{ +	off_t pos = __ftello(f); +	if (pos > LONG_MAX) { +		errno = EOVERFLOW; +		return -1; +	} +	return pos; +} + +weak_alias(__ftello, ftello); + +LFS64(ftello); diff --git a/src/stdio/fwide.c b/src/stdio/fwide.c new file mode 100644 index 00000000..f4da47f6 --- /dev/null +++ b/src/stdio/fwide.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +#define SH (8*sizeof(int)-1) +#define NORMALIZE(x) ((x)>>SH | -((-(x))>>SH)) + +int fwide(FILE *f, int mode) +{ +	if (!f->mode) f->mode = NORMALIZE(mode); +	return f->mode; +} diff --git a/src/stdio/fwrite.c b/src/stdio/fwrite.c new file mode 100644 index 00000000..23974fe1 --- /dev/null +++ b/src/stdio/fwrite.c @@ -0,0 +1,51 @@ +#include "stdio_impl.h" + +size_t __fwritex(const unsigned char *s, size_t l, FILE *f) +{ +	size_t i = 0; +	size_t k = f->wend - f->wpos; + +	/* Handle line-buffered mode by breaking into 2 parts */ +	if (f->lbf >= 0) { +		/* Match /^(.*\n|)/ */ +		for (i=l; i && s[i-1] != '\n'; i--); +		if (i) { +			f->lbf = EOF; +			__fwritex(s, i, f); +			f->lbf = '\n'; +			__oflow(f); +			return ferror(f) ? 0 : i + __fwritex(s+i, l-i, f); +		} +	} + +	/* Buffer initial segment */ +	if (k > l) k = l; +	memcpy(f->wpos, s, k); +	f->wpos += k; +	if (f->wpos < f->wend) return l; + +	/* If there's work left to do, flush buffer */ +	__oflow(f); +	if (ferror(f)) return 0; + +	/* If the remainder will not fit in buffer, write it directly */ +	if (l - k >= f->wend - f->wpos) +		return k + f->write(f, s+k, l-k); + +	/* Otherwise, buffer the remainder */ +	memcpy(f->wpos, s+k, l-k); +	f->wpos += l-k; +	return l; +} + +size_t fwrite(const void *src, size_t size, size_t nmemb, FILE *f) +{ +	size_t l = size*nmemb; +	if (!l) return l; +	FLOCK(f); +	l = __fwritex(src, l, f); +	FUNLOCK(f); +	return l/size; +} + +weak_alias(fwrite, fwrite_unlocked); diff --git a/src/stdio/fwscanf.c b/src/stdio/fwscanf.c new file mode 100644 index 00000000..a6892cf6 --- /dev/null +++ b/src/stdio/fwscanf.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <stdarg.h> +#include <wchar.h> + +int fwscanf(FILE *f, const wchar_t *fmt, ...) +{ +	int ret; +	va_list ap; +	va_start(ap, fmt); +	ret = vfwscanf(f, fmt, ap); +	va_end(ap); +	return ret; +} diff --git a/src/stdio/getc.c b/src/stdio/getc.c new file mode 100644 index 00000000..b739b0a5 --- /dev/null +++ b/src/stdio/getc.c @@ -0,0 +1,6 @@ +#include "stdio_impl.h" + +int getc(FILE *f) +{ +	return fgetc(f); +} diff --git a/src/stdio/getc_unlocked.c b/src/stdio/getc_unlocked.c new file mode 100644 index 00000000..629223ea --- /dev/null +++ b/src/stdio/getc_unlocked.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" + +int getc_unlocked(FILE *f) +{ +	return f->rpos < f->rstop ? *f->rpos++ : __uflow(f); +} + +weak_alias (getc_unlocked, fgetc_unlocked); diff --git a/src/stdio/getchar.c b/src/stdio/getchar.c new file mode 100644 index 00000000..c1012658 --- /dev/null +++ b/src/stdio/getchar.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int getchar(void) +{ +	return fgetc(stdin); +} diff --git a/src/stdio/getchar_unlocked.c b/src/stdio/getchar_unlocked.c new file mode 100644 index 00000000..299cb958 --- /dev/null +++ b/src/stdio/getchar_unlocked.c @@ -0,0 +1,6 @@ +#include "stdio_impl.h" + +int getchar_unlocked(void) +{ +	return stdin->rpos < stdin->rstop ? *stdin->rpos++ : __uflow(stdin); +} diff --git a/src/stdio/getdelim.c b/src/stdio/getdelim.c new file mode 100644 index 00000000..f770d20b --- /dev/null +++ b/src/stdio/getdelim.c @@ -0,0 +1,59 @@ +#include "stdio_impl.h" + +#define MIN(a,b) ((a)<(b) ? (a) : (b)) + +ssize_t getdelim(char **s, size_t *n, int delim, FILE *f) +{ +	char *tmp; +	unsigned char *z; +	size_t k; +	size_t i=0; + +	if (!n || !s) { +		errno = EINVAL; +		return -1; +	} + +	if (!*s) *n=0; + +	FLOCK(f); + +	while (!feof(f)) { +		z = memchr(f->rpos, delim, f->rend - f->rpos); +		k = z ? z - f->rpos + 1 : f->rend - f->rpos; +		if (i+k >= *n) { +			if (k >= SIZE_MAX-i) goto oom; +			*n = i+k+1; +			if (*n < SIZE_MAX/2) *n *= 2; +			tmp = realloc(*s, *n); +			if (!tmp) { +				*n = i+k+1; +				tmp = realloc(*s, *n); +				if (!tmp) goto oom; +			} +			*s = tmp; +		} +		memcpy(*s+i, f->rpos, k); +		f->rpos += k; +		i += k; +		if (z) break; +		__underflow(f); +	} +	(*s)[i] = 0; +	if (feof(f) || ferror(f)) { +		FUNLOCK(f); +		return -1; +	} + +	FUNLOCK(f); + +	if (i > SSIZE_MAX) { +		errno = EOVERFLOW; +		return -1; +	} + +	return i; +oom: +	errno = ENOMEM; +	return -1; +} diff --git a/src/stdio/getline.c b/src/stdio/getline.c new file mode 100644 index 00000000..a3a6651b --- /dev/null +++ b/src/stdio/getline.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +ssize_t getline(char **s, size_t *n, FILE *f) +{ +	return getdelim(s, n, '\n', f); +} diff --git a/src/stdio/gets.c b/src/stdio/gets.c new file mode 100644 index 00000000..24319eb2 --- /dev/null +++ b/src/stdio/gets.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" + +char *gets(char *s) +{ +	char *ret = fgets(s, INT_MAX, stdin); +	if (ret && s[strlen(s)-1] == '\n') s[strlen(s)-1] = 0; +	return ret; +} diff --git a/src/stdio/getw.c b/src/stdio/getw.c new file mode 100644 index 00000000..de9e985a --- /dev/null +++ b/src/stdio/getw.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +int getw(FILE *f) +{ +	int x; +	return fread(&x, sizeof x, 1, f) ? x : EOF; +} diff --git a/src/stdio/getwc.c b/src/stdio/getwc.c new file mode 100644 index 00000000..a2818bc4 --- /dev/null +++ b/src/stdio/getwc.c @@ -0,0 +1,6 @@ +#include "stdio_impl.h" + +wint_t getwc(FILE *f) +{ +	return fgetwc(f); +} diff --git a/src/stdio/getwchar.c b/src/stdio/getwchar.c new file mode 100644 index 00000000..2295bd40 --- /dev/null +++ b/src/stdio/getwchar.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" + +wint_t getwchar(void) +{ +	return fgetwc(stdin); +} + +weak_alias(getwchar, getwchar_unlocked); diff --git a/src/stdio/pclose.c b/src/stdio/pclose.c new file mode 100644 index 00000000..c2fe7a24 --- /dev/null +++ b/src/stdio/pclose.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +int pclose(FILE *f) +{ +	int status; +	fclose(f); +	while (waitpid(f->pipe_pid, &status, 0) == -1) +		if (errno != EINTR) return -1; +	return status; +} diff --git a/src/stdio/perror.c b/src/stdio/perror.c new file mode 100644 index 00000000..e4637c8a --- /dev/null +++ b/src/stdio/perror.c @@ -0,0 +1,27 @@ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include "stdio_impl.h" + +void perror(const char *msg) +{ +#if 1 +	if (msg) fprintf(stderr, "%s: %m\n", msg, strerror(errno)); +	else fprintf(stderr, "%m\n"); +#else +	FILE *f = stderr; +	char *errstr = strerror(errno); + +	FLOCK(f); +	 +	if (msg) { +		__fwritex(msg, strlen(msg), f); +		__putc_unlocked(':', f); +		__putc_unlocked(' ', f); +	} +	__fwritex(errstr, strlen(errstr), f); +	__putc_unlocked('\n', f); + +	FUNLOCK(f); +#endif +} diff --git a/src/stdio/popen.c b/src/stdio/popen.c new file mode 100644 index 00000000..1d33e9d6 --- /dev/null +++ b/src/stdio/popen.c @@ -0,0 +1,43 @@ +#include "stdio_impl.h" + +FILE *popen(const char *cmd, const char *mode) +{ +	int p[2]; +	int op; +	pid_t pid; +	FILE *f; +	const char *modes = "rw", *mi = strchr(modes, *mode); + +	if (mi) { +		op = mi-modes; +	} else { +		errno = EINVAL; +		return 0; +	} +	 +	if (pipe(p)) return NULL; +	f = fdopen(p[op], mode); +	if (!f) { +		close(p[0]); +		close(p[1]); +		return NULL; +	} +	 +	pid = fork(); +	switch (pid) { +	case -1: +		fclose(f); +		close(p[0]); +		close(p[1]); +		return NULL; +	case 0: +		dup2(p[1-op], 1-op); +		close(p[0]); +		close(p[1]); +		execl("/bin/sh", "sh", "-c", cmd, (char *)0); +		_exit(127); +	} +	close(p[1-op]); +	f->pipe_pid = pid; +	return f; +} diff --git a/src/stdio/printf.c b/src/stdio/printf.c new file mode 100644 index 00000000..efeb8b33 --- /dev/null +++ b/src/stdio/printf.c @@ -0,0 +1,12 @@ +#include <stdio.h> +#include <stdarg.h> + +int printf(const char *fmt, ...) +{ +	int ret; +	va_list ap; +	va_start(ap, fmt); +	ret = vprintf(fmt, ap); +	va_end(ap); +	return ret; +} diff --git a/src/stdio/putc.c b/src/stdio/putc.c new file mode 100644 index 00000000..3c9dc11e --- /dev/null +++ b/src/stdio/putc.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" + +int putc(int c, FILE *f) +{ +	return fputc(c, f); +} + +weak_alias(putc, _IO_putc); diff --git a/src/stdio/putc_unlocked.c b/src/stdio/putc_unlocked.c new file mode 100644 index 00000000..f01da717 --- /dev/null +++ b/src/stdio/putc_unlocked.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" + +int putc_unlocked(int c, FILE *f) +{ +	return f->wpos < f->wstop ? (*f->wpos++ = c) : __overflow(f, c); +} + +weak_alias(putc_unlocked, fputc_unlocked); diff --git a/src/stdio/putchar.c b/src/stdio/putchar.c new file mode 100644 index 00000000..945636d5 --- /dev/null +++ b/src/stdio/putchar.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int putchar(int c) +{ +	return fputc(c, stdout); +} diff --git a/src/stdio/putchar_unlocked.c b/src/stdio/putchar_unlocked.c new file mode 100644 index 00000000..72d47d15 --- /dev/null +++ b/src/stdio/putchar_unlocked.c @@ -0,0 +1,7 @@ +#include "stdio_impl.h" + +int putchar_unlocked(int c) +{ +	return stdout->wpos < stdout->wstop ? +		(*stdout->wpos++ = c) : __overflow(stdout, c); +} diff --git a/src/stdio/puts.c b/src/stdio/puts.c new file mode 100644 index 00000000..eb70efdc --- /dev/null +++ b/src/stdio/puts.c @@ -0,0 +1,6 @@ +#include "stdio_impl.h" + +int puts(const char *s) +{ +	return -(fputs(s, stdout) < 0 || putchar('\n') < 0); +} diff --git a/src/stdio/putw.c b/src/stdio/putw.c new file mode 100644 index 00000000..137832ee --- /dev/null +++ b/src/stdio/putw.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int putw(int x, FILE *f) +{ +	return fwrite(&x, sizeof x, 1, f) ? x : EOF; +} diff --git a/src/stdio/putwc.c b/src/stdio/putwc.c new file mode 100644 index 00000000..80b54a47 --- /dev/null +++ b/src/stdio/putwc.c @@ -0,0 +1,6 @@ +#include "stdio_impl.h" + +wint_t putwc(wchar_t c, FILE *f) +{ +	return fputwc(c, f); +} diff --git a/src/stdio/putwchar.c b/src/stdio/putwchar.c new file mode 100644 index 00000000..3aacc1cf --- /dev/null +++ b/src/stdio/putwchar.c @@ -0,0 +1,8 @@ +#include "stdio_impl.h" + +wint_t putwchar(wchar_t c) +{ +	return fputwc(c, stdout); +} + +weak_alias(putwchar, putwchar_unlocked); diff --git a/src/stdio/remove.c b/src/stdio/remove.c new file mode 100644 index 00000000..8e338277 --- /dev/null +++ b/src/stdio/remove.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include "syscall.h" + +int remove(const char *path) +{ +	return __syscall_unlink(path); +} diff --git a/src/stdio/rename.c b/src/stdio/rename.c new file mode 100644 index 00000000..4eced08a --- /dev/null +++ b/src/stdio/rename.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include "syscall.h" + +int rename(const char *old, const char *new) +{ +	return syscall2(__NR_rename, (long)old, (long)new); +} diff --git a/src/stdio/rewind.c b/src/stdio/rewind.c new file mode 100644 index 00000000..7944b434 --- /dev/null +++ b/src/stdio/rewind.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +void rewind(FILE *f) +{ +	fseek(f, 0, SEEK_SET); +} diff --git a/src/stdio/scanf.c b/src/stdio/scanf.c new file mode 100644 index 00000000..a04a4402 --- /dev/null +++ b/src/stdio/scanf.c @@ -0,0 +1,12 @@ +#include <stdio.h> +#include <stdarg.h> + +int scanf(const char *fmt, ...) +{ +	int ret; +	va_list ap; +	va_start(ap, fmt); +	ret = vscanf(fmt, ap); +	va_end(ap); +	return ret; +} diff --git a/src/stdio/setbuf.c b/src/stdio/setbuf.c new file mode 100644 index 00000000..205afcfe --- /dev/null +++ b/src/stdio/setbuf.c @@ -0,0 +1,6 @@ +#include "stdio_impl.h" + +void setbuf(FILE *f, char *buf) +{ +	setvbuf(f, buf, buf ? _IOFBF : _IONBF, BUFSIZ); +} diff --git a/src/stdio/setvbuf.c b/src/stdio/setvbuf.c new file mode 100644 index 00000000..2985d3f1 --- /dev/null +++ b/src/stdio/setvbuf.c @@ -0,0 +1,22 @@ +#include "stdio_impl.h" + +/* This function makes no attempt to protect the user from his/her own + * stupidity. If called any time but when then ISO C standard specifically + * allows it, all hell can and will break loose, especially with threads! + * + * This implementation ignores all arguments except the buffering type, + * and uses the existing buffer allocated alongside the FILE object. + * In the case of stderr where the preexisting buffer is length 1, it + * is not possible to set line buffering or full buffering. */ + +int setvbuf(FILE *f, char *buf, int type, size_t size) +{ +	f->lbf = EOF; + +	if (type == _IONBF) +		f->buf_size = 1; +	else if (type == _IOLBF) +		f->lbf = '\n'; + +	return 0; +} diff --git a/src/stdio/snprintf.c b/src/stdio/snprintf.c new file mode 100644 index 00000000..4071c2f6 --- /dev/null +++ b/src/stdio/snprintf.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <stdarg.h> + +int snprintf(char *s, size_t n, const char *fmt, ...) +{ +	int ret; +	va_list ap; +	va_start(ap, fmt); +	ret = vsnprintf(s, n, fmt, ap); +	va_end(ap); +	return ret; +} + diff --git a/src/stdio/sprintf.c b/src/stdio/sprintf.c new file mode 100644 index 00000000..6b225409 --- /dev/null +++ b/src/stdio/sprintf.c @@ -0,0 +1,12 @@ +#include <stdio.h> +#include <stdarg.h> + +int sprintf(char *s, const char *fmt, ...) +{ +	int ret; +	va_list ap; +	va_start(ap, fmt); +	ret = vsprintf(s, fmt, ap); +	va_end(ap); +	return ret; +} diff --git a/src/stdio/sscanf.c b/src/stdio/sscanf.c new file mode 100644 index 00000000..a1cea699 --- /dev/null +++ b/src/stdio/sscanf.c @@ -0,0 +1,12 @@ +#include <stdio.h> +#include <stdarg.h> + +int sscanf(const char *s, const char *fmt, ...) +{ +	int ret; +	va_list ap; +	va_start(ap, fmt); +	ret = vsscanf(s, fmt, ap); +	va_end(ap); +	return ret; +} diff --git a/src/stdio/stderr.c b/src/stdio/stderr.c new file mode 100644 index 00000000..4a79d4e7 --- /dev/null +++ b/src/stdio/stderr.c @@ -0,0 +1,13 @@ +#include "stdio_impl.h" + +static unsigned char buf[1+UNGET]; +static FILE f = { +	.buf = buf+UNGET, +	.buf_size = 1, +	.fd = 2, +	.flags = F_PERM | F_NORD, +	.write = __stdio_write, +	.seek = __stdio_seek, +	.close = __stdio_close, +}; +FILE *const stderr = &f; diff --git a/src/stdio/stdin.c b/src/stdio/stdin.c new file mode 100644 index 00000000..51c99232 --- /dev/null +++ b/src/stdio/stdin.c @@ -0,0 +1,13 @@ +#include "stdio_impl.h" + +static unsigned char buf[BUFSIZ+UNGET]; +static FILE f = { +	.buf = buf+UNGET, +	.buf_size = sizeof buf-UNGET, +	.fd = 0, +	.flags = F_PERM | F_NOWR, +	.read = __stdio_read, +	.seek = __stdio_seek, +	.close = __stdio_close, +}; +FILE *const stdin = &f; diff --git a/src/stdio/stdout.c b/src/stdio/stdout.c new file mode 100644 index 00000000..bf6eea6c --- /dev/null +++ b/src/stdio/stdout.c @@ -0,0 +1,17 @@ +#include "stdio_impl.h" + +static unsigned char buf[BUFSIZ+UNGET]; +static FILE f = { +	.buf = buf+UNGET, +	.buf_size = sizeof buf-UNGET, +	.fd = 1, +	.flags = F_PERM | F_NORD, +	.lbf = '\n', +	.write = __stdio_write, +	.seek = __stdio_seek, +	.close = __stdio_close, +}; +FILE *const stdout = &f; + +/* overrides symbol in fflush.c, used for flushing NULL */ +FILE *const __stdout_to_flush = &f; diff --git a/src/stdio/swscanf.c b/src/stdio/swscanf.c new file mode 100644 index 00000000..b66ad03e --- /dev/null +++ b/src/stdio/swscanf.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <stdarg.h> +#include <wchar.h> + +int swscanf(const wchar_t *s, const wchar_t *fmt, ...) +{ +	int ret; +	va_list ap; +	va_start(ap, fmt); +	ret = vswscanf(s, fmt, ap); +	va_end(ap); +	return ret; +} diff --git a/src/stdio/tempnam.c b/src/stdio/tempnam.c new file mode 100644 index 00000000..2cbcb864 --- /dev/null +++ b/src/stdio/tempnam.c @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <limits.h> +#include <errno.h> +#include "libc.h" + +char *tempnam(const char *dir, const char *pfx) +{ +	static int lock; +	static int index; +	char *s; +	int pid = getpid(); +	int l; + +	if (!dir) dir = P_tmpdir; +	if (!pfx) pfx = "temp"; + +	if (access(dir, R_OK|W_OK|X_OK) != 0) +		return NULL; + +	l = strlen(dir) + 1 + strlen(pfx) + 2 + sizeof(int)*3*2 + 1; +	s = malloc(l); +	if (!s) { +		errno = ENOMEM; +		return NULL; +	} + +	LOCK(&lock); +	for (; index < TMP_MAX; index++) { +		snprintf(s, l, "%s/%s-%d-%d", dir, pfx, pid, index); +		if (access(s, F_OK) != 0) { +			UNLOCK(&lock); +			return s; +		} +	} +	UNLOCK(&lock); +	free(s); +	return NULL;	 +} diff --git a/src/stdio/tmpfile.c b/src/stdio/tmpfile.c new file mode 100644 index 00000000..185025f1 --- /dev/null +++ b/src/stdio/tmpfile.c @@ -0,0 +1,23 @@ +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include "stdio_impl.h" + +FILE *tmpfile(void) +{ +	char buf[L_tmpnam], *s; +	int fd; +	FILE *f; +	for (;;) { +		s = tmpnam(buf); +		if (!s) return NULL; +		fd = __syscall_open(s, O_RDWR | O_CREAT | O_EXCL, 0600); +		if (fd >= 0) { +			f = __fdopen(fd, "w+"); +			remove(s); +			return f; +		} +	} +} + +LFS64(tmpfile); diff --git a/src/stdio/tmpnam.c b/src/stdio/tmpnam.c new file mode 100644 index 00000000..14d59220 --- /dev/null +++ b/src/stdio/tmpnam.c @@ -0,0 +1,38 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <unistd.h> +#include "libc.h" + +char *tmpnam(char *s) +{ +	static int lock; +	static int index; +	static char *s2; +	int pid = getpid(); +	char *dir = getenv("TMPDIR"); + +	if (!s) { +		if (!s2) s2 = malloc(L_tmpnam); +		s = s2; +	} + +	/* this interface is insecure anyway but at least we can try.. */ +	if (!dir || strlen(dir) > L_tmpnam-32) +		dir = P_tmpdir; + +	if (access(dir, R_OK|W_OK|X_OK) != 0) +		return NULL; + +	LOCK(&lock); +	for (index++; index < TMP_MAX; index++) { +		snprintf(s, L_tmpnam, "%s/temp%d-%d", dir, pid, index); +		if (access(s, F_OK) != 0) { +			UNLOCK(&lock); +			return s; +		} +	} +	UNLOCK(&lock); +	return NULL; +} diff --git a/src/stdio/ungetc.c b/src/stdio/ungetc.c new file mode 100644 index 00000000..07181684 --- /dev/null +++ b/src/stdio/ungetc.c @@ -0,0 +1,33 @@ +#include "stdio_impl.h" + +int ungetc(int c, FILE *f) +{ +	if (c == EOF) return c; + +	FLOCK(f); + +	/* Fail if unreadable or writing and unable to flush */ +	if ((f->flags & (F_ERR|F_NORD)) || (f->wpos && __oflow(f))) { +		FUNLOCK(f); +		return EOF; +	} + +	/* Clear write mode */ +	f->wbase = f->wpos = f->wstop = f->wend = 0; + +	/* Put the file in read mode */ +	if (!f->rpos) f->rpos = f->rend = f->buf; + +	/* If unget buffer is already full, fail. */ +	if (f->rpos <= f->buf - UNGET) { +		FUNLOCK(f); +		return EOF; +	} + +	/* Put a byte back into the buffer */ +	*--f->rpos = c; +	f->flags &= ~F_EOF; + +	FUNLOCK(f); +	return c; +} diff --git a/src/stdio/ungetwc.c b/src/stdio/ungetwc.c new file mode 100644 index 00000000..f7cde2e0 --- /dev/null +++ b/src/stdio/ungetwc.c @@ -0,0 +1,45 @@ +#include "stdio_impl.h" + +wint_t ungetwc(wint_t c, FILE *f) +{ +	unsigned char mbc[MB_LEN_MAX]; +	int l=1; + +	if (c == WEOF) return c; + +	/* Try conversion early so we can fail without locking if invalid */ +	if (!isascii(c) && (l = wctomb(mbc, c)) < 0) +		return WEOF; + +	FLOCK(f); + +	f->mode |= f->mode+1; + +	/* Fail if unreadable or writing and unable to flush */ +	if ((f->flags & (F_ERR|F_NORD)) || (f->wpos && __oflow(f))) { +		FUNLOCK(f); +		return EOF; +	} + +	/* Clear write mode */ +	f->wpos = f->wstop = f->wend = 0; + +	/* Put the file in read mode */ +	if (!f->rpos) f->rpos = f->rend = f->buf; + +	/* If unget buffer is nonempty, fail. */ +	if (f->rpos < f->buf) { +		FUNLOCK(f); +		return WEOF; +	} + +	/* Put character back into the buffer */ +	if (isascii(c)) *--f->rpos = c; +	else memcpy(f->rpos -= l, mbc, l); + +	/* Clear EOF */ +	f->flags &= ~F_EOF; + +	FUNLOCK(f); +	return c; +} diff --git a/src/stdio/vasprintf.c b/src/stdio/vasprintf.c new file mode 100644 index 00000000..f2bbc7aa --- /dev/null +++ b/src/stdio/vasprintf.c @@ -0,0 +1,27 @@ +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> + +#define GUESS 240U + +int vasprintf(char **s, const char *fmt, va_list ap) +{ +	va_list ap2; +	char *a; +	int l=GUESS; + +	if (!(a=malloc(GUESS))) return -1; + +	va_copy(ap2, ap); +	l=vsnprintf(a, GUESS, fmt, ap2); +	va_end(ap2); + +	if (l<GUESS) { +		char *b = realloc(a, l+1U); +		*s = b ? b : a; +		return l; +	} +	free(a); +	if (l<0 || !(*s=malloc(l+1U))) return -1; +	return vsnprintf(*s, l+1U, fmt, ap); +} diff --git a/src/stdio/vdprintf.c b/src/stdio/vdprintf.c new file mode 100644 index 00000000..bfb1b0a9 --- /dev/null +++ b/src/stdio/vdprintf.c @@ -0,0 +1,14 @@ +#include "stdio_impl.h" + +int vdprintf(int fd, const char *fmt, va_list ap) +{ +	int r; +	char buf[BUFSIZ]; +	FILE f = { +		.fd = fd, .lbf = EOF, .write = __stdio_write, +		.buf = buf+UNGET, .buf_size = sizeof buf - UNGET +	}; +	r = vfprintf(&f, fmt, ap); +	__oflow(&f); +	return r; +} diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c new file mode 100644 index 00000000..5e19acc5 --- /dev/null +++ b/src/stdio/vfprintf.c @@ -0,0 +1,640 @@ +#include "stdio_impl.h" + +/* Some useful macros */ + +#define MAX(a,b) ((a)>(b) ? (a) : (b)) +#define MIN(a,b) ((a)<(b) ? (a) : (b)) +#define CONCAT2(x,y) x ## y +#define CONCAT(x,y) CONCAT2(x,y) + +/* Convenient bit representation for modifier flags, which all fall + * within 31 codepoints of the space character. */ + +#define ALT_FORM   (1U<<'#'-' ') +#define ZERO_PAD   (1U<<'0'-' ') +#define LEFT_ADJ   (1U<<'-'-' ') +#define PAD_POS    (1U<<' '-' ') +#define MARK_POS   (1U<<'+'-' ') +#define GROUPED    (1U<<'\''-' ') + +#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED) + +#if UINT_MAX == ULONG_MAX +#define LONG_IS_INT +#endif + +#if SIZE_MAX != ULONG_MAX || UINTMAX_MAX != ULLONG_MAX +#define ODD_TYPES +#endif + +/* State machine to accept length modifiers + conversion specifiers. + * Result is 0 on failure, or an argument type to pop on success. */ + +enum { +	BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE, +	ZTPRE, JPRE, +	STOP, +	PTR, INT, UINT, ULLONG, +#ifndef LONG_IS_INT +	LONG, ULONG, +#else +#define LONG INT +#define ULONG UINT +#endif +	SHORT, USHORT, CHAR, UCHAR, +#ifdef ODD_TYPES +	LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR, +#else +#define LLONG ULLONG +#define SIZET ULONG +#define IMAX LLONG +#define UMAX ULLONG +#define PDIFF LONG +#define UIPTR ULONG +#endif +	DBL, LDBL, +	NOARG, +	MAXSTATE +}; + +#define S(x) [(x)-'A'] + +static const unsigned char states[]['z'-'A'+1] = { +	{ /* 0: bare types */ +		S('d') = INT, S('i') = INT, +		S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT, +		S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, +		S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, +		S('c') = CHAR, S('C') = INT, +		S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR, +		S('m') = NOARG, +		S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE, +		S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE, +	}, { /* 1: l-prefixed */ +		S('d') = LONG, S('i') = LONG, +		S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG, +		S('c') = INT, S('s') = PTR, S('n') = PTR, +		S('l') = LLPRE, +	}, { /* 2: ll-prefixed */ +		S('d') = LLONG, S('i') = LLONG, +		S('o') = ULLONG, S('u') = ULLONG, +		S('x') = ULLONG, S('X') = ULLONG, +		S('n') = PTR, +	}, { /* 3: h-prefixed */ +		S('d') = SHORT, S('i') = SHORT, +		S('o') = USHORT, S('u') = USHORT, +		S('x') = USHORT, S('X') = USHORT, +		S('n') = PTR, +		S('h') = HHPRE, +	}, { /* 4: hh-prefixed */ +		S('d') = CHAR, S('i') = CHAR, +		S('o') = UCHAR, S('u') = UCHAR, +		S('x') = UCHAR, S('X') = UCHAR, +		S('n') = PTR, +	}, { /* 5: L-prefixed */ +		S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL, +		S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL, +		S('n') = PTR, +	}, { /* 6: z- or t-prefixed (assumed to be same size) */ +		S('d') = PDIFF, S('i') = PDIFF, +		S('o') = SIZET, S('u') = SIZET, +		S('x') = SIZET, S('X') = SIZET, +		S('n') = PTR, +	}, { /* 7: j-prefixed */ +		S('d') = IMAX, S('i') = IMAX, +		S('o') = UMAX, S('u') = UMAX, +		S('x') = UMAX, S('X') = UMAX, +		S('n') = PTR, +	} +}; + +#define OOB(x) ((unsigned)(x)-'A' > 'z'-'A') + +union arg +{ +	uintmax_t i; +	long double f; +	void *p; +}; + +static void pop_arg(union arg *arg, int type, va_list *ap) +{ +	/* Give the compiler a hint for optimizing the switch. */ +	if ((unsigned)type > MAXSTATE) return; +	switch (type) { +	       case PTR:	arg->p = va_arg(*ap, void *); +	break; case INT:	arg->i = va_arg(*ap, int); +	break; case UINT:	arg->i = va_arg(*ap, unsigned int); +#ifndef LONG_IS_INT +	break; case LONG:	arg->i = va_arg(*ap, long); +	break; case ULONG:	arg->i = va_arg(*ap, unsigned long); +#endif +	break; case ULLONG:	arg->i = va_arg(*ap, unsigned long long); +	break; case SHORT:	arg->i = (short)va_arg(*ap, int); +	break; case USHORT:	arg->i = (unsigned short)va_arg(*ap, int); +	break; case CHAR:	arg->i = (signed char)va_arg(*ap, int); +	break; case UCHAR:	arg->i = (unsigned char)va_arg(*ap, int); +#ifdef ODD_TYPES +	break; case LLONG:	arg->i = va_arg(*ap, long long); +	break; case SIZET:	arg->i = va_arg(*ap, size_t); +	break; case IMAX:	arg->i = va_arg(*ap, intmax_t); +	break; case UMAX:	arg->i = va_arg(*ap, uintmax_t); +	break; case PDIFF:	arg->i = va_arg(*ap, ptrdiff_t); +	break; case UIPTR:	arg->i = (uintptr_t)va_arg(*ap, void *); +#endif +	break; case DBL:	arg->f = va_arg(*ap, double); +	break; case LDBL:	arg->f = va_arg(*ap, long double); +	} +} + +static void out(FILE *f, const char *s, size_t l) +{ +	__fwritex(s, l, f); +} + +static void pad(FILE *f, char c, int w, int l, int fl) +{ +	char pad[256]; +	if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return; +	l = w - l; +	memset(pad, c, l>sizeof pad ? sizeof pad : l); +	for (; l >= sizeof pad; l -= sizeof pad) +		out(f, pad, sizeof pad); +	out(f, pad, l); +} + +static const char xdigits[16] = { +	"0123456789ABCDEF" +}; + +static char *fmt_x(uintmax_t x, char *s, int lower) +{ +	for (; x; x>>=4) *--s = xdigits[(x&15)]|lower; +	return s; +} + +static char *fmt_o(uintmax_t x, char *s) +{ +	for (; x; x>>=3) *--s = '0' + (x&7); +	return s; +} + +static char *fmt_u(uintmax_t x, char *s) +{ +	unsigned long y; +	for (   ; x>ULONG_MAX; x/=10) *--s = '0' + x%10; +	for (y=x;           y; y/=10) *--s = '0' + y%10; +	return s; +} + +static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) +{ +	uint32_t big[(LDBL_MAX_EXP+LDBL_MANT_DIG)/9+1]; +	uint32_t *a, *d, *r, *z; +	int e2=0, e, i, j, l; +	char buf[9+LDBL_MANT_DIG/4], *s; +	const char *prefix="-+ "; +	int pl; +	char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr; + +	pl=1; +	if (y<0 || 1/y<0) { +		y=-y; +	} else if (fl & MARK_POS) { +		prefix++; +	} else if (fl & PAD_POS) { +		prefix+=2; +	} else pl=0; + +	if (!isfinite(y)) { +		char *s = (t&32)?"inf":"INF"; +		if (y!=y) s=(t&32)?"nan":"NAN", pl=0; +		pad(f, ' ', w, 3+pl, fl&~ZERO_PAD); +		out(f, prefix, pl); +		out(f, s, 3); +		pad(f, ' ', w, 3+pl, fl^LEFT_ADJ); +		return MAX(w, 3+pl); +	} + +	y = frexpl(y, &e2) * 2; +	if (y) e2--; + +	if ((t|32)=='a') { +		long double round = 8.0; +		int re; + +		if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0; +		else re=LDBL_MANT_DIG/4-1-p; + +		if (re) { +			if (pl && *prefix=='-') y=-y; +			while (re--) round*=16; +			y+=round; +			y-=round; +			if (y<0) y=-y; +		} + +		estr=fmt_u(e2<0 ? -e2 : e2, ebuf); +		if (estr==ebuf) *--estr='0'; +		*--estr = (e2<0 ? '-' : '+'); +		*--estr = t+('p'-'a'); + +		s=buf; +		*s++='0'; +		*s++=t+('x'-'a'); +		do { +			int x=y; +			*s++=xdigits[x]|(t&32); +			y=16*(y-x); +			if (s-buf==3 && (y||p>0||(fl&ALT_FORM))) *s++='.'; +		} while (y); + +		if (p<0) p = s-buf-4; +		l = 1 + p + (p || (fl&ALT_FORM)) + ebuf-estr; + +		pad(f, ' ', w, pl+l, fl); +		out(f, prefix, pl); +		pad(f, '0', w, pl+l, fl^ZERO_PAD); +		out(f, buf, s-buf); +		pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0); +		out(f, estr, ebuf-estr); +		pad(f, '0', w, pl+l, fl^LEFT_ADJ); +		return MAX(w, pl+l); +	} +	if (p<0) p=6; + +	y *= 0x1p28; e2-=28; + +	if (e2<0) a=r=z=big; +	else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1; + +	do { +		*z = y; +		y = 1000000000*(y-*z++); +	} while (y); + +	while (e2>0) { +		uint32_t carry=0; +		int sh=MIN(29,e2); +		for (d=z-1; d>=a; d--) { +			uint64_t x = ((uint64_t)*d<<sh)+carry; +			*d = x % 1000000000; +			carry = x / 1000000000; +		} +		if (!z[-1] && z>a) z--; +		if (carry) *--a = carry; +		e2-=sh; +	} +	while (e2<0) { +		uint32_t carry=0, *z2; +		int sh=MIN(9,-e2); +		for (d=a; d<z; d++) { +			uint32_t rm = *d & (1<<sh)-1; +			*d = (*d>>sh) + carry; +			carry = (1000000000>>sh) * rm; +		} +		if (!*a) a++; +		if (carry) *z++ = carry; +		/* Avoid (slow!) computation past requested precision */ +		z2 = ((t|32)=='f' ? r : a) + 2 + p/9; +		z = MIN(z, z2); +		e2+=sh; +	} + +	if (a<z) for (i=10, e=9*(r-a); *a>=i; i*=10, e++); +	else e=0; + +	/* Perform rounding: j is precision after the radix (possibly neg) */ +	j = p - ((t|32)!='f')*e - ((t|32)=='g'); +	if (j < 9*(z-r-1)) { +		uint32_t x; +		/* We avoid C's broken division of negative numbers */ +		d = r + 1 + (j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP; +		j += 9*LDBL_MAX_EXP; +		j %= 9; +		for (i=10, j++; j<9; i*=10, j++); +		x = *d % i; +		/* Are there any significant digits past j? */ +		if (x || d+1!=z) { +			long double round = CONCAT(0x1p,LDBL_MANT_DIG); +			long double small; +			if (x<i/2) small=0x01p-1; +			else if (i==i/2 && d+1==z) small=0x10p-1; +			else small=0x11p-1; +			if (pl && *prefix=='-') round*=-1, small*=-1; +			/* Decide whether to round by probing round+small */ +			if (round+small != round) { +				*d = *d - x + i; +				while (*d > 999999999) { +					*d--=0; +					(*d)++; +				} +				if (d<a) a=d; +				for (i=10, e=9*(r-a); *a>=i; i*=10, e++); +			} +		} +		for (; !z[-1] && z>a; z--); +	} +	 +	if ((t|32)=='g') { +		if (!p) p++; +		if (p>e && e>=-4) { +			t--; +			p-=e+1; +		} else { +			t-=2; +			p--; +		} +		if (!(fl&ALT_FORM)) { +			/* Count trailing zeros in last place */ +			if (z>a) for (i=10, j=0; z[-1]%i==0; i*=10, j++); +			else j=9; +			if ((t|32)=='f') +				p = MIN(p,MAX(0,9*(z-r-1)-j)); +			else +				p = MIN(p,MAX(0,9*(z-r-1)+e-j)); +		} +	} +	l = 1 + p + (p || (fl&ALT_FORM)); +	if ((t|32)=='f') { +		if (e>0) l+=e; +	} else { +		estr=fmt_u(e<0 ? -e : e, ebuf); +		while(ebuf-estr<2) *--estr='0'; +		*--estr = (e<0 ? '-' : '+'); +		*--estr = t; +		l += ebuf-estr; +	} + +	pad(f, ' ', w, pl+l, fl); +	out(f, prefix, pl); +	pad(f, '0', w, pl+l, fl^ZERO_PAD); + +	if ((t|32)=='f') { +		if (a>r) a=r; +		for (d=a; d<=r; d++) { +			char *s = fmt_u(*d, buf+9); +			if (d!=a) while (s>buf) *--s='0'; +			else if (s==buf+9) *--s='0'; +			out(f, s, buf+9-s); +		} +		if (p || (fl&ALT_FORM)) out(f, ".", 1); +		for (; d<z && p>0; d++, p-=9) { +			char *s = fmt_u(*d, buf+9); +			while (s>buf) *--s='0'; +			out(f, s, MIN(9,p)); +		} +		pad(f, '0', p+9, 9, 0); +	} else { +		if (z<=a) z=a+1; +		for (d=a; d<z && p>=0; d++) { +			char *s = fmt_u(*d, buf+9); +			if (s==buf+9) *--s='0'; +			if (d!=a) while (s>buf) *--s='0'; +			else { +				out(f, s++, 1); +				if (p>0||(fl&ALT_FORM)) out(f, ".", 1); +			} +			out(f, s, MIN(buf+9-s, p)); +			p -= buf+9-s; +		} +		pad(f, '0', p+18, 18, 0); +		out(f, estr, ebuf-estr); +	} + +	pad(f, ' ', w, pl+l, fl^LEFT_ADJ); + +	return MAX(w, pl+l); +} + +static int getint(char **s) { +	int i; +	for (i=0; isdigit(**s); (*s)++) +		i = 10*i + (**s-'0'); +	return i; +} + +static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, int *nl_type) +{ +	char *a, *z, *s=(char *)fmt; +	unsigned l10n=0, litpct, fl; +	int w, p; +	union arg arg; +	int argpos; +	unsigned st, ps; +	int cnt=0, l=0; +	int i; +	char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4]; +	const char *prefix; +	int t, pl; +	wchar_t wc[2], *ws; +	char mb[4]; + +	for (;;) { +		/* Update output count, end loop when fmt is exhausted */ +		if (cnt >= 0) { +			if (l > INT_MAX - cnt) { +				if (!ferror(f)) errno = EOVERFLOW; +				cnt = -1; +			} else cnt += l; +		} +		if (!*s) break; + +		/* Handle literal text and %% format specifiers */ +		for (a=s; *s && *s!='%'; s++); +		litpct = strspn(s, "%")/2; /* Optimize %%%% runs */ +		z = s+litpct; +		s += 2*litpct; +		l = z-a; +		if (f) out(f, a, l); +		if (l) continue; + +		if (isdigit(s[1]) && s[2]=='$') { +			l10n=1; +			argpos = s[1]-'0'; +			s+=3; +		} else { +			argpos = -1; +			s++; +		} + +		/* Read modifier flags */ +		for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++) +			fl |= 1U<<*s-' '; + +		/* Read field width */ +		if (*s=='*') { +			if (isdigit(s[1]) && s[2]=='$') { +				l10n=1; +				nl_type[s[1]-'0'] = INT; +				w = nl_arg[s[1]-'0'].i; +				s+=3; +			} else if (!l10n) { +				w = f ? va_arg(*ap, int) : 0; +				s++; +			} else return -1; +			if (w<0) fl|=LEFT_ADJ, w=-w; +		} else if ((w=getint(&s))<0) return -1; + +		/* Read precision */ +		if (*s=='.' && s[1]=='*') { +			if (isdigit(s[2]) && s[3]=='$') { +				nl_type[s[2]-'0'] = INT; +				p = nl_arg[s[2]-'0'].i; +				s+=4; +			} else if (!l10n) { +				p = f ? va_arg(*ap, int) : 0; +				s+=2; +			} else return -1; +		} else if (*s=='.') { +			s++; +			p = getint(&s); +		} else p = -1; + +		/* Format specifier state machine */ +		st=0; +		do { +			if (OOB(*s)) return -1; +			ps=st; +			st=states[st]S(*s++); +		} while (st-1<STOP); +		if (!st) return -1; + +		/* Check validity of argument type (nl/normal) */ +		if (st==NOARG) { +			if (argpos>=0) return -1; +			else if (!f) continue; +		} else { +			if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos]; +			else if (f) pop_arg(&arg, st, ap); +			else return 0; +		} + +		if (!f) continue; + +		z = buf + sizeof(buf); +		prefix = "-+   0X0x"; +		pl = 0; +		t = s[-1]; + +		/* Transform ls,lc -> S,C */ +		if (ps && (t&15)==3) t&=~32; + +		/* - and 0 flags are mutually exclusive */ +		if (fl & LEFT_ADJ) fl &= ~ZERO_PAD; + +		switch(t) { +		case 'n': +			switch(ps) { +			case BARE: *(int *)arg.p = l; +			case LPRE: *(long *)arg.p = l; +			case LLPRE: *(long long *)arg.p = l; +			case HPRE: *(unsigned short *)arg.p = l; +			case HHPRE: *(unsigned char *)arg.p = l; +			case ZTPRE: *(size_t *)arg.p = l; +			case JPRE: *(uintmax_t *)arg.p = l; +			} +			continue; +		case 'p': +			p = MAX(p, 2*sizeof(void*)); +			t = 'x'; +			fl |= ALT_FORM; +		case 'x': case 'X': +			a = fmt_x(arg.i, z, t&32); +			if (fl & ALT_FORM) prefix+=(t>>4), pl=2; +			if (0) { +		case 'o': +			a = fmt_o(arg.i, z); +			if ((fl&ALT_FORM) && arg.i) prefix+=5, pl=1; +			} if (0) { +		case 'd': case 'i': +			pl=1; +			if (arg.i>INTMAX_MAX) { +				arg.i=-arg.i; +			} else if (fl & MARK_POS) { +				prefix++; +			} else if (fl & PAD_POS) { +				prefix+=2; +			} else pl=0; +		case 'u': +			a = fmt_u(arg.i, z); +			} +			if (!arg.i && !p) continue; +			if (p>=0) fl &= ~ZERO_PAD; +			p = MAX(p, z-a + !arg.i); +			break; +		case 'c': +			*(a=z-(p=1))=arg.i; +			fl &= ~ZERO_PAD; +			break; +		case 'm': +			if (1) a = strerror(errno); else +		case 's': +			a = arg.p; +			z = memchr(a, 0, p); +			if (!z) z=a+p; +			else p=z-a; +			fl &= ~ZERO_PAD; +			break; +		case 'C': +			wc[0] = arg.i; +			wc[1] = 0; +			arg.p = wc; +			p = -1; +		case 'S': +			ws = arg.p; +			for (i=0; *ws && (l=wctomb(mb, *ws++))>=0 && l<=0U+p-i; i+=l); +			if (l<0) return -1; +			p = i; +			pad(f, ' ', w, p, fl); +			ws = arg.p; +			for (i=0; *ws && i+(l=wctomb(mb, *ws++))<=p; i+=l) +				out(f, mb, l); +			pad(f, ' ', w, p, fl^LEFT_ADJ); +			l = w>p ? w : p; +			continue; +		case 'e': case 'f': case 'g': case 'a': +		case 'E': case 'F': case 'G': case 'A': +			l = fmt_fp(f, arg.f, w, p, fl, t); +			continue; +		} + +		if (p < z-a) p = z-a; +		if (w < pl+p) w = pl+p; + +		pad(f, ' ', w, pl+p, fl); +		out(f, prefix, pl); +		pad(f, '0', w, pl+p, fl^ZERO_PAD); +		pad(f, '0', p, z-a, 0); +		out(f, a, z-a); +		pad(f, ' ', w, pl+p, fl^LEFT_ADJ); + +		l = w; +	} + +	if (f) return cnt; +	if (!l10n) return 0; + +	for (i=1; i<=NL_ARGMAX && nl_type[i]; i++) +		pop_arg(nl_arg+i, nl_type[i], ap); +	for (; i<=NL_ARGMAX && !nl_type[i]; i++); +	if (i<=NL_ARGMAX) return -1; +	return 1; +} + +int vfprintf(FILE *f, const char *fmt, va_list ap) +{ +	va_list ap2; +	int nl_type[NL_ARGMAX] = {0}; +	union arg nl_arg[NL_ARGMAX]; +	int ret; + +	va_copy(ap2, ap); +	if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) return -1; + +	FLOCK(f); +	ret = printf_core(f, fmt, &ap2, nl_arg, nl_type); +	FUNLOCK(f); +	va_end(ap2); +	return ret; +} diff --git a/src/stdio/vfscanf.c b/src/stdio/vfscanf.c new file mode 100644 index 00000000..69f45081 --- /dev/null +++ b/src/stdio/vfscanf.c @@ -0,0 +1,43 @@ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> + +#include "stdio_impl.h" +#include "__scanf.h" + +static void f_read(rctx_t *r) +{ +	FILE *f = r->opaque; +	if ((r->c = __uflow(f)) >= 0) r->l++; +} + +int vfscanf(FILE *f, const char *fmt, va_list ap) +{ +	size_t l = strlen(fmt), i, result; +	rctx_t r = { f_read, (void *)f, 0, isspace }; +	wchar_t fmt2[l+1]; + +	if (l > 0x100000) { +		errno = ENOMEM; +		return -1; +	} +	for (i=0; i<=l; i++) fmt2[i] = (unsigned char)fmt[i]; + +	FLOCK(f); + +	result = __scanf(&r, fmt2, ap); + +	if (r.u && r.c >= 0) { +		/* This code takes care of the case where the caller performs +		 * a nonmatching scanf to leave a character in the unscan +		 * buffer, followed by an unget, followed by a scanf that +		 * matches zero characters. In this case the final 'unread' +		 * character must be returned to the unget buffer rather than +		 * the unscan buffer. */ +		 f->rpos--; +	} + +	FUNLOCK(f); +	return result; +} diff --git a/src/stdio/vfwscanf.c b/src/stdio/vfwscanf.c new file mode 100644 index 00000000..491c1403 --- /dev/null +++ b/src/stdio/vfwscanf.c @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <wchar.h> +#include <wctype.h> + +#include "stdio_impl.h" +#include "__scanf.h" + +static void f_read(rctx_t *r) +{ +	FILE *f = r->opaque; +	if ((r->c = fgetwc(f)) >= 0) r->l++; +} + +int vfwscanf(FILE *f, const wchar_t *fmt, va_list ap) +{ +	rctx_t r = { f_read, (void *)f, 1, iswspace }; +	int result; + +	result = __scanf(&r, fmt, ap); + +	if (r.u && r.c >= 0) { +		ungetwc(r.c, f); +	} + +	return result; +} diff --git a/src/stdio/vprintf.c b/src/stdio/vprintf.c new file mode 100644 index 00000000..67b38dac --- /dev/null +++ b/src/stdio/vprintf.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int vprintf(const char *fmt, va_list ap) +{ +	return vfprintf(stdout, fmt, ap); +} diff --git a/src/stdio/vscanf.c b/src/stdio/vscanf.c new file mode 100644 index 00000000..6f55b1c3 --- /dev/null +++ b/src/stdio/vscanf.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include <stdarg.h> + +int vscanf(const char *fmt, va_list ap) +{ +	return vfscanf(stdin, fmt, ap); +} diff --git a/src/stdio/vsnprintf.c b/src/stdio/vsnprintf.c new file mode 100644 index 00000000..bda6b49b --- /dev/null +++ b/src/stdio/vsnprintf.c @@ -0,0 +1,33 @@ +#include "stdio_impl.h" + +static size_t sn_write(FILE *f, const unsigned char *s, size_t l) +{ +	/* pretend to succeed, but discard data */ +	return l; +} + +int vsnprintf(char *s, size_t n, const char *fmt, va_list ap) +{ +	int r; +	FILE f; +	unsigned char buf[1]; + +	memset(&f, 0, sizeof(FILE)); +	f.lbf = EOF; +	f.write = sn_write; +	f.buf_size = 1; +	f.buf = buf; +	if (n > INT_MAX) { +		errno = EOVERFLOW; +		return -1; +	} else if (n > 0) { +		if (n > (char *)0+SIZE_MAX-s) n = (char *)0+SIZE_MAX-s; +		f.wpos = s; +		f.wbase = f.wend = s+n-1; +		f.wstop = f.wend - 1; +	} +	r = vfprintf(&f, fmt, ap); +	/* wpos points just after last byte written, or to s+n-1 (wbase) */ +	*f.wpos = 0; +	return r; +} diff --git a/src/stdio/vsprintf.c b/src/stdio/vsprintf.c new file mode 100644 index 00000000..7836ccb2 --- /dev/null +++ b/src/stdio/vsprintf.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include <limits.h> + +int vsprintf(char *s, const char *fmt, va_list ap) +{ +	return vsnprintf(s, INT_MAX, fmt, ap); +} diff --git a/src/stdio/vsscanf.c b/src/stdio/vsscanf.c new file mode 100644 index 00000000..fd48f709 --- /dev/null +++ b/src/stdio/vsscanf.c @@ -0,0 +1,21 @@ +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "__scanf.h" + +static void s_read(rctx_t *r) +{ +	unsigned char *s = r->opaque; +	if (!s[r->l]) r->c = -1; +	else r->c = s[r->l++]; +} + +int vsscanf(const char *s, const char *fmt, va_list ap) +{ +	size_t l = strlen(fmt), i; +	wchar_t fmt2[l+1]; +	rctx_t r = { s_read, (void *)s, 0, isspace }; +	for (i=0; i<=l; i++) fmt2[i] = (unsigned char)fmt[i]; +	return __scanf(&r, fmt2, ap); +} diff --git a/src/stdio/vswscanf.c b/src/stdio/vswscanf.c new file mode 100644 index 00000000..2c4ffbe0 --- /dev/null +++ b/src/stdio/vswscanf.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <string.h> +#include <wchar.h> +#include <wctype.h> + +#include "__scanf.h" + +static void s_read(rctx_t *r) +{ +	wchar_t *s = r->opaque; +	if (!s[r->l]) r->c = -1; +	else r->c = s[r->l++]; +} + +int vswscanf(const wchar_t *s, const wchar_t *fmt, va_list ap) +{ +	rctx_t r = { s_read, (void *)s, 1, iswspace }; +	return __scanf(&r, fmt, ap); +} diff --git a/src/stdio/vwscanf.c b/src/stdio/vwscanf.c new file mode 100644 index 00000000..86da0457 --- /dev/null +++ b/src/stdio/vwscanf.c @@ -0,0 +1,8 @@ +#include <stdio.h> +#include <stdarg.h> +#include <wchar.h> + +int vwscanf(const wchar_t *fmt, va_list ap) +{ +	return vfwscanf(stdin, fmt, ap); +} diff --git a/src/stdio/wscanf.c b/src/stdio/wscanf.c new file mode 100644 index 00000000..34b58846 --- /dev/null +++ b/src/stdio/wscanf.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <stdarg.h> +#include <wchar.h> + +int wscanf(const wchar_t *fmt, ...) +{ +	int ret; +	va_list ap; +	va_start(ap, fmt); +	ret = vwscanf(fmt, ap); +	va_end(ap); +	return ret; +} diff --git a/src/stdlib/abs.c b/src/stdlib/abs.c new file mode 100644 index 00000000..4806d629 --- /dev/null +++ b/src/stdlib/abs.c @@ -0,0 +1,4 @@ +int abs(int a) +{ +	return a>0 ? a : -a; +} diff --git a/src/stdlib/atof.c b/src/stdlib/atof.c new file mode 100644 index 00000000..f7fcd826 --- /dev/null +++ b/src/stdlib/atof.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +double atof(const char *s) +{ +	return strtod(s, 0); +} diff --git a/src/stdlib/atoi.c b/src/stdlib/atoi.c new file mode 100644 index 00000000..648b154f --- /dev/null +++ b/src/stdlib/atoi.c @@ -0,0 +1,15 @@ +#include <stdlib.h> +#include <ctype.h> + +int atoi(const char *s) +{ +	int n=0, neg=0; +	while (isspace(*s)) s++; +	switch (*s) { +	case '-': neg=1; +	case '+': s++; +	} +	while (isdigit(*s)) +		n = 10*n + *s++ - '0'; +	return neg ? -n : n; +} diff --git a/src/stdlib/atol.c b/src/stdlib/atol.c new file mode 100644 index 00000000..9c91bba9 --- /dev/null +++ b/src/stdlib/atol.c @@ -0,0 +1,16 @@ +#include <stdlib.h> +#include <ctype.h> + +long atol(const char *s) +{ +	long n=0; +	int neg=0; +	while (isspace(*s)) s++; +	switch (*s) { +	case '-': neg=1; +	case '+': s++; +	} +	while (isdigit(*s)) +		n = 10*n + *s++ - '0'; +	return neg ? -n : n; +} diff --git a/src/stdlib/atoll.c b/src/stdlib/atoll.c new file mode 100644 index 00000000..0e03e0a1 --- /dev/null +++ b/src/stdlib/atoll.c @@ -0,0 +1,16 @@ +#include <stdlib.h> +#include <ctype.h> + +long long atoll(const char *s) +{ +	long long n=0; +	int neg=0; +	while (isspace(*s)) s++; +	switch (*s) { +	case '-': neg=1; +	case '+': s++; +	} +	while (isdigit(*s)) +		n = 10*n + *s++ - '0'; +	return neg ? -n : n; +} diff --git a/src/stdlib/bsearch.c b/src/stdlib/bsearch.c new file mode 100644 index 00000000..61d89367 --- /dev/null +++ b/src/stdlib/bsearch.c @@ -0,0 +1,20 @@ +#include <stdlib.h> + +void *bsearch(const void *key, const void *base, size_t nel, size_t width, int (*cmp)(const void *, const void *)) +{ +	void *try; +	int sign; +	while (nel > 0) { +		try = (char *)base + width*(nel/2); +		sign = cmp(key, try); +		if (!sign) return try; +		else if (nel == 1) break; +		else if (sign < 0) +			nel /= 2; +		else { +			base = try; +			nel -= nel/2; +		} +	} +	return NULL; +} diff --git a/src/stdlib/div.c b/src/stdlib/div.c new file mode 100644 index 00000000..e42c1f14 --- /dev/null +++ b/src/stdlib/div.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +div_t div(int num, int den) +{ +	return (div_t){ num/den, num%den }; +} diff --git a/src/stdlib/frexp.c b/src/stdlib/frexp.c new file mode 100644 index 00000000..ae82cb30 --- /dev/null +++ b/src/stdlib/frexp.c @@ -0,0 +1,23 @@ +#include <math.h> +#include <inttypes.h> + +double frexp(double x, int *e) +{ +	union { double d; uint64_t i; } y = { x }; +	int ee = y.i>>52 & 0x7ff; + +	if (!ee) { +		if (x) { +			x = frexp(x*0x1p64, e); +			*e -= 64; +		} else *e = 0; +		return x; +	} else if (ee == 0x7ff) { +		return x; +	} + +	*e = ee - 0x3fe; +	y.i &= 0x800fffffffffffffull; +	y.i |= 0x3fe0000000000000ull; +	return y.d; +} diff --git a/src/stdlib/frexpf.c b/src/stdlib/frexpf.c new file mode 100644 index 00000000..ee5e910a --- /dev/null +++ b/src/stdlib/frexpf.c @@ -0,0 +1,23 @@ +#include <math.h> +#include <inttypes.h> + +float frexpf(float x, int *e) +{ +	union { float f; uint32_t i; } y = { x }; +	int ee = y.i>>23 & 0xff; + +	if (!ee) { +		if (x) { +			x = frexpf(x*0x1p64, e); +			*e -= 64; +		} else *e = 0; +		return x; +	} else if (ee == 0xff) { +		return x; +	} + +	*e = ee - 0x7e; +	y.i &= 0x807ffffful; +	y.i |= 0x3f000000ul; +	return y.f; +} diff --git a/src/stdlib/frexpl.c b/src/stdlib/frexpl.c new file mode 100644 index 00000000..ecfff007 --- /dev/null +++ b/src/stdlib/frexpl.c @@ -0,0 +1,25 @@ +#include <math.h> +#include <inttypes.h> + +/* This version is for 80-bit little endian long double */ + +long double frexpl(long double x, int *e) +{ +	union { long double ld; uint16_t hw[5]; } y = { x }; +	int ee = y.hw[4]&0x7fff; + +	if (!ee) { +		if (x) { +			x = frexpl(x*0x1p64, e); +			*e -= 64; +		} else *e = 0; +		return x; +	} else if (ee == 0x7fff) { +		return x; +	} + +	*e = ee - 0x3ffe; +	y.hw[4] &= 0x8000; +	y.hw[4] |= 0x3ffe; +	return y.ld; +} diff --git a/src/stdlib/imaxabs.c b/src/stdlib/imaxabs.c new file mode 100644 index 00000000..81001819 --- /dev/null +++ b/src/stdlib/imaxabs.c @@ -0,0 +1,6 @@ +#include <inttypes.h> + +intmax_t imaxabs(intmax_t a) +{ +	return a>0 ? a : -a; +} diff --git a/src/stdlib/imaxdiv.c b/src/stdlib/imaxdiv.c new file mode 100644 index 00000000..b2ce821f --- /dev/null +++ b/src/stdlib/imaxdiv.c @@ -0,0 +1,6 @@ +#include <inttypes.h> + +imaxdiv_t imaxdiv(intmax_t num, intmax_t den) +{ +	return (imaxdiv_t){ num/den, num%den }; +} diff --git a/src/stdlib/labs.c b/src/stdlib/labs.c new file mode 100644 index 00000000..675b95b8 --- /dev/null +++ b/src/stdlib/labs.c @@ -0,0 +1,4 @@ +long labs(long a) +{ +	return a>0 ? a : -a; +} diff --git a/src/stdlib/ldiv.c b/src/stdlib/ldiv.c new file mode 100644 index 00000000..36eb960b --- /dev/null +++ b/src/stdlib/ldiv.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +ldiv_t ldiv(long num, long den) +{ +	return (ldiv_t){ num/den, num%den }; +} diff --git a/src/stdlib/llabs.c b/src/stdlib/llabs.c new file mode 100644 index 00000000..bec4a03d --- /dev/null +++ b/src/stdlib/llabs.c @@ -0,0 +1,4 @@ +long long llabs(long long a) +{ +	return a>0 ? a : -a; +} diff --git a/src/stdlib/lldiv.c b/src/stdlib/lldiv.c new file mode 100644 index 00000000..7aaf7a0e --- /dev/null +++ b/src/stdlib/lldiv.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +lldiv_t lldiv(long long num, long long den) +{ +	return (lldiv_t){ num/den, num%den }; +} diff --git a/src/stdlib/qsort.c b/src/stdlib/qsort.c new file mode 100644 index 00000000..f5bf3d02 --- /dev/null +++ b/src/stdlib/qsort.c @@ -0,0 +1,50 @@ +#include <stdlib.h> +#include <string.h> + +/* A simple heap sort implementation.. only in-place O(nlogn) sort I know. */ + +#define MIN(a, b) ((a)<(b) ? (a) : (b)) + +static void swap(char *a, char *b, size_t len) +{ +	char tmp[256]; +	size_t l; +	while (len) { +		l = MIN(sizeof tmp, len); +		memcpy(tmp, a, l); +		memcpy(a, b, l); +		memcpy(b, tmp, l); +		a += l; +		b += l; +		len -= l; +	} +} + +static void sift(char *base, size_t root, size_t nel, size_t width, int (*cmp)(const void *, const void *)) +{ +	size_t max; + +	while (2*root <= nel) { +		max = 2*root; +		if (max < nel && cmp(base+max*width, base+(max+1)*width) < 0) +			max++; +		if (cmp(base+root*width, base+max*width) < 0) { +			swap(base+root*width, base+max*width, width); +			root = max; +		} else break; +	} +} + +void qsort(void *_base, size_t nel, size_t width, int (*cmp)(const void *, const void *)) +{ +	char *base = _base; +	size_t i; + +	if (!nel) return; +	for (i=(nel+1)/2; i; i--) +		sift(base, i-1, nel-1, width, cmp); +	for (i=nel-1; i; i--) { +		swap(base, base+i*width, width); +		sift(base, 0, i-1, width, cmp); +	} +} diff --git a/src/stdlib/strtod.c b/src/stdlib/strtod.c new file mode 100644 index 00000000..388058fe --- /dev/null +++ b/src/stdlib/strtod.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +double strtod(const char *s, char **p) +{ +	return strtold(s, p); +} diff --git a/src/stdlib/strtof.c b/src/stdlib/strtof.c new file mode 100644 index 00000000..07b32df4 --- /dev/null +++ b/src/stdlib/strtof.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +float strtof(const char *s, char **p) +{ +	return strtold(s, p); +} diff --git a/src/stdlib/strtoimax.c b/src/stdlib/strtoimax.c new file mode 100644 index 00000000..19691091 --- /dev/null +++ b/src/stdlib/strtoimax.c @@ -0,0 +1,25 @@ +#include <inttypes.h> +#include <errno.h> +#include <ctype.h> + +intmax_t strtoimax(const char *s1, char **p, int base) +{ +	const unsigned char *s = s1; +	int sign = 0; +	uintmax_t x; + +	/* Initial whitespace */ +	for (; isspace(*s); s++); + +	/* Optional sign */ +	if (*s == '-') sign = *s++; +	else if (*s == '+') s++; + +	x = strtoumax(s, p, base); +	if (x > INTMAX_MAX) { +		if (!sign || -x != INTMAX_MIN) +			errno = ERANGE; +		return sign ? INTMAX_MIN : INTMAX_MAX; +	} +	return sign ? -x : x; +} diff --git a/src/stdlib/strtol.c b/src/stdlib/strtol.c new file mode 100644 index 00000000..ace820af --- /dev/null +++ b/src/stdlib/strtol.c @@ -0,0 +1,17 @@ +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +long strtol(const char *s, char **p, int base) +{ +	intmax_t x = strtoimax(s, p, base); +	if (x > LONG_MAX) { +		errno = ERANGE; +		return LONG_MAX; +	} else if (x < LONG_MIN) { +		errno = ERANGE; +		return LONG_MIN; +	} +	return x; +} diff --git a/src/stdlib/strtold.c b/src/stdlib/strtold.c new file mode 100644 index 00000000..54f80469 --- /dev/null +++ b/src/stdlib/strtold.c @@ -0,0 +1,93 @@ +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> + +long double strtold(const char *s1, char **p) +{ +	const unsigned char *s = s1; +	long double x = 0; +	long double frac; +	int sign = 0; +	int nonzero = 0; +	int radix = '.'; +	long e; + +	if (!p) p = (char **)&s1; + +	/* Initial whitespace */ +	for (; isspace(*s); s++); + +	/* Optional sign */ +	if (*s == '-') sign = *s++; +	else if (*s == '+') s++; + +	/* Handle infinities and NaNs. */ +	if ((s[0]|32)=='i' && (s[1]|32)=='n' && (s[2]|32)=='f') { +		*p = (char *)s + 3; +		return sign ? -1.0/0.0 : 1.0/0.0; +	} else if ((s[0]|32)=='n' && (s[1]|32)=='a' && (s[2]|32)=='n') { +		*p = (char *)s + 3; +		return 0.0/0.0; +	} + +	/* Possible hex float */ +	if (s[0]=='0' && (s[1]|32)=='x') { +		/* Mantissa must be non-degenerate */ +		if (!isxdigit(s[2]) && (s[2]!=radix || !isxdigit(s[3]))) { +			/* Decimal float 0, 'x' extraneous */ +			*p = (char *)++s; +			return 0; +		} +		/* We have a real hex float */ +		s += 2; +		for (; isxdigit(*s); s++) { +			x = 16*x + (isdigit(*s)?*s-'0':(*s|32)-'a'); +			if (*s!='0') nonzero=1; +		} +		if (*s == radix) { +			frac = 1.0/16.0; +			for (s++; isxdigit(*s); s++) { +				x += frac * (isdigit(*s)?*s-'0':(*s|32)-'a'); +				frac *= 1.0/16.0; +				if (*s!='0') nonzero=1; +			} +		} +		if ((*s|32) == 'p') { +			e = strtol(s+1, (void *)&s, 10); +			for (; e>0; e--) x *= 2.0; +			for (; e<0; e++) x *= 0.5; +		} +		if ((nonzero && !x) || !(1.0/x)) +			errno = ERANGE; +		*p = (char *)s; +		return sign ? -x : x; +	} + +	/* Mantissa must be non-degenerate */ +	if (!isdigit(s[0]) && (s[0]!=radix || !isdigit(s[1]))) { +		*p = (char *)s1; +		return 0; +	} + +	for (; isdigit(*s); s++) { +		x = 10*x + *s-'0'; +		if (*s!='0') nonzero=1; +	} +	if (*s == radix) { +		frac = 10.0; +		for (s++; isdigit(*s); s++) { +			x += (*s-'0') / frac; +			frac *= 10.0; +			if (*s!='0') nonzero=1; +		} +	} +	if ((*s|32)=='e') { +		e = strtol(++s, (void *)&s, 10); +		for (; e>0; e--) x *= 10.0; +		for (; e<0; e++) x /= 10.0; +	} +	if ((nonzero && !x) || !(1.0/x)) +		errno = ERANGE; +	*p = (char*)s; +	return sign ? -x : x; +} diff --git a/src/stdlib/strtoll.c b/src/stdlib/strtoll.c new file mode 100644 index 00000000..9ab66fd9 --- /dev/null +++ b/src/stdlib/strtoll.c @@ -0,0 +1,17 @@ +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +long long strtoll(const char *s, char **p, int base) +{ +	intmax_t x = strtoimax(s, p, base); +	if (x > LLONG_MAX) { +		errno = ERANGE; +		return LLONG_MAX; +	} else if (x < LLONG_MIN) { +		errno = ERANGE; +		return LLONG_MIN; +	} +	return x; +} diff --git a/src/stdlib/strtoul.c b/src/stdlib/strtoul.c new file mode 100644 index 00000000..951d5e8c --- /dev/null +++ b/src/stdlib/strtoul.c @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +unsigned long strtoul(const char *s, char **p, int base) +{ +	uintmax_t x = strtoumax(s, p, base); +	if (x > ULONG_MAX) { +		errno = ERANGE; +		return ULONG_MAX; +	} +	return x; +} diff --git a/src/stdlib/strtoull.c b/src/stdlib/strtoull.c new file mode 100644 index 00000000..20aa7bde --- /dev/null +++ b/src/stdlib/strtoull.c @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +unsigned long long strtoull(const char *s, char **p, int base) +{ +	uintmax_t x = strtoumax(s, p, base); +	if (x > ULLONG_MAX) { +		errno = ERANGE; +		return ULLONG_MAX; +	} +	return x; +} diff --git a/src/stdlib/strtoumax.c b/src/stdlib/strtoumax.c new file mode 100644 index 00000000..a529f6e8 --- /dev/null +++ b/src/stdlib/strtoumax.c @@ -0,0 +1,123 @@ +#include <inttypes.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <stdio.h> + +/* Lookup table for digit values. -1==255>=36 -> invalid */ +static const unsigned char digits[] = { +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, +-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, +25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, +-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, +25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +}; + +uintmax_t strtoumax(const char *s1, char **p, int base) +{ +	const unsigned char *s = s1; +	size_t x1, z1; +	uintmax_t x, z=0; +	int sign = 0; +	int shift; + +	if (!p) p = (char **)&s1; + +	/* Initial whitespace */ +	for (; isspace(*s); s++); + +	/* Optional sign */ +	if (*s == '-') sign = *s++; +	else if (*s == '+') s++; + +	/* Default base 8, 10, or 16 depending on prefix */ +	if (base == 0) { +		if (s[0] == '0') { +			if ((s[1]|32) == 'x') base = 16; +			else base = 8; +		} else { +			base = 10; +		} +	} + +	if ((unsigned)base-2 > 36-2 || digits[*s]>=base) { +		*p = (char *)s1; +		errno = EINVAL; +		return 0; +	} + +	/* Main loops. Only use big types if we have to. */ +	if (base == 10) { +		for (x1=0; isdigit(*s) && x1<=SIZE_MAX/10-10; s++) +			x1 = 10*x1 + *s-'0'; +		for (x=x1; isdigit(*s) && x<=UINTMAX_MAX/10-10; s++) +			x = 10*x + *s-'0'; +		if (isdigit(*s)) { +			if (isdigit(s[1]) || 10*x>UINTMAX_MAX-(*s-'0')) +				goto overflow; +			x = 10*x + *s-'0'; +		} +	} else if (!(base & base/2)) { +		if (base == 16) { +			if (s[0]=='0' && (s[1]|32)=='x' && digits[s[2]]<16) +				s+=2; +			shift=4; +			z1 = SIZE_MAX/16; +			z = UINTMAX_MAX/16; +		} else if (base == 8) { +			shift=3; +			z1 = SIZE_MAX/8; +			z = UINTMAX_MAX/8; +		} else if (base == 2) { +			shift=1; +			z1 = SIZE_MAX/2; +			z = UINTMAX_MAX/2; +		} else if (base == 4) { +			shift=2; +			z1 = SIZE_MAX/4; +			z = UINTMAX_MAX/4; +		} else /* if (base == 32) */ { +			shift=5; +			z1 = SIZE_MAX/32; +			z = UINTMAX_MAX/32; +		} +		for (x1=0; digits[*s]<base && x1<=z1; s++) +			x1 = (x1<<shift) + digits[*s]; +		for (x=x1; digits[*s]<base && x<=z; s++) +			x = (x<<shift) + digits[*s]; +		if (digits[*s] < base) goto overflow; +	} else { +		z1 = SIZE_MAX/base-base; +		for (x1=0; digits[*s]<base && x1<=z1; s++) +			x1 = x1*base + digits[*s]; +		if (digits[*s]<base) +			z = UINTMAX_MAX/base-base; +		for (x=x1; digits[*s]<base && x<=z; s++) +			x = x*base + digits[*s]; +		if (digits[*s] < base) { +			if (digits[s[1]]<base || x*base>UINTMAX_MAX-digits[*s]) +				goto overflow; +			x = x*base + digits[*s]; +		} +	} + +	*p = (char *)s; +	return sign ? -x : x; + +overflow: +	for (; digits[*s] < base; s++); +	*p = (char *)s; +	errno = ERANGE; +	return UINTMAX_MAX; +} diff --git a/src/stdlib/wcstoimax.c b/src/stdlib/wcstoimax.c new file mode 100644 index 00000000..861fcb54 --- /dev/null +++ b/src/stdlib/wcstoimax.c @@ -0,0 +1,24 @@ +#include <wchar.h> +#include <inttypes.h> +#include <errno.h> + +intmax_t wcstoimax(const wchar_t *s, wchar_t **p, int base) +{ +	int sign = 0; +	uintmax_t x; + +	/* Initial whitespace */ +	for (; iswspace(*s); s++); + +	/* Optional sign */ +	if (*s == '-') sign = *s++; +	else if (*s == '+') s++; + +	x = wcstoumax(s, p, base); +	if (x > INTMAX_MAX) { +		if (!sign || -x != INTMAX_MIN) +			errno = ERANGE; +		return sign ? INTMAX_MIN : INTMAX_MAX; +	} +	return sign ? -x : x; +} diff --git a/src/stdlib/wcstol.c b/src/stdlib/wcstol.c new file mode 100644 index 00000000..aad62e5b --- /dev/null +++ b/src/stdlib/wcstol.c @@ -0,0 +1,18 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +long wcstol(const wchar_t *s, wchar_t **p, int base) +{ +	intmax_t x = wcstoimax(s, p, base); +	if (x > LONG_MAX) { +		errno = ERANGE; +		return LONG_MAX; +	} else if (x < LONG_MIN) { +		errno = ERANGE; +		return LONG_MIN; +	} +	return x; +} diff --git a/src/stdlib/wcstoll.c b/src/stdlib/wcstoll.c new file mode 100644 index 00000000..ddfea74b --- /dev/null +++ b/src/stdlib/wcstoll.c @@ -0,0 +1,18 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +long long wcstoll(const wchar_t *s, wchar_t **p, int base) +{ +	intmax_t x = wcstoimax(s, p, base); +	if (x > LLONG_MAX) { +		errno = ERANGE; +		return LLONG_MAX; +	} else if (x < LLONG_MIN) { +		errno = ERANGE; +		return LLONG_MIN; +	} +	return x; +} diff --git a/src/stdlib/wcstoul.c b/src/stdlib/wcstoul.c new file mode 100644 index 00000000..e39faafe --- /dev/null +++ b/src/stdlib/wcstoul.c @@ -0,0 +1,15 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +unsigned long wcstoul(const wchar_t *s, wchar_t **p, int base) +{ +	uintmax_t x = wcstoumax(s, p, base); +	if (x > ULONG_MAX) { +		errno = ERANGE; +		return ULONG_MAX; +	} +	return x; +} diff --git a/src/stdlib/wcstoull.c b/src/stdlib/wcstoull.c new file mode 100644 index 00000000..e324dfb2 --- /dev/null +++ b/src/stdlib/wcstoull.c @@ -0,0 +1,15 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> +#include <limits.h> + +unsigned long long wcstoull(const wchar_t *s, wchar_t **p, int base) +{ +	uintmax_t x = wcstoumax(s, p, base); +	if (x > ULLONG_MAX) { +		errno = ERANGE; +		return ULLONG_MAX; +	} +	return x; +} diff --git a/src/stdlib/wcstoumax.c b/src/stdlib/wcstoumax.c new file mode 100644 index 00000000..a8f4680f --- /dev/null +++ b/src/stdlib/wcstoumax.c @@ -0,0 +1,47 @@ +#include <wchar.h> +#include <stdlib.h> +#include <inttypes.h> +#include <errno.h> + +uintmax_t wcstoumax(const wchar_t *s, wchar_t **p, int base) +{ +	/* Large enough for largest value in binary */ +	char buf[sizeof(uintmax_t)*8+2]; +	int sign = 0, skipped=0; + +	if (!p) p = (wchar_t **)&s; + +	if (base && (unsigned)base-2 > 36-2) { +		*p = (wchar_t *)s; +		errno = EINVAL; +		return 0; +	} + +	/* Initial whitespace */ +	for (; iswspace(*s); s++); + +	/* Optional sign */ +	if (*s == '-') sign = *s++; +	else if (*s == '+') s++; + +	/* Skip leading zeros but don't allow leading zeros before "0x". */ +	for (; s[0]=='0' && s[1]=='0'; s++) skipped=1; +	if (skipped && (base==0 || base==16) && (s[1]|32)=='x') { +		*p = (wchar_t *)(s+1); +		return 0; +	} + +	/* Convert to normal char string so we can use strtoumax */ +	buf[0] = sign; +	if (wcstombs(buf+!!sign, s, sizeof buf-1) < 0) return 0; +	buf[sizeof buf-1]=0; + +	/* Compute final position */ +	if (p) { +		if ((base==0 || base==16) && s[0]=='0' && (s[1]|32)=='x' && iswxdigit(s[2])) s+=2; +		for(;*s&&((unsigned)*s-'0'<base||((unsigned)*s|32)-'a'<base-10);s++); +		*p = (wchar_t *)s; +	} + +	return strtoumax(buf, 0, base); +} diff --git a/src/string/bcmp.c b/src/string/bcmp.c new file mode 100644 index 00000000..5d6a388b --- /dev/null +++ b/src/string/bcmp.c @@ -0,0 +1,7 @@ +#include <string.h> +#include <strings.h> + +int bcmp(const void *s1, const void *s2, size_t n) +{ +	return memcmp(s1, s2, n); +} diff --git a/src/string/bcopy.c b/src/string/bcopy.c new file mode 100644 index 00000000..e76272fc --- /dev/null +++ b/src/string/bcopy.c @@ -0,0 +1,7 @@ +#include <string.h> +#include <strings.h> + +void bcopy(const void *s1, void *s2, size_t n) +{ +	memmove(s2, s1, n); +} diff --git a/src/string/bzero.c b/src/string/bzero.c new file mode 100644 index 00000000..0f98b4a5 --- /dev/null +++ b/src/string/bzero.c @@ -0,0 +1,7 @@ +#include <string.h> +#include <strings.h> + +void bzero(void *s, size_t n) +{ +	memset(s, 0, n); +} diff --git a/src/string/index.c b/src/string/index.c new file mode 100644 index 00000000..dd611251 --- /dev/null +++ b/src/string/index.c @@ -0,0 +1,7 @@ +#include <string.h> +#include <strings.h> + +char *index(const char *s, int c) +{ +	return strchr(s, c); +} diff --git a/src/string/memchr.c b/src/string/memchr.c new file mode 100644 index 00000000..a0472f78 --- /dev/null +++ b/src/string/memchr.c @@ -0,0 +1,24 @@ +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> + +#define SS (sizeof(size_t)) +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +void *memchr(const void *src, int c, size_t n) +{ +	const unsigned char *s = src; +	c = (unsigned char)c; +	for (; ((uintptr_t)s & ALIGN) && n && *s != c; s++, n--); +	if (n && *s != c) { +		const size_t *w; +		size_t k = ONES * c; +		for (w = (const void *)s; n>=SS && !HASZERO(*w^k); w++, n-=SS); +		for (s = (const void *)w; n && *s != c; s++, n--); +	} +	return n ? (void *)s : 0; +} diff --git a/src/string/memcmp.c b/src/string/memcmp.c new file mode 100644 index 00000000..bdbce9f0 --- /dev/null +++ b/src/string/memcmp.c @@ -0,0 +1,8 @@ +#include <string.h> + +int memcmp(const void *vl, const void *vr, size_t n) +{ +	const unsigned char *l=vl, *r=vr; +	for (; n && *l == *r; n--, l++, r++); +	return n ? *l-*r : 0; +} diff --git a/src/string/memcpy.c b/src/string/memcpy.c new file mode 100644 index 00000000..02cb4694 --- /dev/null +++ b/src/string/memcpy.c @@ -0,0 +1,29 @@ +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +#define SS (sizeof(size_t)) +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) + +void *memcpy(void *dest, const void *src, size_t n) +{ +	unsigned char *d = dest; +	const unsigned char *s = src; + +	if (((uintptr_t)d & ALIGN) != ((uintptr_t)s & ALIGN)) +		goto misaligned; + +	for (; ((uintptr_t)d & ALIGN) && n; n--) *d++ = *s++; +	if (n) { +		size_t *wd = (void *)d; +		const size_t *ws = (const void *)s; + +		for (; n>=SS; n-=SS) *wd++ = *ws++; +		d = (void *)wd; +		s = (const void *)ws; +misaligned: +		for (; n; n--) *d++ = *s++; +	} +	return dest; +} diff --git a/src/string/memmove.c b/src/string/memmove.c new file mode 100644 index 00000000..22bb4b35 --- /dev/null +++ b/src/string/memmove.c @@ -0,0 +1,14 @@ +#include <string.h> + +void *memmove(void *dest, const void *src, size_t n) +{ +	char *d = dest; +	const char *s = src; +	if (d==s) return d; +	if ((size_t)(d-s) < n) { +		while (n--) d[n] = s[n]; +		return dest; +	} +	/* Assumes memcpy is overlap-safe when dest < src */ +	return memcpy(d, s, n); +} diff --git a/src/string/mempcpy.c b/src/string/mempcpy.c new file mode 100644 index 00000000..e54251cd --- /dev/null +++ b/src/string/mempcpy.c @@ -0,0 +1,7 @@ +#include <string.h> + +void *mempcpy(void *dest, void *src, size_t n) +{ +	memcpy(dest, src, n); +	return (char *)dest + n; +} diff --git a/src/string/memset.c b/src/string/memset.c new file mode 100644 index 00000000..20e47c45 --- /dev/null +++ b/src/string/memset.c @@ -0,0 +1,21 @@ +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> + +#define SS (sizeof(size_t)) +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) + +void *memset(void *dest, int c, size_t n) +{ +	unsigned char *s = dest; +	c = (unsigned char)c; +	for (; ((uintptr_t)s & ALIGN) && n; n--) *s++ = c; +	if (n) { +		size_t *w, k = ONES * c; +		for (w = (void *)s; n>=SS; n-=SS, w++) *w = k; +		for (s = (void *)w; n; n--, s++) *s = c; +	} +	return dest; +} diff --git a/src/string/rindex.c b/src/string/rindex.c new file mode 100644 index 00000000..17df2bf2 --- /dev/null +++ b/src/string/rindex.c @@ -0,0 +1,7 @@ +#include <string.h> +#include <strings.h> + +char *rindex(const char *s, int c) +{ +	return strrchr(s, c); +} diff --git a/src/string/stpcpy.c b/src/string/stpcpy.c new file mode 100644 index 00000000..10ca4933 --- /dev/null +++ b/src/string/stpcpy.c @@ -0,0 +1,29 @@ +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> +#include "libc.h" + +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +char *__stpcpy(char *d, const char *s) +{ +	size_t *wd; +	const size_t *ws; + +	if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) { +		for (; (*d=*s) && ((uintptr_t)s & ALIGN); s++, d++); +		if (!*s) return d; +		wd=(void *)d; ws=(const void *)s; +		for (; !HASZERO(*ws); *wd++ = *ws++); +		d=(void *)wd; s=(const void *)ws; +	} +	for (; (*d=*s); s++, d++); + +	return d; +} + +weak_alias(__stpcpy, stpcpy); diff --git a/src/string/stpncpy.c b/src/string/stpncpy.c new file mode 100644 index 00000000..a877f5fe --- /dev/null +++ b/src/string/stpncpy.c @@ -0,0 +1,32 @@ +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> +#include "libc.h" + +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +char *__stpncpy(char *d, const char *s, size_t n) +{ +	size_t *wd; +	const size_t *ws; + +	if (((uintptr_t)s & ALIGN) != ((uintptr_t)d & ALIGN)) { +		for (; ((uintptr_t)s & ALIGN) && n && (*d=*s); n--, s++, d++); +		if (!n || !*s) goto tail; +		wd=(void *)d; ws=(const void *)s; +		for (; n>=sizeof(size_t) && !HASZERO(*ws); +		       n-=sizeof(size_t), ws++, *wd++) *wd = *ws; +		d=(void *)wd; s=(const void *)ws; +	} +	for (; n && (*d=*s); n--, s++, d++); +tail: +	memset(d, 0, n); +	return d; +} + +weak_alias(__stpncpy, stpncpy); + diff --git a/src/string/strcasecmp.c b/src/string/strcasecmp.c new file mode 100644 index 00000000..dd879052 --- /dev/null +++ b/src/string/strcasecmp.c @@ -0,0 +1,9 @@ +#include <strings.h> +#include <ctype.h> + +int strcasecmp(const char *_l, const char *_r) +{ +	const unsigned char *l=_l, *r=_r; +	for (; *l && *r && (*l == *r || tolower(*l) == tolower(*r)); l++, r++); +	return tolower(*l) - tolower(*r); +} diff --git a/src/string/strcasestr.c b/src/string/strcasestr.c new file mode 100644 index 00000000..f1cb0e84 --- /dev/null +++ b/src/string/strcasestr.c @@ -0,0 +1,7 @@ +#include <string.h> + +char *strcasestr(const char *h, const char *n) +{ +	//FIXME! +	return strstr(h, n); +} diff --git a/src/string/strcat.c b/src/string/strcat.c new file mode 100644 index 00000000..29fdb611 --- /dev/null +++ b/src/string/strcat.c @@ -0,0 +1,7 @@ +#include <string.h> + +char *strcat(char *dest, const char *src) +{ +	strcpy(dest + strlen(dest), src); +	return dest; +} diff --git a/src/string/strchr.c b/src/string/strchr.c new file mode 100644 index 00000000..e606f4fe --- /dev/null +++ b/src/string/strchr.c @@ -0,0 +1,23 @@ +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> + +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +char *strchr(const char *s, int c) +{ +	c = (char)c; +	if (!c) return (char *)s + strlen(s); +	for (; ((uintptr_t)s & ALIGN) && *s && *s != c; s++); +	if (*s && *s != c) { +		const size_t *w; +		size_t k = ONES * c; +		for (w = (const void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++); +		for (s = (const void *)w; *s && *s != c; s++); +	} +	return *s ? (char *)s : 0; +} diff --git a/src/string/strchrnul.c b/src/string/strchrnul.c new file mode 100644 index 00000000..5e0c1a1a --- /dev/null +++ b/src/string/strchrnul.c @@ -0,0 +1,7 @@ +#include <string.h> + +char *strchrnul(const char *s, int c) +{ +	char *p = strchr(s, c); +	return p ? p : (char *)s + strlen(s); +} diff --git a/src/string/strcmp.c b/src/string/strcmp.c new file mode 100644 index 00000000..91eb7404 --- /dev/null +++ b/src/string/strcmp.c @@ -0,0 +1,7 @@ +#include <string.h> + +int strcmp(const char *l, const char *r) +{ +	for (; *l==*r && *l && *r; l++, r++); +	return *(unsigned char *)l - *(unsigned char *)r; +} diff --git a/src/string/strcpy.c b/src/string/strcpy.c new file mode 100644 index 00000000..7675e9ce --- /dev/null +++ b/src/string/strcpy.c @@ -0,0 +1,16 @@ +#include <string.h> + +char *__stpcpy(char *, const char *); + +char *strcpy(char *dest, const char *src) +{ +#if 1 +	__stpcpy(dest, src); +	return dest; +#else +	const unsigned char *s = src; +	unsigned char *d = dest; +	while ((*d++ = *s++)); +	return dest; +#endif +} diff --git a/src/string/strcspn.c b/src/string/strcspn.c new file mode 100644 index 00000000..439b7be4 --- /dev/null +++ b/src/string/strcspn.c @@ -0,0 +1,20 @@ +#include <string.h> + +#define BITOP(a,b,op) \ + ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a)))) + +size_t strcspn(const char *_s, const char *_c) +{ +	const unsigned char *s = _s; +	const unsigned char *c = _c; +	const unsigned char *a = s; +	size_t byteset[32/sizeof(size_t)]; + +	if (!c[0]) return strlen(s); +	if (!c[1]) return (s=strchr(s, *c)) ? s-a : strlen(a); + +	memset(byteset, 0, sizeof byteset); +	for (; *c && BITOP(byteset, *c, |=); c++); +	for (; *s && !BITOP(byteset, *s, &); s++); +	return s-a; +} diff --git a/src/string/strdup.c b/src/string/strdup.c new file mode 100644 index 00000000..dd5f80c1 --- /dev/null +++ b/src/string/strdup.c @@ -0,0 +1,13 @@ +#include <stdlib.h> +#include <string.h> +#include "libc.h" + +char *__strdup(const char *s) +{ +	size_t l = strlen(s); +	char *d = malloc(l+1); +	if (!d) return NULL; +	return memcpy(d, s, l+1); +} + +weak_alias(__strdup, strdup); diff --git a/src/string/strerror_r.c b/src/string/strerror_r.c new file mode 100644 index 00000000..6fdd4ce2 --- /dev/null +++ b/src/string/strerror_r.c @@ -0,0 +1,11 @@ +#include <string.h> +#include <errno.h> + +int strerror_r(int err, char *buf, size_t buflen) +{ +	char *msg = strerror(err); +	if (strlen(msg) >= buflen) +		return ERANGE; +	strcpy(buf, msg); +	return 0; +} diff --git a/src/string/strlcat.c b/src/string/strlcat.c new file mode 100644 index 00000000..a6b94c4c --- /dev/null +++ b/src/string/strlcat.c @@ -0,0 +1,8 @@ +#include <string.h> + +size_t strlcat(char *d, const char *s, size_t n) +{ +	size_t l = strnlen(d, n); +	if (l == n) return l + strlen(s); +	return l + strlcpy(d+l, s, n-l); +} diff --git a/src/string/strlcpy.c b/src/string/strlcpy.c new file mode 100644 index 00000000..bbebf1db --- /dev/null +++ b/src/string/strlcpy.c @@ -0,0 +1,32 @@ +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> +#include "libc.h" + +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +size_t strlcpy(char *d, const char *s, size_t n) +{ +	char *d0 = d; +	size_t *wd; +	const size_t *ws; + +	if (!n--) goto finish; +	if (((uintptr_t)s & ALIGN) != ((uintptr_t)d & ALIGN)) { +		for (; ((uintptr_t)s & ALIGN) && n && (*d=*s); n--, s++, d++); +		if (n && *s) { +			wd=(void *)d; ws=(const void *)s; +			for (; n>=sizeof(size_t) && !HASZERO(*ws); +			       n-=sizeof(size_t), ws++, *wd++) *wd = *ws; +			d=(void *)wd; s=(const void *)ws; +		} +	} +	for (; n && (*d=*s); n--, s++, d++); +	*d = 0; +finish: +	return d-d0 + strlen(s); +} diff --git a/src/string/strlen.c b/src/string/strlen.c new file mode 100644 index 00000000..936fb5cf --- /dev/null +++ b/src/string/strlen.c @@ -0,0 +1,21 @@ +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> + +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +size_t strlen(const char *s) +{ +	const char *a = s; +	const size_t *w; +	for (; ((uintptr_t)s & ALIGN) && *s; s++); +	if (*s) { +		for (w = (const void *)s; !HASZERO(*w); w++); +		for (s = (const void *)w; *s; s++); +	} +	return s-a; +} diff --git a/src/string/strncasecmp.c b/src/string/strncasecmp.c new file mode 100644 index 00000000..4f9230e1 --- /dev/null +++ b/src/string/strncasecmp.c @@ -0,0 +1,10 @@ +#include <strings.h> +#include <ctype.h> + +int strncasecmp(const char *_l, const char *_r, size_t n) +{ +	const unsigned char *l=_l, *r=_r; +	if (!n--) return 0; +	for (; *l && *r && n && (*l == *r || tolower(*l) == tolower(*r)); l++, r++, n--); +	return tolower(*l) - tolower(*r); +} diff --git a/src/string/strncat.c b/src/string/strncat.c new file mode 100644 index 00000000..255b7a72 --- /dev/null +++ b/src/string/strncat.c @@ -0,0 +1,10 @@ +#include <string.h> + +char *strncat(char *d, const char *s, size_t n) +{ +	char *a = d; +	d += strlen(d); +	while (n && (*d++ = *s++)) n--; +	*d++ = 0; +	return a; +} diff --git a/src/string/strncmp.c b/src/string/strncmp.c new file mode 100644 index 00000000..52ba0323 --- /dev/null +++ b/src/string/strncmp.c @@ -0,0 +1,9 @@ +#include <string.h> + +int strncmp(const char *_l, const char *_r, size_t n) +{ +	const unsigned char *l=_l, *r=_r; +	if (!n--) return 0; +	for (; *l && *r && n && *l == *r ; l++, r++, n--); +	return *l - *r; +} diff --git a/src/string/strncpy.c b/src/string/strncpy.c new file mode 100644 index 00000000..c0cd7974 --- /dev/null +++ b/src/string/strncpy.c @@ -0,0 +1,9 @@ +#include <string.h> + +char *__stpncpy(char *, const char *, size_t); + +char *strncpy(char *d, const char *s, size_t n) +{ +	__stpncpy(d, s, n); +	return d; +} diff --git a/src/string/strndup.c b/src/string/strndup.c new file mode 100644 index 00000000..617d27ba --- /dev/null +++ b/src/string/strndup.c @@ -0,0 +1,12 @@ +#include <stdlib.h> +#include <string.h> + +char *strndup(const char *s, size_t n) +{ +	size_t l = strnlen(s, n); +	char *d = malloc(l+1); +	if (!d) return NULL; +	memcpy(d, s, l); +	d[l] = 0; +	return d; +} diff --git a/src/string/strnlen.c b/src/string/strnlen.c new file mode 100644 index 00000000..6442eb79 --- /dev/null +++ b/src/string/strnlen.c @@ -0,0 +1,7 @@ +#include <string.h> + +size_t strnlen(const char *s, size_t n) +{ +	const char *p = memchr(s, 0, n); +	return p ? p-s : n; +} diff --git a/src/string/strpbrk.c b/src/string/strpbrk.c new file mode 100644 index 00000000..55947c64 --- /dev/null +++ b/src/string/strpbrk.c @@ -0,0 +1,7 @@ +#include <string.h> + +char *strpbrk(const char *s, const char *b) +{ +	s += strcspn(s, b); +	return *s ? (char *)s : 0; +} diff --git a/src/string/strrchr.c b/src/string/strrchr.c new file mode 100644 index 00000000..31c8e0b8 --- /dev/null +++ b/src/string/strrchr.c @@ -0,0 +1,9 @@ +#include <string.h> + +char *strrchr(const char *s, int c) +{ +	const char *p; +	c = (char)c; +	for (p=s+strlen(s); p>=s && *p!=c; p--); +	return p>=s ? (char *)p : 0; +} diff --git a/src/string/strsep.c b/src/string/strsep.c new file mode 100644 index 00000000..1bfe1db1 --- /dev/null +++ b/src/string/strsep.c @@ -0,0 +1,12 @@ +#include <string.h> + +char *strsep(char **str, const char *sep) +{ +	char *s = *str, *end; +	if (!s) return NULL; +	end = s + strcspn(s, sep); +	if (*end) *end++ = 0; +	else end = 0; +	*str = end; +	return s; +} diff --git a/src/string/strsignal.c b/src/string/strsignal.c new file mode 100644 index 00000000..72fba8d1 --- /dev/null +++ b/src/string/strsignal.c @@ -0,0 +1,98 @@ +#include <signal.h> + +#if (SIGHUP == 1) && (SIGINT == 2) && (SIGQUIT == 3) && (SIGILL == 4) \ + && (SIGTRAP == 5) && (SIGABRT == 6) && (SIGBUS == 7) && (SIGFPE == 8) \ + && (SIGKILL == 9) && (SIGUSR1 == 10) && (SIGSEGV == 11) && (SIGUSR2 == 12) \ + && (SIGPIPE == 13) && (SIGALRM == 14) && (SIGTERM == 15) && (SIGSTKFLT == 16) \ + && (SIGCHLD == 17) && (SIGCONT == 18) && (SIGSTOP == 19) && (SIGTSTP == 20) \ + && (SIGTTIN == 21) && (SIGTTOU == 22) && (SIGURG == 23) && (SIGXCPU == 24) \ + && (SIGXFSZ == 25) && (SIGVTALRM == 26) && (SIGPROF == 27) && (SIGWINCH == 28) \ + && (SIGPOLL == 29) && (SIGPWR == 30) && (SIGSYS == 31) + +#define sigmap(x) x + +#else + +static const char map[] = { +	[SIGHUP]    = 1, +	[SIGINT]    = 2, +	[SIGQUIT]   = 3, +	[SIGILL]    = 4, +	[SIGTRAP]   = 5, +	[SIGABRT]   = 6, +	[SIGBUS]    = 7, +	[SIGFPE]    = 8, +	[SIGKILL]   = 9, +	[SIGUSR1]   = 10, +	[SIGSEGV]   = 11, +	[SIGUSR2]   = 12, +	[SIGPIPE]   = 13, +	[SIGALRM]   = 14, +	[SIGTERM]   = 15, +	[SIGSTKFLT] = 16, +	[SIGCHLD]   = 17, +	[SIGCONT]   = 18, +	[SIGSTOP]   = 19, +	[SIGTSTP]   = 20, +	[SIGTTIN]   = 21, +	[SIGTTOU]   = 22, +	[SIGURG]    = 23, +	[SIGXCPU]   = 24, +	[SIGXFSZ]   = 25, +	[SIGVTALRM] = 26, +	[SIGPROF]   = 27, +	[SIGWINCH]  = 28, +	[SIGPOLL]   = 29, +	[SIGPWR]    = 30, +	[SIGSYS]    = 31 +}; + +#define sigmap(x) ((unsigned)(x) > sizeof map ? 0 : map[(unsigned)(x)]) + +#endif + +static const char strings[] = +	"Unknown signal\0" +	"Hangup\0" +	"Interrupt\0" +	"Quit\0" +	"Illegal instruction\0" +	"Trace/breakpoint trap\0" +	"Aborted\0" +	"Bus error\0" +	"Floating point exception\0" +	"Killed\0" +	"User defined signal 1\0" +	"Segmentation fault\0" +	"User defined signal 2\0" +	"Broken pipe\0" +	"Alarm clock\0" +	"Terminated\0" +	"Stack fault\0" +	"Child exited\0" +	"Continued\0" +	"Stopped (signal)\0" +	"Stopped\0" +	"Stopped (tty input)\0" +	"Stopped (tty output)\0" +	"Urgent I/O condition\0" +	"CPU time limit exceeded\0" +	"File size limit exceeded\0" +	"Virtual timer expired\0" +	"Profiling timer expired\0" +	"Window changed\0" +	"I/O possible\0" +	"Power failure\0" +	"Bad system call"; + +char *strsignal(int signum) +{ +	char *s = (char *)strings; + +	signum = sigmap(signum); +	if ((unsigned)signum - 1 > 31) signum = 0; + +	for (; signum--; s++) for (; *s; s++); + +	return s; +} diff --git a/src/string/strspn.c b/src/string/strspn.c new file mode 100644 index 00000000..59b063e5 --- /dev/null +++ b/src/string/strspn.c @@ -0,0 +1,22 @@ +#include <string.h> + +#define BITOP(a,b,op) \ + ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a)))) + +size_t strspn(const char *_s, const char *_c) +{ +	const unsigned char *s = _s; +	const unsigned char *c = _c; +	const unsigned char *a = s; +	size_t byteset[32/sizeof(size_t)] = { 0 }; + +	if (!c[0]) return 0; +	if (!c[1]) { +		for (; *s == *c; s++); +		return s-a; +	} + +	for (; *c && BITOP(byteset, *c, |=); c++); +	for (; *s && BITOP(byteset, *s, &); s++); +	return s-a; +} diff --git a/src/string/strstr.c b/src/string/strstr.c new file mode 100644 index 00000000..4d536a73 --- /dev/null +++ b/src/string/strstr.c @@ -0,0 +1,166 @@ +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +static char *twobyte_strstr(const unsigned char *h, const unsigned char *n) +{ +	uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1]; +	for (h++; *h && hw != nw; hw = hw<<8 | *++h); +	return *h ? (char *)h-1 : 0; +} + +static char *threebyte_strstr(const unsigned char *h, const unsigned char *n) +{ +	uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8; +	uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8; +	for (h+=2; *h && hw != nw; hw = (hw|*++h)<<8); +	return *h ? (char *)h-2 : 0; +} + +static char *fourbyte_strstr(const unsigned char *h, const unsigned char *n) +{ +	uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3]; +	uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3]; +	for (h+=3; *h && hw != nw; hw = hw<<8 | *++h); +	return *h ? (char *)h-3 : 0; +} + +#if 0 +static char *naive_strstr(const char *h, const char *n) +{ +	size_t i; +	for (i=0; n[i] && h[i]; i++) +	for (   ; n[i] != h[i]; h++, i=0); +	return n[i] ? 0 : (char *)h; +} +#endif + +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)<(b)?(a):(b)) + +#define BITOP(a,b,op) \ + ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a)))) + +static char *twoway_strstr(const unsigned char *h, const unsigned char *n) +{ +	const unsigned char *z; +	size_t l, ip, jp, k, p, ms, p0, mem, mem0; +	size_t byteset[32 / sizeof(size_t)] = { 0 }; +	size_t shift[256]; + +	/* Computing length of needle and fill shift table */ +	for (l=0; n[l] && h[l]; l++) +		BITOP(byteset, n[l], |=), shift[n[l]] = l+1; +	if (n[l]) return 0; /* hit the end of h */ + +	/* Compute maximal suffix */ +	ip = -1; jp = 0; k = p = 1; +	while (jp+k<l) { +		if (n[ip+k] == n[jp+k]) { +			if (k == p) { +				jp += p; +				k = 1; +			} else k++; +		} else if (n[ip+k] > n[jp+k]) { +			jp += k; +			k = 1; +			p = jp - ip; +		} else { +			ip = jp++; +			k = p = 1; +		} +	} +	ms = ip; +	p0 = p; + +	/* And with the opposite comparison */ +	ip = -1; jp = 0; k = p = 1; +	while (jp+k<l) { +		if (n[ip+k] == n[jp+k]) { +			if (k == p) { +				jp += p; +				k = 1; +			} else k++; +		} else if (n[ip+k] < n[jp+k]) { +			jp += k; +			k = 1; +			p = jp - ip; +		} else { +			ip = jp++; +			k = p = 1; +		} +	} +	if (ip+1 > ms+1) ms = ip; +	else p = p0; + +	/* Periodic needle? */ +	if (memcmp(n, n+p, ms+1)) { +		mem0 = 0; +		p = MAX(ms, l-ms-1) + 1; +	} else mem0 = l-p; +	mem = 0; + +	/* Initialize incremental end-of-haystack pointer */ +	z = h; + +	/* Search loop */ +	for (;;) { +		/* Update incremental end-of-haystack pointer */ +		if (z-h < l) { +			/* Fast estimate for MIN(l,63) */ +			size_t grow = l | 63; +			const char *z2 = memchr(z, 0, grow); +			if (z2) { +				z = z2; +				if (z-h < l) return 0; +			} else z += grow; +		} + +		/* Check last byte first; advance by shift on mismatch */ +		if (BITOP(byteset, h[l-1], &)) { +			k = l-shift[h[l-1]]; +			//printf("adv by %zu (on %c) at [%s] (%zu;l=%zu)\n", k, h[l-1], h, shift[h[l-1]], l); +			if (k) { +				if (mem0 && mem && k < p) k = l-p; +				h += k; +				mem = 0; +				continue; +			} +		} else { +			h += l; +			mem = 0; +			continue; +		} + +		/* Compare right half */ +		for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++); +		if (n[k]) { +			h += k-ms; +			mem = 0; +			continue; +		} +		/* Compare left half */ +		for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--); +		if (k == mem) return (char *)h; +		h += p; +		mem = mem0; +	} +} + +char *strstr(const char *h, const char *n) +{ +	/* Return immediately on empty needle */ +	if (!n[0]) return (char *)h; + +	/* Use faster algorithms for short needles */ +	h = strchr(h, *n); +	if (!h || !n[1]) return (char *)h; +	if (!h[1]) return 0; +	if (!n[2]) return twobyte_strstr(h, n); +	if (!h[2]) return 0; +	if (!n[3]) return threebyte_strstr(h, n); +	if (!h[3]) return 0; +	if (!n[4]) return fourbyte_strstr(h, n); + +	return twoway_strstr(h, n); +} diff --git a/src/string/strtok.c b/src/string/strtok.c new file mode 100644 index 00000000..1ba221cb --- /dev/null +++ b/src/string/strtok.c @@ -0,0 +1,13 @@ +#include <string.h> + +char *strtok(char *s, const char *sep) +{ +	static char *p; +	if (!s && !(s = p)) return NULL; +	s += strspn(s, sep); +	if (!*s) return p = 0; +	p = s + strcspn(s, sep); +	if (*p) *p++ = 0; +	else p = 0; +	return s; +} diff --git a/src/string/strtok_r.c b/src/string/strtok_r.c new file mode 100644 index 00000000..c763897a --- /dev/null +++ b/src/string/strtok_r.c @@ -0,0 +1,12 @@ +#include <string.h> + +char *strtok_r(char *s, const char *sep, char **p) +{ +	if (!s && !(s = *p)) return NULL; +	s += strspn(s, sep); +	if (!*s) return *p = 0; +	*p = s + strcspn(s, sep); +	if (**p) *(*p)++ = 0; +	else *p = 0; +	return s; +} diff --git a/src/string/swab.c b/src/string/swab.c new file mode 100644 index 00000000..b2132884 --- /dev/null +++ b/src/string/swab.c @@ -0,0 +1,13 @@ +#include <unistd.h> + +void swab(const void *_src, void *_dest, ssize_t n) +{ +	const char *src = _src; +	char *dest = _dest; +	for (; n>0; n-=2) { +		dest[0] = src[1]; +		dest[1] = src[0]; +		dest += 2; +		src += 2; +	} +} diff --git a/src/string/wcscat.c b/src/string/wcscat.c new file mode 100644 index 00000000..946f16e2 --- /dev/null +++ b/src/string/wcscat.c @@ -0,0 +1,7 @@ +#include <wchar.h> + +wchar_t *wcscat(wchar_t *dest, const wchar_t *src) +{ +	wcscpy(dest + wcslen(dest), src); +	return dest; +} diff --git a/src/string/wcschr.c b/src/string/wcschr.c new file mode 100644 index 00000000..8dfc2f31 --- /dev/null +++ b/src/string/wcschr.c @@ -0,0 +1,8 @@ +#include <wchar.h> + +wchar_t *wcschr(const wchar_t *s, wchar_t c) +{ +	if (!c) return (wchar_t *)s + wcslen(s); +	for (; *s && *s != c; s++); +	return *s ? (wchar_t *)s : 0; +} diff --git a/src/string/wcscmp.c b/src/string/wcscmp.c new file mode 100644 index 00000000..26eeee70 --- /dev/null +++ b/src/string/wcscmp.c @@ -0,0 +1,7 @@ +#include <wchar.h> + +int wcscmp(const wchar_t *l, const wchar_t *r) +{ +	for (; *l==*r && *l && *r; l++, r++); +	return *l - *r; +} diff --git a/src/string/wcscpy.c b/src/string/wcscpy.c new file mode 100644 index 00000000..e0ac194f --- /dev/null +++ b/src/string/wcscpy.c @@ -0,0 +1,8 @@ +#include <wchar.h> + +wchar_t *wcscpy(wchar_t *d, const wchar_t *s) +{ +	wchar_t *a = d; +	while ((*d++ = *s++)); +	return a; +} diff --git a/src/string/wcscspn.c b/src/string/wcscspn.c new file mode 100644 index 00000000..c4e52722 --- /dev/null +++ b/src/string/wcscspn.c @@ -0,0 +1,10 @@ +#include <wchar.h> + +size_t wcscspn(const wchar_t *s, const wchar_t *c) +{ +	const wchar_t *a; +	if (!c[0]) return wcslen(s); +	if (!c[1]) return (s=wcschr(a=s, *c)) ? s-a : wcslen(a); +	for (a=s; *s && !wcschr(c, *s); s++); +	return s-a; +} diff --git a/src/string/wcslen.c b/src/string/wcslen.c new file mode 100644 index 00000000..1b7b6655 --- /dev/null +++ b/src/string/wcslen.c @@ -0,0 +1,8 @@ +#include <wchar.h> + +size_t wcslen(const wchar_t *s) +{ +	const wchar_t *a; +	for (a=s; *s; s++); +	return s-a; +} diff --git a/src/string/wcsncat.c b/src/string/wcsncat.c new file mode 100644 index 00000000..b07abe45 --- /dev/null +++ b/src/string/wcsncat.c @@ -0,0 +1,10 @@ +#include <wchar.h> + +wchar_t *wcsncat(wchar_t *d, const wchar_t *s, size_t n) +{ +	wchar_t *a = d; +	d += wcslen(d); +	while (n && (*d++ = *s++)) n--; +	*d++ = 0; +	return a; +} diff --git a/src/string/wcsncmp.c b/src/string/wcsncmp.c new file mode 100644 index 00000000..1b159f41 --- /dev/null +++ b/src/string/wcsncmp.c @@ -0,0 +1,7 @@ +#include <wchar.h> + +int wcsncmp(const wchar_t *l, const wchar_t *r, size_t n) +{ +	for (; n && *l==*r && *l && *r; l++, r++); +	return n ? *l - *r : 0; +} diff --git a/src/string/wcsncpy.c b/src/string/wcsncpy.c new file mode 100644 index 00000000..0164208d --- /dev/null +++ b/src/string/wcsncpy.c @@ -0,0 +1,9 @@ +#include <wchar.h> + +wchar_t *wcsncpy(wchar_t *d, const wchar_t *s, size_t n) +{ +	wchar_t *a = d; +	while (n && (*d++ = *s++)) n--; +	wmemset(d, 0, n); +	return a; +} diff --git a/src/string/wcspbrk.c b/src/string/wcspbrk.c new file mode 100644 index 00000000..0c72c197 --- /dev/null +++ b/src/string/wcspbrk.c @@ -0,0 +1,7 @@ +#include <wchar.h> + +wchar_t *wcspbrk(const wchar_t *s, const wchar_t *b) +{ +	s += wcscspn(s, b); +	return *s ? (wchar_t *)s : NULL; +} diff --git a/src/string/wcsrchr.c b/src/string/wcsrchr.c new file mode 100644 index 00000000..7503475a --- /dev/null +++ b/src/string/wcsrchr.c @@ -0,0 +1,8 @@ +#include <wchar.h> + +wchar_t *wcsrchr(const wchar_t *s, wint_t c) +{ +	const wchar_t *p; +	for (p=s+wcslen(s); p>=s && *p!=c; p--); +	return p>=s ? (wchar_t *)p : 0; +} diff --git a/src/string/wcsspn.c b/src/string/wcsspn.c new file mode 100644 index 00000000..4320d8f6 --- /dev/null +++ b/src/string/wcsspn.c @@ -0,0 +1,8 @@ +#include <wchar.h> + +size_t wcsspn(const wchar_t *s, const wchar_t *c) +{ +	const wchar_t *a; +	for (a=s; *s && wcschr(c, *s); s++); +	return s-a; +} diff --git a/src/string/wcsstr.c b/src/string/wcsstr.c new file mode 100644 index 00000000..966174f8 --- /dev/null +++ b/src/string/wcsstr.c @@ -0,0 +1,117 @@ +#include <wchar.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +static wchar_t *naive_wcsstr(const wchar_t *h, const wchar_t *n) +{ +	size_t i; +	for (i=0; n[i] && h[i]; i++) +	for (   ; n[i] != h[i]; h++, i=0); +	return n[i] ? 0 : (wchar_t *)h; +} + +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)<(b)?(a):(b)) + +static wchar_t *twoway_wcsstr(const wchar_t *h, const wchar_t *n) +{ +	const wchar_t *z; +	size_t l, ip, jp, k, p, ms, p0, mem, mem0; + +	/* Computing length of needle */ +	for (l=0; n[l] && h[l]; l++); +	if (n[l]) return 0; /* hit the end of h */ + +	/* Compute maximal suffix */ +	ip = -1; jp = 0; k = p = 1; +	while (jp+k<l) { +		if (n[ip+k] == n[jp+k]) { +			if (k == p) { +				jp += p; +				k = 1; +			} else k++; +		} else if (n[ip+k] > n[jp+k]) { +			jp += k; +			k = 1; +			p = jp - ip; +		} else { +			ip = jp++; +			k = p = 1; +		} +	} +	ms = ip; +	p0 = p; + +	/* And with the opposite comparison */ +	ip = -1; jp = 0; k = p = 1; +	while (jp+k<l) { +		if (n[ip+k] == n[jp+k]) { +			if (k == p) { +				jp += p; +				k = 1; +			} else k++; +		} else if (n[ip+k] < n[jp+k]) { +			jp += k; +			k = 1; +			p = jp - ip; +		} else { +			ip = jp++; +			k = p = 1; +		} +	} +	if (ip+1 > ms+1) ms = ip; +	else p = p0; + +	/* Periodic needle? */ +	if (wmemcmp(n, n+p, ms+1)) { +		mem0 = 0; +		p = MAX(ms, l-ms-1) + 1; +	} else mem0 = l-p; +	mem = 0; + +	/* Initialize incremental end-of-haystack pointer */ +	z = h; + +	/* Search loop */ +	for (;;) { +		/* Update incremental end-of-haystack pointer */ +		if (z-h < l) { +			/* Fast estimate for MIN(l,63) */ +			size_t grow = l | 63; +			const wchar_t *z2 = wmemchr(z, 0, grow); +			if (z2) { +				z = z2; +				if (z-h < l) return 0; +			} else z += grow; +		} + +		/* Compare right half */ +		for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++); +		if (n[k]) { +			h += k-ms; +			mem = 0; +			continue; +		} +		/* Compare left half */ +		for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--); +		if (k == mem) return (wchar_t *)h; +		h += p; +		mem = mem0; +	} +} + +wchar_t *wcsstr(const wchar_t *h, const wchar_t *n) +{ +	/* Return immediately on empty needle or haystack */ +	if (!n[0]) return (wchar_t *)h; +	if (!h[0]) return 0; + +	/* Use faster algorithms for short needles */ +	h = wcschr(h, *n); +	if (!h || !n[1]) return (wchar_t *)h; +	if (!h[1]) return 0; +	if (!n[2] || !n[3] || !n[4]) return naive_wcsstr(h, n); + +	return twoway_wcsstr(h, n); +} diff --git a/src/string/wcswcs.c b/src/string/wcswcs.c new file mode 100644 index 00000000..9cfe4ac4 --- /dev/null +++ b/src/string/wcswcs.c @@ -0,0 +1,6 @@ +#include <wchar.h> + +wchar_t *wcswcs(const wchar_t *haystack, const wchar_t *needle) +{ +	return wcsstr(haystack, needle); +} diff --git a/src/string/wmemchr.c b/src/string/wmemchr.c new file mode 100644 index 00000000..a3ee0e61 --- /dev/null +++ b/src/string/wmemchr.c @@ -0,0 +1,8 @@ +#include <string.h> +#include <wchar.h> + +wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t n) +{ +	for (; n && *s != c; s++); +	return n ? (wchar_t *)s : 0; +} diff --git a/src/string/wmemcmp.c b/src/string/wmemcmp.c new file mode 100644 index 00000000..6788a383 --- /dev/null +++ b/src/string/wmemcmp.c @@ -0,0 +1,8 @@ +#include <string.h> +#include <wchar.h> + +int wmemcmp(const wchar_t *l, const wchar_t *r, size_t n) +{ +	for (; n && *l==*r; n--, l++, r++); +	return n ? *l-*r : 0; +} diff --git a/src/string/wmemcpy.c b/src/string/wmemcpy.c new file mode 100644 index 00000000..330e37c7 --- /dev/null +++ b/src/string/wmemcpy.c @@ -0,0 +1,9 @@ +#include <string.h> +#include <wchar.h> + +wchar_t *wmemcpy(wchar_t *d, const wchar_t *s, size_t n) +{ +	wchar_t *a = d; +	while (n--) *d++ = *s++; +	return a; +} diff --git a/src/string/wmemmove.c b/src/string/wmemmove.c new file mode 100644 index 00000000..49608cae --- /dev/null +++ b/src/string/wmemmove.c @@ -0,0 +1,11 @@ +#include <string.h> +#include <wchar.h> + +wchar_t *wmemmove(wchar_t *d, const wchar_t *s, size_t n) +{ +	if ((size_t)(d-s) < n) { +		while (n--) d[n] = s[n]; +		return d; +	} +	return wmemcpy(d, s, n); +} diff --git a/src/string/wmemset.c b/src/string/wmemset.c new file mode 100644 index 00000000..1a2a8618 --- /dev/null +++ b/src/string/wmemset.c @@ -0,0 +1,9 @@ +#include <string.h> +#include <wchar.h> + +wchar_t *wmemset(wchar_t *d, wchar_t c, size_t n) +{ +	wchar_t *ret = d; +	while (n--) *d++ = c; +	return ret; +} diff --git a/src/stub/utmpx.c b/src/stub/utmpx.c new file mode 100644 index 00000000..32003969 --- /dev/null +++ b/src/stub/utmpx.c @@ -0,0 +1,30 @@ +#include <utmpx.h> +#include <stddef.h> + +void endutxent(void) +{ +} + +void setutxent(void) +{ +} + +struct utmpx *getutxent(void) +{ +	return NULL; +} + +struct utmpx *getutxid(const struct utmpx *ut) +{ +	return NULL; +} + +struct utmpx *getutxline(const struct utmpx *ut) +{ +	return NULL; +} + +struct utmpx *pututxline(const struct utmpx *ut) +{ +	return NULL; +} diff --git a/src/temp/mkdtemp.c b/src/temp/mkdtemp.c new file mode 100644 index 00000000..f8b067ec --- /dev/null +++ b/src/temp/mkdtemp.c @@ -0,0 +1,21 @@ +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <limits.h> +#include <errno.h> +#include <sys/stat.h> +#include "libc.h" + +char *mkdtemp(char *template) +{ +	for (;;) { +		if (!mktemp(template)) return 0; +		if (!mkdir(template, 0700)) return template; +		if (errno != EEXIST) return 0; +		/* this is safe because mktemp verified +		 * that we have a valid template string */ +		strcpy(template+strlen(template)-6, "XXXXXX"); +	} +} diff --git a/src/temp/mkstemp.c b/src/temp/mkstemp.c new file mode 100644 index 00000000..b1567191 --- /dev/null +++ b/src/temp/mkstemp.c @@ -0,0 +1,26 @@ +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <limits.h> +#include <errno.h> +#include "libc.h" + +int mkstemp(char *template) +{ +	int fd; +retry: +	if (!mktemp(template)) return -1; +	fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600); +	if (fd >= 0) return fd; +	if (errno == EEXIST) { +		/* this is safe because mktemp verified +		 * that we have a valid template string */ +		strcpy(template+strlen(template)-6, "XXXXXX"); +		goto retry; +	} +	return -1; +} + +LFS64(mkstemp); diff --git a/src/temp/mktemp.c b/src/temp/mktemp.c new file mode 100644 index 00000000..8638e087 --- /dev/null +++ b/src/temp/mktemp.c @@ -0,0 +1,29 @@ +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include "libc.h" + +char *mktemp(char *template) +{ +	static int lock; +	static int index; +	int l = strlen(template); + +	if (l < 6 || strcmp(template+l-6, "XXXXXX")) { +		errno = EINVAL; +		return NULL; +	} +	LOCK(&lock); +	for (; index < 1000000; index++) { +		snprintf(template+l-6, 6, "%06d", index); +		if (access(template, F_OK) != 0) { +			UNLOCK(&lock); +			return template; +		} +	} +	UNLOCK(&lock); +	return NULL;	 +} diff --git a/src/termios/cfgetospeed.c b/src/termios/cfgetospeed.c new file mode 100644 index 00000000..0ebc198c --- /dev/null +++ b/src/termios/cfgetospeed.c @@ -0,0 +1,12 @@ +#include <termios.h> +#include <sys/ioctl.h> + +speed_t cfgetospeed(const struct termios *tio) +{ +	return tio->c_cflag & CBAUD; +} + +speed_t cfgetispeed(const struct termios *tio) +{ +	return cfgetospeed(tio); +} diff --git a/src/termios/cfsetospeed.c b/src/termios/cfsetospeed.c new file mode 100644 index 00000000..80c790f1 --- /dev/null +++ b/src/termios/cfsetospeed.c @@ -0,0 +1,22 @@ +#include <termios.h> +#include <sys/ioctl.h> +#include <errno.h> +#include "libc.h" + +int cfsetospeed(struct termios *tio, speed_t speed) +{ +	if (speed & ~CBAUD) { +		errno = EINVAL; +		return -1; +	} +	tio->c_cflag &= ~CBAUD; +	tio->c_cflag |= speed; +	return 0; +} + +int cfsetispeed(struct termios *tio, speed_t speed) +{ +	return speed ? cfsetospeed(tio, speed) : 0; +} + +weak_alias(cfsetospeed, cfsetspeed); diff --git a/src/termios/tcdrain.c b/src/termios/tcdrain.c new file mode 100644 index 00000000..c51dd401 --- /dev/null +++ b/src/termios/tcdrain.c @@ -0,0 +1,7 @@ +#include <termios.h> +#include <sys/ioctl.h> + +int tcdrain(int fd) +{ +	return ioctl(fd, TCSBRK, 1); +} diff --git a/src/termios/tcflow.c b/src/termios/tcflow.c new file mode 100644 index 00000000..c7fc3fe2 --- /dev/null +++ b/src/termios/tcflow.c @@ -0,0 +1,7 @@ +#include <termios.h> +#include <sys/ioctl.h> + +int tcflow(int fd, int action) +{ +	return ioctl(fd, TCXONC, action); +} diff --git a/src/termios/tcflush.c b/src/termios/tcflush.c new file mode 100644 index 00000000..50222669 --- /dev/null +++ b/src/termios/tcflush.c @@ -0,0 +1,7 @@ +#include <termios.h> +#include <sys/ioctl.h> + +int tcflush(int fd, int queue) +{ +	return ioctl(fd, TCFLSH, queue); +} diff --git a/src/termios/tcgetattr.c b/src/termios/tcgetattr.c new file mode 100644 index 00000000..d9ce786e --- /dev/null +++ b/src/termios/tcgetattr.c @@ -0,0 +1,10 @@ +#include <termios.h> +#include <sys/ioctl.h> +#include <string.h> + +int tcgetattr(int fd, struct termios *tio) +{ +	if (ioctl(fd, TCGETS, tio)) +		return -1; +	return 0; +} diff --git a/src/termios/tcgetsid.c b/src/termios/tcgetsid.c new file mode 100644 index 00000000..1053fd64 --- /dev/null +++ b/src/termios/tcgetsid.c @@ -0,0 +1,10 @@ +#include <termios.h> +#include <sys/ioctl.h> + +pid_t tcgetsid(int fd) +{ +	int sid; +	if (ioctl(fd, TIOCGSID, &sid) < 0) +		return -1; +	return sid; +} diff --git a/src/termios/tcsendbreak.c b/src/termios/tcsendbreak.c new file mode 100644 index 00000000..b6df0a23 --- /dev/null +++ b/src/termios/tcsendbreak.c @@ -0,0 +1,8 @@ +#include <termios.h> +#include <sys/ioctl.h> + +int tcsendbreak(int fd, int dur) +{ +	/* nonzero duration is implementation-defined, so ignore it */ +	return ioctl(fd, TCSBRK, 0); +} diff --git a/src/termios/tcsetattr.c b/src/termios/tcsetattr.c new file mode 100644 index 00000000..e9a168f3 --- /dev/null +++ b/src/termios/tcsetattr.c @@ -0,0 +1,13 @@ +#include <termios.h> +#include <sys/ioctl.h> +#include <string.h> +#include <errno.h> + +int tcsetattr(int fd, int act, const struct termios *tio) +{ +	if (act < 0 || act > 2) { +		errno = EINVAL; +		return -1; +	} +	return ioctl(fd, TCSETS+act, tio); +} diff --git a/src/thread/__futex.c b/src/thread/__futex.c new file mode 100644 index 00000000..93352fa3 --- /dev/null +++ b/src/thread/__futex.c @@ -0,0 +1,8 @@ +#include "futex.h" +#include "syscall.h" + +int __futex(volatile int *addr, int op, int val, void *ts) +{ +	return syscall4(__NR_futex, (long)addr, op, val, (long)ts); +} + diff --git a/src/thread/__lock.c b/src/thread/__lock.c new file mode 100644 index 00000000..557c6a62 --- /dev/null +++ b/src/thread/__lock.c @@ -0,0 +1,12 @@ +#define SYSCALL_RETURN_ERRNO +#include "pthread_impl.h" + +void __lock(volatile int *l) +{ +	int spins=100000; +	/* Do not use futexes because we insist that unlocking is a simple +	 * assignment to optimize non-pathological code with no contention. */ +	while (a_xchg(l, 1)) +		if (spins) spins--, a_spin(); +		else syscall0(__NR_sched_yield); +} diff --git a/src/thread/__set_thread_area.c b/src/thread/__set_thread_area.c new file mode 100644 index 00000000..576d8b40 --- /dev/null +++ b/src/thread/__set_thread_area.c @@ -0,0 +1,9 @@ +#include "syscall.h" + +int __set_thread_area(unsigned long *desc) +{ +	if (syscall1(__NR_set_thread_area, (long)desc) < 0) +		return -1; +	__asm__ __volatile__ ( "movw %w0,%%gs" : : "r"(desc[0]*8+3) ); +	return 0; +} diff --git a/src/thread/__timedwait.c b/src/thread/__timedwait.c new file mode 100644 index 00000000..354def2c --- /dev/null +++ b/src/thread/__timedwait.c @@ -0,0 +1,21 @@ +#include <time.h> +#include <errno.h> +#include "futex.h" +#define SYSCALL_RETURN_ERRNO +#include "syscall.h" +#include <stdio.h> +int __timedwait(volatile int *addr, int val, clockid_t clk, const struct timespec *at, int priv) +{ +	struct timespec to; +	if (at) { +		clock_gettime(clk, &to); +		to.tv_sec = at->tv_sec - to.tv_sec; +		if ((to.tv_nsec = at->tv_nsec - to.tv_nsec) < 0) { +			to.tv_sec--; +			to.tv_nsec += 1000000000; +		} +		if (to.tv_sec < 0) return ETIMEDOUT; +	} +	if (priv) priv = 128; priv=0; +	return syscall4(__NR_futex, (long)addr, FUTEX_WAIT | priv, val, at ? (long)&to : 0); +} diff --git a/src/thread/__unmapself.c b/src/thread/__unmapself.c new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/thread/__unmapself.c diff --git a/src/thread/__wait.c b/src/thread/__wait.c new file mode 100644 index 00000000..8c249cd3 --- /dev/null +++ b/src/thread/__wait.c @@ -0,0 +1,16 @@ +#define SYSCALL_RETURN_ERRNO +#include "pthread_impl.h" + +void __wait(volatile int *addr, volatile int *waiters, int val, int priv) +{ +	int spins=50000; +	if (priv) priv = 128; priv=0; +	while (spins--) { +		if (*addr==val) a_spin(); +		else return; +	} +	if (waiters) a_inc(waiters); +	while (*addr==val) +		syscall4(__NR_futex, (long)addr, FUTEX_WAIT|priv, val, 0); +	if (waiters) a_dec(waiters); +} diff --git a/src/thread/__wake.c b/src/thread/__wake.c new file mode 100644 index 00000000..048ddcc0 --- /dev/null +++ b/src/thread/__wake.c @@ -0,0 +1,9 @@ +#define SYSCALL_RETURN_ERRNO +#include "pthread_impl.h" + +void __wake(volatile int *addr, int cnt, int priv) +{ +	if (priv) priv = 128; priv=0; +	if (cnt<0) cnt = INT_MAX; +	syscall3(__NR_futex, (long)addr, FUTEX_WAKE | priv, cnt); +} diff --git a/src/thread/cancellation.c b/src/thread/cancellation.c new file mode 100644 index 00000000..e35ba824 --- /dev/null +++ b/src/thread/cancellation.c @@ -0,0 +1,22 @@ +#include "pthread_impl.h" + +void __pthread_register_cancel(struct __ptcb *cb) +{ +	struct pthread *self = pthread_self(); +	cb->__next = self->cancelbuf; +	self->cancelbuf = cb; +} + +#define pthread_self __pthread_self + +void __pthread_unregister_cancel(struct __ptcb *cb) +{ +	struct pthread *self = pthread_self(); +	self->cancelbuf = self->cancelbuf->__next; +} + +void __pthread_unwind_next(struct __ptcb *cb) +{ +	if (cb->__next) longjmp((void *)cb->__next->__jb, 1); +	pthread_exit(PTHREAD_CANCELLED); +} diff --git a/src/thread/clone.c b/src/thread/clone.c new file mode 100644 index 00000000..971bfeed --- /dev/null +++ b/src/thread/clone.c @@ -0,0 +1,26 @@ +#if 0 + +int clone(int (*start)(void *), void *stack, int flags, void *arg, +	pid_t *ptid, struct user_desc *tls, pid_t *ctid) +{ +	int ret; +	__asm__( +	        "andl $-16,%%ecx     \n\t" +		"xchgl %%ebx,%2      \n\t" +		"movl %%ebx,(%%ecx)  \n\t" +		"int $0x80           \n\t" +		"testl %%eax,%%eax   \n\t" +		"jnz 1f              \n\t" +		"xorl %%ebp,%%ebp    \n\t" +		"call *%%ebx         \n\t" +		"\n1:                \n\t" +		"xchgl %%ebx,%2      \n\t" +		: "=a" (ret) +		: "a" (__NR_clone), "m" (flags), "c"(stack), "d"(ptid), +		  "S" (tls), "D" (ctid) +		: "memory" +	); +	return __syscall_ret(ret); +} + +#endif diff --git a/src/thread/i386/__unmapself.s b/src/thread/i386/__unmapself.s new file mode 100644 index 00000000..5c674966 --- /dev/null +++ b/src/thread/i386/__unmapself.s @@ -0,0 +1,22 @@ +.text +.global __unmapself +.type   __unmapself,%function +__unmapself: +	call 1f +	.long -1 +	.long -1 +1:	popl %ecx +	xorl %ebx,%ebx +	xorl %edx,%edx +	movl $8,%esi +	movl $175,%eax +	int $128 +	movl $91,%eax +	movl 4(%esp),%ebx +	movl 8(%esp),%ecx +	int $128 +	xorl %ebx,%ebx +	movl $1,%eax +	int $128 + +.size __unmapself,.-__unmapself diff --git a/src/thread/i386/clone.s b/src/thread/i386/clone.s new file mode 100644 index 00000000..4f33366c --- /dev/null +++ b/src/thread/i386/clone.s @@ -0,0 +1,35 @@ +.text +.global __clone +.type   __clone,%function +__clone: +	movl	8(%esp),%ecx +	andl	$0xfffffff0, %ecx +	subl	$28,%ecx +	movl	16(%esp),%eax +	movl	%eax,12(%ecx) +	movl	4(%esp),%eax +	movl	%eax,8(%ecx) +	pushl	%ebx +	pushl	%esi +	pushl	%edi +	movl	$120,%eax +	movl	12+12(%esp),%ebx +	movl	20+12(%esp),%edx +	movl	24+12(%esp),%esi +	movl	28+12(%esp),%edi +	int	$128 +	popl	%edi +	popl	%esi +	popl	%ebx +	test	%eax,%eax +	jnz	1f +	xorl	%ebp,%ebp +	call	*%ebx +	movl	%eax, %ebx +	movl	$1, %eax +	int	$128 +1:	 +	movl %eax, 4(%esp) +	ret + +.size __clone,.-__clone diff --git a/src/thread/pthread_attr_destroy.c b/src/thread/pthread_attr_destroy.c new file mode 100644 index 00000000..b5845dd0 --- /dev/null +++ b/src/thread/pthread_attr_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_attr_destroy(pthread_attr_t *a) +{ +	return 0; +} diff --git a/src/thread/pthread_attr_getdetachstate.c b/src/thread/pthread_attr_getdetachstate.c new file mode 100644 index 00000000..9cd49536 --- /dev/null +++ b/src/thread/pthread_attr_getdetachstate.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_getdetachstate(pthread_attr_t *a, int *state) +{ +	*state = a->__detach; +	return 0; +} diff --git a/src/thread/pthread_attr_getguardsize.c b/src/thread/pthread_attr_getguardsize.c new file mode 100644 index 00000000..3f089c8c --- /dev/null +++ b/src/thread/pthread_attr_getguardsize.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_getguardsize(pthread_attr_t *a, size_t *size) +{ +	*size = a->__guardsize + DEFAULT_GUARD_SIZE; +	return 0; +} diff --git a/src/thread/pthread_attr_getscope.c b/src/thread/pthread_attr_getscope.c new file mode 100644 index 00000000..0cb224d3 --- /dev/null +++ b/src/thread/pthread_attr_getscope.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_attr_getscope(pthread_attr_t *a, int *scope) +{ +	return 0; +} diff --git a/src/thread/pthread_attr_getstacksize.c b/src/thread/pthread_attr_getstacksize.c new file mode 100644 index 00000000..40bbf186 --- /dev/null +++ b/src/thread/pthread_attr_getstacksize.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_getstacksize(pthread_attr_t *a, size_t *size) +{ +	*size = a->__stacksize + DEFAULT_STACK_SIZE; +	return 0; +} diff --git a/src/thread/pthread_attr_init.c b/src/thread/pthread_attr_init.c new file mode 100644 index 00000000..d91bf157 --- /dev/null +++ b/src/thread/pthread_attr_init.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_init(pthread_attr_t *a) +{ +	memset(a, 0, sizeof *a); +	return 0; +} diff --git a/src/thread/pthread_attr_setdetachstate.c b/src/thread/pthread_attr_setdetachstate.c new file mode 100644 index 00000000..d23b4778 --- /dev/null +++ b/src/thread/pthread_attr_setdetachstate.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_setdetachstate(pthread_attr_t *a, int state) +{ +	a->__detach = state; +	return 0; +} diff --git a/src/thread/pthread_attr_setguardsize.c b/src/thread/pthread_attr_setguardsize.c new file mode 100644 index 00000000..e0e8d3fb --- /dev/null +++ b/src/thread/pthread_attr_setguardsize.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_attr_setguardsize(pthread_attr_t *a, size_t size) +{ +	if (size > SIZE_MAX/8) return EINVAL; +	a->__guardsize = size - DEFAULT_GUARD_SIZE; +	return 0; +} diff --git a/src/thread/pthread_attr_setscope.c b/src/thread/pthread_attr_setscope.c new file mode 100644 index 00000000..a970a819 --- /dev/null +++ b/src/thread/pthread_attr_setscope.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_attr_setscope(pthread_attr_t *a, int scope) +{ +	return 0; +} diff --git a/src/thread/pthread_attr_setstacksize.c b/src/thread/pthread_attr_setstacksize.c new file mode 100644 index 00000000..58f4bb18 --- /dev/null +++ b/src/thread/pthread_attr_setstacksize.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_attr_setstacksize(pthread_attr_t *a, size_t size) +{ +	if (size-PAGE_SIZE > SIZE_MAX/4) return EINVAL; +	a->__stacksize = size - DEFAULT_STACK_SIZE; +	return 0; +} diff --git a/src/thread/pthread_barrier_destroy.c b/src/thread/pthread_barrier_destroy.c new file mode 100644 index 00000000..2898c41a --- /dev/null +++ b/src/thread/pthread_barrier_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_barrier_destroy(pthread_barrier_t *b) +{ +	return 0; +} diff --git a/src/thread/pthread_barrier_init.c b/src/thread/pthread_barrier_init.c new file mode 100644 index 00000000..2cc67ed5 --- /dev/null +++ b/src/thread/pthread_barrier_init.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_barrier_init(pthread_barrier_t *b, const pthread_barrierattr_t *a, unsigned count) +{ +	if (!count) return EINVAL; +	*b = (pthread_barrier_t){ .__limit = count-1 }; +	return 0; +} diff --git a/src/thread/pthread_barrier_wait.c b/src/thread/pthread_barrier_wait.c new file mode 100644 index 00000000..02c252ad --- /dev/null +++ b/src/thread/pthread_barrier_wait.c @@ -0,0 +1,31 @@ +#include "pthread_impl.h" + +int pthread_barrier_wait(pthread_barrier_t *b) +{ +	int cur; + +	/* Trivial case: count was set at 1 */ +	if (!b->__limit) return PTHREAD_BARRIER_SERIAL_THREAD; + +	/* Wait for anyone still suspended at previous use of barrier */ +	while ((cur=b->__left)) +		__wait(&b->__left, &b->__waiters, cur, 0); + +	/* If we are the last to reach barrier, reset it and wake others */ +	if (a_fetch_add(&b->__count, 1) == b->__limit) { +		b->__left = b->__limit; +		b->__count = 0; +		__wake(&b->__count, -1, 0); +		return PTHREAD_BARRIER_SERIAL_THREAD; +	} + +	/* Wait for our peers to reach the barrier */ +	while ((cur=b->__count)) +		__wait(&b->__count, 0, cur, 0); + +	/* If we're the last to wake up and barrier is awaiting reuse */ +	if (a_fetch_add(&b->__left, -1) == 1 && b->__waiters) +		__wake(&b->__left, -1, 0); + +	return 0; +} diff --git a/src/thread/pthread_cancel.c b/src/thread/pthread_cancel.c new file mode 100644 index 00000000..9397ffe9 --- /dev/null +++ b/src/thread/pthread_cancel.c @@ -0,0 +1,7 @@ +#define SYSCALL_RETURN_ERRNO +#include "pthread_impl.h" + +int pthread_cancel(pthread_t t) +{ +	return syscall3(__NR_tgkill, t->pid, t->tid, SIGCANCEL); +} diff --git a/src/thread/pthread_cond_broadcast.c b/src/thread/pthread_cond_broadcast.c new file mode 100644 index 00000000..7a023b85 --- /dev/null +++ b/src/thread/pthread_cond_broadcast.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_cond_broadcast(pthread_cond_t *c) +{ +	c->__block = 0; +	__wake(&c->__block, -1, 0); +	return 0; +} diff --git a/src/thread/pthread_cond_destroy.c b/src/thread/pthread_cond_destroy.c new file mode 100644 index 00000000..1d21a5a8 --- /dev/null +++ b/src/thread/pthread_cond_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_cond_destroy(pthread_cond_t *c) +{ +	return 0; +} diff --git a/src/thread/pthread_cond_init.c b/src/thread/pthread_cond_init.c new file mode 100644 index 00000000..33948606 --- /dev/null +++ b/src/thread/pthread_cond_init.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a) +{ +	memset(c, 0, sizeof *c); +	return 0; +} diff --git a/src/thread/pthread_cond_signal.c b/src/thread/pthread_cond_signal.c new file mode 100644 index 00000000..0dd9416b --- /dev/null +++ b/src/thread/pthread_cond_signal.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_cond_signal(pthread_cond_t *c) +{ +	c->__block = 0; +	__wake(&c->__block, 1, 0); +	return 0; +} diff --git a/src/thread/pthread_cond_timedwait.c b/src/thread/pthread_cond_timedwait.c new file mode 100644 index 00000000..b67dded4 --- /dev/null +++ b/src/thread/pthread_cond_timedwait.c @@ -0,0 +1,26 @@ +#include "pthread_impl.h" + +static void relock(void *m) +{ +	pthread_mutex_lock(m); +} + +int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, const struct timespec *ts) +{ +	int r, e=0; +	CANCELPT(0); + +	pthread_cleanup_push(relock, m); +	c->__block = 1; +	if ((r=pthread_mutex_unlock(m))) return r; + +	CANCELPT(1); +	e = __timedwait(&c->__block, 1, CLOCK_REALTIME, ts, 0); +	CANCELPT(0); + +	pthread_cleanup_pop(0); +	if ((r=pthread_mutex_lock(m))) return r; + +	CANCELPT(0); +	return e; +} diff --git a/src/thread/pthread_cond_wait.c b/src/thread/pthread_cond_wait.c new file mode 100644 index 00000000..eb70e5f7 --- /dev/null +++ b/src/thread/pthread_cond_wait.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m) +{ +	return pthread_cond_timedwait(c, m, 0); +} diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c new file mode 100644 index 00000000..6fa484c7 --- /dev/null +++ b/src/thread/pthread_create.c @@ -0,0 +1,189 @@ +#include "pthread_impl.h" + +#define pthread_self __pthread_self + +static void docancel(struct pthread *self) +{ +	struct __ptcb cb = { .__next = self->cancelbuf }; +	__pthread_unwind_next(&cb); +} + +static void cancel_handler(int sig, siginfo_t *si, void *ctx) +{ +	struct pthread *self = pthread_self(); +	self->cancel = 1; +	if (self->canceldisable || (!self->cancelasync && !self->cancelpoint)) +		return; +	docancel(self); +} + +/* "rsyscall" is a mechanism by which a thread can synchronously force all + * other threads to perform an arbitrary syscall. It is necessary to work + * around the non-conformant implementation of setuid() et al on Linux, + * which affect only the calling thread and not the whole process. This + * implementation performs some tricks with signal delivery to work around + * the fact that it does not keep any list of threads in userspace. */ + +static struct { +	volatile int lock, hold, blocks, cnt; +	unsigned long arg[6]; +	int nr; +	int err; +} rs; + +static void rsyscall_handler(int sig, siginfo_t *si, void *ctx) +{ +	if (rs.cnt == libc.threads_minus_1) return; + +	if (syscall6(rs.nr, rs.arg[0], rs.arg[1], rs.arg[2], +		rs.arg[3], rs.arg[4], rs.arg[5]) < 0 && !rs.err) rs.err=errno; + +	a_inc(&rs.cnt); +	__wake(&rs.cnt, 1, 1); +	while(rs.hold) +		__wait(&rs.hold, 0, 1, 1); +	a_dec(&rs.cnt); +	if (!rs.cnt) __wake(&rs.cnt, 1, 1); +} + +static int rsyscall(int nr, long a, long b, long c, long d, long e, long f) +{ +	int i, ret; +	sigset_t set = { 0 }; +	struct pthread *self = pthread_self(); +	sigaddset(&set, SIGSYSCALL); + +	LOCK(&rs.lock); +	while ((i=rs.blocks)) +		__wait(&rs.blocks, 0, i, 1); + +	__libc_sigprocmask(SIG_BLOCK, &set, 0); + +	rs.nr = nr; +	rs.arg[0] = a; rs.arg[1] = b; +	rs.arg[2] = c; rs.arg[3] = d; +	rs.arg[4] = d; rs.arg[5] = f; +	rs.hold = 1; +	rs.err = 0; +	rs.cnt = 0; + +	/* Dispatch signals until all threads respond */ +	for (i=libc.threads_minus_1; i; i--) +		sigqueue(self->pid, SIGSYSCALL, (union sigval){0}); +	while ((i=rs.cnt) < libc.threads_minus_1) { +		sigqueue(self->pid, SIGSYSCALL, (union sigval){0}); +		__wait(&rs.cnt, 0, i, 1); +	} + +	/* Handle any lingering signals with no-op */ +	__libc_sigprocmask(SIG_UNBLOCK, &set, 0); + +	/* Resume other threads' signal handlers and wait for them */ +	rs.hold = 0; +	__wake(&rs.hold, -1, 0); +	while((i=rs.cnt)) __wait(&rs.cnt, 0, i, 1); + +	if (rs.err) errno = rs.err, ret = -1; +	else ret = syscall6(nr, a, b, c, d, e, f); + +	UNLOCK(&rs.lock); +	return ret; +} + +static void cancelpt(int x) +{ +	struct pthread *self = pthread_self(); +	if (self->canceldisable) return; +	self->cancelpoint = x; +	if (self->cancel) docancel(self); +} + +static void init_threads() +{ +	struct sigaction sa = { .sa_flags = SA_SIGINFO | SA_RESTART }; +	libc.lock = __lock; +	libc.cancelpt = cancelpt; +	libc.rsyscall = rsyscall; +	sa.sa_sigaction = cancel_handler; +	__libc_sigaction(SIGCANCEL, &sa, 0); +	sigaddset(&sa.sa_mask, SIGSYSCALL); +	sigaddset(&sa.sa_mask, SIGCANCEL); +	sa.sa_sigaction = rsyscall_handler; +	__libc_sigaction(SIGSYSCALL, &sa, 0); +	sigprocmask(SIG_UNBLOCK, &sa.sa_mask, 0); +} + +static int start(void *p) +{ +	struct pthread *self = p; +	pthread_exit(self->start(self->start_arg)); +	return 0; +} + +#undef pthread_self + +#define CLONE_MAGIC 0x7d0f00 +int __clone(int (*)(void *), void *, int, void *, pid_t *, void *, pid_t *); + +#define ROUND(x) (((x)+PAGE_SIZE-1)&-PAGE_SIZE) + +/* pthread_key_create.c overrides this */ +static const size_t dummy = 0; +weak_alias(dummy, __pthread_tsd_size); + +int pthread_create(pthread_t *res, const pthread_attr_t *attr, void *(*entry)(void *), void *arg) +{ +	static int init; +	int ret; +	size_t size, guard; +	struct pthread *self = pthread_self(), *new; +	unsigned char *map, *stack, *tsd; +	static const pthread_attr_t default_attr; + +	if (!self) return errno = ENOSYS; +	if (!init && ++init) init_threads(); + +	if (!attr) attr = &default_attr; +	guard = ROUND(attr->__guardsize + DEFAULT_GUARD_SIZE); +	size = guard + ROUND(attr->__stacksize + DEFAULT_STACK_SIZE); +	size += __pthread_tsd_size; +	map = mmap(0, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0); +	if (!map) return EAGAIN; +	mprotect(map, guard, PROT_NONE); + +	tsd = map + size - __pthread_tsd_size; +	new = (void *)(tsd - sizeof *new - PAGE_SIZE%sizeof *new); +	new->map_base = map; +	new->map_size = size; +	new->pid = self->pid; +	new->errno_ptr = &new->errno_val; +	new->start = entry; +	new->start_arg = arg; +	new->self = new; +	new->tsd = (void *)tsd; +	new->detached = attr->__detach; +	new->attr = *attr; +	memcpy(new->tlsdesc, self->tlsdesc, sizeof new->tlsdesc); +	new->tlsdesc[1] = (uintptr_t)new; +	stack = (void *)((uintptr_t)new-1 & ~(uintptr_t)15); + +	/* We must synchronize new thread creation with rsyscall +	 * delivery. This looks to be the least expensive way: */ +	a_inc(&rs.blocks); +	while (rs.lock) __wait(&rs.lock, 0, 1, 1); + +	a_inc(&libc.threads_minus_1); +	ret = __clone(start, stack, CLONE_MAGIC, new, +		&new->tid, &new->tlsdesc, &new->tid); + +	a_dec(&rs.blocks); +	if (rs.lock) __wake(&rs.blocks, 1, 1); + +	if (ret < 0) { +		a_dec(&libc.threads_minus_1); +		munmap(map, size); +		return -ret; +	} +	*res = new; +	return 0; +} diff --git a/src/thread/pthread_detach.c b/src/thread/pthread_detach.c new file mode 100644 index 00000000..f0eae3e8 --- /dev/null +++ b/src/thread/pthread_detach.c @@ -0,0 +1,11 @@ +#include "pthread_impl.h" + +int pthread_detach(pthread_t t) +{ +	/* Cannot detach a thread that's already exiting */ +	if (a_xchg(&t->exitlock, 1)) +		return pthread_join(t, 0); +	t->detached = 1; +	t->exitlock = 0; +	return 0; +} diff --git a/src/thread/pthread_equal.c b/src/thread/pthread_equal.c new file mode 100644 index 00000000..a55d280c --- /dev/null +++ b/src/thread/pthread_equal.c @@ -0,0 +1,6 @@ +#include <pthread.h> + +int pthread_equal(pthread_t a, pthread_t b) +{ +	return a==b; +} diff --git a/src/thread/pthread_exit.c b/src/thread/pthread_exit.c new file mode 100644 index 00000000..4966e234 --- /dev/null +++ b/src/thread/pthread_exit.c @@ -0,0 +1,25 @@ +#include "pthread_impl.h" + +#undef pthread_self + +void pthread_exit(void *result) +{ +	int i; +	struct pthread *self = pthread_self(); +	self->result = result; + +	a_dec(&libc.threads_minus_1); +	if (libc.threads_minus_1 < 0) +		exit(0); + +	LOCK(&self->exitlock); + +	if (self->tsd_used) for (i=0; i<PTHREAD_KEYS_MAX; i++) +		if (self->tsd[i] && libc.tsd_keys[i]) +			libc.tsd_keys[i](self->tsd[i]); + +	if (self->detached && self->map_base) +		__unmapself(self->map_base, self->map_size); + +	__syscall_exit(0); +} diff --git a/src/thread/pthread_getspecific.c b/src/thread/pthread_getspecific.c new file mode 100644 index 00000000..a6ca27d0 --- /dev/null +++ b/src/thread/pthread_getspecific.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +void *pthread_getspecific(pthread_key_t k) +{ +	struct pthread *self = pthread_self(); +	if (!self->tsd) return 0; +	return self->tsd[k]; +} diff --git a/src/thread/pthread_join.c b/src/thread/pthread_join.c new file mode 100644 index 00000000..5210ed48 --- /dev/null +++ b/src/thread/pthread_join.c @@ -0,0 +1,12 @@ +#include "pthread_impl.h" + +int pthread_join(pthread_t t, void **res) +{ +	int tmp = t->tid; +	CANCELPT_BEGIN; +	if (tmp) __wait(&t->tid, 0, tmp, 1); +	CANCELPT_END; +	if (res) *res = t->result; +	if (t->map_base) munmap(t->map_base, t->map_size); +	return 0; +} diff --git a/src/thread/pthread_key_create.c b/src/thread/pthread_key_create.c new file mode 100644 index 00000000..efc38046 --- /dev/null +++ b/src/thread/pthread_key_create.c @@ -0,0 +1,25 @@ +#include "pthread_impl.h" + +const size_t __pthread_tsd_size = sizeof(void *) * PTHREAD_KEYS_MAX; + +static void nodtor(void *dummy) +{ +} + +int pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) +{ +	static void (*keys[PTHREAD_KEYS_MAX])(void *); +	int i = (uintptr_t)&k / 16 % PTHREAD_KEYS_MAX; +	int j = i; + +	libc.tsd_keys = keys; +	if (!dtor) dtor = nodtor; +	/* Cheap trick - &k cannot match any destructor pointer */ +	while (a_cas_p(keys+j, 0, &k) +		&& (j=(j+1)%PTHREAD_KEYS_MAX) != i); +	if (keys[j] != (void (*)(void *))&k) +		return EAGAIN; +	keys[j] = dtor; +	*k = j; +	return 0; +} diff --git a/src/thread/pthread_key_delete.c b/src/thread/pthread_key_delete.c new file mode 100644 index 00000000..4914ebb4 --- /dev/null +++ b/src/thread/pthread_key_delete.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_key_delete(pthread_key_t k) +{ +	if (libc.tsd_keys) libc.tsd_keys[k] = 0; +	return 0; +} diff --git a/src/thread/pthread_kill.c b/src/thread/pthread_kill.c new file mode 100644 index 00000000..9d85fa5b --- /dev/null +++ b/src/thread/pthread_kill.c @@ -0,0 +1,7 @@ +#define SYSCALL_RETURN_ERRNO +#include "pthread_impl.h" + +int pthread_kill(pthread_t t, int sig) +{ +	return syscall3(__NR_tgkill, t->pid, t->tid, sig); +} diff --git a/src/thread/pthread_mutex_destroy.c b/src/thread/pthread_mutex_destroy.c new file mode 100644 index 00000000..6d49e689 --- /dev/null +++ b/src/thread/pthread_mutex_destroy.c @@ -0,0 +1,6 @@ +#include <pthread.h> + +int pthread_mutex_destroy(pthread_mutex_t *mutex) +{ +	return 0; +} diff --git a/src/thread/pthread_mutex_init.c b/src/thread/pthread_mutex_init.c new file mode 100644 index 00000000..d453543d --- /dev/null +++ b/src/thread/pthread_mutex_init.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" + +int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *a) +{ +	memset(m, 0, sizeof *m); +	if (a) { +	} +	return 0; +} diff --git a/src/thread/pthread_mutex_lock.c b/src/thread/pthread_mutex_lock.c new file mode 100644 index 00000000..6696f17a --- /dev/null +++ b/src/thread/pthread_mutex_lock.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" + +int pthread_mutex_lock(pthread_mutex_t *m) +{ +	int r; +	while ((r=pthread_mutex_trylock(m)) == EBUSY) +		__wait(&m->__lock, &m->__waiters, 1, 0); +	return r; +} diff --git a/src/thread/pthread_mutex_timedlock.c b/src/thread/pthread_mutex_timedlock.c new file mode 100644 index 00000000..5dfad94f --- /dev/null +++ b/src/thread/pthread_mutex_timedlock.c @@ -0,0 +1,15 @@ +#include "pthread_impl.h" + +int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *at) +{ +	int r, w=0; +	while ((r=pthread_mutex_trylock(m)) == EBUSY) { +		if (!w) a_inc(&m->__waiters), w++; +		if (__timedwait(&m->__lock, 1, CLOCK_REALTIME, at, 0) == ETIMEDOUT) { +			if (w) a_dec(&m->__waiters); +			return ETIMEDOUT; +		} +	} +	if (w) a_dec(&m->__waiters); +	return r; +} diff --git a/src/thread/pthread_mutex_trylock.c b/src/thread/pthread_mutex_trylock.c new file mode 100644 index 00000000..1e3817bb --- /dev/null +++ b/src/thread/pthread_mutex_trylock.c @@ -0,0 +1,28 @@ +#include "pthread_impl.h" + +int pthread_mutex_trylock(pthread_mutex_t *m) +{ +	if (m->__type == PTHREAD_MUTEX_RECURSIVE) { +		pthread_t self = pthread_self(); +		if (m->__owner == self) { +			if ((unsigned)m->__lock >= INT_MAX) return EAGAIN; +			a_inc(&m->__lock); +			return 0; +		} +		if (a_fetch_add(&m->__lock, 1)) { +			if (a_fetch_add(&m->__lock, -1)==1 && m->__waiters) +				__wake(&m->__lock, 1, 0); +			return EBUSY; +		} +		m->__owner = self; +		return 0; +	} + +	if (a_xchg(&m->__lock, 1)) +		if (m->__type == PTHREAD_MUTEX_ERRORCHECK +		 && m->__owner == pthread_self()) return EDEADLK; +		else return EBUSY; +	if (m->__type == PTHREAD_MUTEX_ERRORCHECK) +		m->__owner = pthread_self(); +	return 0; +} diff --git a/src/thread/pthread_mutex_unlock.c b/src/thread/pthread_mutex_unlock.c new file mode 100644 index 00000000..23e64ac8 --- /dev/null +++ b/src/thread/pthread_mutex_unlock.c @@ -0,0 +1,19 @@ +#include "pthread_impl.h" + +int pthread_mutex_unlock(pthread_mutex_t *m) +{ +	if (m->__type == PTHREAD_MUTEX_RECURSIVE) { +		if (a_fetch_add(&m->__lock, -1)==1 && m->__waiters) +			__wake(&m->__lock, 1, 0); +		return 0; +	} + +	if (m->__type == PTHREAD_MUTEX_ERRORCHECK +	 && m->__owner != pthread_self()) +	 	return EPERM; + +	m->__owner = 0; +	m->__lock = 0; +	if (m->__waiters) __wake(&m->__lock, 1, 0); +	return 0; +} diff --git a/src/thread/pthread_mutexattr_destroy.c b/src/thread/pthread_mutexattr_destroy.c new file mode 100644 index 00000000..9fd69747 --- /dev/null +++ b/src/thread/pthread_mutexattr_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_mutexattr_destroy(pthread_mutexattr_t *a) +{ +	return 0; +} diff --git a/src/thread/pthread_mutexattr_gettype.c b/src/thread/pthread_mutexattr_gettype.c new file mode 100644 index 00000000..9edb16c6 --- /dev/null +++ b/src/thread/pthread_mutexattr_gettype.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *a, int *type) +{ +	*type = *a & 3; +	return 0; +} diff --git a/src/thread/pthread_mutexattr_init.c b/src/thread/pthread_mutexattr_init.c new file mode 100644 index 00000000..ea631069 --- /dev/null +++ b/src/thread/pthread_mutexattr_init.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_mutexattr_init(pthread_mutexattr_t *a) +{ +	memset(a, 0, sizeof *a); +	return 0; +} diff --git a/src/thread/pthread_mutexattr_settype.c b/src/thread/pthread_mutexattr_settype.c new file mode 100644 index 00000000..4e85950e --- /dev/null +++ b/src/thread/pthread_mutexattr_settype.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_mutexattr_settype(pthread_mutexattr_t *a, int type) +{ +	if ((unsigned)type > 2) return EINVAL; +	*a = (*a & ~3) | type; +	return 0; +} diff --git a/src/thread/pthread_once.c b/src/thread/pthread_once.c new file mode 100644 index 00000000..72230054 --- /dev/null +++ b/src/thread/pthread_once.c @@ -0,0 +1,38 @@ +#include "pthread_impl.h" + +static void undo(void *control) +{ +	a_store(control, 0); +	__wake(control, 1, 0); +} + +int pthread_once(pthread_once_t *control, void (*init)(void)) +{ +	static int waiters; + +	/* Return immediately if init finished before */ +	if (*control == 2) return 0; + +	/* Try to enter initializing state. Three possibilities: +	 *  0 - we're the first or the other cancelled; run init +	 *  1 - another thread is running init; wait +	 *  2 - another thread finished running init; just return */ + +	for (;;) switch (a_swap(control, 1)) { +	case 0: +		break; +	case 1: +		__wait(control, &waiters, 1, 0); +		continue; +	case 2: +		a_store(control, 2); +		return 0; +	} + +	pthread_cleanup_push(undo, control); +	init(); +	pthread_cleanup_pop(0); + +	if (waiters) __wake(control, -1, 0); +	return 0; +} diff --git a/src/thread/pthread_rwlock_destroy.c b/src/thread/pthread_rwlock_destroy.c new file mode 100644 index 00000000..49ecfbd0 --- /dev/null +++ b/src/thread/pthread_rwlock_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_rwlock_destroy(pthread_rwlock_t *rw) +{ +	return 0; +} diff --git a/src/thread/pthread_rwlock_init.c b/src/thread/pthread_rwlock_init.c new file mode 100644 index 00000000..f87d566c --- /dev/null +++ b/src/thread/pthread_rwlock_init.c @@ -0,0 +1,9 @@ +#include "pthread_impl.h" + +int pthread_rwlock_init(pthread_rwlock_t *rw, const pthread_rwlockattr_t *a) +{ +	memset(rw, 0, sizeof *rw); +	if (a) { +	} +	return 0; +} diff --git a/src/thread/pthread_rwlock_rdlock.c b/src/thread/pthread_rwlock_rdlock.c new file mode 100644 index 00000000..6bcdb815 --- /dev/null +++ b/src/thread/pthread_rwlock_rdlock.c @@ -0,0 +1,8 @@ +#include "pthread_impl.h" + +int pthread_rwlock_rdlock(pthread_rwlock_t *rw) +{ +	while (pthread_rwlock_tryrdlock(rw)) +		__wait(&rw->__wrlock, &rw->__waiters, 1, 0); +	return 0; +} diff --git a/src/thread/pthread_rwlock_timedrdlock.c b/src/thread/pthread_rwlock_timedrdlock.c new file mode 100644 index 00000000..290327de --- /dev/null +++ b/src/thread/pthread_rwlock_timedrdlock.c @@ -0,0 +1,15 @@ +#include "pthread_impl.h" + +int pthread_rwlock_timedrdlock(pthread_rwlock_t *rw, const struct timespec *at) +{ +	int w=0; +	while (pthread_rwlock_tryrdlock(rw)) { +		if (!w) a_inc(&rw->__waiters), w++; +		if (__timedwait(&rw->__wrlock, 1, CLOCK_REALTIME, at, 0)==ETIMEDOUT) { +			if (w) a_dec(&rw->__waiters); +			return ETIMEDOUT; +		} +	} +	if (w) a_dec(&rw->__waiters); +	return 0; +} diff --git a/src/thread/pthread_rwlock_timedwrlock.c b/src/thread/pthread_rwlock_timedwrlock.c new file mode 100644 index 00000000..9f749648 --- /dev/null +++ b/src/thread/pthread_rwlock_timedwrlock.c @@ -0,0 +1,17 @@ +#include "pthread_impl.h" + +int pthread_rwlock_timedwrlock(pthread_rwlock_t *rw, const struct timespec *at) +{ +	int nr, *p, w=0; +	while (pthread_rwlock_trywrlock(rw)==EAGAIN) { +		if (!w) a_inc(&rw->__waiters), w++; +		if ((nr=rw->__readers)) p = &rw->__readers; +		else nr=1, p = &rw->__wrlock; +		if (__timedwait(p, nr, CLOCK_REALTIME, at, 0)==ETIMEDOUT) { +			if (w) a_dec(&rw->__waiters); +			return ETIMEDOUT; +		} +	} +	if (w) a_dec(&rw->__waiters); +	return 0; +} diff --git a/src/thread/pthread_rwlock_tryrdlock.c b/src/thread/pthread_rwlock_tryrdlock.c new file mode 100644 index 00000000..f59fbbdd --- /dev/null +++ b/src/thread/pthread_rwlock_tryrdlock.c @@ -0,0 +1,13 @@ +#include "pthread_impl.h" + +int pthread_rwlock_tryrdlock(pthread_rwlock_t *rw) +{ +	a_inc(&rw->__readers); +	if (rw->__wrlock) { +		a_dec(&rw->__readers); +		if (rw->__waiters && !rw->__readers) +			__wake(&rw->__readers, 1, 0); +		return EAGAIN; +	} +	return 0; +} diff --git a/src/thread/pthread_rwlock_trywrlock.c b/src/thread/pthread_rwlock_trywrlock.c new file mode 100644 index 00000000..c029b874 --- /dev/null +++ b/src/thread/pthread_rwlock_trywrlock.c @@ -0,0 +1,13 @@ +#include "pthread_impl.h" + +int pthread_rwlock_trywrlock(pthread_rwlock_t *rw) +{ +	if (a_xchg(&rw->__wrlock, 1)) +		return EAGAIN; +	if (rw->__readers) { +		a_store(&rw->__wrlock, 0); +		return EAGAIN; +	} +	rw->__owner = pthread_self()->tid; +	return 0; +} diff --git a/src/thread/pthread_rwlock_unlock.c b/src/thread/pthread_rwlock_unlock.c new file mode 100644 index 00000000..f39117e7 --- /dev/null +++ b/src/thread/pthread_rwlock_unlock.c @@ -0,0 +1,17 @@ +#include "pthread_impl.h" + +int pthread_rwlock_unlock(pthread_rwlock_t *rw) +{ +	struct pthread *self = pthread_self(); +	if (rw->__owner == self->tid) { +		rw->__owner = 0; +		a_store(&rw->__wrlock, 0); +		if (rw->__waiters) +			__wake(&rw->__wrlock, -1, 0); +		return 0; +	} +	a_dec(&rw->__readers); +	if (rw->__waiters && !rw->__readers) +		__wake(&rw->__readers, 1, 0); +	return 0; +} diff --git a/src/thread/pthread_rwlock_wrlock.c b/src/thread/pthread_rwlock_wrlock.c new file mode 100644 index 00000000..219e924a --- /dev/null +++ b/src/thread/pthread_rwlock_wrlock.c @@ -0,0 +1,13 @@ +#include "pthread_impl.h" + +int pthread_rwlock_wrlock(pthread_rwlock_t *rw) +{ +	int nr; +	while (pthread_rwlock_trywrlock(rw)==EAGAIN) { +		if ((nr=rw->__readers)) +			__wait(&rw->__readers, &rw->__waiters, nr, 0); +		else +			__wait(&rw->__wrlock, &rw->__waiters, 1, 0); +	} +	return 0; +} diff --git a/src/thread/pthread_self.c b/src/thread/pthread_self.c new file mode 100644 index 00000000..686d73d5 --- /dev/null +++ b/src/thread/pthread_self.c @@ -0,0 +1,39 @@ +#include "pthread_impl.h" + +static struct pthread main_thread; + +#undef errno +static int *errno_location() +{ +	return pthread_self()->errno_ptr; +} + +static int init_main_thread() +{ +	main_thread.tlsdesc[0] = -1; +	main_thread.tlsdesc[1] = (long)&main_thread; +	main_thread.tlsdesc[2] = SIZE_MAX/PAGE_SIZE; +	main_thread.tlsdesc[3] = 0x51; +	main_thread.self = &main_thread; +	main_thread.errno_ptr = __errno_location(); +	if (__set_thread_area(main_thread.tlsdesc) < 0) +		return -1; +	syscall1(__NR_set_tid_address, (long)&main_thread.tid); +	libc.errno_location = errno_location; +	main_thread.tid = main_thread.pid = getpid(); +	return 0; +} + +#undef pthread_self + +pthread_t pthread_self() +{ +	static int init, failed; +	if (!init) { +		if (failed) return 0; +		if (init_main_thread() < 0) failed = 1; +		if (failed) return 0; +		init = 1; +	} +	return __pthread_self(); +} diff --git a/src/thread/pthread_setcancelstate.c b/src/thread/pthread_setcancelstate.c new file mode 100644 index 00000000..23c38851 --- /dev/null +++ b/src/thread/pthread_setcancelstate.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" + +int pthread_setcancelstate(int new, int *old) +{ +	struct pthread *self = pthread_self(); +	if (old) *old = self->canceldisable; +	if ((unsigned)new > 1) return EINVAL; +	self->canceldisable = new; +	return 0; +} diff --git a/src/thread/pthread_setcanceltype.c b/src/thread/pthread_setcanceltype.c new file mode 100644 index 00000000..c73db22f --- /dev/null +++ b/src/thread/pthread_setcanceltype.c @@ -0,0 +1,10 @@ +#include "pthread_impl.h" + +int pthread_setcanceltype(int new, int *old) +{ +	struct pthread *self = pthread_self(); +	if (old) *old = self->cancelasync; +	if ((unsigned)new > 1) return EINVAL; +	self->cancelasync = new; +	return 0; +} diff --git a/src/thread/pthread_setspecific.c b/src/thread/pthread_setspecific.c new file mode 100644 index 00000000..171cef41 --- /dev/null +++ b/src/thread/pthread_setspecific.c @@ -0,0 +1,18 @@ +#include "pthread_impl.h" + +int pthread_setspecific(pthread_key_t k, const void *x) +{ +	struct pthread *self = pthread_self(); +	/* Handle the case of the main thread */ +	if (!self->tsd) { +		if (!x) return 0; +		if (!(self->tsd = calloc(sizeof(void *), PTHREAD_KEYS_MAX))) +			return ENOMEM; +	} +	/* Avoid unnecessary COW */ +	if (self->tsd[k] != x) { +		self->tsd[k] = (void *)x; +		self->tsd_used = 1; +	} +	return 0; +} diff --git a/src/thread/pthread_spin_destroy.c b/src/thread/pthread_spin_destroy.c new file mode 100644 index 00000000..e65a820c --- /dev/null +++ b/src/thread/pthread_spin_destroy.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_spin_destroy(pthread_spinlock_t *s) +{ +	return 0; +} diff --git a/src/thread/pthread_spin_init.c b/src/thread/pthread_spin_init.c new file mode 100644 index 00000000..681881cf --- /dev/null +++ b/src/thread/pthread_spin_init.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_spin_init(pthread_spinlock_t *s, int shared) +{ +	return *s = 0; +} diff --git a/src/thread/pthread_spin_lock.c b/src/thread/pthread_spin_lock.c new file mode 100644 index 00000000..59fa6ea8 --- /dev/null +++ b/src/thread/pthread_spin_lock.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_spin_lock(pthread_spinlock_t *s) +{ +	while (a_xchg(s, 1)); +	return 0; +} diff --git a/src/thread/pthread_spin_trylock.c b/src/thread/pthread_spin_trylock.c new file mode 100644 index 00000000..c12696b3 --- /dev/null +++ b/src/thread/pthread_spin_trylock.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_spin_trylock(pthread_spinlock_t *s) +{ +	return -a_xchg(s, 1) & EBUSY; +} diff --git a/src/thread/pthread_spin_unlock.c b/src/thread/pthread_spin_unlock.c new file mode 100644 index 00000000..a7eab334 --- /dev/null +++ b/src/thread/pthread_spin_unlock.c @@ -0,0 +1,6 @@ +#include "pthread_impl.h" + +int pthread_spin_unlock(pthread_spinlock_t *s) +{ +	return *s = 0; +} diff --git a/src/thread/pthread_testcancel.c b/src/thread/pthread_testcancel.c new file mode 100644 index 00000000..774b7068 --- /dev/null +++ b/src/thread/pthread_testcancel.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +void pthread_testcancel() +{ +	CANCELPT_BEGIN; +	CANCELPT_END; +} diff --git a/src/time/__asctime.c b/src/time/__asctime.c new file mode 100644 index 00000000..18535802 --- /dev/null +++ b/src/time/__asctime.c @@ -0,0 +1,27 @@ +#include <time.h> +#include <stdio.h> +#include <langinfo.h> + +const char *__langinfo(nl_item); + +char *__asctime(const struct tm *tm, char *buf) +{ +	/* FIXME: change __langinfo to __C_langinfo once we have locales */ +	if (snprintf(buf, 26, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", +		__langinfo(ABDAY_1+tm->tm_wday), +		__langinfo(ABMON_1+tm->tm_mon), +		tm->tm_mday, tm->tm_hour, +		tm->tm_min, tm->tm_sec, +		1900 + tm->tm_year) >= 26) +	{ +		/* ISO C requires us to use the above format string, +		 * even if it will not fit in the buffer. Thus asctime_r +		 * is _supposed_ to crash if the fields in tm are too large. +		 * We follow this behavior and crash "gracefully" to warn +		 * application developers that they may not be so lucky +		 * on other implementations (e.g. stack smashing..). +		 */ +		*(int*)0 = 0; +	} +	return buf; +} diff --git a/src/time/__time.h b/src/time/__time.h new file mode 100644 index 00000000..967e5180 --- /dev/null +++ b/src/time/__time.h @@ -0,0 +1,9 @@ +time_t __tm_to_time(struct tm *); +struct tm *__time_to_tm(time_t, struct tm *); +void __tzset(void); +struct tm *__dst_adjust(struct tm *tm); + +extern long __timezone; +extern int __daylight; +extern int __dst_offset; +extern char *__tzname[2]; diff --git a/src/time/__time_to_tm.c b/src/time/__time_to_tm.c new file mode 100644 index 00000000..a1ebc452 --- /dev/null +++ b/src/time/__time_to_tm.c @@ -0,0 +1,81 @@ +#include <time.h> + +/* C defines the rounding for division in a nonsensical way */ +#define Q(a,b) ((a)>0 ? (a)/(b) : -(((b)-(a)-1)/(b))) + +#define DAYS_PER_400Y (365*400 + 97) +#define DAYS_PER_100Y (365*100 + 24) +#define DAYS_PER_4Y   (365*4   + 1) + +/* FIXME: use lldiv once it's fixed to compute quot,rem together */ +struct tm *__time_to_tm(time_t t, struct tm *tm) +{ +	/* months are march-based */ +	static const int days_thru_month[] = {31,61,92,122,153,184,214,245,275,306,337,366}; +	long long bigday; +	unsigned int day, year4, year100; +	int year, year400; +	int month; +	int leap; +	int hour, min, sec; +	int wday, mday, yday; + +	/* start from 2000-03-01 (multiple of 400 years) */ +	t += -946684800 - 86400*(31+29); + +	bigday = Q(t, 86400); +	sec = t-bigday*86400; + +	hour = sec/3600; +	sec -= hour*3600; +	min = sec/60; +	sec -= min*60; + +	/* 2000-03-01 was a wednesday */ +	wday = (3+bigday)%7; +	if (wday < 0) wday += 7; + +	t = -946684800LL - 86400*(31+29) + 9000000; +	 +	year400 = Q(bigday, DAYS_PER_400Y); +	day = bigday-year400*DAYS_PER_400Y; + +	year100 = day/DAYS_PER_100Y; +	if (year100 == 4) year100--; +	day -= year100*DAYS_PER_100Y; + +	year4 = day/DAYS_PER_4Y; +	if (year4 == 25) year4--; +	day -= year4*DAYS_PER_4Y; + +	year = day/365; +	if (year == 4) year--; +	day -= year*365; + +	leap = !year && (year4 || !year100); +	yday = day + 31+28 + leap; +	if (yday >= 365+leap) yday -= 365+leap; + +	year += 4*year4 + 100*year100 + 400*year400 + 2000-1900; + +	for (month=0; days_thru_month[month] <= day; month++); +	if (month) day -= days_thru_month[month-1]; +	month += 2; +	if (month >= 12) { +		month -= 12; +		year++; +	} + +	mday = day+1; + +	tm->tm_sec = sec; +	tm->tm_min = min; +	tm->tm_hour= hour; +	tm->tm_mday= mday; +	tm->tm_mon = month; +	tm->tm_year= year; +	tm->tm_wday= wday; +	tm->tm_yday= yday; + +	return tm; +} diff --git a/src/time/__tm_to_time.c b/src/time/__tm_to_time.c new file mode 100644 index 00000000..3fa15fad --- /dev/null +++ b/src/time/__tm_to_time.c @@ -0,0 +1,33 @@ +#include <time.h> + +/* C defines the rounding for division in a nonsensical way */ +#define Q(a,b) ((a)>0 ? (a)/(b) : -(((b)-(a)-1)/(b))) + +time_t __tm_to_time(struct tm *tm) +{ +	time_t year  = tm->tm_year + -100; +	int    month = tm->tm_mon; +	int    day   = tm->tm_mday; +	int z4, z100, z400; + +	/* normalize month */ +	if (month >= 12) { +		year += month/12; +		month %= 12; +	} else if (month < 0) { +		year += month/12; +		month %= 12; +		if (month) { +			month += 12; +			year--; +		} +	} +	z4 = Q(year - (month < 2), 4); +	z100 = Q(z4, 25); +	z400 = Q(z100, 4); +	day += year*365 + z4 - z100 + z400 + +		month[(int []){0,31,59,90,120,151,181,212,243,273,304,335}]; +	return (long long)day*86400 +		+ tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec +		- -946684800; /* the dawn of time :) */ +} diff --git a/src/time/asctime.c b/src/time/asctime.c new file mode 100644 index 00000000..3102eb87 --- /dev/null +++ b/src/time/asctime.c @@ -0,0 +1,9 @@ +#include <time.h> + +char *__asctime(const struct tm *, char *); + +char *asctime(const struct tm *tm) +{ +	static char buf[26]; +	return __asctime(tm, buf); +} diff --git a/src/time/asctime_r.c b/src/time/asctime_r.c new file mode 100644 index 00000000..e51b8804 --- /dev/null +++ b/src/time/asctime_r.c @@ -0,0 +1,8 @@ +#include <time.h> + +char *__asctime(const struct tm *, char *); + +char *asctime_r(const struct tm *tm, char *buf) +{ +	return __asctime(tm, buf); +} diff --git a/src/time/clock.c b/src/time/clock.c new file mode 100644 index 00000000..2feddb36 --- /dev/null +++ b/src/time/clock.c @@ -0,0 +1,9 @@ +#include <time.h> +#include <sys/times.h> + +/* this function assumes 100 hz linux and corrects for it */ +clock_t clock() +{ +	struct tms tms; +	return (unsigned long)times(&tms)*10000; +} diff --git a/src/time/clock_gettime.c b/src/time/clock_gettime.c new file mode 100644 index 00000000..dab09d50 --- /dev/null +++ b/src/time/clock_gettime.c @@ -0,0 +1,7 @@ +#include <time.h> +#include "syscall.h" + +int clock_gettime(clockid_t clk, struct timespec *ts) +{ +	return syscall2(__NR_clock_gettime, clk, (long)ts); +} diff --git a/src/time/ctime.c b/src/time/ctime.c new file mode 100644 index 00000000..185ec554 --- /dev/null +++ b/src/time/ctime.c @@ -0,0 +1,6 @@ +#include <time.h> + +char *ctime(const time_t *t) +{ +	return asctime(localtime(t)); +} diff --git a/src/time/ctime_r.c b/src/time/ctime_r.c new file mode 100644 index 00000000..d2260a16 --- /dev/null +++ b/src/time/ctime_r.c @@ -0,0 +1,8 @@ +#include <time.h> + +char *ctime_r(const time_t *t, char *buf) +{ +	struct tm tm; +	localtime_r(t, &tm); +	return asctime_r(&tm, buf); +} diff --git a/src/time/difftime.c b/src/time/difftime.c new file mode 100644 index 00000000..80a18cc0 --- /dev/null +++ b/src/time/difftime.c @@ -0,0 +1,6 @@ +#include <time.h> + +double difftime(time_t t1, time_t t0) +{ +	return t1-t0; +} diff --git a/src/time/gettimeofday.c b/src/time/gettimeofday.c new file mode 100644 index 00000000..2b8a287d --- /dev/null +++ b/src/time/gettimeofday.c @@ -0,0 +1,9 @@ +#define SYSCALL_RETURN_ERRNO +#include <sys/time.h> +#include "syscall.h" + +int gettimeofday(struct timeval *tv, void *tz) +{ +	syscall2(__NR_gettimeofday, (long)tv, 0); +	return 0; +} diff --git a/src/time/gmtime.c b/src/time/gmtime.c new file mode 100644 index 00000000..d4d5d1f1 --- /dev/null +++ b/src/time/gmtime.c @@ -0,0 +1,11 @@ +#include <time.h> + +#include "__time.h" + +struct tm *gmtime(const time_t *t) +{ +	static struct tm tm; +	__time_to_tm(*t, &tm); +	tm.tm_isdst = 0; +	return &tm; +} diff --git a/src/time/gmtime_r.c b/src/time/gmtime_r.c new file mode 100644 index 00000000..5b565a65 --- /dev/null +++ b/src/time/gmtime_r.c @@ -0,0 +1,10 @@ +#include <time.h> + +#include "__time.h" + +struct tm *gmtime_r(const time_t *t, struct tm *result) +{ +	__time_to_tm(*t, result); +	result->tm_isdst = 0; +	return result; +} diff --git a/src/time/localtime.c b/src/time/localtime.c new file mode 100644 index 00000000..abd5e84d --- /dev/null +++ b/src/time/localtime.c @@ -0,0 +1,12 @@ +#include <time.h> + +#include "__time.h" + +struct tm *localtime(const time_t *t) +{ +	static struct tm tm; +	__tzset(); +	__time_to_tm(*t - __timezone, &tm); +	tm.tm_isdst = -1; +	return __dst_adjust(&tm); +} diff --git a/src/time/localtime_r.c b/src/time/localtime_r.c new file mode 100644 index 00000000..2bf10378 --- /dev/null +++ b/src/time/localtime_r.c @@ -0,0 +1,11 @@ +#include <time.h> + +#include "__time.h" + +struct tm *localtime_r(const time_t *t, struct tm *result) +{ +	__tzset(); +	__time_to_tm(*t - __timezone, result); +	result->tm_isdst = -1; +	return __dst_adjust(result); +} diff --git a/src/time/mktime.c b/src/time/mktime.c new file mode 100644 index 00000000..858cd50d --- /dev/null +++ b/src/time/mktime.c @@ -0,0 +1,24 @@ +#include <time.h> + +#include "__time.h" + +time_t mktime(struct tm *tm) +{ +	int isdst = tm->tm_isdst; +	time_t t, lt; + +	__tzset(); + +	tm->tm_sec += __timezone; +	if (isdst > 0) tm->tm_sec += __dst_offset; + +	t = __tm_to_time(tm); +	 +	lt = t - __timezone; +	if (isdst > 0) lt -= __dst_offset; +	__time_to_tm(lt, tm); + +	__dst_adjust(tm); +	 +	return t; +} diff --git a/src/time/nanosleep.c b/src/time/nanosleep.c new file mode 100644 index 00000000..5ac4c359 --- /dev/null +++ b/src/time/nanosleep.c @@ -0,0 +1,13 @@ +#include <unistd.h> +#include <time.h> +#include "syscall.h" +#include "libc.h" + +int nanosleep(const struct timespec *req, struct timespec *rem) +{ +	int ret; +	CANCELPT_BEGIN; +	ret = syscall2(__NR_nanosleep, (long)req, (long)rem); +	CANCELPT_END; +	return ret; +} diff --git a/src/time/strftime.c b/src/time/strftime.c new file mode 100644 index 00000000..f1b94631 --- /dev/null +++ b/src/time/strftime.c @@ -0,0 +1,172 @@ +#include <stdio.h> +#include <stdlib.h> +#include <langinfo.h> +#include <time.h> +#include "__time.h" + +// FIXME: integer overflows + +const char *__langinfo(nl_item); + +size_t strftime(char *s, size_t n, const char *f, const struct tm *tm) +{ +	nl_item item; +	int val; +	const char *fmt; +	size_t l; +	for (l=0; *f && l<n; f++) { +		if (*f == '%') { +do_fmt: +		switch (*++f) { +		case '%': +			goto literal; +		case 'E': +		case 'O': +			goto do_fmt; +		case 'a': +			item = ABDAY_1 + tm->tm_wday; +			goto nl_strcat; +		case 'A': +			item = DAY_1 + tm->tm_wday; +			goto nl_strcat; +		case 'h': +		case 'b': +			item = ABMON_1 + tm->tm_mon; +			goto nl_strcat; +		case 'B': +			item = MON_1 + tm->tm_mon; +			goto nl_strcat; +		case 'c': +			item = D_T_FMT; +			goto nl_strftime; +		case 'C': +			val = (1900+tm->tm_year) / 100; +			fmt = "%02d"; +			goto number; +		case 'd': +			val = tm->tm_mday; +			fmt = "%02d"; +			goto number; +		case 'D': +			fmt = "%m/%d/%y"; +			goto recu_strftime; +		case 'e': +			val = tm->tm_mday; +			fmt = "%2d"; +			goto number; +		case 'F': +			fmt = "%Y-%m-%d"; +			goto recu_strftime; +		case 'g': +			// FIXME +			val = 0; //week_based_year(tm)%100; +			fmt = "%02d"; +			goto number; +		case 'G': +			// FIXME +			val = 0; //week_based_year(tm); +			fmt = "%04d"; +			goto number; +		case 'H': +			val = tm->tm_hour; +			fmt = "%02d"; +			goto number; +		case 'I': +			val = tm->tm_hour; +			if (!val) val = 12; +			else if (val > 12) val -= 12; +			fmt = "%02d"; +			goto number; +		case 'j': +			val = tm->tm_yday+1; +			fmt = "%03d"; +			goto number; +		case 'm': +			val = tm->tm_mon+1; +			fmt = "%02d"; +			goto number; +		case 'M': +			val = tm->tm_min; +			fmt = "%02d"; +			goto number; +		case 'n': +			s[l++] = '\n'; +			continue; +		case 'p': +			item = tm->tm_hour >= 12 ? PM_STR : AM_STR; +			goto nl_strcat; +		case 'r': +			item = T_FMT_AMPM; +			goto nl_strftime; +		case 'R': +			fmt = "%H:%M"; +			goto recu_strftime; +		case 'S': +			val = tm->tm_sec; +			fmt = "%02d"; +			goto number; +		case 't': +			s[l++] = '\t'; +			continue; +		case 'T': +			fmt = "%H:%M:%S"; +			goto recu_strftime; +		case 'u': +			val = tm->tm_wday ? tm->tm_wday : 7; +			fmt = "%d"; +			goto number; +		case 'U': +		case 'V': +		case 'W': +			// FIXME: week number mess.. +			continue; +		case 'w': +			val = tm->tm_wday; +			fmt = "%d"; +			goto number; +		case 'x': +			item = D_FMT; +			goto nl_strftime; +		case 'X': +			item = T_FMT; +			goto nl_strftime; +		case 'y': +			val = tm->tm_year % 100; +			fmt = "%02d"; +			goto number; +		case 'Y': +			val = tm->tm_year + 1900; +			fmt = "%04d"; +			goto number; +		case 'z': +			if (tm->tm_isdst < 0) continue; +			val = -__timezone - (tm->tm_isdst ? __dst_offset : 0); +			l += snprintf(s+l, n-l, "%+.2d%.2d", val/3600, abs(val%3600)/60); +			continue; +		case 'Z': +			if (tm->tm_isdst < 0 || !__tzname[0] || !__tzname[0][0]) +				continue; +			l += snprintf(s+l, n-l, "%s", __tzname[!!tm->tm_isdst]); +			continue; +		default: +			return 0; +		} +		} +literal: +		s[l++] = *f; +		continue; +number: +		l += snprintf(s+l, n-l, fmt, val); +		continue; +nl_strcat: +		l += snprintf(s+l, n-l, "%s", __langinfo(item)); +		continue; +nl_strftime: +		fmt = __langinfo(item); +recu_strftime: +		l += strftime(s+l, n-l, fmt, tm); +	} +	if (l >= n) return 0; +	s[l] = 0; +	return l; +} diff --git a/src/time/strptime.c b/src/time/strptime.c new file mode 100644 index 00000000..db72e610 --- /dev/null +++ b/src/time/strptime.c @@ -0,0 +1,178 @@ +#include <stdio.h> +#include <stdlib.h> +#include <langinfo.h> +#include <time.h> + +const char *__langinfo(nl_item); + +char *strptime(const char *s, const char *f, struct tm *tm) +{ +	return NULL; +} + +#if 0 + +char *strptime(const char *s, const char *f, struct tm *tm) +{ +	nl_item item; +	int *dest; +	const char *fmt; +	for (; *f; f++) { +		if (isspace(*f)) goto whitespace; +		if (*f == '%') { +do_fmt: +		switch (*++f) { +		case '%': +			goto literal; +		case 'E': +		case 'O': +			goto do_fmt; +		case 'a': +			item = ABDAY_1 + tm->tm_wday; +			goto nl_strcat; +		case 'A': +			item = DAY_1 + tm->tm_wday; +			goto nl_strcat; +		case 'h': +		case 'b': +			item = ABMON_1 + tm->tm_mon; +			goto nl_strcat; +		case 'B': +			item = MON_1 + tm->tm_mon; +			goto nl_strcat; +		case 'c': +			item = D_T_FMT; +			goto nl_strftime; +		case 'C': +			val = (1900+tm->tm_year) / 100; +			fmt = "%02d"; +			goto number; +		case 'd': +			val = tm->tm_mday; +			fmt = "%02d"; +			goto number; +		case 'D': +			fmt = "%m/%d/%y"; +			goto recu_strftime; +		case 'e': +			val = tm->tm_mday; +			fmt = "%2d"; +			goto number; +		case 'F': +			fmt = "%Y-%m-%d"; +			goto recu_strftime; +		case 'g': +			// FIXME +			val = 0; //week_based_year(tm)%100; +			fmt = "%02d"; +			goto number; +		case 'G': +			// FIXME +			val = 0; //week_based_year(tm); +			fmt = "%04d"; +			goto number; +		case 'H': +			val = tm->tm_hour; +			fmt = "%02d"; +			goto number; +		case 'I': +			val = tm->tm_hour; +			if (!val) val = 12; +			else if (val > 12) val -= 12; +			fmt = "%02d"; +			goto number; +		case 'j': +			val = tm->tm_yday+1; +			fmt = "%03d"; +			goto number; +		case 'm': +			val = tm->tm_mon+1; +			fmt = "%02d"; +			goto number; +		case 'M': +			val = tm->tm_min; +			fmt = "%02d"; +			goto number; +		case 'n': +		case 't': +			goto whitespace; +		case 'p': +			item = tm->tm_hour >= 12 ? PM_STR : AM_STR; +			goto nl_strcat; +		case 'r': +			item = T_FMT_AMPM; +			goto nl_strftime; +		case 'R': +			fmt = "%H:%M"; +			goto recu_strftime; +		case 'S': +			val = tm->tm_sec; +			fmt = "%02d"; +			goto number; +		case 'T': +			fmt = "%H:%M:%S"; +			goto recu_strftime; +		case 'u': +			val = tm->tm_wday ? tm->tm_wday : 7; +			fmt = "%d"; +			goto number; +		case 'U': +		case 'V': +		case 'W': +			// FIXME: week number mess.. +			continue; +		case 'w': +			val = tm->tm_wday; +			fmt = "%d"; +			goto number; +		case 'x': +			item = D_FMT; +			goto nl_strftime; +		case 'X': +			item = T_FMT; +			goto nl_strftime; +		case 'y': +			val = tm->tm_year % 100; +			fmt = "%02d"; +			goto number; +		case 'Y': +			val = tm->tm_year + 1900; +			fmt = "%04d"; +			goto number; +		case 'z': +			if (tm->tm_isdst < 0) continue; +			val = timezone + (tm->tm_isdst) ? __dst_offset : 0; +			l += snprintf(s+l, n-l, "%+02d%02d", val/60, abs(val%60)); +			continue; +		case 'Z': +			if (tm->tm_isdst < 0 || !tzname[0] || !tzname[0][0]) +				continue; +			l += snprintf(s+l, n-l, "%s", tzname[!!tm->tm_isdst]); +			continue; +		} +		default: +			return NULL; +		} +literal: +		if (*s++ != *f) return NULL; +		continue; +whitespace: +		while(isspace(*s)) s++; +		continue; +number: +		l += snprintf(s+l, n-l, fmt, val); +		continue; +nl_strcat: +		l += snprintf(s+l, n-l, "%s", __langinfo(item)); +		continue; +nl_strftime: +		fmt = __langinfo(item); +recu_strftime: +		l += strftime(s+l, n-l, fmt, tm); +	} +	if (l >= n) return 0; +	s[l] = 0; +	return l; +} + +#endif diff --git a/src/time/time.c b/src/time/time.c new file mode 100644 index 00000000..3457dade --- /dev/null +++ b/src/time/time.c @@ -0,0 +1,12 @@ +#define SYSCALL_RETURN_ERRNO +#include <time.h> +#include <sys/time.h> +#include "syscall.h" + +time_t time(time_t *t) +{ +	struct timeval tv; +	syscall2(__NR_gettimeofday, (long)&tv, 0); +	if (t) *t = tv.tv_sec; +	return tv.tv_sec; +} diff --git a/src/time/times.c b/src/time/times.c new file mode 100644 index 00000000..e9b5a823 --- /dev/null +++ b/src/time/times.c @@ -0,0 +1,7 @@ +#include <sys/times.h> +#include "syscall.h" + +clock_t times(struct tms *tms) +{ +	return syscall1(__NR_times, (long)&tms); +} diff --git a/src/time/timezone.s b/src/time/timezone.s new file mode 100644 index 00000000..4e167b0b --- /dev/null +++ b/src/time/timezone.s @@ -0,0 +1,27 @@ +.data + +.global timezone +.global __timezone +.global daylight +.global __daylight +.global tzname +.global __tzname + +__timezone: +timezone: +	.long 0 +.size timezone,.-timezone +.size __timezone,.-__timezone + +__daylight: +daylight: +	.long 0 +.size daylight,.-daylight +.size __daylight,.-__daylight + +__tzname: +tzname: +	.long 0 +	.long 0 +.size tzname,.-tzname +.size __tzname,.-__tzname diff --git a/src/time/tzset.c b/src/time/tzset.c new file mode 100644 index 00000000..6d69957e --- /dev/null +++ b/src/time/tzset.c @@ -0,0 +1,173 @@ +#include <time.h> +#include <ctype.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include "libc.h" + +#include "__time.h" + +long  __timezone = 0; +int   __daylight = 0; +char *__tzname[2] = { 0, 0 }; +int   __dst_offset = 0; + +weak_alias(__timezone, timezone); +weak_alias(__daylight, daylight); +weak_alias(__tzname, tzname); +weak_alias(__dst_offset, dst_offset); + +static char std_name[TZNAME_MAX+1]; +static char dst_name[TZNAME_MAX+1]; + +/* all elements are zero-based */ +static struct rule { +	char month; +	char week; +	short day; +	int time; +} __dst_start, __dst_end; + +static void zname(char *d, char **s) +{ +	int i; +	for (i=0; i<TZNAME_MAX && isalpha(d[i]=**s); i++, (*s)++); +	d[i] = 0; +} + +static int hhmmss(char **s) +{ +	int ofs = strtol(*s, s, 10)*3600; +	if (ofs >= 0) { +		if (**s == ':') ofs += strtol(*s+1, s, 10)*60; +		if (**s == ':') ofs += strtol(*s+1, s, 10); +	} else { +		if (**s == ':') ofs -= strtol(*s+1, s, 10)*60; +		if (**s == ':') ofs -= strtol(*s+1, s, 10); +	} +	return ofs; +} + +static int dstrule(struct rule *rule, char **s) +{ +	if (**s != ',') return -1; +	switch (*++*s) { +	case 'J': +		rule->month = 'J'; +		rule->day = strtol(*s+1, s, 10)-1; +		break; +	case 'M': +		rule->month = strtol(*s+1, s, 10)-1; +		if (**s != '.' || rule->month < 0 || rule->month > 11) +			return -1; +		rule->week = strtol(*s+1, s, 10)-1; +		if (**s != '.' || rule->week < 0 || rule->week > 4) +			return -1; +		rule->day = strtol(*s+1, s, 10); +		if (rule->day < 0 || rule->day > 6) +			return -1; +		break; +	default: +		rule->month = 'L'; +		rule->day = strtol(*s+1, s, 10); +		break; +	} +	if (**s == '/') { +		(*s)++; +		rule->time = hhmmss(s); +	} else rule->time = 7200; +	return 0; +} + +void tzset(void) +{ +	char *z, *a; +	 +	strcpy(std_name, "GMT"); +	strcpy(dst_name, "GMT"); +	__tzname[0] = std_name; +	__tzname[1] = dst_name; +	__timezone = 0; +	__daylight = 0; +	 +	if (!(z = getenv("TZ")) || !isalpha(*z)) return; + +	zname(std_name, &z); +	__timezone = hhmmss(&z); + +	zname(dst_name, &z); +	if (dst_name[0]) __daylight=1; +	a = z; +	__dst_offset = hhmmss(&z) - __timezone; +	if (z==a) __dst_offset = -3600; + +	if (dstrule(&__dst_start, &z) || dstrule(&__dst_end, &z)) +		__daylight = 0; +} + +void __tzset(void) +{ +	static int lock, init; +	if (init) return; +	LOCK(&lock); +	if (!init) tzset(); +	init=1; +	UNLOCK(&lock); +} + +static int is_leap(int year) +{ +	year -= 100; +	return !(year&3) && ((year%100) || !(year%400)); +} + +static int cutoff_yday(struct tm *tm, struct rule *rule) +{ +	static const char days_in_month[] = {31,28,31,30,31,30,31,31,30,31,30,31}; +	static const int first_day[] = {0,31,59,90,120,151,181,212,243,273,304,335}; +	int yday, mday, leap; +	 +	switch (rule->month) { +	case 'J': +		return rule->day + (tm->tm_mon > 1 && is_leap(tm->tm_year)); +	case 'L': +		return rule->day; +	default: +		yday = first_day[rule->month]; +		leap = is_leap(tm->tm_year); +		if (rule->month > 1 && leap) yday++; +		mday = (rule->day - (yday + tm->tm_wday - tm->tm_yday) + 1400)%7 + 7*rule->week; +		if (mday >= days_in_month[rule->month] + (leap && rule->month == 1)) +			mday -= 7; +		return mday + yday; +	} +} + +struct tm *__dst_adjust(struct tm *tm) +{ +	time_t t; +	int start, end, secs; +	int after_start, before_end; + +	if (tm->tm_isdst >= 0) return tm; +	if (!__daylight) { +		tm->tm_isdst = 0; +		return tm; +	} +	 +	secs = tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec; +	start = cutoff_yday(tm, &__dst_start); +	end = cutoff_yday(tm, &__dst_end); + +	after_start = (tm->tm_yday > start || (tm->tm_yday == start && secs >= __dst_start.time)); +	before_end = (tm->tm_yday < end || (tm->tm_yday == end && secs < __dst_end.time)); + +	if ((after_start && before_end) || ((end < start) && (after_start || before_end))) { +		tm->tm_sec -= __dst_offset; +		tm->tm_isdst = 1; +		t = __tm_to_time(tm); +		return __time_to_tm(t, tm); +	} else tm->tm_isdst = 0; + +	return tm; +} diff --git a/src/time/utime.c b/src/time/utime.c new file mode 100644 index 00000000..56e9e13a --- /dev/null +++ b/src/time/utime.c @@ -0,0 +1,12 @@ +#include <utime.h> +#include "syscall.h" + +int utime(const char *path, const struct utimbuf *times) +{ +	long ktimes[2]; +	if (times) { +		ktimes[0] = times->actime; +		ktimes[1] = times->modtime; +	} +	return syscall2(__NR_utime, (long)path, times ? (long)ktimes : 0); +} diff --git a/src/unistd/_exit.c b/src/unistd/_exit.c new file mode 100644 index 00000000..d2e84c4c --- /dev/null +++ b/src/unistd/_exit.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include <stdlib.h> + +void _exit(int status) +{ +	_Exit(status); +} diff --git a/src/unistd/access.c b/src/unistd/access.c new file mode 100644 index 00000000..2c10e58c --- /dev/null +++ b/src/unistd/access.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int access(const char *filename, int amode) +{ +	return syscall2(__NR_access, (long)filename, amode); +} diff --git a/src/unistd/alarm.c b/src/unistd/alarm.c new file mode 100644 index 00000000..bba444d8 --- /dev/null +++ b/src/unistd/alarm.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +unsigned alarm(unsigned seconds) +{ +	return syscall1(__NR_alarm, seconds); +} diff --git a/src/unistd/chdir.c b/src/unistd/chdir.c new file mode 100644 index 00000000..c89bda38 --- /dev/null +++ b/src/unistd/chdir.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int chdir(const char *path) +{ +	return syscall1(__NR_chdir, (long)path); +} diff --git a/src/unistd/chown.c b/src/unistd/chown.c new file mode 100644 index 00000000..6069a2fe --- /dev/null +++ b/src/unistd/chown.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int chown(const char *path, uid_t uid, gid_t gid) +{ +	return syscall3(__NR_chown32, (long)path, uid, gid); +} diff --git a/src/unistd/close.c b/src/unistd/close.c new file mode 100644 index 00000000..97302f67 --- /dev/null +++ b/src/unistd/close.c @@ -0,0 +1,11 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +int close(int fd) +{ +	int ret = __syscall_close(fd); +	CANCELPT_BEGIN; +	CANCELPT_END; +	return ret; +} diff --git a/src/unistd/confstr.c b/src/unistd/confstr.c new file mode 100644 index 00000000..4332f726 --- /dev/null +++ b/src/unistd/confstr.c @@ -0,0 +1,17 @@ +#include <unistd.h> +#include <stdio.h> +#include <errno.h> + +size_t confstr(int name, char *buf, size_t len) +{ +	const char *s = ""; +	if (!name) { +		s = "/bin:/usr/bin"; +	} else if ((name&~4U)!=1 && name-_CS_POSIX_V6_ILP32_OFF32_CFLAGS>31U) { +		errno = EINVAL; +		return 0; +	} +	// snprintf is overkill but avoid wasting code size to implement +	// this completely useless function and its truncation semantics +	return snprintf(buf, len, "%s", s); +} diff --git a/src/unistd/ctermid.c b/src/unistd/ctermid.c new file mode 100644 index 00000000..21b44ec8 --- /dev/null +++ b/src/unistd/ctermid.c @@ -0,0 +1,23 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <limits.h> + +char *ctermid(char *s) +{ +	static char *s2; +	int fd; +	if (!s) { +		if (!s2) s2 = malloc(L_ctermid); +		s = s2; +	} +	fd = open("/dev/tty", O_WRONLY | O_NOCTTY); +	if (fd < 0) +		return strcpy(s, ""); +	if (ttyname_r(fd, s, L_ctermid)) +		strcpy(s, ""); +	close(fd); +	return s; +} diff --git a/src/unistd/dup.c b/src/unistd/dup.c new file mode 100644 index 00000000..b11cd715 --- /dev/null +++ b/src/unistd/dup.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int dup(int fd) +{ +	return syscall1(__NR_dup, fd); +} diff --git a/src/unistd/dup2.c b/src/unistd/dup2.c new file mode 100644 index 00000000..93325446 --- /dev/null +++ b/src/unistd/dup2.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int dup2(int old, int new) +{ +	return __syscall_dup2(old, new); +} diff --git a/src/unistd/faccessat.c b/src/unistd/faccessat.c new file mode 100644 index 00000000..99a93785 --- /dev/null +++ b/src/unistd/faccessat.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int faccessat(int fd, const char *filename, int amode, int flag) +{ +	return syscall4(__NR_faccessat, fd, (long)filename, amode, flag); +} diff --git a/src/unistd/fchdir.c b/src/unistd/fchdir.c new file mode 100644 index 00000000..b2acbc29 --- /dev/null +++ b/src/unistd/fchdir.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int fchdir(int fd) +{ +	return syscall1(__NR_fchdir, fd); +} diff --git a/src/unistd/fchown.c b/src/unistd/fchown.c new file mode 100644 index 00000000..990f006d --- /dev/null +++ b/src/unistd/fchown.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int fchown(int fd, uid_t uid, gid_t gid) +{ +	return syscall3(__NR_fchown32, fd, uid, gid); +} diff --git a/src/unistd/fchownat.c b/src/unistd/fchownat.c new file mode 100644 index 00000000..70626428 --- /dev/null +++ b/src/unistd/fchownat.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int fchownat(int fd, const char *path, uid_t uid, gid_t gid, int flag) +{ +	return syscall5(__NR_fchownat, fd, (long)path, uid, gid, flag); +} diff --git a/src/unistd/fdatasync.c b/src/unistd/fdatasync.c new file mode 100644 index 00000000..ef7c9a9d --- /dev/null +++ b/src/unistd/fdatasync.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int fdatasync(int fd) +{ +	return 0; +} diff --git a/src/unistd/fsync.c b/src/unistd/fsync.c new file mode 100644 index 00000000..7cfedc98 --- /dev/null +++ b/src/unistd/fsync.c @@ -0,0 +1,8 @@ +#include <unistd.h> +#include "syscall.h" + +int fsync(int fd) +{ +	//return syscall1(__NR_fsync, fd); +	return 0; +} diff --git a/src/unistd/ftruncate.c b/src/unistd/ftruncate.c new file mode 100644 index 00000000..e0b2f4bb --- /dev/null +++ b/src/unistd/ftruncate.c @@ -0,0 +1,15 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +int ftruncate(int fd, off_t length) +{ +	if (sizeof(long) == 8) +		return syscall2(__NR_ftruncate, fd, length); +	else { +		union { long long ll; long l[2]; } u = { length }; +		return syscall3(__NR_ftruncate64, fd, u.l[0], u.l[1]); +	} +} + +LFS64(ftruncate); diff --git a/src/unistd/getcwd.c b/src/unistd/getcwd.c new file mode 100644 index 00000000..4910f42c --- /dev/null +++ b/src/unistd/getcwd.c @@ -0,0 +1,8 @@ +#include <unistd.h> +#include <errno.h> +#include "syscall.h" + +char *getcwd(char *buf, size_t size) +{ +	return syscall2(__NR_getcwd, (long)buf, size) < 0 ? NULL : buf; +} diff --git a/src/unistd/getegid.c b/src/unistd/getegid.c new file mode 100644 index 00000000..0e626b75 --- /dev/null +++ b/src/unistd/getegid.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +gid_t getegid(void) +{ +	return syscall0(__NR_getegid32); +} diff --git a/src/unistd/geteuid.c b/src/unistd/geteuid.c new file mode 100644 index 00000000..39d6ac7b --- /dev/null +++ b/src/unistd/geteuid.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +uid_t geteuid(void) +{ +	return syscall0(__NR_geteuid32); +} diff --git a/src/unistd/getgid.c b/src/unistd/getgid.c new file mode 100644 index 00000000..186635a2 --- /dev/null +++ b/src/unistd/getgid.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +gid_t getgid(void) +{ +	return syscall0(__NR_getgid32); +} diff --git a/src/unistd/getgroups.c b/src/unistd/getgroups.c new file mode 100644 index 00000000..6f19870e --- /dev/null +++ b/src/unistd/getgroups.c @@ -0,0 +1,8 @@ +#include <unistd.h> +#include "syscall.h" + +int getgroups(int count, gid_t list[]) +{ +	/* this depends on our gid_t being 32bit */ +	return syscall2(__NR_getgroups32, count, (long)list); +} diff --git a/src/unistd/gethostname.c b/src/unistd/gethostname.c new file mode 100644 index 00000000..a406c4eb --- /dev/null +++ b/src/unistd/gethostname.c @@ -0,0 +1,14 @@ +#include <unistd.h> +#include <sys/utsname.h> +#include <string.h> + +int gethostname(char *name, size_t len) +{ +	size_t i; +	struct utsname uts; +	if (uname(&uts)) return -1; +	if (len > sizeof uts.nodename) len = sizeof uts.nodename; +	for (i=0; i<len && (name[i] = uts.nodename[i]); i++); +	if (i==len) name[i-1] = 0; +	return 0; +} diff --git a/src/unistd/getlogin.c b/src/unistd/getlogin.c new file mode 100644 index 00000000..06011913 --- /dev/null +++ b/src/unistd/getlogin.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include <stdlib.h> + +char *getlogin(void) +{ +	return getenv("LOGNAME"); +} diff --git a/src/unistd/getlogin_r.c b/src/unistd/getlogin_r.c new file mode 100644 index 00000000..f04f71e5 --- /dev/null +++ b/src/unistd/getlogin_r.c @@ -0,0 +1,13 @@ +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +int getlogin_r(char *name, size_t size) +{ +	char *logname = getlogin(); +	if (!logname) return ENXIO; /* or...? */ +	if (strlen(name) >= size) return ERANGE; +	strcpy(name, logname); +	return 0; +} diff --git a/src/unistd/getpgid.c b/src/unistd/getpgid.c new file mode 100644 index 00000000..50d716b5 --- /dev/null +++ b/src/unistd/getpgid.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +pid_t getpgid(pid_t pid) +{ +	return syscall1(__NR_getpgid, pid); +} diff --git a/src/unistd/getpgrp.c b/src/unistd/getpgrp.c new file mode 100644 index 00000000..2004630a --- /dev/null +++ b/src/unistd/getpgrp.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +pid_t getpgrp(void) +{ +	return syscall0(__NR_getpgrp); +} diff --git a/src/unistd/getpid.c b/src/unistd/getpid.c new file mode 100644 index 00000000..31cbe1cb --- /dev/null +++ b/src/unistd/getpid.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +pid_t getpid(void) +{ +	return syscall0(__NR_getpid); +} diff --git a/src/unistd/getppid.c b/src/unistd/getppid.c new file mode 100644 index 00000000..a3241829 --- /dev/null +++ b/src/unistd/getppid.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +pid_t getppid(void) +{ +	return syscall0(__NR_getppid); +} diff --git a/src/unistd/getsid.c b/src/unistd/getsid.c new file mode 100644 index 00000000..064229cf --- /dev/null +++ b/src/unistd/getsid.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +pid_t getsid(pid_t pid) +{ +	return syscall1(__NR_getsid, pid); +} diff --git a/src/unistd/getuid.c b/src/unistd/getuid.c new file mode 100644 index 00000000..9d4e53f5 --- /dev/null +++ b/src/unistd/getuid.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +uid_t getuid(void) +{ +	return syscall0(__NR_getuid32); +} diff --git a/src/unistd/isatty.c b/src/unistd/isatty.c new file mode 100644 index 00000000..cff6e9fe --- /dev/null +++ b/src/unistd/isatty.c @@ -0,0 +1,8 @@ +#include <unistd.h> +#include <termios.h> + +int isatty(int fd) +{ +	struct termios t; +	return tcgetattr(fd, &t) == 0; +} diff --git a/src/unistd/lchown.c b/src/unistd/lchown.c new file mode 100644 index 00000000..30e83916 --- /dev/null +++ b/src/unistd/lchown.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int lchown(const char *path, uid_t uid, gid_t gid) +{ +	return syscall3(__NR_lchown32, (long)path, uid, gid); +} diff --git a/src/unistd/link.c b/src/unistd/link.c new file mode 100644 index 00000000..f121bb9e --- /dev/null +++ b/src/unistd/link.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int link(const char *existing, const char *new) +{ +	return syscall2(__NR_link, (long)existing, (long)new); +} diff --git a/src/unistd/linkat.c b/src/unistd/linkat.c new file mode 100644 index 00000000..0eb51221 --- /dev/null +++ b/src/unistd/linkat.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int linkat(int fd1, const char *existing, int fd2, const char *new, int flag) +{ +	return syscall5(__NR_linkat, fd1, (long)existing, fd2, (long)new, flag); +} diff --git a/src/unistd/lseek.c b/src/unistd/lseek.c new file mode 100644 index 00000000..0dab2679 --- /dev/null +++ b/src/unistd/lseek.c @@ -0,0 +1,16 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +off_t lseek(int fd, off_t offset, int whence) +{ +	/* optimized away at compiletime */ +	if (sizeof(long) == 8) +		return syscall3(__NR_lseek, fd, offset, whence); +	else { +		off_t result; +		return syscall5(__NR__llseek, fd, offset>>32, offset, (long)&result, whence) ? -1 : result; +	} +} + +LFS64(lseek); diff --git a/src/unistd/nice.c b/src/unistd/nice.c new file mode 100644 index 00000000..4b28ef41 --- /dev/null +++ b/src/unistd/nice.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int nice(int inc) +{ +	return syscall1(__NR_nice, inc); +} diff --git a/src/unistd/pause.c b/src/unistd/pause.c new file mode 100644 index 00000000..14720651 --- /dev/null +++ b/src/unistd/pause.c @@ -0,0 +1,12 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +int pause(void) +{ +	int r; +	CANCELPT_BEGIN; +	r = syscall0(__NR_pause); +	CANCELPT_END; +	return r; +} diff --git a/src/unistd/pipe.c b/src/unistd/pipe.c new file mode 100644 index 00000000..2dfc9c99 --- /dev/null +++ b/src/unistd/pipe.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int pipe(int fd[2]) +{ +	return syscall1(__NR_pipe, (long)fd); +} diff --git a/src/unistd/pread.c b/src/unistd/pread.c new file mode 100644 index 00000000..029ba3d1 --- /dev/null +++ b/src/unistd/pread.c @@ -0,0 +1,14 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +ssize_t pread(int fd, void *buf, size_t size, off_t ofs) +{ +	ssize_t r; +	CANCELPT_BEGIN; +	r = syscall5(__NR_pread64, fd, (long)buf, size, SYSCALL_LL(ofs)); +	CANCELPT_END; +	return r; +} + +LFS64(pread); diff --git a/src/unistd/pwrite.c b/src/unistd/pwrite.c new file mode 100644 index 00000000..8f23d1b9 --- /dev/null +++ b/src/unistd/pwrite.c @@ -0,0 +1,14 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +ssize_t pwrite(int fd, const void *buf, size_t size, off_t ofs) +{ +	ssize_t r; +	CANCELPT_BEGIN; +	r = syscall5(__NR_pwrite64, fd, (long)buf, size, SYSCALL_LL(ofs)); +	CANCELPT_END; +	return r; +} + +LFS64(pwrite); diff --git a/src/unistd/read.c b/src/unistd/read.c new file mode 100644 index 00000000..87ff1f10 --- /dev/null +++ b/src/unistd/read.c @@ -0,0 +1,12 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +ssize_t read(int fd, void *buf, size_t count) +{ +	ssize_t r; +	CANCELPT_BEGIN; +	r = __syscall_read(fd, buf, count); +	CANCELPT_END; +	return r; +} diff --git a/src/unistd/readlink.c b/src/unistd/readlink.c new file mode 100644 index 00000000..f6b1635c --- /dev/null +++ b/src/unistd/readlink.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int readlink(const char *path, char *buf, size_t bufsize) +{ +	return syscall3(__NR_readlink, (long)path, (long)buf, bufsize); +} diff --git a/src/unistd/readlinkat.c b/src/unistd/readlinkat.c new file mode 100644 index 00000000..8171050d --- /dev/null +++ b/src/unistd/readlinkat.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int readlinkat(int fd, const char *path, char *buf, size_t bufsize) +{ +	return syscall4(__NR_readlinkat, fd, (long)path, (long)buf, bufsize); +} diff --git a/src/unistd/readv.c b/src/unistd/readv.c new file mode 100644 index 00000000..e311f9de --- /dev/null +++ b/src/unistd/readv.c @@ -0,0 +1,12 @@ +#include <sys/uio.h> +#include "syscall.h" +#include "libc.h" + +ssize_t readv(int fd, const struct iovec *iov, int count) +{ +	ssize_t r; +	CANCELPT_BEGIN; +	r = syscall3(__NR_readv, fd, (long)iov, count); +	CANCELPT_END; +	return r; +} diff --git a/src/unistd/renameat.c b/src/unistd/renameat.c new file mode 100644 index 00000000..0dae9f11 --- /dev/null +++ b/src/unistd/renameat.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include "syscall.h" + +int renameat(int oldfd, const char *old, int newfd, const char *new) +{ +	return syscall4(__NR_renameat, oldfd, (long)old, newfd, (long)new); +} diff --git a/src/unistd/rmdir.c b/src/unistd/rmdir.c new file mode 100644 index 00000000..8e18c7a8 --- /dev/null +++ b/src/unistd/rmdir.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int rmdir(const char *path) +{ +	return syscall1(__NR_rmdir, (long)path); +} diff --git a/src/unistd/setegid.c b/src/unistd/setegid.c new file mode 100644 index 00000000..85348842 --- /dev/null +++ b/src/unistd/setegid.c @@ -0,0 +1,6 @@ +#include <unistd.h> + +int setegid(gid_t egid) +{ +	return setregid(-1, egid); +} diff --git a/src/unistd/seteuid.c b/src/unistd/seteuid.c new file mode 100644 index 00000000..0aaa86e0 --- /dev/null +++ b/src/unistd/seteuid.c @@ -0,0 +1,6 @@ +#include <unistd.h> + +int seteuid(uid_t euid) +{ +	return setreuid(-1, euid); +} diff --git a/src/unistd/setgid.c b/src/unistd/setgid.c new file mode 100644 index 00000000..00c7a03a --- /dev/null +++ b/src/unistd/setgid.c @@ -0,0 +1,9 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +int setgid(gid_t gid) +{ +	if (libc.rsyscall) return libc.rsyscall(__NR_setgid32, gid, 0, 0, 0, 0, 0); +	return syscall1(__NR_setgid32, gid); +} diff --git a/src/unistd/setpgid.c b/src/unistd/setpgid.c new file mode 100644 index 00000000..748d2907 --- /dev/null +++ b/src/unistd/setpgid.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +pid_t setpgid(pid_t pid, pid_t pgid) +{ +	return syscall2(__NR_setpgid, pid, pgid); +} diff --git a/src/unistd/setpgrp.c b/src/unistd/setpgrp.c new file mode 100644 index 00000000..a2a37f65 --- /dev/null +++ b/src/unistd/setpgrp.c @@ -0,0 +1,6 @@ +#include <unistd.h> + +pid_t setpgrp(void) +{ +	return setpgid(0, 0); +} diff --git a/src/unistd/setregid.c b/src/unistd/setregid.c new file mode 100644 index 00000000..d25dab76 --- /dev/null +++ b/src/unistd/setregid.c @@ -0,0 +1,9 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +int setregid(gid_t rgid, gid_t egid) +{ +	if (libc.rsyscall) return libc.rsyscall(__NR_setregid32, rgid, egid, 0, 0, 0, 0); +	return syscall2(__NR_setregid32, rgid, egid); +} diff --git a/src/unistd/setreuid.c b/src/unistd/setreuid.c new file mode 100644 index 00000000..0ba2277b --- /dev/null +++ b/src/unistd/setreuid.c @@ -0,0 +1,9 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +int setreuid(uid_t ruid, uid_t euid) +{ +	if (libc.rsyscall) return libc.rsyscall(__NR_setreuid32, ruid, euid, 0, 0, 0, 0); +	return syscall2(__NR_setreuid32, ruid, euid); +} diff --git a/src/unistd/setsid.c b/src/unistd/setsid.c new file mode 100644 index 00000000..e2c5690c --- /dev/null +++ b/src/unistd/setsid.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +pid_t setsid(void) +{ +	return syscall0(__NR_setsid); +} diff --git a/src/unistd/setuid.c b/src/unistd/setuid.c new file mode 100644 index 00000000..53b74d88 --- /dev/null +++ b/src/unistd/setuid.c @@ -0,0 +1,9 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +int setuid(uid_t uid) +{ +	if (libc.rsyscall) return libc.rsyscall(__NR_setuid32, uid, 0, 0, 0, 0, 0); +	return syscall1(__NR_setuid32, uid); +} diff --git a/src/unistd/sleep.c b/src/unistd/sleep.c new file mode 100644 index 00000000..d6450941 --- /dev/null +++ b/src/unistd/sleep.c @@ -0,0 +1,10 @@ +#include <unistd.h> +#include <time.h> + +unsigned sleep(unsigned seconds) +{ +	struct timespec tv = { .tv_sec = seconds, .tv_nsec = 0 }; +	if (nanosleep(&tv, &tv)) +		return tv.tv_sec; +	return 0; +} diff --git a/src/unistd/symlink.c b/src/unistd/symlink.c new file mode 100644 index 00000000..8d380d85 --- /dev/null +++ b/src/unistd/symlink.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int symlink(const char *existing, const char *new) +{ +	return syscall2(__NR_symlink, (long)existing, (long)new); +} diff --git a/src/unistd/symlinkat.c b/src/unistd/symlinkat.c new file mode 100644 index 00000000..9693b226 --- /dev/null +++ b/src/unistd/symlinkat.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int symlinkat(const char *existing, int fd, const char *new) +{ +	return syscall3(__NR_symlinkat, (long)existing, fd, (long)new); +} diff --git a/src/unistd/sync.c b/src/unistd/sync.c new file mode 100644 index 00000000..a49808fd --- /dev/null +++ b/src/unistd/sync.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +void sync(void) +{ +	syscall0(__NR_sync); +} diff --git a/src/unistd/tcgetpgrp.c b/src/unistd/tcgetpgrp.c new file mode 100644 index 00000000..50080c7e --- /dev/null +++ b/src/unistd/tcgetpgrp.c @@ -0,0 +1,11 @@ +#include <unistd.h> +#include <termios.h> +#include <sys/ioctl.h> + +pid_t tcgetpgrp(int fd) +{ +	int pgrp; +	if (ioctl(fd, TIOCGPGRP, &pgrp) < 0) +		return -1; +	return pgrp; +} diff --git a/src/unistd/tcsetpgrp.c b/src/unistd/tcsetpgrp.c new file mode 100644 index 00000000..67c38cb4 --- /dev/null +++ b/src/unistd/tcsetpgrp.c @@ -0,0 +1,9 @@ +#include <unistd.h> +#include <termios.h> +#include <sys/ioctl.h> + +int tcsetpgrp(int fd, pid_t pgrp) +{ +	int pgrp_int = pgrp; +	return ioctl(fd, TIOCSPGRP, &pgrp_int); +} diff --git a/src/unistd/truncate.c b/src/unistd/truncate.c new file mode 100644 index 00000000..f75e824e --- /dev/null +++ b/src/unistd/truncate.c @@ -0,0 +1,15 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +int truncate(const char *path, off_t length) +{ +	if (sizeof(long) == 8) +		return syscall2(__NR_truncate, (long)path, length); +	else { +		union { long long ll; long l[2]; } u = { length }; +		return syscall3(__NR_truncate64, (long)path, u.l[0], u.l[1]); +	} +} + +LFS64(truncate); diff --git a/src/unistd/ttyname.c b/src/unistd/ttyname.c new file mode 100644 index 00000000..0f3e1141 --- /dev/null +++ b/src/unistd/ttyname.c @@ -0,0 +1,14 @@ +#include <unistd.h> +#include <errno.h> +#include <limits.h> + +char *ttyname(int fd) +{ +	static char buf[TTY_NAME_MAX]; +	int result; +	if ((result = ttyname_r(fd, buf, sizeof buf))) { +		errno = result; +		return NULL; +	} +	return buf; +} diff --git a/src/unistd/ttyname_r.c b/src/unistd/ttyname_r.c new file mode 100644 index 00000000..f86fbd9c --- /dev/null +++ b/src/unistd/ttyname_r.c @@ -0,0 +1,19 @@ +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +int ttyname_r(int fd, char *name, size_t size) +{ +	char procname[sizeof "/proc/self/fd/" + 3*sizeof(int) + 2]; +	ssize_t l; + +	if (!isatty(fd)) return ENOTTY; + +	snprintf(procname, sizeof procname, "/proc/self/fd/%d", fd); +	l = readlink(procname, name, size); + +	if (l < 0) return errno; +	else if (l == size) return ERANGE; +	else return 0; +} diff --git a/src/unistd/ualarm.c b/src/unistd/ualarm.c new file mode 100644 index 00000000..be853035 --- /dev/null +++ b/src/unistd/ualarm.c @@ -0,0 +1,8 @@ +#include <unistd.h> +#include "syscall.h" + +/* FIXME: ?? */ +useconds_t ualarm(useconds_t useconds, useconds_t interval) +{ +	return -1; +} diff --git a/src/unistd/unlink.c b/src/unistd/unlink.c new file mode 100644 index 00000000..fb577920 --- /dev/null +++ b/src/unistd/unlink.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int unlink(const char *path) +{ +	return __syscall_unlink(path); +} diff --git a/src/unistd/unlinkat.c b/src/unistd/unlinkat.c new file mode 100644 index 00000000..47fccc17 --- /dev/null +++ b/src/unistd/unlinkat.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include "syscall.h" + +int unlinkat(int fd, const char *path, int flag) +{ +	return syscall3(__NR_unlinkat, fd, (long)path, flag); +} diff --git a/src/unistd/usleep.c b/src/unistd/usleep.c new file mode 100644 index 00000000..e3869017 --- /dev/null +++ b/src/unistd/usleep.c @@ -0,0 +1,11 @@ +#include <unistd.h> +#include <time.h> + +int usleep(useconds_t useconds) +{ +	struct timespec tv = { +		.tv_sec = useconds/1000000, +		.tv_nsec = (useconds%1000000)*1000 +	}; +	return nanosleep(&tv, &tv); +} diff --git a/src/unistd/write.c b/src/unistd/write.c new file mode 100644 index 00000000..426cfc5b --- /dev/null +++ b/src/unistd/write.c @@ -0,0 +1,12 @@ +#include <unistd.h> +#include "syscall.h" +#include "libc.h" + +ssize_t write(int fd, const void *buf, size_t count) +{ +	int r; +	CANCELPT_BEGIN; +	r = __syscall_write(fd, buf, count); +	CANCELPT_END; +	return r; +} diff --git a/src/unistd/writev.c b/src/unistd/writev.c new file mode 100644 index 00000000..a6a118af --- /dev/null +++ b/src/unistd/writev.c @@ -0,0 +1,12 @@ +#include <sys/uio.h> +#include "syscall.h" +#include "libc.h" + +ssize_t writev(int fd, const struct iovec *iov, int count) +{ +	ssize_t r; +	CANCELPT_BEGIN; +	r = syscall3(__NR_writev, fd, (long)iov, count); +	CANCELPT_END; +	return r; +} diff --git a/tools/gen-musl-gcc.sh b/tools/gen-musl-gcc.sh new file mode 100644 index 00000000..89f7f4d9 --- /dev/null +++ b/tools/gen-musl-gcc.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +printf '#!/bin/sh\n\nlibc_prefix="%s"\n' "$1" + +cat <<"EOF" +libc_lib=$libc_prefix/lib +libc_inc=$libc_prefix/include +libc_crt="$libc_lib/crt1.o" +libc_start="$libc_lib/crti.o" +libc_end="$libc_lib/crtn.o" + +gcc_inc=$libc_inc +libgcc="`gcc \"$@\" -print-file-name=libgcc.a`" + +gcc -wrapper sh,-c,' +x= ; y= ; z= ; s= ; for i ; do +  [ "$z" ] || set -- ; z=1 +  case "$i" in +    -shared) s=1 ; set -- "$@" -shared ;; +    -Lxxxxxx) x=1 ;; +    -xxxxxx) x= ; [ "$s" ] || set -- "$@" "'"$libc_start"'" "'"$libc_crt"'" ;; +    -l*) [ "$y" ] || set -- "$@" '"$libc_end"' ; set -- "$@" "$i" ; y=1 ;; +    *) [ "$x" ] || set -- "$@" "$i" ;; +  esac +done +exec "$0" "$@" +' -std=gnu99 -nostdinc -nostdlib \ +  -isystem "$libc_inc" -isystem "$gcc_inc" \ +  -Wl,-xxxxxx "$@" -L"$libc_lib" -lc "$libgcc" -Lxxxxxx -Wl,-nostdlib +EOF  | 
