From Textutils-1.6
authorNate Willams <nate@FreeBSD.org>
Tue, 29 Jun 1993 04:58:06 +0000 (04:58 +0000)
committerNate Willams <nate@FreeBSD.org>
Tue, 29 Jun 1993 04:58:06 +0000 (04:58 +0000)
12 files changed:
gnu/usr.bin/pr/COPYING [new file with mode: 0644]
gnu/usr.bin/pr/Makefile [new file with mode: 0644]
gnu/usr.bin/pr/error.c [new file with mode: 0644]
gnu/usr.bin/pr/getopt.c [new file with mode: 0644]
gnu/usr.bin/pr/getopt.h [new file with mode: 0644]
gnu/usr.bin/pr/getopt1.c [new file with mode: 0644]
gnu/usr.bin/pr/pr.1 [new file with mode: 0644]
gnu/usr.bin/pr/pr.c [new file with mode: 0644]
gnu/usr.bin/pr/system.h [new file with mode: 0644]
gnu/usr.bin/pr/version.c [new file with mode: 0644]
gnu/usr.bin/pr/version.h [new file with mode: 0644]
gnu/usr.bin/pr/xmalloc.c [new file with mode: 0644]

diff --git a/gnu/usr.bin/pr/COPYING b/gnu/usr.bin/pr/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/usr.bin/pr/Makefile b/gnu/usr.bin/pr/Makefile
new file mode 100644 (file)
index 0000000..6c8d431
--- /dev/null
@@ -0,0 +1,7 @@
+
+PROG=  pr
+SRCS=  pr.c getopt.c getopt1.c error.c xmalloc.c version.c
+
+CFLAGS+=-I${.CURDIR}
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/pr/error.c b/gnu/usr.bin/pr/error.c
new file mode 100644 (file)
index 0000000..e849c5b
--- /dev/null
@@ -0,0 +1,106 @@
+/* error.c -- error handler for noninteractive utilities
+   Copyright (C) 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by David MacKenzie.  */
+
+#include <stdio.h>
+
+#ifdef HAVE_VPRINTF
+
+#if __STDC__
+#include <stdarg.h>
+#define VA_START(args, lastarg) va_start(args, lastarg)
+#else /* !__STDC__ */
+#include <varargs.h>
+#define VA_START(args, lastarg) va_start(args)
+#endif /* !__STDC__ */
+
+#else /* !HAVE_VPRINTF */
+
+#ifdef HAVE_DOPRNT
+#define va_alist args
+#define va_dcl int args;
+#else /* !HAVE_DOPRNT */
+#define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif /* !HAVE_DOPRNT */
+
+#endif /* !HAVE_VPRINTF */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else /* !STDC_HEADERS */
+void exit ();
+#endif /* !STDC_HEADERS */
+
+extern char *program_name;
+
+#ifndef HAVE_STRERROR
+static char *
+private_strerror (errnum)
+     int errnum;
+{
+  extern char *sys_errlist[];
+  extern int sys_nerr;
+
+  if (errnum > 0 && errnum <= sys_nerr)
+    return sys_errlist[errnum];
+  return "Unknown system error";
+}
+#define strerror private_strerror
+#endif /* !HAVE_STRERROR */
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+   format string with optional args.
+   If ERRNUM is nonzero, print its corresponding system error message.
+   Exit with status STATUS if it is nonzero.  */
+/* VARARGS */
+void
+#if defined (HAVE_VPRINTF) && __STDC__
+error (int status, int errnum, char *message, ...)
+#else /* !HAVE_VPRINTF or !__STDC__ */
+error (status, errnum, message, va_alist)
+     int status;
+     int errnum;
+     char *message;
+     va_dcl
+#endif /* !HAVE_VPRINTF or !__STDC__ */
+{
+#ifdef HAVE_VPRINTF
+  va_list args;
+#endif /* HAVE_VPRINTF */
+
+  fprintf (stderr, "%s: ", program_name);
+#ifdef HAVE_VPRINTF
+  VA_START (args, message);
+  vfprintf (stderr, message, args);
+  va_end (args);
+#else /* !HAVE_VPRINTF */
+#ifdef HAVE_DOPRNT
+  _doprnt (message, &args, stderr);
+#else /* !HAVE_DOPRNT */
+  fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif /* !HAVE_DOPRNT */
+#endif /* !HAVE_VPRINTF */
+  if (errnum)
+    fprintf (stderr, ": %s", strerror (errnum));
+  putc ('\n', stderr);
+  fflush (stderr);
+  if (status)
+    exit (status);
+}
diff --git a/gnu/usr.bin/pr/getopt.c b/gnu/usr.bin/pr/getopt.c
new file mode 100644 (file)
index 0000000..a59a013
--- /dev/null
@@ -0,0 +1,731 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+       Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+/* NOTE!!!  AIX requires this to be the first thing in the file.
+   Do not put ANYTHING before it!  */
+#if !defined (__GNUC__) && defined (_AIX)
+ #pragma alloca
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
+#include <alloca.h>
+#else
+#ifndef _AIX
+char *alloca ();
+#endif
+#endif /* alloca.h */
+#endif /* not __GNUC__ */
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#undef alloca
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#else  /* Not GNU C library.  */
+#define        __alloca        alloca
+#endif /* GNU C library.  */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+   long-named option.  Because this is not POSIX.2 compliant, it is
+   being phased out.  */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* XXX 1003.2 says this must be 1 before any call.  */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+\f
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define        my_index        strchr
+#define        my_bcopy(src, dst, n)   memcpy ((dst), (src), (n))
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+       return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+static void
+my_bcopy (from, to, size)
+     const char *from;
+     char *to;
+     int size;
+{
+  int i;
+  for (i = 0; i < size; i++)
+    to[i] = from[i];
+}
+#endif                         /* GNU C library.  */
+\f
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
+  char **temp = (char **) __alloca (nonopts_size);
+
+  /* Interchange the two blocks of data in ARGV.  */
+
+  my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
+  my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
+           (optind - last_nonopt) * sizeof (char *));
+  my_bcopy ((char *) temp,
+           (char *) &argv[first_nonopt + optind - last_nonopt],
+           nonopts_size);
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+\f
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns `EOF'.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  int option_index;
+
+  optarg = 0;
+
+  /* Initialize the internal data when the first call is made.
+     Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  if (optind == 0)
+    {
+      first_nonopt = last_nonopt = optind = 1;
+
+      nextchar = NULL;
+
+      /* Determine how to handle the ordering of options and nonoptions.  */
+
+      if (optstring[0] == '-')
+       {
+         ordering = RETURN_IN_ORDER;
+         ++optstring;
+       }
+      else if (optstring[0] == '+')
+       {
+         ordering = REQUIRE_ORDER;
+         ++optstring;
+       }
+      else if (getenv ("POSIXLY_CORRECT") != NULL)
+       ordering = REQUIRE_ORDER;
+      else
+       ordering = PERMUTE;
+    }
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      if (ordering == PERMUTE)
+       {
+         /* If we have just processed some options following some non-options,
+            exchange them so that the options come first.  */
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (last_nonopt != optind)
+           first_nonopt = optind;
+
+         /* Now skip any additional non-options
+            and extend the range of non-options previously skipped.  */
+
+         while (optind < argc
+                && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+                && (longopts == NULL
+                    || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif                         /* GETOPT_COMPAT */
+                )
+           optind++;
+         last_nonopt = optind;
+       }
+
+      /* Special ARGV-element `--' means premature end of options.
+        Skip it like a null option,
+        then exchange with previous non-options as if it were an option,
+        then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+       {
+         optind++;
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (first_nonopt == last_nonopt)
+           first_nonopt = optind;
+         last_nonopt = argc;
+
+         optind = argc;
+       }
+
+      /* If we have done all the ARGV-elements, stop the scan
+        and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+       {
+         /* Set the next-arg-index to point at the non-options
+            that we previously skipped, so the caller will digest them.  */
+         if (first_nonopt != last_nonopt)
+           optind = first_nonopt;
+         return EOF;
+       }
+
+      /* If we have come to a non-option and did not permute it,
+        either stop the scan or describe it to the caller and pass it by.  */
+
+      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+         && (longopts == NULL
+             || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif                         /* GETOPT_COMPAT */
+         )
+       {
+         if (ordering == REQUIRE_ORDER)
+           return EOF;
+         optarg = argv[optind++];
+         return 1;
+       }
+
+      /* We have found another option-ARGV-element.
+        Start decoding its characters.  */
+
+      nextchar = (argv[optind] + 1
+                 + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  if (longopts != NULL
+      && ((argv[optind][0] == '-'
+          && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+         || argv[optind][0] == '+'
+#endif                         /* GETOPT_COMPAT */
+         ))
+    {
+      const struct option *p;
+      char *s = nextchar;
+      int exact = 0;
+      int ambig = 0;
+      const struct option *pfound = NULL;
+      int indfound;
+
+      while (*s && *s != '=')
+       s++;
+
+      /* Test all options for either exact match or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name;
+          p++, option_index++)
+       if (!strncmp (p->name, nextchar, s - nextchar))
+         {
+           if (s - nextchar == strlen (p->name))
+             {
+               /* Exact match found.  */
+               pfound = p;
+               indfound = option_index;
+               exact = 1;
+               break;
+             }
+           else if (pfound == NULL)
+             {
+               /* First nonexact match found.  */
+               pfound = p;
+               indfound = option_index;
+             }
+           else
+             /* Second nonexact match found.  */
+             ambig = 1;
+         }
+
+      if (ambig && !exact)
+       {
+         if (opterr)
+           fprintf (stderr, "%s: option `%s' is ambiguous\n",
+                    argv[0], argv[optind]);
+         nextchar += strlen (nextchar);
+         optind++;
+         return '?';
+       }
+
+      if (pfound != NULL)
+       {
+         option_index = indfound;
+         optind++;
+         if (*s)
+           {
+             /* Don't test has_arg with >, because some C compilers don't
+                allow it to be used on enums.  */
+             if (pfound->has_arg)
+               optarg = s + 1;
+             else
+               {
+                 if (opterr)
+                   {
+                     if (argv[optind - 1][1] == '-')
+                       /* --option */
+                       fprintf (stderr,
+                                "%s: option `--%s' doesn't allow an argument\n",
+                                argv[0], pfound->name);
+                     else
+                       /* +option or -option */
+                       fprintf (stderr,
+                            "%s: option `%c%s' doesn't allow an argument\n",
+                            argv[0], argv[optind - 1][0], pfound->name);
+                   }
+                 nextchar += strlen (nextchar);
+                 return '?';
+               }
+           }
+         else if (pfound->has_arg == 1)
+           {
+             if (optind < argc)
+               optarg = argv[optind++];
+             else
+               {
+                 if (opterr)
+                   fprintf (stderr, "%s: option `%s' requires an argument\n",
+                            argv[0], argv[optind - 1]);
+                 nextchar += strlen (nextchar);
+                 return optstring[0] == ':' ? ':' : '?';
+               }
+           }
+         nextchar += strlen (nextchar);
+         if (longind != NULL)
+           *longind = option_index;
+         if (pfound->flag)
+           {
+             *(pfound->flag) = pfound->val;
+             return 0;
+           }
+         return pfound->val;
+       }
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+        or the option starts with '--' or is not a valid short
+        option, then it's an error.
+        Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+         || argv[optind][0] == '+'
+#endif                         /* GETOPT_COMPAT */
+         || my_index (optstring, *nextchar) == NULL)
+       {
+         if (opterr)
+           {
+             if (argv[optind][1] == '-')
+               /* --option */
+               fprintf (stderr, "%s: unrecognized option `--%s'\n",
+                        argv[0], nextchar);
+             else
+               /* +option or -option */
+               fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+                        argv[0], argv[optind][0], nextchar);
+           }
+         nextchar = (char *) "";
+         optind++;
+         return '?';
+       }
+    }
+
+  /* Look at and handle the next option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+       if (opterr)
+         {
+#if 0
+           if (c < 040 || c >= 0177)
+             fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+                      argv[0], c);
+           else
+             fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+           /* 1003.2 specifies the format of this message.  */
+           fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+         }
+       optopt = c;
+       return '?';
+      }
+    if (temp[1] == ':')
+      {
+       if (temp[2] == ':')
+         {
+           /* This is an option that accepts an argument optionally.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               optind++;
+             }
+           else
+             optarg = 0;
+           nextchar = NULL;
+         }
+       else
+         {
+           /* This is an option that requires an argument.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               /* If we end this ARGV-element by taking the rest as an arg,
+                  we must advance to the next element now.  */
+               optind++;
+             }
+           else if (optind == argc)
+             {
+               if (opterr)
+                 {
+#if 0
+                   fprintf (stderr, "%s: option `-%c' requires an argument\n",
+                            argv[0], c);
+#else
+                   /* 1003.2 specifies the format of this message.  */
+                   fprintf (stderr, "%s: option requires an argument -- %c\n",
+                            argv[0], c);
+#endif
+                 }
+               optopt = c;
+               if (optstring[0] == ':')
+                 c = ':';
+               else
+                 c = '?';
+             }
+           else
+             /* We already incremented `optind' once;
+                increment it again when taking next ARGV-elt as argument.  */
+             optarg = argv[optind++];
+           nextchar = NULL;
+         }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+                          (const struct option *) 0,
+                          (int *) 0,
+                          0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+\f
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == EOF)
+       break;
+
+      switch (c)
+       {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/pr/getopt.h b/gnu/usr.bin/pr/getopt.h
new file mode 100644 (file)
index 0000000..45541f5
--- /dev/null
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument         (or 0) if the option does not take an argument,
+   required_argument   (or 1) if the option requires an argument,
+   optional_argument   (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+#if    __STDC__
+  const char *name;
+#else
+  char *name;
+#endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define        no_argument             0
+#define required_argument      1
+#define optional_argument      2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+                       const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind,
+                            int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/usr.bin/pr/getopt1.c b/gnu/usr.bin/pr/getopt1.c
new file mode 100644 (file)
index 0000000..a32615c
--- /dev/null
@@ -0,0 +1,176 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+       Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "getopt.h"
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef        NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+\f
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+       {"add", 1, 0, 0},
+       {"append", 0, 0, 0},
+       {"delete", 1, 0, 0},
+       {"verbose", 0, 0, 0},
+       {"create", 0, 0, 0},
+       {"file", 1, 0, 0},
+       {0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+                      long_options, &option_index);
+      if (c == EOF)
+       break;
+
+      switch (c)
+       {
+       case 0:
+         printf ("option %s", long_options[option_index].name);
+         if (optarg)
+           printf (" with arg %s", optarg);
+         printf ("\n");
+         break;
+
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case 'd':
+         printf ("option d with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/gnu/usr.bin/pr/pr.1 b/gnu/usr.bin/pr/pr.1
new file mode 100644 (file)
index 0000000..10cdd8c
--- /dev/null
@@ -0,0 +1,103 @@
+.TH PR 1L \" -*- nroff -*-
+.SH NAME
+pr \- convert text files for printing
+.SH SYNOPSIS
+.B pr
+[+PAGE] [\-COLUMN] [\-abcdfFmrtv] [\-e[in-tab-char[in-tab-width]]]
+[\-h header] [\-i[out-tab-char[out-tab-width]]] [\-l page-length]
+[\-n[number-separator[digits]]] [\-o left-margin]
+[\-s[column-separator]] [\-w page-width] [\-\-help] [\-\-version] [file...]
+.SH DESCRIPTION
+This manual page
+documents the GNU version of
+.BR pr .
+.B pr
+prints on the standard output a paginated and optionally multicolumn
+copy of the text files given on the command line, or of the standard
+input if no files are given or when the file name `\-' is encountered.
+Form feeds in the input cause page breaks in the output.
+.SS OPTIONS
+.TP
+.I \+PAGE
+Begin printing with page \fIPAGE\fP.
+.TP
+.I \-COLUMN
+Produce \fICOLUMN\fP-column output and print columns down.  The column
+width is automatically decreased as \fICOLUMN\fP increases; unless you
+use the \fI\-w\fP option to increase the page width as well, this
+option might cause some columns to be truncated.
+.TP
+.I \-a
+Print columns across rather than down.
+.TP
+.I \-b
+Balance columns on the last page.
+.TP
+.I \-c
+Print control characters using hat notation (e.g., `^G'); print other
+unprintable characters in octal backslash notation.
+.TP
+.I \-d
+Double space the output.
+.TP
+.I "\-e[in-tab-char[in-tab-width]]"
+Expand tabs to spaces on input.  Optional argument \fIin-tab-char\fP
+is the input tab character, default tab.  Optional argument
+\fIin-tab-width\fP is the input tab character's width, default 8.
+.TP
+.I "\-F, \-f"
+Use a formfeed instead of newlines to separate output pages.
+.TP
+.I "\-h header"
+Replace the filename in the header with the string \fIheader\fP.
+.TP
+.I "\-\-help"
+Print a usage message and exit with a non-zero status.
+.TP
+.I "\-i[out-tab-char[out-tab-width]]"
+Replace spaces with tabs on output.  Optional argument
+\fIout-tab-char\fP is the output tab character, default tab.
+Optional argument \fIout-tab-width\fP is the output tab character's
+width, default 8.
+.TP
+.I "\-l page-length"
+Set the page length to \fIpage-length\fP lines.  The default is 66.
+If \fIpage-length\fP is less than 10, the headers and footers are
+omitted, as if the \fI\-t\fP option had been given.
+.TP
+.I \-m
+Print all files in parallel, one in each column.
+.TP
+.I "\-n[number-separator[digits]]"
+Precede each column with a line number; with parallel files, precede
+each line with a line number.  Optional argument
+\fInumber-separator\fP is the character to print after each number,
+default tab.  Optional argument \fIdigits\fP is the number of digits
+per line number, default 5.
+.TP
+.I "\-o left-margin"
+Offset each line with a margin \fIleft-margin\fP spaces wide.  The
+total page width is this offset plus the width set with the \fI\-w\fP
+option.
+.TP
+.I \-r
+Do not print a warning message when an argument file cannot be opened.
+Failure to open a file still makes the exit status nonzero, however.
+.TP
+.I "\-s[column-separator]"
+Separate columns by the single character \fIcolumn-separator\fP,
+default tab, instead of spaces.
+.TP
+.I \-t
+Do not print the 5-line header and the 5-line trailer that are
+normally on each page, and do not fill out the bottoms of pages (with
+blank lines or formfeeds).
+.TP
+.I \-v
+Print unprintable characters in octal backslash notation.
+.TP
+.I "\-\-version"
+Print version information on standard error then exit.
+.TP
+.I "\-w page-width"
+Set the page width to \fIpage-width\fP columns.  The default is 72.
diff --git a/gnu/usr.bin/pr/pr.c b/gnu/usr.bin/pr/pr.c
new file mode 100644 (file)
index 0000000..250f532
--- /dev/null
@@ -0,0 +1,1875 @@
+/* pr -- convert text files for printing.
+   Copyright (C) 1988, 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/*  Author: Pete TerMaat.  */
+\f
+/* Things to watch: Sys V screws up on ...
+   pr -n -3 -s: /usr/dict/words
+   pr -m -o10 -n /usr/dict/words{,,,}
+   pr -6 -a -n -o5 /usr/dict/words
+
+   Ideas:
+
+   Keep a things_to_do list of functions to call when we know we have
+   something to print.  Cleaner than current series of checks.
+
+   Improve the printing of control prefixes.
+
+
+   Options:
+
+   +PAGE       Begin output at page PAGE of the output.
+
+   -COLUMN     Produce output that is COLUMN columns wide and print
+               columns down.
+
+   -a          Print columns across rather than down.  The input
+               one
+               two
+               three
+               four
+               will be printed as
+               one     two     three
+               four
+
+   -b          Balance columns on the last page.
+
+   -c          Print unprintable characters as control prefixes.
+               Control-g is printed as ^G.
+
+   -d          Double space the output.
+
+   -e[c[k]]    Expand tabs to spaces on input.  Optional argument C
+               is the input tab character. (Default is `\t'.)  Optional
+               argument K is the input tab character's width.  (Default is 8.)
+
+   -F
+   -f          Use formfeeds instead of newlines to separate pages.
+
+   -h header   Replace the filename in the header with the string HEADER.
+
+   -i[c[k]]    Replace spaces with tabs on output.  Optional argument
+               C is the output tab character.  (Default is `\t'.)  Optional
+               argument K is the output tab character's width.  (Default
+               is 8.)
+
+   -l lines    Set the page length to LINES.  Default is 66.
+
+   -m          Print files in parallel.
+
+   -n[c[k]]    Precede each column with a line number.
+               (With parallel files, precede each line with a line
+               number.)  Optional argument C is the character to print
+               after each number.  (Default `\t'.)  Optional argument
+               K is the number of digits per line number.  (Default 5.)
+
+   -o offset   Offset each line with a margin OFFSET spaces wide.
+               Total page width is the size of this offset plus the
+               width set with `-w'.
+
+   -r          Ignore files that can't be opened.
+
+   -s[c]       Separate each line with a character.  Optional argument C is
+               the character to be used.  Default is `\t'.
+
+   -t          Do not print headers or footers.
+
+   -v          Print unprintable characters as escape sequences.
+               Control-G becomes \007.
+
+   -w width    Set the page width to WIDTH characters. */
+\f
+
+#include <stdio.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <time.h>
+#include "system.h"
+#include "version.h"
+
+char *xmalloc ();
+char *xrealloc ();
+void error ();
+
+static int char_to_clump ();
+static int read_line ();
+static int print_page ();
+static int print_stored ();
+static int open_file ();
+static int skip_to_page ();
+static void getoptarg ();
+static void usage ();
+static void print_files ();
+static void init_header ();
+static void init_store_cols ();
+static void store_columns ();
+static void balance ();
+static void store_char ();
+static void pad_down ();
+static void read_rest_of_line ();
+static void print_char ();
+static void cleanup ();
+
+#ifndef TRUE
+#define TRUE   1
+#define FALSE  0
+#endif
+
+/* Used with start_position in the struct COLUMN described below.
+   If start_position == ANYWHERE, we aren't truncating columns and
+   can begin printing a column anywhere.  Otherwise we must pad to
+   the horizontal position start_position. */
+#define ANYWHERE       0
+
+/* Each column has one of these structures allocated for it.
+   If we're only dealing with one file, fp is the same for all
+   columns.
+
+   The general strategy is to spend time setting up these column
+   structures (storing columns if necessary), after which printing
+   is a matter of flitting from column to column and calling
+   print_func.
+
+   Parallel files, single files printing across in multiple
+   columns, and single files printing down in multiple columns all
+   fit the same printing loop.
+
+   print_func          Function used to print lines in this column.
+                       If we're storing this column it will be
+                       print_stored(), Otherwise it will be read_line().
+
+   char_func           Function used to process characters in this column.
+                       If we're storing this column it will be store_char(),
+                       otherwise it will be print_char().
+
+   current_line                Index of the current entry in line_vector, which
+                       contains the index of the first character of the
+                       current line in buff[].
+
+   lines_stored                Number of lines in this column which are stored in
+                       buff.
+
+   lines_to_print      If we're storing this column, lines_to_print is
+                       the number of stored_lines which remain to be
+                       printed.  Otherwise it is the number of lines
+                       we can print without exceeding lines_per_body.
+
+   start_position      The horizontal position we want to be in before we
+                       print the first character in this column.
+
+   numbered            True means precede this column with a line number. */
+
+struct COLUMN
+{
+  FILE *fp;                    /* Input stream for this column. */
+  char *name;                  /* File name. */
+  enum
+  {
+    OPEN,
+    ON_HOLD,                   /* Hit a form feed. */
+    CLOSED
+  } status;                    /* Status of the file pointer. */
+  int (*print_func) ();                /* Func to print lines in this col. */
+  void (*char_func) ();                /* Func to print/store chars in this col. */
+  int current_line;            /* Index of current place in line_vector. */
+  int lines_stored;            /* Number of lines stored in buff. */
+  int lines_to_print;          /* No. lines stored or space left on page. */
+  int start_position;          /* Horizontal position of first char. */
+  int numbered;
+};
+
+typedef struct COLUMN COLUMN;
+
+#define NULLCOL (COLUMN *)0
+
+/* The name under which this program was invoked. */
+char *program_name;
+
+/* All of the columns to print.  */
+static COLUMN *column_vector;
+
+/* When printing a single file in multiple downward columns,
+   we store the leftmost columns contiguously in buff.
+   To print a line from buff, get the index of the first char
+   from line_vector[i], and print up to line_vector[i + 1]. */
+static char *buff;
+
+/* Index of the position in buff where the next character
+   will be stored. */
+static int buff_current;
+
+/* The number of characters in buff.
+   Used for allocation of buff and to detect overflow of buff. */
+static int buff_allocated;
+
+/* Array of indices into buff.
+   Each entry is an index of the first character of a line.
+   This is used when storing lines to facilitate shuffling when
+   we do column balancing on the last page. */
+static int *line_vector;
+
+/* Array of horizonal positions.
+   For each line in line_vector, end_vector[line] is the horizontal
+   position we are in after printing that line.  We keep track of this
+   so that we know how much we need to pad to prepare for the next
+   column. */
+static int *end_vector;
+
+/* (-m) True means we're printing multiple files in parallel. */
+static int parallel_files = FALSE;
+
+/* (-[0-9]+) True means we're given an option explicitly specifying
+   number of columns.  Used to detect when this option is used with -m. */
+static int explicit_columns = FALSE;
+
+/* (-t) True means we're printing headers and footers. */
+static int extremities = TRUE;
+
+/* True means we need to print a header as soon as we know we've got input
+   to print after it. */
+static int print_a_header;
+
+/* (-h) True means we're using the standard header rather than a
+   customized one specified by the -h flag. */
+static int standard_header = TRUE;
+
+/* (-f) True means use formfeeds instead of newlines to separate pages. */
+static int use_form_feed = FALSE;
+
+/* True means we have read the standard input. */
+static int have_read_stdin = FALSE;
+
+/* True means the -a flag has been given. */
+static int print_across_flag = FALSE;
+
+/* True means we're printing one file in multiple (>1) downward columns. */
+static int storing_columns = TRUE;
+
+/* (-b) True means balance columns on the last page as Sys V does. */
+static int balance_columns = FALSE;
+
+/* (-l) Number of lines on a page, including header and footer lines. */
+static int lines_per_page = 66;
+
+/* Number of lines in the header and footer can be reset to 0 using
+   the -t flag. */
+static int lines_per_header = 5;
+static int lines_per_body;
+static int lines_per_footer = 5;
+
+/* (-w) Width in characters of the page.  Does not include the width of
+   the margin. */
+static int chars_per_line = 72;
+
+/* Number of characters in a column.  Based on the gutter and page widths. */
+static int chars_per_column;
+
+/* (-e) True means convert tabs to spaces on input. */
+static int untabify_input = FALSE;
+
+/* (-e) The input tab character. */
+static char input_tab_char = '\t';
+
+/* (-e) Tabstops are at chars_per_tab, 2*chars_per_tab, 3*chars_per_tab, ...
+   where the leftmost column is 1. */
+static int chars_per_input_tab = 8;
+
+/* (-i) True means convert spaces to tabs on output. */
+static int tabify_output = FALSE;
+
+/* (-i) The output tab character. */
+static char output_tab_char = '\t';
+
+/* (-i) The width of the output tab. */
+static int chars_per_output_tab = 8;
+
+/* Keeps track of pending white space.  When we hit a nonspace
+   character after some whitespace, we print whitespace, tabbing
+   if necessary to get to output_position + spaces_not_printed. */
+static int spaces_not_printed;
+
+/* Number of spaces between columns (though tabs can be used when possible to
+   use up the equivalent amount of space).  Not sure if this is worth making
+   a flag for.  BSD uses 0, Sys V uses 1.  Sys V looks better. */
+static int chars_per_gutter = 1;
+
+/* (-o) Number of spaces in the left margin (tabs used when possible). */
+static int chars_per_margin = 0;
+
+/* Position where the next character will fall.
+   Leftmost position is 0 + chars_per_margin.
+   Rightmost position is chars_per_margin + chars_per_line - 1.
+   This is important for converting spaces to tabs on output. */
+static int output_position;
+
+/* Horizontal position relative to the current file.
+   (output_position depends on where we are on the page;
+   input_position depends on where we are in the file.)
+   Important for converting tabs to spaces on input. */
+static int input_position;
+
+/* Count number of failed opens so we can exit with non-zero
+   status if there were any.  */
+static int failed_opens = 0;
+
+/* The horizontal position we'll be at after printing a tab character
+   of width c_ from the position h_. */
+#define pos_after_tab(c_, h_) h_ - h_ % c_ + c_
+
+/* The number of spaces taken up if we print a tab character with width
+   c_ from position h_. */
+#define tab_width(c_, h_) - h_ % c_ + c_
+
+/* (-NNN) Number of columns of text to print. */
+static int columns = 1;
+
+/* (+NNN) Page number on which to begin printing. */
+static int first_page_number = 1;
+
+/* Number of files open (not closed, not on hold). */
+static int files_ready_to_read = 0;
+
+/* Current page number.  Displayed in header. */
+static int page_number;
+
+/* Current line number.  Displayed when -n flag is specified.
+
+   When printing files in parallel (-m flag), line numbering is as follows:
+   1   foo     goo     moo
+   2   hoo     too     zoo
+
+   When printing files across (-a flag), ...
+   1   foo     2       moo     3       goo
+   4   hoo     3       too     6       zoo
+
+   Otherwise, line numbering is as follows:
+   1   foo     3       goo     5       too
+   2   moo     4       hoo     6       zoo */
+static int line_number;
+
+/* (-n) True means lines should be preceded by numbers. */
+static int numbered_lines = FALSE;
+
+/* (-n) Character which follows each line number. */
+static char number_separator = '\t';
+
+/* (-n) Width in characters of a line number. */
+static int chars_per_number = 5;
+
+/* Used when widening the first column to accommodate numbers -- only
+   needed when printing files in parallel.  Includes width of both the
+   number and the number_separator. */
+static int number_width;
+
+/* Buffer sprintf uses to format a line number. */
+static char *number_buff;
+
+/* (-v) True means unprintable characters are printed as escape sequences.
+   control-g becomes \007. */
+static int use_esc_sequence = FALSE;
+
+/* (-c) True means unprintable characters are printed as control prefixes.
+   control-g becomes ^G. */
+static int use_cntrl_prefix = FALSE;
+
+/* (-d) True means output is double spaced. */
+static int double_space = FALSE;
+
+/* Number of files opened initially in init_files.  Should be 1
+   unless we're printing multiple files in parallel. */
+static int total_files = 0;
+
+/* (-r) True means don't complain if we can't open a file. */
+static int ignore_failed_opens = FALSE;
+
+/* (-s) True means we separate columns with a specified character. */
+static int use_column_separator = FALSE;
+
+/* Character used to separate columns if the the -s flag has been specified. */
+static char column_separator = '\t';
+
+/* Number of separator characters waiting to be printed as soon as we
+   know that we have any input remaining to be printed. */
+static int separators_not_printed;
+
+/* Position we need to pad to, as soon as we know that we have input
+   remaining to be printed. */
+static int padding_not_printed;
+
+/* True means we should pad the end of the page.  Remains false until we
+   know we have a page to print. */
+static int pad_vertically;
+
+/* (-h) String of characters used in place of the filename in the header. */
+static char *custom_header;
+
+/* String containing the date, filename or custom header, and "Page ". */
+static char *header;
+
+static int *clump_buff;
+
+/* True means we truncate lines longer than chars_per_column. */
+static int truncate_lines = FALSE;
+
+/* If non-zero, display usage information and exit.  */
+static int flag_help;
+
+/* If non-zero, print the version on standard error.  */
+static int flag_version;
+
+static struct option const long_options[] =
+{
+  {"help", no_argument, &flag_help, 1},
+  {"version", no_argument, &flag_version, 1},
+  {0, 0, 0, 0}
+};
+
+/* Return the number of columns that have either an open file or
+   stored lines. */
+
+static int
+cols_ready_to_print ()
+{
+  COLUMN *q;
+  int i;
+  int n;
+
+  n = 0;
+  for (q = column_vector, i = 0; i < columns; ++q, ++i)
+    if (q->status == OPEN ||
+       (storing_columns && q->lines_stored > 0 && q->lines_to_print > 0))
+      ++n;
+  return n;
+}
+
+void
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int accum = 0;
+  int n_files;
+  char **file_names;
+
+  program_name = argv[0];
+
+  n_files = 0;
+  file_names = (char **) xmalloc ((argc - 1) * sizeof (char *));
+
+  while (1)
+    {
+      c = getopt_long (argc, argv,
+                      "-0123456789abcde::fFh:i::l:mn::o:rs::tvw:",
+                      long_options, (int *) 0);
+      if (c == 1)              /* Non-option argument. */
+       {
+         char *s;
+         s = optarg;
+         if (*s == '+')
+           {
+             ++s;
+             if (!ISDIGIT (*s))
+               {
+                 error (0, 0, "`+' requires a numeric argument");
+                 usage ();
+               }
+             /* FIXME: use strtol */
+             first_page_number = atoi (s);
+           }
+         else
+           {
+             file_names[n_files++] = optarg;
+           }
+       }
+      else
+       {
+         if (ISDIGIT (c))
+           {
+             accum = accum * 10 + c - '0';
+             continue;
+           }
+         else
+           {
+             if (accum > 0)
+               {
+                 columns = accum;
+                 explicit_columns = TRUE;
+                 accum = 0;
+               }
+           }
+       }
+
+      if (c == 1)
+       continue;
+
+      if (c == EOF)
+       break;
+
+      switch (c)
+       {
+       case 0: /* getopt long option */
+         break;
+
+       case 'a':
+         print_across_flag = TRUE;
+         storing_columns = FALSE;
+         break;
+       case 'b':
+         balance_columns = TRUE;
+         break;
+       case 'c':
+         use_cntrl_prefix = TRUE;
+         break;
+       case 'd':
+         double_space = TRUE;
+         break;
+       case 'e':
+         if (optarg)
+           getoptarg (optarg, 'e', &input_tab_char,
+                      &chars_per_input_tab);
+         /* Could check tab width > 0. */
+         untabify_input = TRUE;
+         break;
+       case 'f':
+       case 'F':
+         use_form_feed = TRUE;
+         break;
+       case 'h':
+         custom_header = optarg;
+         standard_header = FALSE;
+         break;
+       case 'i':
+         if (optarg)
+           getoptarg (optarg, 'i', &output_tab_char,
+                      &chars_per_output_tab);
+         /* Could check tab width > 0. */
+         tabify_output = TRUE;
+         break;
+       case 'l':
+         lines_per_page = atoi (optarg);
+         break;
+       case 'm':
+         parallel_files = TRUE;
+         storing_columns = FALSE;
+         break;
+       case 'n':
+         numbered_lines = TRUE;
+         if (optarg)
+           getoptarg (optarg, 'n', &number_separator,
+                      &chars_per_number);
+         break;
+       case 'o':
+         chars_per_margin = atoi (optarg);
+         break;
+       case 'r':
+         ignore_failed_opens = TRUE;
+         break;
+       case 's':
+         use_column_separator = TRUE;
+         if (optarg)
+           {
+             char *s;
+             s = optarg;
+             column_separator = *s;
+             if (*++s)
+               {
+                 fprintf (stderr, "\
+%s: extra characters in the argument to the `-s' option: `%s'\n",
+                          program_name, s);
+                 usage ();
+               }
+           }
+         break;
+       case 't':
+         extremities = FALSE;
+         break;
+       case 'v':
+         use_esc_sequence = TRUE;
+         break;
+       case 'w':
+         chars_per_line = atoi (optarg);
+         break;
+       default:
+         usage ();
+         break;
+       }
+    }
+
+  if (flag_version)
+    {
+      fprintf (stderr, "%s\n", version_string);
+      exit (0);
+    }
+
+  if (flag_help)
+    usage ();
+
+  if (parallel_files && explicit_columns)
+    error (1, 0,
+  "Cannot specify number of columns when printing in parallel.");
+
+  if (parallel_files && print_across_flag)
+    error (1, 0,
+  "Cannot specify both printing across and printing in parallel.");
+
+  for ( ; optind < argc; optind++)
+    {
+      file_names[n_files++] = argv[optind];
+    }
+
+  if (n_files == 0)
+    {
+      /* No file arguments specified;  read from standard input.  */
+      print_files (0, (char **) 0);
+    }
+  else
+    {
+      if (parallel_files)
+       print_files (n_files, file_names);
+      else
+       {
+         int i;
+         for (i=0; i<n_files; i++)
+           print_files (1, &file_names[i]);
+       }
+    }
+
+  cleanup ();
+
+  if (have_read_stdin && fclose (stdin) == EOF)
+    error (1, errno, "standard input");
+  if (ferror (stdout) || fclose (stdout) == EOF)
+    error (1, errno, "write error");
+  if (failed_opens > 0)
+    exit(1);
+  exit (0);
+}
+
+/* Parse options of the form -scNNN.
+
+   Example: -nck, where 'n' is the option, c is the optional number
+   separator, and k is the optional width of the field used when printing
+   a number. */
+
+static void
+getoptarg (arg, switch_char, character, number)
+     char *arg, switch_char, *character;
+     int *number;
+{
+  if (!ISDIGIT (*arg))
+    *character = *arg++;
+  if (*arg)
+    {
+      if (ISDIGIT (*arg))
+       *number = atoi (arg);
+      else
+       {
+         fprintf (stderr, "\
+%s: extra characters in the argument to the `-%c' option: `%s'\n",
+                  program_name, switch_char, arg);
+         usage ();
+       }
+    }
+}
+\f
+/* Set parameters related to formatting. */
+
+static void
+init_parameters (number_of_files)
+     int number_of_files;
+{
+  int chars_used_by_number = 0;
+
+  lines_per_body = lines_per_page - lines_per_header - lines_per_footer;
+  if (lines_per_body <= 0)
+    extremities = FALSE;
+  if (extremities == FALSE)
+    lines_per_body = lines_per_page;
+
+  if (double_space)
+    lines_per_body = lines_per_body / 2;
+
+  /* If input is stdin, cannot print parallel files.  BSD dumps core
+     on this. */
+  if (number_of_files == 0)
+    parallel_files = FALSE;
+
+  if (parallel_files)
+    columns = number_of_files;
+
+  /* Tabification is assumed for multiple columns. */
+  if (columns > 1)
+    {
+      if (!use_column_separator)
+       truncate_lines = TRUE;
+
+      untabify_input = TRUE;
+      tabify_output = TRUE;
+    }
+  else
+    storing_columns = FALSE;
+
+  if (numbered_lines)
+    {
+      if (number_separator == input_tab_char)
+       {
+         number_width = chars_per_number +
+           tab_width (chars_per_input_tab,
+                      (chars_per_margin + chars_per_number));
+       }
+      else
+       number_width = chars_per_number + 1;
+      /* The number is part of the column width unless we are
+         printing files in parallel. */
+      if (parallel_files)
+       chars_used_by_number = number_width;
+    }
+
+  chars_per_column = (chars_per_line - chars_used_by_number -
+                     (columns - 1) * chars_per_gutter) / columns;
+
+  if (chars_per_column < 1)
+    error (1, 0, "page width too narrow");
+
+  if (numbered_lines)
+    {
+      if (number_buff != (char *) 0)
+       free (number_buff);
+      number_buff = (char *)
+       xmalloc (2 * chars_per_number * sizeof (char));
+    }
+
+  /* Pick the maximum between the tab width and the width of an
+     escape sequence. */
+  if (clump_buff != (int *) 0)
+    free (clump_buff);
+  clump_buff = (int *) xmalloc ((chars_per_input_tab > 4
+                                ? chars_per_input_tab : 4) * sizeof (int));
+}
+\f
+/* Open the necessary files,
+   maintaining a COLUMN structure for each column.
+
+   With multiple files, each column p has a different p->fp.
+   With single files, each column p has the same p->fp.
+   Return 1 if (number_of_files > 0) and no files can be opened,
+   0 otherwise.  */
+
+static int
+init_fps (number_of_files, av)
+     int number_of_files;
+     char **av;
+{
+  int i, files_left;
+  COLUMN *p;
+  FILE *firstfp;
+  char *firstname;
+
+  total_files = 0;
+
+  if (column_vector != NULLCOL)
+    free ((char *) column_vector);
+  column_vector = (COLUMN *) xmalloc (columns * sizeof (COLUMN));
+
+  if (parallel_files)
+    {
+      files_left = number_of_files;
+      for (p = column_vector; files_left--; ++p, ++av)
+       {
+         if (open_file (*av, p) == 0)
+           {
+             --p;
+             --columns;
+           }
+       }
+      if (columns == 0)
+       return 1;
+      init_header ("", -1);
+    }
+  else
+    {
+      p = column_vector;
+      if (number_of_files > 0)
+       {
+         if (open_file (*av, p) == 0)
+           return 1;
+         init_header (*av, fileno (p->fp));
+       }
+      else
+       {
+         p->name = "standard input";
+         p->fp = stdin;
+         have_read_stdin = TRUE;
+         p->status = OPEN;
+         ++total_files;
+         init_header ("", -1);
+       }
+
+      firstname = p->name;
+      firstfp = p->fp;
+      for (i = columns - 1, ++p; i; --i, ++p)
+       {
+         p->name = firstname;
+         p->fp = firstfp;
+         p->status = OPEN;
+       }
+    }
+  files_ready_to_read = total_files;
+  return 0;
+}
+\f
+/* Determine print_func and char_func, the functions
+   used by each column for printing and/or storing.
+
+   Determine the horizontal position desired when we begin
+   printing a column (p->start_position). */
+
+static void
+init_funcs ()
+{
+  int i, h, h_next;
+  COLUMN *p;
+
+  h = chars_per_margin;
+
+  if (use_column_separator)
+    h_next = ANYWHERE;
+  else
+    {
+      /* When numbering lines of parallel files, we enlarge the
+         first column to accomodate the number.  Looks better than
+         the Sys V approach. */
+      if (parallel_files && numbered_lines)
+       h_next = h + chars_per_column + number_width;
+      else
+       h_next = h + chars_per_column;
+    }
+
+  /* This loop takes care of all but the rightmost column. */
+
+  for (p = column_vector, i = 1; i < columns; ++p, ++i)
+    {
+      if (storing_columns)     /* One file, multi columns down. */
+       {
+         p->char_func = store_char;
+         p->print_func = print_stored;
+       }
+      else
+       /* One file, multi columns across; or parallel files.  */
+       {
+         p->char_func = print_char;
+         p->print_func = read_line;
+       }
+
+      /* Number only the first column when printing files in
+         parallel. */
+      p->numbered = numbered_lines && (!parallel_files || i == 1);
+      p->start_position = h;
+
+      /* If we're using separators, all start_positions are
+         ANYWHERE, except the first column's start_position when
+         using a margin. */
+
+      if (use_column_separator)
+       {
+         h = ANYWHERE;
+         h_next = ANYWHERE;
+       }
+      else
+       {
+         h = h_next + chars_per_gutter;
+         h_next = h + chars_per_column;
+       }
+    }
+
+  /* The rightmost column.
+
+     Doesn't need to be stored unless we intend to balance
+     columns on the last page. */
+  if (storing_columns && balance_columns)
+    {
+      p->char_func = store_char;
+      p->print_func = print_stored;
+    }
+  else
+    {
+      p->char_func = print_char;
+      p->print_func = read_line;
+    }
+
+  p->numbered = numbered_lines && (!parallel_files || i == 1);
+  p->start_position = h;
+}
+\f
+/* Open a file.  Return nonzero if successful, zero if failed. */
+
+static int
+open_file (name, p)
+     char *name;
+     COLUMN *p;
+{
+  if (!strcmp (name, "-"))
+    {
+      p->name = "standard input";
+      p->fp = stdin;
+      have_read_stdin = 1;
+    }
+  else
+    {
+      p->name = name;
+      p->fp = fopen (name, "r");
+    }
+  if (p->fp == NULL)
+    {
+      ++failed_opens;
+      if (!ignore_failed_opens)
+       error (0, errno, "%s", name);
+      return 0;
+    }
+  p->status = OPEN;
+  ++total_files;
+  return 1;
+}
+
+/* Close the file in P.
+
+   If we aren't dealing with multiple files in parallel, we change
+   the status of all columns in the column list to reflect the close. */
+
+static void
+close_file (p)
+     COLUMN *p;
+{
+  COLUMN *q;
+  int i;
+
+  if (p->status == CLOSED)
+    return;
+  if (ferror (p->fp))
+    error (1, errno, "%s", p->name);
+  if (p->fp != stdin && fclose (p->fp) == EOF)
+    error (1, errno, "%s", p->name);
+
+  if (!parallel_files)
+    {
+      for (q = column_vector, i = columns; i; ++q, --i)
+       {
+         q->status = CLOSED;
+         if (q->lines_stored == 0)
+           {
+             q->lines_to_print = 0;
+           }
+       }
+    }
+  else
+    {
+      p->status = CLOSED;
+      p->lines_to_print = 0;
+    }
+
+  --files_ready_to_read;
+}
+
+/* Put a file on hold until we start a new page,
+   since we've hit a form feed.
+
+   If we aren't dealing with parallel files, we must change the
+   status of all columns in the column list. */
+
+static void
+hold_file (p)
+     COLUMN *p;
+{
+  COLUMN *q;
+  int i;
+
+  if (!parallel_files)
+    for (q = column_vector, i = columns; i; ++q, --i)
+      q->status = ON_HOLD;
+  else
+    p->status = ON_HOLD;
+  p->lines_to_print = 0;
+  --files_ready_to_read;
+}
+
+/* Undo hold_file -- go through the column list and change any
+   ON_HOLD columns to OPEN.  Used at the end of each page. */
+
+static void
+reset_status ()
+{
+  int i = columns;
+  COLUMN *p;
+
+  for (p = column_vector; i; --i, ++p)
+    if (p->status == ON_HOLD)
+      {
+       p->status = OPEN;
+       files_ready_to_read++;
+      }
+}
+\f
+/* Print a single file, or multiple files in parallel.
+
+   Set up the list of columns, opening the necessary files.
+   Allocate space for storing columns, if necessary.
+   Skip to first_page_number, if user has asked to skip leading pages.
+   Determine which functions are appropriate to store/print lines
+   in each column.
+   Print the file(s). */
+
+static void
+print_files (number_of_files, av)
+     int number_of_files;
+     char **av;
+{
+  init_parameters (number_of_files);
+  if (init_fps (number_of_files, av))
+    return;
+  if (storing_columns)
+    init_store_cols ();
+
+  if (first_page_number > 1)
+    {
+      if (!skip_to_page (first_page_number))
+       return;
+      else
+       page_number = first_page_number;
+    }
+  else
+    page_number = 1;
+
+  init_funcs ();
+
+  line_number = 1;
+  while (print_page ())
+    ;
+}
+\f
+/* Generous estimate of number of characters taken up by "Jun  7 00:08 " and
+   "Page NNNNN". */
+#define CHARS_FOR_DATE_AND_PAGE        50
+
+/* Initialize header information.
+   If DESC is non-negative, it is a file descriptor open to
+   FILENAME for reading.
+
+   Allocate space for a header string,
+   Determine the time, insert file name or user-specified string.
+
+   It might be nice to have a "blank headers" option, since
+   pr -h "" still prints the date and page number. */
+
+static void
+init_header (filename, desc)
+     char *filename;
+     int desc;
+{
+  int chars_per_header;
+  char *f = filename;
+  char *t, *middle;
+  struct stat st;
+
+  if (filename == 0)
+    f = "";
+
+  /* If parallel files or standard input, use current time. */
+  if (desc < 0 || !strcmp (filename, "-") || fstat (desc, &st))
+    st.st_mtime = time ((time_t *) 0);
+  t = ctime (&st.st_mtime);
+
+  t[16] = '\0';                        /* Mark end of month and time string. */
+  t[24] = '\0';                        /* Mark end of year string. */
+
+  middle = standard_header ? f : custom_header;
+
+  chars_per_header = strlen (middle) + CHARS_FOR_DATE_AND_PAGE + 1;
+  if (header != (char *) 0)
+    free (header);
+  header = (char *) xmalloc (chars_per_header * sizeof (char));
+
+  sprintf (header, "%s %s  %s Page", &t[4], &t[20], middle);
+}
+\f
+/* Set things up for printing a page
+
+   Scan through the columns ...
+     Determine which are ready to print
+       (i.e., which have lines stored or open files)
+     Set p->lines_to_print appropriately
+       (to p->lines_stored if we're storing, or lines_per_body
+       if we're reading straight from the file)
+     Keep track of this total so we know when to stop printing */
+
+static void
+init_page ()
+{
+  int j;
+  COLUMN *p;
+
+  if (storing_columns)
+    {
+      store_columns ();
+      for (j = columns - 1, p = column_vector; j; --j, ++p)
+       {
+         p->lines_to_print = p->lines_stored;
+       }
+
+      /* Last column. */
+      if (balance_columns)
+       {
+         p->lines_to_print = p->lines_stored;
+       }
+      /* Since we're not balancing columns, we don't need to store
+         the rightmost column.   Read it straight from the file. */
+      else
+       {
+         if (p->status == OPEN)
+           {
+             p->lines_to_print = lines_per_body;
+           }
+         else
+           p->lines_to_print = 0;
+       }
+    }
+  else
+    for (j = columns, p = column_vector; j; --j, ++p)
+      if (p->status == OPEN)
+       {
+         p->lines_to_print = lines_per_body;
+       }
+      else
+       p->lines_to_print = 0;
+}
+
+/* Print one page.
+
+   As long as there are lines left on the page and columns ready to print,
+     Scan across the column list
+       if the column has stored lines or the file is open
+         pad to the appropriate spot
+         print the column
+   pad the remainder of the page with \n or \f as requested
+   reset the status of all files -- any files which where on hold because
+     of formfeeds are now put back into the lineup. */
+
+static int
+print_page ()
+{
+  int j;
+  int lines_left_on_page;
+  COLUMN *p;
+
+  /* Used as an accumulator (with | operator) of successive values of
+     pad_vertically.  The trick is to set pad_vertically
+     to zero before each run through the inner loop, then after that
+     loop, it tells us whether a line was actually printed (whether a
+     newline needs to be output -- or two for double spacing).  But those
+     values have to be accumulated (in pv) so we can invoke pad_down
+     properly after the outer loop completes. */
+  int pv;
+
+  init_page ();
+
+  if (cols_ready_to_print () == 0)
+    return FALSE;
+
+  if (extremities)
+    print_a_header = TRUE;
+
+  /* Don't pad unless we know a page was printed. */
+  pad_vertically = FALSE;
+  pv = FALSE;
+
+  lines_left_on_page = lines_per_body;
+  if (double_space)
+    lines_left_on_page *= 2;
+
+  while (lines_left_on_page > 0 && cols_ready_to_print () > 0)
+    {
+      output_position = 0;
+      spaces_not_printed = 0;
+      separators_not_printed = 0;
+      pad_vertically = FALSE;
+
+      for (j = 1, p = column_vector; j <= columns; ++j, ++p)
+       {
+         input_position = 0;
+         if (p->lines_to_print > 0)
+           {
+             padding_not_printed = p->start_position;
+
+             if (!(p->print_func) (p))
+               read_rest_of_line (p);
+             pv |= pad_vertically;
+
+             if (use_column_separator)
+               ++separators_not_printed;
+
+             --p->lines_to_print;
+             if (p->lines_to_print <= 0)
+               {
+                 if (cols_ready_to_print () <= 0)
+                   break;
+               }
+           }
+       }
+
+      if (pad_vertically)
+       {
+         putchar ('\n');
+         --lines_left_on_page;
+       }
+
+      if (double_space && pv && extremities)
+       {
+         putchar ('\n');
+         --lines_left_on_page;
+       }
+    }
+
+  pad_vertically = pv;
+
+  if (pad_vertically && extremities)
+    pad_down (lines_left_on_page + lines_per_footer);
+
+  reset_status ();             /* Change ON_HOLD to OPEN. */
+
+  return TRUE;                 /* More pages to go. */
+}
+\f
+/* Allocate space for storing columns.
+
+   This is necessary when printing multiple columns from a single file.
+   Lines are stored consecutively in buff, separated by '\0'.
+   (We can't use a fixed offset since with the '-s' flag lines aren't
+   truncated.)
+
+   We maintain a list (line_vector) of pointers to the beginnings
+   of lines in buff.  We allocate one more than the number of lines
+   because the last entry tells us the index of the last character,
+   which we need to know in order to print the last line in buff. */
+
+static void
+init_store_cols ()
+{
+  int total_lines = lines_per_body * columns;
+  int chars_if_truncate = total_lines * (chars_per_column + 1);
+
+  if (line_vector != (int *) 0)
+    free ((int *) line_vector);
+  line_vector = (int *) xmalloc ((total_lines + 1) * sizeof (int *));
+
+  if (end_vector != (int *) 0)
+    free ((int *) end_vector);
+  end_vector = (int *) xmalloc (total_lines * sizeof (int *));
+
+  if (buff != (char *) 0)
+    free (buff);
+  buff_allocated = use_column_separator ? 2 * chars_if_truncate
+    : chars_if_truncate;       /* Tune this. */
+  buff = (char *) xmalloc (buff_allocated * sizeof (char));
+}
+
+/* Store all but the rightmost column.
+   (Used when printing a single file in multiple downward columns)
+
+   For each column
+     set p->current_line to be the index in line_vector of the
+       first line in the column
+     For each line in the column
+       store the line in buff
+       add to line_vector the index of the line's first char
+    buff_start is the index in buff of the first character in the
+     current line. */
+
+static void
+store_columns ()
+{
+  int i, j;
+  int line = 0;
+  int buff_start;
+  int last_col;                        /* The rightmost column which will be saved in buff */
+  COLUMN *p;
+
+  buff_current = 0;
+  buff_start = 0;
+
+  if (balance_columns)
+    last_col = columns;
+  else
+    last_col = columns - 1;
+
+  for (i = 1, p = column_vector; i <= last_col; ++i, ++p)
+    p->lines_stored = 0;
+
+  for (i = 1, p = column_vector; i <= last_col && files_ready_to_read;
+       ++i, ++p)
+    {
+      p->current_line = line;
+      for (j = lines_per_body; j && files_ready_to_read; --j)
+
+       if (p->status == OPEN)  /* Redundant.  Clean up. */
+         {
+           input_position = 0;
+
+           if (!read_line (p, i))
+             read_rest_of_line (p);
+
+           if (p->status == OPEN
+               || buff_start != buff_current)
+             {
+               ++p->lines_stored;
+               line_vector[line] = buff_start;
+               end_vector[line++] = input_position;
+               buff_start = buff_current;
+             }
+         }
+    }
+
+  /* Keep track of the location of the last char in buff. */
+  line_vector[line] = buff_start;
+
+  if (balance_columns && p->lines_stored != lines_per_body)
+    balance (line);
+}
+
+static void
+balance (total_stored)
+     int total_stored;
+{
+  COLUMN *p;
+  int i, lines;
+  int first_line = 0;
+
+  for (i = 1, p = column_vector; i <= columns; ++i, ++p)
+    {
+      lines = total_stored / columns;
+      if (i <= total_stored % columns)
+       ++lines;
+
+      p->lines_stored = lines;
+      p->current_line = first_line;
+
+      first_line += lines;
+    }
+}
+
+/* Store a character in the buffer. */
+
+static void
+store_char (c)
+     int c;
+{
+  if (buff_current >= buff_allocated)
+    {
+      /* May be too generous. */
+      buff_allocated = 2 * buff_allocated;
+      buff = (char *) xrealloc (buff, buff_allocated * sizeof (char));
+    }
+  buff[buff_current++] = (char) c;
+}
+
+static void
+number (p)
+     COLUMN *p;
+{
+  int i;
+  char *s;
+
+  sprintf (number_buff, "%*d", chars_per_number, line_number++);
+  s = number_buff;
+  for (i = chars_per_number; i > 0; i--)
+    (p->char_func) ((int) *s++);
+
+  if (number_separator == input_tab_char)
+    {
+      i = number_width - chars_per_number;
+      while (i-- > 0)
+       (p->char_func) ((int) ' ');
+    }
+  else
+    (p->char_func) ((int) number_separator);
+
+  if (truncate_lines && !parallel_files)
+    input_position += number_width;
+}
+\f
+/* Print (or store) padding until the current horizontal position
+   is position. */
+
+static void
+pad_across_to (position)
+     int position;
+{
+  register int h = output_position;
+
+  if (tabify_output)
+    spaces_not_printed = position - output_position;
+  else
+    {
+      while (++h <= position)
+       putchar (' ');
+      output_position = position;
+    }
+}
+
+/* Pad to the bottom of the page.
+
+   If the user has requested a formfeed, use one.
+   Otherwise, use newlines. */
+
+static void
+pad_down (lines)
+     int lines;
+{
+  register int i;
+
+  if (use_form_feed)
+    putchar ('\f');
+  else
+    for (i = lines; i; --i)
+      putchar ('\n');
+}
+
+/* Read the rest of the line.
+
+   Read from the current column's file until an end of line is
+   hit.  Used when we've truncated a line and we no longer need
+   to print or store its characters. */
+
+static void
+read_rest_of_line (p)
+     COLUMN *p;
+{
+  register int c;
+  FILE *f = p->fp;
+
+  while ((c = getc (f)) != '\n')
+    {
+      if (c == '\f')
+       {
+         hold_file (p);
+         break;
+       }
+      else if (c == EOF)
+       {
+         close_file (p);
+         break;
+       }
+    }
+}
+\f
+/* If we're tabifying output,
+
+   When print_char encounters white space it keeps track
+   of our desired horizontal position and delays printing
+   until this function is called. */
+
+static void
+print_white_space ()
+{
+  register int h_new;
+  register int h_old = output_position;
+  register int goal = h_old + spaces_not_printed;
+
+  while (goal - h_old > 1
+         && (h_new = pos_after_tab (chars_per_output_tab, h_old)) <= goal)
+    {
+      putchar (output_tab_char);
+      h_old = h_new;
+    }
+  while (++h_old <= goal)
+    putchar (' ');
+
+  output_position = goal;
+  spaces_not_printed = 0;
+}
+
+/* Print column separators.
+
+   We keep a count until we know that we'll be printing a line,
+   then print_separators() is called. */
+
+static void
+print_separators ()
+{
+  for (; separators_not_printed > 0; --separators_not_printed)
+    print_char (column_separator);
+}
+
+/* Print (or store, depending on p->char_func) a clump of N
+   characters. */
+
+static void
+print_clump (p, n, clump)
+     COLUMN *p;
+     int n;
+     int *clump;
+{
+  while (n--)
+    (p->char_func) (*clump++);
+}
+
+/* Print a character.
+
+   If we're tabifying, all tabs have been converted to spaces by
+   process_char().  Keep a count of consecutive spaces, and when
+   a nonspace is encountered, call print_white_space() to print the
+   required number of tabs and spaces. */
+
+static void
+print_char (c)
+     int c;
+{
+  if (tabify_output)
+    {
+      if (c == ' ')
+       {
+         ++spaces_not_printed;
+         return;
+       }
+      else if (spaces_not_printed > 0)
+       print_white_space ();
+
+      /* Nonprintables are assumed to have width 0, except '\b'. */
+      if (!ISPRINT (c))
+       {
+         if (c == '\b')
+           --output_position;
+       }
+      else
+       ++output_position;
+    }
+  putchar (c);
+}
+
+/* Skip to page PAGE before printing. */
+
+static int
+skip_to_page (page)
+     int page;
+{
+  int n, i, j;
+  COLUMN *p;
+
+  for (n = 1; n < page; ++n)
+    {
+      for (i = 1; i <= lines_per_body; ++i)
+       {
+         for (j = 1, p = column_vector; j <= columns; ++j, ++p)
+           read_rest_of_line (p);
+       }
+      reset_status ();
+    }
+  return files_ready_to_read > 0;
+}
+
+/* Print a header.
+
+   Formfeeds are assumed to use up two lines at the beginning of
+   the page. */
+
+static void
+print_header ()
+{
+  if (!use_form_feed)
+    fprintf (stdout, "\n\n");
+
+  output_position = 0;
+  pad_across_to (chars_per_margin);
+  print_white_space ();
+
+  fprintf (stdout, "%s %d\n\n\n", header, page_number++);
+
+  print_a_header = FALSE;
+  output_position = 0;
+}
+
+/* Print (or store, if p->char_func is store_char()) a line.
+
+   Read a character to determine whether we have a line or not.
+   (We may hit EOF, \n, or \f)
+
+   Once we know we have a line,
+     set pad_vertically = TRUE, meaning it's safe
+       to pad down at the end of the page, since we do have a page.
+       print a header if needed.
+     pad across to padding_not_printed if needed.
+     print any separators which need to be printed.
+     print a line number if it needs to be printed.
+
+   Print the clump which corresponds to the first character.
+
+   Enter a loop and keep printing until an end of line condition
+     exists, or until we exceed chars_per_column.
+
+   Return FALSE if we exceed chars_per_column before reading
+     an end of line character, TRUE otherwise. */
+
+static int
+read_line (p)
+     COLUMN *p;
+{
+  register int c, chars;
+  int last_input_position;
+
+  c = getc (p->fp);
+
+  last_input_position = input_position;
+  switch (c)
+    {
+    case '\f':
+      hold_file (p);
+      return TRUE;
+    case EOF:
+      close_file (p);
+      return TRUE;
+    case '\n':
+      break;
+    default:
+      chars = char_to_clump (c);
+    }
+
+  if (truncate_lines && input_position > chars_per_column)
+    {
+      input_position = last_input_position;
+      return FALSE;
+    }
+
+  if (p->char_func != store_char)
+    {
+      pad_vertically = TRUE;
+
+      if (print_a_header)
+       print_header ();
+
+      if (padding_not_printed != ANYWHERE)
+       {
+         pad_across_to (padding_not_printed);
+         padding_not_printed = ANYWHERE;
+       }
+
+      if (use_column_separator)
+       print_separators ();
+    }
+
+  if (p->numbered)
+    number (p);
+
+  if (c == '\n')
+    return TRUE;
+
+  print_clump (p, chars, clump_buff);
+
+  for (;;)
+    {
+      c = getc (p->fp);
+
+      switch (c)
+       {
+       case '\n':
+         return TRUE;
+       case '\f':
+         hold_file (p);
+         return TRUE;
+       case EOF:
+         close_file (p);
+         return TRUE;
+       }
+
+      last_input_position = input_position;
+      chars = char_to_clump (c);
+      if (truncate_lines && input_position > chars_per_column)
+       {
+         input_position = last_input_position;
+         return FALSE;
+       }
+
+      print_clump (p, chars, clump_buff);
+    }
+}
+
+/* Print a line from buff.
+
+   If this function has been called, we know we have something to
+   print.  Therefore we set pad_vertically to TRUE, print
+   a header if necessary, pad across if necessary, and print
+   separators if necessary.
+
+   Return TRUE, meaning there is no need to call read_rest_of_line. */
+
+static int
+print_stored (p)
+     COLUMN *p;
+{
+  int line = p->current_line++;
+  register char *first = &buff[line_vector[line]];
+  register char *last = &buff[line_vector[line + 1]];
+
+  pad_vertically = TRUE;
+
+  if (print_a_header)
+    print_header ();
+
+  if (padding_not_printed != ANYWHERE)
+    {
+      pad_across_to (padding_not_printed);
+      padding_not_printed = ANYWHERE;
+    }
+
+  if (use_column_separator)
+    print_separators ();
+
+  while (first != last)
+    print_char (*first++);
+
+  if (spaces_not_printed == 0)
+    output_position = p->start_position + end_vector[line];
+
+  return TRUE;
+}
+
+/* Convert a character to the proper format and return the number of
+   characters in the resulting clump.  Increment input_position by
+   the width of the clump.
+
+   Tabs are converted to clumps of spaces.
+   Nonprintable characters may be converted to clumps of escape
+   sequences or control prefixes.
+
+   Note: the width of a clump is not necessarily equal to the number of
+   characters in clump_buff.  (e.g, the width of '\b' is -1, while the
+   number of characters is 1.) */
+
+static int
+char_to_clump (c)
+     int c;
+{
+  register int *s = clump_buff;
+  register int i;
+  char esc_buff[4];
+  int width;
+  int chars;
+
+  if (c == input_tab_char)
+    {
+      width = tab_width (chars_per_input_tab, input_position);
+
+      if (untabify_input)
+       {
+         for (i = width; i; --i)
+           *s++ = ' ';
+         chars = width;
+       }
+      else
+       {
+         *s = c;
+         chars = 1;
+       }
+
+    }
+  else if (!ISPRINT (c))
+    {
+      if (use_esc_sequence)
+       {
+         width = 4;
+         chars = 4;
+         *s++ = '\\';
+         sprintf (esc_buff, "%03o", c);
+         for (i = 0; i <= 2; ++i)
+           *s++ = (int) esc_buff[i];
+       }
+      else if (use_cntrl_prefix)
+       {
+         if (c < 0200)
+           {
+             width = 2;
+             chars = 2;
+             *s++ = '^';
+             *s++ = c ^ 0100;
+           }
+         else
+           {
+             width = 4;
+             chars = 4;
+             *s++ = '\\';
+             sprintf (esc_buff, "%03o", c);
+             for (i = 0; i <= 2; ++i)
+               *s++ = (int) esc_buff[i];
+           }
+       }
+      else if (c == '\b')
+       {
+         width = -1;
+         chars = 1;
+         *s = c;
+       }
+      else
+       {
+         width = 0;
+         chars = 1;
+         *s = c;
+       }
+    }
+  else
+    {
+      width = 1;
+      chars = 1;
+      *s = c;
+    }
+
+  input_position += width;
+  return chars;
+}
+
+/* We've just printed some files and need to clean up things before
+   looking for more options and printing the next batch of files.
+
+   Free everything we've xmalloc'ed, except `header'. */
+
+static void
+cleanup ()
+{
+  if (number_buff)
+    free (number_buff);
+  if (clump_buff)
+    free (clump_buff);
+  if (column_vector)
+    free (column_vector);
+  if (line_vector)
+    free (line_vector);
+  if (end_vector)
+    free (end_vector);
+  if (buff)
+    free (buff);
+}
+\f
+/* Complain, print a usage message, and die. */
+
+static void
+usage ()
+{
+  fprintf (stderr, "\
+Usage: %s [+PAGE] [-COLUMN] [-abcdfFmrtv] [-e[in-tab-char[in-tab-width]]]\n\
+       [-h header] [-i[out-tab-char[out-tab-width]]] [-l page-length]\n\
+       [-n[number-separator[digits]]] [-o left-margin]\n\
+       [-s[column-separator]] [-w page-width] [--help] [--version] [file...]\n",
+          program_name);
+  exit (2);
+}
diff --git a/gnu/usr.bin/pr/system.h b/gnu/usr.bin/pr/system.h
new file mode 100644 (file)
index 0000000..2e03ea8
--- /dev/null
@@ -0,0 +1,166 @@
+/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Include sys/types.h before this file.  */
+
+#include <sys/stat.h>
+#ifndef S_ISREG                        /* Doesn't have POSIX.1 stat stuff. */
+#define mode_t unsigned short
+#endif
+#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
+
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
+#include <memory.h>
+#endif
+#include <string.h>
+#ifndef index
+#define index strchr
+#endif
+#ifndef rindex
+#define rindex strrchr
+#endif
+/* Don't define bcopy; we need one that can handle overlaps.  */
+#ifndef bzero
+#define bzero(s, n) memset ((s), 0, (n))
+#endif
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
+#endif
+#else
+#include <strings.h>
+char *memchr ();
+#endif
+
+#include <errno.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *getenv ();
+extern int errno;
+#endif
+
+#if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
+#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>
+
+#ifndef isascii
+#define isascii(c) 1
+#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))
diff --git a/gnu/usr.bin/pr/version.c b/gnu/usr.bin/pr/version.c
new file mode 100644 (file)
index 0000000..a629418
--- /dev/null
@@ -0,0 +1,2 @@
+#include "version.h"
+const char *version_string = "GNU textutils 1.6";
diff --git a/gnu/usr.bin/pr/version.h b/gnu/usr.bin/pr/version.h
new file mode 100644 (file)
index 0000000..63de4fd
--- /dev/null
@@ -0,0 +1 @@
+extern const char *version_string;
diff --git a/gnu/usr.bin/pr/xmalloc.c b/gnu/usr.bin/pr/xmalloc.c
new file mode 100644 (file)
index 0000000..f989004
--- /dev/null
@@ -0,0 +1,65 @@
+/* xmalloc.c -- malloc with out of memory checking
+   Copyright (C) 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+char *realloc ();
+void free ();
+#endif
+
+void error ();
+
+/* Allocate N bytes of memory dynamically, with error checking.  */
+
+char *
+xmalloc (n)
+     unsigned n;
+{
+  char *p;
+
+  p = malloc (n);
+  if (p == 0)
+    /* Must exit with 2 for `cmp'.  */
+    error (2, 0, "virtual memory exhausted");
+  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 xmalloc (n);
+  if (n == 0)
+    {
+      free (p);
+      return 0;
+    }
+  p = realloc (p, n);
+  if (p == 0)
+    /* Must exit with 2 for `cmp'.  */
+    error (2, 0, "virtual memory exhausted");
+  return p;
+}