From 9a35093c1cb8b16df0e369abf59350c0369231b9 Mon Sep 17 00:00:00 2001 From: Nate Willams Date: Tue, 29 Jun 1993 04:58:06 +0000 Subject: [PATCH] From Textutils-1.6 --- gnu/usr.bin/pr/COPYING | 339 +++++++ gnu/usr.bin/pr/Makefile | 7 + gnu/usr.bin/pr/error.c | 106 +++ gnu/usr.bin/pr/getopt.c | 731 +++++++++++++++ gnu/usr.bin/pr/getopt.h | 129 +++ gnu/usr.bin/pr/getopt1.c | 176 ++++ gnu/usr.bin/pr/pr.1 | 103 +++ gnu/usr.bin/pr/pr.c | 1875 ++++++++++++++++++++++++++++++++++++++ gnu/usr.bin/pr/system.h | 166 ++++ gnu/usr.bin/pr/version.c | 2 + gnu/usr.bin/pr/version.h | 1 + gnu/usr.bin/pr/xmalloc.c | 65 ++ 12 files changed, 3700 insertions(+) create mode 100644 gnu/usr.bin/pr/COPYING create mode 100644 gnu/usr.bin/pr/Makefile create mode 100644 gnu/usr.bin/pr/error.c create mode 100644 gnu/usr.bin/pr/getopt.c create mode 100644 gnu/usr.bin/pr/getopt.h create mode 100644 gnu/usr.bin/pr/getopt1.c create mode 100644 gnu/usr.bin/pr/pr.1 create mode 100644 gnu/usr.bin/pr/pr.c create mode 100644 gnu/usr.bin/pr/system.h create mode 100644 gnu/usr.bin/pr/version.c create mode 100644 gnu/usr.bin/pr/version.h create mode 100644 gnu/usr.bin/pr/xmalloc.c diff --git a/gnu/usr.bin/pr/COPYING b/gnu/usr.bin/pr/COPYING new file mode 100644 index 0000000000..a43ea2126f --- /dev/null +++ b/gnu/usr.bin/pr/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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. + + , 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 index 0000000000..6c8d431ebc --- /dev/null +++ b/gnu/usr.bin/pr/Makefile @@ -0,0 +1,7 @@ + +PROG= pr +SRCS= pr.c getopt.c getopt1.c error.c xmalloc.c version.c + +CFLAGS+=-I${.CURDIR} + +.include diff --git a/gnu/usr.bin/pr/error.c b/gnu/usr.bin/pr/error.c new file mode 100644 index 0000000000..e849c5b2fb --- /dev/null +++ b/gnu/usr.bin/pr/error.c @@ -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 + +#ifdef HAVE_VPRINTF + +#if __STDC__ +#include +#define VA_START(args, lastarg) va_start(args, lastarg) +#else /* !__STDC__ */ +#include +#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 +#include +#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 index 0000000000..a59a013398 --- /dev/null +++ b/gnu/usr.bin/pr/getopt.c @@ -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. */ + +/* 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 +#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 . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#include + +/* 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 +#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; + +#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 +#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. */ + +/* 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; +} + +/* 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__. */ + +#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 index 0000000000..45541f5ac0 --- /dev/null +++ b/gnu/usr.bin/pr/getopt.h @@ -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 index 0000000000..a32615ce36 --- /dev/null +++ b/gnu/usr.bin/pr/getopt1.c @@ -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. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "getopt.h" + +#if !__STDC__ && !defined(const) && IN_GCC +#define const +#endif + +#include + +/* 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 +#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__. */ + +#ifdef TEST + +#include + +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 index 0000000000..10cdd8c133 --- /dev/null +++ b/gnu/usr.bin/pr/pr.1 @@ -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 index 0000000000..250f532b73 --- /dev/null +++ b/gnu/usr.bin/pr/pr.c @@ -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. */ + +/* 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. */ + + +#include +#include +#include +#include +#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 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 (); + } + } +} + +/* 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)); +} + +/* 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; +} + +/* 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; +} + +/* 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++; + } +} + +/* 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 ()) + ; +} + +/* 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); +} + +/* 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. */ +} + +/* 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; +} + +/* 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; + } + } +} + +/* 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); +} + +/* 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 index 0000000000..2e03ea8af1 --- /dev/null +++ b/gnu/usr.bin/pr/system.h @@ -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 +#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 +#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 +#endif +#include +#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 +char *memchr (); +#endif + +#include +#ifdef STDC_HEADERS +#include +#else +char *getenv (); +extern int errno; +#endif + +#if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION) +#include +#else +#include +#endif + +#if !defined(SEEK_SET) +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif + +#ifndef _POSIX_SOURCE +#include +#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 + +#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 index 0000000000..a6294189cc --- /dev/null +++ b/gnu/usr.bin/pr/version.c @@ -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 index 0000000000..63de4fd147 --- /dev/null +++ b/gnu/usr.bin/pr/version.h @@ -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 index 0000000000..f989004beb --- /dev/null +++ b/gnu/usr.bin/pr/xmalloc.c @@ -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 +#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; +} -- 2.20.1