summaryrefslogtreecommitdiffstats
path: root/funtools/gnu
diff options
context:
space:
mode:
Diffstat (limited to 'funtools/gnu')
-rw-r--r--funtools/gnu/COPYING340
-rw-r--r--funtools/gnu/Makefile.in150
-rw-r--r--funtools/gnu/conf.h.in59
-rw-r--r--funtools/gnu/copyright29
-rwxr-xr-xfuntools/gnu/install-sh276
-rw-r--r--funtools/gnu/sort.c2879
-rw-r--r--funtools/gnu/sorttest.c152
-rw-r--r--funtools/gnu/system.h187
8 files changed, 4072 insertions, 0 deletions
diff --git a/funtools/gnu/COPYING b/funtools/gnu/COPYING
new file mode 100644
index 0000000..60549be
--- /dev/null
+++ b/funtools/gnu/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 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.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/funtools/gnu/Makefile.in b/funtools/gnu/Makefile.in
new file mode 100644
index 0000000..26cbf53
--- /dev/null
+++ b/funtools/gnu/Makefile.in
@@ -0,0 +1,150 @@
+#
+# This is a Makefile for the gnu binary sort. If it has the name "Makefile.in"
+# then it is a template for a Makefile; to generate the actual Makefile,
+# run "./configure", which is a configuration script generated by the
+# "autoconf" program (constructs like "@foo@" will get replaced in the
+# actual Makefile.
+#
+
+#----------------------------------------------------------------
+# Things you can change to personalize the Makefile for your own
+# site (you can make these changes in either Makefile.in or
+# Makefile, but changes to Makefile will get lost if you re-run
+# the configuration script).
+#----------------------------------------------------------------
+
+# Default top-level directories in which to install architecture-
+# specific files (exec_prefix) and machine-independent files such
+# as scripts (prefix). The values specified here may be overridden
+# at configure-time with the --exec-prefix and --prefix options
+# to the "configure" script.
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+# The following definition can be set to non-null for special systems
+# like AFS with replication. It allows the pathnames used for installation
+# to be different than those used for actually reference files at
+# run-time. INSTALL_ROOT is prepended to $prefix and $exec_prefix
+# when installing files.
+INSTALL_ROOT =
+
+# extra includes for compiling
+INCLUDES = -I. -I$(prefix)/include
+
+# extra libs
+EXTRA_LIBS = @EXTRA_LIBS@
+
+# the full set of libraries for linking
+LIBS =
+
+# To change the compiler switches, for example to change from -O
+# to -g, change the following line:
+CFLAGS = @CFLAGS@ -DSAOMOD_BINARY
+
+# To add ld switches, change the following line:
+LDFLAGS = @LDFLAGS@
+
+# Some versions of make, like SGI's, use the following variable to
+# determine which shell to use for executing commands:
+SHELL = /bin/sh
+
+# extra modules added by configure.in to fix OS bugs
+EXTRA_OBJS = @EXTRA_OBJS@
+
+# Directory in which to install the .a, .so, and .o files:
+LIB_INSTALL_DIR = $(INSTALL_ROOT)$(exec_prefix)/lib
+
+# Directory in which to install the programs:
+BIN_INSTALL_DIR = $(INSTALL_ROOT)$(exec_prefix)/bin
+
+# Directory in which to install the include files:
+INCLUDE_INSTALL_DIR = $(INSTALL_ROOT)$(prefix)/include
+
+# There are just too many different versions of "install" around;
+# better to use the install-sh script that comes with the distribution,
+# which is slower but guaranteed to work.
+
+INSTALL = @srcdir@/install-sh -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+
+#----------------------------------------------------------------
+# The information below is modified by the configure script when
+# Makefile is generated from Makefile.in. You shouldn't normally
+# modify any of this stuff by hand.
+#----------------------------------------------------------------
+
+AC_FLAGS = @DEFS@
+RANLIB = @RANLIB@
+EXE = @EXEEXT@
+
+#----------------------------------------------------------------
+# The information below should be usable as is. The configure
+# script won't modify it and you shouldn't need to modify it
+# either.
+#----------------------------------------------------------------
+
+CC = @CC@
+
+CC_SWITCHES = ${CFLAGS} ${CPPFLAGS} ${INCLUDES} ${AC_FLAGS}
+
+DEPEND_SWITCHES = ${CFLAGS} ${INCLUDES} ${AC_FLAGS}
+
+SRCS = sort.c
+
+OBJS = sort.o
+
+PROGS = _funsort
+
+TESTPROGS = sorttest
+
+all: $(PROGS)
+
+_funsort: $(OBJS)
+ $(CC) $(LDFLAGS) $(OBJS) -o _funsort
+
+sorttest: sorttest.o
+ $(CC) $(LDFLAGS) sorttest.o -o sorttest -L.. -lfuntools
+
+Makefile: Makefile.in
+ $(SHELL) config.status
+
+RM = rm -f
+
+clean:
+ $(RM) *.a *.so *.o *.exe core errs *pure* .nfs* \
+ foo* *~ *.log \#* TAGS *.E a.out errors \
+ $(PROGS) $(TESTPROGS) \
+ gmon.out *.pg *.bak \
+ config.info config.log \
+ *fun*.out doc/*~
+ $(RM) -r autom4te.cache
+
+distclean: clean
+ $(RM) Makefile config.status config.cache config.log
+
+pclean:
+ $(RM) $(PROGS)
+
+depend:
+ makedepend -- $(DEPEND_SWITCHES) -- $(SRCS)
+
+sort.o: sort.c
+ $(CC) -c $(CC_SWITCHES) sort.c
+
+install: $(PROGS)
+ @for i in $(PROGS) ; \
+ do \
+ echo "Installing $$i$(EXE)" ; \
+ $(INSTALL_PROGRAM) $$i$(EXE) $(BIN_INSTALL_DIR)/$$i$(EXE) ; \
+ done;
+
+
+pure: _funsort.pure
+
+_funsort.pure: $(FUNLIB) sort.o
+ purify $(CC) $(LDFLAGS) sort.o -o _funsort.pure \
+ $(FUNLIB) $(LIBS)
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/funtools/gnu/conf.h.in b/funtools/gnu/conf.h.in
new file mode 100644
index 0000000..5f3fa16
--- /dev/null
+++ b/funtools/gnu/conf.h.in
@@ -0,0 +1,59 @@
+/* Define as 1 if this compiler supports long long. */
+#undef HAVE_LONG_LONG
+
+/* Define as 1 if you have string.h */
+#undef HAVE_STRING_H
+
+/* Define as 1 if you have stdlib.h */
+#undef HAVE_STDLIB_H
+
+/* Define as 1 if you have malloc.h */
+#undef HAVE_MALLOC_H
+
+/* Define as 1 if you have unistd.h */
+#undef HAVE_UNISTD_H
+
+/* Define as 1 if you have getopt.h */
+#undef HAVE_GETOPT_H
+
+/* Define as 1 if you have values.h */
+#undef HAVE_VALUES_H
+
+/* Define as 1 if you have dlfcn.h */
+#undef HAVE_DLFCN_H
+
+/* Define as 1 if you have sys/un.h */
+#undef HAVE_SYS_UN_H
+
+/* Define as 1 if you have sys/shm.h */
+#undef HAVE_SYS_SHM_H
+
+/* Define as 1 if you have sys/mman.h */
+#undef HAVE_SYS_MMAN_H
+
+/* Define as 1 if you have sys/ipc.h */
+#undef HAVE_SYS_IPC_H
+
+/* Define as 1 if you have socklen_t */
+#undef HAVE_SOCKLEN_T
+
+/* Define as 1 if you have strchr */
+#undef HAVE_STRCHR
+
+/* Define as 1 if you have memcpy */
+#undef HAVE_MEMCPY
+
+/* Define as 1 if you have snprintf */
+#undef HAVE_SNPRINTF
+
+/* Define as 1 if you have Tcl */
+#undef HAVE_TCL
+
+/* Define as 1 if you have Xt */
+#undef HAVE_XT
+
+/* Define as 1 if you are running Cygwin. */
+#undef HAVE_CYGWIN
+
+/* Define as 1 if you are running MinGW. */
+#undef HAVE_MINGW32
diff --git a/funtools/gnu/copyright b/funtools/gnu/copyright
new file mode 100644
index 0000000..1778779
--- /dev/null
+++ b/funtools/gnu/copyright
@@ -0,0 +1,29 @@
+Unless otherwise indicated, all source is:
+
+Copyright (C) 1999-2003
+Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Correspondence concerning SAOds9 and SAOtk should be addressed as follows:
+
+William Joye
+Smithsonian Astrophysical Observatory
+Garden St.
+Cambridge, MA 02138 USA
+
+wjoye@cfa.harvard.edu
+
+http://hea-www.harvard.edu/RD/ds9/
diff --git a/funtools/gnu/install-sh b/funtools/gnu/install-sh
new file mode 100755
index 0000000..36f96f3
--- /dev/null
+++ b/funtools/gnu/install-sh
@@ -0,0 +1,276 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd=$cpprog
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd=$stripprog
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "$0: no input file specified" >&2
+ exit 1
+else
+ :
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d "$dst" ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=$mkdirprog
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f "$src" ] || [ -d "$src" ]
+ then
+ :
+ else
+ echo "$0: $src does not exist" >&2
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "$0: no destination specified" >&2
+ exit 1
+ else
+ :
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d "$dst" ]
+ then
+ dst=$dst/`basename "$src"`
+ else
+ :
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+ '
+IFS="${IFS-$defaultIFS}"
+
+oIFS=$IFS
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS=$oIFS
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp=$pathcomp$1
+ shift
+
+ if [ ! -d "$pathcomp" ] ;
+ then
+ $mkdirprog "$pathcomp"
+ else
+ :
+ fi
+
+ pathcomp=$pathcomp/
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd "$dst" &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename "$dst"`
+ else
+ dstfile=`basename "$dst" $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename "$dst"`
+ else
+ :
+ fi
+
+# Make a couple of temp file names in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+ rmtmp=$dstdir/#rm.$$#
+
+# Trap to clean up temp files at exit.
+
+ trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
+ trap '(exit $?); exit' 1 2 13 15
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd "$src" "$dsttmp" &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi &&
+
+# Now remove or move aside any old file at destination location. We try this
+# two ways since rm can't unlink itself on some systems and the destination
+# file might be busy for other reasons. In this case, the final cleanup
+# might fail but the new file should still install successfully.
+
+{
+ if [ -f "$dstdir/$dstfile" ]
+ then
+ $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null ||
+ $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null ||
+ {
+ echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+ (exit 1); exit
+ }
+ else
+ :
+ fi
+} &&
+
+# Now rename the file to the real destination.
+
+ $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+
+fi &&
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+
+{
+ (exit 0); exit
+}
diff --git a/funtools/gnu/sort.c b/funtools/gnu/sort.c
new file mode 100644
index 0000000..56d8bb2
--- /dev/null
+++ b/funtools/gnu/sort.c
@@ -0,0 +1,2879 @@
+/* sort - sort lines of text (with all kinds of options).
+ Copyright (C) 1988, 1991, 1992, 1993, 1994, 1995 Free Software Foundation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Written December 1988 by Mike Haertel.
+ The author may be reached (Email) at the address mike@gnu.ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+/* define to sort binary data */
+/* #define SAOMOD_BINARY 1 */
+
+/* define to sorts on hms, mjd */
+/* #define SAOMOD_ASTRO 1 */
+
+/* define to sort RDB tables */
+/* #define SAOMOD_TABLE 1 */
+
+/* always define --this just marks code fixes */
+#define SAOMOD_FIX 1
+
+/* Get isblank from GNU libc. */
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+
+#ifndef RTMX
+#include <signal.h>
+#else
+#include <sys/signal.h>
+#endif
+
+#if HAVE_CONFIG_H
+#include <conf.h>
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include "system.h"
+#ifdef LOCAL_INCLUDES
+#include "version.h"
+#include "error.h"
+#endif
+
+#ifdef SAOMOD_TABLE
+#include <table.h>
+#endif
+#ifdef SAOMOD_ASTRO
+double mjd();
+#endif
+
+#ifdef _POSIX_VERSION
+#include <limits.h>
+#else
+#ifndef UCHAR_MAX
+#define UCHAR_MAX 255
+#endif
+#endif
+
+#if HAVE_LONG_LONG
+typedef long long longlong;
+#else
+typedef long longlong;
+#endif
+
+static void usage ();
+
+#ifdef SAOMOD_TABLE
+ int table = 0;
+#endif
+
+#ifdef SAOMOD_BINARY
+ int BinarySort = 0;
+#endif
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define UCHAR_LIM (UCHAR_MAX + 1)
+#define UCHAR(c) ((unsigned char) (c))
+
+#ifndef DEFAULT_TMPDIR
+#define DEFAULT_TMPDIR "/tmp"
+#endif
+
+/* The kind of blanks for '-b' to skip in various options. */
+enum blanktype { bl_start, bl_end, bl_both };
+
+/* The name this program was run with. */
+char *program_name;
+
+/* Table of digits. */
+static int digits[UCHAR_LIM];
+
+/* Table of white space. */
+static int blanks[UCHAR_LIM];
+
+/* Table of non-printing characters. */
+static int nonprinting[UCHAR_LIM];
+
+/* Table of non-dictionary characters (not letters, digits, or blanks). */
+static int nondictionary[UCHAR_LIM];
+
+/* Translation table folding lower case to upper. */
+static char fold_toupper[UCHAR_LIM];
+
+/* Table mapping 3-letter month names to integers.
+ Alphabetic order allows binary search. */
+static struct month
+{
+ char *name;
+ int val;
+} const monthtab[] =
+{
+ {"APR", 4},
+ {"AUG", 8},
+ {"DEC", 12},
+ {"FEB", 2},
+ {"JAN", 1},
+ {"JUL", 7},
+ {"JUN", 6},
+ {"MAR", 3},
+ {"MAY", 5},
+ {"NOV", 11},
+ {"OCT", 10},
+ {"SEP", 9}
+};
+
+/* During the merge phase, the number of files to merge at once. */
+#define NMERGE 48
+
+/* Initial buffer size for in core sorting. Will not grow unless a
+ line longer than this is seen. */
+static int sortalloc = 1024 * 1024;
+
+/* Initial buffer size for in core merge buffers. Bear in mind that
+ up to NMERGE * mergealloc bytes may be allocated for merge buffers. */
+static int mergealloc = 32 * 1024;
+
+/* Guess of average line length. */
+static int linelength = 30;
+
+/* Maximum number of elements for the array(s) of struct line's, in bytes. */
+#define LINEALLOC (8 * 256 * 1024)
+
+/* Prefix for temporary file names. */
+static char *temp_file_prefix;
+
+/* Flag to reverse the order of all comparisons. */
+static int reverse;
+
+/* Flag for stable sort. This turns off the last ditch bytewise
+ comparison of lines, and instead leaves lines in the same order
+ they were read if all keys compare equal. */
+static int stable;
+
+/* Tab character separating fields. If NUL, then fields are separated
+ by the empty string between a non-whitespace character and a whitespace
+ character. */
+static char tab = '\0';
+
+/* Nonzero if any of the input files are the standard input. */
+static int have_read_stdin;
+
+/* Lines are held in core as counted strings. */
+struct line
+{
+ char *text; /* Text of the line. */
+ int length; /* Length not including final newline. */
+ char *keybeg; /* Start of first key. */
+ char *keylim; /* Limit of first key. */
+#ifdef SAOMOD_ASTRO
+ int flag;
+ double value; /* the chached value of the a numeric key. */
+#endif
+};
+
+/* Arrays of lines. */
+struct lines
+{
+ struct line *lines; /* Dynamically allocated array of lines. */
+ int used; /* Number of slots used. */
+ int alloc; /* Number of slots allocated. */
+ int limit; /* Max number of slots to allocate. */
+};
+
+/* Input buffers. */
+struct buffer
+{
+ char *buf; /* Dynamically allocated buffer. */
+ int used; /* Number of bytes used. */
+ int alloc; /* Number of bytes allocated. */
+ int left; /* Number of bytes left after line parsing. */
+};
+
+/* Lists of key field comparisons to be tried. */
+static struct keyfield
+{
+ int sword; /* Zero-origin 'word' to start at. */
+ int schar; /* Additional characters to skip. */
+ int skipsblanks; /* Skip leading white space at start. */
+ int eword; /* Zero-origin first word after field. */
+ int echar; /* Additional characters in field. */
+ int skipeblanks; /* Skip trailing white space at finish. */
+ int *ignore; /* Boolean array of characters to ignore. */
+ char *translate; /* Translation applied to characters. */
+ int numeric; /* Flag for numeric comparison. */
+ int month; /* Flag for comparison by month name. */
+ int reverse; /* Reverse the sense of comparison. */
+ int nzone;
+ double dzone;
+ int btype;
+ struct keyfield *next; /* Next keyfield to try. */
+} keyhead;
+
+/* The list of temporary files. */
+static struct tempnode
+{
+ char *name;
+ struct tempnode *next;
+} temphead;
+
+
+/* Flag to remove consecutive duplicate lines from the output.
+ Only the last of a sequence of equal lines will be output. */
+static int unique = 0;
+static int differ = 0;
+static int countr = 0;
+static int setcnt = 1;
+
+
+/* Clean up any remaining temporary files. */
+
+static void
+cleanup ()
+{
+ struct tempnode *node;
+
+ for (node = temphead.next; node; node = node->next)
+ unlink (node->name);
+}
+
+/* Allocate N bytes of memory dynamically, with error checking. */
+
+char *
+xmalloc (n)
+ unsigned n;
+{
+ char *p;
+
+ p = (char *)malloc (n);
+ if (p == 0)
+ {
+ fprintf (stderr, "virtual memory exhausted");
+ cleanup ();
+ exit (2);
+ }
+ return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+ with error checking.
+ If P is NULL, run xmalloc.
+ If N is 0, run free and return NULL. */
+
+char *
+xrealloc (p, n)
+ char *p;
+ unsigned n;
+{
+ if (p == 0)
+ return (char *)xmalloc (n);
+ if (n == 0)
+ {
+ free (p);
+ return 0;
+ }
+ p = (char *)realloc (p, n);
+ if (p == 0)
+ {
+ fprintf (stderr, "virtual memory exhausted");
+ cleanup ();
+ exit (2);
+ }
+ return p;
+}
+static FILE *
+xfopen (file, how)
+ char *file, *how;
+{
+#ifdef SAOMOD_TABLE
+ FILE *fp = Open(file, how);
+#else
+ FILE *fp;
+ if ( !strcmp(file, "-") && !strcmp(how, "r") ) fp = stdin;
+ else if ( !strcmp(file, "-") && !strcmp(how, "w") ) fp = stdout;
+ else fp = fopen(file, how);
+#endif
+
+ if (fp == 0) {
+ perror (file);
+ cleanup ();
+ exit (2);
+ }
+
+ if (fp == stdin) have_read_stdin = 1;
+
+ return fp;
+}
+
+static void
+xfclose (fp)
+ FILE *fp;
+{
+ if (fp == stdin) {
+ /* Allow reading stdin from tty more than once. */
+ if (feof (fp))
+ clearerr (fp);
+ } else if ( fp == stdout ) {
+ if (fflush (fp) != 0) {
+ perror ("flushing file");
+ cleanup ();
+ exit (2);
+ }
+ } else {
+#ifdef SAOMOD_TABLE
+ if ( Close(fp) != 0 ) {
+#else
+ if ( fclose(fp) != 0 ) {
+#endif
+
+ perror ("closing file");
+ cleanup ();
+ exit (2);
+ }
+ }
+}
+
+static void
+xfwrite (buf, size, nelem, fp)
+ char *buf;
+ int size, nelem;
+ FILE *fp;
+{
+ if (fwrite (buf, size, nelem, fp) != (size_t)nelem)
+ {
+ perror ("writing file");
+ cleanup ();
+ exit (2);
+ }
+}
+
+/* Return a name for a temporary file. */
+
+static char *
+tempname ()
+{
+ static int seq;
+ int len = strlen (temp_file_prefix);
+ char *name = xmalloc (len + 16);
+ struct tempnode *node =
+ (struct tempnode *) xmalloc (sizeof (struct tempnode));
+
+ sprintf (name,
+ "%s%ssort%5.5d%5.5d",
+ temp_file_prefix,
+ (len && temp_file_prefix[len - 1] != '/') ? "/" : "",
+ (unsigned int) getpid () & 0xffff, ++seq);
+ node->name = name;
+ node->next = temphead.next;
+ temphead.next = node;
+ return name;
+}
+
+/* Search through the list of temporary files for NAME;
+ remove it if it is found on the list. */
+
+static void
+zaptemp (name)
+ char *name;
+{
+ struct tempnode *node, *temp;
+
+ for (node = &temphead; node->next; node = node->next)
+ if (!strcmp (name, node->next->name))
+ break;
+ if (node->next)
+ {
+ temp = node->next;
+ unlink (temp->name);
+ free (temp->name);
+ node->next = temp->next;
+ free ((char *) temp);
+ }
+}
+
+/* Initialize the character class tables. */
+
+static void
+inittables ()
+{
+ int i;
+
+ for (i = 0; i < UCHAR_LIM; ++i)
+ {
+ if (ISBLANK (i))
+ blanks[i] = 1;
+ if (ISDIGIT (i))
+ digits[i] = 1;
+ if (!ISPRINT (i))
+ nonprinting[i] = 1;
+ if (!ISALNUM (i) && !ISBLANK (i))
+ nondictionary[i] = 1;
+ if (ISLOWER (i))
+ fold_toupper[i] = toupper (i);
+ else
+ fold_toupper[i] = i;
+ }
+}
+
+/* Initialize BUF, allocating ALLOC bytes initially. */
+
+static void
+initbuf (buf, alloc)
+ struct buffer *buf;
+ int alloc;
+{
+ buf->alloc = alloc;
+ buf->buf = xmalloc (buf->alloc);
+ buf->used = buf->left = 0;
+}
+
+/* Fill BUF reading from FP, moving buf->left bytes from the end
+ of buf->buf to the beginning first. If EOF is reached and the
+ file wasn't terminated by a newline, supply one. Return a count
+ of bytes buffered. */
+
+static int
+fillbuf (buf, fp)
+ struct buffer *buf;
+ FILE *fp;
+{
+ int cc;
+
+ memmove (buf->buf, buf->buf + buf->used - buf->left, buf->left);
+ buf->used = buf->left;
+
+#ifdef SAOMOD_BINARY
+ if ( BinarySort ) {
+ cc = fread (buf->buf + buf->used, 1, buf->alloc - buf->used, fp);
+
+ buf->used += cc;
+
+ return buf->used;
+ }
+#endif
+
+ while (!feof (fp) && (buf->used == 0 || !memchr (buf->buf, '\n', buf->used)))
+ {
+ if (buf->used == buf->alloc)
+ {
+ buf->alloc *= 2;
+ buf->buf = xrealloc (buf->buf, buf->alloc);
+ }
+ cc = fread (buf->buf + buf->used, 1, buf->alloc - buf->used, fp);
+ if (ferror (fp))
+ {
+ perror ("reading file");
+ cleanup ();
+ exit (2);
+ }
+ buf->used += cc;
+ }
+
+ if (feof (fp) && buf->used && buf->buf[buf->used - 1] != '\n')
+ {
+ if (buf->used == buf->alloc)
+ {
+ buf->alloc *= 2;
+ buf->buf = xrealloc (buf->buf, buf->alloc);
+ }
+ buf->buf[buf->used++] = '\n';
+ }
+
+ return buf->used;
+}
+
+/* Initialize LINES, allocating space for ALLOC lines initially.
+ LIMIT is the maximum possible number of lines to allocate space
+ for, ever. */
+
+static void
+initlines (lines, alloc, limit)
+ struct lines *lines;
+ int alloc;
+ int limit;
+{
+ lines->alloc = alloc;
+ lines->lines = (struct line *) xmalloc (lines->alloc * sizeof (struct line));
+ lines->used = 0;
+ lines->limit = limit;
+}
+
+/* Return a pointer to the first character of the field specified
+ by KEY in LINE. */
+
+static char *
+begfield (line, key)
+ struct line *line;
+ struct keyfield *key;
+{
+ register char *ptr = line->text, *lim = ptr + line->length;
+ register int sword = key->sword, schar = key->schar;
+
+ if (tab)
+ while (ptr < lim && sword--)
+ {
+ while (ptr < lim && *ptr != tab)
+ ++ptr;
+ if (ptr < lim)
+ ++ptr;
+ }
+ else
+ while (ptr < lim && sword--)
+ {
+ while (ptr < lim && blanks[UCHAR (*ptr)])
+ ++ptr;
+ while (ptr < lim && !blanks[UCHAR (*ptr)])
+ ++ptr;
+ }
+
+ if (key->skipsblanks
+#ifdef SAOMOD_TABLE
+||table
+#endif
+ )
+ while (ptr < lim && blanks[UCHAR (*ptr)])
+ ++ptr;
+
+ while (ptr < lim && schar--)
+ ++ptr;
+
+ return ptr;
+}
+
+/* Return the limit of (a pointer to the first character after) the field
+ in LINE specified by KEY. */
+
+static char *
+limfield (line, key)
+ struct line *line;
+ struct keyfield *key;
+{
+ register char *ptr = line->text, *lim = ptr + line->length;
+ register int eword = key->eword, echar = key->echar;
+
+ if ( eword == -1 ) {
+ eword = 1;
+ echar = 0;
+ }
+
+ if (tab)
+ while (ptr < lim && eword--)
+ {
+ while (ptr < lim && *ptr != tab)
+ ++ptr;
+ if (ptr < lim && (eword > 0 || key->skipeblanks))
+ ++ptr;
+ }
+ else
+ while (ptr < lim && eword--)
+ {
+ while (ptr < lim && blanks[UCHAR (*ptr)])
+ ++ptr;
+ while (ptr < lim && !blanks[UCHAR (*ptr)])
+ ++ptr;
+ }
+
+#ifdef SAOMOD_TABLE
+ if ( table ) {
+ if ( blanks[UCHAR (*ptr)] ) {
+ while (ptr > line->text && blanks[UCHAR (*ptr)] ) --ptr;
+ ptr++;
+ }
+ } else
+#endif
+ {
+ if (key->skipeblanks)
+ while (ptr < lim && blanks[UCHAR (*ptr)])
+ ++ptr;
+
+ while (ptr < lim && echar--)
+ ++ptr;
+ }
+
+ return ptr;
+}
+
+/* Find the lines in BUF, storing pointers and lengths in LINES.
+ Also replace newlines with NULs. */
+
+static void
+findlines (buf, lines)
+ struct buffer *buf;
+ struct lines *lines;
+{
+ register char *beg = buf->buf, *lim = buf->buf + buf->used, *ptr;
+ struct keyfield *key = keyhead.next;
+
+ lines->used = 0;
+
+#ifdef SAOMOD_BINARY
+ if ( lim - beg < BinarySort ) {
+ fprintf(stderr, "Odd sized records in buffer?\n");
+ cleanup();
+ abort();
+ }
+#else
+ if ( lim - beg < 0 ) {
+ fprintf(stderr, "Odd sized records in buffer?\n");
+ cleanup();
+ abort();
+ }
+#endif
+
+#ifdef SAOMOD_BINARY
+ if ( BinarySort ) {
+ while ( beg + BinarySort <= lim )
+ {
+
+ if (lines->used == lines->alloc)
+ {
+ lines->alloc *= 2;
+ lines->lines = (struct line *)
+ xrealloc ((char *) lines->lines,
+ lines->alloc * sizeof (struct line));
+ }
+
+ lines->lines[lines->used].text = beg;
+ lines->lines[lines->used].length = BinarySort;
+#ifdef SAOMOD_ASTRO
+ lines->lines[lines->used].flag = 0;
+#endif
+
+ beg += BinarySort;
+ lines->used++;
+ }
+
+ buf->left = lim - beg;
+ return;
+ }
+#endif
+
+ while (beg < lim && (ptr = memchr (beg, '\n', lim - beg))
+ && lines->used < lines->limit)
+ {
+ /* There are various places in the code that rely on a NUL
+ being at the end of in-core lines; NULs inside the lines
+ will not cause trouble, though. */
+ *ptr = '\0';
+
+ if (lines->used == lines->alloc)
+ {
+ lines->alloc *= 2;
+ lines->lines = (struct line *)
+ xrealloc ((char *) lines->lines,
+ lines->alloc * sizeof (struct line));
+ }
+
+ lines->lines[lines->used].text = beg;
+ lines->lines[lines->used].length = ptr - beg;
+#ifdef SAOMOD_ASTRO
+ lines->lines[lines->used].flag = 0;
+#endif
+
+ /* Precompute the position of the first key for efficiency. */
+ if (key)
+ {
+ if ( key->eword >= 0
+#ifdef SAOMOD_TABLE
+ || table
+#endif
+ )
+ lines->lines[lines->used].keylim =
+ limfield (&lines->lines[lines->used], key);
+ else
+ lines->lines[lines->used].keylim = ptr;
+
+ if (key->sword >= 0)
+ lines->lines[lines->used].keybeg =
+ begfield (&lines->lines[lines->used], key);
+ else
+ {
+ if (key->skipsblanks
+#ifdef SAOMOD_TABLE
+||table
+#endif
+)
+ while (blanks[UCHAR (*beg)])
+ ++beg;
+ lines->lines[lines->used].keybeg = beg;
+ }
+ }
+ else
+ {
+ lines->lines[lines->used].keybeg = 0;
+ lines->lines[lines->used].keylim = 0;
+ }
+
+ ++lines->used;
+ beg = ptr + 1;
+ }
+
+ buf->left = lim - beg;
+}
+
+/* Compare strings A and B containing decimal fractions < 1. Each string
+ should begin with a decimal point followed immediately by the digits
+ of the fraction. Strings not of this form are considered to be zero. */
+
+static int
+fraccompare (a, b)
+ register char *a, *b;
+{
+ register int tmpa = UCHAR (*a), tmpb = UCHAR (*b);
+
+ if (tmpa == '.' && tmpb == '.')
+ {
+ do
+ tmpa = UCHAR (*++a), tmpb = UCHAR (*++b);
+ while (tmpa == tmpb && digits[tmpa]);
+ if (digits[tmpa] && digits[tmpb])
+ return tmpa - tmpb;
+ if (digits[tmpa])
+ {
+ while (tmpa == '0')
+ tmpa = UCHAR (*++a);
+ if (digits[tmpa])
+ return 1;
+ return 0;
+ }
+ if (digits[tmpb])
+ {
+ while (tmpb == '0')
+ tmpb = UCHAR (*++b);
+ if (digits[tmpb])
+ return -1;
+ return 0;
+ }
+ return 0;
+ }
+ else if (tmpa == '.')
+ {
+ do
+ tmpa = UCHAR (*++a);
+ while (tmpa == '0');
+ if (digits[tmpa])
+ return 1;
+ return 0;
+ }
+ else if (tmpb == '.')
+ {
+ do
+ tmpb = UCHAR (*++b);
+ while (tmpb == '0');
+ if (digits[tmpb])
+ return -1;
+ return 0;
+ }
+ return 0;
+}
+
+/* Compare strings A and B as numbers without explicitly converting them to
+ machine numbers. Comparatively slow for short strings, but asymptotically
+ hideously fast. */
+
+static int
+numcompare (a, b)
+ register char *a, *b;
+{
+ register int tmpa, tmpb, loga, logb, tmp;
+
+ tmpa = UCHAR (*a), tmpb = UCHAR (*b);
+
+
+ while (blanks[tmpa])
+ tmpa = UCHAR (*++a);
+ while (blanks[tmpb])
+ tmpb = UCHAR (*++b);
+
+ if (tmpa == '-')
+ {
+ tmpa = UCHAR (*++a);
+ if (tmpb != '-')
+ {
+ if (digits[tmpa] && digits[tmpb])
+ return -1;
+ return 0;
+ }
+ tmpb = UCHAR (*++b);
+
+ while (tmpa == '0')
+ tmpa = UCHAR (*++a);
+ while (tmpb == '0')
+ tmpb = UCHAR (*++b);
+
+ while (tmpa == tmpb && digits[tmpa])
+ tmpa = UCHAR (*++a), tmpb = UCHAR (*++b);
+
+ if ((tmpa == '.' && !digits[tmpb]) || (tmpb == '.' && !digits[tmpa]))
+ return -fraccompare (a, b);
+
+ if (digits[tmpa])
+ for (loga = 1; digits[UCHAR (*++a)]; ++loga)
+ ;
+ else
+ loga = 0;
+
+ if (digits[tmpb])
+ for (logb = 1; digits[UCHAR (*++b)]; ++logb)
+ ;
+ else
+ logb = 0;
+
+ if ((tmp = logb - loga) != 0)
+ return tmp;
+
+ if (!loga)
+ return 0;
+
+ return tmpb - tmpa;
+ }
+ else if (tmpb == '-')
+ {
+ if (digits[UCHAR (tmpa)] && digits[UCHAR (*++b)])
+ return 1;
+ return 0;
+ }
+ else
+ {
+ while (tmpa == '0')
+ tmpa = UCHAR (*++a);
+ while (tmpb == '0')
+ tmpb = UCHAR (*++b);
+
+ while (tmpa == tmpb && digits[tmpa])
+ tmpa = UCHAR (*++a), tmpb = UCHAR (*++b);
+
+ if ((tmpa == '.' && !digits[tmpb]) || (tmpb == '.' && !digits[tmpa]))
+ return fraccompare (a, b);
+
+ if (digits[tmpa])
+ for (loga = 1; digits[UCHAR (*++a)]; ++loga)
+ ;
+ else
+ loga = 0;
+
+ if (digits[tmpb])
+ for (logb = 1; digits[UCHAR (*++b)]; ++logb)
+ ;
+ else
+ logb = 0;
+
+ if ((tmp = loga - logb) != 0)
+ return tmp;
+
+ if (!loga)
+ return 0;
+
+ return tmpa - tmpb;
+ }
+}
+
+/* Return an integer <= 12 associated with month name S with length LEN,
+ 0 if the name in S is not recognized. */
+
+static int
+getmonth (s, len)
+ char *s;
+ int len;
+{
+ char month[4];
+ register int i, lo = 0, hi = 12;
+
+ while (len > 0 && blanks[UCHAR(*s)])
+ ++s, --len;
+
+ if (len < 3)
+ return 0;
+
+ for (i = 0; i < 3; ++i)
+ month[i] = fold_toupper[UCHAR (s[i])];
+ month[3] = '\0';
+
+ while (hi - lo > 1)
+ if (strcmp (month, monthtab[(lo + hi) / 2].name) < 0)
+ hi = (lo + hi) / 2;
+ else
+ lo = (lo + hi) / 2;
+ if (!strcmp (month, monthtab[lo].name))
+ return monthtab[lo].val;
+ return 0;
+}
+
+/* Compare two lines A and B trying every key in sequence until there
+ are no more keys or a difference is found. */
+
+static int
+keycompare (a, b)
+ struct line *a, *b;
+{
+ register char *texta, *textb, *lima, *limb, *translate;
+ register int *ignore;
+ struct keyfield *key;
+ int diff = 0, iter = 0, lena, lenb;
+
+ for (key = keyhead.next; key; key = key->next, ++iter)
+ {
+ ignore = key->ignore;
+ translate = key->translate;
+
+#ifdef SAOMOD_BINARY
+ if ( BinarySort ) {
+ switch ( key->btype ) {
+ case 'c' :
+ case 'b' : {
+ char va, vb;
+
+ va = *((char *) a->text+key->sword);
+ vb = *((char *) b->text+key->sword);
+
+ if ( key->nzone ) {
+ va = (int) (va / key->dzone);
+ vb = (int) (vb / key->dzone);
+ }
+
+ diff = va == vb ? 0 : ( va < vb ? -1 : 1 );
+ break;
+ }
+ case 'C' :
+ case 'B' : {
+ unsigned char va, vb;
+
+ va = *((unsigned char *) a->text+key->sword);
+ vb = *((unsigned char *) b->text+key->sword);
+
+ if ( key->nzone ) {
+ va = (int) (va / key->dzone);
+ vb = (int) (vb / key->dzone);
+ }
+
+ diff = va == vb ? 0 : ( va < vb ? -1 : 1 );
+ break;
+ }
+ case 's' : {
+ short va, vb;
+
+ if ( !iter ) {
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(short));
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(short));
+ if ( key->nzone ) {
+ va = (int) (va / key->dzone);
+ vb = (int) (vb / key->dzone);
+ }
+ } else {
+#ifdef SAOMOD_ASTRO
+ if ( a->flag ) va = a->value;
+ else {
+#endif
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(short));
+ if ( key->nzone ) va = (int) (va / key->dzone);
+#ifdef SAOMOD_ASTRO
+ a->flag = 1;
+ a->value = va;
+ }
+ if ( b->flag ) vb = b->value;
+ else {
+#endif
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(short));
+ if ( key->nzone ) va = (int) (vb / key->dzone);
+#ifdef SAOMOD_ASTRO
+ b->flag = 1;
+ b->value = vb;
+ }
+#endif
+ }
+
+ diff = va == vb ? 0 : ( va < vb ? -1 : 1 );
+ break;
+ }
+ case 'S' : {
+ unsigned short va, vb;
+
+ if ( !iter ) {
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(short));
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(short));
+ if ( key->nzone ) {
+ va = (int) (va / key->dzone);
+ vb = (int) (vb / key->dzone);
+ }
+ } else {
+#ifdef SAOMOD_ASTRO
+ if ( a->flag ) va = a->value;
+ else {
+#endif
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(short));
+ if ( key->nzone ) va = (int) (va / key->dzone);
+#ifdef SAOMOD_ASTRO
+ a->flag = 1;
+ a->value = va;
+ }
+ if ( b->flag ) vb = b->value;
+ else {
+#endif
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(short));
+ if ( key->nzone ) va = (int) (vb / key->dzone);
+#ifdef SAOMOD_ASTRO
+ b->flag = 1;
+ b->value = vb;
+ }
+#endif
+ }
+
+ diff = va == vb ? 0 : ( va < vb ? -1 : 1 );
+ break;
+ }
+ case 'i' : {
+ int va, vb;
+
+ if ( !iter ) {
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(int));
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(int));
+ if ( key->nzone ) {
+ va = (int) (va / key->dzone);
+ vb = (int) (vb / key->dzone);
+ }
+ } else {
+#ifdef SAOMOD_ASTRO
+ if ( a->flag ) va = a->value;
+ else {
+#endif
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(int));
+ if ( key->nzone ) va = (int) (va / key->dzone);
+#ifdef SAOMOD_ASTRO
+ a->flag = 1;
+ a->value = va;
+ }
+ if ( b->flag ) vb = b->value;
+ else {
+#endif
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(int));
+ if ( key->nzone ) va = (int) (vb / key->dzone);
+#ifdef SAOMOD_ASTRO
+ b->flag = 1;
+ b->value = vb;
+ }
+#endif
+ }
+
+ diff = va == vb ? 0 : ( va < vb ? -1 : 1 );
+ break;
+ }
+ case 'l' : {
+ longlong va, vb;
+#if HAVE_LONG_LONG == 0
+ fprintf (stderr, "long long support was not built into this program\n");
+ exit(1);
+#endif
+ if ( !iter ) {
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(longlong));
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(longlong));
+ if ( key->nzone ) {
+ va = (longlong) (va / key->dzone);
+ vb = (longlong) (vb / key->dzone);
+ }
+ } else {
+#ifdef SAOMOD_ASTRO
+ if ( a->flag ) va = a->value;
+ else {
+#endif
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(longlong));
+ if ( key->nzone ) va = (longlong) (va / key->dzone);
+#ifdef SAOMOD_ASTRO
+ a->flag = 1;
+ a->value = va;
+ }
+ if ( b->flag ) vb = b->value;
+ else {
+#endif
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(longlong));
+ if ( key->nzone ) va = (longlong) (vb / key->dzone);
+#ifdef SAOMOD_ASTRO
+ b->flag = 1;
+ b->value = vb;
+ }
+#endif
+ }
+
+ diff = va == vb ? 0 : ( va < vb ? -1 : 1 );
+ break;
+ }
+ case 'I' : {
+ unsigned int va, vb;
+
+ if ( !iter ) {
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(int));
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(int));
+ if ( key->nzone ) {
+ va = (int) (va / key->dzone);
+ vb = (int) (vb / key->dzone);
+ }
+ } else {
+#ifdef SAOMOD_ASTRO
+ if ( a->flag ) va = a->value;
+ else {
+#endif
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(int));
+ if ( key->nzone ) va = (int) (va / key->dzone);
+#ifdef SAOMOD_ASTRO
+ a->flag = 1;
+ a->value = va;
+ }
+ if ( b->flag ) vb = b->value;
+ else {
+#endif
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(int));
+ if ( key->nzone ) va = (int) (vb / key->dzone);
+#ifdef SAOMOD_ASTRO
+ b->flag = 1;
+ b->value = vb;
+ }
+#endif
+ }
+
+ diff = va == vb ? 0 : ( va < vb ? -1 : 1 );
+ break;
+ }
+ case 'f' : {
+ float va, vb;
+
+ if ( !iter ) {
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(float));
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(float));
+ if ( key->nzone ) {
+ va = (int) (va / key->dzone);
+ vb = (int) (vb / key->dzone);
+ }
+ } else {
+#ifdef SAOMOD_ASTRO
+ if ( a->flag ) va = a->value;
+ else {
+#endif
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(float));
+ if ( key->nzone ) va = (int) (va / key->dzone);
+#ifdef SAOMOD_ASTRO
+ a->flag = 1;
+ a->value = va;
+ }
+ if ( b->flag ) vb = b->value;
+ else {
+#endif
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(float));
+ if ( key->nzone ) va = (int) (vb / key->dzone);
+#ifdef SAOMOD_ASTRO
+ b->flag = 1;
+ b->value = vb;
+ }
+#endif
+ }
+
+ diff = va == vb ? 0 : ( va < vb ? -1 : 1 );
+ break;
+ }
+ case 'd' : {
+ double va, vb;
+
+ if ( !iter ) {
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(double));
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(double));
+ if ( key->nzone ) {
+ va = (int) (va / key->dzone);
+ vb = (int) (vb / key->dzone);
+ }
+ } else {
+#ifdef SAOMOD_ASTRO
+ if ( a->flag ) va = a->value;
+ else {
+#endif
+ memcpy(&va, (void *) (a->text+key->sword), sizeof(double));
+ if ( key->nzone ) va = (int) (va / key->dzone);
+#ifdef SAOMOD_ASTRO
+ a->flag = 1;
+ a->value = va;
+ }
+ if ( b->flag ) vb = b->value;
+ else {
+#endif
+ memcpy(&vb, (void *) (b->text+key->sword), sizeof(double));
+ if ( key->nzone ) va = (int) (vb / key->dzone);
+#ifdef SAOMOD_ASTRO
+ b->flag = 1;
+ b->value = vb;
+ }
+#endif
+ }
+
+ diff = va == vb ? 0 : ( va < vb ? -1 : 1 );
+ break;
+ }
+ case 't' : {
+ diff = strncmp(a->text+key->sword, b->text+key->sword, key->schar);
+ break;
+ }
+ default:
+ fprintf(stderr, "Bad type in binary value compare\n");
+ cleanup();
+ abort();
+ }
+
+ if ( diff ) return diff;
+ continue;
+ }
+#endif
+
+ /* Find the beginning and limit of each field. */
+ if (iter || a->keybeg == NULL || b->keybeg == NULL)
+ {
+ if ( key->eword >= 0
+#ifdef SAOMOD_TABLE
+|| table
+#endif
+ ) {
+ lima = limfield (a, key);
+ limb = limfield (b, key);
+ } else {
+ lima = a->text + a->length;
+ limb = b->text + b->length;
+ }
+
+ if (key->sword >= 0) {
+ texta = begfield (a, key); textb = begfield (b, key);
+ } else {
+ texta = a->text; textb = b->text;
+ if (key->skipsblanks
+#ifdef SAOMOD_TABLE
+||table
+#endif
+)
+ {
+ while (texta < lima && blanks[UCHAR (*texta)])
+ ++texta;
+ while (textb < limb && blanks[UCHAR (*textb)])
+ ++textb;
+ }
+ }
+ }
+ else
+ {
+ /* For the first iteration only, the key positions have
+ been precomputed for us. */
+ texta = a->keybeg; lima = a->keylim;
+ textb = b->keybeg; limb = b->keylim;
+ }
+
+ /* Find the lengths. */
+ lena = lima - texta; lenb = limb - textb;
+ if (lena < 0)
+ lena = 0;
+ if (lenb < 0)
+ lenb = 0;
+
+ /* Actually compare the fields. */
+ if ( key->numeric ) {
+#ifdef SAOMOD_FIX
+ if ( *texta != '+' && *texta != '-' && !ISDIGIT((int)*texta) ) {
+ if ( *textb != '+' && *textb != '-' && !ISDIGIT((int)*textb) ) {
+ diff = memcmp (texta, textb, min(lena, lenb));
+ } else {
+ diff = 1;
+ }
+ } else
+ if ( *textb != '+' && *textb != '-' && !ISDIGIT((int)*textb) ) {
+ diff = -1;
+ } else
+#endif
+#ifdef SAOMOD_ASTRO
+ if ( key->numeric == 2 || key->numeric == 3 ) {
+ double va;
+ double vb;
+
+ static int x = 0;
+
+ if ( iter ) {
+ if (*lima || *limb) {
+ char savea = *lima;
+ char saveb = *limb;
+
+ *lima = *limb = '\0';
+
+ if ( key->numeric == 2 ) {
+ va = SAOstrtod(texta, NULL);
+ vb = SAOstrtod(textb, NULL);
+ } else {
+ va = mjd(texta, 0);
+ vb = mjd(textb, 0);
+ }
+
+ *lima = savea; *limb = saveb;
+ } else {
+ if ( key->numeric == 2 ) {
+ va = SAOstrtod(texta, NULL);
+ vb = SAOstrtod(textb, NULL);
+ } else {
+ va = mjd(texta, 0);
+ vb = mjd(textb, 0);
+ }
+ }
+ } else {
+ if ( a->flag ) va = a->value;
+ else {
+ char savea = *lima;
+
+ *lima = '\0';
+ if ( key->numeric == 2 ) {
+ va = a->value = SAOstrtod(texta, NULL);
+ } else {
+ va = mjd(texta, 0);
+ }
+ *lima = savea;
+ a->flag++;
+
+ }
+ if ( b->flag ) vb = b->value;
+ else {
+ char saveb = *limb;
+
+ *limb = '\0';
+ if ( key->numeric == 2 ) {
+ vb = b->value = SAOstrtod(textb, NULL);
+ } else {
+ vb = mjd(textb, 0);
+ }
+ *limb = saveb;
+ b->flag++;
+ }
+ }
+
+ if ( key->nzone ) {
+ va = (int) (va / key->dzone);
+ vb = (int) (vb / key->dzone);
+ }
+
+ diff = (va < vb) ? -1 : ((va == vb) ? 0 : 1);
+
+ if ( diff )
+ return key->reverse ? -diff : diff;
+ continue;
+ } else
+#endif
+ if ( key->numeric == 1 )
+ {
+ if (*lima || *limb)
+ {
+ char savea = *lima; char saveb = *limb;
+
+ *lima = *limb = '\0';
+
+ diff = numcompare (texta, textb);
+ *lima = savea, *limb = saveb;
+ }
+ else {
+ diff = numcompare (texta, textb);
+ }
+
+
+ if (diff)
+ return key->reverse ? -diff : diff;
+ continue;
+ }
+#ifdef SAOMOD_FIX
+ if (diff) /* This catches the text diffs */
+ return key->reverse ? -diff : diff;
+#endif
+ }
+ else if (key->month)
+ {
+ diff = getmonth (texta, lena) - getmonth (textb, lenb);
+ if (diff)
+ return key->reverse ? -diff : diff;
+ continue;
+ }
+ else if (ignore && translate)
+ while (texta < lima && textb < limb)
+ {
+ while (texta < lima && ignore[UCHAR (*texta)])
+ ++texta;
+ while (textb < limb && ignore[UCHAR (*textb)])
+ ++textb;
+ if (texta < lima && textb < limb &&
+ translate[UCHAR (*texta++)] != translate[UCHAR (*textb++)])
+ {
+ diff = translate[UCHAR (*--texta)] - translate[UCHAR (*--textb)];
+ break;
+ }
+ else if (texta == lima && textb < limb) diff = -1;
+ else if (texta < lima && textb == limb) diff = 1;
+ }
+ else if (ignore)
+ while (texta < lima && textb < limb)
+ {
+ while (texta < lima && ignore[UCHAR (*texta)])
+ ++texta;
+ while (textb < limb && ignore[UCHAR (*textb)])
+ ++textb;
+ if (texta < lima && textb < limb && *texta++ != *textb++)
+ {
+ diff = *--texta - *--textb;
+ break;
+ }
+ else if (texta == lima && textb < limb) diff = -1;
+ else if (texta < lima && textb == limb) diff = 1;
+ }
+ else if (translate)
+ while (texta < lima && textb < limb)
+ {
+ if (translate[UCHAR (*texta++)] != translate[UCHAR (*textb++)])
+ {
+ diff = translate[UCHAR (*--texta)] - translate[UCHAR (*--textb)];
+ break;
+ }
+ }
+ else
+ diff = memcmp (texta, textb, min (lena, lenb));
+
+ if (diff)
+ return key->reverse ? -diff : diff;
+ if ((diff = lena - lenb) != 0)
+ return key->reverse ? -diff : diff;
+ }
+
+ return 0;
+}
+
+/* Compare two lines A and B, returning negative, zero, or positive
+ depending on whether A compares less than, equal to, or greater than B. */
+
+static int
+compare (a, b)
+ register struct line *a, *b;
+{
+ int diff, tmpa, tmpb, mini;
+
+ /* First try to compare on the specified keys (if any).
+ The only two cases with no key at all are unadorned sort,
+ and unadorned sort -r. */
+ if (keyhead.next)
+ {
+ diff = keycompare (a, b);
+ if (diff != 0)
+ return diff;
+ if (unique || stable)
+ return 0;
+ }
+
+ /* If the keys all compare equal (or no keys were specified)
+ fall through to the default byte-by-byte comparison. */
+ tmpa = a->length, tmpb = b->length;
+ mini = min (tmpa, tmpb);
+ if (mini == 0)
+ diff = tmpa - tmpb;
+ else
+ {
+ char *ap = a->text, *bp = b->text;
+
+ diff = UCHAR (*ap) - UCHAR (*bp);
+ if (diff == 0)
+ {
+ diff = memcmp (ap, bp, mini);
+ if (diff == 0)
+ diff = tmpa - tmpb;
+ }
+ }
+
+ return reverse ? -diff : diff;
+}
+
+/* Check that the lines read from the given FP come in order. Return
+ 1 if they do and 0 if there is a disorder. */
+
+static int line;
+static int
+checkfp (fp)
+ FILE *fp;
+{
+ struct buffer buf; /* Input buffer. */
+ struct lines lines; /* Lines scanned from the buffer. */
+ struct line *prev_line; /* Pointer to previous line. */
+ struct line temp; /* Copy of previous line. */
+ int cc; /* Character count. */
+ int cmp; /* Result of calling compare. */
+ int alloc, i, success = 1;
+
+ initbuf (&buf, mergealloc);
+ initlines (&lines, mergealloc / linelength + 1,
+ LINEALLOC / ((NMERGE + NMERGE) * sizeof (struct line)));
+ alloc = linelength;
+ temp.text = xmalloc (alloc);
+
+ cc = fillbuf (&buf, fp);
+ findlines (&buf, &lines);
+
+ if (cc)
+ do
+ {
+
+ /* Compare each line in the buffer with its successor. */
+ for (i = 0; i < lines.used - 1; ++i)
+ {
+ line++;
+ cmp = compare (&lines.lines[i], &lines.lines[i + 1]);
+ if ((unique && cmp >= 0) || (cmp > 0))
+ {
+ success = 0;
+ goto finish;
+ }
+ }
+
+ /* Save the last line of the buffer and refill the buffer. */
+ prev_line = lines.lines + lines.used - 1;
+ if (prev_line->length > alloc)
+ {
+ while (prev_line->length + 1 > alloc)
+ alloc *= 2;
+ temp.text = xrealloc (temp.text, alloc);
+ }
+ memcpy (temp.text, prev_line->text, prev_line->length + 1);
+ temp.length = prev_line->length;
+ temp.keybeg = temp.text + (prev_line->keybeg - prev_line->text);
+ temp.keylim = temp.text + (prev_line->keylim - prev_line->text);
+#ifdef SAOMOD_ASTRO
+ temp.flag = prev_line->flag;
+ temp.value = prev_line->value;
+#endif
+
+ cc = fillbuf (&buf, fp);
+ if (cc)
+ {
+ findlines (&buf, &lines);
+ /* Make sure the line saved from the old buffer contents is
+ less than or equal to the first line of the new buffer. */
+ cmp = compare (&temp, &lines.lines[0]);
+ if ((unique && cmp >= 0) || (cmp > 0))
+ {
+ success = 0;
+ break;
+ }
+ }
+ }
+ while (cc);
+
+finish:
+ xfclose (fp);
+ free (buf.buf);
+ free ((char *) lines.lines);
+ free (temp.text);
+ return success;
+}
+
+/* Merge lines from FPS onto OFP. NFPS cannot be greater than NMERGE.
+ Close FPS before returning. */
+
+static void
+mergefps (fps, nfps, ofp)
+ FILE *fps[], *ofp;
+ register int nfps;
+{
+ struct buffer buffer[NMERGE]; /* Input buffers for each file. */
+ struct lines lines[NMERGE]; /* Line tables for each buffer. */
+ struct line saved; /* Saved line for unique check. */
+ int savedflag = 0; /* True if there is a saved line. */
+ int savealloc = 0; /* Size allocated for the saved line. */
+ int cur[NMERGE]; /* Current line in each line table. */
+ int ord[NMERGE]; /* Table representing a permutation of fps,
+ such that lines[ord[0]].lines[cur[ord[0]]]
+ is the smallest line and will be next
+ output. */
+ register int i, j, t;
+
+ /* Allocate space for a saved line if necessary. */
+ if (unique)
+ {
+ savealloc = linelength;
+ saved.text = xmalloc (savealloc);
+#ifdef SAOMOD_ASTRO
+ saved.flag = 0;
+#endif
+ }
+
+ /* Read initial lines from each input file. */
+ for (i = 0; i < nfps; ++i)
+ {
+ initbuf (&buffer[i], mergealloc);
+ /* If a file is empty, eliminate it from future consideration. */
+ while (i < nfps && !fillbuf (&buffer[i], fps[i]))
+ {
+ xfclose (fps[i]);
+ --nfps;
+ for (j = i; j < nfps; ++j)
+ fps[j] = fps[j + 1];
+ }
+ if (i == nfps)
+ free (buffer[i].buf);
+ else
+ {
+ initlines (&lines[i], mergealloc / linelength + 1,
+ LINEALLOC / ((NMERGE + NMERGE) * sizeof (struct line)));
+ findlines (&buffer[i], &lines[i]);
+ cur[i] = 0;
+ }
+ }
+
+ /* Set up the ord table according to comparisons among input lines.
+ Since this only reorders two items if one is strictly greater than
+ the other, it is stable. */
+ for (i = 0; i < nfps; ++i)
+ ord[i] = i;
+ for (i = 1; i < nfps; ++i)
+ if (compare (&lines[ord[i - 1]].lines[cur[ord[i - 1]]],
+ &lines[ord[i]].lines[cur[ord[i]]]) > 0)
+ t = ord[i - 1], ord[i - 1] = ord[i], ord[i] = t, i = 0;
+
+ /* Repeatedly output the smallest line until no input remains. */
+ while ( nfps )
+ {
+ /* If uniqified output is turned on, output only the last of
+ an identical series of lines. */
+ if (unique)
+ { int cmp;
+
+ if ( savedflag ) {
+ cmp = compare (&saved, &lines[ord[0]].lines[cur[ord[0]]]);
+
+ if ( !cmp ) {
+ savedflag++;
+ } else {
+ if ( savedflag >= 1 ) {
+ if ( !differ ) {
+ if ( countr )
+ fprintf(ofp, "%d\t", savedflag);
+ xfwrite (saved.text, 1, saved.length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ } else {
+ if ( (differ == 1 && savedflag == 1)
+ || (differ == 2 && savedflag >= 2) ) {
+ xfwrite (saved.text, 1, saved.length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ }
+ }
+
+ if ( differ == 3 ) setcnt++;
+
+ savedflag = 0;
+ }
+ }
+ }
+
+ if ( !savedflag) {
+ if (savealloc < lines[ord[0]].lines[cur[ord[0]]].length + 1)
+ {
+ while (savealloc < lines[ord[0]].lines[cur[ord[0]]].length + 1)
+ savealloc *= 2;
+ saved.text = xrealloc (saved.text, savealloc);
+ }
+ saved.length = lines[ord[0]].lines[cur[ord[0]]].length;
+ memcpy (saved.text, lines[ord[0]].lines[cur[ord[0]]].text,
+ saved.length + 1);
+ if (lines[ord[0]].lines[cur[ord[0]]].keybeg != NULL)
+ {
+ saved.keybeg = saved.text +
+ (lines[ord[0]].lines[cur[ord[0]]].keybeg
+ - lines[ord[0]].lines[cur[ord[0]]].text);
+ }
+ if (lines[ord[0]].lines[cur[ord[0]]].keylim != NULL)
+ {
+ saved.keylim = saved.text +
+ (lines[ord[0]].lines[cur[ord[0]]].keylim
+ - lines[ord[0]].lines[cur[ord[0]]].text);
+ }
+
+#ifdef SAOMOD_ASTRO
+ saved.flag = lines[ord[0]].lines[cur[ord[0]]].flag;
+ saved.value = lines[ord[0]].lines[cur[ord[0]]].value;
+#endif
+
+ savedflag = 1;
+ }
+
+ if ( differ == 3 ) {
+ fprintf(ofp, "%d\t", setcnt);
+ xfwrite (lines[ord[0]].lines[cur[ord[0]]].text, 1,
+ lines[ord[0]].lines[cur[ord[0]]].length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ }
+
+ if ( savedflag >= 2 && differ == 4 ) {
+ if ( savedflag == 2 ) {
+ xfwrite (saved.text, 1,
+ saved.length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ }
+ xfwrite (lines[ord[0]].lines[cur[ord[0]]].text, 1,
+ lines[ord[0]].lines[cur[ord[0]]].length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ }
+
+ }
+
+ else {
+ xfwrite (lines[ord[0]].lines[cur[ord[0]]].text, 1,
+ lines[ord[0]].lines[cur[ord[0]]].length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ }
+
+ /* Check if we need to read more lines into core. */
+ if (++cur[ord[0]] == lines[ord[0]].used){
+ if (fillbuf (&buffer[ord[0]], fps[ord[0]]))
+ {
+ findlines (&buffer[ord[0]], &lines[ord[0]]);
+ cur[ord[0]] = 0;
+ }
+ else
+ {
+ /* We reached EOF on fps[ord[0]]. */
+ for (i = 1; i < nfps; ++i)
+ if (ord[i] > ord[0])
+ --ord[i];
+ --nfps;
+ xfclose (fps[ord[0]]);
+ free (buffer[ord[0]].buf);
+ free ((char *) lines[ord[0]].lines);
+ for (i = ord[0]; i < nfps; ++i)
+ {
+ fps[i] = fps[i + 1];
+ buffer[i] = buffer[i + 1];
+ lines[i] = lines[i + 1];
+ cur[i] = cur[i + 1];
+ }
+ for (i = 0; i < nfps; ++i)
+ ord[i] = ord[i + 1];
+ continue;
+ }
+ }
+ /* The new line just read in may be larger than other lines
+ already in core; push it back in the queue until we encounter
+ a line larger than it. */
+ for (i = 1; i < nfps; ++i)
+ {
+ t = compare (&lines[ord[0]].lines[cur[ord[0]]],
+ &lines[ord[i]].lines[cur[ord[i]]]);
+ if (!t)
+ t = ord[0] - ord[i];
+ if (t < 0)
+ break;
+ }
+ t = ord[0];
+ for (j = 1; j < i; ++j)
+ ord[j - 1] = ord[j];
+ ord[i - 1] = t;
+ }
+
+ if (unique && savedflag)
+ {
+ if ( !differ && savedflag >= 1 )
+ {
+ if ( countr )
+ fprintf(ofp, "%d\t", savedflag);
+
+ xfwrite (saved.text, 1, saved.length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ }
+
+ if ( (differ == 1 && savedflag == 1)
+ || (differ == 2 && savedflag >= 2) ) {
+ xfwrite (saved.text, 1,
+ saved.length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ }
+
+ free (saved.text);
+ }
+}
+
+/* Sort the array LINES with NLINES members, using TEMP for temporary space. */
+
+static void
+sortlines (lines, nlines, temp)
+ struct line *lines, *temp;
+ int nlines;
+{
+ register struct line *lo, *hi, *t;
+ register int nlo, nhi;
+
+ if (nlines == 2)
+ {
+ if (compare (&lines[0], &lines[1]) > 0)
+ *temp = lines[0], lines[0] = lines[1], lines[1] = *temp;
+ return;
+ }
+
+ nlo = nlines / 2;
+ lo = lines;
+ nhi = nlines - nlo;
+ hi = lines + nlo;
+
+ if (nlo > 1)
+ sortlines (lo, nlo, temp);
+
+ if (nhi > 1)
+ sortlines (hi, nhi, temp);
+
+ t = temp;
+
+ while (nlo && nhi)
+ if (compare (lo, hi) <= 0)
+ *t++ = *lo++, --nlo;
+ else
+ *t++ = *hi++, --nhi;
+ while (nlo--)
+ *t++ = *lo++;
+
+ for (lo = lines, nlo = nlines - nhi, t = temp; nlo; --nlo)
+ *lo++ = *t++;
+}
+
+/* Check that each of the NFILES FILES is ordered.
+ Return a count of disordered files. */
+
+
+static int
+check (files, nfiles)
+ char *files[];
+ int nfiles;
+{
+ int i, disorders = 0;
+ FILE *fp;
+
+ for (i = 0; i < nfiles; ++i)
+ {
+ fp = xfopen (files[i], "r");
+ line = 0;
+ if (!checkfp (fp))
+ {
+ printf ("%s: disorder on %s at line %d\n", program_name, files[i]
+ , line);
+ ++disorders;
+ }
+ }
+ return disorders;
+}
+
+/* Merge NFILES FILES onto OFP. */
+
+static void
+merge (files, nfiles, ofp)
+ char *files[];
+ int nfiles;
+ FILE *ofp;
+{
+ int i, j, t;
+ char *temp;
+ FILE *fps[NMERGE], *tfp;
+
+#ifdef SAOMOD_TABLE
+ static TableHead TH = NULL;
+ TableHead th;
+#endif
+
+ int saveunique = unique;
+
+ unique = 0;
+
+ while (nfiles > NMERGE)
+ {
+ t = 0;
+ for (i = 0; i < nfiles / NMERGE; ++i)
+ {
+ for (j = 0; j < NMERGE; ++j) {
+ fps[j] = xfopen (files[i * NMERGE + j], "r");
+#ifdef SAOMOD_TABLE
+ if ( table == 2 ) {
+ if ( TH == NULL ) TH = table_header(fps[j], TABLE_PARSE);
+ else {
+ int k;
+
+ th = table_header(fps[j], TABLE_PARSE);
+ for ( k = 0; k < table_ncol(TH); k++ )
+ if ( strcmp(table_colnam(TH, k + 1), table_colnam(th, k + 1)) ) {
+ fprintf(stderr, "sorttable: can't merge tables with different column definitions: \"%\"s != \"%s\"\n", table_colnam(TH, k+1), table_colnam(th, k+1));
+ exit(1);
+ }
+ table_hdrfree(th);
+ }
+ }
+#endif
+ }
+
+
+ tfp = xfopen (temp = tempname (), "w");
+ mergefps (fps, NMERGE, tfp);
+ xfclose (tfp);
+ for (j = 0; j < NMERGE; ++j)
+ zaptemp (files[i * NMERGE + j]);
+ files[t++] = temp;
+ }
+
+ for (j = 0; j < nfiles % NMERGE; ++j) {
+ fps[j] = xfopen (files[i * NMERGE + j], "r");
+#ifdef SAOMOD_TABLE
+ if ( table == 2 ) {
+ if ( TH == NULL ) TH = table_header(fps[j], TABLE_PARSE);
+ else {
+ int k;
+
+ th = table_header(fps[j], TABLE_PARSE);
+ for ( k = 0; k < table_ncol(TH); k++ )
+ if ( strcmp(table_colnam(TH, k + 1), table_colnam(th, k + 1)) ) {
+ fprintf(stderr, "sorttable: can't merge tables with different column definitions: \"%s\" != \"%s\"\n", table_colnam(TH, k+1), table_colnam(th, k+1));
+ exit(1);
+ }
+ table_hdrfree(th);
+ }
+ }
+#endif
+ }
+
+
+ tfp = xfopen (temp = tempname (), "w");
+ mergefps (fps, nfiles % NMERGE, tfp);
+ xfclose (tfp);
+ for (j = 0; j < nfiles % NMERGE; ++j)
+ zaptemp (files[i * NMERGE + j]);
+ files[t++] = temp;
+ nfiles = t;
+ }
+
+ for (i = 0; i < nfiles; ++i) {
+ fps[i] = xfopen (files[i], "r");
+#ifdef SAOMOD_TABLE
+ if ( table == 2 ) {
+ if ( TH == NULL ) TH = table_header(fps[i], TABLE_PARSE);
+ else {
+ int k;
+
+ th = table_header(fps[i], TABLE_PARSE);
+ for ( k = 0; k < table_ncol(TH); k++ ) {
+ if ( strcmp(table_colnam(TH, k + 1), table_colnam(th, k + 1)) ) {
+ fprintf(stderr, "sorttable: can't merge tables with different column definitions: \"%s\" != \"%s\"\n", table_colnam(TH, k+1), table_colnam(th, k+1));
+ exit(1);
+ }
+ }
+ table_hdrfree(th);
+ }
+ }
+#endif
+ }
+
+ unique = saveunique;
+ mergefps (fps, i, ofp);
+ for (i = 0; i < nfiles; ++i)
+ zaptemp (files[i]);
+}
+
+/* Sort NFILES FILES onto OFP. */
+
+static void
+sort (files, nfiles, ofp)
+ char **files;
+ int nfiles;
+ FILE *ofp;
+{
+ struct buffer buf;
+ struct lines lines;
+ struct line saved; /* Saved line for unique check. */
+ int savedflag = 0;
+ int savealloc = 0; /* Size allocated for the saved line. */
+ struct line *tmp;
+ int i, ntmp;
+ FILE *fp, *tfp;
+ struct tempnode *node;
+ int ntemp = 0;
+ char **tempfiles;
+
+ initbuf (&buf, sortalloc);
+ initlines (&lines, sortalloc / linelength + 1,
+ LINEALLOC / sizeof (struct line));
+ ntmp = lines.alloc;
+ tmp = (struct line *) xmalloc (ntmp * sizeof (struct line));
+
+ /* Allocate space for a saved line if necessary. */
+ if (unique)
+ {
+ savealloc = linelength;
+ saved.text = xmalloc (savealloc);
+#ifdef SAOMOD_ASTRO
+ saved.flag = 0;
+#endif
+ }
+
+ while (nfiles--)
+ {
+ fp = xfopen (*files++, "r");
+ while (fillbuf (&buf, fp))
+ {
+ findlines (&buf, &lines);
+ if (lines.used > ntmp)
+ {
+ while (lines.used > ntmp)
+ ntmp *= 2;
+ tmp = (struct line *)
+ xrealloc ((char *) tmp, ntmp * sizeof (struct line));
+ }
+ sortlines (lines.lines, lines.used, tmp);
+ if (feof (fp) && !nfiles && !ntemp && !buf.left)
+ tfp = ofp;
+ else
+ {
+ ++ntemp;
+ tfp = xfopen (tempname (), "w");
+ }
+ if ( !unique || tfp != ofp )
+ for (i = 0; i < lines.used; ++i) {
+ xfwrite (lines.lines[i].text, 1, lines.lines[i].length, tfp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', tfp);
+#endif
+ }
+ else {
+ for (i = 0; i < lines.used; ++i) {
+ int cmp;
+
+ if ( savedflag ) {
+ cmp = compare (&saved, &lines.lines[i]);
+
+ if ( !cmp ) {
+ savedflag++;
+ } else {
+ if ( savedflag >= 1 ) {
+ if ( !differ ) {
+ if ( countr )
+ fprintf(ofp, "%d\t", savedflag);
+ xfwrite (saved.text, 1, saved.length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ } else {
+ if ( (differ == 1 && savedflag == 1)
+ || (differ == 2 && savedflag >= 2) ) {
+ xfwrite (saved.text, 1, saved.length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ }
+ }
+
+ if ( differ == 3 ) setcnt++;
+ savedflag = 0;
+ }
+ }
+ }
+
+ if ( !savedflag) {
+ if (savealloc < lines.lines[i].length + 1)
+ {
+ while (savealloc < lines.lines[i].length + 1)
+ savealloc *= 2;
+ saved.text = xrealloc (saved.text, savealloc);
+ }
+ saved.length = lines.lines[i].length;
+ memcpy (saved.text, lines.lines[i].text,
+ saved.length + 1);
+ if (lines.lines[i].keybeg != NULL)
+ {
+ saved.keybeg = saved.text +
+ (lines.lines[i].keybeg - lines.lines[i].text);
+ }
+ if (lines.lines[i].keylim != NULL)
+ {
+ saved.keylim = saved.text +
+ (lines.lines[i].keylim - lines.lines[i].text);
+ }
+
+#ifdef SAOMOD_ASTRO
+ saved.flag = lines.lines[i].flag;
+ saved.value = lines.lines[i].value;
+#endif
+
+ savedflag = 1;
+ }
+
+ if ( differ == 3 ) {
+ fprintf(ofp, "%d\t", setcnt);
+ xfwrite (lines.lines[i].text, 1, lines.lines[i].length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ }
+
+ if ( savedflag >= 2 && differ == 4 ) {
+ if ( savedflag == 2 ) {
+ xfwrite (saved.text, 1,
+ saved.length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ }
+ xfwrite (lines.lines[i].text, 1, lines.lines[i].length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ }
+
+ }
+ }
+ if (tfp != ofp)
+ xfclose (tfp);
+ }
+ xfclose (fp);
+ }
+
+ if (unique && savedflag)
+ {
+ if ( !differ && savedflag >= 1 )
+ {
+ if ( countr )
+ fprintf(ofp, "%d\t", savedflag);
+
+ xfwrite (saved.text, 1, saved.length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ }
+
+ if ( (differ == 1 && savedflag == 1)
+ || (differ == 2 && savedflag >= 2) ) {
+ xfwrite (saved.text, 1,
+ saved.length, ofp);
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) putc ('\n', ofp);
+#endif
+ }
+
+ free (saved.text);
+ }
+
+ free (buf.buf);
+ free ((char *) lines.lines);
+ free ((char *) tmp);
+
+ if (ntemp)
+ {
+ tempfiles = (char **) xmalloc (ntemp * sizeof (char *));
+ i = ntemp;
+ for (node = temphead.next; i > 0; node = node->next)
+ tempfiles[--i] = node->name;
+ merge (tempfiles, ntemp, ofp);
+ free ((char *) tempfiles);
+ }
+}
+
+/* Insert key KEY at the end of the list (`keyhead'). */
+
+static void
+insertkey (key)
+ struct keyfield *key;
+{
+ struct keyfield *k = &keyhead;
+
+ while (k->next)
+ k = k->next;
+ k->next = key;
+ key->next = NULL;
+}
+
+static void
+badfieldspec (s)
+ char *s;
+{
+ fprintf (stderr, "invalid field specification `%s'", s);
+ exit(2);
+}
+
+/* Handle interrupts and hangups. */
+
+static void
+sighandler (sig)
+ int sig;
+{
+#ifdef _POSIX_VERSION
+ struct sigaction sigact;
+
+ sigact.sa_handler = SIG_DFL;
+ sigemptyset (&sigact.sa_mask);
+ sigact.sa_flags = 0;
+ sigaction (sig, &sigact, NULL);
+#else /* !_POSIX_VERSION */
+ signal (sig, SIG_DFL);
+#endif /* _POSIX_VERSION */
+ cleanup ();
+#if HAVE_MINGW32==0
+ kill (getpid (), sig);
+#else
+ exit(1);
+#endif
+}
+
+/* Set the ordering options for KEY specified in S.
+ Return the address of the first character in S that
+ is not a valid ordering option.
+ BLANKTYPE is the kind of blanks that 'b' should skip. */
+
+static char *
+set_ordering (s, key, blanktype)
+ char *s;
+ struct keyfield *key;
+ enum blanktype blanktype;
+{
+ while (*s)
+ {
+ switch (*s)
+ {
+ case 'b':
+ if (blanktype == bl_start || blanktype == bl_both)
+ key->skipsblanks = 1;
+ if (blanktype == bl_end || blanktype == bl_both)
+ key->skipeblanks = 1;
+ break;
+ case 'd':
+ key->ignore = nondictionary;
+ break;
+ case 'f':
+ key->translate = fold_toupper;
+ break;
+#if 0
+ case 'g':
+ /* Reserved for comparing floating-point numbers. */
+ break;
+#endif
+ case 'i':
+ key->ignore = nonprinting;
+ break;
+ case 'M':
+ key->month = 1;
+ break;
+ case 'n':
+ key->nzone = 0;
+ key->numeric = 1;
+ break;
+#ifdef SAOMOD_ASTRO
+ case 'h':
+ key->nzone = 0;
+ key->numeric = 2;
+ break;
+#endif
+ case 'q':
+ key->nzone = 0;
+ key->numeric = 3;
+ break;
+#ifdef SAOMOD_ASTRO
+ case 'z':
+ key->nzone = 1;
+ key->numeric = 2;
+ s++;
+ key->dzone = SAOstrtod(s, &s);
+ s--;
+ break;
+#endif
+ case 'r':
+ key->reverse = 1;
+ break;
+ default:
+ return s;
+ }
+ ++s;
+ }
+ return s;
+}
+
+int main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct keyfield *key = NULL, gkey;
+ char *s;
+ int i, t, t2;
+ int checkonly = 0, mergeonly = 0, nfiles = 0;
+ char *minus = "-", *outfile = minus, **files, *tmp;
+ FILE *ofp;
+#ifdef _POSIX_VERSION
+ struct sigaction oldact, newact;
+#endif /* _POSIX_VERSION */
+#ifdef SAOMOD_FIX
+ int pipes[4];
+ char *ss=NULL, *tt=NULL, *uu=NULL;
+#endif
+
+ program_name = argv[0];
+
+#ifdef SAOMOD_FIX
+ /* Launch() sometimes rearranges passed pipes to be stdin/stdout */
+ if( (ss=getenv("LAUNCH_PIPES")) ){
+ tt = (char *)strdup(ss);
+ for(i=0, uu=(char *)strtok(tt, ","); i<4 && uu;
+ i++, uu=(char *)strtok(NULL,",")){
+ pipes[i] = atoi(uu);
+ }
+ if( tt ) free(tt);
+ if( i < 4 ) return(1);
+ close(pipes[0]);
+ close(pipes[3]);
+ dup2(pipes[2], 0); close(pipes[2]);
+ dup2(pipes[1], 1); close(pipes[1]);
+ }
+#endif
+
+#ifdef SAOMOD_FIX
+ if ( (program_name = (char *)strrchr(program_name, '/')) )
+ program_name++;
+ else
+ program_name = argv[0];
+#endif
+
+#ifdef SAOMOD_TABLE
+ if ( strstr(program_name, "table") ) {
+ table = 1;
+ tab = '\t';
+ }
+#endif
+
+#ifdef SAOMOD_FIX
+ /* Ask for a stable sort
+ */
+ stable = 1;
+#endif
+
+ have_read_stdin = 0;
+ inittables ();
+
+ temp_file_prefix = getenv ("TMPDIR");
+ if (temp_file_prefix == NULL)
+ temp_file_prefix = DEFAULT_TMPDIR;
+
+#ifdef _POSIX_VERSION
+ newact.sa_handler = sighandler;
+ sigemptyset (&newact.sa_mask);
+ newact.sa_flags = 0;
+
+ sigaction (SIGINT, NULL, &oldact);
+ if (oldact.sa_handler != SIG_IGN)
+ sigaction (SIGINT, &newact, NULL);
+#if HAVE_MINGW32==0
+ sigaction (SIGHUP, NULL, &oldact);
+ if (oldact.sa_handler != SIG_IGN)
+ sigaction (SIGHUP, &newact, NULL);
+ sigaction (SIGPIPE, NULL, &oldact);
+ if (oldact.sa_handler != SIG_IGN)
+ sigaction (SIGPIPE, &newact, NULL);
+#endif
+ sigaction (SIGTERM, NULL, &oldact);
+ if (oldact.sa_handler != SIG_IGN)
+ sigaction (SIGTERM, &newact, NULL);
+#else /* !_POSIX_VERSION */
+ if (signal (SIGINT, SIG_IGN) != SIG_IGN)
+ signal (SIGINT, sighandler);
+#if HAVE_MINGW32==0
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
+ signal (SIGHUP, sighandler);
+ if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
+ signal (SIGPIPE, sighandler);
+#endif
+ if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
+ signal (SIGTERM, sighandler);
+#endif /* !_POSIX_VERSION */
+
+ gkey.sword = gkey.eword = -1;
+ gkey.ignore = NULL;
+ gkey.translate = NULL;
+ gkey.nzone = gkey.numeric = gkey.month = gkey.reverse = 0;
+ gkey.skipsblanks = gkey.skipeblanks = 0;
+
+ files = (char **) xmalloc (sizeof (char *) * argc);
+
+ for (i = 1; i < argc; ++i)
+ {
+ if( !strcasecmp(argv[1], "--help") ){
+ usage(0);
+ }
+ if (argv[i][0] == '+')
+ {
+ if (key)
+ insertkey (key);
+ key = (struct keyfield *) xmalloc (sizeof (struct keyfield));
+ key->eword = -1;
+ key->ignore = NULL;
+ key->translate = NULL;
+ key->skipsblanks = key->skipeblanks = 0;
+ key->nzone = key->numeric = key->month = key->reverse = 0;
+ s = argv[i] + 1;
+ if (!digits[UCHAR (*s)]) {
+ switch ( *s ) {
+ case 'c' :
+ case 'C' :
+ case 'b' :
+ case 'B' :
+ case 's' :
+ case 'S' :
+ case 'i' :
+ case 'I' :
+ case 'l' :
+ case 'f' :
+ case 'd' :
+ case 't' :
+#ifdef SAOMOD_BINARY
+ if ( !BinarySort ) BinarySort = -1;
+#endif
+ key->btype = *s;
+ s++;
+
+ break;
+
+ default:
+ badfieldspec (argv[i]);
+ }
+ }
+ for (t = 0; digits[UCHAR (*s)]; ++s)
+ t = 10 * t + *s - '0';
+ t2 = 0;
+ if (*s == '.')
+ for (++s; digits[UCHAR (*s)]; ++s)
+ t2 = 10 * t2 + *s - '0';
+ if (t2 || t)
+ {
+ key->sword = t;
+ key->schar = t2;
+ }
+ else {
+#ifdef SAOMOD_BINARY
+ if ( BinarySort == 0 ) {
+ key->sword = -1;
+ key->schar = 0;
+ } else {
+#endif
+ key->sword = t;
+ key->schar = t2;
+#ifdef SAOMOD_BINARY
+ }
+#endif
+ }
+ s = set_ordering (s, key, bl_start);
+ if (*s)
+ badfieldspec (argv[i]);
+ }
+ else if (argv[i][0] == '-' && argv[i][1])
+ {
+ s = argv[i] + 1;
+ if (digits[UCHAR (*s)])
+ {
+ if (!key)
+ usage (2);
+ for (t = 0; digits[UCHAR (*s)]; ++s)
+ t = t * 10 + *s - '0';
+ t2 = 0;
+ if (*s == '.')
+ for (++s; digits[UCHAR (*s)]; ++s)
+ t2 = t2 * 10 + *s - '0';
+ key->eword = t;
+ key->echar = t2;
+ s = set_ordering (s, key, bl_end);
+ if (*s)
+ badfieldspec (argv[i]);
+ insertkey (key);
+ key = NULL;
+ }
+ else
+ while (*s)
+ {
+ s = set_ordering (s, &gkey, bl_both);
+ switch (*s)
+ {
+#ifdef SAOMOD_BINARY
+ case 'B' :
+ s++;
+ BinarySort = strtol(s, &s, 10);
+ linelength = BinarySort;
+ break;
+#endif
+ case '\0':
+ break;
+ case 'c':
+ checkonly = 1;
+ break;
+ case 'k':
+ if (s[1])
+ ++s;
+ else
+ {
+ if (i == argc - 1){
+ fprintf (stderr, "option `-k' requires an argument");
+ exit(2);
+ }
+ else
+ s = argv[++i];
+ }
+ if (key)
+ insertkey (key);
+ key = (struct keyfield *)
+ xmalloc (sizeof (struct keyfield));
+ key->eword = -1;
+ key->echar = 0;
+ key->ignore = NULL;
+ key->translate = NULL;
+ key->skipsblanks = key->skipeblanks = 0;
+ key->nzone = key->numeric = key->month = key->reverse = 0;
+ /* Get POS1. */
+ if (!digits[UCHAR (*s)])
+ badfieldspec (argv[i]);
+ for (t = 0; digits[UCHAR (*s)]; ++s)
+ t = 10 * t + *s - '0';
+ if (t)
+ t--;
+ t2 = 0;
+ if (*s == '.')
+ {
+ for (++s; digits[UCHAR (*s)]; ++s)
+ t2 = 10 * t2 + *s - '0';
+ if (t2)
+ t2--;
+ }
+ if (t2 || t)
+ {
+ key->sword = t;
+ key->schar = t2;
+ }
+ else
+ key->sword = -1;
+ s = set_ordering (s, key, bl_start);
+ if (*s && *s != ',')
+ badfieldspec (argv[i]);
+ else if (*s++)
+ {
+ /* Get POS2. */
+ for (t = 0; digits[UCHAR (*s)]; ++s)
+ t = t * 10 + *s - '0';
+ if (t)
+ t--;
+ t2 = 0;
+ if (*s == '.')
+ {
+ for (++s; digits[UCHAR (*s)]; ++s)
+ t2 = t2 * 10 + *s - '0';
+ if (t2)
+ t2--;
+ }
+ key->eword = t;
+ key->echar = t2;
+ s = set_ordering (s, key, bl_end);
+ if (*s)
+ badfieldspec (argv[i]);
+ }
+ insertkey (key);
+ key = NULL;
+ goto outer;
+#ifdef SAOMOD_TABLE
+ case 'm':
+ mergeonly = 1;
+ if ( table ) table=2;
+ break;
+#endif
+ case 'o':
+ if (s[1])
+ outfile = s + 1;
+ else
+ {
+ if (i == argc - 1){
+ fprintf (stderr, "option `-o' requires an argument");
+ exit(2);
+ }
+ else
+ outfile = argv[++i];
+ }
+ goto outer;
+ case 's':
+ stable = 1;
+ break;
+ case 't':
+ if (s[1])
+ tab = *++s;
+ else if (i < argc - 1)
+ {
+ tab = *argv[++i];
+ goto outer;
+ }
+ else{
+ fprintf (stderr, "option `-t' requires an argument");
+ exit(2);
+ }
+ break;
+ case 'T':
+ if (s[1])
+ temp_file_prefix = ++s;
+ else
+ {
+ if (i < argc - 1)
+ temp_file_prefix = argv[++i];
+ else{
+ fprintf (stderr, "option `-T' requires an argument");
+ exit(2);
+ }
+ }
+ goto outer;
+
+ case 'u': unique = 1; differ = 0; break; /* One each only */
+ case 'U': unique = 1; differ = 1; break; /* Unique lines only */
+ case 'D': unique = 1; differ = 2; break; /* Duplic lines only */
+ case 'A': unique = 1; differ = 4; break; /* All Duplic lines */
+ case 'S': unique = 1; differ = 3; break; /* Set counter */
+ case 'C': unique = 1; countr = 1; break; /* Count same lines */
+ case 'y':
+ /* Accept and ignore e.g. -y0 for compatibility with
+ Solaris 2. */
+ goto outer;
+ default:
+ fprintf (stderr, "%s: unrecognized option `-%c'\n",
+ argv[0], *s);
+ usage (2);
+ }
+ if (*s)
+ ++s;
+ }
+ }
+ else /* Not an option. */
+ {
+ files[nfiles++] = argv[i];
+ }
+ outer:;
+ }
+
+ if (key)
+ insertkey (key);
+
+#ifdef SAOMOD_BINARY
+ if ( BinarySort == -1 ) {
+ fprintf (stderr, "No record length specified with binary file sort flags.\n");
+ usage(2);
+ }
+ if ( BinarySort && key == NULL ) {
+ fprintf (stderr, "Keys must be specified with binary file sort.\n");
+ usage(2);
+ }
+#endif
+
+#ifdef SAOMOD_BINARY
+ /* Inheritance of global options to individual keys. */
+if ( !BinarySort ) {
+ for (key = keyhead.next; key; key = key->next)
+ if (!key->ignore && !key->translate && !key->skipsblanks && !key->reverse
+ && !key->skipeblanks && !key->month && !key->numeric && !key->nzone)
+ {
+ key->ignore = gkey.ignore;
+ key->translate = gkey.translate;
+ key->skipsblanks = gkey.skipsblanks;
+ key->skipeblanks = gkey.skipeblanks;
+ key->month = gkey.month;
+ key->numeric = gkey.numeric;
+ key->reverse = gkey.reverse;
+ key->nzone = gkey.nzone;
+ key->dzone = gkey.dzone;
+
+ }
+
+ if (!keyhead.next && (gkey.ignore || gkey.translate || gkey.skipsblanks
+ || gkey.skipeblanks || gkey.month || gkey.numeric))
+ insertkey (&gkey);
+}
+#endif
+
+ reverse = gkey.reverse;
+
+ if (nfiles == 0)
+ {
+ nfiles = 1;
+ files = &minus;
+ }
+
+ if (checkonly)
+ exit (check (files, nfiles) != 0);
+
+ if (strcmp (outfile, "-"))
+ {
+ struct stat outstat;
+ if (stat (outfile, &outstat) == 0)
+ {
+ /* The following code prevents a race condition when
+ people use the brain dead shell programming idiom:
+ cat file | sort -o file
+ This feature is provided for historical compatibility,
+ but we strongly discourage ever relying on this in
+ new shell programs. */
+
+ /* Temporarily copy each input file that might be another name
+ for the output file. When in doubt (e.g. a pipe), copy. */
+ for (i = 0; i < nfiles; ++i)
+ {
+ char buf[8192];
+ FILE *fp;
+ int cc;
+
+ if (S_ISREG (outstat.st_mode) && strcmp (outfile, files[i]))
+ {
+ struct stat instat;
+ if ((strcmp (files[i], "-")
+ ? stat (files[i], &instat)
+ : fstat (fileno (stdin), &instat)) != 0)
+ {
+ perror (files[i]);
+ cleanup ();
+ exit (2);
+ }
+ if (S_ISREG (instat.st_mode)
+ && (instat.st_ino != outstat.st_ino
+ || instat.st_dev != outstat.st_dev))
+ {
+ /* We know the files are distinct. */
+ continue;
+ }
+ }
+
+ fp = xfopen (files[i], "r");
+ tmp = tempname ();
+ ofp = xfopen (tmp, "w");
+ while ((cc = fread (buf, 1, sizeof buf, fp)) > 0)
+ xfwrite (buf, 1, cc, ofp);
+ if (ferror (fp))
+ {
+ fprintf (stderr, "%s", files[i]);
+ cleanup ();
+ exit (2);
+ }
+ xfclose (ofp);
+ xfclose (fp);
+ files[i] = tmp;
+ }
+ }
+ ofp = xfopen (outfile, "w");
+ }
+ else
+ ofp = stdout;
+
+ if (mergeonly)
+ merge (files, nfiles, ofp);
+ else
+ sort (files, nfiles, ofp);
+ cleanup ();
+
+ /* If we wait for the implicit flush on exit, and the parent process
+ has closed stdout (e.g., exec >&- in a shell), then the output file
+ winds up empty. I don't understand why. This is under SunOS,
+ Solaris, Ultrix, and Irix. This premature fflush makes the output
+ reappear. --karl@cs.umb.edu */
+ if (fflush (ofp) < 0)
+ perror (outfile);
+
+ if (have_read_stdin && fclose (stdin) == EOF)
+ perror (outfile);
+ if (ferror (stdout) || fclose (stdout) == EOF)
+ perror (outfile);
+
+ return(0);
+}
+
+static void
+usage (status)
+ int status;
+{
+ if (status != 0)
+ fprintf (stderr, "Try `%s --help' for more information.\n",
+ program_name);
+ else
+ {
+ fprintf(stderr,"Usage: %s [OPTION]... [FILE]...\n", program_name);
+ fprintf(stderr,"Write sorted concatenation of all FILE(s) to standard output.\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,"+POS1 [-POS2] start a key at POS1, end it before POS2\n");
+ fprintf(stderr,"-M compare (unknown) < `JAN' < ... < `DEC', imply -b\n");
+ fprintf(stderr,"-T DIRECT use DIRECT for temporary files, not $TMPDIR or %s\n", DEFAULT_TMPDIR);
+ fprintf(stderr,"-b ignore leading blanks in sort fields or keys\n");
+ fprintf(stderr,"-c check if given files already sorted, do not sort\n");
+ fprintf(stderr,"-d consider only [a-zA-Z0-9 ] characters in keys\n");
+ fprintf(stderr,"-f fold lower case to upper case characters in keys\n");
+ fprintf(stderr,"-i consider only [\\040-\\0176] characters in keys\n");
+ fprintf(stderr,"-k POS1[,POS2] same as +POS1 [-POS2], but all positions counted from 1\n");
+ fprintf(stderr,"-m merge already sorted files, do not sort\n");
+ fprintf(stderr,"-n compare according to string numerical value, imply -b\n");
+ fprintf(stderr,"-o FILE write result on FILE instead of standard output\n");
+ fprintf(stderr,"-r reverse the result of comparisons\n");
+ fprintf(stderr,"-s stabilize sort by disabling last resort comparison\n");
+ fprintf(stderr,"-t SEP use SEParator instead of non- to whitespace transition\n");
+ fprintf(stderr,"-u with -c, check for strict ordering\n");
+ fprintf(stderr,"-u with -m, only output the first of an equal sequence\n");
+ fprintf(stderr,"-U output only unique records.\n");
+ fprintf(stderr,"-D output only duplicate records.\n");
+ fprintf(stderr,"--help display this help and exit\n");
+ fprintf(stderr,"--version output version information and exit\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,"Binary File Options:\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,"-Blen record length in bytes\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,"+<type1>offset1 +<type2>.offset2 ...\n");
+ fprintf(stderr,"or\n");
+ fprintf(stderr,"+<type1>offset1.len1 ... (+t text data only)\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,"where <type> can be:\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,"c character data\n");
+ fprintf(stderr,"C unsigned character data\n");
+ fprintf(stderr,"b byte data\n");
+ fprintf(stderr,"B unsigned byte data\n");
+ fprintf(stderr,"s short data\n");
+ fprintf(stderr,"S unsigned short data\n");
+ fprintf(stderr,"i integer data\n");
+ fprintf(stderr,"I unsigned integer data\n");
+ fprintf(stderr,"f float data\n");
+ fprintf(stderr,"d double data\n");
+ fprintf(stderr,"t text data\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,"POS is F[.C][OPTS], where F is the field number and C the character\n");
+ fprintf(stderr,"position in the field, both counted from zero. OPTS is made up of one\n");
+ fprintf(stderr,"or more of Mbdfinr; this effectively disables global -Mbdfinr settings\n");
+ fprintf(stderr,"for that key. If no key given, use the entire line as key. With no\n");
+ fprintf(stderr,"FILE, or when FILE is -, read standard input.\n");
+ fprintf(stderr,"\n");
+ }
+ exit (status);
+}
+
diff --git a/funtools/gnu/sorttest.c b/funtools/gnu/sorttest.c
new file mode 100644
index 0000000..5cc0ad2
--- /dev/null
+++ b/funtools/gnu/sorttest.c
@@ -0,0 +1,152 @@
+/*
+ export EVENTS="(dval:D,fval:E,ival:J,uival:V,sval:I,cval:B,cval2:B)"
+ sorttest | _funsort -B24 +... | fundisp "stdin[EVENTS()]"
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <salloc.h>
+
+extern char *optarg;
+extern int optind;
+
+#define NREC 10
+#define SZ_LINE 1024
+
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+typedef struct brec{
+ double dval;
+ float fval;
+ int ival;
+ unsigned int uival;
+ short sval;
+ char cval;
+ char cval2;
+} Binary;
+
+void
+fillb(Binary *b, int i, int dodouble)
+{
+ int idiv;
+ b->dval = (double)rand();
+ b->fval = (float)rand();
+ if( dodouble ){
+ if( (i%2) == 0 )
+ b->ival = rand();
+ }
+ else{
+ b->ival = rand();
+ }
+ b->uival = (unsigned)rand();
+ idiv = MAX(1,(RAND_MAX/32768));
+ b->sval = rand()/idiv;
+ idiv = MAX(1,(RAND_MAX/128));
+ b->cval = rand()/idiv;
+ b->cval2 = rand()/idiv;
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+ int c;
+ int ival;
+ int ichan, ochan, pid, status;
+ int rlen;
+ int nrec=NREC;
+ int dodouble=0;
+ int doxeq=0;
+ char *prog="_funsort";
+ char *slist=NULL;
+ char *s;
+ char tbuf[SZ_LINE];
+ char cmd[SZ_LINE];
+ FILE *fp=stdout;
+ Binary b;
+
+ /* process switch arguments */
+ while ((c = getopt(argc, argv, "dn:s:x")) != -1){
+ switch(c){
+ case 'd':
+ dodouble = 1;
+ break;
+ case 'n':
+ nrec = atoi(optarg);
+ break;
+ case 's':
+ doxeq = 1;
+ slist=(char *)NewString(optarg);
+ break;
+ case 'x':
+ doxeq = 1;
+ break;
+ }
+ }
+
+ /* see rand */
+ srand(time(NULL));
+
+ /* generate sort parameters and start sort program */
+ if( doxeq ){
+ snprintf(cmd, SZ_LINE-1, "%s -B%d %s", prog, sizeof(Binary), tbuf);
+ rlen = SZ_LINE - strlen(cmd);
+ if( !slist ){
+ slist = (char *)NewString("d");
+ }
+ for(s=slist; *s; s++){
+ switch(*s){
+ case 'd':
+ sprintf(tbuf, "+d0");
+ break;
+ case 'f':
+ sprintf(tbuf, "+f8");
+ break;
+ case 'i':
+ sprintf(tbuf, "+i12");
+ break;
+ case 'I':
+ sprintf(tbuf, "+I16");
+ break;
+ case 's':
+ sprintf(tbuf, "+s20");
+ break;
+ case 'c':
+ sprintf(tbuf, "+c22");
+ break;
+ default:
+ fprintf(stderr, "ERROR: unknown sort type: %s\n", s);
+ exit(1);
+ }
+ strncat(cmd, " ", rlen);
+ rlen--;
+ strncat(cmd, tbuf, rlen);
+ rlen -= strlen(tbuf);
+ if( rlen <=0 ){
+ fprintf(stderr, "ERROR: too many arguments\n");
+ exit(1);
+ }
+ }
+ if( !ProcessOpen(cmd, &ichan, &ochan, &pid) ){
+ fprintf(stderr, "ERROR: can't start %s\n", prog);
+ exit(1);
+ }
+ /* write unsorted records */
+ for(i=0; i<nrec; i++){
+ fillb(&b, i, dodouble);
+ write(ochan, &b, sizeof(Binary));
+ }
+ /* signal EOF to sort program */
+ close(ochan);
+ while( read(ichan, &b, sizeof(Binary)) == sizeof(Binary) )
+ write(1, &b, sizeof(Binary));
+ if( slist ) free(slist);
+ ProcessClose(pid, &status);
+ }
+ else{
+ /* write unsorted records */
+ for(i=0; i<nrec; i++){
+ fillb(&b, i, dodouble);
+ fwrite(&b, sizeof(Binary), 1, fp);
+ }
+ }
+}
diff --git a/funtools/gnu/system.h b/funtools/gnu/system.h
new file mode 100644
index 0000000..6ebebda
--- /dev/null
+++ b/funtools/gnu/system.h
@@ -0,0 +1,187 @@
+/* system-dependent definitions for textutils programs.
+ Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Include sys/types.h before this file. */
+
+#include <sys/stat.h>
+
+#ifdef STAT_MACROS_BROKEN
+#undef S_ISBLK
+#undef S_ISCHR
+#undef S_ISDIR
+#undef S_ISFIFO
+#undef S_ISLNK
+#undef S_ISMPB
+#undef S_ISMPC
+#undef S_ISNWK
+#undef S_ISREG
+#undef S_ISSOCK
+#endif /* STAT_MACROS_BROKEN. */
+
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
+#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
+#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
+#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+#endif
+#if !defined(HAVE_MKFIFO)
+#define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0))
+#endif
+
+/*
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+*/
+
+#ifndef _POSIX_VERSION
+off_t lseek ();
+#endif
+
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+/* Don't use bcopy! Use memmove if source and destination may overlap,
+ memcpy otherwise. */
+
+#ifdef HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#else
+# include <strings.h>
+char *memchr ();
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#endif
+
+#if !defined(SEEK_SET)
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+#ifndef _POSIX_SOURCE
+#include <sys/param.h>
+#endif
+
+/* Get or fake the disk device blocksize.
+ Usually defined by sys/param.h (if at all). */
+#if !defined(DEV_BSIZE) && defined(BSIZE)
+#define DEV_BSIZE BSIZE
+#endif
+#if !defined(DEV_BSIZE) && defined(BBSIZE) /* SGI */
+#define DEV_BSIZE BBSIZE
+#endif
+#ifndef DEV_BSIZE
+#define DEV_BSIZE 4096
+#endif
+
+/* Extract or fake data from a `struct stat'.
+ ST_BLKSIZE: Optimal I/O blocksize for the file, in bytes. */
+#ifndef HAVE_ST_BLKSIZE
+# define ST_BLKSIZE(statbuf) DEV_BSIZE
+#else /* HAVE_ST_BLKSIZE */
+/* Some systems, like Sequents, return st_blksize of 0 on pipes. */
+# define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
+ ? (statbuf).st_blksize : DEV_BSIZE)
+#endif /* HAVE_ST_BLKSIZE */
+
+#ifndef S_ISLNK
+#define lstat stat
+#endif
+
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+
+#include <ctype.h>
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+#define ISASCII(c) 1
+#else
+#define ISASCII(c) isascii(c)
+#endif
+
+#ifdef isblank
+#define ISBLANK(c) (ISASCII (c) && isblank (c))
+#else
+#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+#ifdef isgraph
+#define ISGRAPH(c) (ISASCII (c) && isgraph (c))
+#else
+#define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
+#endif
+
+#define ISPRINT(c) (ISASCII (c) && isprint (c))
+#define ISDIGIT(c) (ISASCII (c) && isdigit (c))
+#define ISALNUM(c) (ISASCII (c) && isalnum (c))
+#define ISALPHA(c) (ISASCII (c) && isalpha (c))
+#define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
+#define ISLOWER(c) (ISASCII (c) && islower (c))
+#define ISPUNCT(c) (ISASCII (c) && ispunct (c))
+#define ISSPACE(c) (ISASCII (c) && isspace (c))
+#define ISUPPER(c) (ISASCII (c) && isupper (c))
+#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))