diff options
| author | svn2git <svn2git@FreeBSD.org> | 1994-05-01 08:00:00 +0000 |
|---|---|---|
| committer | svn2git <svn2git@FreeBSD.org> | 1994-05-01 08:00:00 +0000 |
| commit | a16f65c7d117419bd266c28a1901ef129a337569 (patch) | |
| tree | 2626602f66dc3551e7a7c7bc9ad763c3bc7ab40a /gnu/usr.bin/dc | |
| parent | 8503f4f13f77abf7adc8f7e329c6f9c1d52b6a20 (diff) | |
Release FreeBSD 1.1upstream/1.1.0_cvsrelease/1.1.0_cvs
This commit was manufactured to restore the state of the 1.1-RELEASE image.
Releases prior to 5.3-RELEASE are omitting the secure/ and crypto/ subdirs.
Diffstat (limited to 'gnu/usr.bin/dc')
| -rw-r--r-- | gnu/usr.bin/dc/COPYING | 339 | ||||
| -rw-r--r-- | gnu/usr.bin/dc/ChangeLog | 77 | ||||
| -rw-r--r-- | gnu/usr.bin/dc/Makefile | 7 | ||||
| -rw-r--r-- | gnu/usr.bin/dc/NEWS | 7 | ||||
| -rw-r--r-- | gnu/usr.bin/dc/README | 13 | ||||
| -rw-r--r-- | gnu/usr.bin/dc/dc.1 | 278 | ||||
| -rw-r--r-- | gnu/usr.bin/dc/dc.c | 909 | ||||
| -rw-r--r-- | gnu/usr.bin/dc/dc.info | 330 | ||||
| -rw-r--r-- | gnu/usr.bin/dc/dc.texinfo | 381 | ||||
| -rw-r--r-- | gnu/usr.bin/dc/decimal.c | 1235 | ||||
| -rw-r--r-- | gnu/usr.bin/dc/decimal.h | 93 | ||||
| -rw-r--r-- | gnu/usr.bin/dc/texinfo.tex | 4003 |
12 files changed, 7672 insertions, 0 deletions
diff --git a/gnu/usr.bin/dc/COPYING b/gnu/usr.bin/dc/COPYING new file mode 100644 index 000000000000..e77696ae8ddf --- /dev/null +++ b/gnu/usr.bin/dc/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 + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/gnu/usr.bin/dc/ChangeLog b/gnu/usr.bin/dc/ChangeLog new file mode 100644 index 000000000000..09aaf4706884 --- /dev/null +++ b/gnu/usr.bin/dc/ChangeLog @@ -0,0 +1,77 @@ +Fri May 21 15:02:52 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * Version 0.2 released. + +Fri May 21 11:48:11 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * decimal.c (decimal_rem): Update to match fixes in decimal_div. + +Thu May 20 03:12:41 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * Makefile.in (realclean): Delete dc.info* and configure. + (DISTFILES): Add `texinfo.tex' and `NEWS'. + texinfo.tex: New file (symlink to canonical source). + NEWS: New file. + +Wed May 19 11:30:09 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * dc.c (dec_read): Accept only A through F. + +Tue May 18 12:35:54 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * dc.c (read_string): New arg STARTC to handle nested brackets. + (execute): Change calls to read_string. + (condop): Don't assume result of decimal_compare has abs value <= 1. + (popmacro): If no macro in progress, exit. + +Sun May 2 00:42:47 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * decimal.c (decimal_div): Include in trial_dividend the digit + at length2 + i - 2, if there is one. + +Sat May 1 09:54:35 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * decimal.c (decimal_parse): Don't use digits without recalculation + if some digit exceeds the radix. + + * dc.c (execute): Treat A...F as digits. + (dec_read): Treat A...F as digits. + +Thu Apr 29 14:17:30 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu) + + * decimal.h (bcopy): Use memcpy, not memmove. + + * decimal.c (flush_trailing_digits): Use explicit loop, not bcopy. + +Tue Apr 20 17:21:27 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * dc.c (pushsqrt): `precision' is an argument to `decimal_sqrt', not + `push'. + +Sat Apr 17 15:47:55 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * All files: Updated GPL version number. + + * decimal.c: Include decimal.h and delete duplicate declarations. + + * decimal.h [!HAVE_BCOPY]: #define bcopy. + [!HAVE_BZERO]: #define bzero. + +Sun Feb 10 22:06:15 1991 Richard Stallman (rms at mole.ai.mit.edu) + + * dc.c (execute): Insert break; in \n case. + +Sun Jul 29 17:50:14 1990 Richard Stallman (rms at sugar-bombs.ai.mit.edu) + + * decimal.c (decimal_neg): New function. + +Fri Jul 27 04:11:34 1990 David J. MacKenzie (djm at albert.ai.mit.edu) + + * bceval.c, bclex.c, bcprint.c, bcsym.c: Declare some functions + static. + +Mon Dec 25 03:01:49 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu) + + * Makefile: add some missing rules. + + * decimal.c: change a 'max' to 'MAX'. diff --git a/gnu/usr.bin/dc/Makefile b/gnu/usr.bin/dc/Makefile new file mode 100644 index 000000000000..937c7d9f2d65 --- /dev/null +++ b/gnu/usr.bin/dc/Makefile @@ -0,0 +1,7 @@ +PROG= dc +SRCS= dc.c decimal.c +CFLAGS+=-I${.CURDIR} -DHAVE_BCOPY=1 -DHAVE_BZERO=1 +DPADD= ${LIBM} +LDADD= -lm + +.include <bsd.prog.mk> diff --git a/gnu/usr.bin/dc/NEWS b/gnu/usr.bin/dc/NEWS new file mode 100644 index 000000000000..6486afb3ec86 --- /dev/null +++ b/gnu/usr.bin/dc/NEWS @@ -0,0 +1,7 @@ +Changes between version 0.2 and 0.1: + +* You can now have nested square bracket pairs within a string. + +* The letters A-F can now be part of a number when the input radix is +large enough to make them meaningful. + diff --git a/gnu/usr.bin/dc/README b/gnu/usr.bin/dc/README new file mode 100644 index 000000000000..c23cc6699202 --- /dev/null +++ b/gnu/usr.bin/dc/README @@ -0,0 +1,13 @@ +This is a preliminary release of GNU `dc', since people asked for it. GNU +`bc' (which doesn't rely on a separate `dc') has been available separately +for a couple of years. Eventually this version of `dc' will be merged with +the bc package. + +See comments in the file decimal.c for some limitations in the arbitrary +precision library. It's questionable whether it's worth fixing these +problems since the merged dc will probably use bc's math library instead. +However, you might want to be aware of known problems. + +See the file `INSTALL' for instructions on building and installing dc. + +Please report bugs to bug-gnu-utils@prep.ai.mit.edu. diff --git a/gnu/usr.bin/dc/dc.1 b/gnu/usr.bin/dc/dc.1 new file mode 100644 index 000000000000..17d9356a8fa0 --- /dev/null +++ b/gnu/usr.bin/dc/dc.1 @@ -0,0 +1,278 @@ +.TH DC 1 "03 Aug 1993" "GNU Project" +.SH NAME +dc, An Arbitrary Precision Calculator +.SH SYNOPSIS +.B dc +.SH DESCRIPTION +.PP +DC is a reverse-polish desk calculator which supports unlimited +precision arithmetic. It also allows you to define and call macros. +Normally DC reads from the standard input; if any command arguments +are given to it, they are filenames, and DC reads and executes the +contents of the files before reading from standard input. All output +is to standard output. + +A reverse-polish calculator stores numbers on a stack. Entering a +number pushes it on the stack. Arithmetic operations pop arguments off +the stack and push the results. + +To enter a number in DC, type the digits, with an optional decimal +point. Exponential notation is not supported. To enter a negative +number, begin the number with `_'. `-' cannot be used for this, as it +is a binary operator for subtraction instead. To enter two numbers in +succession, separate them with spaces or newlines. These have no +meaning as commands. +.PD +.SH "Printing Commands" +.PP +.B p +Prints the value on the top of the stack, +without altering the stack. A newline is printed +after the value. +.PP +.B P +Prints the value on the top of the stack, +popping it off, and does not print a newline after. +.PP +.B f +Prints the entire contents of the stack +and the contents of all of the registers, +without altering anything. This is a good command +to use if you are lost or want to figure out +what the effect of some command has been. +.PD +.SH "Arithmetic" +.PP +.B + +Pops two values off the stack, adds them, +and pushes the result. The precision of the result +is determined only by the values of the arguments, +and is enough to be exact. +.PP +.B - +Pops two values, subtracts the first one popped +from the second one popped, and pushes the result. +.PP +.B * +Pops two values, multiplies them, and pushes the result. +The number of fraction digits in the result is controlled +by the current precision flag (see below) and does not +depend on the values being multiplied. +.PP +.B / +Pops two values, divides the second one popped from +the first one popped, and pushes the result. +The number of fraction digits is specified by the precision flag. +.PP +.B % +Pops two values, computes the remainder of the division +that the \fB/\fR command would do, and pushes that. +The division is done with as many fraction digits +as the precision flag specifies, and the remainder +is also computed with that many fraction digits. +.PP +.B ^ +Pops two values and exponentiates, using the first +value popped as the exponent and the second popped as the base. +The fraction part of the exponent is ignored. +The precision flag specifies the number of fraction +digits in the result. +.PP +.B v +Pops one value, computes its square root, and pushes that. +The precision flag specifies the number of fraction digits +in the result. +.PP +Most arithmetic operations are affected by the "precision flag", +which you can set with the +.BR k +command. The default precision +value is zero, which means that all arithmetic except for +addition and subtraction produces integer results. +.PP +The remainder operation +.BR % +requires some explanation: applied to +arguments `a' and `b' it produces `a - (b * (a / b))', +where `a / b' is computed in the current precision. +.PP +.SH "Stack Control" +.PP +.B c +Clears the stack, rendering it empty. +.PP +.B d +Duplicates the value on the top of the stack, +pushing another copy of it. Thus, +`4d*p' computes 4 squared and prints it. +.SH "Registers" +.PP +DC provides 128 memory registers, each named by a single +ASCII character. You can store a number in a register +and retrieve it later. +.PP +.B s\fIr\fR +Pop the value off the top of the stack and store +it into register \fIr\fR. +.PP +.B l\fIr\fR +Copy the value in register \fIr\fR and push it onto the stack. This +does not alter the contents of \fIr\fR. +.PP +Each register also contains its own stack. The current +register value is the top of the register's stack. +.PP +.B S\fIr\fR +Pop the value off the top of the (main) stack and +push it onto the stack of register \fIr\fR. +The previous value of the register becomes inaccessible. +.PP +.B L\fIr\fR +Pop the value off the top of register \fIr\fR's stack +and push it onto the main stack. The previous value +in register \fIr\fR's stack, if any, is now accessible +via the +.BR Ir +command. +.PP +The +.BR f +command prints a list of all registers that have contents +stored in them, together with their contents. Only the +current contents of each register (the top of its stack) +is printed. +.PP +.SH "Parameters" +.PP +DC has three parameters that control its operation: the precision, the +input radix, and the output radix. The precision specifies the number +of fraction digits to keep in the result of most arithmetic operations. +The input radix controls the interpretation of numbers typed in; +allnumbers typed in use this radix. The output radix is used +for printing numbers. +.PP +The input and output radices are separate parameters; you can make them +unequal, which can be useful or confusing. Each radix must be between 2 +and 36 inclusive. The precision must be zero or greater. The precision +is always measured in decimal digits, regardless of the current input or +output radix. +.PP +.B i +Pops the value off the top of the stack +and uses it to set the input radix. +.PP +.B o +.PP +.B k +Similarly set the output radix and the precision. +.PP +.B I +Pushes the current input radix on the stack. +.PP +.B O +.PP +.B K +Similarly push the current output radix and the current precision. +.PP +.SH "Strings" +.PP +DC can operate on strings as well as on numbers. The only things you +can do with strings are print them and execute them as macros (which +means that the contents of the string are processed as DC commands). +Both registers and the stack can hold strings, and DC always knows +whether any given object is a string or a number. Some commands such as +arithmetic operations demand numbers as arguments and print errors if +given strings. Other commands can accept either a number or a string; +for example, the +.BR p +command can accept either and prints the object +according to its type. +.PP +.B [characters] +Makes a string containing +.BR characters +and pushes it +on the stack. For example, +.BR [foo]p +prints the +characters \fBfoo\fR (with no newline). +.PP +.B x +Pops a value off the stack and executes it as a macro. +Normally it should be a string; if it is a number, +it is simply pushed back onto the stack. +For example, +.BR [1p]x +executes the macro +.BR 1p +which pushes \fB1\fR on the stack and prints \fB1\fR +on a separate line. +.PP +Macros are most often stored in registers; +\fB[1p]sa\fR stores a macro to print \fB1\fR into register \fBa\fR, +and \fBlax\fR invokes the macro. +.PP +.B >\fIr\fR +Pops two values off the stack and compares them +assuming they are numbers, executing the contents +of register \fIr\fR as a macro if the original top-of-stack +is greater. Thus, \fB1 2>a\fR will invoke register \fBa\fR's contents +and \fB2 1>a\fR will not. +.PP +.B <\fIr\fB +Similar but invokes the macro if the original top-of-stack +is less. +.PP +.B =\fIr\fR +Similar but invokes the macro if the two numbers popped +are equal. This can also be validly used to compare two +strings for equality. +.PP +.B ? +Reads a line from the terminal and executes it. +This command allows a macro to request input from the user. +.PP +.B q +During the execution of a macro, this comand +does not exit DC. Instead, it exits from that +macro and also from the macro which invoked it (if any). +.PP +.B Q +Pops a value off the stack and uses it as a count +of levels of macro execution to be exited. Thus, +\fB3Q\fR exits three levels. +.SH "Status Inquiry" +.PP +.B Z +Pops a value off the stack, calculates the number of +digits it has (or number of characters, if it is a string) +and pushes that number. +.PP +.B X +Pops a value off the stack, calculates the number of +fraction digits it has, and pushes that number. +For a string, the value pushed is -1. +.PP +.B z +Pushes the current stack depth; the number of +objects on the stack before the execution of the \fBz\fR command. +.PP +.B I +Pushes the current value of the input radix. +.PP +.B O +Pushes the current value of the output radix. +.PP +.B K +Pushes the current value of the precision. +.SH "Notes" +.PP +The \fB:\fR and \fB;\fR commands of the Unix DC program are +not supported, as the documentation does not say what they do. +The \fB!\fR command is not supported, but will be supported +as soon as a library for executing a line as a command exists. +.SH BUGS +.PP +Email bug reports to +.BR bug-gnu-utils@prep.ai.mit.edu . +Be sure to include the word ``dc'' somewhere in the ``Subject:'' field. diff --git a/gnu/usr.bin/dc/dc.c b/gnu/usr.bin/dc/dc.c new file mode 100644 index 000000000000..933b24b916cd --- /dev/null +++ b/gnu/usr.bin/dc/dc.c @@ -0,0 +1,909 @@ +/* + * `dc' desk calculator utility. + * + * Copyright (C) 1984, 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, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +#include <stdio.h> +#include "decimal.h" /* definitions for our decimal arithmetic package */ + +FILE *open_file; /* input file now open */ +int file_count; /* Number of input files not yet opened */ +char **next_file; /* Pointer to vector of names of input files left */ + +struct regstack + { + decimal value; /* Saved value of register */ + struct regstack *rest; /* Tail of list */ + }; + +typedef struct regstack *regstack; + +regstack freeregstacks; /* Chain of free regstack structures for fast realloc */ + +decimal regs[128]; /* "registers", with single-character names */ +regstack regstacks[128]; /* For each register, a stack of previous values */ + +int stacktop; /* index of last used element in stack */ +int stacksize; /* Current allocates size of stack */ +decimal *stack; /* Pointer to computation stack */ + +/* A decimal number can be regarded as a string by + treating its contents as characters and ignoring the + position of its decimal point. + Decimal numbers are marked as strings by having an `after' field of -1 + One use of strings is to execute them as macros. +*/ + +#define STRING -1 + +int macrolevel; /* Current macro nesting; 0 if taking keyboard input */ +int macrostacksize; /* Current allocated size of macrostack and macroindex */ +decimal *macrostack; /* Pointer to macro stack array */ +int *macroindex; /* Pointer to index-within-macro stack array */ + /* Note that an empty macro is popped from the stack + only when an trying to read a character from it + or trying to push another macro. */ + +int ibase; /* Radix for numeric input. */ +int obase; /* Radix for numeric output. */ +int precision; /* Number of digits to keep in multiply and divide. */ + +char *buffer; /* Address of buffer used for reading numbers */ +int bufsize; /* Current size of buffer (made bigger when nec) */ + +decimal dec_read (); +regstack get_regstack (); +int fetch (); +int fgetchar (); +char *concat (); +void pushsqrt (); +void condop (); +void setibase (); +void setobase (); +void setprecision (); +void pushmacro (); +decimal read_string (); +void pushlength (); +void pushscale (); +void unfetch (); +void popmacros (); +void popmacro (); +void popstack (); +void print_obj (); +void print_string (); +void free_regstack (); +void pushreg (); +void execute (); +void fputchar (); +void push (); +void incref (); +void decref (); +void binop (); + +main (argc, argv, env) + int argc; + char **argv, **env; +{ + + ibase = 10; + obase = 10; + precision = 0; + + freeregstacks = 0; + + bzero (regs, sizeof regs); + bzero (regstacks, sizeof regstacks); + + bufsize = 40; + buffer = (char *) xmalloc (40); + + stacksize = 40; + stack = (decimal *) xmalloc (stacksize * sizeof (decimal)); + stacktop = -1; + + macrostacksize = 40; + macrostack = (decimal *) xmalloc (macrostacksize * sizeof (decimal)); + macroindex = (int *) xmalloc (macrostacksize * sizeof (int)); + macrolevel = 0; + /* Initialize for reading input files if any */ + + open_file = 0; + + file_count = argc - 1; + next_file = argv + 1; + + + while (1) + { + execute (); + } +} + +/* Read and execute one command from the current source of input */ + +void +execute () +{ + int c = fetch (); + + if (c < 0) exit (0); + + { + switch (c) + { + case '+': /* Arithmetic operators... */ + binop (decimal_add); + break; + + case '-': + binop (decimal_sub); + break; + + case '*': + binop (decimal_mul_dc); /* Like decimal_mul but hairy + way of deciding precision to keep */ + break; + + case '/': + binop (decimal_div); + break; + + case '%': + binop (decimal_rem); + break; + + case '^': + binop (decimal_expt); + break; + + case '_': /* Begin a negative decimal constant */ + { + decimal tem = dec_read (stdin); + tem->sign = !tem->sign; + push (tem); + } + break; + + case '.': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': /* All these begin decimal constants */ + unfetch (c); + push (dec_read (stdin)); + break; + + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + unfetch (c); + push (dec_read (stdin)); + break; + + case 'c': /* Clear the stack */ + while (stacktop >= 0) + decref (stack[stacktop--]); + break; + + case 'd': /* Duplicate top of stack */ + if (stacktop < 0) + error ("stack empty", 0); + else push (stack[stacktop]); + break; + + case 'f': /* Describe all registers and stack contents */ + { + int regno; + int somereg = 0; /* set to 1 if we print any registers */ + for (regno = 0; regno < 128; regno++) + { + if (regs[regno]) + { + printf ("register %c: ", regno); + print_obj (regs[regno]); + somereg = 1; + printf ("\n"); + } + } + if (somereg) + printf ("\n"); + if (stacktop < 0) + printf ("stack empty\n"); + else + { + int i; + printf ("stack:\n"); + for (i = 0; i <= stacktop; i++) + { + print_obj (stack[stacktop - i]); + printf ("\n"); + } + } + } + break; + + case 'i': /* ibase <- top of stack */ + popstack (setibase); + break; + + case 'I': /* Push current ibase */ + push (decimal_from_int (ibase)); + break; + + case 'k': /* like i, I but for precision instead of ibase */ + popstack (setprecision); + break; + + case 'K': + push (decimal_from_int (precision)); + break; + + case 'l': /* l<x> load register <x> onto stack */ + { + char c1 = fetch (); + if (c1 < 0) exit (0); + if (!regs[c1]) + error ("register %c empty", c1); + else + push (regs[c1]); + } + break; + + case 'L': /* L<x> load register <x> to stack, pop <x>'s own stack */ + { + char c1 = fetch (); + if (c1 < 0) exit (0); + if (!regstacks[c1]) + error ("nothing pushed on register %c", c1); + else + { + regstack r = regstacks[c1]; + if (!regs[c1]) + error ("register %c empty after pop", c1); + else + push (regs[c1]); + regs[c1] = r->value; + regstacks[c1] = r->rest; + free_regstack (r); + } + } + break; + + case 'o': /* o, O like i, I but for obase instead of ibase */ + popstack (setobase); + break; + + case 'O': + push (decimal_from_int (obase)); + break; + + case 'p': /* Print tos, don't pop, do print newline afterward */ + if (stacktop < 0) + error ("stack empty", 0); + else + { + print_obj (stack[stacktop]); + printf ("\n"); + } + break; + + case 'P': /* Print tos, do pop, no newline afterward */ + popstack (print_obj); + break; + + case 'q': /* Exit */ + if (macrolevel) + { popmacro (); popmacro (); } /* decrease recursion level by 2 */ + else + exit (0); /* If not in a macro, exit the program. */ + + break; + + case 'Q': /* Tos says how many levels to exit */ + popstack (popmacros); + break; + + case 's': /* s<x> -- Pop stack and set register <x> */ + if (stacktop < 0) + empty (); + else + { + int c1 = fetch (); + if (c1 < 0) exit (0); + if (regs[c1]) decref (regs[c1]); + regs[c1] = stack[stacktop--]; + } + break; + + case 'S': /* S<x> -- pop stack and push as new value of register <x> */ + if (stacktop < 0) + empty (); + else + { + int c1 = fetch (); + if (c1 < 0) exit (0); + pushreg (c1); + regs[c1] = stack[stacktop--]; + } + break; + + case 'v': /* tos gets square root of tos */ + popstack (pushsqrt); + break; + + case 'x': /* pop stack , call as macro */ + popstack (pushmacro); + break; + + case 'X': /* Pop stack, get # fraction digits, push that */ + popstack (pushscale); + break; + + case 'z': /* Compute depth of stack, push that */ + push (decimal_from_int (stacktop + 1)); + break; + + case 'Z': /* Pop stack, get # digits, push that */ + popstack (pushlength); + break; + + case '<': /* Conditional: pop two numbers, compare, maybe execute register */ + /* Note: for no obvious reason, the standard Unix `dc' + considers < to be true if the top of stack is less + than the next-to-top of stack, + and vice versa for >. + This seems backwards to me, but I am preserving compatibility. */ + condop (1); + break; + + case '>': + condop (-1); + break; + + case '=': + condop (0); + break; + + case '?': /* Read expression from terminal and execute it */ + /* First ignore any leading newlines */ + { + int c1; + while ((c1 = getchar ()) == '\n'); + ungetc (c1, stdin); + } + /* Read a line from the terminal and execute it. */ + pushmacro (read_string ('\n', fgetchar, 0)); + break; + + case '[': /* Begin string constant */ + push (read_string (']', fetch, '[')); + break; + + case ' ': + case '\n': + break; + + default: + error ("undefined command %c", c); + } + } +} + +/* Functionals for performing arithmetic, etc */ + +/* Call the function `op', with the top of stack value as argument, + and then pop the stack. + If the stack is empty, print a message and do not call `op'. */ + +void +popstack (op) + void (*op) (); +{ + if (stacktop < 0) + empty (); + else + { + decimal value = stack[stacktop--]; + op (value); + decref (value); + } +} + +/* Call the function `op' with two arguments taken from the stack top, + then pop those arguments and push the value returned by `op'. + `op' is assumed to return a decimal number. + If there are not two values on the stack, print a message + and do not call `op'. */ + +void +binop (op) + decimal (*op) (); +{ + if (stacktop < 1) + error ("stack empty", 0); + else if (stack[stacktop]->after == STRING || stack[stacktop - 1]->after == STRING) + error ("operands not both numeric"); + else + { + decimal arg2 = stack [stacktop--]; + decimal arg1 = stack [stacktop--]; + + push (op (arg1, arg2, precision)); + + decref (arg1); + decref (arg2); + } +} + +void +condop (cond) + int cond; +{ + int regno = fetch (); + if (!regs[regno]) + error ("register %c is empty", regno); + else if (stacktop < 1) + empty (); + else + { + decimal arg2 = stack[stacktop--]; + decimal arg1 = stack[stacktop--]; + int relation = decimal_compare (arg1, arg2); + decref (arg1); + decref (arg2); + if (cond == relation + || (cond < 0 && relation < 0) + || (cond > 0 && relation > 0)) + pushmacro (regs[regno]); + } +} + +/* Handle the command input source */ + +/* Fetch the next command character from a macro or from the terminal */ + +int +fetch() +{ + int c = -1; + + while (macrolevel && + LENGTH (macrostack[macrolevel-1]) == macroindex[macrolevel-1]) + popmacro(); + if (macrolevel) + return macrostack[macrolevel - 1]->contents[macroindex[macrolevel-1]++]; + while (1) + { + if (open_file) + { + c = getc (open_file); + if (c >= 0) break; + fclose (open_file); + open_file = 0; + } + else if (file_count) + { + open_file = fopen (*next_file++, "r"); + file_count--; + if (!open_file) + perror_with_name (*(next_file - 1)); + } + else break; + } + if (c >= 0) return c; + return getc (stdin); +} + +/* Unread character c on command input stream, whatever it is */ + +void +unfetch (c) + char c; +{ + if (macrolevel) + macroindex[macrolevel-1]--; + else if (open_file) + ungetc (c, open_file); + else + ungetc (c, stdin); +} + +/* Begin execution of macro m. */ + +void +pushmacro (m) + decimal m; +{ + while (macrolevel && + LENGTH (macrostack[macrolevel-1]) == macroindex[macrolevel-1]) + popmacro(); + if (m->after == STRING) + { + if (macrolevel == macrostacksize) + { + macrostacksize *= 2; + macrostack = (decimal *) xrealloc (macrostack, macrostacksize * sizeof (decimal)); + macroindex = (int *) xrealloc (macroindex, macrostacksize * sizeof (int)); + } + macroindex[macrolevel] = 0; + macrostack[macrolevel++] = m; + incref (m); + } + else + { /* Number supplied as a macro! */ + push (m); /* Its effect wouyld be to push the number. */ + } +} + +/* Pop a specified number of levels of macro execution. + The number of levels is specified by a decimal number d. */ + +void +popmacros (d) + decimal d; +{ + int num_pops = decimal_to_int (d); + int i; + for (i = 0; i < num_pops; i++) + popmacro (); +} +/* Exit one level of macro execution. */ + +void +popmacro () +{ + if (!macrolevel) + exit (0); + else + { + decref (macrostack[--macrolevel]); + } +} + +void +push (d) + decimal d; +{ + if (stacktop == stacksize - 1) + stack = (decimal *) xrealloc (stack, (stacksize *= 2) * sizeof (decimal)); + + incref (d); + + stack[++stacktop] = d; +} + +/* Reference counting and storage freeing */ + +void +decref (d) + decimal d; +{ + if (!--d->refcnt) + free (d); +} + +void +incref (d) + decimal d; +{ + d->refcnt++; +} + +empty () +{ + error ("stack empty", 0); +} + +regstack +get_regstack () +{ + if (freeregstacks) + { + regstack r = freeregstacks; + freeregstacks = r ->rest; + return r; + } + else + return (regstack) xmalloc (sizeof (struct regstack)); +} + +void +free_regstack (r) + regstack r; +{ + r->rest = freeregstacks; + freeregstacks = r; +} + +void +pushreg (c) + char c; +{ + regstack r = get_regstack (); + + r->rest = regstacks[c]; + r->value = regs[c]; + regstacks[c] = r; + regs[c] = 0; +} + +/* Input of numbers and strings */ + +/* Return a character read from the terminal. */ + +fgetchar () +{ + return getchar (); +} + +void +fputchar (c) + char (c); +{ + putchar (c); +} + +/* Read text from command input source up to a close-bracket, + make a string out of it, and return it. + If STARTC is nonzero, then it and STOPC must balance when nested. */ + +decimal +read_string (stopc, inputfn, startc) + char stopc; + int (*inputfn) (); + int startc; +{ + int c; + decimal result; + int i = 0; + int count = 0; + + while (1) + { + c = inputfn (); + if (c < 0 || (c == stopc && count == 0)) + { + if (count != 0) + error ("Unmatched `%c'", startc); + break; + } + if (c == stopc) + count--; + if (c == startc) + count++; + if (i + 1 >= bufsize) + buffer = (char *) xrealloc (buffer, bufsize *= 2); + buffer[i++] = c; + } + result = make_decimal (i, 0); + result->after = -1; /* Mark it as a string */ + result->before++; /* but keep the length unchanged */ + bcopy (buffer, result->contents, i); + return result; +} + +/* Read a number from the current input source */ + +decimal +dec_read () +{ + int c; + int i = 0; + + while (1) + { + c = fetch (); + if (! ((c >= '0' && c <= '9') + || (c >= 'A' && c <= 'F') + || c == '.')) + break; + if (i + 1 >= bufsize) + buffer = (char *) xrealloc (buffer, bufsize *= 2); + buffer[i++] = c; + } + buffer[i++] = 0; + unfetch (c); + + return decimal_parse (buffer, ibase); +} + +/* Output of numbers and strings */ + +/* Print the contents of obj, either numerically or as a string, + according to what obj says it is. */ + +void +print_obj (obj) + decimal obj; +{ + if (obj->after == STRING) + print_string (obj); + else + decimal_print (obj, fputchar, obase); +} + +/* Print the contents of the decimal number `string', treated as a string. */ + +void +print_string (string) + decimal string; +{ + char *p = string->contents; + int len = LENGTH (string); + int i; + + for (i = 0; i < len; i++) + { + putchar (*p++); + } +} + +/* Set the input radix from the value of the decimal number d, if valid. */ + +void +setibase (d) + decimal d; +{ + int value = decimal_to_int (d); + if (value < 2 || value > 36) + error ("input radix must be from 2 to 36", 0); + else + ibase = value; +} + +/* Set the output radix from the value of the decimal number d, if valid. */ + +void +setobase (d) + decimal d; +{ + int value = decimal_to_int (d); + if (value < 2 || value > 36) + error ("output radix must be from 2 to 36", 0); + else + obase = value; +} + +/* Set the precision for mul and div from the value of the decimal number d, if valid. */ + +void +setprecision (d) + decimal d; +{ + int value = decimal_to_int (d); + if (value < 0 || value > 30000) + error ("precision must be nonnegative and < 30000", 0); + else + precision = value; +} + +/* Push the number of digits in decimal number d, as a decimal number. */ + +void +pushlength (d) + decimal d; +{ + push (decimal_from_int (LENGTH (d))); +} + +/* Push the number of fraction digits in d. */ + +void +pushscale (d) + decimal d; +{ + push (decimal_from_int (d->after)); +} + +/* Push the square root of decimal number d. */ + +void +pushsqrt (d) + decimal d; +{ + push (decimal_sqrt (d, precision)); +} + +/* Print error message and exit. */ + +fatal (s1, s2) + char *s1, *s2; +{ + error (s1, s2); + exit (1); +} + +/* Print error message. `s1' is printf control string, `s2' is arg for it. */ + +error (s1, s2) + char *s1, *s2; +{ + printf ("dc: "); + printf (s1, s2); + printf ("\n"); +} + +decimal_error (s1, s2) + char *s1, *s2; +{ + error (s1, s2); +} + +perror_with_name (name) + char *name; +{ + extern int errno, sys_nerr; + extern char *sys_errlist[]; + char *s; + + if (errno < sys_nerr) + s = concat ("", sys_errlist[errno], " for %s"); + else + s = "cannot open %s"; + error (s, name); +} + +/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ + +char * +concat (s1, s2, s3) + char *s1, *s2, *s3; +{ + int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); + char *result = (char *) xmalloc (len1 + len2 + len3 + 1); + + strcpy (result, s1); + strcpy (result + len1, s2); + strcpy (result + len1 + len2, s3); + *(result + len1 + len2 + len3) = 0; + + return result; +} + +/* Like malloc but get fatal error if memory is exhausted. */ + +int +xmalloc (size) + int size; +{ + int result = malloc (size); + if (!result) + fatal ("virtual memory exhausted", 0); + return result; +} + +int +xrealloc (ptr, size) + char *ptr; + int size; +{ + int result = realloc (ptr, size); + if (!result) + fatal ("virtual memory exhausted"); + return result; +} diff --git a/gnu/usr.bin/dc/dc.info b/gnu/usr.bin/dc/dc.info new file mode 100644 index 000000000000..a30fea9f5555 --- /dev/null +++ b/gnu/usr.bin/dc/dc.info @@ -0,0 +1,330 @@ +This is Info file dc.info, produced by Makeinfo-1.52 from the input +file dc.texinfo. + + This file documents DC, an arbitrary precision calculator. + + Published by the Free Software Foundation, 675 Massachusetts Avenue, +Cambridge, MA 02139 USA + + Copyright (C) 1984 Free Software Foundation, Inc. + + Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be stated in a +translation approved by the Foundation. + + +File: dc.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) + +* Menu: + +* Introduction:: Introduction +* Printing Commands:: Printing Commands +* Arithmetic:: Arithmetic +* Stack Control:: Stack Control +* Registers:: Registers +* Parameters:: Parameters +* Strings:: Strings +* Status Inquiry:: Status Inquiry +* Notes:: Notes + + +File: dc.info, Node: Introduction, Next: Printing Commands, Prev: Top, Up: Top + +Introduction +************ + + DC is a reverse-polish desk calculator which supports unlimited +precision arithmetic. It also allows you to define and call macros. +Normally DC reads from the standard input; if any command arguments are +given to it, they are filenames, and DC reads and executes the contents +of the files before reading from standard input. All output is to +standard output. + + To exit, use `q'. `C-c' does not exit; it is used to abort macros +that are looping, etc. (Currently this is not true; `C-c' does exit.) + + A reverse-polish calculator stores numbers on a stack. Entering a +number pushes it on the stack. Arithmetic operations pop arguments off +the stack and push the results. + + To enter a number in DC, type the digits, with an optional decimal +point. Exponential notation is not supported. To enter a negative +number, begin the number with `_'. `-' cannot be used for this, as it +is a binary operator for subtraction instead. To enter two numbers in +succession, separate them with spaces or newlines. These have no +meaning as commands. + + +File: dc.info, Node: Printing Commands, Next: Arithmetic, Prev: Introduction, Up: Top + +Printing Commands +***************** + +`p' + Prints the value on the top of the stack, without altering the + stack. A newline is printed after the value. + +`P' + Prints the value on the top of the stack, popping it off, and does + not print a newline after. + +`f' + Prints the entire contents of the stack and the contents of all of + the registers, without altering anything. This is a good command + to use if you are lost or want to figure out what the effect of + some command has been. + + +File: dc.info, Node: Arithmetic, Next: Stack Control, Prev: Printing Commands, Up: Top + +Arithmetic +********** + +`+' + Pops two values off the stack, adds them, and pushes the result. + The precision of the result is determined only by the values of + the arguments, and is enough to be exact. + +`-' + Pops two values, subtracts the first one popped from the second + one popped, and pushes the result. + +`*' + Pops two values, multiplies them, and pushes the result. The + number of fraction digits in the result is controlled by the + current precision flag (see below) and does not depend on the + values being multiplied. + +`/' + Pops two values, divides the second one popped from the first one + popped, and pushes the result. The number of fraction digits is + specified by the precision flag. + +`%' + Pops two values, computes the remainder of the division that the + `/' command would do, and pushes that. The division is done with + as many fraction digits as the precision flag specifies, and the + remainder is also computed with that many fraction digits. + +`^' + Pops two values and exponentiates, using the first value popped as + the exponent and the second popped as the base. The fraction part + of the exponent is ignored. The precision flag specifies the + number of fraction digits in the result. + +`v' + Pops one value, computes its square root, and pushes that. The + precision flag specifies the number of fraction digits in the + result. + + Most arithmetic operations are affected by the "precision flag", +which you can set with the `k' command. The default precision value is +zero, which means that all arithmetic except for addition and +subtraction produces integer results. + + The remainder operation (`%') requires some explanation: applied to +arguments `a' and `b' it produces `a - (b * (a / b))', where `a / b' is +computed in the current precision. + + +File: dc.info, Node: Stack Control, Next: Registers, Prev: Arithmetic, Up: Top + +Stack Control +************* + +`c' + Clears the stack, rendering it empty. + +`d' + Duplicates the value on the top of the stack, pushing another copy + of it. Thus, `4d*p' computes 4 squared and prints it. + + +File: dc.info, Node: Registers, Next: Parameters, Prev: Stack Control, Up: Top + +Registers +********* + + DC provides 128 memory registers, each named by a single ASCII +character. You can store a number in a register and retrieve it later. + +`sR' + Pop the value off the top of the stack and store it into register + R. + +`lR' + Copy the value in register R, and push it onto the stack. This + does not alter the contents of R. + + Each register also contains its own stack. The current register + value is the top of the register's stack. + +`SR' + Pop the value off the top of the (main) stack and push it onto the + stack of register R. The previous value of the register becomes + inaccessible. + +`LR' + Pop the value off the top of register R's stack and push it onto + the main stack. The previous value in register R's stack, if any, + is now accessible via the `lR' command. + + The `f' command prints a list of all registers that have contents +stored in them, together with their contents. Only the current +contents of each register (the top of its stack) is printed. + + +File: dc.info, Node: Parameters, Next: Strings, Prev: Registers, Up: Top + +Parameters +********** + + DC has three parameters that control its operation: the precision, +the input radix, and the output radix. The precision specifies the +number of fraction digits to keep in the result of most arithmetic +operations. The input radix controls the interpretation of numbers +typed in; *all* numbers typed in use this radix. The output radix is +used for printing numbers. + + The input and output radices are separate parameters; you can make +them unequal, which can be useful or confusing. Each radix must be +between 2 and 36 inclusive. The precision must be zero or greater. +The precision is always measured in decimal digits, regardless of the +current input or output radix. + +`i' + Pops the value off the top of the stack and uses it to set the + input radix. + +`o' +`k' + Similarly set the output radix and the precision. + +`I' + Pushes the current input radix on the stack. + +`O' +`K' + Similarly push the current output radix and the current precision. + + +File: dc.info, Node: Strings, Next: Status Inquiry, Prev: Parameters, Up: Top + +Strings +******* + + DC can operate on strings as well as on numbers. The only things you +can do with strings are print them and execute them as macros (which +means that the contents of the string are processed as DC commands). +Both registers and the stack can hold strings, and DC always knows +whether any given object is a string or a number. Some commands such as +arithmetic operations demand numbers as arguments and print errors if +given strings. Other commands can accept either a number or a string; +for example, the `p' command can accept either and prints the object +according to its type. + +`[CHARACTERS]' + Makes a string containing CHARACTERS and pushes it on the stack. + For example, `[foo]P' prints the characters `foo' (with no + newline). + +`x' + Pops a value off the stack and executes it as a macro. Normally + it should be a string; if it is a number, it is simply pushed back + onto the stack. For example, `[1p]x' executes the macro `1p', + which pushes 1 on the stack and prints `1' on a separate line. + + Macros are most often stored in registers; `[1p]sa' stores a macro + to print `1' into register `a', and `lax' invokes the macro. + +`>R' + Pops two values off the stack and compares them assuming they are + numbers, executing the contents of register R as a macro if the + original top-of-stack is greater. Thus, `1 2>a' will invoke + register `a''s contents and `2 1>a' will not. + +`<R' + Similar but invokes the macro if the original top-of-stack is less. + +`=R' + Similar but invokes the macro if the two numbers popped are equal. + This can also be validly used to compare two strings for equality. + +`?' + Reads a line from the terminal and executes it. This command + allows a macro to request input from the user. + +`q' + During the execution of a macro, this comand does not exit DC. + Instead, it exits from that macro and also from the macro which + invoked it (if any). + +`Q' + Pops a value off the stack and uses it as a count of levels of + macro execution to be exited. Thus, `3Q' exits three levels. + + +File: dc.info, Node: Status Inquiry, Next: Notes, Prev: Strings, Up: Top + +Status Inquiry +************** + +`Z' + Pops a value off the stack, calculates the number of digits it has + (or number of characters, if it is a string) and pushes that + number. + +`X' + Pops a value off the stack, calculates the number of fraction + digits it has, and pushes that number. For a string, the value + pushed is -1. + +`z' + Pushes the current stack depth; the number of objects on the stack + before the execution of the `z' command. + +`I' + Pushes the current value of the input radix. + +`O' + Pushes the current value of the output radix. + +`K' + Pushes the current value of the precision. + + +File: dc.info, Node: Notes, Prev: Status Inquiry, Up: Top + +Notes +***** + + The `:' and `;' commands of the Unix DC program are not supported, +as the documentation does not say what they do. The `!' command is not +supported, but will be supported as soon as a library for executing a +line as a command exists. + + + +Tag Table: +Node: Top960 +Node: Introduction1440 +Node: Printing Commands2603 +Node: Arithmetic3211 +Node: Stack Control5168 +Node: Registers5468 +Node: Parameters6586 +Node: Strings7659 +Node: Status Inquiry9857 +Node: Notes10571 + +End Tag Table diff --git a/gnu/usr.bin/dc/dc.texinfo b/gnu/usr.bin/dc/dc.texinfo new file mode 100644 index 000000000000..15b285fbd579 --- /dev/null +++ b/gnu/usr.bin/dc/dc.texinfo @@ -0,0 +1,381 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename dc.info +@settitle DC, An Arbitrary Precision Calculator +@c %**end of header + +@c This file has the new style title page commands. +@c Run `makeinfo' rather than `texinfo-format-buffer'. + +@c smallbook + +@c tex +@c \overfullrule=0pt +@c end tex + +@c Combine indices. +@synindex cp fn +@syncodeindex vr fn +@syncodeindex ky fn +@syncodeindex pg fn +@syncodeindex tp fn + +@ifinfo +This file documents DC, an arbitrary precision calculator. + +Published by the Free Software Foundation, +675 Massachusetts Avenue, +Cambridge, MA 02139 USA + +Copyright (C) 1984 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + +@setchapternewpage odd + +@titlepage +@title DC, An Arbitrary Precision Calculator + +@author by Richard Stallman +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1984 Free Software Foundation, Inc. + +@sp 2 +Published by the Free Software Foundation, @* +675 Massachusetts Avenue, @* +Cambridge, MA 02139 USA + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. + +@end titlepage +@page + +@node Top, Introduction, (dir), (dir) + +@menu +* Introduction:: Introduction +* Printing Commands:: Printing Commands +* Arithmetic:: Arithmetic +* Stack Control:: Stack Control +* Registers:: Registers +* Parameters:: Parameters +* Strings:: Strings +* Status Inquiry:: Status Inquiry +* Notes:: Notes +@end menu + +@node Introduction, Printing Commands, Top, Top +@comment node-name, next, previous, up +@chapter Introduction + +DC is a reverse-polish desk calculator which supports unlimited +precision arithmetic. It also allows you to define and call macros. +Normally DC reads from the standard input; if any command arguments +are given to it, they are filenames, and DC reads and executes the +contents of the files before reading from standard input. All output +is to standard output. + +To exit, use @samp{q}. @kbd{C-c} does not exit; it is used to abort +macros that are looping, etc. (Currently this is not true; @kbd{C-c} +does exit.) + +A reverse-polish calculator stores numbers on a stack. Entering a +number pushes it on the stack. Arithmetic operations pop arguments off +the stack and push the results. + +To enter a number in DC, type the digits, with an optional decimal +point. Exponential notation is not supported. To enter a negative +number, begin the number with @samp{_}. @samp{-} cannot be used for +this, as it is a binary operator for subtraction instead. +To enter two numbers in succession, separate them with spaces or +newlines. These have no meaning as commands. + +@node Printing Commands, Arithmetic, Introduction, Top +@chapter Printing Commands + +@table @samp +@item p +Prints the value on the top of the stack, +without altering the stack. A newline is printed +after the value. + +@item P +Prints the value on the top of the stack, +popping it off, and does not print a newline after. + +@item f +Prints the entire contents of the stack +and the contents of all of the registers, +without altering anything. This is a good command +to use if you are lost or want to figure out +what the effect of some command has been. +@end table + +@node Arithmetic, Stack Control, Printing Commands, Top +@chapter Arithmetic + +@table @samp +@item + +Pops two values off the stack, adds them, +and pushes the result. The precision of the result +is determined only by the values of the arguments, +and is enough to be exact. + +@item - +Pops two values, subtracts the first one popped +from the second one popped, and pushes the result. + +@item * +Pops two values, multiplies them, and pushes the result. +The number of fraction digits in the result is controlled +by the current precision flag (see below) and does not +depend on the values being multiplied. + +@item / +Pops two values, divides the second one popped from +the first one popped, and pushes the result. +The number of fraction digits is specified by the precision flag. + +@item % +Pops two values, computes the remainder of the division +that the @samp{/} command would do, and pushes that. +The division is done with as many fraction digits +as the precision flag specifies, and the remainder +is also computed with that many fraction digits. + +@item ^ +Pops two values and exponentiates, using the first +value popped as the exponent and the second popped as the base. +The fraction part of the exponent is ignored. +The precision flag specifies the number of fraction +digits in the result. + +@item v +Pops one value, computes its square root, and pushes that. +The precision flag specifies the number of fraction digits +in the result. +@end table + +Most arithmetic operations are affected by the "precision flag", +which you can set with the @samp{k} command. The default precision +value is zero, which means that all arithmetic except for +addition and subtraction produces integer results. + +The remainder operation (@samp{%}) requires some explanation: applied to +arguments @samp{a} and @samp{b} it produces @samp{a - (b * (a / b))}, +where @samp{a / b} is computed in the current precision. + +@node Stack Control, Registers, Arithmetic, Top +@chapter Stack Control + +@table @samp +@item c +Clears the stack, rendering it empty. + +@item d +Duplicates the value on the top of the stack, +pushing another copy of it. Thus, +`4d*p' computes 4 squared and prints it. +@end table + +@node Registers, Parameters, Stack Control, Top +@chapter Registers + +DC provides 128 memory registers, each named by a single +ASCII character. You can store a number in a register +and retrieve it later. + +@table @samp +@item s@var{r} +Pop the value off the top of the stack and store +it into register @var{r}. + +@item l@var{r} +Copy the value in register @var{r}, and push it onto +the stack. This does not alter the contents of @var{r}. + +Each register also contains its own stack. The current +register value is the top of the register's stack. + +@item S@var{r} +Pop the value off the top of the (main) stack and +push it onto the stack of register @var{r}. +The previous value of the register becomes inaccessible. + +@item L@var{r} +Pop the value off the top of register @var{r}'s stack +and push it onto the main stack. The previous value +in register @var{r}'s stack, if any, is now accessible +via the `l@var{r}' command. +@end table + +The @samp{f} command prints a list of all registers that have contents +stored in them, together with their contents. Only the +current contents of each register (the top of its stack) +is printed. + +@node Parameters, Strings, Registers, Top +@chapter Parameters + +DC has three parameters that control its operation: the precision, the +input radix, and the output radix. The precision specifies the number +of fraction digits to keep in the result of most arithmetic operations. +The input radix controls the interpretation of numbers typed in; +@emph{all} numbers typed in use this radix. The output radix is used +for printing numbers. + +The input and output radices are separate parameters; you can make them +unequal, which can be useful or confusing. Each radix must be between 2 +and 36 inclusive. The precision must be zero or greater. The precision +is always measured in decimal digits, regardless of the current input or +output radix. + +@table @samp +@item i +Pops the value off the top of the stack +and uses it to set the input radix. + +@item o +@itemx k +Similarly set the output radix and the precision. + +@item I +Pushes the current input radix on the stack. + +@item O +@itemx K +Similarly push the current output radix and the current precision. +@end table + +@node Strings, Status Inquiry, Parameters, Top +@chapter Strings + +DC can operate on strings as well as on numbers. The only things you +can do with strings are print them and execute them as macros (which +means that the contents of the string are processed as DC commands). +Both registers and the stack can hold strings, and DC always knows +whether any given object is a string or a number. Some commands such as +arithmetic operations demand numbers as arguments and print errors if +given strings. Other commands can accept either a number or a string; +for example, the @samp{p} command can accept either and prints the object +according to its type. + +@table @samp +@item [@var{characters}] +Makes a string containing @var{characters} and pushes it +on the stack. For example, @samp{[foo]P} prints the +characters @samp{foo} (with no newline). + +@item x +Pops a value off the stack and executes it as a macro. +Normally it should be a string; if it is a number, +it is simply pushed back onto the stack. +For example, @samp{[1p]x} executes the macro @samp{1p}, which +pushes 1 on the stack and prints @samp{1} on a separate line. + +Macros are most often stored in registers; +@samp{[1p]sa} stores a macro to print @samp{1} into register @samp{a}, +and @samp{lax} invokes the macro. + +@item >@var{r} +Pops two values off the stack and compares them +assuming they are numbers, executing the contents +of register @var{r} as a macro if the original top-of-stack +is greater. Thus, @samp{1 2>a} will invoke register @samp{a}'s contents +and @samp{2 1>a} will not. + +@item <@var{r} +Similar but invokes the macro if the original top-of-stack +is less. + +@item =@var{r} +Similar but invokes the macro if the two numbers popped +are equal. This can also be validly used to compare two +strings for equality. + +@item ? +Reads a line from the terminal and executes it. +This command allows a macro to request input from the user. + +@item q +During the execution of a macro, this comand +does not exit DC. Instead, it exits from that +macro and also from the macro which invoked it (if any). + +@item Q +Pops a value off the stack and uses it as a count +of levels of macro execution to be exited. Thus, +@samp{3Q} exits three levels. +@end table + +@node Status Inquiry, Notes, Strings, Top +@chapter Status Inquiry + +@table @samp +@item Z +Pops a value off the stack, calculates the number of +digits it has (or number of characters, if it is a string) +and pushes that number. + +@item X +Pops a value off the stack, calculates the number of +fraction digits it has, and pushes that number. +For a string, the value pushed is -1. + +@item z +Pushes the current stack depth; the number of +objects on the stack before the execution of the @samp{z} command. + +@item I +Pushes the current value of the input radix. + +@item O +Pushes the current value of the output radix. + +@item K +Pushes the current value of the precision. +@end table + +@node Notes, , Status Inquiry, Top +@chapter Notes + +The @samp{:} and @samp{;} commands of the Unix DC program are +not supported, as the documentation does not say what they do. +The @samp{!} command is not supported, but will be supported +as soon as a library for executing a line as a command exists. + +@contents +@bye diff --git a/gnu/usr.bin/dc/decimal.c b/gnu/usr.bin/dc/decimal.c new file mode 100644 index 000000000000..1fb95c18aa14 --- /dev/null +++ b/gnu/usr.bin/dc/decimal.c @@ -0,0 +1,1235 @@ +/* + * Arbitrary precision decimal arithmetic. + * + * Copyright (C) 1984 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, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +/* Some known problems: + + Another problem with decimal_div is found when you try to + divide a number with > scale fraction digits by 1. The + expected result is simply truncation, but all sorts of things + happen instead. An example is that the result of .99999998/1 + with scale set to 6 is .000001 + + There are some problems in the behavior of the decimal package + related to printing and parsing. The + printer is weird about very large output radices, tending to want + to output single ASCII characters for any and all digits (even + in radices > 127). The UNIX bc approach is to print digit groups + separated by spaces. There is a rather overwrought workaround in + the function decputc() in bcmisc.c, but it would be better if + decimal.c got a fix for this. */ + +/* For stand-alone testing, compile with -DTEST. + This DTESTable feature defines a `main' function + which is a simple loop that accepts input of the form + number space op space number newline + where op is +, -, *, /, %, p or r, + and performs the operation and prints the operands and result. + `p' means print the first number in the radix spec'd by the second. + `r' means read the first one in the radix specified by the second + (and print the result in decimal). + Divide in this test keeps three fraction digits. */ + +#include "decimal.h" + +#define MAX(a, b) (((a) > (b) ? (a) : (b))) + +/* Some constant decimal numbers */ + +struct decimal decimal_zero = {0, 0, 0, 0, 0}; + +struct decimal decimal_one = {0, 0, 1, 0, 1}; + +/*** Assumes RADIX is even ***/ +struct decimal decimal_half = {0, 1, 0, 0, RADIX / 2}; + +decimal static decimal_add1 (), decimal_sub1 (); +static void add_scaled (); +static int subtract_scaled (); + +/* Create and return a decimal number that has `before' digits before + the decimal point and `after' digits after. The digits themselves are + initialized to zero. */ + +decimal +make_decimal (before, after) + int before, after; +{ + decimal result; + if (before >= 1<<16) + { + decimal_error ("%d too many decimal digits", before); + return 0; + } + if (after >= 1<<15) + { + decimal_error ("%d too many decimal digits", after); + return 0; + } + result = (decimal) malloc (sizeof (struct decimal) + before + after - 1); + result->sign = 0; + result->before = before; + result->after = after; + result->refcnt = 0; + bzero (result->contents, before + after); + return result; +} + +/* Create a copy of the decimal number `b' and return it. */ + +decimal +decimal_copy (b) + decimal b; +{ + decimal result = make_decimal (b->before, b->after); + bcopy (b->contents, result->contents, LENGTH(b)); + result->sign = b->sign; + return result; +} + +/* Copy a decimal number `b' but extend or truncate to exactly + `digits' fraction digits. */ + +static decimal +decimal_copy_1 (b, digits) + decimal b; + int digits; +{ + if (digits > b->after) + { + decimal result = make_decimal (b->before, digits); + bcopy (b->contents, result->contents + (digits - (int) b->after), LENGTH(b)); + return result; + } + else + return decimal_round_digits (b, digits); +} + +/* flush specified number `digits' of trailing fraction digits, + and flush any trailing fraction zero digits exposed after they are gone. + The number `b' is actually modified; no new storage is allocated. + That is why this is not global. */ + +static void +flush_trailing_digits (b, digits) + decimal b; + int digits; +{ + int flush = digits; + int maxdig = b->after; + + while (flush < maxdig && !b->contents [flush]) + flush++; + + if (flush) + { + int i; + + b->after -= flush; + for (i = 0; i < LENGTH (b); i++) + b->contents[i] = b->contents[flush + i]; + } + +} + +/* Return nonzero integer if the value of decimal number `b' is zero. */ + +int +decimal_zerop (b) + decimal b; +{ + return !LENGTH(b); +} + +/* Compare two decimal numbers arithmetically. + The value is < 0 if b1 < b2, > 0 if b1 > b2, 0 if b1 = b2. + This is the same way that `strcmp' reports the result of comparing + strings. */ + +int +decimal_compare (b1, b2) + decimal b1, b2; +{ + int l1, l2; + char *p1, *p2, *s1, *s2; + int i; + + /* If signs differ, deduce result from the signs */ + + if (b2->sign && !b1->sign) return 1; + if (b1->sign && !b2->sign) return -1; + + /* If same sign but number of nonfraction digits differs, + the one with more of them is farther from zero. */ + + if (b1->before != b2->before) + if (b1->sign) + return (int) (b2->before - b1->before); + else + return (int) (b1->before - b2->before); + + /* Else compare the numbers digit by digit from high end */ + l1 = LENGTH(b1); + l2 = LENGTH(b2); + s1 = b1->contents; /* Start of number -- don't back up digit pointer past here */ + s2 = b2->contents; + p1 = b1->contents + l1; /* Scanning pointer, for fetching digits. */ + p2 = b2->contents + l2; + for (i = MAX(l1, l2); i >= 0; i--) + { + int r = ((p1 != s1) ? *--p1 : 0) - ((p2 != s2) ? *--p2 : 0); + if (r) + return b1->sign ? -r : r; + } + return 0; +} + +/* Return the number of digits stored in decimal number `b' */ + +int +decimal_length (b) + decimal b; +{ + return LENGTH(b); +} + +/* Return the number of fraction digits stored in decimal number `b'. */ + +int +decimal_after (b) + decimal b; +{ + return b->after; +} + +/* Round decimal number `b' to have only `digits' fraction digits. + Result is rounded to nearest unit in the last remaining digit. + Return the result, another decimal number. */ + +decimal +decimal_round_digits (b, digits) + decimal b; + int digits; +{ + decimal result; + int old; + + if (b->after <= digits) return decimal_copy (b); + + if (digits < 0) + { + decimal_error ("request to keep negative number of digits %d", digits); + return decimal_copy (b); + } + + result = make_decimal (b->before + 1, b->after); + result->sign = b->sign; + bcopy (b->contents, result->contents, LENGTH(b)); + + old = result->after; + + /* Add .5 * last place to keep, so that we round rather than truncate */ + /* Note this ignores sign of result, so if result is negative + it is subtracting */ + + add_scaled (result, DECIMAL_HALF, 1, old - digits - 1); + + /* Flush desired digits, and any trailing zeros exposed by them. */ + + flush_trailing_digits (result, old - digits); + + /* Flush leading digits -- always is one, unless was a carry into it */ + + while (result->before > 0 + && result->contents[LENGTH(result) - 1] == 0) + result->before--; + + return result; +} + +/* Truncate decimal number `b' to have only `digits' fraction digits. + Any fraction digits in `b' beyond that are dropped and ignored. + Truncation is toward zero. + Return the result, another decimal number. */ + +decimal +decimal_trunc_digits (b, digits) + decimal b; + int digits; +{ + decimal result = decimal_copy (b); + int old = result->after; + + if (old <= digits) return result; + + if (digits < 0) + { + decimal_error ("request to keep negative number of digits %d", digits); + return result; + } + + flush_trailing_digits (result, old - digits); + + return result; +} + +/* Return the fractional part of decimal number `b': + that is, `b' - decimal_trunc_digits (`b') */ + +decimal +decimal_fraction (b) + decimal b; +{ + decimal result = make_decimal (0, b->after); + bcopy (b->contents, result->contents, b->after); + return result; +} + +/* return an integer whose value is that of decimal `b', sans its fraction. */ + +int +decimal_to_int (b) + decimal b; +{ + int result = 0; + int i; + int end = b->after; + + for (i = LENGTH(b) - 1; i >= end; i--) + { + result *= RADIX; + result += b->contents[i]; + } + return result; +} + +/* return a decimal whose value is the integer i. */ + +decimal +decimal_from_int (i) + int i; +{ + int log, tem; + decimal result; + + for (log = 0, tem = (i > 0 ? i : - i); tem; log++, tem /= RADIX); + + result = make_decimal (log, 0); + + for (log = 0, tem = (i > 0 ? i : - i); tem; log++, tem /= RADIX) + result->contents[log] = tem % RADIX; + + if (i < 0) result->sign = 1; + return result; +} + +/* Return (as an integer) the result of dividing decimal number `b' by + integer `divisor'. + This is used in printing decimal numbers in other radices. */ + +int +decimal_int_rem (b, divisor) + decimal b; + int divisor; +{ + int len = LENGTH(b); + int end = b->after; + int accum = 0; + int i; + + for (i = len - 1; i >= end; i--) + { + accum %= divisor; + accum *= RADIX; + accum += b->contents[i]; + } + return accum % divisor; +} + +/* Convert digit `digit' to a character and output it by calling + `charout' with it as arg. */ + +static void +print_digit (digit, charout) + int digit; + void (*charout) (); +{ + if (digit < 10) + charout ('0' + digit); + else + charout ('A' + digit - 10); +} + +/* print decimal number `b' in radix `radix', assuming it is an integer. + `r' is `radix' expressed as a decimal number. */ + +static +decimal_print_1 (b, r, radix, charout) + decimal b, r; + int radix; + void (*charout) (); +{ + int digit = decimal_int_rem (b, radix); + decimal rest = decimal_div (b, r, 0); + + if (!decimal_zerop (rest)) + decimal_print_1 (rest, r, radix, charout); + + print_digit (digit, charout); + + free (rest); +} + +/* User entry: print decimal number `b' in radix `radix' (an integer), + outputting characters by calling `charout'. */ + +void +decimal_print (b, charout, radix) + decimal b; + void (*charout) (); + int radix; +{ + if (b->sign) charout ('-'); + + if (radix == RADIX) + { + /* decimal output => just print the digits, inserting a point in + the proper place. */ + int i; + int before = b->before; + int len = before + b->after; + for (i = 0; i < len; i++) + { + if (i == before) charout ('.'); + /* Broken if RADIX /= 10 + charout ('0' + b->contents [len - 1 - i]); */ + print_digit (b->contents [len - 1 - i], charout); + } + if (!len) + charout ('0'); + } + else + { + /* nonstandard radix: must use multiply and divide to determine the + digits of the number in that radix. */ + + int i; + extern double log10 (); + /* Compute the number of fraction digits we want to have in the + new radix. They should contain the same amount of + information as the decimal digits we have. */ + int nfrac = (b->after / log10 ((double) radix) + .99); + decimal r = decimal_from_int (radix); + decimal intpart = decimal_trunc_digits (b, 0); + + /* print integer part */ + decimal_print_1 (intpart, r, radix, charout); + free (intpart); + + /* print fraction part */ + if (nfrac) + { + decimal tem1, tem2; + tem1 = decimal_fraction (b); + charout ('.'); + /* repeatedly multiply by `radix', print integer part as one digit, + and flush the integer part. */ + for (i = 0; i < nfrac; i++) + { + tem2 = decimal_mul (tem1, r); + free (tem1); + print_digit (decimal_to_int (tem2), charout); + tem1 = decimal_fraction (tem2); + free (tem2); + } + free (tem1); + } + free (r); + } +} + +static int +decode_digit (digitchar) + char digitchar; +{ + if ('0' <= digitchar && digitchar <= '9') + return digitchar - '0'; + if ('a' <= digitchar && digitchar <= 'z') + return digitchar - 'a' + 10; + if ('A' <= digitchar && digitchar <= 'Z') + return digitchar - 'A' + 10; + return -1; +} + +/* Parse string `s' into a number using radix `radix' + and return result as a decimal number. */ + +decimal +decimal_parse (s, radix) + char *s; + int radix; +{ + int i, len, before = -1; + char *p; + char c; + decimal result; + int negative = 0; + int excess_digit = 0; + + if (*s == '-') + { + s++; + negative = 1; + } + + /* First scan for valid characters. + Count total num digits, and count num before the decimal point. */ + + p = s; + i = 0; + while (c = *p++) + { + if (c == '.') + { + if (before >= 0) + decimal_error ("two decimal points in %s", s); + before = i; + } + else if (c == '0' && !i && before < 0) + s++; /* Discard leading zeros */ + else if (decode_digit (c) >= 0) + { + i++; + if (decode_digit (c) > RADIX) + excess_digit = 1; + } + else + decimal_error ("invalid number %s", s); + } + + len = i; + if (before < 0) before = i; + + p = s; + + /* Now parse those digits */ + + if (radix != RADIX || excess_digit) + { + decimal r = decimal_from_int (radix); + extern double log10 (); + int digits = (len - before) * log10 ((double) radix) + .99; + result = decimal_copy (DECIMAL_ZERO); + + /* Parse all the digits into an integer, ignoring decimal point, + by multiplying by `radix'. */ + + while (i > 0 && (c = *p++)) + { + if (c != '.') + { + decimal newdig = decimal_from_int (decode_digit (c)); + decimal prod = decimal_mul (result, r); + decimal newresult = decimal_add (newdig, prod); + + free (newdig); free (prod); free (result); + result = newresult; + i--; + } + } + + /* Now put decimal point in right place + by dividing by `radix' once for each digit + that really should have followed the decimal point. */ + + for (i = before; i < len; i++) + { + decimal newresult = decimal_div (result, r, digits); + free (result); + result = newresult; + } + free (r); + } + else + { + /* radix is standard - just copy the digits into a decimal number. */ + + int tem; + result = make_decimal (before, len - before); + + while (i > 0 && (c = *p++)) + { + if ((c != '.') && + ((tem = decode_digit (c)) >= 0)) + result->contents [--i] = tem; + } + } + + if (negative) result->sign = 1; + flush_trailing_digits (result, 0); + return result; +} + +/* Add b1 and b2, considering their signs */ + +decimal +decimal_add (b1, b2) + decimal b1, b2; +{ + decimal v; + + if (b1->sign != b2->sign) + v = decimal_sub1 (b1, b2); + else + v = decimal_add1 (b1, b2); + if (b1->sign && !decimal_zerop (v)) + v->sign = !v->sign; + return v; +} + +/* Add b1 and minus b2, considering their signs */ + +decimal +decimal_sub (b1, b2) + decimal b1, b2; +{ + decimal v; + + if (b1->sign != b2->sign) + v = decimal_add1 (b1, b2); + else + v = decimal_sub1 (b1, b2); + if (b1->sign && !decimal_zerop (v)) + v->sign = !v->sign; + return v; +} + +/* Return the negation of b2. */ + +decimal +decimal_neg (b2) + decimal b2; +{ + decimal v = decimal_copy (b2); + + if (!decimal_zerop (v)) + v->sign = !v->sign; + return v; +} + +/* add magnitudes of b1 and b2, ignoring their signs. */ + +static decimal +decimal_add1 (b1, b2) + decimal b1, b2; +{ + int before = MAX (b1->before, b2->before); + int after = MAX (b1->after, b2->after); + + int len = before+after+1; + decimal result = make_decimal (before+1, after); + + int i; + char *s1 = b1->contents; + char *s2 = b2->contents; + char *p1 = s1 + b1->after - after; + char *p2 = s2 + b2->after - after; + char *e1 = s1 + b1->before + b1->after; + char *e2 = s2 + b2->before + b2->after; + char *pr = result->contents; + int accum = 0; + + for (i = 0; i < len; i++, p1++, p2++) + { + accum /= RADIX; + if (p1 >= s1 && p1 < e1) accum += *p1; + if (p2 >= s2 && p2 < e2) accum += *p2; + *pr++ = accum % RADIX; + } + if (!accum) + (result->before)--; + + flush_trailing_digits (result, 0); + + return result; +} + +/* subtract magnitude of b2 from that or b1, returning signed decimal + number. */ + +static decimal +decimal_sub1 (b1, b2) + decimal b1, b2; +{ + int before = MAX (b1->before, b2->before); + int after = MAX (b1->after, b2->after); + + int len = before+after; + decimal result = make_decimal (before, after); + + int i; + char *s1 = b1->contents; + char *s2 = b2->contents; + char *p1 = s1 + b1->after - after; + char *p2 = s2 + b2->after - after; + char *e1 = s1 + b1->before + b1->after; + char *e2 = s2 + b2->before + b2->after; + char *pr = result->contents; + int accum = 0; + + for (i = 0; i < len; i++, p1++, p2++) + { + if (p1 >= s1 && p1 < e1) accum += *p1; + if (p2 >= s2 && p2 < e2) accum -= *p2; + if (accum < 0 && accum % RADIX) + *pr = RADIX - (- accum) % RADIX; + else + *pr = accum % RADIX; + accum -= *pr++; + accum /= RADIX; + } + + /* If result is negative, subtract it from RADIX**length + so that we get the right digits for sign-magnitude + rather than RADIX-complement */ + + if (accum) + { + result->sign = 1; + pr = result->contents; + accum = 0; + for (i = 0; i < len; i++) + { + accum -= *pr; + if (accum) + *pr = accum + RADIX; + else + *pr = 0; + accum -= *pr++; + accum /= RADIX; + } + } + + /* flush leading nonfraction zero digits */ + + while (result->before && *--pr == 0) + (result->before)--; + + flush_trailing_digits (result, 0); + + return result; +} + +/* multiply b1 and b2 keeping `digits' fraction digits */ + +decimal +decimal_mul_rounded (b1, b2, digits) + decimal b1, b2; + int digits; +{ + decimal tem = decimal_mul (b1, b2); + decimal result = decimal_round_digits (tem, digits); + free (tem); + return result; +} + +/* multiply b1 and b2 keeping the right number of fraction digits + for the `dc' program with precision = `digits'. */ + +decimal +decimal_mul_dc (b1, b2, digits) + decimal b1, b2; + int digits; +{ + decimal tem = decimal_mul (b1, b2); + decimal result + = decimal_round_digits (tem, MAX (digits, MAX (b1->after, b2->after))); + free (tem); + return result; +} + +/* multiply b1 and b2 as decimal error-free values; + keep LENGTH(b1) plus LENGTH(b2) significant figures. */ + +decimal +decimal_mul (b1, b2) + decimal b1, b2; +{ + decimal result = make_decimal (b1->before + b2->before, b1->after + b2->after); + int i; + int length2 = LENGTH(b2); + char *pr; + + for (i = 0; i < length2; i++) + add_scaled (result, b1, b2->contents[i], i); + + /* flush leading nonfraction zero digits */ + + pr = result->contents + LENGTH(result); + while (result->before && *--pr == 0) + (result->before)--; + + flush_trailing_digits (result, 0); /* flush trailing zeros */ + + /* Set sign properly */ + + if (b1->sign != b2->sign && LENGTH(result)) + result->sign = 1; + + return result; +} + +/* Modify decimal number `into' by adding `from', + multiplied by `factor' (which should be nonnegative and less than RADIX) + and shifted left `scale' digits at the least significant end. */ + +static void +add_scaled (into, from, factor, scale) + decimal into, from; + int factor, scale; +{ + char *pf = from->contents; + char *pi = into->contents + scale; + int lengthf = LENGTH(from); + int lengthi = LENGTH(into) - scale; + + int accum = 0; + int i; + + for (i = 0; i < lengthi; i++) + { + accum /= RADIX; + if (i < lengthf) + accum += *pf++ * factor; + accum += *pi; + *pi++ = accum % RADIX; + } +} + +/* Divide decimal number `b1' by `b2', keeping at most `digits' + fraction digits. + Returns the result as a decimal number. + + When division is not exact, the quotient is truncated toward zero. */ + +decimal +decimal_div (b1, b2, digits) + decimal b1, b2; + int digits; +{ + decimal result = make_decimal (MAX(1, (int) (1 + b1->before - b2->before)), digits); + + /* b1copy holds what is left of the dividend, + that is not accounted for by the quotient digits already known */ + + decimal b1copy = decimal_copy_1 (b1, b2->after + digits); + int length1 = LENGTH(b1copy); + int length2 = LENGTH(b2); + int lengthr = LENGTH(result); + int i; + + /* leading_divisor_digits contains the first two divisor digits, as + an integer */ + + int leading_divisor_digits = b2->contents[length2-1]*RADIX; + if (length2 > 1) + leading_divisor_digits += b2->contents[length2-2]; + + if (decimal_zerop (b2)) + { + decimal_error ("divisor is zero", 0); + return decimal_copy (DECIMAL_ZERO); + } + + if (lengthr <= (length1 - length2)) + abort(); /* My reasoning says this cannot happen, I hope */ + + for (i = length1 - length2; i >= 0; i--) + { + /* Guess the next quotient digit (in order of decreasing significance) + using integer division */ + + int guess; + int trial_dividend = b1copy->contents[length2+i-1]*RADIX; + if (i != length1 - length2) + trial_dividend += b1copy->contents[length2+i]*RADIX*RADIX; + if (length2 + i > 1) + trial_dividend += b1copy->contents[length2+i-2]; + + guess = trial_dividend / leading_divisor_digits; + + /* Remove the quotient times this digit from the dividend left */ + /* We may find that the quotient digit is too large, + when we consider the entire divisor. + Then we decrement the quotient digit and add the divisor back in */ + + if (guess && 0 > subtract_scaled (b1copy, b2, guess, i)) + { + guess--; + add_scaled (b1copy, b2, 1, i); + } + + if (guess >= RADIX) + { + result->contents[i + 1] += guess / RADIX; + guess %= RADIX; + } + result->contents[i] = guess; + } + + free (b1copy); + + result->sign = (b1->sign != b2->sign); + + /* flush leading nonfraction zero digits */ + + { + char *pr = result->contents + lengthr; + while (result->before && *--pr == 0) + (result->before)--; + } + + flush_trailing_digits (result, 0); /* Flush trailing zero fraction digits */ + + return result; +} + +/* The remainder for the above division. + Same as `b1' - (`b1' / `b2') * 'b2'. + Note that the value depends on the number of fraction digits + that were kept in computing `b1' / `b2'; + the argument `digits' specifies this. + + The remainder has the same sign as the dividend. + The divisor's sign is ignored. */ + +decimal +decimal_rem (b1, b2, digits) + decimal b1, b2; + int digits; +{ + decimal b1copy = decimal_copy_1 (b1, b2->after + digits); + int length1 = LENGTH(b1copy); + int length2 = LENGTH(b2); + int i; + + int leading_divisor_digits = b2->contents[length2-1]*RADIX; + + if (length2 > 1) + leading_divisor_digits += b2->contents[length2-2]; + + if (decimal_zerop (b2)) + { + decimal_error ("divisor is zero", 0); + return decimal_copy (DECIMAL_ZERO); + } + + /* Do like division, above, but throw away the quotient. + Keep only the final `rest of dividend', which becomes the remainder. */ + + for (i = length1 - length2; i >= 0; i--) + { + int guess; + int trial_dividend = b1copy->contents[length2+i-1]*RADIX; + if (i != length1 - length2) + trial_dividend += b1copy->contents[length2+i]*RADIX*RADIX; + if (length2 + i > 1) + trial_dividend += b1copy->contents[length2+i-2]; + + guess = trial_dividend / leading_divisor_digits; + + if (guess && 0 > subtract_scaled (b1copy, b2, guess, i)) + { + guess--; + add_scaled (b1copy, b2, 1, i); + } + /* No need to check whether guess exceeds RADIX + since we are not saving guess. */ + } + + /* flush leading nonfraction zero digits */ + + { + char *pr = b1copy->contents + length1; + while (b1copy->before && *--pr == 0) + (b1copy->before)--; + } + + flush_trailing_digits (b1copy, 0); + return b1copy; +} + +/* returns negative number if we chose factor too large */ + +static int +subtract_scaled (into, from, factor, scale) + decimal into, from; + int factor, scale; +{ + char *pf = from->contents; + char *pi = into->contents + scale; + int lengthf = LENGTH(from); + int lengthi = LENGTH(into) - scale; + int accum = 0; + int i; + + for (i = 0; i < lengthi && i <= lengthf; i++) + { + if (i < lengthf) + accum -= *pf++ * factor; + accum += *pi; + if (accum < 0 && accum % RADIX) + *pi = RADIX - (- accum) % RADIX; + else + *pi = accum % RADIX; + accum -= *pi++; + accum /= RADIX; + } + return accum; +} + +/* Return the square root of decimal number D, using Newton's method. + Number of fraction digits returned is max of FRAC_DIGITS + and D's number of fraction digits. */ + +decimal +decimal_sqrt (d, frac_digits) + decimal d; + int frac_digits; +{ + decimal guess; + int notdone = 1; + + if (decimal_zerop (d)) return d; + if (d->sign) + { + decimal_error ("square root argument negative", 0); + return decimal_copy (DECIMAL_ZERO); + } + + frac_digits = MAX (frac_digits, d->after); + + /* Compute an initial guess by taking the square root + of a nearby power of RADIX. */ + + if (d->before) + { + guess = make_decimal ((d->before + 1) / 2, 0); + guess->contents[guess->before - 1] = 1; + } + else + { + /* Arg is less than 1; compute nearest power of RADIX */ + char *p = d->contents + LENGTH(d); + char *sp = p; + + while (!*--p); /* Find most significant nonzero digit */ + if (sp - p == 1) + { + /* Arg is bigger than 1/RADIX; use 1 as a guess */ + guess = decimal_copy (DECIMAL_ONE); + } + else + { + guess = make_decimal (0, (sp - p) / 2); + guess->contents[0] = 1; + } + } + + /* Iterate doing guess = (guess + d/guess) / 2 */ + + while (notdone) + { + decimal tem1 = decimal_div (d, guess, frac_digits + 1); + decimal tem2 = decimal_add (guess, tem1); + decimal tem3 = decimal_mul_rounded (tem2, DECIMAL_HALF, frac_digits); + notdone = decimal_compare (guess, tem3); + free (tem1); + free (tem2); + free (guess); + guess = tem3; + if (decimal_zerop (guess)) return guess; /* Avoid divide-by-zero */ + } + + return guess; +} + +/* Raise decimal number `base' to power of integer part of decimal + number `expt'. + This function depends on using radix 10. + It is too hard to write it to work for any value of RADIX, + so instead it is simply not available if RADIX is not ten. */ + +#if !(RADIX - 10) + +decimal +decimal_expt (base, expt, frac_digits) + decimal base, expt; + int frac_digits; +{ + decimal accum = decimal_copy (DECIMAL_ONE); + decimal basis1 = base; + int digits = expt->before; + int dig = 0; /* Expt digit being processed */ + + if (expt->sign) + /* If negative power, take reciprocal first thing + so that fraction digit truncation won't destroy + what will ultimately be nonfraction digits. */ + basis1 = decimal_div (DECIMAL_ONE, base, frac_digits); + while (dig < digits) + { + decimal basis2, basis4, basis8, basis10; + int thisdigit = expt->contents[expt->after + dig]; + + /* Compute factors to multiply in for each bit of this digit */ + + basis2 = decimal_mul_rounded (basis1, basis1, frac_digits); + basis4 = decimal_mul_rounded (basis2, basis2, frac_digits); + basis8 = decimal_mul_rounded (basis4, basis4, frac_digits); + + /* Now accumulate the factors this digit value selects */ + + if (thisdigit & 1) + { + decimal accum1 = decimal_mul_rounded (accum, basis1, frac_digits); + free (accum); + accum = accum1; + } + + if (thisdigit & 2) + { + decimal accum1 = decimal_mul_rounded (accum, basis2, frac_digits); + free (accum); + accum = accum1; + } + + if (thisdigit & 4) + { + decimal accum1 = decimal_mul_rounded (accum, basis4, frac_digits); + free (accum); + accum = accum1; + } + + if (thisdigit & 8) + { + decimal accum1 = decimal_mul_rounded (accum, basis8, frac_digits); + free (accum); + accum = accum1; + } + + /* If there are further digits, compute the basis1 for the next digit */ + + if (++dig < digits) + basis10 = decimal_mul_rounded (basis2, basis8, frac_digits); + + /* Free intermediate results */ + + if (basis1 != base) free (basis1); + free (basis2); + free (basis4); + free (basis8); + basis1 = basis10; + } + return accum; +} +#endif + +#ifdef TEST + +fputchar (c) + char c; +{ + putchar (c); +} + +/* Top level that can be used to test the arithmetic functions */ + +main () +{ + char s1[40], s2[40]; + decimal b1, b2, b3; + char c; + + while (1) + { + scanf ("%s %c %s", s1, &c, s2); + b1 = decimal_parse (s1, RADIX); + b2 = decimal_parse (s2, RADIX); + switch (c) + { + default: + c = '+'; + case '+': + b3 = decimal_add (b1, b2); + break; + case '*': + b3 = decimal_mul (b1, b2); + break; + case '/': + b3 = decimal_div (b1, b2, 3); + break; + case '%': + b3 = decimal_rem (b1, b2, 3); + break; + case 'p': + decimal_print (b1, fputchar, RADIX); + printf (" printed in base %d is ", decimal_to_int (b2)); + decimal_print (b1, fputchar, decimal_to_int (b2)); + printf ("\n"); + continue; + case 'r': + printf ("%s read in base %d is ", s1, decimal_to_int (b2)); + decimal_print (decimal_parse (s1, decimal_to_int (b2)), fputchar, RADIX); + printf ("\n"); + continue; + } + decimal_print (b1, fputchar, RADIX); + printf (" %c ", c); + decimal_print (b2, fputchar, RADIX); + printf (" = "); + decimal_print (b3, fputchar, RADIX); + printf ("\n"); + } +} + +decimal_error (s1, s2) + char *s1, *s2; +{ + printf ("\n"); + printf (s1, s2); + printf ("\n"); +} + +static void +pbi (b) + int b; +{ + decimal_print ((decimal) b, fputchar, RADIX); +} + +static void +pb (b) + decimal b; +{ + decimal_print (b, fputchar, RADIX); +} + +#endif diff --git a/gnu/usr.bin/dc/decimal.h b/gnu/usr.bin/dc/decimal.h new file mode 100644 index 000000000000..2b41158166a2 --- /dev/null +++ b/gnu/usr.bin/dc/decimal.h @@ -0,0 +1,93 @@ +/* + * Header file for decimal.c (arbitrary precision decimal arithmetic) + * + * Copyright (C) 1984 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, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +/* Autoconf stuff */ +#ifndef HAVE_BCOPY +#undef bcopy +#define bcopy(s2, s1, n) memcpy (s1, s2, n) +#endif + +#ifndef HAVE_BZERO +#undef bzero +#define bzero(b, l) memset (b, 0, l) +#endif + +/* Define the radix to use by default, and for representing the + numbers internally. This does not need to be decimal; that is just + the default for it. */ + +/* Currently, this is required to be even for this program to work. */ + +#ifndef RADIX +#define RADIX 10 +#endif + +/* The user must define the external function `decimal_error' + which is called with two arguments to report errors in this package. + The two arguments may be passed to `printf' to print a message. */ + +/* Structure that represents a decimal number */ + +struct decimal +{ + unsigned int sign: 1; /* One for negative number */ + /* The sign should always be zero for the number 0 */ + int after: 15; /* number of fraction digits */ + unsigned short before; /* number of non-fraction digits */ + unsigned short refcnt; /* number of pointers to this number */ + /* (used by calling program) */ + char contents[1]; /* the digits themselves, least significant first. */ + /* digits are just numbers 0 .. RADIX-1 */ +}; + +/* There may never be leading nonfraction zeros or trailing fraction + zeros in a number. They must be removed by all the arithmetic + functions. Therefore, the number zero always has no digits stored. */ + +typedef struct decimal *decimal; + +/* Decimal numbers are always passed around as pointers. + All the external entries in this file allocate new numbers + using `malloc' to store values in. + They never modify their arguments or any existing numbers. */ + +/* Return the total number of digits stored in the number `b' */ +#define LENGTH(b) ((b)->before + (b)->after) + +/* Some constant decimal numbers */ + + +#define DECIMAL_ZERO &decimal_zero + + +#define DECIMAL_ONE &decimal_one + +#define DECIMAL_HALF &decimal_half + +decimal decimal_add (), decimal_sub (), decimal_mul (), decimal_div (); +decimal decimal_mul_dc (), decimal_mul_rounded (), decimal_rem (); +decimal decimal_round_digits (); +decimal make_decimal (), decimal_copy (), decimal_parse (); +decimal decimal_sqrt (), decimal_expt (); + +void decimal_print (); + +/* End of decimal.h */ diff --git a/gnu/usr.bin/dc/texinfo.tex b/gnu/usr.bin/dc/texinfo.tex new file mode 100644 index 000000000000..ce8124ecb7bd --- /dev/null +++ b/gnu/usr.bin/dc/texinfo.tex @@ -0,0 +1,4003 @@ +%% TeX macros to handle texinfo files + +% Copyright (C) 1985, 86, 88, 90, 91, 92, 1993 Free Software Foundation, Inc. + +%This texinfo.tex file 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 texinfo.tex file 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 texinfo.tex file; see the file COPYING. If not, write +%to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, +%USA. + + +%In other words, you are welcome to use, share and improve this program. +%You are forbidden to forbid anyone else to use, share and improve +%what you give them. Help stamp out software-hoarding! + +\def\texinfoversion{2.108} +\message{Loading texinfo package [Version \texinfoversion]:} + +% Print the version number if in a .fmt file. +\everyjob{\message{[Texinfo version \texinfoversion]}\message{}} + +% Save some parts of plain tex whose names we will redefine. + +\let\ptexlbrace=\{ +\let\ptexrbrace=\} +\let\ptexdots=\dots +\let\ptexdot=\. +\let\ptexstar=\* +\let\ptexend=\end +\let\ptexbullet=\bullet +\let\ptexb=\b +\let\ptexc=\c +\let\ptexi=\i +\let\ptext=\t +\let\ptexl=\l +\let\ptexL=\L + +\def\tie{\penalty 10000\ } % Save plain tex definition of ~. + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Ignore a token. +% +\def\gobble#1{} + +\hyphenation{ap-pen-dix} +\hyphenation{mini-buf-fer mini-buf-fers} +\hyphenation{eshell} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen \bindingoffset \bindingoffset=0pt +\newdimen \normaloffset \normaloffset=\hoffset +\newdimen\pagewidth \newdimen\pageheight +\pagewidth=\hsize \pageheight=\vsize + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% + +%---------------------Begin change----------------------- +% +%%%% For @cropmarks command. +% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\cornerlong \newdimen\cornerthick +\newdimen \topandbottommargin +\newdimen \outerhsize \newdimen \outervsize +\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks +\outerhsize=7in +%\outervsize=9.5in +% Alternative @smallbook page size is 9.25in +\outervsize=9.25in +\topandbottommargin=.75in +% +%---------------------End change----------------------- + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions itself, but you have to call it yourself. +\chardef\PAGE=255 \output={\onepageout{\pagecontents\PAGE}} +\def\onepageout#1{\hoffset=\normaloffset +\ifodd\pageno \advance\hoffset by \bindingoffset +\else \advance\hoffset by -\bindingoffset\fi +{\escapechar=`\\\relax % makes sure backslash is used in output files. +\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}% +{\let\hsize=\pagewidth \makefootline}}}% +\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi} + +%%%% For @cropmarks command %%%% + +% Here is a modification of the main output routine for Near East Publications +% This provides right-angle cropmarks at all four corners. +% The contents of the page are centerlined into the cropmarks, +% and any desired binding offset is added as an \hskip on either +% site of the centerlined box. (P. A. MacKay, 12 November, 1986) +% +\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up +{\escapechar=`\\\relax % makes sure backslash is used in output files. + \shipout + \vbox to \outervsize{\hsize=\outerhsize + \vbox{\line{\ewtop\hfill\ewtop}} + \nointerlineskip + \line{\vbox{\moveleft\cornerthick\nstop} + \hfill + \vbox{\moveright\cornerthick\nstop}} + \vskip \topandbottommargin + \centerline{\ifodd\pageno\hskip\bindingoffset\fi + \vbox{ + {\let\hsize=\pagewidth \makeheadline} + \pagebody{#1} + {\let\hsize=\pagewidth \makefootline}} + \ifodd\pageno\else\hskip\bindingoffset\fi} + \vskip \topandbottommargin plus1fill minus1fill + \boxmaxdepth\cornerthick + \line{\vbox{\moveleft\cornerthick\nsbot} + \hfill + \vbox{\moveright\cornerthick\nsbot}} + \nointerlineskip + \vbox{\line{\ewbot\hfill\ewbot}} + }} + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi} +% +% Do @cropmarks to get crop marks +\def\cropmarks{\let\onepageout=\croppageout } + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% here.) But this means we cannot call \removeactivespaces as part of +% \argremovec{,omment}, since @c uses \parsearg, and thus the argument +% that \parsearg gets might well have any character at all in it. +% +\def\removeactivespaces#1{% + \begingroup + \ignoreactivespaces + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +%% These are used to keep @begin/@end levels from running away +%% Call \inENV within environments (after a \begingroup) +\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} +\def\ENVcheck{% +\ifENV\errmessage{Still within an environment. Type Return to continue.} +\endgroup\fi} % This is not perfect, but it should reduce lossage + +% @begin foo is the same as @foo, for now. +\newhelp\EMsimple{Type <Return> to continue.} + +\outer\def\begin{\parsearg\beginxxx} + +\def\beginxxx #1{% +\expandafter\ifx\csname #1\endcsname\relax +{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else +\csname #1\endcsname\fi} + +% @end foo executes the definition of \Efoo. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% There is an environment #1, but it hasn't been started. Give an error. +% +\def\unmatchedenderror#1{% + \errhelp = \EMsimple + \errmessage{This `@end #1' doesn't have a matching `@#1'}% +} + +% Define the control sequence \E#1 to give an unmatched @end error. +% +\def\defineunmatchedend#1{% + \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% +} + + +% Single-spacing is done by various environments (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = \baselineskip +\def\singlespace{% +% Why was this kern here? It messes up equalizing space above and below +% environments. --karl, 6may93 +%{\advance \baselineskip by -\singlespaceskip +%\kern \baselineskip}% +\baselineskip=\singlespaceskip +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt \char '100}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. + +\def\mylbrace {{\tt \char '173}} +\def\myrbrace {{\tt \char '175}} +\let\{=\mylbrace +\let\}=\myrbrace + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=3000 } + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +\def\group{\begingroup + \ifnum\catcode13=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % The \vtop we start below produces a box with normal height and large + % depth; thus, TeX puts \baselineskip glue before it, and (when the + % next line of text is done) \lineskip glue after it. (See p.82 of + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % We do @comment here in case we are called inside an environment, + % such as @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\def\need{\parsearg\needx} + +% Old definition--didn't work. +%\def\needx #1{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000 +%\prevdepth=-1000pt +%}} + +\def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \allowbreak + \nointerlineskip + \vtop to #1\mil{\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak +} + +% @br forces paragraph break + +\let\br = \par + +% @dots{} output some dots + +\def\dots{$\ldots$} + +% @page forces the start of a new page + +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. + +\def\include{\parsearg\includezzz} +%Use \input\thisfile to avoid blank after \input, which may be an active +%char (in which case the blank would become the \input argument). +%The grouping keeps the value of \thisfile correct even when @include +%is nested. +\def\includezzz #1{\begingroup +\def\thisfile{#1}\input\thisfile +\endgroup} + +\def\thisfile{} + +% @center line outputs that line, centered + +\def\center{\parsearg\centerzzz} +\def\centerzzz #1{{\advance\hsize by -\leftskip +\advance\hsize by -\rightskip +\centerline{#1}}} + +% @sp n outputs n lines of vertical space + +\def\sp{\parsearg\spxxx} +\def\spxxx #1{\par \vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other% +\parsearg \commentxxx} + +\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 } + +\let\c=\comment + +% Prevent errors for section commands. +% Used in @ignore and in failing conditionals. +\def\ignoresections{% +\let\chapter=\relax +\let\unnumbered=\relax +\let\top=\relax +\let\unnumberedsec=\relax +\let\unnumberedsection=\relax +\let\unnumberedsubsec=\relax +\let\unnumberedsubsection=\relax +\let\unnumberedsubsubsec=\relax +\let\unnumberedsubsubsection=\relax +\let\section=\relax +\let\subsec=\relax +\let\subsubsec=\relax +\let\subsection=\relax +\let\subsubsection=\relax +\let\appendix=\relax +\let\appendixsec=\relax +\let\appendixsection=\relax +\let\appendixsubsec=\relax +\let\appendixsubsection=\relax +\let\appendixsubsubsec=\relax +\let\appendixsubsubsection=\relax +\let\contents=\relax +\let\smallbook=\relax +\let\titlepage=\relax +} + +% Used in nested conditionals, where we have to parse the Texinfo source +% and so want to turn off most commands, in case they are used +% incorrectly. +% +\def\ignoremorecommands{% + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Also ignore @ifinfo, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\def\menu{\doignore{menu}} +\def\direntry{\doignore{direntry}} + +% Ignore text until a line `@end #1'. +% +\def\doignore#1{\begingroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define a command to swallow text until we reach `@end #1'. + \long\def\doignoretext##1\end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{***WARNING*** for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% Ignore text, except that we keep track of conditional commands for +% purposes of nesting, up to an `@end #1' command. +% +\def\nestedignore#1{% + \obstexwarn + % We must actually expand the ignored text to look for the @end + % command, so that nested ignore constructs work. Thus, we put the + % text into a \vbox and then do nothing with the result. To minimize + % the change of memory overflow, we follow the approach outlined on + % page 401 of the TeXbook: make the current font be a dummy font. + % + \setbox0 = \vbox\bgroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % We can't do anything about stray @-signs, unfortunately; + % they'll produce `undefined control sequence' errors. + \ignoremorecommands + % + % Set the current font to be \nullfont, a TeX primitive, and define + % all the font commands to also use \nullfont. We don't use + % dummy.tfm, as suggested in the TeXbook, because not all sites + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}} +} + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. +% +\def\set{\parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi +} +\def\setzzz#1#2 \endsetzzz{\expandafter\xdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +% +\def\value#1{\expandafter + \ifx\csname SET#1\endcsname\relax + {\{No value for ``#1''\}} + \else \csname SET#1\endcsname \fi} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +\def\ifset{\parsearg\ifsetxxx} +\def\ifsetxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +\def\ifclear{\parsearg\ifclearxxx} +\def\ifclearxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @iftex always succeeds; we read the text following, through @end +% iftex). But `@end iftex' should be valid only after an @iftex. +% +\def\iftex{\conditionalsucceed{iftex}} +\defineunmatchedend{iftex} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% define \Eiftex to redefine itself to be its previous value. (We can't +% just define it to fail again with an ``unmatched end'' error, since +% the @ifset might be nested.) +% +\def\conditionalsucceed#1{% + \edef\temp{% + % Remember the current value of \E#1. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\def\nece#1{\expandafter\noexpand\csname#1\endcsname} + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math means output in math mode. +% We don't use $'s directly in the definition of \math because control +% sequences like \math are expanded when the toc file is written. Then, +% we read the toc file back, the $'s will be normal characters (as they +% should be, according to the definition of Texinfo). So we must use a +% control sequence to switch into and out of math mode. +% +% This isn't quite enough for @math to work properly in indices, but it +% seems unlikely it will ever be needed there. +% +\let\implicitmath = $ +\def\math#1{\implicitmath #1\implicitmath} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +\def\donoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\setref{\lastnode}\fi +\let\lastnode=\relax} + +\def\unnumbnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi +\let\lastnode=\relax} + +\def\appendixnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi +\let\lastnode=\relax} + +\let\refill=\relax + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \readauxfile + \opencontents + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + \comment % Ignore the actual filename. +} + +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{See Info file \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +\message{fonts,} + +% Font-change commands. + +% Texinfo supports the sans serif font style, which plain TeX does not. +% So we set up a \sf analogous to plain's \rm, etc. +\newfam\sffam +\def\sf{\fam=\sffam \tensf} +\let\li = \sf % Sometimes we call it \li, not \sf. + +%% Try out Computer Modern fonts at \magstephalf +\let\mainmagstep=\magstephalf + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\font\textrm=cmr12 +\font\texttt=cmtt12 +\else +\font\textrm=cmr10 scaled \mainmagstep +\font\texttt=cmtt10 scaled \mainmagstep +\fi +% Instead of cmb10, you many want to use cmbx10. +% cmbx10 is a prettier font on its own, but cmb10 +% looks better when embedded in a line with cmr10. +\font\textbf=cmb10 scaled \mainmagstep +\font\textit=cmti10 scaled \mainmagstep +\font\textsl=cmsl10 scaled \mainmagstep +\font\textsf=cmss10 scaled \mainmagstep +\font\textsc=cmcsc10 scaled \mainmagstep +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun, etc. +\font\defbf=cmbx10 scaled \magstep1 %was 1314 +\font\deftt=cmtt10 scaled \magstep1 +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} + +% Fonts for indices and small examples. +% We actually use the slanted font rather than the italic, +% because texinfo normally uses the slanted fonts for that. +% Do not make many font distinctions in general in the index, since they +% aren't very useful. +\font\ninett=cmtt9 +\font\indrm=cmr9 +\font\indit=cmsl9 +\let\indsl=\indit +\let\indtt=\ninett +\let\indsf=\indrm +\let\indbf=\indrm +\let\indsc=\indrm +\font\indi=cmmi9 +\font\indsy=cmsy9 + +% Fonts for headings +\font\chaprm=cmbx12 scaled \magstep2 +\font\chapit=cmti12 scaled \magstep2 +\font\chapsl=cmsl12 scaled \magstep2 +\font\chaptt=cmtt12 scaled \magstep2 +\font\chapsf=cmss12 scaled \magstep2 +\let\chapbf=\chaprm +\font\chapsc=cmcsc10 scaled\magstep3 +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +\font\secrm=cmbx12 scaled \magstep1 +\font\secit=cmti12 scaled \magstep1 +\font\secsl=cmsl12 scaled \magstep1 +\font\sectt=cmtt12 scaled \magstep1 +\font\secsf=cmss12 scaled \magstep1 +\font\secbf=cmbx12 scaled \magstep1 +\font\secsc=cmcsc10 scaled\magstep2 +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% \font\ssecrm=cmbx10 scaled \magstep1 % This size an font looked bad. +% \font\ssecit=cmti10 scaled \magstep1 % The letters were too crowded. +% \font\ssecsl=cmsl10 scaled \magstep1 +% \font\ssectt=cmtt10 scaled \magstep1 +% \font\ssecsf=cmss10 scaled \magstep1 + +%\font\ssecrm=cmb10 scaled 1315 % Note the use of cmb rather than cmbx. +%\font\ssecit=cmti10 scaled 1315 % Also, the size is a little larger than +%\font\ssecsl=cmsl10 scaled 1315 % being scaled magstep1. +%\font\ssectt=cmtt10 scaled 1315 +%\font\ssecsf=cmss10 scaled 1315 + +%\let\ssecbf=\ssecrm + +\font\ssecrm=cmbx12 scaled \magstephalf +\font\ssecit=cmti12 scaled \magstephalf +\font\ssecsl=cmsl12 scaled \magstephalf +\font\ssectt=cmtt12 scaled \magstephalf +\font\ssecsf=cmss12 scaled \magstephalf +\font\ssecbf=cmbx12 scaled \magstephalf +\font\ssecsc=cmcsc10 scaled \magstep1 +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled \magstep1 +% The smallcaps and symbol fonts should actually be scaled \magstep1.5, +% but that is not a standard magnification. + +% Fonts for title page: +\font\titlerm = cmbx12 scaled \magstep3 +\let\authorrm = \secrm + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts, we +% don't bother to reset \scriptfont and \scriptscriptfont (which would +% also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy + \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf + \textfont\ttfam = \tentt \textfont\sffam = \tensf +} + + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this so that font changes will continue to work +% in math mode, where it is the current \fam that is relevant in most +% cases, not the current. Plain TeX does, for example, +% \def\bf{\fam=\bffam \tenbf} By redefining \tenbf, we obviate the need +% to redefine \bf itself. +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy + \resetmathfonts} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy + \resetmathfonts} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy + \resetmathfonts} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy + \resetmathfonts} +\def\indexfonts{% + \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl + \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc + \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy + \resetmathfonts} + +% Set up the default fonts, so we can use them for creating boxes. +% +\textfonts + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\font\shortcontrm=cmr12 +\font\shortcontbf=cmbx12 +\font\shortcontsl=cmsl12 + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} +\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\var=\smartitalic +\let\dfn=\smartitalic +\let\emph=\smartitalic +\let\cite=\smartitalic + +\def\b#1{{\bf #1}} +\let\strong=\b + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +\def\t#1{% + {\tt \nohyphenation \rawbackslash \frenchspacing #1}% + \null +} +\let\ttfont = \t +%\def\samp #1{`{\tt \rawbackslash \frenchspacing #1}'\null} +\def\samp #1{`\tclose{#1}'\null} +\def\key #1{{\tt \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +\let\file=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in \code. +% Otherwise, it is too hard to avoid overful hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate an a dash. +% -- rms. +{ +\catcode `\-=\active +\catcode `\_=\active +\global\def\code{\begingroup \catcode `\-=\active \let-\codedash \let_\codeunder \codex} +} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{\normalunderscore\discretionary{}{}{}} +\def\codex #1{\tclose{#1}\endgroup} + +%\let\exp=\tclose %Was temporary + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else\tclose{\look}\fi +\else\tclose{\look}\fi} + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of +% @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +\def\l#1{{\li #1}\null} % + +\def\r#1{{\rm #1}} % roman font +% Use of \lowercase was suggested. +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\def\titlefont#1{{\titlerm #1}} + +\newif\ifseenauthor +\newif\iffinishedtitlepage + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm +% I deinstalled the following change because \cmr12 is undefined. +% This change was not in the ChangeLog anyway. --rms. +% \let\subtitlerm=\cmr12 + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefont{##1}} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \def\author{\parsearg\authorzzz}% + \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi + {\authorfont \leftline{##1}}}% + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% +% \def\page{\oldpage \hbox{}} +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + \HEADINGSon +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks \evenheadline % Token sequence for heading line of even pages +\newtoks \oddheadline % Token sequence for heading line of odd pages +\newtoks \evenfootline % Token sequence for footing line of even pages +\newtoks \oddfootline % Token sequence for footing line of odd pages + +% Now make Tex use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + +\def\evenheading{\parsearg\evenheadingxxx} +\def\oddheading{\parsearg\oddheadingxxx} +\def\everyheading{\parsearg\everyheadingxxx} + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\oddfooting{\parsearg\oddfootingxxx} +\def\everyfooting{\parsearg\everyfootingxxx} + +{\catcode`\@=0 % + +\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} +\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} +\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish} +\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}} +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} +\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} +\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% +\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish} +\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}} +\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} +% +}% unbind the catcode of @. + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{ +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{ +%\pagealignmacro +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{ +%\pagealignmacro +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} + +% Subroutines used in generating headings +% Produces Day Month Year style of output. +\def\today{\number\day\space +\ifcase\month\or +January\or February\or March\or April\or May\or June\or +July\or August\or September\or October\or November\or December\fi +\space\number\year} + +% Use this if you want the Month Day, Year style of output. +%\def\today{\ifcase\month\or +%January\or February\or March\or April\or May\or June\or +%July\or August\or September\or October\or November\or December\fi +%\space\number\day, \number\year} + +% @settitle line... specifies the title of the document, for headings +% It generates no output of its own + +\def\thistitle{No Title} +\def\settitle{\parsearg\settitlezzz} +\def\settitlezzz #1{\gdef\thistitle{#1}} + +\message{tables,} + +% @tabs -- simple alignment + +% These don't work. For one thing, \+ is defined as outer. +% So these macros cannot even be defined. + +%\def\tabs{\parsearg\tabszzz} +%\def\tabszzz #1{\settabs\+#1\cr} +%\def\tabline{\parsearg\tablinezzz} +%\def\tablinezzz #1{\+#1\cr} +%\def\&{&} + +% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\par \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \par \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\par \parsearg\kitemzzz} + +\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + +\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % Be sure we are not still in the middle of a paragraph. + {\parskip = 0in + \par + }% + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + \setbox0=\hbox{\hskip \leftskip \hskip -\tableindent \unhbox0}\box0 + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. + \nobreak + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. Since that + % text will be indented by \tableindent, we make the item text be in + % a zero-width box. + \noindent + \rlap{\hskip -\tableindent\box0}% + \fi + \endgroup +} + +\def\item{\errmessage{@item while not in a table}} +\def\itemx{\errmessage{@itemx while not in a table}} +\def\kitem{\errmessage{@kitem while not in a table}} +\def\kitemx{\errmessage{@kitemx while not in a table}} +\def\xitem{\errmessage{@xitem while not in a table}} +\def\xitemx{\errmessage{@xitemx while not in a table}} + +%% Contains a kludge to get @end[description] to work +\def\description{\tablez{\dontindex}{1}{}{}{}{}} + +\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} +{\obeylines\obeyspaces% +\gdef\tablex #1^^M{% +\tabley\dontindex#1 \endtabley}} + +\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} +{\obeylines\obeyspaces% +\gdef\ftablex #1^^M{% +\tabley\fnitemindex#1 \endtabley +\def\Eftable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} +{\obeylines\obeyspaces% +\gdef\vtablex #1^^M{% +\tabley\vritemindex#1 \endtabley +\def\Evtable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\code{#1}}}% + +{\obeyspaces % +\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% +\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\tablez #1#2#3#4#5#6{% +\aboveenvbreak % +\begingroup % +\def\Edescription{\Etable}% Neccessary kludge. +\let\itemindex=#1% +\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % +\ifnum 0#4>0 \tableindent=#4\mil \fi % +\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % +\def\itemfont{#2}% +\itemmax=\tableindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \tableindent % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\afterenvbreak\endgroup}% +\let\item = \internalBitem % +\let\itemx = \internalBitemx % +\let\kitem = \internalBkitem % +\let\kitemx = \internalBkitemx % +\let\xitem = \internalBxitem % +\let\xitemx = \internalBxitemx % +} + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\def\itemize{\parsearg\itemizezzz} + +\def\itemizezzz #1{% + \begingroup % ended by the @end itemsize + \itemizey {#1}{\Eitemize} +} + +\def\itemizey #1#2{% +\aboveenvbreak % +\itemmax=\itemindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \itemindent % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\afterenvbreak\endgroup}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% Set sfcode to normal for the chars that usually have another value. +% These are `.?!:;,' +\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\def\enumerate{\parsearg\enumeratezzz} +\def\enumeratezzz #1{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a <number>. + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call itemizey, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \itemizey{#1.}\Eenumerate\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + +% Definition of @item while inside @itemize. + +\def\itemizeitem{% +\advance\itemno by 1 +{\let\par=\endgraf \smallbreak}% +\ifhmode \errmessage{\in hmode at itemizeitem}\fi +{\parskip=0in \hskip 0pt +\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% +\vadjust{\penalty 1200}}% +\flushcr} + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within \newindex. +{\catcode`\@=11 +\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. + +\def\newindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#1}} +} + +% @defindex foo == \newindex{foo} + +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. + +\def\newcodeindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#1}} +} + +\def\defcodeindex{\parsearg\newcodeindex} + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +\def\synindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#2}}% +} + +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +\def\syncodeindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#2}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +\def\indexdummies{% +\def\_{{\realbackslash _}}% +\def\w{\realbackslash w }% +\def\bf{\realbackslash bf }% +\def\rm{\realbackslash rm }% +\def\sl{\realbackslash sl }% +\def\sf{\realbackslash sf}% +\def\tt{\realbackslash tt}% +\def\gtr{\realbackslash gtr}% +\def\less{\realbackslash less}% +\def\hat{\realbackslash hat}% +\def\char{\realbackslash char}% +\def\TeX{\realbackslash TeX}% +\def\dots{\realbackslash dots }% +\def\copyright{\realbackslash copyright }% +\def\tclose##1{\realbackslash tclose {##1}}% +\def\code##1{\realbackslash code {##1}}% +\def\samp##1{\realbackslash samp {##1}}% +\def\t##1{\realbackslash r {##1}}% +\def\r##1{\realbackslash r {##1}}% +\def\i##1{\realbackslash i {##1}}% +\def\b##1{\realbackslash b {##1}}% +\def\cite##1{\realbackslash cite {##1}}% +\def\key##1{\realbackslash key {##1}}% +\def\file##1{\realbackslash file {##1}}% +\def\var##1{\realbackslash var {##1}}% +\def\kbd##1{\realbackslash kbd {##1}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##1}}% +} + +% \indexnofonts no-ops all font-change commands. +% This is used when outputting the strings to sort the index by. +\def\indexdummyfont#1{#1} +\def\indexdummytex{TeX} +\def\indexdummydots{...} + +\def\indexnofonts{% +\let\w=\indexdummyfont +\let\t=\indexdummyfont +\let\r=\indexdummyfont +\let\i=\indexdummyfont +\let\b=\indexdummyfont +\let\emph=\indexdummyfont +\let\strong=\indexdummyfont +\let\cite=\indexdummyfont +\let\sc=\indexdummyfont +%Don't no-op \tt, since it isn't a user-level command +% and is used in the definitions of the active chars like <, >, |... +%\let\tt=\indexdummyfont +\let\tclose=\indexdummyfont +\let\code=\indexdummyfont +\let\file=\indexdummyfont +\let\samp=\indexdummyfont +\let\kbd=\indexdummyfont +\let\key=\indexdummyfont +\let\var=\indexdummyfont +\let\TeX=\indexdummytex +\let\dots=\indexdummydots +} + +% To define \realbackslash, we must make \ not be an escape. +% We must first make another character (@) an escape +% so we do not become unable to do a definition. + +{\catcode`\@=0 \catcode`\\=\other +@gdef@realbackslash{\}} + +\let\indexbackslash=0 %overridden during \printindex. + +\def\doind #1#2{% +{\count10=\lastpenalty % +{\indexdummies % Must do this here, since \bf, etc expand at this stage +\escapechar=`\\% +{\let\folio=0% Expand all macros now EXCEPT \folio +\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now +% so it will be output as is; and it will print as backslash in the indx. +% +% Now process the index-string once, with all font commands turned off, +% to get the string to sort the index by. +{\indexnofonts +\xdef\temp1{#2}% +}% +% Now produce the complete index entry. We process the index-string again, +% this time with font commands expanded, to get what to print in the index. +\edef\temp{% +\write \csname#1indfile\endcsname{% +\realbackslash entry {\temp1}{\folio}{#2}}}% +\temp }% +}\penalty\count10}} + +\def\dosubind #1#2#3{% +{\count10=\lastpenalty % +{\indexdummies % Must do this here, since \bf, etc expand at this stage +\escapechar=`\\% +{\let\folio=0% +\def\rawbackslashxx{\indexbackslash}% +% +% Now process the index-string once, with all font commands turned off, +% to get the string to sort the index by. +{\indexnofonts +\xdef\temp1{#2 #3}% +}% +% Now produce the complete index entry. We process the index-string again, +% this time with font commands expanded, to get what to print in the index. +\edef\temp{% +\write \csname#1indfile\endcsname{% +\realbackslash entry {\temp1}{\folio}{#2}{#3}}}% +\temp }% +}\penalty\count10}} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% This is what you call to cause a particular index to get printed. +% Write +% @unnumbered Function Index +% @printindex fn + +\def\printindex{\parsearg\doprintindex} + +\def\doprintindex#1{% + \tex + \dobreak \chapheadingskip {10000} + \catcode`\%=\other\catcode`\&=\other\catcode`\#=\other + \catcode`\$=\other\catcode`\_=\other + \catcode`\~=\other + % + % The following don't help, since the chars were translated + % when the raw index was written, and their fonts were discarded + % due to \indexnofonts. + %\catcode`\"=\active + %\catcode`\^=\active + %\catcode`\_=\active + %\catcode`\|=\active + %\catcode`\<=\active + %\catcode`\>=\active + % % + \def\indexbackslash{\rawbackslashxx} + \indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt + \begindoublecolumns + % + % See if the index file exists and is nonempty. + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + (Index is nonexistent) + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + (Index is empty) + \else + \input \jobname.#1s + \fi + \fi + \closein 1 + \enddoublecolumns + \Etex +} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +% Same as \bigskipamount except no shrink. +% \balancecolumns gets confused if there is any shrink. +\newskip\initialskipamount \initialskipamount 12pt plus4pt + +\def\initial #1{% +{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt +\ifdim\lastskip<\initialskipamount +\removelastskip \penalty-200 \vskip \initialskipamount\fi +\line{\secbf#1\hfill}\kern 2pt\penalty10000}} + +% This typesets a paragraph consisting of #1, dot leaders, and then #2 +% flush to the right margin. It is used for index and table of contents +% entries. The paragraph is indented by \leftskip. +% +\def\entry #1#2{\begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent=2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % Insert the text of the index entry. TeX will do line-breaking on it. + #1% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ #2% The page number ends the paragraph. + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu . \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm + +\def\secondary #1#2{ +{\parfillskip=0in \parskip=0in +\hangindent =1in \hangafter=1 +\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par +}} + +%% Define two-column mode, which is used in indexes. +%% Adapted from the TeXbook, page 416. +\catcode `\@=11 + +\newbox\partialpage + +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup + % Grab any single-column material above us. + \output = {\global\setbox\partialpage + =\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}% + \eject + % + % Now switch to the double-column output routine. + \output={\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it once. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +- < + % 1pt) as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \vsize = 2\vsize + \doublecolumnpagegoal +} + +\def\enddoublecolumns{\eject \endgroup \pagegoal=\vsize \unvbox\partialpage} + +\def\doublecolumnsplit{\splittopskip=\topskip \splitmaxdepth=\maxdepth + \global\dimen@=\pageheight \global\advance\dimen@ by-\ht\partialpage + \global\setbox1=\vsplit255 to\dimen@ \global\setbox0=\vbox{\unvbox1} + \global\setbox3=\vsplit255 to\dimen@ \global\setbox2=\vbox{\unvbox3} + \ifdim\ht0>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi + \ifdim\ht2>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi +} +\def\doublecolumnpagegoal{% + \dimen@=\vsize \advance\dimen@ by-2\ht\partialpage \global\pagegoal=\dimen@ +} +\def\pagesofar{\unvbox\partialpage % + \hsize=\doublecolumnhsize % have to restore this since output routine + \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}} +\def\doublecolumnout{% + \setbox5=\copy255 + {\vbadness=10000 \doublecolumnsplit} + \ifvbox255 + \setbox0=\vtop to\dimen@{\unvbox0} + \setbox2=\vtop to\dimen@{\unvbox2} + \onepageout\pagesofar \unvbox255 \penalty\outputpenalty + \else + \setbox0=\vbox{\unvbox5} + \ifvbox0 + \dimen@=\ht0 \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip + \divide\dimen@ by2 \splittopskip=\topskip \splitmaxdepth=\maxdepth + {\vbadness=10000 + \loop \global\setbox5=\copy0 + \setbox1=\vsplit5 to\dimen@ + \setbox3=\vsplit5 to\dimen@ + \ifvbox5 \global\advance\dimen@ by1pt \repeat + \setbox0=\vbox to\dimen@{\unvbox1} + \setbox2=\vbox to\dimen@{\unvbox3} + \global\setbox\partialpage=\vbox{\pagesofar} + \doublecolumnpagegoal + } + \fi + \fi +} + +\catcode `\@=\other +\message{sectioning,} +% Define chapters, sections, etc. + +\newcount \chapno +\newcount \secno \secno=0 +\newcount \subsecno \subsecno=0 +\newcount \subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount \appendixno \appendixno = `\@ +\def\appendixletter{\char\the\appendixno} + +\newwrite \contentsfile +% This is called from \setfilename. +\def\opencontents{\openout \contentsfile = \jobname.toc} + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise + +\def\thischapter{} \def\thissection{} +\def\seccheck#1{\if \pageno<0 % +\errmessage{@#1 not allowed after generating table of contents}\fi +% +} + +\def\chapternofonts{% +\let\rawbackslash=\relax% +\let\frenchspacing=\relax% +\def\result{\realbackslash result} +\def\equiv{\realbackslash equiv} +\def\expansion{\realbackslash expansion} +\def\print{\realbackslash print} +\def\TeX{\realbackslash TeX} +\def\dots{\realbackslash dots} +\def\copyright{\realbackslash copyright} +\def\tt{\realbackslash tt} +\def\bf{\realbackslash bf } +\def\w{\realbackslash w} +\def\less{\realbackslash less} +\def\gtr{\realbackslash gtr} +\def\hat{\realbackslash hat} +\def\char{\realbackslash char} +\def\tclose##1{\realbackslash tclose {##1}} +\def\code##1{\realbackslash code {##1}} +\def\samp##1{\realbackslash samp {##1}} +\def\r##1{\realbackslash r {##1}} +\def\b##1{\realbackslash b {##1}} +\def\key##1{\realbackslash key {##1}} +\def\file##1{\realbackslash file {##1}} +\def\kbd##1{\realbackslash kbd {##1}} +% These are redefined because @smartitalic wouldn't work inside xdef. +\def\i##1{\realbackslash i {##1}} +\def\cite##1{\realbackslash cite {##1}} +\def\var##1{\realbackslash var {##1}} +\def\emph##1{\realbackslash emph {##1}} +\def\dfn##1{\realbackslash dfn {##1}} +} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + + +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz #1{\seccheck{chapter}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \chapno by 1 \message{Chapter \the\chapno}% +\chapmacro {#1}{\the\chapno}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +% We don't substitute the actual chapter name into \thischapter +% because we don't want its macros evaluated now. +\xdef\thischapter{Chapter \the\chapno: \noexpand\thischaptername}% +{\chapternofonts% +\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec +}} + +\outer\def\appendix{\parsearg\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{\seccheck{appendix}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 \message{Appendix \appendixletter}% +\chapmacro {#1}{Appendix \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{Appendix \appendixletter: \noexpand\thischaptername}% +{\chapternofonts% +\edef\temp{{\realbackslash chapentry + {#1}{Appendix \appendixletter}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +}} + +\outer\def\top{\parsearg\unnumberedyyy} +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{\seccheck{unnumbered}% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% argument to \message. Therefore, if #1 contained @-commands, TeX +% expanded them. For example, in `@unnumbered The @cite{Book}', TeX +% expanded @cite (which turns out to cause errors because \cite is meant +% to be executed, not expanded). +% +% Anyway, we don't want the fully-expanded definition of @cite to appear +% as a result of the \message, we just want `@cite' itself. We use +% \the<toks register> to achieve this: TeX expands \the<toks> only once, +% simply yielding the contents of the <toks register>. +\toks0 = {#1}\message{(\the\toks0)}% +% +\unnumbchapmacro {#1}% +\gdef\thischapter{#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\global\let\section = \unnumberedsec +\global\let\subsection = \unnumberedsubsec +\global\let\subsubsection = \unnumberedsubsubsec +}} + +\outer\def\numberedsec{\parsearg\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls seczzz +\def\seczzz #1{\seccheck{section}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% +{\chapternofonts% +\edef\temp{{\realbackslash secentry % +{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appenixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz #1{\seccheck{appendixsection}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% +{\chapternofonts% +\edef\temp{{\realbackslash secentry % +{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz #1{\seccheck{unnumberedsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz #1{\seccheck{subsection}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsecentry % +{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz #1{\seccheck{appendixsubsec}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsecentry % +{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz #1{\seccheck{subsubsection}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsubsecentry % + {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno} + {\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsubsecentry{#1}% + {\appendixletter} + {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +% These are variants which are not "outer", so they can appear in @ifinfo. +% Actually, they should now be obsolete; ordinary section commands should work. +\def\infotop{\parsearg\unnumberedzzz} +\def\infounnumbered{\parsearg\unnumberedzzz} +\def\infounnumberedsec{\parsearg\unnumberedseczzz} +\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} +\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + +\def\infoappendix{\parsearg\appendixzzz} +\def\infoappendixsec{\parsearg\appendixseczzz} +\def\infoappendixsubsec{\parsearg\appendixsubseczzz} +\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + +\def\infochapter{\parsearg\chapterzzz} +\def\infosection{\parsearg\sectionzzz} +\def\infosubsection{\parsearg\subsectionzzz} +\def\infosubsubsection{\parsearg\subsubsectionzzz} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and +% such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{\parsearg\majorheadingzzz} +\def\majorheadingzzz #1{% +{\advance\chapheadingskip by 10pt \chapbreak }% +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\chapheading{\parsearg\chapheadingzzz} +\def\chapheadingzzz #1{\chapbreak % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\heading{\parsearg\secheadingi} + +\def\subheading{\parsearg\subsecheadingi} + +\def\subsubheading{\parsearg\subsubsecheadingi} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{ +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{ +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{ +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +\def\CHAPFplain{ +\global\let\chapmacro=\chfplain +\global\let\unnumbchapmacro=\unnchfplain} + +\def\chfplain #1#2{% + \pchapsepmacro + {% + \chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #2\enspace #1}% + }% + \bigskip + \penalty5000 +} + +\def\unnchfplain #1{% +\pchapsepmacro % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 10000 % +} +\CHAPFplain % The default + +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 10000 % +} + +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} + +\def\CHAPFopen{ +\global\let\chapmacro=\chfopen +\global\let\unnumbchapmacro=\unnchfopen} + +% Parameter controlling skip before section headings. + +\newskip \subsecheadingskip \subsecheadingskip = 17pt plus 8pt minus 4pt +\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} + +\newskip \secheadingskip \secheadingskip = 21pt plus 8pt minus 4pt +\def\secheadingbreak{\dobreak \secheadingskip {-1000}} + +% @paragraphindent is defined for the Info formatting commands only. +\let\paragraphindent=\comment + +% Section fonts are the base font at magstep2, which produces +% a size a bit more than 14 points in the default situation. + +\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}} +\def\plainsecheading #1{\secheadingi {#1}} +\def\secheadingi #1{{\advance \secheadingskip by \parskip % +\secheadingbreak}% +{\secfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% +\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 } + + +% Subsection fonts are the base font at magstep1, +% which produces a size of 12 points. + +\def\subsecheading #1#2#3#4{\subsecheadingi {#2.#3.#4\enspace #1}} +\def\subsecheadingi #1{{\advance \subsecheadingskip by \parskip % +\subsecheadingbreak}% +{\subsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% +\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 } + +\def\subsubsecfonts{\subsecfonts} % Maybe this should change: + % Perhaps make sssec fonts scaled + % magstep half +\def\subsubsecheading #1#2#3#4#5{\subsubsecheadingi {#2.#3.#4.#5\enspace #1}} +\def\subsubsecheadingi #1{{\advance \subsecheadingskip by \parskip % +\subsecheadingbreak}% +{\subsubsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% +\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000} + + +\message{toc printing,} + +% Finish up the main text and prepare to read what we've written +% to \contentsfile. + +\newskip\contentsrightmargin \contentsrightmargin=1in +\def\startcontents#1{% + \pagealignmacro + \immediate\closeout \contentsfile + \ifnum \pageno>0 + \pageno = -1 % Request roman numbered pages. + \fi + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \unnumbchapmacro{#1}\def\thischapter{}% + \begingroup % Set up to handle contents files properly. + \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. +} + + +% Normal (long) toc. +\outer\def\contents{% + \startcontents{Table of Contents}% + \input \jobname.toc + \endgroup + \vfill \eject +} + +% And just the chapters. +\outer\def\summarycontents{% + \startcontents{Short Contents}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \input \jobname.toc + \endgroup + \vfill \eject +} +\let\shortcontents = \summarycontents + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapter-level things, for both the long and short contents. +\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + +% See comments in \dochapentry re vbox and related settings +\def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% We could simplify the code here by writing out an \appendixentry +% command in the toc file for appendices, instead of using \chapentry +% for both, but it doesn't seem worth it. +\setbox0 = \hbox{\shortcontrm Appendix } +\newdimen\shortappendixwidth \shortappendixwidth = \wd0 + +\def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in in \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}} + +% Sections. +\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} +\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + +% Subsections. +\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} +\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + +% And subsubsections. +\def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} +\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + + +% This parameter controls the indentation of the various levels. +\newdimen\tocindent \tocindent = 3pc + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we would want to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno{#2}}% + \endgroup + \nobreak\vskip .25\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% the index entries, but we want to suppress hyphenation here. (We +% can't do that in the \entry macro, since index entries might consist +% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) +% +\def\tocentry#1#2{\begingroup + \hyphenpenalty = 10000 + \entry{#1}{#2}% +\endgroup} + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\let\subsecentryfonts = \textfonts +\let\subsubsecentryfonts = \textfonts + + +\message{environments,} + +% Since these characters are used in examples, it should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% Furthermore, these definitions must come after we define our fonts. +\newbox\dblarrowbox \newbox\longdblarrowbox +\newbox\pushcharbox \newbox\bullbox +\newbox\equivbox \newbox\errorbox + +\let\ptexequiv = \equiv + +%{\tentt +%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} +%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} +%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} +%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} +% Adapted from the manmac format (p.420 of TeXbook) +%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex +% depth .1ex\hfil} +%} + +\def\point{$\star$} + +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} + +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% Adapted from the TeXbook's \boxit. +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + +\global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + +% The @error{} command. +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\def\tex{\begingroup +\catcode `\\=0 \catcode `\{=1 \catcode `\}=2 +\catcode `\$=3 \catcode `\&=4 \catcode `\#=6 +\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie +\catcode `\%=14 +\catcode 43=12 +\catcode`\"=12 +\catcode`\==12 +\catcode`\|=12 +\catcode`\<=12 +\catcode`\>=12 +\escapechar=`\\ +% +\let\{=\ptexlbrace +\let\}=\ptexrbrace +\let\.=\ptexdot +\let\*=\ptexstar +\let\dots=\ptexdots +\def\@{@}% +\let\bullet=\ptexbullet +\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl +\let\L=\ptexL +% +\let\Etex=\endgroup} + +% Define @lisp ... @endlisp. +% @lisp does a \begingroup so it can rebind things, +% including the definition of @endlisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% Make each space character in the input produce a normal interword +% space in the output. Don't allow a line break at this space, as this +% is used only in environments like @example, where each line of input +% should produce a line of output anyway. +% +{\obeyspaces % +\gdef\sepspaces{\obeyspaces\let =\tie}} + +% Define \obeyedspace to be our active space, whatever it is. This is +% for use in \parsearg. +{\sepspaces % +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip +% +\def\aboveenvbreak{{\advance\envskipamount by \parskip +\endgraf \ifdim\lastskip<\envskipamount +\removelastskip \penalty-50 \vskip\envskipamount \fi}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. +\let\nonarrowing=\relax + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% \cartouche: draw rectangle w/rounded corners around argument +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\long\def\cartouche{% +\begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18pt % allow for 3pt kerns on either +% side, and for 6pt waste from +% each corner char + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip +\def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup +\endgroup +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \inENV % This group ends at the end of the body + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \singlespace + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +% To ending an @example-like environment, we first end the paragraph +% (via \afterenvbreak's vertical glue), and then the group. That way we +% keep the zero \parskip that the environments set -- \parskip glue +% will be inserted at the beginning of the next paragraph in the +% document, after the environment. +% +\def\nonfillfinish{\afterenvbreak\endgroup}% + +% This macro is +\def\lisp{\begingroup + \nonfillstart + \let\Elisp = \nonfillfinish + \tt + \rawbackslash % have \ input char produce \ char from current font + \gobble +} + +% Define the \E... control sequence only if we are inside the +% environment, so the error checking in \end will work. +% +% We must call \lisp last in the definition, since it reads the +% return following the @example (or whatever) command. +% +\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} +\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + +% @smallexample and @smalllisp. This is not used unless the @smallbook +% command is given. Originally contributed by Pavel@xerox. +% +\def\smalllispx{\begingroup + \nonfillstart + \let\Esmalllisp = \nonfillfinish + \let\Esmallexample = \nonfillfinish + % + % Smaller interline space and fonts for small examples. + \baselineskip 10pt + \indexfonts \tt + \rawbackslash % output the \ character from the current font + \gobble +} + +% This is @display; same as @lisp except use roman font. +% +\def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble +} + +% This is @format; same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble +} + +% @flushleft (same as @format) and @flushright. +% +\def\flushleft{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushleft = \nonfillfinish + \gobble +} +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble} + +% @quotation does normal linebreaking and narrows the margins. +% +\def\quotation{% +\begingroup\inENV %This group ends at the end of the @quotation body +{\parskip=0pt % because we will skip by \parskip too, later +\aboveenvbreak}% +\singlespace +\parindent=0pt +\let\Equotation = \nonfillfinish +% @cartouche defines \nonarrowing to inhibit narrowing +% at next level down. +\ifx\nonarrowing\relax +\advance \leftskip by \lispnarrowing +\advance \rightskip by \lispnarrowing +\exdentamount=\lispnarrowing +\let\nonarrowing=\relax +\fi} + +\message{defuns,} +% Define formatter for defuns +% First, allow user to change definition object font (\df) internally +\def\setdeffont #1 {\csname DEF#1\endcsname} + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deftypemargin \deftypemargin=12pt +\newskip\deflastargmargin \deflastargmargin=18pt + +\newcount\parencount +% define \functionparens, which makes ( and ) and & do special things. +% \functionparens affects the group it is contained in. +\def\activeparens{% +\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active +\catcode`\[=\active \catcode`\]=\active} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } +\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} + +% Definitions of (, ) and & used in args for functions. +% This is the definition of ( outside of all parentheses. +\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested % +\global\advance\parencount by 1 } +% +% This is the definition of ( when already inside a level of parens. +\gdef\opnested{\char`\(\global\advance\parencount by 1 } +% +\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. +% also in that case restore the outer-level definition of (. +\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi +\global\advance \parencount by -1 } +% If we encounter &foo, then turn on ()-hacking afterwards +\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } +% +\gdef\normalparens{\boldbrax\let&=\ampnr} +} % End of definition inside \activeparens +%% These parens (in \boldbrax) actually are a little bolder than the +%% contained text. This is especially needed for [ and ] +\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&} +\def\lbrb{{\bf\char`\[}} \def\rbrb{{\bf\char`\]}} + +% First, defname, which formats the header line itself. +% #1 should be the function name. +% #2 should be the type of definition, such as "Function". + +\def\defname #1#2{% +% Get the values of \leftskip and \rightskip as they were +% outside the @def... +\dimen2=\leftskip +\advance\dimen2 by -\defbodyindent +\dimen3=\rightskip +\advance\dimen3 by -\defbodyindent +\noindent % +\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% +\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line +\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations +\parshape 2 0in \dimen0 \defargsindent \dimen1 % +% Now output arg 2 ("Function" or some such) +% ending at \deftypemargin from the right margin, +% but stuck inside a box of width 0 so it does not interfere with linebreaking +{% Adjust \hsize to exclude the ambient margins, +% so that \rightline will obey them. +\advance \hsize by -\dimen2 \advance \hsize by -\dimen3 +\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}% +% Make all lines underfull and no complaints: +\tolerance=10000 \hbadness=10000 +\advance\leftskip by -\defbodyindent +\exdentamount=\defbodyindent +{\df #1}\enskip % Generate function name +} + +% Actually process the body of a definition +% #1 should be the terminating control sequence, such as \Edefun. +% #2 should be the "another name" control sequence, such as \defunx. +% #3 should be the control sequence that actually processes the header, +% such as \defunheader. + +\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\activeparens\spacesplit#3} + +\def\defmethparsebody #1#2#3#4 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + +\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + +% These parsing functions are similar to the preceding ones +% except that they do not make parens into active characters. +% These are used for "variables" since they have no arguments. + +\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\spacesplit#3} + +\def\defvrparsebody #1#2#3#4 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#4}}} + +% This seems to work right in all cases. +\let\deftpparsebody=\defvrparsebody +% This fails to work. When given `@deftp {Data Type} foo_t', +% it thinks the type name is just `f'. +%%% This is the same as all the others except for the last line. We need +%%% to parse the arguments differently for @deftp, since the ``attributes'' +%%% there are optional. +%%% +%%\def\deftpparsebody #1#2#3#4 {\begingroup\inENV % +%%\medbreak % +%%% Define the end token that this defining construct specifies +%%% so that it will exit this group. +%%\def#1{\endgraf\endgroup\medbreak}% +%%\def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% +%%\parindent=0in +%%\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +%%\exdentamount=\defbodyindent +%%\begingroup\obeylines\parsetpheaderline{#3{#4}}} + +%%{\obeylines % +%% % Parse the type name and any attributes (field names, etc.). +%% % #1 is the beginning of the macro call that will produce the output, +%% % i.e., \deftpheader{CLASS}; this is passed from \deftpparsebody. +%% % #2 is the type name, e.g., `struct termios'. +%% % #3 is the (possibly empty) attribute list. +%% % +%% \gdef\parsetpheaderline#1#2#3^^M{% +%% \endgroup % Started in \deftpparsebody. +%% % +%% % If the attribute list is in fact empty, there will be no space after +%% % #2; so we can't put a space in our TeX parameter list. But if it +%% % isn't empty, then #3 will begin with an unwanted space. +%% \def\theargs{\ignorespaces #3}% +%% % +%% % Call the macro to produce the output. +%% #1{#2}\theargs % +%% }% +%%} + +\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#5}}} + +% Split up #2 at the first space token. +% call #1 with two arguments: +% the first is all of #2 before the space token, +% the second is all of #2 after that space token. +% If #2 contains no space token, all of it is passed as the first arg +% and the second is passed as empty. + +{\obeylines +\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% +\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% +\ifx\relax #3% +#1{#2}{}\else #1{#2}{#3#4}\fi}} + +% So much for the things common to all kinds of definitions. + +% Define @defun. + +% First, define the processing that is wanted for arguments of \defun +% Use this to expand the args and terminate the paragraph they make up + +\def\defunargs #1{\functionparens \sl +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\hyphenchar\tensl=0 +#1% +\hyphenchar\tensl=45 +\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +\def\deftypefunargs #1{% +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\functionparens +\code{#1}% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +% Do complete processing of one @defun or @defunx line already parsed. + +% @deffn Command forward-char nchars + +\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + +\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% +\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defun == @deffn Function + +\def\defun{\defparsebody\Edefun\defunx\defunheader} + +\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Function}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefun int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + +% #1 is the data type. #2 is the name and args. +\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} +% #1 is the data type, #2 the name, #3 the args. +\def\deftypefunheaderx #1#2 #3\relax{% +\doind {fn}{\code{#2}}% Make entry in function index +\begingroup\defname {\code{#1} #2}{Function}% +\deftypefunargs {#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + +% #1 is the classification. #2 is the data type. #3 is the name and args. +\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} +% #1 is the classification, #2 the data type, #3 the name, #4 the args. +\def\deftypefnheaderx #1#2#3 #4\relax{% +\doind {fn}{\code{#3}}% Make entry in function index +\begingroup\defname {\code{#2} #3}{#1}% +\deftypefunargs {#4}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defmac == @deffn Macro + +\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + +\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Macro}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defspec == @deffn Special Form + +\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + +\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Special Form}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% This definition is run if you use @defunx +% anywhere other than immediately after a @defun or @defunx. + +\def\deffnx #1 {\errmessage{@deffnx in invalid context}} +\def\defunx #1 {\errmessage{@defunx in invalid context}} +\def\defmacx #1 {\errmessage{@defmacx in invalid context}} +\def\defspecx #1 {\errmessage{@defspecx in invalid context}} +\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}} +\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}} + +% @defmethod, and so on + +% @defop {Funny Method} foo-class frobnicate argument + +\def\defop #1 {\def\defoptype{#1}% +\defopparsebody\Edefop\defopx\defopheader\defoptype} + +\def\defopheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index +\begingroup\defname {#2}{\defoptype{} on #1}% +\defunargs {#3}\endgroup % +} + +% @defmethod == @defop Method + +\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} + +\def\defmethodheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% entry in function index +\begingroup\defname {#2}{Method on #1}% +\defunargs {#3}\endgroup % +} + +% @defcv {Class Option} foo-class foo-flag + +\def\defcv #1 {\def\defcvtype{#1}% +\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + +\def\defcvarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{\defcvtype{} of #1}% +\defvarargs {#3}\endgroup % +} + +% @defivar == @defcv {Instance Variable} + +\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} + +\def\defivarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{Instance Variable of #1}% +\defvarargs {#3}\endgroup % +} + +% These definitions are run if you use @defmethodx, etc., +% anywhere other than immediately after a @defmethod, etc. + +\def\defopx #1 {\errmessage{@defopx in invalid context}} +\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}} +\def\defcvx #1 {\errmessage{@defcvx in invalid context}} +\def\defivarx #1 {\errmessage{@defivarx in invalid context}} + +% Now @defvar + +% First, define the processing that is wanted for arguments of @defvar. +% This is actually simple: just print them in roman. +% This must expand the args and terminate the paragraph they make up +\def\defvarargs #1{\normalparens #1% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000} + +% @defvr Counter foo-count + +\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + +\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% +\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + +% @defvar == @defvr Variable + +\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + +\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{Variable}% +\defvarargs {#2}\endgroup % +} + +% @defopt == @defvr {User Option} + +\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + +\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{User Option}% +\defvarargs {#2}\endgroup % +} + +% @deftypevar int foobar + +\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + +% #1 is the data type. #2 is the name. +\def\deftypevarheader #1#2{% +\doind {vr}{\code{#2}}% Make entry in variables index +\begingroup\defname {\code{#1} #2}{Variable}% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% @deftypevr {Global Flag} int enable + +\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + +\def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}% +\begingroup\defname {\code{#2} #3}{#1} +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% This definition is run if you use @defvarx +% anywhere other than immediately after a @defvar or @defvarx. + +\def\defvrx #1 {\errmessage{@defvrx in invalid context}} +\def\defvarx #1 {\errmessage{@defvarx in invalid context}} +\def\defoptx #1 {\errmessage{@defoptx in invalid context}} +\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}} +\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}} + +% Now define @deftp +% Args are printed in bold, a slight difference from @defvar. + +\def\deftpargs #1{\bf \defvarargs{#1}} + +% @deftp Class window height width ... + +\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + +\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% +\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + +% This definition is run if you use @deftpx, etc +% anywhere other than immediately after a @deftp, etc. + +\def\deftpx #1 {\errmessage{@deftpx in invalid context}} + +\message{cross reference,} +% Define cross-reference macros +\newwrite \auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% \setref{foo} defines a cross-reference point named foo. + +\def\setref#1{% +%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ysectionnumberandtype}} + +\def\unnumbsetref#1{% +%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ynothing}} + +\def\appendixsetref#1{% +%\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Yappendixletterandtype}} + +% \xref, \pxref, and \ref generate cross-references to specified points. +% For \xrefX, #1 is the node name, #2 the name of the Info +% cross-reference, #3 the printed node name, #4 the name of the Info +% file, #5 the name of the printed manual. All but the node name can be +% omitted. +% +\def\pxref#1{see \xrefX[#1,,,,,,,]} +\def\xref#1{See \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup% +\def\printedmanual{\ignorespaces #5}% +\def\printednodename{\ignorespaces #3}% +% +\setbox1=\hbox{\printedmanual}% +\setbox0=\hbox{\printednodename}% +\ifdim \wd0=0pt% +\def\printednodename{\ignorespaces #1}% +%%% Uncommment the following line to make the actual chapter or section title +%%% appear inside the square brackets. +%\def\printednodename{#1-title}% +\fi% +% +% +% If we use \unhbox0 and \unhbox1 to print the node names, TeX does +% not insert empty discretionaries after hyphens, which means that it +% will not find a line break at a hyphen in a node names. Since some +% manuals are best written with fairly long node names, containing +% hyphens, this is a loss. Therefore, we simply give the text of +% the node name again, so it is as if TeX is seeing it for the first +% time. +\ifdim \wd1>0pt +section ``\printednodename'' in \cite{\printedmanual}% +\else% +\turnoffactive% +\refx{#1-snt}{} [\printednodename], page\tie\refx{#1-pg}{}% +\fi +\endgroup} + +% \dosetq is the interface for calls from other macros + +% Use \turnoffactive so that punctuation chars such as underscore +% work in node names. +\def\dosetq #1#2{{\let\folio=0 \turnoffactive% +\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}% +\next}} + +% \internalsetq {foo}{page} expands into +% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} +% When the aux file is read, ' is the escape character + +\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + +% Things to be expanded by \internalsetq + +\def\Ypagenumber{\folio} + +\def\Ytitle{\thischapter} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 Chapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 Section\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +Section\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +Section\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\def\Yappendixletterandtype{% +\ifnum\secno=0 Appendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 Section\xreftie'char\the\appendixno.\the\secno % +\else \ifnum \subsubsecno=0 % +Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\gdef\xreftie{'tie} + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Non-3.0. +\else + \def\linenumber{\the\inputlineno:\space} +\fi + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. + +\def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + $\langle$un\-de\-fined$\rangle$% + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. +} + +% Read the last existing aux file, if any. No error if none exists. + +% This is the macro invoked by entries in the aux file. +\def\xrdef #1#2{ +{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}} + +\def\readauxfile{% +\begingroup +\catcode `\^^@=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\^^C=\other +\catcode `\^^D=\other +\catcode `\^^E=\other +\catcode `\^^F=\other +\catcode `\^^G=\other +\catcode `\^^H=\other +\catcode `\=\other +\catcode `\^^L=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode 26=\other +\catcode `\^^[=\other +\catcode `\^^\=\other +\catcode `\^^]=\other +\catcode `\^^^=\other +\catcode `\^^_=\other +\catcode `\@=\other +\catcode `\^=\other +\catcode `\~=\other +\catcode `\[=\other +\catcode `\]=\other +\catcode`\"=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode `\$=\other +\catcode `\#=\other +\catcode `\&=\other +% `\+ does not work, so use 43. +\catcode 43=\other +% the aux file uses ' as the escape. +% Turn off \ as an escape so we do not lose on +% entries which were dumped with control sequences in their names. +% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ +% Reference to such entries still does not work the way one would wish, +% but at least they do not bomb out when the aux file is read in. +\catcode `\{=1 \catcode `\}=2 +\catcode `\%=\other +\catcode `\'=0 +\catcode `\\=\other +\openin 1 \jobname.aux +\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue +\global\warnedobstrue +\fi +% Open the new aux file. Tex will close it automatically at exit. +\openout \auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only.. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +\long\gdef\footnotezzz#1{\insert\footins{% + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + #1\strut}% +} + +}%end \catcode `\@=11 + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + + +% End of control word definitions. + +\message{and turning on texinfo input format.} + +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% Set some numeric style parameters, for 8.5 x 11 format. + +%\hsize = 6.5in +\newdimen\defaultparindent \defaultparindent = 15pt +\parindent = \defaultparindent +\parskip 18pt plus 1pt +\setleading{15pt} +\advance\topskip by 1.2cm + +% Prevent underfull vbox error messages. +\vbadness=10000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. This makes it come to about 9pt for the 8.5x11 format. +% +\ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% +\else + \emergencystretch = \hsize + \divide\emergencystretch by 45 +\fi + +% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25) +\def\smallbook{ + +% These values for secheadingskip and subsecheadingskip are +% experiments. RJC 7 Aug 1992 +\global\secheadingskip = 17pt plus 6pt minus 3pt +\global\subsecheadingskip = 14pt plus 6pt minus 3pt + +\global\lispnarrowing = 0.3in +\setleading{12pt} +\advance\topskip by -1cm +\global\parskip 3pt plus 1pt +\global\hsize = 5in +\global\vsize=7.5in +\global\tolerance=700 +\global\hfuzz=1pt +\global\contentsrightmargin=0pt + +\global\pagewidth=\hsize +\global\pageheight=\vsize + +\global\let\smalllisp=\smalllispx +\global\let\smallexample=\smalllispx +\global\def\Esmallexample{\Esmalllisp} +} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{ +\global\tolerance=700 +\global\hfuzz=1pt +\setleading{12pt} +\global\parskip 15pt plus 1pt + +\global\vsize= 53\baselineskip +\advance\vsize by \topskip +%\global\hsize= 5.85in % A4 wide 10pt +\global\hsize= 6.5in +\global\outerhsize=\hsize +\global\advance\outerhsize by 0.5in +\global\outervsize=\vsize +\global\advance\outervsize by 0.6in + +\global\pagewidth=\hsize +\global\pageheight=\vsize +} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} + +% This macro is used to make a character print one way in ttfont +% where it can probably just be output, and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt \char '042}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt \char '176}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +% Subroutine for the previous macro. +\def\_{\lvvmode \kern.06em \vbox{\hrule width.3em height.1ex}} + +% \lvvmode is equivalent in function to \leavevmode. +% Using \leavevmode runs into trouble when written out to +% an index file due to the expansion of \leavevmode into ``\unhbox +% \voidb@x'' ---which looks to TeX like ``\unhbox \voidb\x'' due to our +% magic tricks with @. +\def\lvvmode{\vbox to 0pt{}} + +\catcode`\|=\active +\def|{{\tt \char '174}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +%\catcode 27=\active +%\def^^[{$\diamondsuit$} + +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +\def\turnoffactive{\let"=\normaldoublequote +\let~=\normaltilde +\let^=\normalcaret +\let_=\normalunderscore +\let|=\normalverticalbar +\let<=\normalless +\let>=\normalgreater +\let+=\normalplus} + +% Set up an active definition for =, but don't enable it most of the time. +{\catcode`\==\active +\global\def={{\tt \char 61}}} + +\catcode`\@=0 + +% \rawbackslashxx output one backslash character in current font +\global\chardef\rawbackslashxx=`\\ +%{\catcode`\\=\other +%@gdef@rawbackslashxx{\}} + +% \rawbackslash redefines \ as input to do \rawbackslashxx. +{\catcode`\\=\active +@gdef@rawbackslash{@let\=@rawbackslashxx }} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\rawbackslashxx}} + +% Say @foo, not \foo, in error messages. +\escapechar=`\@ + +% \catcode 17=0 % Define control-q +\catcode`\\=\active + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\{ in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% +@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi} + +%% These look ok in all fonts, so just make them not special. The @rm below +%% makes sure that the current font starts out as the newly loaded cmr10 +@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other + +@textfonts +@rm + +@c Local variables: +@c page-delimiter: "^\\\\message" +@c End: |
