diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2016-10-27 17:38:41 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2016-10-27 17:38:41 (GMT) |
commit | 5b44fb0d6530c4ff66a446afb69933aa8ffd014f (patch) | |
tree | e059f66d1f612e21fe9d83f9620c8715530353ec /funtools/gnu | |
parent | da2e3d212171bbe64c1af39114fd067308656990 (diff) | |
parent | 23c7930d27fe11c4655e1291a07a821dbbaba78d (diff) | |
download | blt-5b44fb0d6530c4ff66a446afb69933aa8ffd014f.zip blt-5b44fb0d6530c4ff66a446afb69933aa8ffd014f.tar.gz blt-5b44fb0d6530c4ff66a446afb69933aa8ffd014f.tar.bz2 |
Merge commit '23c7930d27fe11c4655e1291a07a821dbbaba78d' as 'funtools'
Diffstat (limited to 'funtools/gnu')
-rw-r--r-- | funtools/gnu/COPYING | 340 | ||||
-rw-r--r-- | funtools/gnu/Makefile.in | 150 | ||||
-rw-r--r-- | funtools/gnu/conf.h.in | 59 | ||||
-rw-r--r-- | funtools/gnu/copyright | 29 | ||||
-rwxr-xr-x | funtools/gnu/install-sh | 276 | ||||
-rw-r--r-- | funtools/gnu/sort.c | 2879 | ||||
-rw-r--r-- | funtools/gnu/sorttest.c | 152 | ||||
-rw-r--r-- | funtools/gnu/system.h | 187 |
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 = − + } + + 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)) |