summaryrefslogtreecommitdiff
path: root/web/c_cpp
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /web/c_cpp
Initial commit
Diffstat (limited to 'web/c_cpp')
-rw-r--r--web/c_cpp/c2cweb/COPYING339
-rw-r--r--web/c_cpp/c2cweb/Makefile146
-rw-r--r--web/c_cpp/c2cweb/c2cweb.c1195
-rw-r--r--web/c_cpp/c2cweb/c2cweb.def3
-rw-r--r--web/c_cpp/c2cweb/c2cweb.dvibin0 -> 73904 bytes
-rw-r--r--web/c_cpp/c2cweb/c2cweb.ger17
-rw-r--r--web/c_cpp/c2cweb/c2cweb.txt479
-rw-r--r--web/c_cpp/c2cweb/c2cweb.w1406
-rw-r--r--web/c_cpp/c2cweb/compiler.w71
-rw-r--r--web/c_cpp/c2cweb/cweb/Makefile106
-rw-r--r--web/c_cpp/c2cweb/cweb/common.c1280
-rw-r--r--web/c_cpp/c2cweb/cweb/common.ch83
-rw-r--r--web/c_cpp/c2cweb/cweb/common.h201
-rw-r--r--web/c_cpp/c2cweb/cweb/common.w1415
-rw-r--r--web/c_cpp/c2cweb/cweb/cweave.c4543
-rw-r--r--web/c_cpp/c2cweb/cweb/cweave.ch1095
-rw-r--r--web/c_cpp/c2cweb/cweb/cweave.def3
-rw-r--r--web/c_cpp/c2cweb/cweb/cweave.w4505
-rw-r--r--web/c_cpp/c2cweb/cweb/cwebmac.ori346
-rw-r--r--web/c_cpp/c2cweb/cweb/cwebmac.tex375
-rw-r--r--web/c_cpp/c2cweb/cweb/cwebmaca.tex381
-rw-r--r--web/c_cpp/c2cweb/cweb/prod-alt.w303
-rw-r--r--web/c_cpp/c2cweb/example.c98
-rw-r--r--web/c_cpp/c2cweb/example.h20
-rw-r--r--web/c_cpp/c2cweb/history.txt122
-rw-r--r--web/c_cpp/cnoweb/README4
-rw-r--r--web/c_cpp/cnoweb/cnoweb.tex511
-rw-r--r--web/c_cpp/cnoweb/pf.c371
-rw-r--r--web/c_cpp/ctie/ChangeLog25
-rw-r--r--web/c_cpp/ctie/Makefile51
-rw-r--r--web/c_cpp/ctie/README75
-rw-r--r--web/c_cpp/ctie/ctie-k.c1166
-rw-r--r--web/c_cpp/ctie/ctie-k.ch461
-rw-r--r--web/c_cpp/ctie/ctie.158
-rw-r--r--web/c_cpp/ctie/ctie.c1111
-rw-r--r--web/c_cpp/ctie/ctie.cf114
-rw-r--r--web/c_cpp/ctie/ctie.cf226
-rw-r--r--web/c_cpp/ctie/ctie.cf313
-rw-r--r--web/c_cpp/ctie/ctie.chf.gen26
-rw-r--r--web/c_cpp/ctie/ctie.inc4
-rw-r--r--web/c_cpp/ctie/ctie.inc11
-rw-r--r--web/c_cpp/ctie/ctie.inc21
-rw-r--r--web/c_cpp/ctie/ctie.master.gen19
-rw-r--r--web/c_cpp/ctie/ctie.tie16
-rw-r--r--web/c_cpp/ctie/ctie.w1280
-rw-r--r--web/c_cpp/ctie/ctiedoc.tex242
-rw-r--r--web/c_cpp/cweb/Makefile197
-rw-r--r--web/c_cpp/cweb/README110
-rw-r--r--web/c_cpp/cweb/c++lib.w85
-rw-r--r--web/c_cpp/cweb/comm-amiga.ch17
-rw-r--r--web/c_cpp/cweb/comm-bs.ch229
-rw-r--r--web/c_cpp/cweb/comm-mac.ch150
-rw-r--r--web/c_cpp/cweb/comm-man.ch22
-rw-r--r--web/c_cpp/cweb/comm-os2.ch24
-rw-r--r--web/c_cpp/cweb/comm-pc.ch33
-rw-r--r--web/c_cpp/cweb/comm-ql.ch332
-rw-r--r--web/c_cpp/cweb/comm-vms.ch81
-rw-r--r--web/c_cpp/cweb/comm-w32.ch94
-rw-r--r--web/c_cpp/cweb/common.c1242
-rw-r--r--web/c_cpp/cweb/common.h193
-rw-r--r--web/c_cpp/cweb/common.w1418
-rw-r--r--web/c_cpp/cweb/ctang-bs.ch202
-rw-r--r--web/c_cpp/cweb/ctang-man.ch22
-rw-r--r--web/c_cpp/cweb/ctang-pc.ch24
-rw-r--r--web/c_cpp/cweb/ctang-ql.ch25
-rw-r--r--web/c_cpp/cweb/ctang-vms.ch35
-rw-r--r--web/c_cpp/cweb/ctang-w32.ch66
-rw-r--r--web/c_cpp/cweb/ctangle.c1579
-rw-r--r--web/c_cpp/cweb/ctangle.w1557
-rw-r--r--web/c_cpp/cweb/cweav-bs.ch302
-rw-r--r--web/c_cpp/cweb/cweav-man.ch22
-rw-r--r--web/c_cpp/cweb/cweav-pc.ch39
-rw-r--r--web/c_cpp/cweb/cweav-ql.ch32
-rw-r--r--web/c_cpp/cweb/cweav-vms.ch37
-rw-r--r--web/c_cpp/cweb/cweav-w32.ch52
-rw-r--r--web/c_cpp/cweb/cweave.w4652
-rw-r--r--web/c_cpp/cweb/cweb.1138
-rw-r--r--web/c_cpp/cweb/cweb.el218
-rw-r--r--web/c_cpp/cweb/cwebmac.tex553
-rw-r--r--web/c_cpp/cweb/cwebman.tex1763
-rw-r--r--web/c_cpp/cweb/makefile.bs60
-rw-r--r--web/c_cpp/cweb/prod.w307
-rw-r--r--web/c_cpp/cweb/readme.ql84
-rw-r--r--web/c_cpp/cwebbin/README-2019.txt478
-rw-r--r--web/c_cpp/cwebbin/README.md58
-rw-r--r--web/c_cpp/cwebx/Makefile122
-rw-r--r--web/c_cpp/cwebx/README111
-rw-r--r--web/c_cpp/cwebx/common.c885
-rw-r--r--web/c_cpp/cwebx/common.h90
-rw-r--r--web/c_cpp/cwebx/common.inc184
-rw-r--r--web/c_cpp/cwebx/common.w1757
-rw-r--r--web/c_cpp/cwebx/compare.tex202
-rw-r--r--web/c_cpp/cwebx/ctangle.c996
-rw-r--r--web/c_cpp/cwebx/ctangle.w1856
-rw-r--r--web/c_cpp/cwebx/cweave.w3588
-rw-r--r--web/c_cpp/cwebx/cwebcmac.tex77
-rw-r--r--web/c_cpp/cwebx/cwebhmac.tex143
-rw-r--r--web/c_cpp/cwebx/cwebxmac.tex442
-rw-r--r--web/c_cpp/cwebx/examples/Makefile45
-rw-r--r--web/c_cpp/cwebx/examples/compare.w108
-rw-r--r--web/c_cpp/cwebx/examples/treeprint.w229
-rw-r--r--web/c_cpp/cwebx/examples/wc.w226
-rw-r--r--web/c_cpp/cwebx/examples/wmerge.w52
-rw-r--r--web/c_cpp/cwebx/intro.inc88
-rw-r--r--web/c_cpp/cwebx/man1/cweb.1165
-rw-r--r--web/c_cpp/cwebx/manual.dvibin0 -> 297772 bytes
-rw-r--r--web/c_cpp/cwebx/manual.pdfbin0 -> 324004 bytes
-rw-r--r--web/c_cpp/cwebx/manual.tex2558
-rw-r--r--web/c_cpp/cwebx/parser.w1233
-rw-r--r--web/c_cpp/cwebx/rules.w701
-rw-r--r--web/c_cpp/cwebx/sample.ps621
l---------web/c_cpp/macweave1
112 files changed, 57019 insertions, 0 deletions
diff --git a/web/c_cpp/c2cweb/COPYING b/web/c_cpp/c2cweb/COPYING
new file mode 100644
index 0000000000..a43ea2126f
--- /dev/null
+++ b/web/c_cpp/c2cweb/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <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/web/c_cpp/c2cweb/Makefile b/web/c_cpp/c2cweb/Makefile
new file mode 100644
index 0000000000..616b2af16e
--- /dev/null
+++ b/web/c_cpp/c2cweb/Makefile
@@ -0,0 +1,146 @@
+# This file is part of the c2cweb package Version 1.5 (10-Nov-1996)
+
+# GNU Makefile for c2cweb
+
+# you should use the CWEAVE program of this package
+
+.PHONY: default all debug documentation clean \
+ do_all cweb
+.CAUTIOUS: c2cweb.c
+
+
+default:
+ @echo " say "
+ @echo ". "
+ @echo " make <TARGET> OS=<SYSTEM> "
+ @echo ". "
+ @echo " SYSTEM can be one of the following:"
+ @echo ". "
+ @echo " unix (gcc) "
+ @echo " os2 bound (emx) "
+ @echo " dos (djgpp) "
+ @echo ". "
+ @echo " TARGET can be one of the following:"
+ @echo ". "
+ @echo " all debug "
+ @echo " documentation "
+ @echo " clean "
+
+
+ifdef OS
+
+ ifeq ($(OS),unix)
+ CC = gcc -Wall -O
+ O = .o
+ LIB =
+ EXE =
+ CP = cp
+ RM = rm -f
+ endif
+
+ ifeq ($(OS),os2)
+ CC = gcc -Wall -Zomf -Zmtd -O
+ O = .obj
+ LIB = c2cweb.def
+ EXE = .exe
+ CP = copy
+ RM = del
+ endif
+
+ ifeq ($(OS),dos)
+ CC = gcc -Wall -O
+ O = .o
+ LIB =
+ EXE = .exe
+ CP = copy
+ RM = del
+ endif
+
+ ifeq ($(OS),bound)
+ CC = gcc -Wall -O
+ O = .o
+ LIB =
+ EXE = .exe
+ CP = copy
+ RM = del
+ endif
+
+
+ ifeq ($(OS),unix)
+ define sub_make
+ cd cweb; make $@
+ endef
+ else
+ define sub_make
+ cd cweb
+ make $@
+ cd ..
+ endef
+ endif
+
+
+ OBJ = c2cweb$O
+ OUR_CWEAVE = cweb/cweave
+
+ %$O: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+ %.c: %.w %.ch
+ $(CTANGLE) $^ $@
+ %.c: %.w
+ $(CTANGLE) $<
+
+ %.tex: %.w %.ch
+ $(OUR_CWEAVE) +ai $^ $@
+ %.tex: %.w
+ $(OUR_CWEAVE) +ai $<
+
+
+ all:
+ $(MAKE) do_all CFLAGS=-s
+
+ debug:
+ $(MAKE) do_all CFLAGS=-g
+
+ # this builds a .dvi-file
+ # for .dvi files of cweave etc. please get the original CWEB package
+ documentation: c2cweb.dvi
+
+ # remove the unnecessary files.
+ clean:
+ $(sub_make)
+ -$(RM) *$O
+ -$(RM) *.tex
+ -$(RM) *.scn
+ -$(RM) *.toc
+ -$(RM) *.idx
+ -$(RM) *.log
+
+
+ do_all: cweb c2cweb$(EXE)
+
+ cweb:
+ $(sub_make)
+
+ c2cweb$(EXE): $(OBJ)
+ ifeq ($(OS),dos)
+ $(CC) $(CFLAGS) -o $(basename $@) $^
+ strip $(basename $@)
+ coff2exe $(basename $@)
+ -$(RM) $(basename $@)
+ else
+ $(CC) $(CFLAGS) -o $@ $^ $(LIB)
+ endif
+
+ c2cweb.dvi: c2cweb.tex cweb/cwebmaca.tex
+ -$(RM) cwebmaca.tex
+ $(CP) cweb/cwebmaca.tex .
+ $(TEX) c2cweb
+
+else # ifdef OS
+
+ all debug documentation clean: default
+
+endif
+
+# end of Makefile
diff --git a/web/c_cpp/c2cweb/c2cweb.c b/web/c_cpp/c2cweb/c2cweb.c
new file mode 100644
index 0000000000..f5869cf8b5
--- /dev/null
+++ b/web/c_cpp/c2cweb/c2cweb.c
@@ -0,0 +1,1195 @@
+#define banner "\nThis is c2cweb Version 1.5 (c) 1996 by Werner Lemberg\n\n" \
+ \
+
+#define FALSE 0
+#define TRUE 1
+#define DONE 2
+#define WAIT 3 \
+
+#define DIR_LENGTH 80
+#define TITLE_LENGTH 100
+#define PATH_SEPARATOR '/' \
+
+#define FILE_NAME_LENGTH 80 \
+
+#define BUFFER_LENGTH 500 \
+
+#define xisspace(c) (isspace(c) &&((unsigned char) c<0200) ) \
+
+/*4:*/
+#line 120 "c2cweb.w"
+
+/*5:*/
+#line 155 "c2cweb.w"
+
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*:5*/
+#line 121 "c2cweb.w"
+;
+/*11:*/
+#line 370 "c2cweb.w"
+
+void open_files(char*);
+
+/*:11*//*14:*/
+#line 464 "c2cweb.w"
+
+void handle_input(void);
+
+
+/*:14*//*33:*/
+#line 1145 "c2cweb.w"
+
+void usage(void);
+
+/*:33*//*35:*/
+#line 1171 "c2cweb.w"
+
+void modify_filename(char*);
+
+
+/*:35*//*38:*/
+#line 1211 "c2cweb.w"
+
+char*get_line(void);
+
+
+/*:38*//*41:*/
+#line 1250 "c2cweb.w"
+
+char*protect_underlines(char*);
+
+
+/*:41*//*43:*/
+#line 1276 "c2cweb.w"
+
+#ifndef __EMX__
+char*_getname(char*);
+#endif
+
+
+/*:43*/
+#line 122 "c2cweb.w"
+;
+/*8:*/
+#line 249 "c2cweb.w"
+
+int tab_length= 4;
+int verbatim= FALSE;
+int user_linefeed= FALSE;
+int one_side= FALSE;
+char outdir[DIR_LENGTH+1];
+char include_file[FILE_NAME_LENGTH+1];
+char title[TITLE_LENGTH+1];
+
+#ifdef __EMX__
+char optchar[]= "-/";
+char pathsepchar[]= "\\/";
+#else
+char optchar[]= "-";
+char pathsepchar[]= "/";
+#endif
+
+char at_nmb[]= "@#";
+
+
+
+/*:8*//*10:*/
+#line 365 "c2cweb.w"
+
+FILE*in,*out;
+
+
+/*:10*//*15:*/
+#line 471 "c2cweb.w"
+
+char buffer[BUFFER_LENGTH+1];
+
+/*:15*//*37:*/
+#line 1205 "c2cweb.w"
+
+int line_number= 0;
+int column;
+
+
+/*:37*//*40:*/
+#line 1245 "c2cweb.w"
+
+char tempbuf[2*FILE_NAME_LENGTH+1];
+
+
+/*:40*/
+#line 123 "c2cweb.w"
+;
+
+void main(argc,argv)
+int argc;
+char*argv[];
+
+{int i;
+char buffer[DIR_LENGTH+FILE_NAME_LENGTH+1];
+char*p,*q;
+
+
+printf(banner);
+
+#ifdef __EMX__
+_response(&argc,&argv);
+_wildcard(&argc,&argv);
+#endif
+
+/*9:*/
+#line 271 "c2cweb.w"
+
+{char c;
+int i;
+
+
+outdir[0]= '\0';
+include_file[0]= '\0';
+title[0]= '\0';
+
+#ifdef __EMX__
+optswchar= optchar;
+#endif
+
+strcpy(title,"c2cweb output");
+
+while((c= getopt(argc,argv,"b:f:lo:t:v1"))!=EOF)
+{switch(c)
+{case'b':
+if(strchr(optchar,optarg[0]))
+
+usage();
+
+if(strlen(optarg)>=TITLE_LENGTH)
+fprintf(stderr,
+"\nTitle too long. Will use \"c2cweb output\".\n");
+else
+strcpy(title,optarg);
+break;
+case'f':
+if(strchr(optchar,optarg[0]))
+usage();
+
+if(strlen(optarg)>=FILE_NAME_LENGTH)
+fprintf(stderr,
+"\nInclude file name too long. Will be ignored.\n");
+else
+strcpy(include_file,optarg);
+break;
+case'l':
+user_linefeed= TRUE;
+break;
+case'o':
+if(strchr(optchar,optarg[0]))
+usage();
+
+if((i= strlen(optarg))>=DIR_LENGTH)
+fprintf(stderr,
+"\nOutput directory name too long. Will be ignored.\n");
+else
+{strcpy(outdir,optarg);
+if(!strchr(pathsepchar,outdir[i-1]))
+
+{outdir[i]= PATH_SEPARATOR;
+outdir[i+1]= '\0';
+}
+}
+break;
+case't':
+if(strchr(optchar,optarg[0]))
+usage();
+
+tab_length= atoi(optarg);
+if(tab_length==0||tab_length>8)
+tab_length= 4;
+break;
+case'v':
+verbatim= TRUE;
+break;
+case'1':
+one_side= TRUE;
+break;
+default:
+usage();
+break;
+}
+}
+
+if(optind==argc)
+usage();
+}
+
+
+/*:9*/
+#line 141 "c2cweb.w"
+;
+
+/*6:*/
+#line 164 "c2cweb.w"
+
+for(i= optind;i<argc-1;i++)
+{printf(" processing %s\n",argv[i]);
+
+open_files(argv[i]);
+q= protect_underlines(_getname(argv[i]));
+if((p= strrchr(q,'.'))!=NULL)
+
+
+fprintf(out,
+"@*{%s\\ZZZ{\\setbox0=\\hbox{%s}\\hskip-\\wd0}}.\n"
+"\\ind=2\n\n",q,p);
+else
+fprintf(out,"@*{%s}.\n"
+"\\ind=2\n\n",q);
+
+handle_input();
+fclose(in);
+fclose(out);
+}
+
+
+/*:6*/
+#line 143 "c2cweb.w"
+;
+/*7:*/
+#line 190 "c2cweb.w"
+
+printf(" processing %s\n",argv[i]);
+
+open_files(argv[i]);
+/*13:*/
+#line 418 "c2cweb.w"
+
+fprintf(out,
+"\\font\\symb=cmsy10\n"
+"\\font\\math=cmmi10\n"
+"\\def\\ob"
+"{\\parskip=0pt\\parindent=0pt%%\n"
+"\\let\\\\=\\BS\\let\\{=\\LB\\let\\}=\\RB\\let\\~=\\TL%%\n"
+"\\let\\ =\\SP\\let\\_=\\UL\\let\\&=\\AM\\let\\^=\\CF%%\n"
+"\\obeyspaces\\frenchspacing\\tt}\n"
+"\n"
+"\\def\\e{\\hfill\\break\\hbox{}}\n"
+"\\def\\{{\\relax\\ifmmode\\lbrace\\else$\\lbrace$\\fi}\n"
+"\\def\\}{\\relax\\ifmmode\\rbrace\\else$\\rbrace$\\fi}\n"
+"\\def\\takenone#1{\\hskip-0.1em}\n"
+"\\let\\ZZZ=\\relax\n"
+"\n"
+"%s"
+"\n"
+"\\pageno=\\contentspagenumber \\advance\\pageno by 1\n"
+"\\let\\maybe=\\iftrue\n"
+"\n"
+"\\def\\title{%s}\n"
+"\n"
+"@i compiler.w\n"
+"\n",one_side?"\\let\\lheader=\\rheader\n":"",title);
+
+if(*include_file)
+fprintf(out,
+"@i %s\n"
+"\n",include_file);
+
+for(i= optind;i<argc-1;i++)
+{strcpy(buffer,argv[i]);
+modify_filename(buffer);
+
+fprintf(out,"@i %s\n",_getname(buffer));
+}
+
+fputc('\n',out);
+
+
+
+/*:13*/
+#line 194 "c2cweb.w"
+;
+q= protect_underlines(_getname(argv[i]));
+if((p= strrchr(q,'.'))!=NULL)
+fprintf(out,
+"@*{%s\\ZZZ{\\setbox0=\\hbox{%s}\\hskip-\\wd0}}.\n"
+"\\ind=2\n\n",q,p);
+else
+fprintf(out,"@*{%s}.\n"
+"\\ind=2\n\n",q);
+
+handle_input();
+/*32:*/
+#line 1137 "c2cweb.w"
+
+fprintf(out,
+"\n"
+"@*Index.\n"
+"\\let\\ZZZ=\\takenone\n");
+
+
+/*:32*/
+#line 205 "c2cweb.w"
+;
+
+strcpy(buffer,argv[argc-1]);
+modify_filename(buffer);
+
+printf(
+"\n You must now call CWEAVE with %s%s\n"
+" as the argument to get a TeX output",outdir,_getname(buffer));
+if(optind<argc-1)
+printf(" of all processed files");
+printf("\n");
+
+
+
+/*:7*/
+#line 144 "c2cweb.w"
+;
+
+fclose(in);
+fclose(out);
+}
+
+
+/*:4*//*12:*/
+#line 374 "c2cweb.w"
+
+void open_files(filename)
+char*filename;
+{char buffer[DIR_LENGTH+FILE_NAME_LENGTH+1];
+
+
+if(strlen(filename)>FILE_NAME_LENGTH-2)
+{fprintf(stderr,"\n File name too long.\n");
+exit(-1);
+}
+
+if((in= fopen(filename,"rt"))==NULL)
+{fprintf(stderr,"\n Can't open input file %s\n",filename);
+exit(-1);
+}
+
+strcpy(buffer,outdir);
+strcat(buffer,filename);
+modify_filename(buffer);
+
+if((out= fopen(buffer,"wt"))==NULL)
+{fprintf(stderr,"\n Can't open output file %s\n",buffer);
+exit(-1);
+}
+}
+
+
+
+/*:12*//*16:*/
+#line 480 "c2cweb.w"
+
+void handle_input(void)
+{char*buf_p;
+char ch;
+/*17:*/
+#line 571 "c2cweb.w"
+
+int any_input= FALSE;
+
+int brace_count= 0;
+int blank_count= 0;
+
+int in_comment= FALSE;
+int in_C= FALSE;
+int in_string= FALSE;
+int short_comment= FALSE;
+int leading_blanks= TRUE;
+int double_linefeed= FALSE;
+int linefeed_comment= FALSE;
+
+int comment_slash= FALSE;
+int comment_star= FALSE;
+int escape_state= FALSE;
+
+
+int before_TeX_text= FALSE;
+
+int function_blocks= FALSE;
+
+
+/*:17*/
+#line 484 "c2cweb.w"
+;
+
+line_number= 0;
+while(get_line())
+{buf_p= buffer;
+
+do
+{ch= *buf_p;
+
+/*18:*/
+#line 598 "c2cweb.w"
+
+/*19:*/
+#line 690 "c2cweb.w"
+
+if(buf_p==buffer)
+{if(!(in_comment||in_string))
+{if(!strncmp(buf_p,"/""*@@*""/",6))
+{in_C= FALSE;
+before_TeX_text= TRUE;
+function_blocks= WAIT;
+brace_count= 0;
+
+if(any_input)
+fputs("\n@\n"
+"\\ind=2\n\n",out);
+
+
+any_input= FALSE;
+*(buf_p--)= '\n';
+
+goto end;
+}
+else if(!strncmp(buf_p,"/""*@*""/",5))
+{in_C= FALSE;
+before_TeX_text= TRUE;
+function_blocks= FALSE;
+
+if(any_input)
+fputs("\n@\n"
+"\\ind=2\n\n",out);
+
+any_input= FALSE;
+*(buf_p--)= '\n';
+goto end;
+}
+else if(!strncmp(buf_p,"/""*{*""/",5))
+{brace_count++;
+fputs("@{\n",out);
+
+ch= '\n';
+goto end;
+}
+else if(!strncmp(buf_p,"/""*}*""/",5))
+{brace_count--;
+fputs("@}\n",out);
+
+if(!brace_count&&function_blocks)
+
+{in_C= FALSE;
+before_TeX_text= TRUE;
+
+break;
+}
+
+ch= '\n';
+goto end;
+}
+else if(!strncmp(buf_p,"/""*{}*""/",6))
+{fputs("@{@}\n",out);
+
+ch= '\n';
+goto end;
+}
+}
+}
+
+
+/*:19*/
+#line 599 "c2cweb.w"
+;
+
+if(double_linefeed&&ch=='/')
+linefeed_comment= TRUE;
+
+if(double_linefeed&&(ch==' '||ch=='\t'))
+leading_blanks= TRUE;
+
+if(ch!='\n')
+double_linefeed= FALSE;
+
+if(!xisspace(ch))
+{any_input= TRUE;
+
+if(before_TeX_text&&function_blocks)
+{before_TeX_text= FALSE;
+
+if(function_blocks==WAIT)
+function_blocks= TRUE;
+
+else
+{fputs("@\n"
+"\\ind=2\n\n",out);
+
+
+if(leading_blanks)
+{leading_blanks= FALSE;
+
+while(blank_count--)
+fputc(' ',out);
+blank_count= 0;
+}
+}
+}
+
+if(in_comment&&leading_blanks)
+{leading_blanks= FALSE;
+
+while(blank_count--)
+fputc(' ',out);
+blank_count= 0;
+}
+}
+
+if(!(ch=='/'||xisspace(ch)))
+
+{if(!(in_comment||in_C||comment_slash))
+
+{in_C= TRUE;
+
+fputs("@c\n",out);
+
+if(leading_blanks)
+{leading_blanks= FALSE;
+
+while(blank_count--)
+fputc(' ',out);
+blank_count= 0;
+}
+}
+
+if(!(in_comment||comment_slash)&&leading_blanks)
+{leading_blanks= FALSE;
+
+while(blank_count--)
+fputc(' ',out);
+blank_count= 0;
+}
+}
+
+if(comment_slash&&!(ch=='*'||ch=='/'))
+
+{comment_slash= FALSE;
+if(!in_comment)
+linefeed_comment= FALSE;
+
+fputc('/',out);
+}
+
+if(comment_star&&ch!='/')
+{comment_star= FALSE;
+
+fputc('*',out);
+}
+
+if(escape_state&&!(ch=='\"'||ch=='\n'||ch=='\\'))
+
+escape_state= FALSE;
+
+
+/*:18*/
+#line 493 "c2cweb.w"
+;
+
+switch(ch)
+{case' ':
+if(leading_blanks)
+{blank_count++;
+goto end;
+}
+break;
+
+case'\t':
+{int i= tab_length-(column%tab_length);
+
+column+= i-1;
+
+if(leading_blanks)
+{blank_count+= i;
+goto end;
+}
+
+while(i--)
+fputc(' ',out);
+goto end;
+}
+break;
+
+case'{':
+/*20:*/
+#line 755 "c2cweb.w"
+
+if(in_comment)
+fputc('\\',out);
+else if(in_string)
+break;
+else if(function_blocks)
+{brace_count++;
+in_C= TRUE;
+}
+
+/*:20*/
+#line 520 "c2cweb.w"
+;
+break;
+
+case'}':
+/*25:*/
+#line 802 "c2cweb.w"
+
+if(in_comment)
+fputc('\\',out);
+else if(in_string)
+break;
+else if(function_blocks)
+{brace_count--;
+if(!brace_count)
+{in_C= FALSE;
+
+before_TeX_text= TRUE;
+break;
+}
+}
+
+/*:25*/
+#line 524 "c2cweb.w"
+;
+break;
+
+case'/':
+/*26:*/
+#line 818 "c2cweb.w"
+
+if(comment_star)
+{/*27:*/
+#line 832 "c2cweb.w"
+
+comment_star= FALSE;
+leading_blanks= FALSE;
+
+if(!short_comment)
+{in_comment= FALSE;
+
+if(!in_C)
+{linefeed_comment= FALSE;
+
+if(verbatim)
+fputs("*""/}",out);
+
+if(*(buf_p+1)=='\n')
+fputs("\\e{}%",out);
+
+goto end;
+}
+
+if(in_C&&verbatim)
+{if(linefeed_comment)
+{linefeed_comment= FALSE;
+
+fputs("*""/@>",out);
+if(*(buf_p+1)=='\n'&&!user_linefeed)
+fputs("@/",out);
+goto end;
+}
+else
+fputc('}',out);
+}
+
+linefeed_comment= FALSE;
+
+if(in_C||verbatim)
+fputc('*',out);
+else
+goto end;
+}
+else
+fputc('*',out);
+
+/*:27*/
+#line 820 "c2cweb.w"
+;
+}
+else if(comment_slash)
+{/*28:*/
+#line 875 "c2cweb.w"
+
+comment_slash= FALSE;
+
+if(!short_comment)
+{in_comment= TRUE;
+short_comment= TRUE;
+
+if(!in_C&&verbatim)
+{fputs("{\\ob{}",out);
+if(leading_blanks)
+{leading_blanks= FALSE;
+
+while(blank_count--)
+fputc(' ',out);
+blank_count= 0;
+}
+fputs("//",out);
+
+goto end;
+}
+
+if(in_C&&verbatim)
+{if(leading_blanks||linefeed_comment)
+{linefeed_comment= TRUE;
+
+if(!user_linefeed)
+fputs("@/",out);
+fputs("@t}\\8{\\ob{}",out);
+
+
+if(leading_blanks)
+{leading_blanks= FALSE;
+
+while(blank_count--)
+fputc(' ',out);
+blank_count= 0;
+}
+fputs("//",out);
+}
+else
+fputs("//{\\ob{}",out);
+
+goto end;
+}
+
+if(in_C||verbatim)
+fputc('/',out);
+else
+goto end;
+}
+else
+fputc('/',out);
+
+
+/*:28*/
+#line 823 "c2cweb.w"
+;
+}
+else
+{comment_slash= TRUE;
+
+goto end;
+}
+
+/*:26*/
+#line 528 "c2cweb.w"
+;
+break;
+
+case'*':
+/*29:*/
+#line 930 "c2cweb.w"
+
+if(comment_slash)
+{comment_slash= FALSE;
+
+if(in_comment&&!short_comment)
+
+
+
+
+
+
+
+{fprintf(stderr,
+" Error line %d: Nested comments not supported\n",
+line_number);
+exit(-1);
+}
+
+if(!short_comment)
+{in_comment= TRUE;
+
+if(!in_C&&verbatim)
+{fputs("{\\ob{}",out);
+if(leading_blanks)
+{leading_blanks= FALSE;
+
+while(blank_count--)
+fputc(' ',out);
+blank_count= 0;
+}
+fputs("/""*",out);
+
+goto end;
+}
+
+if(in_C&&verbatim)
+{if(leading_blanks||linefeed_comment)
+{linefeed_comment= TRUE;
+
+if(!user_linefeed)
+fputs("@/",out);
+fputs("@t}\\8{\\ob{}",out);
+if(leading_blanks)
+{leading_blanks= FALSE;
+
+while(blank_count--)
+fputc(' ',out);
+blank_count= 0;
+}
+fputs("/""*",out);
+}
+else
+fputs("/""*{\\ob{}",out);
+
+goto end;
+}
+
+if(in_C||verbatim)
+fputc('/',out);
+else
+{fputs(" ",out);
+
+goto end;
+}
+}
+else
+fputc('/',out);
+}
+else
+{comment_star= TRUE;
+
+goto end;
+}
+
+
+/*:29*/
+#line 532 "c2cweb.w"
+;
+break;
+
+case'\n':
+/*30:*/
+#line 1006 "c2cweb.w"
+
+blank_count= 0;
+
+if(!in_comment&&in_C)
+{if(double_linefeed==FALSE)
+{double_linefeed= TRUE;
+if(escape_state)
+{escape_state= FALSE;
+
+leading_blanks= TRUE;
+
+if(in_string)
+fputc('\n',out);
+else
+fputs("\n@/",out);
+goto end;
+}
+
+if(!leading_blanks&&user_linefeed)
+fputs("@/",out);
+}
+else if(double_linefeed==TRUE)
+{double_linefeed= DONE;
+
+
+fputs(at_nmb,out);
+}
+}
+
+leading_blanks= TRUE;
+
+if(short_comment)
+{short_comment= FALSE;
+in_comment= FALSE;
+double_linefeed= TRUE;
+
+if(verbatim)
+{if(linefeed_comment&&in_C)
+fputs("@>",out);
+else
+fputc('}',out);
+}
+
+if(!in_C)
+fputs("\\e{}%",out);
+else if(linefeed_comment&&verbatim)
+fputs("@/",out);
+
+linefeed_comment= FALSE;
+}
+
+if(in_comment&&in_C&&verbatim&&linefeed_comment)
+{
+fputs("@>@/\n@t}\\8{\\ob{}",out);
+
+goto end;
+}
+
+if(in_comment&&verbatim)
+
+
+
+{fputs("\n\\e{}",out);
+goto end;
+}
+
+
+/*:30*/
+#line 536 "c2cweb.w"
+;
+break;
+
+case'@':
+/*21:*/
+#line 766 "c2cweb.w"
+
+if(in_comment)
+{fputs("{\\char64}",out);
+goto end;
+}
+else
+fputc('@',out);
+
+/*:21*/
+#line 540 "c2cweb.w"
+;
+break;
+
+case'\'':
+/*22:*/
+#line 775 "c2cweb.w"
+
+if(!in_comment)
+{if(*(buf_p+1)=='\"'&&*(buf_p+2)=='\'')
+escape_state= TRUE;
+}
+
+/*:22*/
+#line 544 "c2cweb.w"
+;
+break;
+
+case'\"':
+/*23:*/
+#line 782 "c2cweb.w"
+
+if(!in_comment)
+{if(escape_state)
+escape_state= FALSE;
+else
+in_string= TRUE-in_string;
+}
+
+/*:23*/
+#line 548 "c2cweb.w"
+;
+break;
+
+case'\\':
+/*24:*/
+#line 791 "c2cweb.w"
+
+if(in_comment)
+{fputs("{\\symb\\char110}",out);
+goto end;
+}
+else
+escape_state= TRUE-escape_state;
+
+
+
+/*:24*/
+#line 552 "c2cweb.w"
+;
+break;
+
+default:
+/*31:*/
+#line 1077 "c2cweb.w"
+
+if(in_comment)
+{switch(ch)
+{case'#':
+fputs("{\\#}",out);
+break;
+
+case'$':
+fputs("{\\$}",out);
+break;
+
+case'%':
+fputs("{\\%}",out);
+break;
+
+case'&':
+fputs("{\\AM}",out);
+break;
+
+case'_':
+fputs("{\\_}",out);
+break;
+
+case'^':
+fputs("{\\^{}}",out);
+break;
+
+case'\\':
+fputs("{\\symb\\char110}",out);
+break;
+
+case'~':
+fputs("{\\~{}}",out);
+break;
+
+case'|':
+fputs("{\\symb\\char106}",out);
+break;
+
+case'<':
+fputs("{\\math\\char60}",out);
+break;
+
+case'>':
+fputs("{\\math\\char62}",out);
+break;
+
+default:
+fputc(ch,out);
+break;
+}
+
+goto end;
+}
+
+
+/*:31*/
+#line 556 "c2cweb.w"
+;
+break;
+}
+
+fputc(ch,out);
+
+end:
+buf_p++;
+column++;
+}while(ch!='\n');
+}
+}
+
+
+/*:16*//*34:*/
+#line 1149 "c2cweb.w"
+
+void usage(void)
+{fprintf(stderr,
+"Usage: c2cweb [switches] csourcefile(s) | @responsefile(s)"
+"\n"
+"\n possible switches:"
+"\n"
+"\n -b \"title\" set title"
+"\n -l use input linefeeds"
+"\n -o dirname set output directory (must already exist)"
+"\n -f filename use this file as a format file"
+"\n -t tablength set tabulator length (default 4)"
+"\n -v verbatim mode"
+"\n -1 one-sided output"
+"\n"
+"\n");
+
+exit(-1);
+}
+
+
+/*:34*//*36:*/
+#line 1180 "c2cweb.w"
+
+void modify_filename(name)
+char*name;
+{char*p;
+
+
+if((p= strrchr(name,'.'))!=NULL)
+{p++;
+if(*p&&*p!=' ')
+p++;
+if(*p&&*p!=' ')
+p++;
+if(*p!='w')
+*p= 'w';
+else
+*p= 'x';
+p++;
+*p= '\0';
+}
+else
+strcat(name,".w");
+}
+
+
+/*:36*//*39:*/
+#line 1218 "c2cweb.w"
+
+char*get_line(void)
+{char*p;
+int i= BUFFER_LENGTH;
+
+
+if((p= fgets(buffer,BUFFER_LENGTH+1,in))!=NULL)
+{while(i--)
+{if(*(p++)=='\n')
+break;
+}
+
+p--;
+p--;
+while((*p==' '||*p=='\t')&&p>=buffer)
+p--;
+*(p+1)= '\n';
+*(p+2)= '\0';
+
+line_number++;
+column= 0;
+}
+return(p);
+}
+
+
+/*:39*//*42:*/
+#line 1257 "c2cweb.w"
+
+char*protect_underlines(p)
+char*p;
+{char*q;
+
+
+q= tempbuf;
+
+do
+{if(*p=='_')
+*(q++)= '\\';
+*(q++)= *p;
+}while(*(p++));
+
+return tempbuf;
+}
+
+
+/*:42*//*44:*/
+#line 1287 "c2cweb.w"
+
+#ifndef __EMX__
+char*_getname(char*path)
+{char*p;
+
+p= strrchr(path,'/');
+return p==NULL?path:(p+1);
+}
+#endif
+
+
+
+/*:44*/
diff --git a/web/c_cpp/c2cweb/c2cweb.def b/web/c_cpp/c2cweb/c2cweb.def
new file mode 100644
index 0000000000..9fdd016403
--- /dev/null
+++ b/web/c_cpp/c2cweb/c2cweb.def
@@ -0,0 +1,3 @@
+NAME C2CWEB WINDOWCOMPAT
+DESCRIPTION 'C2CWEB 1.5'
+STACKSIZE 0x80000
diff --git a/web/c_cpp/c2cweb/c2cweb.dvi b/web/c_cpp/c2cweb/c2cweb.dvi
new file mode 100644
index 0000000000..f0b0fcd989
--- /dev/null
+++ b/web/c_cpp/c2cweb/c2cweb.dvi
Binary files differ
diff --git a/web/c_cpp/c2cweb/c2cweb.ger b/web/c_cpp/c2cweb/c2cweb.ger
new file mode 100644
index 0000000000..895137a5f3
--- /dev/null
+++ b/web/c_cpp/c2cweb/c2cweb.ger
@@ -0,0 +1,17 @@
+% This file is part of the c2cweb package Version 1.5
+
+% this is a small german `package' for c2cweb
+% written by Werner Lemberg (a7971428@unet.univie.ac.at) 10-Nov-1996
+
+\catcode`^^8e=\active \def ^^8e{\"A}
+\catcode`^^99=\active \def ^^99{\"O}
+\catcode`^^9a=\active \def ^^9a{\"U}
+\catcode`^^84=\active \def ^^84{\"a}
+\catcode`^^94=\active \def ^^94{\"o}
+\catcode`^^81=\active \def ^^81{\"u}
+\catcode`^^e1=\active \def ^^e1{\ss{}}
+
+\font\tentex=cmtt10
+
+
+% end of c2cweb.ger
diff --git a/web/c_cpp/c2cweb/c2cweb.txt b/web/c_cpp/c2cweb/c2cweb.txt
new file mode 100644
index 0000000000..9a7b64eb62
--- /dev/null
+++ b/web/c_cpp/c2cweb/c2cweb.txt
@@ -0,0 +1,479 @@
+
+This is the c2cweb package Version 1.5 (10-Nov-1996)
+=====================================================
+
+Copyright (C) 1996 Werner Lemberg
+
+[see below for a German introduction]
+
+
+c2cweb will transform plain C or C++ code into a CWEB file to get a pretty
+formatted output. A modified CWEAVE (which transforms the CWEB file into a
+TeX file, see below) is included also.
+
+Some c2cweb highlights:
+
+ variables and function names in italics
+ reserved words (int, char, return etc.) in bold face
+ strings in typewriter type
+ comments in typwriter type or roman
+ an index(!) of all variables, constants, function names etc.
+ each function gets a section
+
+ and more
+
+
+The c2cweb package contains the following files:
+
+ c2cweb.txt this file
+ history.txt the history file
+ Makefile a makefile to compile c2cweb for UNIX, OS/2, and DOS
+ c2cweb.def definition file (needed for compiling under OS/2
+ only)
+ COPYING the GNU Copying License
+ c2cweb.w a CWEB file of the program
+ you should say
+ make documentation (using this package's CWEAVE)
+ to produce a TeX-output
+ c2cweb.c extracted with CTANGLE from c2cweb.w
+ c2cweb.dvi the final .dvi-file
+ c2cweb.exe an executable for DOS and OS/2
+ compiler.w compiler dependent formatting commands
+ (an output of c2cweb reads this file)
+ c2cweb.ger a small german `package' to demonstrate national
+ language support
+ example.h
+ example.c a C code example with inserted c2cweb control
+ commands
+ cweb/cweave.exe a modified executable (for DOS and OS/2) of CWEAVE
+ Ver. 3.2 with three important new features:
+
+ o the switch +a causes CWEAVE to produce a
+ different output format, basically
+
+ if(a)
+ {bla bla bla...
+ }
+
+ instead of
+
+ if(a) {
+ bla bla bla...
+ }
+
+ o the switch +i causes CWEAVE to append () after a
+ function name in the index (this makes only
+ sense if all names are unique)
+ o the #define statement handling was basically
+ enhanced to allow macros with parameters
+ cweb/cweave.w this is the original CWEAVE source file of Levy's
+ CWEB package ver 3.2 (July 1994)
+ cweb/cweave.ch the change file for cweave.w
+ cweb/cweave.c extracted with CTANGLE from cweave.{w,ch}
+ cweb/common.h this is needed to build CWEAVE
+ (slightly different from the original)
+ cweb/common.w taken unaltered from CWEB 3.2
+ cweb/common.ch change file for common.w
+ cweb/common.c extracted with CTANGLE from common.{w,ch}
+ cweb/Makefile Makefile for CWEAVE (UNIX, OS/2, and DOS)
+ cweb/cweave.def definition file (needed for compiling under OS/2
+ only)
+ cweb/cwebmac.ori the standard cwebmac.tex file (slightly modified)
+ cweb/cwebmac.tex alternative format file
+ cweb/cwebmaca.tex this alternative format file is read by TeX if you
+ use the +a switch; similar to cwebmac.tex
+ cweb/prod-alt.w this file is an include file of cweave.ch; it
+ contains the alternative syntax rules of CWEAVE if
+ the switch a is on
+
+You should get the original CWEB package for further documentation; it
+contains change files for different operating systems also.
+
+
+Copying
+-------
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 as published by
+the Free Software Foundation.
+
+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.
+
+
+Installation
+------------
+
+The c2cweb executable should be in the path.
+
+The CWEAVE executable should also be in the path; it needs the file
+compiler.w (use the environment variable CWEBINPUTS to set the path).
+
+c2cweb.ger, cwebmac.tex and cwebmaca.tex must be found by TeX (the path is
+usually controlled by the TEXINPUT environment variable).
+
+DOS and WINDOWS users must assure that emx.exe and rsx.exe can be found
+(either in the path or set with the EMX and RSX environment variables).
+
+OS/2 users must assure that emx.dll and rsx.exe can be found (either in the
+path or set with the EMX and RSX environment variables).
+
+[emx.exe, emx.dll, and rsx.exe can be found in the the emxrsx.zip package of
+ the emTeX distribution.]
+
+
+Remarks for UNIX systems users
+------------------------------
+
+Because of the many different UNIX implementations, no executables are
+included. The programs should compile without great problems if you use the
+gcc compiler, the GNU C library and gnumake; you should say
+
+ make all OS=unix
+
+in the c2cweb directory to build the binaries.
+
+Included in the package you will already find .c files extracted with
+CTANGLE which can be directly used to compile.
+
+
+How to use
+----------
+
+The only change the user has to do normally is to insert /*@@*/, starting an
+empty line outside of a comment or string before the first function block
+(normally main(){ ... }) in the C code. After this command c2cweb writes
+each function block into a section. Before /*@@*/ all stuff is written into
+a (possibly large) section. If you want to structure this further or if you
+have structure definitions between functions, use /*@*/ to start a new
+section without starting the function block algorithm (and of course /*@@*/
+before the next function). The function algorithm simply counts paired
+braces; if none are open, a new section will begin. The file example.c has
+these control codes inserted already.
+
+
+The syntax is
+
+ c2cweb [switches] csourcefile(s) | @responsefile(s)
+
+The possible switches are:
+
+-v:
+ all comments are written in typewriter type. You will need this if you
+ have already formatted your comments, for example
+
+ /********************/
+ /* example.c */
+ /********************/.
+
+-t value:
+ all tabs will be expanded, and the -t switch defines the tab length
+ (default value is 4).
+
+-l:
+ causes all linefeeds inside of C text to be output explicitly by inserting
+ @/ (a CWEB control code) at the end of each code line.
+
+-o directory:
+ sets the output directory which must exist already.
+
+-f format_file:
+ include a format file (additionally to compiler.w).
+
+-b "titlestring":
+ defines a title with the titlestring enclosed in double quotes. This
+ string will be passed directly to \TeX.
+
+-1:
+ one-sided output (i.e. left header is the same as right header).
+
+
+The last steps are calling CWEAVE with the transformed master file and then
+calling TeX to get a printable .dvi-file.
+
+
+An example:
+
+ your input files are
+ header1.h, header2.h, file1.c, file2.c, file3.c
+
+ you must call then
+ c2cweb [options] header*.h file*.c
+
+ to get the *.*w files. c2cweb will now process your files and tells you
+ which file is the input file for CWEAVE (we'll assume file3.cw).
+
+ After calling
+ cweave [options] file3.cw
+
+ you get a .tex file (and some additional auxiliary files) which should
+ be processed further by PLAIN TeX (LaTeX is not supported):
+
+ tex file3[.tex]
+
+
+Please read the `Hints and Tricks' section about enhancements and
+limitations of c2cweb in the file c2cweb.w (say `make documentation' to
+build the .dvi file).
+
+
+Author
+------
+
+Werner Lemberg (a7971428@unet.univie.ac.at)
+
+Please report any errors, comments or suggestions to this email-address.
+
+ Werner Lemberg
+ Goldschlagstr. 52/14
+ A-1150 Vienna/Austria
+
+
+
+--------------------------------------------------------------------------------
+
+
+
+c2cweb Paket Version 1.5 (10-Nov-1996)
+=======================================
+
+Copyright (C) 1996 Werner Lemberg
+
+
+c2cweb verwandelt gewoehnlichen C - oder C++ - Quellcode in eine CWEB-Datei,
+um einen gut formatierten Ausdruck zu erhalten. Dieses Paket enthaelt
+ausserdem eine modifizierte Version von CWEAVE (welche die CWEB-Datei in
+eine TeX-Datei transformiert).
+
+Besonderheiten u.a.:
+
+ Variablen und Funktionsnamen in Kursivschrift
+ reservierte Woerter (int, char, return etc.) in Fettschrift
+ Strings in Schreibmaschinenschrift
+ Kommentare in Normal- oder Schreibmaschinenschrift
+ ein Index(!) aller Variablen, Konstanten, Funktionsnamen etc.
+ jede Funktion fuellt einen eigenen Abschnitt
+
+
+Das c2cweb-Paket enthaelt folgende Dateien:
+
+ c2cweb.txt diese Datei
+ history.txt Entstehungsgeschichte von c2cweb
+ Makefile ein Makefile fuer c2cweb (UNIX, OS/2 und DOS)
+ c2cweb.def Definitionsdatei (wird nur fuer die Kompilation
+ unter OS/2 gebraucht)
+ COPYING GNU Kopierlizenz
+ c2cweb.w die CWEB-Realisation dieses Programms
+ Um eine TeX .dvi-Datei zu erhalten sollte man
+ make documentation
+ eingeben (mit der CWEAVE-Version dieses Pakets)
+ c2cweb.c extrahiert mittels CTANGLE aus c2cweb.w
+ c2cweb.dvi die finale .dvi-Datei
+ c2cweb.exe ausfuehrbares Programm fuer DOS und OS/2
+ compiler.w Compiler-abhaengige Formatierbefehle (von c2cweb
+ erzeugte Dateien inkludieren diese Datei)
+ c2cweb.ger ein kleines Deutsch-`Paket', um die Unterstuetzung
+ von nichtenglischen Sprachen zu demonstrieren.
+ example.h
+ example.c ein C-Code-Beispiel mit bereits eingefuegten
+ c2cweb-Kontrollbefehlen
+ cweb/cweave.exe eine modifizierte Version von CWEAVE Version 3.2
+ (fuer DOS und OS/2) mit drei wichtigen neuen
+ Eigenschaften:
+
+ o mit der Option +a formatiert CWEAVE den
+ Quellcode anders, und zwar im Prinzip
+
+ if(a)
+ {bla bla bla...
+ }
+
+ anstelle von
+
+ if(a) {
+ bla bla bla...
+ }
+
+ o die Option +i veranlasst CWEAVE, jedem
+ Funktionsnamen () im Index anzuhaengen (nur
+ sinnvoll, wenn alle Namen eindeutig sind)
+ o die Behandlung von Praeprozessorbefehlen
+ (#define etc.) wurde entscheidend verbessert, um
+ Makros mit Parametern zu ermoeglichen
+ cweb/cweave.w die originale CWEAVE Quelldatei aus Levy's
+ CWEB-Paket Version 3.2 (Juli 1994)
+ cweb/cweave.ch Change-Datei fuer cweave.w
+ cweb/cweave.c extrahiert aus cweave.{w,ch} mittels CTANGLE
+ cweb/common.h wird benoetigt fuer die Kompilation von cweave.exe
+ (Original wurde etwas modifiziert)
+ cweb/common.w unveraendert von CWEB 3.2 uebernommen
+ cweb/common.ch Change-Datei fuer common.w
+ cweb/common.c extrahiert aus common.{w,ch} mittels CTANGLE
+ cweb/Makefile Make-Datei fuer CWEAVE (UNIX, OS/2 und DOS)
+ cweb/cweave.def Definitionsfile (wird nur fuer die Kompilation unter
+ OS/2 gebraucht)
+ cweb/cwebmac.ori urspruengliche cwebmac.tex-Datei (leicht veraendert)
+ cweb/cwebmac.tex alternative Formatdatei
+ cweb/cwebmaca.tex diese alternative Formatdatei wird von TeX gelesen,
+ wenn die +a-Option angegeben ist; sonst gleich zu
+ cwebmac.tex
+ cweb/prod-alt.w diese Datei ist eine Include-Datei von cweave.ch;
+ sie enthaelt die alternativen Syntaxregeln, falls
+ Option +a verwendet wird
+
+Es ist empfehlenswert, sich das originale CWEB-Paket zu besorgen, welches
+weitere Dokumentation enthaelt. Ausserdem sind Change-Dateien fuer andere
+Betriebssysteme enthalten.
+
+
+Installation
+------------
+
+c2cweb (c2cweb.exe fuer DOS und OS/2 Benutzer) sollte im Pfad sein.
+
+CWEAVE (cweave.exe fuer DOS und OS/2 Benutzer) sollte auch im Pfad sein; es
+braucht die Datei compiler.w (die Umgebungsvariable CWEBINPUTS setzt den
+Pfad).
+
+TeX muss die Dateien c2cweb.ger, cwebmac.tex und cwebmaca.tex finden koennen
+(der Pfad wird normalerweise von der TEXINPUT-Umgebungsvariablen
+kontrolliert).
+
+DOS und WINDOWS Benuetzer muessen sicherstellen, dass emx.exe und rsx.exe
+gefunden werden koennen (entweder im Pfad oder durch die Umgebungsvariablen
+EMX und RSX bestimmt).
+
+OS/2 Benuetzer muessen sicherstellen, dass emx.dll und rsx.exe gefunden
+werden koennen (entweder im Pfad oder durch die Umgebungsvariablen EMX und
+RSX bestimmt).
+
+[emx.dll, emx.exe und rsx.exe koennen im Paket exmrsx.zip gefunden werden,
+ das Bestandteil von emTeX ist.]
+
+
+Bemerkungen fuer UNIX Benutzer
+------------------------------
+
+Aufgrund der vielen verschiedenen UNIX-Systeme sind keine ausfuehrbaren
+Dateien inkludiert. Die Programme sollten ohne groessere Probleme
+kompilierbar sein, wenn gcc, die GNU C-Bibliothek und gnumake verwendet
+wird.
+
+ make all OS=unix
+
+im c2cweb- und cweb-Verzeichnis erstellt die ausfuehrbaren Dateien.
+
+In diesem Paket befinden sich bereits mittels CTANGLE extrahiert .c Dateien,
+die man direkt kompilieren kann.
+
+
+Verwendung
+----------
+
+Die einzige Veraenderung, die der Anwender normalerweise machen muss, ist
+das Einfuegen von /*@@*/ am Anfang einer leeren Zeile ausserhalb eines
+Kommentars oder Strings vor dem ersten Funktionsblock (das ist in der Regel
+main(){ ...}) im C-Quellcode. Nach diesem Befehl erzeugt c2cweb fuer jede
+Funktion einen eigenen Abschnitt. Vor /*@@*/ wird alles in eine einzige
+(u.U. grosse) Sektion geschrieben. Will man solche Abschnitte zusaetzlich
+strukturieren oder hat man Struktur-Definitionen zwischen Funktionen, sollte
+man /*@*/ verwenden, um einen neuen Abschnitt zu beginnen, ohne den
+Funktionsalgorithmus einzuschalten (und natuerlich /*@@*/ vor der naechsten
+Funktion einfuegen). Der Funktionsalgorithmus zaehlt einfach paarweise
+geschwungene Klammern; falls keine mehr offen, wird ein neuer Abschnitt
+begonnen. In der Beispieldatei example.c sind diese Kontrollcodes bereits
+enthalten.
+
+
+Aufruf:
+
+ c2cweb [Optionen] C-Quelldatei(en) | @Response-Datei(en)
+
+Folgende Optionen sind moeglich:
+
+-v:
+ alle Kommentare werden in Schreibmaschinenschrift ausgegeben. Dieser
+ Schalter ist notwendig, falls die Kommentare bereits formatiert sind, zum
+ Beispiel
+
+ /********************/
+ /* example.c */
+ /********************/.
+
+-t Wert:
+ all Tabulator-Stopps werden expandiert; -t Wert definiert die
+ Tabulatorweite (Grundeinstellung: Wert=4).
+
+-l:
+ Zeilenumbrueche in der Eingabe innerhalb von C-Text bleiben in der Ausgabe
+ erhalten durch explizites Anhaengen von @/ (einem CWEB Kontrollcode) an
+ jede Code-Zeile.
+
+-o Verzeichnis
+ definiert das Ausgabeverzeichis (muss bereits existieren).
+
+-o Format-Datei
+ Inkludiert (zusaetzlich zu compiler.w) eine Format-Datei
+
+-b "Titel":
+
+definiert einen Titel (in doppelten Anfuehrungszeichen). Dieser String wird
+direkt an TeX weitergegeben.
+
+-1:
+ einseitige Ausgabe (d.h., linker Seitenkopf wird dem rechten Seitenkopf
+ gleichgesetzt).
+
+
+Die letzten Schritte sind das Aufrufen von CWEAVE mit der transformierten
+Hauptdatei und danach der Aufruf von TeX, um eine druckfaehige .dvi-Datei zu
+erhalten.
+
+
+Ein Beispiel:
+
+ die Eingabedateien:
+ header1.h, header2.h, file1.c, file2.c, file3.c
+
+ Man muss jetzt
+ c2cweb [Optionen] header*.h file*.c
+
+ aufrufen, um die *.*w-Dateien zu erhalten. c2cweb bearbeitet jetzt alle
+ Eingabedateien und teilt mit, welche Datei die Eingabedatei fuer CWEAVE
+ ist (hier im Beispiel sei es file3.cw).
+
+ Nach dem Aufruf
+ cweave [Optionen] file3.cw
+
+ erhaelt man eine .tex-Datei (und einige zusaetzliche Hilfsdateien), die
+ mit PLAIN TeX weiterverarbeitet werden muss (LaTeX wird nicht
+ unterstuetzt):
+
+ tex file3[.tex]
+
+
+Im Abschnitt `Hints and Tricks' in der Datei c2cweb.w werden weitere
+Verbesserungen und Beschraenkungen von c2cweb beschrieben (der Aufruf `make
+documentation' erzeugt die .dvi-Datei).
+
+
+Autor
+-----
+
+Werner Lemberg (a7971428@unet.univie.ac.at)
+
+Bitte alle Fehler, Kommentare oder Bemerkungen an obige email-Adresse
+schicken.
+
+ Werner Lemberg
+ Goldschlagstr. 52/14
+ A-1150 Vienna/Austria
+
+
+--- end of c2cweb.txt ---
diff --git a/web/c_cpp/c2cweb/c2cweb.w b/web/c_cpp/c2cweb/c2cweb.w
new file mode 100644
index 0000000000..eb3b0e7691
--- /dev/null
+++ b/web/c_cpp/c2cweb/c2cweb.w
@@ -0,0 +1,1406 @@
+% This is the cweb file c2cweb Version 1.5 10-Nov-1996
+%
+% You should process this file with
+%
+% cweave +ai c2cweb.w
+
+\pageno=\contentspagenumber \advance\pageno by 1
+\let\maybe=\iftrue
+\fullpageheight=240mm
+\pageheight=223mm
+\pagewidth=158mm
+\setpage
+\frenchspacing
+\def\in{\leavevmode\vrule width 0pt\nobreak\hskip 2em\hskip 0pt} % indentation
+\font\sixrm=cmr6
+\def\tm{$^{\hbox{\sixrm TM}}$} % trademark
+
+\def\title{c2cweb (Version 1.5)}
+
+\def\topofcontents{%
+ \null\vfill
+ \centerline{\titlefont The {\ttitlefont c2cweb} program}
+ \vskip 20pt
+ \centerline{(Version 1.5)}
+ \vfill}
+
+\def\botofcontents{%
+ \vfill
+ \noindent
+ Copyright \copyright\ 1996 by Werner Lemberg
+ \bigskip\noindent
+ Permission is granted to make and distribute verbatim copies of this
+ document provided that the copyright notice and this permission notice are
+ preserved on all copies.
+
+ \smallskip\noindent
+ Permission is granted to copy and distribute modified versions of this
+ document 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.}
+
+
+
+@* Introduction.
+This is the \.{c2cweb} program by Werner Lemberg
+(\.{a7971428@@unet.univie.ac.at}).
+
+The ``banner line'' defined here should be changed whenever \.{c2cweb} is
+modified.
+
+@d banner "\nThis is c2cweb Version 1.5 (c) 1996 by Werner Lemberg\n\n"
+
+
+@
+\.{c2cweb} will transform ordinary \CEE/ or \CPLUSPLUS/ source code into
+\.{CWEB} formatted code. Three primary functions are performed: inserting
+\.{@@}-commands between code blocks, transforming comments into \TeX-text,
+and replacing offending characters like \.{\\}, \.{\_}, \.{\&} etc. with
+commands \TeX\ (and \.{CWEB}) can understand.
+
+The only changes the user has to do normally is to insert `\.{/*@@@@*/}' or
+`\.{/*@@*/}' \\{starting a line} outside of a comment or string (the rest of
+these lines will be ignored):
+
+\advance\leftskip by 3em
+
+ \item{$\bullet$} \.{/*@@@@*/} starts a new section and switches the
+ function block algorithm on (see below).
+
+ \item{$\bullet$} \.{/*@@*/} starts a new section and switches the
+ function block algorithm off. This is the default when \.{c2cweb}
+ begins to scan a file.
+
+\advance\leftskip by -3em
+
+Both `commands' will be suppressed in the output (two additional commands
+are described in the `Hints and Tricks'-section).
+
+
+@
+Normal \CEE/ code consists of two parts: the code before function blocks
+(\.{\#include} and \.{\#define} statements, prototypes, structure
+definitions, global variables, etc.) and the function blocks (i.e.
+\.{foo()\{ ... \}}) itselves (possibly mixed with global definitions of
+variables, structures etc.). The main reason to separate them are memory
+constraints of \.{CWEAVE}; inserting \.{/*@@@@*/} causes each function block
+to be written into an own section.
+
+In header files, nothing is to do because there are no function blocks. In
+\CEE/ code files, it's usually sufficient to insert \.{/*@@@@*/} once, but
+you can structure your code further by inserting \.{/*@@*/} (and
+\.{/*@@@@*/} if necessary). See also the example file delivered with this
+package.
+
+You will need a special \.{CWEAVE} executable which has among others two
+additional control codes sometimes needed. See also the section `Hints and
+Tricks'.
+
+From now on, the words \.{CWEB} and \.{CWEAVE} will be used mutually in
+spite of the fact that \.{CWEB} consists of both the programs \.{CWEAVE} and
+\.{CTANGLE}---\.{c2cweb} is intended to create a well printed listing, and
+the use of \.{CTANGLE} is of course possible but senseless.
+
+
+
+@* The program.
+The use of |_response()|, |_wildcard()|, and |_getname()| is compiler
+specific. If you don't use emx-gcc, it's likely that you have to use
+different functions. If you use this program under DOS, consider the
+\UNIX/-like behavior of the ``|*|''-wildcard character.
+
+After processing the options, the global variable |optind| (defined in
+\.{getopt.h}) is the index to the first file name.
+
+@d FALSE 0
+@d TRUE 1
+@d DONE 2
+@d WAIT 3
+
+@c
+@<Include files@>;
+@<Prototypes@>;
+@<Global variables@>;@#
+
+void main(argc, argv)
+ int argc;
+ char *argv[];
+
+ {int i;
+ char buffer[DIR_LENGTH + FILE_NAME_LENGTH + 1];
+ char *p, *q;
+
+
+ printf(banner);@#
+
+#ifdef __EMX__
+ _response(&argc, &argv); /* to expand response files */
+ _wildcard(&argc, &argv); /* to expand wildcards */
+#endif@#
+
+ @<Get command switches@>;@#
+
+ @<Processing all files except the last one@>;
+ @<Processing the last file@>;@#
+
+ fclose(in);
+ fclose(out);
+ }
+
+
+@
+\.{getopt.h} contains the \UNIX/-specific |getopt()|. If your system doesn't
+support this function, get the GNU \CEE/-library for an implementation.
+
+@<Include files@>=
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+@
+@<Processing all files except the last one@>=
+ for (i = optind; i < argc - 1; i++)
+ {printf(" processing %s\n", argv[i]);@#
+
+ open_files(argv[i]);
+ q = protect_underlines(_getname(argv[i]));
+ if ((p = strrchr(q, '.')) != NULL)
+ /* the macro \.{\\ZZZ} suppresses the final dot after
+ the section title if the filename contains a dot */
+ fprintf(out,@/
+ "@@*{%s\\ZZZ{\\setbox0=\\hbox{%s}\\hskip-\\wd0}}.\n"@/
+ "\\ind=2\n\n", q, p);
+ else
+ fprintf(out, "@@*{%s}.\n"@/
+ "\\ind=2\n\n", q);@#
+
+ handle_input();
+ fclose(in);
+ fclose(out);
+ }
+
+
+@
+The last file will be the `master' file; you have to call \.{CWEAVE} with
+this file as the argument; all other files will be included.
+
+@<Processing the last file@>=
+ printf(" processing %s\n", argv[i]);@#
+
+ open_files(argv[i]);
+ @<Write limbo@>;
+ q = protect_underlines(_getname(argv[i]));
+ if ((p = strrchr(q, '.')) != NULL)
+ fprintf(out,@/
+ "@@*{%s\\ZZZ{\\setbox0=\\hbox{%s}\\hskip-\\wd0}}.\n"@/
+ "\\ind=2\n\n", q, p);
+ else
+ fprintf(out, "@@*{%s}.\n"@/
+ "\\ind=2\n\n", q);@#
+
+ handle_input();
+ @<Write index section@>;@#
+
+ strcpy(buffer, argv[argc - 1]);
+ modify_filename(buffer);@#
+
+ printf(@/
+ "\n You must now call CWEAVE with %s%s\n"@/
+ " as the argument to get a TeX output", outdir, _getname(buffer));
+ if (optind < argc - 1)
+ printf(" of all processed files");
+ printf("\n");
+
+
+
+@*1 The input switches.
+If the switch \.{-v} is set, all comments are written in typewriter type;
+comments starting a line will also start a line in the output.
+
+All tabs will be expanded, and the \.{-t} switch defines the tab length
+(default value is 4).
+
+The switch \.{-l} causes all linefeeds inside of \CEE/-text to be output
+explicitly by inserting a \.{@@/} command at the end of each code line.
+
+The output directory will be set with the \.{-o} option; this directory must
+already exist. Probably you have to adjust |PATH_SEPARATOR| and
+|pathsepchar[]| to make it work correctly under your operating system.
+
+To get a title, use the \.{-b} switch with the titlestring enclosed in
+double quotes; this string will be passed directly to \TeX.
+
+To include a format file (additionally to \.{compiler.w}), use the \.{-f}
+switch.
+
+One-sided output is enabled with the option \.{-1} set.
+
+The global variable |optarg| (defined in \.{getopt.h}) points to the option
+argument; the string |optswchar[]| is modified to allow |'-'| and |'/'| as
+characters which start options (not under \UNIX/).
+
+@d DIR_LENGTH 80
+@d TITLE_LENGTH 100
+@d PATH_SEPARATOR '/'
+
+@<Global...@>=
+int tab_length = 4;
+int verbatim = FALSE;
+int user_linefeed = FALSE;
+int one_side = FALSE;
+char outdir[DIR_LENGTH + 1];
+char include_file[FILE_NAME_LENGTH + 1];
+char title[TITLE_LENGTH + 1];@#
+
+#ifdef __EMX__
+char optchar[] = "-/";
+char pathsepchar[] = "\\/";
+#else
+char optchar[] = "-";
+char pathsepchar[] = "/";
+#endif@#
+
+char at_nmb[] = "@@#";
+ /* the \.{CWEB} command for inserting vertical space */
+
+
+@
+@<Get command switches@>=
+ {int c;
+ int i;
+
+
+ outdir[0] = '\0';
+ include_file[0] = '\0';
+ title[0] = '\0';@#
+
+#ifdef __EMX__
+ optswchar = optchar;
+#endif@#
+
+ strcpy(title, "c2cweb output"); /* the default title */@#
+
+ while ((c = getopt(argc, argv, "b:f:lo:t:v1")) != EOF)
+ {switch (c)
+ {case 'b':
+ if (strchr(optchar, optarg[0]))
+ /* check if argument is an option */
+ usage();@#
+
+ if (strlen(optarg) >= TITLE_LENGTH)
+ fprintf(stderr,@/
+ "\nTitle too long. Will use \"c2cweb output\".\n");
+ else
+ strcpy(title, optarg);
+ break;
+ case 'f':
+ if (strchr(optchar, optarg[0]))
+ usage();@#
+
+ if (strlen(optarg) >= FILE_NAME_LENGTH)
+ fprintf(stderr,@/
+ "\nInclude file name too long. Will be ignored.\n");
+ else
+ strcpy(include_file, optarg);
+ break;
+ case 'l':
+ user_linefeed = TRUE;
+ break;
+ case 'o':
+ if (strchr(optchar, optarg[0]))
+ usage();@#
+
+ if ((i = strlen(optarg)) >= DIR_LENGTH)
+ fprintf(stderr,@/
+ "\nOutput directory name too long. Will be ignored.\n");
+ else
+ {strcpy(outdir, optarg);
+ if (!strchr(pathsepchar, outdir[i - 1]))
+ /* check if last character is a path separator */
+ {outdir[i] = PATH_SEPARATOR;
+ outdir[i + 1] = '\0';
+ }
+ }
+ break;
+ case 't':
+ if (strchr(optchar, optarg[0]))
+ usage();@#
+
+ tab_length = atoi(optarg);
+ if (tab_length == 0 || tab_length > 8)
+ tab_length = 4; /* default value */
+ break;
+ case 'v':
+ verbatim = TRUE;
+ break;
+ case '1':
+ one_side = TRUE;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }@#
+
+ if (optind == argc)
+ usage();
+ }
+
+
+@
+The output file has the same name as the input file but a different
+extension: it will append a \.{w} or, if the extension is three characters
+long, substitute the third character with a \.{w}, i.e. \.{.c} becomes
+\.{.cw}, \.{.h} becomes \.{.hw}, \.{.cpp} will be replaced by \.{.cpw} and
+so on (notice that for example \.{.cppp} also becomes \.{.cpw}). If the
+character to be changed is a \.{w}, an \.{x} is used instead of. This will
+be done by the function |modify_filename()|. No checking for overwriting
+existing files is done.
+
+@d FILE_NAME_LENGTH 80
+
+@<Global...@>=
+ FILE *in, *out;
+
+
+@
+@<Prototypes@>=
+void open_files(char *);
+
+@
+@c
+void open_files(filename)
+ char *filename;
+ {char buffer[DIR_LENGTH + FILE_NAME_LENGTH + 1];
+
+
+ if (strlen(filename) > FILE_NAME_LENGTH - 2)
+ {fprintf(stderr, "\n File name too long.\n");
+ exit(-1);
+ }@#
+
+ if ((in = fopen(filename, "rt")) == NULL)
+ {fprintf(stderr, "\n Can't open input file %s\n", filename);
+ exit(-1);
+ }@#
+
+ strcpy(buffer, outdir);
+ strcat(buffer, filename);
+ modify_filename(buffer);@#
+
+ if ((out = fopen(buffer, "wt")) == NULL)
+ {fprintf(stderr, "\n Can't open output file %s\n", buffer);
+ exit(-1);
+ }
+ }
+
+
+
+@*1 The output header.
+This is the header of the last output file. You must call \.{CWEAVE} with
+this file as an argument---all other processed files will be included.
+
+Additionally this `master' file will include the file \.{compiler.w}, which
+should contain all system dependent definitions (like \.{va\_decl} or
+\.{va\_arg}) not contained in the \.{CWEAVE} program. The syntax of
+\.{compiler.w} is \.{CWEB} syntax; please read the documentation if you have
+questions. You should set the environment variable |CWEBINPUTS| used by
+\.{CWEAVE} (and \.{CTANGLE}) to the directory where \.{compiler.w} resides.
+
+The function |_getname()| will accept forward and backward slashes as path
+separators if you compile under emx. However, options can be introduced with
+|'-'| and |'/'|, therefore paths starting with a forward slash must be
+enclosed in double quotes (not under \UNIX/).
+
+@<Write limbo@>=
+ fprintf(out,@/
+ "\\font\\symb=cmsy10\n"@/
+ "\\font\\math=cmmi10\n"@/
+ "\\def\\ob"@/
+ "{\\parskip=0pt\\parindent=0pt%%\n"@/
+ "\\let\\\\=\\BS\\let\\{=\\LB\\let\\}=\\RB\\let\\~=\\TL%%\n"@/
+ "\\let\\ =\\SP\\let\\_=\\UL\\let\\&=\\AM\\let\\^=\\CF%%\n"@/
+ "\\obeyspaces\\frenchspacing\\tt}\n"@/
+ "\n"@/
+ "\\def\\e{\\hfill\\break\\hbox{}}\n"@/
+ "\\def\\{{\\relax\\ifmmode\\lbrace\\else$\\lbrace$\\fi}\n"@/
+ "\\def\\}{\\relax\\ifmmode\\rbrace\\else$\\rbrace$\\fi}\n"@/
+ "\\def\\takenone#1{\\hskip-0.1em}\n"@/
+ "\\let\\ZZZ=\\relax\n"@/
+ "\n"@/
+ "%s"@/
+ "\n"@/
+ "\\pageno=\\contentspagenumber \\advance\\pageno by 1\n"@/
+ "\\let\\maybe=\\iftrue\n"@/
+ "\n"@/
+ "\\def\\title{%s}\n"@/
+ "\n"@/
+ "@@i compiler.w\n"@/
+ "\n", one_side ? "\\let\\lheader=\\rheader\n" : "", title);@#
+
+ if (*include_file)
+ fprintf(out,@/
+ "@@i %s\n"@/
+ "\n", include_file);@#
+
+ for (i = optind; i < argc - 1; i++)
+ {strcpy(buffer, argv[i]);
+ modify_filename(buffer);@#
+
+ fprintf(out, "@@i %s\n", _getname(buffer));
+ }@#
+
+ fputc('\n', out);@#
+
+
+
+@*1 Input Handling.
+
+@d BUFFER_LENGTH 500
+
+@<Prototypes@>=
+void handle_input(void);
+
+
+@
+This is a wild hack. Perhaps in a future version I will improve it.
+
+@<Global...@>=
+char buffer[BUFFER_LENGTH + 1];
+
+@
+The main routine. Characters which will be treated in a special way by
+\.{CWEB} and \TeX\ are handled within a great switch.
+
+@d xisspace(c) (isspace(c) && ((unsigned char)c < 0200))
+
+@c
+void handle_input(void)
+ {char *buf_p;
+ char ch;
+ @<Control flags@>;
+
+ line_number = 0;
+ while (get_line())
+ {buf_p = buffer;@#
+
+ do
+ {ch = *buf_p;@#
+
+ @<Special cases@>;@#
+
+ switch (ch)
+ {case ' ':
+ if (leading_blanks)
+ {blank_count++;
+ goto end;
+ }
+ break;@#
+
+ case '\t':
+ {int i = tab_length - (column % tab_length);
+
+ column += i - 1; /* we'll say later |column++| */@#
+
+ if (leading_blanks)
+ {blank_count += i;
+ goto end;
+ }@#
+
+ while (i--)
+ fputc(' ', out);
+ goto end;
+ }
+ break;@#
+
+ case '{':
+ @<Cases for |'{'|@>;
+ break;@#
+
+ case '}':
+ @<Cases for |'}'|@>;
+ break;@#
+
+ case '/':
+ @<Cases for |'/'|@>;
+ break;@#
+
+ case '*':
+ @<Cases for |'*'|@>;
+ break;@#
+
+ case '\n':
+ @<Cases for |'\n'|@>;
+ break;@#
+
+ case '@@':
+ @<Cases for |'@@'|@>;
+ break;@#
+
+ case '\'':
+ @<Cases for |'\''|@>;
+ break;@#
+
+ case '\"':
+ @<Cases for |'\"'|@>;
+ break;@#
+
+ case '\\':
+ @<Cases for |'\\'|@>;
+ break;@#
+
+ default:
+ @<Cases for |default|@>;
+ break;
+ }@#
+
+ fputc(ch, out);@#
+
+end:
+ buf_p++;
+ column++;
+ } while(ch != '\n');
+ }
+ }
+
+
+@
+@<Control flags@>=
+ int any_input = FALSE;
+ /* set after the first non blank character in a new section */
+ int brace_count = 0;
+ int blank_count = 0;@#
+
+ int in_comment = FALSE;
+ int in_C = FALSE;
+ int in_string = FALSE;
+ int short_comment = FALSE;
+ int leading_blanks = TRUE;
+ int double_linefeed = FALSE; /* set if last character was a linefeed */
+ int linefeed_comment = FALSE;
+ /* set if a comment follows a linefeed immediately */
+ int comment_slash = FALSE; /* set if last character was a slash */
+ int comment_star = FALSE; /* set if last character was a star */
+ int escape_state = FALSE;
+ /* needed to check whether in string or
+ at the end of a preprocessor line */
+ int before_TeX_text = FALSE;
+ /* the state after leaving a function block */
+ int function_blocks = FALSE; /* set if function block algorithm is on */
+
+
+@
+Here comes a bunch of |if|-statements.
+
+@<Special cases@>=
+ @<Check conditions while at start of a line@>;@#
+
+ if (double_linefeed && ch == '/')
+ linefeed_comment = TRUE;@#
+
+ if (double_linefeed && (ch == ' ' || ch == '\t'))
+ leading_blanks = TRUE;@#
+
+ if (ch != '\n') /* multiple linefeed ? */
+ double_linefeed = FALSE;@#
+
+ if (!xisspace(ch)) /* whitespaces ? */
+ {any_input = TRUE;@#
+
+ if (before_TeX_text && function_blocks)
+ {before_TeX_text = FALSE;@#
+
+ if (function_blocks == WAIT)
+ function_blocks = TRUE;
+ /* start at the second occurrence */
+ else
+ {fputs("@@\n"@/
+ "\\ind=2\n\n", out);
+ /* start a new text section */@#
+
+ if (leading_blanks)
+ {leading_blanks = FALSE;@#
+
+ while (blank_count--)
+ fputc(' ', out);
+ blank_count = 0;
+ }
+ }
+ }@#
+
+ if (in_comment && leading_blanks)
+ {leading_blanks = FALSE;@#
+
+ while (blank_count--)
+ fputc(' ', out);
+ blank_count = 0;
+ }
+ }@#
+
+ if (!(ch == '/' || xisspace(ch)))
+ /* whitespace or possible start of comment ? */
+ {if (!(in_comment || in_C || comment_slash))
+ /* outside of code ? */
+ {in_C = TRUE;@#
+
+ fputs("@@c\n", out); /* start of a new code section */@#
+
+ if (leading_blanks)
+ {leading_blanks = FALSE;@#
+
+ while (blank_count--)
+ fputc(' ', out);
+ blank_count = 0;
+ }
+ }@#
+
+ if (!(in_comment || comment_slash) && leading_blanks)
+ {leading_blanks = FALSE;@#
+
+ while (blank_count--)
+ fputc(' ', out);
+ blank_count = 0;
+ }
+ }@#
+
+ if (comment_slash && !(ch == '*' || ch == '/'))
+ /* start of a comment ? */
+ {comment_slash = FALSE;
+ if (!in_comment)
+ linefeed_comment = FALSE;@#
+
+ fputc('/', out);
+ }@#
+
+ if (comment_star && ch != '/') /* end of a comment ? */
+ {comment_star = FALSE;@#
+
+ fputc('*', out);
+ }@#
+
+ if (escape_state && !(ch == '\"' || ch == '\n' || ch == '\\'))
+ /* end of string or end of preprocessor line or backslash itself ? */
+ escape_state = FALSE;@#
+
+
+@
+@<Check conditions while at start of a line@>=
+ if (buf_p == buffer)
+ {if (!(in_comment || in_string))
+ {if (!strncmp(buf_p, "/""*@@@@*""/", 6))
+ {in_C = FALSE;
+ before_TeX_text = TRUE;
+ function_blocks = WAIT; /* switch on the algorithm */
+ brace_count = 0;@#
+
+ if (any_input)
+ fputs("\n@@\n"@/
+ "\\ind=2\n\n", out);
+ /* start a new section */@#
+
+ any_input = FALSE;
+ *(buf_p--) = '\n';
+ /* the rest of the line will be ignored */
+ goto end;
+ }
+ else if (!strncmp(buf_p, "/""*@@*""/", 5))
+ {in_C = FALSE;
+ before_TeX_text = TRUE;
+ function_blocks = FALSE; /* switch off the algorithm */@#
+
+ if (any_input)
+ fputs("\n@@\n"@/
+ "\\ind=2\n\n", out);@#
+
+ any_input = FALSE;
+ *(buf_p--) = '\n';
+ goto end;
+ }
+ else if (!strncmp(buf_p, "/""*{*""/", 5))
+ {brace_count++; /* a dummy opening brace */
+ fputs("@@{\n", out);@#
+
+ ch = '\n'; /* an end of line is simulated */
+ goto end;
+ }
+ else if (!strncmp(buf_p, "/""*}*""/", 5))
+ {brace_count--; /* a dummy closing brace */
+ fputs("@@}\n", out);@#
+
+ if (!brace_count && function_blocks)
+ /* end of function block reached ? */
+ {in_C = FALSE;
+ before_TeX_text = TRUE;@#
+
+ break;
+ }@#
+
+ ch = '\n';
+ goto end;
+ }
+ else if (!strncmp(buf_p, "/""*{}*""/", 6))
+ {fputs("@@{@@}\n", out);@# /* a dummy function body */
+
+ ch = '\n';
+ goto end;
+ }
+ }
+ }
+
+
+@
+@<Cases for |'{'|@>=
+ if (in_comment)
+ fputc('\\', out);
+ else if (in_string)
+ break;
+ else if (function_blocks)
+ {brace_count++;
+ in_C = TRUE;
+ }
+
+@
+@<Cases for |'@@'|@>=
+ if (in_comment)
+ {fputs("{\\char64}", out);
+ goto end;
+ }
+ else /* \.{CWEB} needs \.{@@@@} to output \.{@@} */
+ fputc('@@', out);
+
+@
+@<Cases for |'\''|@>=
+ if (!in_comment)
+ {if (*(buf_p + 1) == '\"' && *(buf_p + 2) == '\'')
+ escape_state = TRUE; /* this catches |'"'| */
+ }
+
+@
+@<Cases for |'\"'|@>=
+ if (!in_comment) /* start or end of a string ? */
+ {if (escape_state)
+ escape_state = FALSE;
+ else
+ in_string = TRUE - in_string;
+ }
+
+@
+@<Cases for |'\\'|@>=
+ if (in_comment)
+ {fputs("{\\symb\\char110}", out);
+ goto end;
+ }
+ else
+ escape_state = TRUE - escape_state;
+ /* continuation of preprocessor line or
+ an escape character */
+
+@
+@<Cases for |'}'|@>=
+ if (in_comment)
+ fputc('\\', out);
+ else if (in_string)
+ break;
+ else if (function_blocks)
+ {brace_count--;
+ if (!brace_count) /* end of function block reached ? */
+ {in_C = FALSE;@#
+
+ before_TeX_text = TRUE;
+ break;
+ }
+ }
+
+@
+@<Cases for |'/'|@>=
+ if (comment_star)
+ {@<Cases for |'*/'|@>;
+ }
+ else if (comment_slash)
+ {@<Cases for |'//'|@>;
+ }
+ else
+ {comment_slash = TRUE;@#
+
+ goto end;
+ }
+
+@
+@<Cases for |'*/'|@>=
+ comment_star = FALSE;
+ leading_blanks = FALSE;@#
+
+ if (!short_comment)
+ {in_comment = FALSE; /* end of comment */@#
+
+ if (!in_C)
+ {linefeed_comment = FALSE;@#
+
+ if (verbatim) @q { @>
+ fputs("*""/}", out);@#
+
+ if (*(buf_p + 1) == '\n') /* end of line ? */
+ fputs("\\e{}%", out);@#
+
+ goto end;
+ }
+
+ if (in_C && verbatim)
+ {if (linefeed_comment)
+ {linefeed_comment = FALSE;@#
+
+ fputs("*""/@@>", out);
+ if (*(buf_p + 1) == '\n' && !user_linefeed)
+ fputs("@@/", out);
+ goto end;
+ }
+ else @q { @>
+ fputc('}', out);@#
+ }@#
+
+ linefeed_comment = FALSE;@#
+
+ if (in_C || verbatim)
+ fputc('*', out);
+ else
+ goto end;
+ }
+ else
+ fputc('*', out);
+
+@
+@<Cases for |'//'|@>=
+ comment_slash = FALSE;@#
+
+ if (!short_comment)
+ {in_comment = TRUE;
+ short_comment = TRUE; /* start of a short comment */@#
+
+ if (!in_C && verbatim)
+ {fputs("{\\ob{}", out); @q } @>
+ if (leading_blanks)
+ {leading_blanks = FALSE;@#
+
+ while (blank_count--)
+ fputc(' ', out);
+ blank_count = 0;
+ }
+ fputs("//", out);@#
+
+ goto end;
+ }@#
+
+ if (in_C && verbatim)
+ {if (leading_blanks || linefeed_comment)
+ {linefeed_comment = TRUE;@#
+
+ if (!user_linefeed)
+ fputs("@@/", out); @q { @>
+ fputs("@@t}\\8{\\ob{}", out); @q } @>
+ /* this cryptic command starts a
+ comment line without indentation */
+ if (leading_blanks)
+ {leading_blanks = FALSE;@#
+
+ while (blank_count--)
+ fputc(' ', out);
+ blank_count = 0;
+ }
+ fputs("//", out);
+ }
+ else
+ fputs("//{\\ob{}", out);@# @q } @>
+
+ goto end;
+ }@#
+
+ if (in_C || verbatim)
+ fputc('/', out);
+ else
+ goto end;
+ }
+ else
+ fputc('/', out);
+
+
+@
+@<Cases for |'*'|@>=
+ if (comment_slash)
+ {comment_slash = FALSE;@#
+
+ if (in_comment && !short_comment)
+ /* uuh, ooh, for people who `comment
+ out' code with comments instead of
+ using \.{\#if 0} and \.{\#endif} for
+ example---this non-ANSI behaviour
+ would cause bad formatted code and is
+ therefore not supported; the program
+ exits */
+ {fprintf(stderr,
+ " Error line %d: Nested comments not supported\n",
+ line_number);
+ exit(-1);
+ }@#
+
+ if (!short_comment)
+ {in_comment = TRUE; /* start of comment */@#
+
+ if (!in_C && verbatim)
+ {fputs("{\\ob{}", out); @q } @>
+ if (leading_blanks)
+ {leading_blanks = FALSE;@#
+
+ while (blank_count--)
+ fputc(' ', out);
+ blank_count = 0;
+ }
+ fputs("/""*", out);@#
+
+ goto end;
+ }@#
+
+ if (in_C && verbatim)
+ {if (leading_blanks || linefeed_comment)
+ {linefeed_comment = TRUE;
+
+ if (!user_linefeed)
+ fputs("@@/", out); @q { @>
+ fputs("@@t}\\8{\\ob{}", out); @q } @>
+ if (leading_blanks)
+ {leading_blanks = FALSE;@#
+
+ while (blank_count--)
+ fputc(' ', out);
+ blank_count = 0;
+ }
+ fputs("/""*", out);
+ }
+ else
+ fputs("/""*{\\ob{}", out);@# @q } @>
+
+ goto end;
+ }@#
+
+ if (in_C || verbatim)
+ fputc('/', out);
+ else
+ {fputs(" ", out);@#
+
+ goto end;
+ }
+ }
+ else
+ fputc('/', out);
+ }
+ else
+ {comment_star = TRUE;@#
+
+ goto end;
+ }
+
+
+@
+@<Cases for |'\n'|@>=
+ blank_count = 0;@#
+
+ if (!in_comment && in_C)
+ {if (double_linefeed == FALSE)
+ {double_linefeed = TRUE;
+ if (escape_state)
+ {escape_state = FALSE;
+ /* continuation of a preprocessor line */
+ leading_blanks = TRUE;@#
+
+ if (in_string)
+ fputc('\n', out);
+ else
+ fputs("\n@@/", out);
+ goto end;
+ }@#
+
+ if (!leading_blanks && user_linefeed)
+ fputs("@@/", out);
+ }
+ else if (double_linefeed == TRUE)
+ {double_linefeed = DONE;
+ /* blank lines in the input will be output as
+ little white space between code lines */@#
+ fputs(at_nmb, out);
+ }
+ }@#
+
+ leading_blanks = TRUE;@#
+
+ if (short_comment)
+ {short_comment = FALSE;
+ in_comment = FALSE;
+ double_linefeed = TRUE;@#
+
+ if (verbatim)
+ {if (linefeed_comment && in_C)
+ fputs("@@>", out);
+ else @q { @>
+ fputc('}', out);
+ }@#
+
+ if (!in_C)
+ fputs("\\e{}%", out);
+ else if (linefeed_comment && verbatim)
+ fputs("@@/", out);@#
+
+ linefeed_comment = FALSE;
+ }@#
+
+ if (in_comment && in_C && verbatim && linefeed_comment)
+ { @q { @>
+ fputs("@@>@@/\n@@t}\\8{\\ob{}", out); @q } @>
+ /* continuation of a comment line without indentation */
+ goto end;
+ }@#
+
+ if (in_comment && verbatim)
+ /* Both \.{CWEAVE} and \TeX\ need an input at the beginning of a line
+ to prevent leading blanks be swallowed while in verbatim mode;
+ this will be the macro \.{\\e} which causes a linebreak */
+ {fputs("\n\\e{}", out);
+ goto end;
+ }
+
+
+@
+All other special characters will be substituted with proper sequences \TeX\
+can understand.
+
+@<Cases for |default|@>=
+ if (in_comment)
+ {switch (ch)
+ {case '#':
+ fputs("{\\#}", out);
+ break;@#
+
+ case '$':
+ fputs("{\\$}", out);
+ break;@#
+
+ case '%':
+ fputs("{\\%}", out);
+ break;@#
+
+ case '&':
+ fputs("{\\AM}", out);
+ break;@#
+
+ case '_':
+ fputs("{\\_}", out);
+ break;@#
+
+ case '^':
+ fputs("{\\^{}}", out);
+ break;@#
+
+ case '\\':
+ fputs("{\\symb\\char110}", out);
+ break;@#
+
+ case '~':
+ fputs("{\\~{}}", out);
+ break;@#
+
+ case '|':
+ fputs("{\\symb\\char106}", out);
+ break;@#
+
+ case '<':
+ fputs("{\\math\\char60}", out);
+ break;@#
+
+ case '>':
+ fputs("{\\math\\char62}", out);
+ break;@#
+
+ default:
+ fputc(ch, out);
+ break;
+ }@#
+
+ goto end;
+ }
+
+
+@
+Because the index macros defined in \.{cwebmac.tex} don't append a dot, we
+have to redefine \.{\\ZZZ}.
+
+@<Write index section@>=
+ fprintf(out,@/
+ "\n"@/
+ "@@*Index.\n"@/
+ "\\let\\ZZZ=\\takenone\n");
+
+
+@
+@<Prototypes@>=
+void usage(void);
+
+@
+@c
+void usage(void)
+ {fprintf(stderr,@/
+ "Usage: c2cweb [switches] csourcefile(s) | @@responsefile(s)"@/
+ "\n"@/
+ "\n possible switches:"@/
+ "\n"@/
+ "\n -b \"title\" set title"@/
+ "\n -l use input linefeeds"@/
+ "\n -o dirname set output directory (must already exist)"@/
+ "\n -f filename use this file as a format file"@/
+ "\n -t tablength set tabulator length (default 4)"@/
+ "\n -v verbatim mode"@/
+ "\n -1 one-sided output"@/
+ "\n"@/
+ "\n");@#
+
+ exit(-1);
+ }
+
+
+@
+@<Prototypes@>=
+void modify_filename(char *);
+
+
+@
+If a response file is expanded, trailing blanks can occur which will be
+ignored here. The same happens if a filename with trailing blanks is
+enclosed in quotes.
+
+@c
+void modify_filename(name)
+ char *name;
+ {char *p;
+
+
+ if ((p = strrchr(name, '.')) != NULL)
+ {p++;
+ if (*p && *p != ' ')
+ p++;
+ if (*p && *p != ' ')
+ p++;
+ if (*p != 'w')
+ *p = 'w';
+ else
+ *p = 'x';
+ p++;
+ *p = '\0';
+ }
+ else
+ strcat(name, ".w");
+ }
+
+
+@
+@<Global...@>=
+int line_number = 0;
+int column;
+
+
+@
+@<Prototypes@>=
+char *get_line(void);
+
+
+@
+|get_line()| gets the next line and removes all trailing blanks or tabs.
+
+@c
+char *get_line(void)
+ {char *p;
+ int i = BUFFER_LENGTH;
+
+
+ if ((p = fgets(buffer, BUFFER_LENGTH + 1, in)) != NULL)
+ {while (i--)
+ {if (*(p++) == '\n')
+ break;
+ }@#
+
+ p--;
+ p--;
+ while ((*p == ' ' || *p == '\t') && p >= buffer)
+ p--;
+ *(p + 1) = '\n';
+ *(p + 2) = '\0';@#
+
+ line_number++;
+ column = 0;
+ }
+ return(p);
+ }
+
+
+@
+@<Global...@>=
+char tempbuf[2 * FILE_NAME_LENGTH + 1];
+
+
+@
+@<Prototypes@>=
+char *protect_underlines(char *);
+
+
+@
+This function is needed for the names of named sections, i.e. file names.
+
+@c
+char *protect_underlines(p)
+ char *p;
+ {char *q;
+
+
+ q = tempbuf;@#
+
+ do
+ {if (*p == '_')
+ *(q++) = '\\';
+ *(q++) = *p;
+ } while (*(p++));@#
+
+ return tempbuf;
+ }
+
+
+@
+@<Prototypes@>=
+#ifndef __EMX__
+char *_getname(char *);
+#endif
+
+
+@
+For Linux and other \UNIX/-systems the function |_getname()| must be
+defined.
+
+
+@c
+#ifndef __EMX__
+char *_getname(char *path)
+ {char *p;
+
+ p = strrchr(path, '/');
+ return p == NULL ? path : (p + 1);
+ }
+#endif
+
+
+
+@* Hints and Tricks.
+Some words are reserved by \.{CWEAVE} you would like to use. Here is a small
+list of them (see the manual for a complete one):
+
+ \in \.{error}, \.{line}, \.{try}, $\ldots$
+
+To make a word unreserved write a line
+
+ \in \.{@@s} \\{ident} \\{x}
+
+into \.{compiler.w} where \\{ident} is the reserved word.
+
+Some words you would expect \.{CWEAVE} knows actually are not in its memory:
+
+ \in \.{va\_arg}, \.{va\_end}, \.{va\_start}, $\ldots$
+
+To make a word \\{ident1} reserved you should write
+
+ \in \.{@@s} \\{ident1} \\{ident2}
+
+into \.{compiler.w}. Now \\{ident1} will behave as \\{ident2}; for example
+
+ \in \.{@@s va\_decl va\_dcl}
+
+causes \.{CWEAVE} to treat \.{va\_decl} as it treats \.{va\_dcl}.
+
+Bear always in mind that \.{CWEAVE} has been developed for use with \UNIX/
+and not for DOS or OS/2. Weird non-ANSI constructions like
+
+ \in \&{void \_FAR} |*| \&{\_FARFUNC \_Cdecl} \\{memcpy} $\ldots$
+
+will cause some, hmmm, troubles if you use the original \.{CWEAVE} program.
+Until now it's also a bit difficult to program for Windows\tm\ or the
+Presentation Manager\tm, because you have to include every structure and
+constant you use in your program manually, which can be a tedious work.
+
+Do not use the same name for a structure and an instance of it. This means
+that you must avoid things like this:
+
+ \in \&{struct foo} \\{foo;}
+
+\.{CWEAVE} would be confused totally. The same applies to all identifiers
+which will be used as reserved and as unreserved words at the same time (This
+usually will not affect identical names of variables and functions. But in
+this case the reader of your program will get confused).
+
+Most of the \CEE/ constants are written in upper case, and \.{CWEAVE} writes
+them in typewriter type. But some constants like \.{\_Windows} or
+\.{\_\_cplusplus} are mixed or lower case, and \.{CWEAVE} will use italic
+type instead of. Look at \.{compiler.w} again to see a workaround how to get
+a correct output (Note: underline characters are converted to `x' in the
+\TeX\ control string).
+
+Nested comments are not supported; the program aborts with an error message.
+
+If you have unbalanced braces due to \.{\#ifdef foo} $\ldots$ \.{\#endif}
+constructions, you can keep \.{c2cweb} and your editor happy if you write a
+\.{/*\{*/} or \.{/*\}*/} command where needed; otherwise memory of \.{CWEAVE}
+can overflow. \.{c2cweb} replaces these commands with the equal \.{CWEB}
+constructions (only defined in this package's modified \.{CWEAVE} version!).
+
+Another trick with preprocessor conditionals:
+
+ \in \.{/*@@*/}
+
+ \in \&{\#ifdef} \.{foo}
+
+ \in\in \&{int} \\{func1} $\{\,\ldots\,\}$
+
+ \in \&{\#endif}
+
+ \in \.{/*@@@@*/}
+
+Without \.{/*@@*/} the \&{\#endif} instruction would be written into the next
+section.
+
+The \.{/*\{\}*/} command proved to be useful in cases like this:
+
+ \in \&{\#if} \.{\_\_STDC\_\_}
+
+ \in\in \&{void} \\{func1}(\&{int} \\{a})
+
+ \in \.{/*\{\}*/}
+
+ \in \&{\#else}
+
+ \in\in \&{void} \\{func1}(\\{a})
+
+ \in\in\in \&{int} \\{a};
+
+ \in \&{\#endif}
+
+ \in $\{\,\ldots\,\}$
+
+It is essentially the same as
+
+ \in \.{/*\{*/}
+
+ \in \.{/*\}*/}
+
+but will not start a new section (Thus it is not necessary to insert a
+\.{/*@@*/} before the actual function).
+
+
+@* Index.
+
+
+@q end of c2cweb.w @>
diff --git a/web/c_cpp/c2cweb/compiler.w b/web/c_cpp/c2cweb/compiler.w
new file mode 100644
index 0000000000..e03320c0f2
--- /dev/null
+++ b/web/c_cpp/c2cweb/compiler.w
@@ -0,0 +1,71 @@
+@q this file is part of the c2cweb package Version 1.5 @>
+
+@q this is the file compiler.w @>
+@q written by Werner Lemberg (a7971428@@unet.univie.ac.at) 10-Nov-1996 @>
+
+
+@q the format definitions below are just examples and not complete! @>
+
+@q definition strings @>
+
+% A4 paper format
+
+\fullpageheight=240mm
+\pageheight=223mm
+\pagewidth=158mm
+\setpage
+
+\def\botofcontents{
+ \vfill
+ \centerline{This document was produced with the \.{c2cweb}
+ program by Werner Lemberg}}
+
+\input c2cweb.ger @q uncomment this if not needed @>
+
+\def\xWindows{\.{\_Windows}}
+\def\xxcplusplus{\.{\_\_cplusplus}}
+
+
+@s error x @q if you use C++ 3.0, you must delete this line @>
+@s line x @q if you want to use the #line preprocessor command, delete this line @>
+
+
+@q most of the DOS C and C++ compilers need that stuff @>
+
+@s _cdecl const
+@s cdecl const
+@s _cs const
+@s _ds const
+@s _es const
+@s _export const
+@s _far const
+@s far const
+@s huge const
+@s interrupt const
+@s _loadds const
+@s _near const
+@s near const
+@s _pascal const
+@s pascal const
+@s _saveregs const
+@s _seg const
+@s _ss const
+
+@s _Windows TeX
+@s __cplusplus TeX
+
+
+@q some GNU C directives @>
+
+@s asm const
+@s inline const
+@s const const
+@s __asm__ const
+@s __inline__ const
+@s __const__ const
+@s __label__ int
+@s __attribute__ int
+@s __alignof__ sizeof
+
+
+@q end of compiler.w @>
diff --git a/web/c_cpp/c2cweb/cweb/Makefile b/web/c_cpp/c2cweb/cweb/Makefile
new file mode 100644
index 0000000000..68d0ca8e18
--- /dev/null
+++ b/web/c_cpp/c2cweb/cweb/Makefile
@@ -0,0 +1,106 @@
+# This file is part of the c2cweb package Version 1.5 (10-Nov-1996)
+
+# GNU Makefile for c2cweb's version of CWEAVE
+
+
+.PHONY: default all debug clean \
+ cweb
+.CAUTIOUS: common.c cweave.c
+
+
+default:
+ @echo " say "
+ @echo ". "
+ @echo " make <TARGET> OS=<SYSTEM> "
+ @echo ". "
+ @echo " SYSTEM can be one of the following: "
+ @echo ". "
+ @echo " unix (gcc) "
+ @echo " os2 bound (emx) "
+ @echo " dos (djgpp) "
+ @echo ". "
+ @echo " TARGET can be one of the following: "
+ @echo ". "
+ @echo " all debug clean "
+
+
+ifdef OS
+
+ ifeq ($(OS),unix)
+ CC = gcc -Wall -O
+ O = .o
+ LIB =
+ EXE =
+ RM = rm -f
+ endif
+
+ ifeq ($(OS),os2)
+ CC = gcc -Wall -Zomf -Zmtd -O
+ O = .obj
+ LIB = cweave.def
+ EXE = .exe
+ RM = del
+ endif
+
+ ifeq ($(OS),dos)
+ CC = gcc -Wall -O
+ O = .o
+ LIB =
+ EXE = .exe
+ RM = del
+ endif
+
+ ifeq ($(OS),bound)
+ CC = gcc -Wall -O
+ O = .o
+ LIB =
+ EXE = .exe
+ RM = del
+ endif
+
+
+ OBJ = common$O cweave$O
+
+
+ %$O: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+ %.c: %.w %.ch
+ $(CTANGLE) $^ $@
+ %.c: %.w
+ $(CTANGLE) $<
+
+
+ all:
+ $(MAKE) cweb CFLAGS=-s
+
+ debug:
+ $(MAKE) cweb CFLAGS=-g
+
+ # remove the unnecessary files.
+ clean:
+ -$(RM) *$O
+
+
+ cweb: cweave$(EXE)
+
+ cweave$(EXE): $(OBJ)
+ ifeq ($(OS),dos)
+ $(CC) $(CFLAGS) -o $(basename $@) $^
+ strip $(basename $@)
+ coff2exe $(basename $@)
+ -$(RM) $(basename $@)
+ else
+ $(CC) $(CFLAGS) -o $@ $^ $(LIB)
+ endif
+
+ cweave.w: common.h
+ cweave.ch: prod-alt.w
+
+else # ifdef OS
+
+ all debug clean: default
+
+endif
+
+# end of Makefile
diff --git a/web/c_cpp/c2cweb/cweb/common.c b/web/c_cpp/c2cweb/cweb/common.c
new file mode 100644
index 0000000000..963a20d9c1
--- /dev/null
+++ b/web/c_cpp/c2cweb/cweb/common.c
@@ -0,0 +1,1280 @@
+/*1:*/
+#line 57 "common.w"
+
+/*5:*/
+#line 101 "common.w"
+
+#include <ctype.h>
+
+/*:5*//*8:*/
+#line 163 "common.w"
+
+#include <stdio.h>
+
+/*:8*//*22:*/
+#line 468 "common.w"
+
+#include <stdlib.h>
+
+/*:22*/
+#line 58 "common.w"
+
+#define ctangle 0
+#define cweave 1 \
+
+#define and_and 04
+#define lt_lt 020
+#define gt_gt 021
+#define plus_plus 013
+#define minus_minus 01
+#define minus_gt 031
+#define not_eq 032
+#define lt_eq 034
+#define gt_eq 035
+#define eq_eq 036
+#define or_or 037
+#define dot_dot_dot 016
+#define colon_colon 06
+#define period_ast 026
+#define minus_gt_ast 027 \
+
+#define buf_size 400
+#define long_buf_size 500
+#define xisspace(c) (isspace(c) &&((unsigned char) c<0200) )
+#define xisupper(c) (isupper(c) &&((unsigned char) c<0200) ) \
+
+#define max_include_depth 10 \
+
+#define max_file_name_length 60
+#define cur_file file[include_depth]
+#define cur_file_name file_name[include_depth]
+#define cur_line line[include_depth]
+#define web_file file[0]
+#define web_file_name file_name[0] \
+
+#define lines_dont_match (change_limit-change_buffer!=limit-buffer|| \
+strncmp(buffer,change_buffer,limit-buffer) ) \
+
+#define if_section_start_make_pending(b) {*limit= '!'; \
+for(loc= buffer;xisspace(*loc) ;loc++) ; \
+*limit= ' '; \
+if(*loc=='@'&&(xisspace(*(loc+1) ) ||*(loc+1) =='*') ) change_pending= b; \
+} \
+
+#define max_sections 2000 \
+ \
+
+#define too_long() {include_depth--; \
+err_print("! Include file name too long") ;goto restart;} \
+
+#define max_bytes 225000 \
+
+#define max_names 10000 \
+ \
+
+#define length(c) (c+1) ->byte_start-(c) ->byte_start
+#define print_id(c) term_write((c) ->byte_start,length((c) ) ) \
+
+#define hash_size 353 \
+
+#define llink link
+#define rlink dummy.Rlink
+#define root name_dir->rlink \
+ \
+
+#define first_chunk(p) ((p) ->byte_start+2)
+#define prefix_length(p) (int) ((unsigned char) *((p) ->byte_start) *256+ \
+(unsigned char) *((p) ->byte_start+1) )
+#define set_prefix_length(p,m) (*((p) ->byte_start) = (m) /256, \
+*((p) ->byte_start+1) = (m) %256) \
+
+#define less 0
+#define equal 1
+#define greater 2
+#define prefix 3
+#define extension 4 \
+
+#define bad_extension 5 \
+
+#define spotless 0
+#define harmless_message 1
+#define error_message 2
+#define fatal_message 3
+#define mark_harmless {if(history==spotless) history= harmless_message;}
+#define mark_error history= error_message \
+
+#define confusion(s) fatal("! This can't happen: ",s) \
+ \
+
+#define show_banner flags['b']
+#define show_progress flags['p']
+#define show_stats flags['s']
+#define show_happiness flags['h'] \
+
+#define update_terminal fflush(stdout) \
+
+#define new_line putchar('\n')
+#define putxchar putchar
+#define term_write(a,b) fflush(stdout) ,fwrite(a,sizeof(char) ,b,stdout)
+#define C_printf(c,a) fprintf(C_file,c,a)
+#define C_putc(c) putc(c,C_file) \
+
+
+#line 59 "common.w"
+
+/*2:*/
+#line 72 "common.w"
+
+typedef short boolean;
+boolean program;
+
+/*:2*//*7:*/
+#line 157 "common.w"
+
+char buffer[long_buf_size];
+char*buffer_end= buffer+buf_size-2;
+char*limit= buffer;
+char*loc= buffer;
+
+/*:7*//*10:*/
+#line 212 "common.w"
+
+int include_depth;
+FILE*file[max_include_depth];
+FILE*change_file;
+char file_name[max_include_depth][max_file_name_length];
+
+char change_file_name[max_file_name_length];
+char alt_web_file_name[max_file_name_length];
+int line[max_include_depth];
+int change_line;
+int change_depth;
+boolean input_has_ended;
+boolean changing;
+boolean web_file_open= 0;
+
+/*:10*//*20:*/
+#line 416 "common.w"
+
+typedef unsigned short sixteen_bits;
+sixteen_bits section_count;
+boolean changed_section[max_sections];
+boolean change_pending;
+
+boolean print_where= 0;
+
+/*:20*//*27:*/
+#line 586 "common.w"
+
+typedef struct name_info{
+char*byte_start;
+/*31:*/
+#line 623 "common.w"
+
+struct name_info*link;
+
+/*:31*//*40:*/
+#line 722 "common.w"
+
+union{
+struct name_info*Rlink;
+
+#line 31 "common.ch"
+struct{
+char Ilk;
+boolean Func_flag;}dummy1;
+}dummy;
+#line 728 "common.w"
+
+/*:40*//*55:*/
+#line 1054 "common.w"
+
+char*equiv_or_xref;
+
+/*:55*/
+#line 589 "common.w"
+
+}name_info;
+typedef name_info*name_pointer;
+char byte_mem[max_bytes];
+char*byte_mem_end= byte_mem+max_bytes-1;
+name_info name_dir[max_names];
+name_pointer name_dir_end= name_dir+max_names-1;
+
+/*:27*//*29:*/
+#line 609 "common.w"
+
+name_pointer name_ptr;
+char*byte_ptr;
+
+/*:29*//*32:*/
+#line 636 "common.w"
+
+typedef name_pointer*hash_pointer;
+name_pointer hash[hash_size];
+hash_pointer hash_end= hash+hash_size-1;
+hash_pointer h;
+
+/*:32*//*56:*/
+#line 1074 "common.w"
+
+int history= spotless;
+
+/*:56*//*67:*/
+#line 1212 "common.w"
+
+int argc;
+char**argv;
+char C_file_name[max_file_name_length];
+char tex_file_name[max_file_name_length];
+char idx_file_name[max_file_name_length];
+char scn_file_name[max_file_name_length];
+boolean flags[128];
+
+/*:67*//*77:*/
+#line 1366 "common.w"
+
+FILE*C_file;
+FILE*tex_file;
+FILE*idx_file;
+FILE*scn_file;
+FILE*active_file;
+
+/*:77*/
+#line 60 "common.w"
+
+/*3:*/
+#line 82 "common.w"
+int phase;
+
+/*:3*//*11:*/
+#line 238 "common.w"
+
+char change_buffer[buf_size];
+char*change_limit;
+
+/*:11*/
+#line 61 "common.w"
+
+/*33:*/
+#line 642 "common.w"
+
+extern int names_match();
+
+/*:33*//*38:*/
+#line 695 "common.w"
+
+void init_p();
+
+/*:38*//*46:*/
+#line 844 "common.w"
+
+extern void init_node();
+
+/*:46*//*53:*/
+#line 1009 "common.w"
+
+int section_name_cmp();
+
+/*:53*//*57:*/
+#line 1084 "common.w"
+
+void err_print();
+
+/*:57*//*60:*/
+#line 1132 "common.w"
+
+int wrap_up();
+extern void print_stats();
+
+/*:60*//*63:*/
+#line 1165 "common.w"
+
+void fatal(),overflow();
+
+/*:63*//*69:*/
+#line 1243 "common.w"
+
+void scan_args();
+
+/*:69*//*81:*/
+#line 1407 "common.w"
+
+extern int strlen();
+extern int strcmp();
+extern char*strcpy();
+extern int strncmp();
+extern char*strncpy();
+
+/*:81*/
+#line 62 "common.w"
+
+
+/*:1*//*4:*/
+#line 88 "common.w"
+
+void
+common_init()
+{
+/*30:*/
+#line 613 "common.w"
+
+name_dir->byte_start= byte_ptr= byte_mem;
+name_ptr= name_dir+1;
+name_ptr->byte_start= byte_mem;
+
+/*:30*//*34:*/
+#line 647 "common.w"
+
+for(h= hash;h<=hash_end;*h++= NULL);
+
+/*:34*//*41:*/
+#line 729 "common.w"
+
+root= NULL;
+
+/*:41*/
+#line 92 "common.w"
+;
+/*68:*/
+#line 1225 "common.w"
+
+show_banner= show_happiness= show_progress= 1;
+
+/*:68*/
+#line 93 "common.w"
+;
+/*78:*/
+#line 1373 "common.w"
+
+scan_args();
+if(program==ctangle){
+if((C_file= fopen(C_file_name,"w"))==NULL)
+fatal("! Cannot open output file ",C_file_name);
+
+}
+else{
+if((tex_file= fopen(tex_file_name,"w"))==NULL)
+fatal("! Cannot open output file ",tex_file_name);
+}
+
+/*:78*/
+#line 94 "common.w"
+;
+}
+
+/*:4*//*9:*/
+#line 170 "common.w"
+
+int input_ln(fp)
+FILE*fp;
+{
+register int c= EOF;
+register char*k;
+if(feof(fp))return(0);
+limit= k= buffer;
+while(k<=buffer_end&&(c= getc(fp))!=EOF&&c!='\n')
+if((*(k++)= c)!=' ')limit= k;
+if(k>buffer_end)
+if((c= getc(fp))!=EOF&&c!='\n'){
+ungetc(c,fp);loc= buffer;err_print("! Input line too long");
+
+}
+if(c==EOF&&limit==buffer)return(0);
+
+return(1);
+}
+
+/*:9*//*12:*/
+#line 249 "common.w"
+
+void
+prime_the_change_buffer()
+{
+change_limit= change_buffer;
+/*13:*/
+#line 263 "common.w"
+
+while(1){
+change_line++;
+if(!input_ln(change_file))return;
+if(limit<buffer+2)continue;
+if(buffer[0]!='@')continue;
+if(xisupper(buffer[1]))buffer[1]= tolower(buffer[1]);
+if(buffer[1]=='x')break;
+if(buffer[1]=='y'||buffer[1]=='z'||buffer[1]=='i'){
+loc= buffer+2;
+err_print("! Missing @x in change file");
+
+}
+}
+
+/*:13*/
+#line 254 "common.w"
+;
+/*14:*/
+#line 280 "common.w"
+
+do{
+change_line++;
+if(!input_ln(change_file)){
+err_print("! Change file ended after @x");
+
+return;
+}
+}while(limit==buffer);
+
+/*:14*/
+#line 255 "common.w"
+;
+/*15:*/
+#line 290 "common.w"
+
+{
+change_limit= change_buffer-buffer+limit;
+strncpy(change_buffer,buffer,limit-buffer+1);
+}
+
+/*:15*/
+#line 256 "common.w"
+;
+}
+
+/*:12*//*16:*/
+#line 318 "common.w"
+
+void
+check_change()
+{
+int n= 0;
+if(lines_dont_match)return;
+change_pending= 0;
+if(!changed_section[section_count]){
+if_section_start_make_pending(1);
+if(!change_pending)changed_section[section_count]= 1;
+}
+while(1){
+changing= 1;print_where= 1;change_line++;
+if(!input_ln(change_file)){
+err_print("! Change file ended before @y");
+
+change_limit= change_buffer;changing= 0;
+return;
+}
+if(limit>buffer+1&&buffer[0]=='@'){
+if(xisupper(buffer[1]))buffer[1]= tolower(buffer[1]);
+/*17:*/
+#line 356 "common.w"
+
+if(buffer[1]=='x'||buffer[1]=='z'){
+loc= buffer+2;err_print("! Where is the matching @y?");
+
+}
+else if(buffer[1]=='y'){
+if(n>0){
+loc= buffer+2;
+printf("\n! Hmm... %d ",n);
+err_print("of the preceding lines failed to match");
+
+}
+change_depth= include_depth;
+return;
+}
+
+/*:17*/
+#line 340 "common.w"
+;
+}
+/*15:*/
+#line 290 "common.w"
+
+{
+change_limit= change_buffer-buffer+limit;
+strncpy(change_buffer,buffer,limit-buffer+1);
+}
+
+/*:15*/
+#line 342 "common.w"
+;
+changing= 0;cur_line++;
+while(!input_ln(cur_file)){
+if(include_depth==0){
+err_print("! CWEB file ended during a change");
+
+input_has_ended= 1;return;
+}
+include_depth--;cur_line++;
+}
+if(lines_dont_match)n++;
+}
+}
+
+/*:16*//*18:*/
+#line 376 "common.w"
+
+void
+reset_input()
+{
+limit= buffer;loc= buffer+1;buffer[0]= ' ';
+/*19:*/
+#line 391 "common.w"
+
+if((web_file= fopen(web_file_name,"r"))==NULL){
+strcpy(web_file_name,alt_web_file_name);
+if((web_file= fopen(web_file_name,"r"))==NULL)
+fatal("! Cannot open input file ",web_file_name);
+}
+
+
+web_file_open= 1;
+if((change_file= fopen(change_file_name,"r"))==NULL)
+fatal("! Cannot open change file ",change_file_name);
+
+/*:19*/
+#line 381 "common.w"
+;
+include_depth= 0;cur_line= 0;change_line= 0;
+change_depth= include_depth;
+changing= 1;prime_the_change_buffer();changing= !changing;
+limit= buffer;loc= buffer+1;buffer[0]= ' ';input_has_ended= 0;
+}
+
+/*:18*//*21:*/
+#line 424 "common.w"
+
+int get_line()
+{
+restart:
+if(changing&&include_depth==change_depth)
+/*25:*/
+#line 529 "common.w"
+{
+change_line++;
+if(!input_ln(change_file)){
+err_print("! Change file ended without @z");
+
+buffer[0]= '@';buffer[1]= 'z';limit= buffer+2;
+}
+if(limit>buffer){
+if(change_pending){
+if_section_start_make_pending(0);
+if(change_pending){
+changed_section[section_count]= 1;change_pending= 0;
+}
+}
+*limit= ' ';
+if(buffer[0]=='@'){
+if(xisupper(buffer[1]))buffer[1]= tolower(buffer[1]);
+if(buffer[1]=='x'||buffer[1]=='y'){
+loc= buffer+2;
+err_print("! Where is the matching @z?");
+
+}
+else if(buffer[1]=='z'){
+prime_the_change_buffer();changing= !changing;print_where= 1;
+}
+}
+}
+}
+
+/*:25*/
+#line 429 "common.w"
+;
+if(!changing||include_depth>change_depth){
+/*24:*/
+#line 512 "common.w"
+{
+cur_line++;
+while(!input_ln(cur_file)){
+print_where= 1;
+if(include_depth==0){input_has_ended= 1;break;}
+else{
+fclose(cur_file);include_depth--;
+if(changing&&include_depth==change_depth)break;
+cur_line++;
+}
+}
+if(!changing&&!input_has_ended)
+if(limit-buffer==change_limit-change_buffer)
+if(buffer[0]==change_buffer[0])
+if(change_limit>change_buffer)check_change();
+}
+
+/*:24*/
+#line 431 "common.w"
+;
+if(changing&&include_depth==change_depth)goto restart;
+}
+loc= buffer;*limit= ' ';
+if(*buffer=='@'&&(*(buffer+1)=='i'||*(buffer+1)=='I')){
+loc= buffer+2;
+while(loc<=limit&&(*loc==' '||*loc=='\t'||*loc=='"'))loc++;
+if(loc>=limit){
+err_print("! Include file name not given");
+
+goto restart;
+}
+if(include_depth>=max_include_depth-1){
+err_print("! Too many nested includes");
+
+goto restart;
+}
+include_depth++;
+/*23:*/
+#line 471 "common.w"
+{
+char temp_file_name[max_file_name_length];
+char*cur_file_name_end= cur_file_name+max_file_name_length-1;
+char*k= cur_file_name,*kk;
+int l;
+
+while(*loc!=' '&&*loc!='\t'&&*loc!='"'&&k<=cur_file_name_end)*k++= *loc++;
+if(k>cur_file_name_end)too_long();
+
+*k= '\0';
+if((cur_file= fopen(cur_file_name,"r"))!=NULL){
+cur_line= 0;print_where= 1;
+goto restart;
+}
+kk= getenv("CWEBINPUTS");
+if(kk!=NULL){
+if((l= strlen(kk))>max_file_name_length-2)too_long();
+strcpy(temp_file_name,kk);
+}
+else{
+#ifdef CWEBINPUTS
+if((l= strlen(CWEBINPUTS))>max_file_name_length-2)too_long();
+strcpy(temp_file_name,CWEBINPUTS);
+#else
+l= 0;
+#endif
+}
+if(l>0){
+if(k+l+2>=cur_file_name_end)too_long();
+
+for(;k>=cur_file_name;k--)*(k+l+1)= *k;
+strcpy(cur_file_name,temp_file_name);
+cur_file_name[l]= '/';
+if((cur_file= fopen(cur_file_name,"r"))!=NULL){
+cur_line= 0;print_where= 1;
+goto restart;
+}
+}
+include_depth--;err_print("! Cannot open include file");goto restart;
+}
+
+/*:23*/
+#line 449 "common.w"
+;
+}
+return(!input_has_ended);
+}
+
+/*:21*//*26:*/
+#line 561 "common.w"
+
+void
+check_complete(){
+if(change_limit!=change_buffer){
+strncpy(buffer,change_buffer,change_limit-change_buffer+1);
+limit= buffer+(int)(change_limit-change_buffer);
+changing= 1;change_depth= include_depth;loc= buffer;
+err_print("! Change file entry did not match");
+
+}
+}
+
+/*:26*//*35:*/
+#line 652 "common.w"
+
+name_pointer
+id_lookup(first,last,t)
+char*first;
+char*last;
+char t;
+{
+char*i= first;
+int h;
+int l;
+name_pointer p;
+if(last==NULL)for(last= first;*last!='\0';last++);
+l= last-first;
+/*36:*/
+#line 675 "common.w"
+
+h= (unsigned char)*i;
+while(++i<last)h= (h+h+(int)((unsigned char)*i))%hash_size;
+
+
+/*:36*/
+#line 665 "common.w"
+;
+/*37:*/
+#line 683 "common.w"
+
+p= hash[h];
+while(p&&!names_match(p,first,l,t))p= p->link;
+if(p==NULL){
+p= name_ptr;
+p->link= hash[h];hash[h]= p;
+}
+
+/*:37*/
+#line 666 "common.w"
+;
+if(p==name_ptr)/*39:*/
+#line 698 "common.w"
+{
+if(byte_ptr+l>byte_mem_end)overflow("byte memory");
+if(name_ptr>=name_dir_end)overflow("name");
+strncpy(byte_ptr,first,l);
+(++name_ptr)->byte_start= byte_ptr+= l;
+if(program==cweave)init_p(p,t);
+}
+
+/*:39*/
+#line 667 "common.w"
+;
+return(p);
+}
+
+/*:35*//*42:*/
+#line 756 "common.w"
+
+void
+print_section_name(p)
+name_pointer p;
+{
+char*ss,*s= first_chunk(p);
+name_pointer q= p+1;
+while(p!=name_dir){
+ss= (p+1)->byte_start-1;
+if(*ss==' '&&ss>=s){
+term_write(s,ss-s);p= q->link;q= p;
+}else{
+term_write(s,ss+1-s);p= name_dir;q= NULL;
+}
+s= p->byte_start;
+}
+if(q)term_write("...",3);
+}
+
+/*:42*//*43:*/
+#line 775 "common.w"
+
+void
+sprint_section_name(dest,p)
+char*dest;
+name_pointer p;
+{
+char*ss,*s= first_chunk(p);
+name_pointer q= p+1;
+while(p!=name_dir){
+ss= (p+1)->byte_start-1;
+if(*ss==' '&&ss>=s){
+p= q->link;q= p;
+}else{
+ss++;p= name_dir;
+}
+strncpy(dest,s,ss-s),dest+= ss-s;
+s= p->byte_start;
+}
+*dest= '\0';
+}
+
+/*:43*//*44:*/
+#line 796 "common.w"
+
+void
+print_prefix_name(p)
+name_pointer p;
+{
+char*s= first_chunk(p);
+int l= prefix_length(p);
+term_write(s,l);
+if(s+l<(p+1)->byte_start)term_write("...",3);
+}
+
+/*:44*//*45:*/
+#line 817 "common.w"
+
+int web_strcmp(j,j_len,k,k_len)
+char*j,*k;
+int j_len,k_len;
+{
+char*j1= j+j_len,*k1= k+k_len;
+while(k<k1&&j<j1&&*j==*k)k++,j++;
+if(k==k1)if(j==j1)return equal;
+else return extension;
+else if(j==j1)return prefix;
+else if(*j<*k)return less;
+else return greater;
+}
+
+/*:45*//*47:*/
+#line 847 "common.w"
+
+name_pointer
+add_section_name(par,c,first,last,ispref)
+name_pointer par;
+int c;
+char*first;
+char*last;
+int ispref;
+{
+name_pointer p= name_ptr;
+char*s= first_chunk(p);
+int name_len= last-first+ispref;
+if(s+name_len>byte_mem_end)overflow("byte memory");
+if(name_ptr+1>=name_dir_end)overflow("name");
+(++name_ptr)->byte_start= byte_ptr= s+name_len;
+if(ispref){
+*(byte_ptr-1)= ' ';
+name_len--;
+name_ptr->link= name_dir;
+(++name_ptr)->byte_start= byte_ptr;
+}
+set_prefix_length(p,name_len);
+strncpy(s,first,name_len);
+p->llink= NULL;
+p->rlink= NULL;
+init_node(p);
+return par==NULL?(root= p):c==less?(par->llink= p):(par->rlink= p);
+}
+
+/*:47*//*48:*/
+#line 876 "common.w"
+
+void
+extend_section_name(p,first,last,ispref)
+name_pointer p;
+char*first;
+char*last;
+int ispref;
+{
+char*s;
+name_pointer q= p+1;
+int name_len= last-first+ispref;
+if(name_ptr>=name_dir_end)overflow("name");
+while(q->link!=name_dir)q= q->link;
+q->link= name_ptr;
+s= name_ptr->byte_start;
+name_ptr->link= name_dir;
+if(s+name_len>byte_mem_end)overflow("byte memory");
+(++name_ptr)->byte_start= byte_ptr= s+name_len;
+strncpy(s,first,name_len);
+if(ispref)*(byte_ptr-1)= ' ';
+}
+
+/*:48*//*49:*/
+#line 904 "common.w"
+
+name_pointer
+section_lookup(first,last,ispref)
+char*first,*last;
+int ispref;
+{
+int c= 0;
+name_pointer p= root;
+name_pointer q= NULL;
+name_pointer r= NULL;
+name_pointer par= NULL;
+
+int name_len= last-first+1;
+/*50:*/
+#line 928 "common.w"
+
+while(p){
+c= web_strcmp(first,name_len,first_chunk(p),prefix_length(p));
+if(c==less||c==greater){
+if(r==NULL)
+par= p;
+p= (c==less?p->llink:p->rlink);
+}else{
+if(r!=NULL){
+printf("\n! Ambiguous prefix: matches <");
+
+print_prefix_name(p);
+printf(">\n and <");
+print_prefix_name(r);
+err_print(">");
+return name_dir;
+}
+r= p;
+p= p->llink;
+q= r->rlink;
+}
+if(p==NULL)
+p= q,q= NULL;
+}
+
+/*:50*/
+#line 918 "common.w"
+;
+/*51:*/
+#line 953 "common.w"
+
+if(r==NULL)
+return add_section_name(par,c,first,last+1,ispref);
+
+/*:51*/
+#line 919 "common.w"
+;
+/*52:*/
+#line 961 "common.w"
+
+switch(section_name_cmp(&first,name_len,r)){
+
+case prefix:
+if(!ispref){
+printf("\n! New name is a prefix of <");
+
+print_section_name(r);
+err_print(">");
+}
+else if(name_len<prefix_length(r))set_prefix_length(r,name_len);
+
+case equal:return r;
+case extension:if(!ispref||first<=last)
+extend_section_name(r,first,last+1,ispref);
+return r;
+case bad_extension:
+printf("\n! New name extends <");
+
+print_section_name(r);
+err_print(">");
+return r;
+default:
+printf("\n! Section name incompatible with <");
+
+print_prefix_name(r);
+printf(">,\n which abbreviates <");
+print_section_name(r);
+err_print(">");
+return r;
+}
+
+/*:52*/
+#line 920 "common.w"
+;
+}
+
+/*:49*//*54:*/
+#line 1012 "common.w"
+
+int section_name_cmp(pfirst,len,r)
+char**pfirst;
+int len;
+name_pointer r;
+{
+char*first= *pfirst;
+name_pointer q= r+1;
+char*ss,*s= first_chunk(r);
+int c;
+int ispref;
+while(1){
+ss= (r+1)->byte_start-1;
+if(*ss==' '&&ss>=r->byte_start)ispref= 1,q= q->link;
+else ispref= 0,ss++,q= name_dir;
+switch(c= web_strcmp(first,len,s,ss-s)){
+case equal:if(q==name_dir)
+if(ispref){
+*pfirst= first+(ss-s);
+return extension;
+}else return equal;
+else return(q->byte_start==(q+1)->byte_start)?equal:prefix;
+case extension:
+if(!ispref)return bad_extension;
+first+= ss-s;
+if(q!=name_dir){len-= ss-s;s= q->byte_start;r= q;continue;}
+*pfirst= first;return extension;
+default:return c;
+}
+}
+}
+
+/*:54*//*58:*/
+#line 1087 "common.w"
+
+void
+err_print(s)
+char*s;
+{
+char*k,*l;
+printf(*s=='!'?"\n%s":"%s",s);
+if(web_file_open)/*59:*/
+#line 1107 "common.w"
+
+{if(changing&&include_depth==change_depth)
+printf(". (l. %d of change file)\n",change_line);
+else if(include_depth==0)printf(". (l. %d)\n",cur_line);
+else printf(". (l. %d of include file %s)\n",cur_line,cur_file_name);
+l= (loc>=limit?limit:loc);
+if(l>buffer){
+for(k= buffer;k<l;k++)
+if(*k=='\t')putchar(' ');
+else putchar(*k);
+putchar('\n');
+for(k= buffer;k<l;k++)putchar(' ');
+}
+for(k= l;k<limit;k++)putchar(*k);
+if(*limit=='|')putchar('|');
+putchar(' ');
+}
+
+/*:59*/
+#line 1094 "common.w"
+;
+update_terminal;mark_error;
+}
+
+/*:58*//*61:*/
+#line 1142 "common.w"
+
+int wrap_up(){
+putchar('\n');
+if(show_stats)
+print_stats();
+/*62:*/
+#line 1152 "common.w"
+
+switch(history){
+case spotless:if(show_happiness)printf("(No errors were found.)\n");break;
+case harmless_message:
+printf("(Did you see the warning message above?)\n");break;
+case error_message:
+printf("(Pardon me, but I think I spotted something wrong.)\n");break;
+case fatal_message:printf("(That was a fatal error, my friend.)\n");
+}
+
+/*:62*/
+#line 1147 "common.w"
+;
+if(history>harmless_message)return(1);
+else return(0);
+}
+
+/*:61*//*64:*/
+#line 1171 "common.w"
+void
+fatal(s,t)
+char*s,*t;
+{
+if(*s)printf(s);
+err_print(t);
+history= fatal_message;exit(wrap_up());
+}
+
+/*:64*//*65:*/
+#line 1182 "common.w"
+void
+overflow(t)
+char*t;
+{
+printf("\n! Sorry, %s capacity exceeded",t);fatal("","");
+}
+
+
+/*:65*//*70:*/
+#line 1246 "common.w"
+
+void
+scan_args()
+{
+char*dot_pos;
+char*name_pos;
+register char*s;
+boolean found_web= 0,found_change= 0,found_out= 0;
+
+boolean flag_change;
+
+while(--argc>0){
+if((**(++argv)=='-'||**argv=='+')&&*(*argv+1))/*74:*/
+#line 1340 "common.w"
+
+{
+if(**argv=='-')flag_change= 0;
+else flag_change= 1;
+for(dot_pos= *argv+1;*dot_pos>'\0';dot_pos++)
+flags[*dot_pos]= flag_change;
+}
+
+/*:74*/
+#line 1258 "common.w"
+
+else{
+s= name_pos= *argv;dot_pos= NULL;
+while(*s){
+if(*s=='.')dot_pos= s++;
+#line 47 "common.ch"
+#ifdef __EMX__
+else if(*s==':'||*s=='\\'||*s=='/')
+dot_pos= NULL,name_pos= ++s;
+#else
+else if(*s=='/')dot_pos= NULL,name_pos= ++s;
+#endif
+#line 1264 "common.w"
+ else s++;
+}
+if(!found_web)/*71:*/
+#line 1284 "common.w"
+
+{
+if(s-*argv>max_file_name_length-5)
+/*76:*/
+#line 1360 "common.w"
+fatal("! Filename too long\n",*argv);
+
+
+/*:76*/
+#line 1287 "common.w"
+;
+if(dot_pos==NULL)
+sprintf(web_file_name,"%s.w",*argv);
+else{
+strcpy(web_file_name,*argv);
+*dot_pos= 0;
+}
+sprintf(alt_web_file_name,"%s.web",*argv);
+sprintf(tex_file_name,"%s.tex",name_pos);
+sprintf(idx_file_name,"%s.idx",name_pos);
+sprintf(scn_file_name,"%s.scn",name_pos);
+sprintf(C_file_name,"%s.c",name_pos);
+found_web= 1;
+}
+
+/*:71*/
+#line 1267 "common.w"
+
+else if(!found_change)/*72:*/
+#line 1302 "common.w"
+
+{
+if(strcmp(*argv,"-")==0)found_change= -1;
+else{
+if(s-*argv>max_file_name_length-4)
+/*76:*/
+#line 1360 "common.w"
+fatal("! Filename too long\n",*argv);
+
+
+/*:76*/
+#line 1307 "common.w"
+;
+if(dot_pos==NULL)
+sprintf(change_file_name,"%s.ch",*argv);
+else strcpy(change_file_name,*argv);
+found_change= 1;
+}
+}
+
+/*:72*/
+#line 1268 "common.w"
+
+else if(!found_out)/*73:*/
+#line 1315 "common.w"
+
+{
+if(s-*argv>max_file_name_length-5)
+/*76:*/
+#line 1360 "common.w"
+fatal("! Filename too long\n",*argv);
+
+
+/*:76*/
+#line 1318 "common.w"
+;
+if(dot_pos==NULL){
+sprintf(tex_file_name,"%s.tex",*argv);
+sprintf(idx_file_name,"%s.idx",*argv);
+sprintf(scn_file_name,"%s.scn",*argv);
+sprintf(C_file_name,"%s.c",*argv);
+}else{
+strcpy(tex_file_name,*argv);
+if(flags['x']){
+if(program==cweave&&strcmp(*argv+strlen(*argv)-4,".tex")!=0)
+fatal("! Output file name should end with .tex\n",*argv);
+
+strcpy(idx_file_name,*argv);
+strcpy(idx_file_name+strlen(*argv)-4,".idx");
+strcpy(scn_file_name,*argv);
+strcpy(scn_file_name+strlen(*argv)-4,".scn");
+}
+strcpy(C_file_name,*argv);
+}
+found_out= 1;
+}
+
+/*:73*/
+#line 1269 "common.w"
+
+else/*75:*/
+#line 1348 "common.w"
+
+{
+if(program==ctangle)
+fatal(
+"! Usage: ctangle [options] webfile[.w] [{changefile[.ch]|-} [outfile[.c]]]\n"
+,"");
+
+else fatal(
+#line 69 "common.ch"
+"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n"
+"\n"
+" possible options: (default values shown)\n"
+"\n"
+" -a alternative output format\n"
+" +b show banner\n"
+" +f force line breaks after C statements\n"
+" +h print happy message if successful\n"
+" -i append () after functions in index\n"
+" +p give progress reports\n"
+" -s show memory statistics\n"
+" +x include indices and table of contents\n","");
+#line 1358 "common.w"
+}
+
+/*:75*/
+#line 1270 "common.w"
+;
+}
+}
+if(!found_web)/*75:*/
+#line 1348 "common.w"
+
+{
+if(program==ctangle)
+fatal(
+"! Usage: ctangle [options] webfile[.w] [{changefile[.ch]|-} [outfile[.c]]]\n"
+,"");
+
+else fatal(
+#line 69 "common.ch"
+"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n"
+"\n"
+" possible options: (default values shown)\n"
+"\n"
+" -a alternative output format\n"
+" +b show banner\n"
+" +f force line breaks after C statements\n"
+" +h print happy message if successful\n"
+" -i append () after functions in index\n"
+" +p give progress reports\n"
+" -s show memory statistics\n"
+" +x include indices and table of contents\n","");
+#line 1358 "common.w"
+}
+
+/*:75*/
+#line 1273 "common.w"
+;
+#line 58 "common.ch"
+#ifdef __EMX__
+if(found_change<=0)strcpy(change_file_name,"NUL");
+#else
+if(found_change<=0)strcpy(change_file_name,"/dev/null");
+#endif
+#line 1275 "common.w"
+}
+
+/*:70*/
diff --git a/web/c_cpp/c2cweb/cweb/common.ch b/web/c_cpp/c2cweb/cweb/common.ch
new file mode 100644
index 0000000000..f591d774bf
--- /dev/null
+++ b/web/c_cpp/c2cweb/cweb/common.ch
@@ -0,0 +1,83 @@
+This file is part of the c2cweb package Version 1.5
+
+This is the change file for CWEB's COMMON (Ver. 3.2 July 1994)
+
+modified by Werner Lemberg (a7971428@@unet.univie.ac.at) 10-Nov-1996
+
+===============================================================================
+
+@x section 7
+@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */
+@y
+@d buf_size 400 /* for \.{CWEAVE} and \.{CTANGLE} */
+@z
+
+@x section 27
+@d max_bytes 90000 /* the number of bytes in identifiers,
+ index entries, and section names; must be less than $2^{24}$ */
+@d max_names 4000 /* number of identifiers, strings, section names;
+ must be less than 10240 */
+@y
+@d max_bytes 225000 /* the number of bytes in identifiers,
+ index entries, and section names; must be less than $2^{24}$ */
+@d max_names 10000 /* number of identifiers, strings, section names;
+ must be less than 10240 */
+@z
+
+@x section 40
+ char Ilk; /* used by identifiers in \.{CWEAVE} only */
+} dummy;
+@y
+ struct {
+ char Ilk; /* used by identifiers in \.{CWEAVE} only */
+ boolean Func_flag; } dummy1;
+} dummy;
+@z
+
+@x section 69
+An omitted change file argument means that |"/dev/null"| should be used,
+@y
+An omitted change file argument means that |"/dev/null"| (or |"NUL"| under DOS
+and OS/2) should be used,
+@z
+
+@x section 70
+ else if (*s=='/') dot_pos=NULL,name_pos=++s;
+@y
+#ifdef __EMX__
+ else if (*s == ':' || *s == '\\' || *s == '/')
+ dot_pos=NULL,name_pos=++s;
+#else
+ else if (*s=='/') dot_pos=NULL,name_pos=++s;
+#endif
+@z
+
+@x section 70
+ if (found_change<=0) strcpy(change_file_name,"/dev/null");
+@y
+#ifdef __EMX__
+ if (found_change<=0) strcpy(change_file_name,"NUL");
+#else
+ if (found_change<=0) strcpy(change_file_name,"/dev/null");
+#endif
+@z
+
+@x section 75
+"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n"
+ ,"");
+@y
+"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n"
+"\n"
+" possible options: (default values shown)\n"
+"\n"
+" -a alternative output format\n"
+" +b show banner\n"
+" +f force line breaks after C statements\n"
+" +h print happy message if successful\n"
+" -i append () after functions in index\n"
+" +p give progress reports\n"
+" -s show memory statistics\n"
+" +x include indices and table of contents\n", "");
+@z
+
+--- end of common.ch ---
diff --git a/web/c_cpp/c2cweb/cweb/common.h b/web/c_cpp/c2cweb/cweb/common.h
new file mode 100644
index 0000000000..200ec27358
--- /dev/null
+++ b/web/c_cpp/c2cweb/cweb/common.h
@@ -0,0 +1,201 @@
+% This file is part of CWEB.
+% This program by Silvio Levy and Donald E. Knuth
+% is based on a program by Knuth.
+% It is distributed WITHOUT ANY WARRANTY, express or implied.
+% Version 3.0 --- June 1993
+
+% Copyright (C) 1987,1990,1993 Silvio Levy and Donald E. Knuth
+
+% this file is part of the c2cweb package Version 1.5
+% modified by Werner Lemberg (a7971428@@unet.univie.ac.at) 10-Nov-1996
+
+% Permission is granted to make and distribute verbatim copies of this
+% document provided that the copyright notice and this permission notice
+% are preserved on all copies.
+
+% Permission is granted to copy and distribute modified versions of this
+% document 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.
+
+% Please send comments, suggestions, etc. to levy@@geom.umn.edu.
+
+% The next few sections contain stuff from the file |"common.w"| that has
+% to be included in both |"ctangle.w"| and |"cweave.w"|. It appears in this
+% file |"common.h"|, which needs to be updated when |"common.w"| changes.
+
+First comes general stuff:
+
+@d ctangle 0
+@d cweave 1
+
+@<Common code for \.{CWEAVE} and \.{CTANGLE}@>=
+typedef short boolean;
+typedef char unsigned eight_bits;
+extern boolean program; /* \.{CWEAVE} or \.{CTANGLE}? */
+extern int phase; /* which phase are we in? */
+
+@ @<Include files@>=
+#include <stdio.h>
+
+@ Code related to the character set:
+@^ASCII code dependencies@>
+
+@d and_and 04 /* `\.{\&\&}'\,; corresponds to MIT's {\tentex\char'4} */
+@d lt_lt 020 /* `\.{<<}'\,; corresponds to MIT's {\tentex\char'20} */
+@d gt_gt 021 /* `\.{>>}'\,; corresponds to MIT's {\tentex\char'21} */
+@d plus_plus 013 /* `\.{++}'\,; corresponds to MIT's {\tentex\char'13} */
+@d minus_minus 01 /* `\.{--}'\,; corresponds to MIT's {\tentex\char'1} */
+@d minus_gt 031 /* `\.{->}'\,; corresponds to MIT's {\tentex\char'31} */
+@d not_eq 032 /* `\.{!=}'\,; corresponds to MIT's {\tentex\char'32} */
+@d lt_eq 034 /* `\.{<=}'\,; corresponds to MIT's {\tentex\char'34} */
+@d gt_eq 035 /* `\.{>=}'\,; corresponds to MIT's {\tentex\char'35} */
+@d eq_eq 036 /* `\.{==}'\,; corresponds to MIT's {\tentex\char'36} */
+@d or_or 037 /* `\.{\v\v}'\,; corresponds to MIT's {\tentex\char'37} */
+@d dot_dot_dot 016 /* `\.{...}'\,; corresponds to MIT's {\tentex\char'16} */
+@d colon_colon 06 /* `\.{::}'\,; corresponds to MIT's {\tentex\char'6} */
+@d period_ast 026 /* `\.{.*}'\,; corresponds to MIT's {\tentex\char'26} */
+@d minus_gt_ast 027 /* `\.{->*}'\,; corresponds to MIT's {\tentex\char'27} */
+
+@<Common code...@>=
+char section_text[longest_name+1]; /* name being sought for */
+char *section_text_end = section_text+longest_name; /* end of |section_text| */
+char *id_first; /* where the current identifier begins in the buffer */
+char *id_loc; /* just after the current identifier in the buffer */
+
+@ Code related to input routines:
+
+@d xisalpha(c) (isalpha(c)&&((eight_bits)c<0200))
+@d xisdigit(c) (isdigit(c)&&((eight_bits)c<0200))
+@d xisspace(c) (isspace(c)&&((eight_bits)c<0200))
+@d xislower(c) (islower(c)&&((eight_bits)c<0200))
+@d xisupper(c) (isupper(c)&&((eight_bits)c<0200))
+@d xisxdigit(c) (isxdigit(c)&&((eight_bits)c<0200))
+
+@<Common code...@>=
+extern char buffer[]; /* where each line of input goes */
+extern char *buffer_end; /* end of |buffer| */
+extern char *loc; /* points to the next character to be read from the buffer*/
+extern char *limit; /* points to the last character in the buffer */
+
+@ Code related to identifier and section name storage:
+@d length(c) (c+1)->byte_start-(c)->byte_start /* the length of a name */
+@d print_id(c) term_write((c)->byte_start,length((c))) /* print identifier */
+@d llink link /* left link in binary search tree for section names */
+@d rlink dummy.Rlink /* right link in binary search tree for section names */
+@d root name_dir->rlink /* the root of the binary search tree
+ for section names */
+@d chunk_marker 0
+
+@<Common code...@>=
+typedef struct name_info {
+ char *byte_start; /* beginning of the name in |byte_mem| */
+ struct name_info *link;
+ union {
+ struct name_info *Rlink; /* right link in binary search tree for section
+ names */
+ struct {
+ char Ilk; /* used by identifiers in \.{CWEAVE} only */
+ boolean Func_flag;
+ } dummy1;
+ } dummy;
+ char *equiv_or_xref; /* info corresponding to names */
+} name_info; /* contains information about an identifier or section name */
+typedef name_info *name_pointer; /* pointer into array of \&{name\_info}s */
+typedef name_pointer *hash_pointer;
+extern char byte_mem[]; /* characters of names */
+extern char *byte_mem_end; /* end of |byte_mem| */
+extern name_info name_dir[]; /* information about names */
+extern name_pointer name_dir_end; /* end of |name_dir| */
+extern name_pointer name_ptr; /* first unused position in |byte_start| */
+extern char *byte_ptr; /* first unused position in |byte_mem| */
+extern name_pointer hash[]; /* heads of hash lists */
+extern hash_pointer hash_end; /* end of |hash| */
+extern hash_pointer h; /* index into hash-head array */
+extern name_pointer id_lookup(); /* looks up a string in the identifier table */
+extern name_pointer section_lookup(); /* finds section name */
+extern void print_section_name(), sprint_section_name();
+
+@ Code related to error handling:
+@d spotless 0 /* |history| value for normal jobs */
+@d harmless_message 1 /* |history| value when non-serious info was printed */
+@d error_message 2 /* |history| value when an error was noted */
+@d fatal_message 3 /* |history| value when we had to stop prematurely */
+@d mark_harmless {if (history==spotless) history=harmless_message;}
+@d mark_error history=error_message
+@d confusion(s) fatal("! This can't happen: ",s)
+
+@<Common...@>=
+extern history; /* indicates how bad this run was */
+extern err_print(); /* print error message and context */
+extern wrap_up(); /* indicate |history| and exit */
+extern void fatal(); /* issue error message and die */
+extern void overflow(); /* succumb because a table has overflowed */
+
+@ Code related to file handling:
+@f line x /* make |line| an unreserved word */
+@d max_file_name_length 60
+@d cur_file file[include_depth] /* current file */
+@d cur_file_name file_name[include_depth] /* current file name */
+@d web_file_name file_name[0] /* main source file name */
+@d cur_line line[include_depth] /* number of current line in current file */
+
+@<Common code...@>=
+extern include_depth; /* current level of nesting */
+extern FILE *file[]; /* stack of non-change files */
+extern FILE *change_file; /* change file */
+extern char C_file_name[]; /* name of |C_file| */
+extern char tex_file_name[]; /* name of |tex_file| */
+extern char idx_file_name[]; /* name of |idx_file| */
+extern char scn_file_name[]; /* name of |scn_file| */
+extern char file_name[][max_file_name_length];
+ /* stack of non-change file names */
+extern char change_file_name[]; /* name of change file */
+extern line[]; /* number of current line in the stacked files */
+extern change_line; /* number of current line in change file */
+extern boolean input_has_ended; /* if there is no more input */
+extern boolean changing; /* if the current line is from |change_file| */
+extern boolean web_file_open; /* if the web file is being read */
+extern reset_input(); /* initialize to read the web file and change file */
+extern get_line(); /* inputs the next line */
+extern check_complete(); /* checks that all changes were picked up */
+
+@ Code related to section numbers:
+@<Common code...@>=
+typedef unsigned short sixteen_bits;
+extern sixteen_bits section_count; /* the current section number */
+extern boolean changed_section[]; /* is the section changed? */
+extern boolean change_pending; /* is a decision about change still unclear? */
+extern boolean print_where; /* tells \.{CTANGLE} to print line and file info */
+
+@ Code related to command line arguments:
+@d show_banner flags['b'] /* should the banner line be printed? */
+@d show_progress flags['p'] /* should progress reports be printed? */
+@d show_happiness flags['h'] /* should lack of errors be announced? */
+
+@<Common code...@>=
+extern int argc; /* copy of |ac| parameter to |main| */
+extern char **argv; /* copy of |av| parameter to |main| */
+extern boolean flags[]; /* an option for each 7-bit code */
+
+@ Code relating to output:
+@d update_terminal fflush(stdout) /* empty the terminal output buffer */
+@d new_line putchar('\n') @d putxchar putchar
+@d term_write(a,b) fflush(stdout),fwrite(a,sizeof(char),b,stdout)
+@d C_printf(c,a) fprintf(C_file,c,a)
+@d C_putc(c) putc(c,C_file)
+
+@<Common code...@>=
+extern FILE *C_file; /* where output of \.{CTANGLE} goes */
+extern FILE *tex_file; /* where output of \.{CWEAVE} goes */
+extern FILE *idx_file; /* where index from \.{CWEAVE} goes */
+extern FILE *scn_file; /* where list of sections from \.{CWEAVE} goes */
+extern FILE *active_file; /* currently active file for \.{CWEAVE} output */
+
+@ The procedure that gets everything rolling:
+
+@<Common code...@>=
+extern void common_init();
+
+
+@q end of common.h @>
diff --git a/web/c_cpp/c2cweb/cweb/common.w b/web/c_cpp/c2cweb/cweb/common.w
new file mode 100644
index 0000000000..48caf68e24
--- /dev/null
+++ b/web/c_cpp/c2cweb/cweb/common.w
@@ -0,0 +1,1415 @@
+% This file is part of CWEB.
+% This program by Silvio Levy and Donald E. Knuth
+% is based on a program by Knuth.
+% It is distributed WITHOUT ANY WARRANTY, express or implied.
+% Version 3.3 --- December 1994 (works with later versions too)
+
+% Copyright (C) 1987,1990,1993 Silvio Levy and Donald E. Knuth
+
+% Permission is granted to make and distribute verbatim copies of this
+% document provided that the copyright notice and this permission notice
+% are preserved on all copies.
+
+% Permission is granted to copy and distribute modified versions of this
+% document under the conditions for verbatim copying, provided that the
+% entire resulting derived work is given a different name and distributed
+% under the terms of a permission notice identical to this one.
+
+\def\v{\char'174} % vertical (|) in typewriter font
+
+\def\title{Common code for CTANGLE and CWEAVE (Version 3.3)}
+\def\topofcontents{\null\vfill
+ \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and
+ {\ttitlefont CWEAVE}}
+ \vskip 15pt
+ \centerline{(Version 3.3)}
+ \vfill}
+\def\botofcontents{\vfill
+\noindent
+Copyright \copyright\ 1987, 1990, 1993 Silvio Levy and Donald E. Knuth
+\bigskip\noindent
+Permission is granted to make and distribute verbatim copies of this
+document provided that the copyright notice and this permission notice
+are preserved on all copies.
+
+\smallskip\noindent
+Permission is granted to copy and distribute modified versions of this
+document under the conditions for verbatim copying, provided that the
+entire resulting derived work is given a different name and distributed
+under the terms of a permission notice identical to this one.
+}
+
+\pageno=\contentspagenumber \advance\pageno by 1
+\let\maybe=\iftrue
+
+@** Introduction. This file contains code common
+to both \.{CTANGLE} and \.{CWEAVE}, which roughly concerns the following
+problems: character uniformity, input routines, error handling and
+parsing of command line. We have tried to concentrate in this file
+all the system dependencies, so as to maximize portability.
+
+In the texts below we will
+sometimes use \.{CWEB} to refer to either of the two component
+programs, if no confusion can arise.
+
+The file begins with a few basic definitions.
+
+@c
+@<Include files@>@/
+@h
+@<Definitions that should agree with \.{CTANGLE} and \.{CWEAVE}@>@/
+@<Other definitions@>@/
+@<Predeclaration of procedures@>@/
+
+@ In certain cases \.{CTANGLE} and \.{CWEAVE} should do almost, but not
+quite, the same thing. In these cases we've written common code for
+both, differentiating between the two by means of the global variable
+|program|.
+
+@d ctangle 0
+@d cweave 1
+
+@<Definitions...@>=
+typedef short boolean;
+boolean program; /* \.{CWEAVE} or \.{CTANGLE}? */
+
+@ \.{CWEAVE} operates in three phases: first it inputs the source
+file and stores cross-reference data, then it inputs the source once again and
+produces the \TEX/ output file, and finally it sorts and outputs the index.
+Similarly, \.{CTANGLE} operates in two phases.
+The global variable |phase| tells which phase we are in.
+
+@<Other...@>= int phase; /* which phase are we in? */
+
+@ There's an initialization procedure that gets both \.{CTANGLE} and
+\.{CWEAVE} off to a good start. We will fill in the details of this
+procedure later.
+
+@c
+void
+common_init()
+{
+ @<Initialize pointers@>;
+ @<Set the default options common to \.{CTANGLE} and \.{CWEAVE}@>;
+ @<Scan arguments and open output files@>;
+}
+
+@*1 The character set.
+\.{CWEB} uses the conventions of \CEE/ programs found in the standard
+\.{ctype.h} header file.
+
+@<Include files@>=
+#include <ctype.h>
+
+@ A few character pairs are encoded internally as single characters,
+using the definitions below. These definitions are consistent with
+an extension of ASCII code originally developed at MIT and explained in
+Appendix~C of {\sl The \TEX/book\/}; thus, users who have such a
+character set can type things like \.{\char'32} and \.{\char'4} instead
+of \.{!=} and \.{\&\&}. (However, their files will not be too portable
+until more people adopt the extended code.)
+
+If the character set is not ASCII, the definitions given here may conflict
+with existing characters; in such cases, other arbitrary codes should be
+substituted. The indexes to \.{CTANGLE} and \.{CWEAVE} mention every
+case where similar codes may have to be changed in order to
+avoid character conflicts. Look for the entry ``ASCII code dependencies''
+in those indexes.
+
+@^ASCII code dependencies@>
+@^system dependencies@>
+
+@d and_and 04 /* `\.{\&\&}'\,; corresponds to MIT's {\tentex\char'4} */
+@d lt_lt 020 /* `\.{<<}'\,; corresponds to MIT's {\tentex\char'20} */
+@d gt_gt 021 /* `\.{>>}'\,; corresponds to MIT's {\tentex\char'21} */
+@d plus_plus 013 /* `\.{++}'\,; corresponds to MIT's {\tentex\char'13} */
+@d minus_minus 01 /* `\.{--}'\,; corresponds to MIT's {\tentex\char'1} */
+@d minus_gt 031 /* `\.{->}'\,; corresponds to MIT's {\tentex\char'31} */
+@d not_eq 032 /* `\.{!=}'\,; corresponds to MIT's {\tentex\char'32} */
+@d lt_eq 034 /* `\.{<=}'\,; corresponds to MIT's {\tentex\char'34} */
+@d gt_eq 035 /* `\.{>=}'\,; corresponds to MIT's {\tentex\char'35} */
+@d eq_eq 036 /* `\.{==}'\,; corresponds to MIT's {\tentex\char'36} */
+@d or_or 037 /* `\.{\v\v}'\,; corresponds to MIT's {\tentex\char'37} */
+@d dot_dot_dot 016 /* `\.{...}'\,; corresponds to MIT's {\tentex\char'16} */
+@d colon_colon 06 /* `\.{::}'\,; corresponds to MIT's {\tentex\char'6} */
+@d period_ast 026 /* `\.{.*}'\,; corresponds to MIT's {\tentex\char'26} */
+@d minus_gt_ast 027 /* `\.{->*}'\,; corresponds to MIT's {\tentex\char'27} */
+
+@** Input routines. The lowest level of input to the \.{CWEB} programs
+is performed by |input_ln|, which must be told which file to read from.
+The return value of |input_ln| is 1 if the read is successful and 0 if
+not (generally this means the file has ended). The conventions
+of \TEX/ are followed; i.e., the characters of the next line of the file
+are copied into the |buffer| array,
+and the global variable |limit| is set to the first unoccupied position.
+Trailing blanks are ignored. The value of |limit| must be strictly less
+than |buf_size|, so that |buffer[buf_size-1]| is never filled.
+
+Since |buf_size| is strictly less than |long_buf_size|,
+some of \.{CWEB}'s routines use the fact that it is safe to refer to
+|*(limit+2)| without overstepping the bounds of the array.
+
+@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */
+@d longest_name 1000
+@d long_buf_size (buf_size+longest_name) /* for \.{CWEAVE} */
+@d xisspace(c) (isspace(c)&&((unsigned char)c<0200))
+@d xisupper(c) (isupper(c)&&((unsigned char)c<0200))
+
+@<Definitions...@>=
+char buffer[long_buf_size]; /* where each line of input goes */
+char *buffer_end=buffer+buf_size-2; /* end of |buffer| */
+char *limit=buffer; /* points to the last character in the buffer */
+char *loc=buffer; /* points to the next character to be read from the buffer */
+
+@ @<Include files@>=
+#include <stdio.h>
+
+@ In the unlikely event that your standard I/O library does not
+support |feof|, |getc| and |ungetc| you may have to change things here.
+@^system dependencies@>
+
+@c
+int input_ln(fp) /* copies a line into |buffer| or returns 0 */
+FILE *fp; /* what file to read from */
+{
+ register int c=EOF; /* character read; initialized so some compilers won't complain */
+ register char *k; /* where next character goes */
+ if (feof(fp)) return(0); /* we have hit end-of-file */
+ limit = k = buffer; /* beginning of buffer */
+ while (k<=buffer_end && (c=getc(fp)) != EOF && c!='\n')
+ if ((*(k++) = c) != ' ') limit = k;
+ if (k>buffer_end)
+ if ((c=getc(fp))!=EOF && c!='\n') {
+ ungetc(c,fp); loc=buffer; err_print("! Input line too long");
+@.Input line too long@>
+ }
+ if (c==EOF && limit==buffer) return(0); /* there was nothing after
+ the last newline */
+ return(1);
+}
+
+@ Now comes the problem of deciding which file to read from next.
+Recall that the actual text that \.{CWEB} should process comes from two
+streams: a |web_file|, which can contain possibly nested include
+commands \.{@@i}, and a |change_file|, which might also contain
+includes. The |web_file| together with the currently open include
+files form a stack |file|, whose names are stored in a parallel stack
+|file_name|. The boolean |changing| tells whether or not we're reading
+from the |change_file|.
+
+The line number of each open file is also kept for error reporting and
+for the benefit of \.{CTANGLE}.
+
+@f line x /* make |line| an unreserved word */
+@d max_include_depth 10 /* maximum number of source files open
+ simultaneously, not counting the change file */
+@d max_file_name_length 60
+@d cur_file file[include_depth] /* current file */
+@d cur_file_name file_name[include_depth] /* current file name */
+@d cur_line line[include_depth] /* number of current line in current file */
+@d web_file file[0] /* main source file */
+@d web_file_name file_name[0] /* main source file name */
+
+@<Definitions...@>=
+int include_depth; /* current level of nesting */
+FILE *file[max_include_depth]; /* stack of non-change files */
+FILE *change_file; /* change file */
+char file_name[max_include_depth][max_file_name_length];
+ /* stack of non-change file names */
+char change_file_name[max_file_name_length]; /* name of change file */
+char alt_web_file_name[max_file_name_length]; /* alternate name to try */
+int line[max_include_depth]; /* number of current line in the stacked files */
+int change_line; /* number of current line in change file */
+int change_depth; /* where \.{@@y} originated during a change */
+boolean input_has_ended; /* if there is no more input */
+boolean changing; /* if the current line is from |change_file| */
+boolean web_file_open=0; /* if the web file is being read */
+
+@ When |changing==0|, the next line of |change_file| is kept in
+|change_buffer|, for purposes of comparison with the next
+line of |cur_file|. After the change file has been completely input, we
+set |change_limit=change_buffer|,
+so that no further matches will be made.
+
+Here's a shorthand expression for inequality between the two lines:
+
+@d lines_dont_match (change_limit-change_buffer != limit-buffer ||
+ strncmp(buffer, change_buffer, limit-buffer))
+
+@<Other...@>=
+char change_buffer[buf_size]; /* next line of |change_file| */
+char *change_limit; /* points to the last character in |change_buffer| */
+
+@ Procedure |prime_the_change_buffer|
+sets |change_buffer| in preparation for the next matching operation.
+Since blank lines in the change file are not used for matching, we have
+|(change_limit==change_buffer && !changing)| if and only if
+the change file is exhausted. This procedure is called only when
+|changing| is 1; hence error messages will be reported correctly.
+
+@c
+void
+prime_the_change_buffer()
+{
+ change_limit=change_buffer; /* this value is used if the change file ends */
+ @<Skip over comment lines in the change file; |return| if end of file@>;
+ @<Skip to the next nonblank line; |return| if end of file@>;
+ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>;
+}
+
+@ While looking for a line that begins with \.{@@x} in the change file, we
+allow lines that begin with \.{@@}, as long as they don't begin with \.{@@y},
+\.{@@z} or \.{@@i} (which would probably mean that the change file is fouled up).
+
+@<Skip over comment lines in the change file...@>=
+while(1) {
+ change_line++;
+ if (!input_ln(change_file)) return;
+ if (limit<buffer+2) continue;
+ if (buffer[0]!='@@') continue;
+ if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]);
+ if (buffer[1]=='x') break;
+ if (buffer[1]=='y' || buffer[1]=='z' || buffer[1]=='i') {
+ loc=buffer+2;
+ err_print("! Missing @@x in change file");
+@.Missing @@x...@>
+ }
+}
+
+@ Here we are looking at lines following the \.{@@x}.
+
+@<Skip to the next nonblank line...@>=
+do {
+ change_line++;
+ if (!input_ln(change_file)) {
+ err_print("! Change file ended after @@x");
+@.Change file ended...@>
+ return;
+ }
+} while (limit==buffer);
+
+@ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>=
+{
+ change_limit=change_buffer-buffer+limit;
+ strncpy(change_buffer,buffer,limit-buffer+1);
+}
+
+@ The following procedure is used to see if the next change entry should
+go into effect; it is called only when |changing| is 0.
+The idea is to test whether or not the current
+contents of |buffer| matches the current contents of |change_buffer|.
+If not, there's nothing more to do; but if so, a change is called for:
+All of the text down to the \.{@@y} is supposed to match. An error
+message is issued if any discrepancy is found. Then the procedure
+prepares to read the next line from |change_file|.
+
+When a match is found, the current section is marked as changed unless
+the first line after the \.{@@x} and after the \.{@@y} both start with
+either |'@@*'| or |'@@ '| (possibly preceded by whitespace).
+
+This procedure is called only when |buffer<limit|, i.e., when the
+current line is nonempty.
+
+@d if_section_start_make_pending(b) {@+*limit='!';
+ for (loc=buffer;xisspace(*loc);loc++) ;
+ *limit=' ';
+ if (*loc=='@@' && (xisspace(*(loc+1)) || *(loc+1)=='*')) change_pending=b;
+}
+
+@c
+void
+check_change() /* switches to |change_file| if the buffers match */
+{
+ int n=0; /* the number of discrepancies found */
+ if (lines_dont_match) return;
+ change_pending=0;
+ if (!changed_section[section_count]) {
+ if_section_start_make_pending(1);
+ if (!change_pending) changed_section[section_count]=1;
+ }
+ while (1) {
+ changing=1; print_where=1; change_line++;
+ if (!input_ln(change_file)) {
+ err_print("! Change file ended before @@y");
+@.Change file ended...@>
+ change_limit=change_buffer; changing=0;
+ return;
+ }
+ if (limit>buffer+1 && buffer[0]=='@@') {
+ if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]);
+ @<If the current line starts with \.{@@y},
+ report any discrepancies and |return|@>;
+ }
+ @<Move |buffer| and |limit|...@>;
+ changing=0; cur_line++;
+ while (!input_ln(cur_file)) { /* pop the stack or quit */
+ if (include_depth==0) {
+ err_print("! CWEB file ended during a change");
+@.CWEB file ended...@>
+ input_has_ended=1; return;
+ }
+ include_depth--; cur_line++;
+ }
+ if (lines_dont_match) n++;
+ }
+}
+
+@ @<If the current line starts with \.{@@y}...@>=
+if (buffer[1]=='x' || buffer[1]=='z') {
+ loc=buffer+2; err_print("! Where is the matching @@y?");
+@.Where is the match...@>
+ }
+else if (buffer[1]=='y') {
+ if (n>0) {
+ loc=buffer+2;
+ printf("\n! Hmm... %d ",n);
+ err_print("of the preceding lines failed to match");
+@.Hmm... n of the preceding...@>
+ }
+ change_depth=include_depth;
+ return;
+}
+
+@ The |reset_input| procedure, which gets \.{CWEB} ready to read the
+user's \.{CWEB} input, is used at the beginning of phase one of \.{CTANGLE},
+phases one and two of \.{CWEAVE}.
+
+@c
+void
+reset_input()
+{
+ limit=buffer; loc=buffer+1; buffer[0]=' ';
+ @<Open input files@>;
+ include_depth=0; cur_line=0; change_line=0;
+ change_depth=include_depth;
+ changing=1; prime_the_change_buffer(); changing=!changing;
+ limit=buffer; loc=buffer+1; buffer[0]=' '; input_has_ended=0;
+}
+
+@ The following code opens the input files.
+@^system dependencies@>
+
+@<Open input files@>=
+if ((web_file=fopen(web_file_name,"r"))==NULL) {
+ strcpy(web_file_name,alt_web_file_name);
+ if ((web_file=fopen(web_file_name,"r"))==NULL)
+ fatal("! Cannot open input file ", web_file_name);
+}
+@.Cannot open input file@>
+@.Cannot open change file@>
+web_file_open=1;
+if ((change_file=fopen(change_file_name,"r"))==NULL)
+ fatal("! Cannot open change file ", change_file_name);
+
+@ The |get_line| procedure is called when |loc>limit|; it puts the next
+line of merged input into the buffer and updates the other variables
+appropriately. A space is placed at the right end of the line.
+This procedure returns |!input_has_ended| because we often want to
+check the value of that variable after calling the procedure.
+
+If we've just changed from the |cur_file| to the |change_file|, or if
+the |cur_file| has changed, we tell \.{CTANGLE} to print this
+information in the \CEE/ file by means of the |print_where| flag.
+
+@d max_sections 2000 /* number of identifiers, strings, section names;
+ must be less than 10240 */
+
+@<Defin...@>=
+typedef unsigned short sixteen_bits;
+sixteen_bits section_count; /* the current section number */
+boolean changed_section[max_sections]; /* is the section changed? */
+boolean change_pending; /* if the current change is not yet recorded in
+ |changed_section[section_count]| */
+boolean print_where=0; /* should \.{CTANGLE} print line and file info? */
+
+@ @c
+int get_line() /* inputs the next line */
+{
+ restart:
+ if (changing && include_depth==change_depth)
+ @<Read from |change_file| and maybe turn off |changing|@>;
+ if (! changing || include_depth>change_depth) {
+ @<Read from |cur_file| and maybe turn on |changing|@>;
+ if (changing && include_depth==change_depth) goto restart;
+ }
+ loc=buffer; *limit=' ';
+ if (*buffer=='@@' && (*(buffer+1)=='i' || *(buffer+1)=='I')) {
+ loc=buffer+2;
+ while (loc<=limit && (*loc==' '||*loc=='\t'||*loc=='"')) loc++;
+ if (loc>=limit) {
+ err_print("! Include file name not given");
+@.Include file name ...@>
+ goto restart;
+ }
+ if (include_depth>=max_include_depth-1) {
+ err_print("! Too many nested includes");
+@.Too many nested includes@>
+ goto restart;
+ }
+ include_depth++; /* push input stack */
+ @<Try to open include file, abort push if unsuccessful, go to |restart|@>;
+ }
+ return (!input_has_ended);
+}
+
+@ When an \.{@@i} line is found in the |cur_file|, we must temporarily
+stop reading it and start reading from the named include file. The
+\.{@@i} line should give a complete file name with or without
+double quotes.
+If the environment variable \.{CWEBINPUTS} is set, or if the compiler flag
+of the same name was defined at compile time,
+\.{CWEB} will look for include files in the directory thus named, if
+it cannot find them in the current directory.
+(Colon-separated paths are not supported.)
+The remainder of the \.{@@i} line after the file name is ignored.
+
+@d too_long() {include_depth--;
+ err_print("! Include file name too long"); goto restart;}
+
+@<Include...@>=
+#include <stdlib.h> /* declaration of |getenv| and |exit| */
+
+@ @<Try to open...@>= {
+ char temp_file_name[max_file_name_length];
+ char *cur_file_name_end=cur_file_name+max_file_name_length-1;
+ char *k=cur_file_name, *kk;
+ int l; /* length of file name */
+
+ while (*loc!=' '&&*loc!='\t'&&*loc!='"'&&k<=cur_file_name_end) *k++=*loc++;
+ if (k>cur_file_name_end) too_long();
+@.Include file name ...@>
+ *k='\0';
+ if ((cur_file=fopen(cur_file_name,"r"))!=NULL) {
+ cur_line=0; print_where=1;
+ goto restart; /* success */
+ }
+ kk=getenv("CWEBINPUTS");
+ if (kk!=NULL) {
+ if ((l=strlen(kk))>max_file_name_length-2) too_long();
+ strcpy(temp_file_name,kk);
+ }
+ else {
+#ifdef CWEBINPUTS
+ if ((l=strlen(CWEBINPUTS))>max_file_name_length-2) too_long();
+ strcpy(temp_file_name,CWEBINPUTS);
+#else
+ l=0;
+#endif /* |CWEBINPUTS| */
+ }
+ if (l>0) {
+ if (k+l+2>=cur_file_name_end) too_long();
+@.Include file name ...@>
+ for (; k>= cur_file_name; k--) *(k+l+1)=*k;
+ strcpy(cur_file_name,temp_file_name);
+ cur_file_name[l]='/'; /* \UNIX/ pathname separator */
+ if ((cur_file=fopen(cur_file_name,"r"))!=NULL) {
+ cur_line=0; print_where=1;
+ goto restart; /* success */
+ }
+ }
+ include_depth--; err_print("! Cannot open include file"); goto restart;
+}
+
+@ @<Read from |cur_file|...@>= {
+ cur_line++;
+ while (!input_ln(cur_file)) { /* pop the stack or quit */
+ print_where=1;
+ if (include_depth==0) {input_has_ended=1; break;}
+ else {
+ fclose(cur_file); include_depth--;
+ if (changing && include_depth==change_depth) break;
+ cur_line++;
+ }
+ }
+ if (!changing && !input_has_ended)
+ if (limit-buffer==change_limit-change_buffer)
+ if (buffer[0]==change_buffer[0])
+ if (change_limit>change_buffer) check_change();
+}
+
+@ @<Read from |change_file|...@>= {
+ change_line++;
+ if (!input_ln(change_file)) {
+ err_print("! Change file ended without @@z");
+@.Change file ended...@>
+ buffer[0]='@@'; buffer[1]='z'; limit=buffer+2;
+ }
+ if (limit>buffer) { /* check if the change has ended */
+ if (change_pending) {
+ if_section_start_make_pending(0);
+ if (change_pending) {
+ changed_section[section_count]=1; change_pending=0;
+ }
+ }
+ *limit=' ';
+ if (buffer[0]=='@@') {
+ if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]);
+ if (buffer[1]=='x' || buffer[1]=='y') {
+ loc=buffer+2;
+ err_print("! Where is the matching @@z?");
+@.Where is the match...@>
+ }
+ else if (buffer[1]=='z') {
+ prime_the_change_buffer(); changing=!changing; print_where=1;
+ }
+ }
+ }
+}
+
+@ At the end of the program, we will tell the user if the change file
+had a line that didn't match any relevant line in |web_file|.
+
+@c
+void
+check_complete(){
+ if (change_limit!=change_buffer) { /* |changing| is 0 */
+ strncpy(buffer,change_buffer,change_limit-change_buffer+1);
+ limit=buffer+(int)(change_limit-change_buffer);
+ changing=1; change_depth=include_depth; loc=buffer;
+ err_print("! Change file entry did not match");
+@.Change file entry did not match@>
+ }
+}
+
+@** Storage of names and strings.
+Both \.{CWEAVE} and \.{CTANGLE} store identifiers, section names and
+other strings in a large array of |char|s, called |byte_mem|.
+Information about the names is kept in the array |name_dir|, whose
+elements are structures of type |name_info|, containing a pointer into
+the |byte_mem| array (the address where the name begins) and other data.
+A |name_pointer| variable is a pointer into |name_dir|.
+
+@d max_bytes 90000 /* the number of bytes in identifiers,
+ index entries, and section names; must be less than $2^{24}$ */
+@d max_names 4000 /* number of identifiers, strings, section names;
+ must be less than 10240 */
+
+@<Definitions that...@>=
+typedef struct name_info {
+ char *byte_start; /* beginning of the name in |byte_mem| */
+ @<More elements of |name_info| structure@>@;
+} name_info; /* contains information about an identifier or section name */
+typedef name_info *name_pointer; /* pointer into array of |name_info|s */
+char byte_mem[max_bytes]; /* characters of names */
+char *byte_mem_end = byte_mem+max_bytes-1; /* end of |byte_mem| */
+name_info name_dir[max_names]; /* information about names */
+name_pointer name_dir_end = name_dir+max_names-1; /* end of |name_dir| */
+
+@ The actual sequence of characters in the name pointed to by a |name_pointer
+p| appears in positions |p->byte_start| to |(p+1)->byte_start-1|, inclusive.
+The |print_id| macro prints this text on the user's terminal.
+
+@d length(c) (c+1)->byte_start-(c)->byte_start /* the length of a name */
+@d print_id(c) term_write((c)->byte_start,length((c))) /* print identifier */
+
+@ The first unused position in |byte_mem| and |name_dir| is
+kept in |byte_ptr| and |name_ptr|, respectively. Thus we
+usually have |name_ptr->byte_start==byte_ptr|, and certainly
+we want to keep |name_ptr<=name_dir_end| and |byte_ptr<=byte_mem_end|.
+
+@<Defini...@>=
+name_pointer name_ptr; /* first unused position in |byte_start| */
+char *byte_ptr; /* first unused position in |byte_mem| */
+
+@ @<Init...@>=
+name_dir->byte_start=byte_ptr=byte_mem; /* position zero in both arrays */
+name_ptr=name_dir+1; /* |name_dir[0]| will be used only for error recovery */
+name_ptr->byte_start=byte_mem; /* this makes name 0 of length zero */
+
+@ The names of identifiers are found by computing a hash address |h| and
+then looking at strings of bytes signified by the |name_pointer|s
+|hash[h]|, |hash[h]->link|, |hash[h]->link->link|, \dots,
+until either finding the desired name or encountering the null pointer.
+
+@<More elements of |name...@>=
+struct name_info *link;
+
+@ The hash table itself
+consists of |hash_size| entries of type |name_pointer|, and is
+updated by the |id_lookup| procedure, which finds a given identifier
+and returns the appropriate |name_pointer|. The matching is done by the
+function |names_match|, which is slightly different in
+\.{CWEAVE} and \.{CTANGLE}. If there is no match for the identifier,
+it is inserted into the table.
+
+@d hash_size 353 /* should be prime */
+
+@<Defini...@>=
+typedef name_pointer *hash_pointer;
+name_pointer hash[hash_size]; /* heads of hash lists */
+hash_pointer hash_end = hash+hash_size-1; /* end of |hash| */
+hash_pointer h; /* index into hash-head array */
+
+@ @<Predec...@>=
+extern int names_match();
+
+@ Initially all the hash lists are empty.
+
+@<Init...@>=
+for (h=hash; h<=hash_end; *h++=NULL) ;
+
+@ Here is the main procedure for finding identifiers:
+
+@c
+name_pointer
+id_lookup(first,last,t) /* looks up a string in the identifier table */
+char *first; /* first character of string */
+char *last; /* last character of string plus one */
+char t; /* the |ilk|; used by \.{CWEAVE} only */
+{
+ char *i=first; /* position in |buffer| */
+ int h; /* hash code */
+ int l; /* length of the given identifier */
+ name_pointer p; /* where the identifier is being sought */
+ if (last==NULL) for (last=first; *last!='\0'; last++);
+ l=last-first; /* compute the length */
+ @<Compute the hash code |h|@>;
+ @<Compute the name location |p|@>;
+ if (p==name_ptr) @<Enter a new name into the table at position |p|@>;
+ return(p);
+}
+
+@ A simple hash code is used: If the sequence of
+character codes is $c_1c_2\ldots c_n$, its hash value will be
+$$(2^{n-1}c_1+2^{n-2}c_2+\cdots+c_n)\,\bmod\,|hash_size|.$$
+
+@<Compute the hash...@>=
+h=(unsigned char)*i;
+while (++i<last) h=(h+h+(int)((unsigned char)*i)) % hash_size;
+@^high-bit character handling@>
+
+@ If the identifier is new, it will be placed in position |p=name_ptr|,
+otherwise |p| will point to its existing location.
+
+@<Compute the name location...@>=
+p=hash[h];
+while (p && !names_match(p,first,l,t)) p=p->link;
+if (p==NULL) {
+ p=name_ptr; /* the current identifier is new */
+ p->link=hash[h]; hash[h]=p; /* insert |p| at beginning of hash list */
+}
+
+@ The information associated with a new identifier must be initialized
+in a slightly different way in \.{CWEAVE} than in \.{CTANGLE}; hence the
+|init_p| procedure.
+
+@<Pred...@>=
+void init_p();
+
+@ @<Enter a new name...@>= {
+ if (byte_ptr+l>byte_mem_end) overflow("byte memory");
+ if (name_ptr>=name_dir_end) overflow("name");
+ strncpy(byte_ptr,first,l);
+ (++name_ptr)->byte_start=byte_ptr+=l;
+ if (program==cweave) init_p(p,t);
+}
+
+@ The names of sections are stored in |byte_mem| together
+with the identifier names, but a hash table is not used for them because
+\.{CTANGLE} needs to be able to recognize a section name when given a prefix of
+that name. A conventional binary search tree is used to retrieve section names,
+with fields called |llink| and |rlink| (where |llink| takes the place
+of |link|). The root of this tree is stored in |name_dir->rlink|;
+this will be the only information in |name_dir[0]|.
+
+Since the space used by |rlink| has a different function for
+identifiers than for section names, we declare it as a |union|.
+
+@d llink link /* left link in binary search tree for section names */
+@d rlink dummy.Rlink /* right link in binary search tree for section names */
+@d root name_dir->rlink /* the root of the binary search tree
+ for section names */
+
+@<More elements of |name...@>=
+union {
+ struct name_info *Rlink; /* right link in binary search tree for section
+ names */
+ char Ilk; /* used by identifiers in \.{CWEAVE} only */
+} dummy;
+
+@ @<Init...@>=
+root=NULL; /* the binary search tree starts out with nothing in it */
+
+@ If |p| is a |name_pointer| variable, as we have seen,
+|p->byte_start| is the beginning of the area where the name
+corresponding to |p| is stored. However, if |p| refers to a section
+name, the name may need to be stored in chunks, because it may
+``grow'': a prefix of the section name may be encountered before
+the full name. Furthermore we need to know the length of the shortest
+prefix of the name that was ever encountered.
+
+We solve this problem by inserting two extra bytes at |p->byte_start|,
+representing the length of the shortest prefix, when |p| is a
+section name. Furthermore, the last byte of the name will be a blank
+space if |p| is a prefix. In the latter case, the name pointer
+|p+1| will allow us to access additional chunks of the name:
+The second chunk will begin at the name pointer |(p+1)->link|,
+and if it too is a prefix (ending with blank) its |link| will point
+to additional chunks in the same way. Null links are represented by
+|name_dir|.
+
+@d first_chunk(p) ((p)->byte_start+2)
+@d prefix_length(p) (int)((unsigned char)*((p)->byte_start)*256 +
+ (unsigned char)*((p)->byte_start+1))
+@d set_prefix_length(p,m) (*((p)->byte_start)=(m)/256,
+ *((p)->byte_start+1)=(m)%256)
+
+@c
+void
+print_section_name(p)
+name_pointer p;
+{
+ char *ss, *s = first_chunk(p);
+ name_pointer q = p+1;
+ while (p!=name_dir) {
+ ss = (p+1)->byte_start-1;
+ if (*ss==' ' && ss>=s) {
+ term_write(s,ss-s); p=q->link; q=p;
+ } else {
+ term_write(s,ss+1-s); p=name_dir; q=NULL;
+ }
+ s = p->byte_start;
+ }
+ if (q) term_write("...",3); /* complete name not yet known */
+}
+
+@ @c
+void
+sprint_section_name(dest,p)
+ char*dest;
+ name_pointer p;
+{
+ char *ss, *s = first_chunk(p);
+ name_pointer q = p+1;
+ while (p!=name_dir) {
+ ss = (p+1)->byte_start-1;
+ if (*ss==' ' && ss>=s) {
+ p=q->link; q=p;
+ } else {
+ ss++; p=name_dir;
+ }
+ strncpy(dest,s,ss-s), dest+=ss-s;
+ s = p->byte_start;
+ }
+ *dest='\0';
+}
+
+@ @c
+void
+print_prefix_name(p)
+name_pointer p;
+{
+ char *s = first_chunk(p);
+ int l = prefix_length(p);
+ term_write(s,l);
+ if (s+l<(p+1)->byte_start) term_write("...",3);
+}
+
+@ When we compare two section names, we'll need a function analogous to
+|strcmp|. But we do not assume the strings
+are null-terminated, and we keep an eye open for prefixes and extensions.
+
+@d less 0 /* the first name is lexicographically less than the second */
+@d equal 1 /* the first name is equal to the second */
+@d greater 2 /* the first name is lexicographically greater than the second */
+@d prefix 3 /* the first name is a proper prefix of the second */
+@d extension 4 /* the first name is a proper extension of the second */
+
+@c
+int web_strcmp(j,j_len,k,k_len) /* fuller comparison than |strcmp| */
+ char *j, *k; /* beginning of first and second strings */
+ int j_len, k_len; /* length of strings */
+{
+ char *j1=j+j_len, *k1=k+k_len;
+ while (k<k1 && j<j1 && *j==*k) k++, j++;
+ if (k==k1) if (j==j1) return equal;
+ else return extension;
+ else if (j==j1) return prefix;
+ else if (*j<*k) return less;
+ else return greater;
+}
+
+@ Adding a section name to the tree is straightforward if we know its
+parent and whether it's the |rlink| or |llink| of the parent. As a
+special case, when the name is the first section being added, we set the
+``parent'' to |NULL|. When a section name is created, it has only one
+chunk, which however may be just a prefix: the full name will
+hopefully be unveiled later. Obviously, |prefix_length| starts
+out as the length of the first chunk, though it may decrease later.
+
+The information associated with a new node must be initialized
+differently in \.{CWEAVE} and \.{CTANGLE}; hence the
+|init_node| procedure, which is defined differently in \.{cweave.w}
+and \.{ctangle.w}.
+
+@<Prede...@>=
+extern void init_node();
+
+@ @c
+name_pointer
+add_section_name(par,c,first,last,ispref) /* install a new node in the tree */
+name_pointer par; /* parent of new node */
+int c; /* right or left? */
+char *first; /* first character of section name */
+char *last; /* last character of section name, plus one */
+int ispref; /* are we adding a prefix or a full name? */
+{
+ name_pointer p=name_ptr; /* new node */
+ char *s=first_chunk(p);
+ int name_len=last-first+ispref; /* length of section name */
+ if (s+name_len>byte_mem_end) overflow("byte memory");
+ if (name_ptr+1>=name_dir_end) overflow("name");
+ (++name_ptr)->byte_start=byte_ptr=s+name_len;
+ if (ispref) {
+ *(byte_ptr-1)=' ';
+ name_len--;
+ name_ptr->link=name_dir;
+ (++name_ptr)->byte_start=byte_ptr;
+ }
+ set_prefix_length(p,name_len);
+ strncpy(s,first,name_len);
+ p->llink=NULL;
+ p->rlink=NULL;
+ init_node(p);
+ return par==NULL ? (root=p) : c==less ? (par->llink=p) : (par->rlink=p);
+}
+
+@ @c
+void
+extend_section_name(p,first,last,ispref)
+name_pointer p; /* name to be extended */
+char *first; /* beginning of extension text */
+char *last; /* one beyond end of extension text */
+int ispref; /* are we adding a prefix or a full name? */
+{
+ char *s;
+ name_pointer q=p+1;
+ int name_len=last-first+ispref;
+ if (name_ptr>=name_dir_end) overflow("name");
+ while (q->link!=name_dir) q=q->link;
+ q->link=name_ptr;
+ s=name_ptr->byte_start;
+ name_ptr->link=name_dir;
+ if (s+name_len>byte_mem_end) overflow("byte memory");
+ (++name_ptr)->byte_start=byte_ptr=s+name_len;
+ strncpy(s,first,name_len);
+ if (ispref) *(byte_ptr-1)=' ';
+}
+
+@ The |section_lookup| procedure is supposed to find a
+section name that matches a new name, installing the new name if
+it doesn't match an existing one. The new name is the string
+between |first| and |last|; a ``match'' means that the new name
+exactly equals or is a prefix or extension of a name in the tree.
+
+@c
+name_pointer
+section_lookup(first,last,ispref) /* find or install section name in tree */
+char *first, *last; /* first and last characters of new name */
+int ispref; /* is the new name a prefix or a full name? */
+{
+ int c=0; /* comparison between two names; initialized so some compilers won't complain */
+ name_pointer p=root; /* current node of the search tree */
+ name_pointer q=NULL; /* another place to look in the tree */
+ name_pointer r=NULL; /* where a match has been found */
+ name_pointer par=NULL; /* parent of |p|, if |r| is |NULL|;
+ otherwise parent of |r| */
+ int name_len=last-first+1;
+ @<Look for matches for new name among shortest prefixes, complaining
+ if more than one is found@>;
+ @<If no match found, add new name to tree@>;
+ @<If one match found, check for compatibility and return match@>;
+}
+
+@ A legal new name matches an existing section name if and only if it
+matches the shortest prefix of that section name. Therefore we can
+limit our search for matches to shortest prefixes, which eliminates
+the need for chunk-chasing at this stage.
+
+@<Look for matches for new name among...@>=
+while (p) { /* compare shortest prefix of |p| with new name */
+ c=web_strcmp(first,name_len,first_chunk(p),prefix_length(p));
+ if (c==less || c==greater) { /* new name does not match |p| */
+ if (r==NULL) /* no previous matches have been found */
+ par=p;
+ p=(c==less?p->llink:p->rlink);
+ } else { /* new name matches |p| */
+ if (r!=NULL) { /* and also |r|: illegal */
+ printf("\n! Ambiguous prefix: matches <");
+@.Ambiguous prefix ... @>
+ print_prefix_name(p);
+ printf(">\n and <");
+ print_prefix_name(r);
+ err_print(">");
+ return name_dir; /* the unsection */
+ }
+ r=p; /* remember match */
+ p=p->llink; /* try another */
+ q=r->rlink; /* we'll get back here if the new |p| doesn't match */
+ }
+ if (p==NULL)
+ p=q, q=NULL; /* |q| held the other branch of |r| */
+}
+
+@ @<If no match ...@>=
+ if (r==NULL) /* no matches were found */
+ return add_section_name(par,c,first,last+1,ispref);
+
+@ Although error messages are given in anomalous cases, we do return the
+unique best match when a discrepancy is found, because users often
+change a title in one place while forgetting to change it elsewhere.
+
+@<If one match found, check for compatibility and return match@>=
+switch(section_name_cmp(&first,name_len,r)) {
+ /* compare all of |r| with new name */
+ case prefix:
+ if (!ispref) {
+ printf("\n! New name is a prefix of <");
+@.New name is a prefix...@>
+ print_section_name(r);
+ err_print(">");
+ }
+ else if (name_len<prefix_length(r)) set_prefix_length(r,name_len);
+ /* fall through */
+ case equal: return r;
+ case extension: if (!ispref || first<=last)
+ extend_section_name(r,first,last+1,ispref);
+ return r;
+ case bad_extension:
+ printf("\n! New name extends <");
+@.New name extends...@>
+ print_section_name(r);
+ err_print(">");
+ return r;
+ default: /* no match: illegal */
+ printf("\n! Section name incompatible with <");
+@.Section name incompatible...@>
+ print_prefix_name(r);
+ printf(">,\n which abbreviates <");
+ print_section_name(r);
+ err_print(">");
+ return r;
+}
+
+@ The return codes of |section_name_cmp|, which compares a string with
+the full name of a section, are those of |web_strcmp| plus
+|bad_extension|, used when the string is an extension of a
+supposedly already complete section name. This function has a side
+effect when the comparison string is an extension: it advances the
+address of the first character of the string by an amount equal to
+the length of the known part of the section name.
+
+The name \.{@@<foo...@@>} should be an acceptable ``abbreviation''
+for \.{@@<foo@@>}. If such an abbreviation comes after the complete
+name, there's no trouble recognizing it. If it comes before the
+complete name, we simply append a null chunk. This logic requires
+us to regard \.{@@<foo...@@>} as an ``extension'' of itself.
+
+@d bad_extension 5
+
+@<Predec...@>=
+int section_name_cmp();
+
+@ @c
+int section_name_cmp(pfirst,len,r)
+char **pfirst; /* pointer to beginning of comparison string */
+int len; /* length of string */
+name_pointer r; /* section name being compared */
+{
+ char *first=*pfirst; /* beginning of comparison string */
+ name_pointer q=r+1; /* access to subsequent chunks */
+ char *ss, *s=first_chunk(r);
+ int c; /* comparison */
+ int ispref; /* is chunk |r| a prefix? */
+ while (1) {
+ ss=(r+1)->byte_start-1;
+ if (*ss==' ' && ss>=r->byte_start) ispref=1,q=q->link;
+ else ispref=0,ss++,q=name_dir;
+ switch(c=web_strcmp(first,len,s,ss-s)) {
+ case equal: if (q==name_dir)
+ if (ispref) {
+ *pfirst=first+(ss-s);
+ return extension; /* null extension */
+ } else return equal;
+ else return (q->byte_start==(q+1)->byte_start)? equal: prefix;
+ case extension:
+ if (!ispref) return bad_extension;
+ first += ss-s;
+ if (q!=name_dir) {len -= ss-s; s=q->byte_start; r=q; continue;}
+ *pfirst=first; return extension;
+ default: return c;
+ }
+ }
+}
+
+@ The last component of |name_info| is different for \.{CTANGLE} and
+\.{CWEAVE}. In \.{CTANGLE}, if |p| is a pointer to a section name,
+|p->equiv| is a pointer to its replacement text, an element of the
+array |text_info|. In \.{CWEAVE}, on the other hand, if
+|p| points to an identifier, |p->xref| is a pointer to its
+list of cross-references, an element of the array |xmem|. The make-up
+of |text_info| and |xmem| is discussed in the \.{CTANGLE} and \.{CWEAVE}
+source files, respectively; here we just declare a common field
+|equiv_or_xref| as a pointer to a |char|.
+
+@<More elements of |name...@>=
+char *equiv_or_xref; /* info corresponding to names */
+
+@** Reporting errors to the user.
+A global variable called |history| will contain one of four values
+at the end of every run: |spotless| means that no unusual messages were
+printed; |harmless_message| means that a message of possible interest
+was printed but no serious errors were detected; |error_message| means that
+at least one error was found; |fatal_message| means that the program
+terminated abnormally. The value of |history| does not influence the
+behavior of the program; it is simply computed for the convenience
+of systems that might want to use such information.
+
+@d spotless 0 /* |history| value for normal jobs */
+@d harmless_message 1 /* |history| value when non-serious info was printed */
+@d error_message 2 /* |history| value when an error was noted */
+@d fatal_message 3 /* |history| value when we had to stop prematurely */
+@d mark_harmless {if (history==spotless) history=harmless_message;}
+@d mark_error history=error_message
+
+@<Definit...@>=
+int history=spotless; /* indicates how bad this run was */
+
+@ The command `|err_print("! Error message")|' will report a syntax error to
+the user, by printing the error message at the beginning of a new line and
+then giving an indication of where the error was spotted in the source file.
+Note that no period follows the error message, since the error routine
+will automatically supply a period. A newline is automatically supplied
+if the string begins with |"!"|.
+
+@<Predecl...@>=
+void err_print();
+
+@ @c
+void
+err_print(s) /* prints `\..' and location of error message */
+char *s;
+{
+ char *k,*l; /* pointers into |buffer| */
+ printf(*s=='!'? "\n%s" : "%s",s);
+ if(web_file_open) @<Print error location based on input buffer@>;
+ update_terminal; mark_error;
+}
+
+@ The error locations can be indicated by using the global variables
+|loc|, |cur_line|, |cur_file_name| and |changing|,
+which tell respectively the first
+unlooked-at position in |buffer|, the current line number, the current
+file, and whether the current line is from |change_file| or |cur_file|.
+This routine should be modified on systems whose standard text editor
+has special line-numbering conventions.
+@^system dependencies@>
+
+@<Print error location based on input buffer@>=
+{if (changing && include_depth==change_depth)
+ printf(". (l. %d of change file)\n", change_line);
+else if (include_depth==0) printf(". (l. %d)\n", cur_line);
+ else printf(". (l. %d of include file %s)\n", cur_line, cur_file_name);
+l= (loc>=limit? limit: loc);
+if (l>buffer) {
+ for (k=buffer; k<l; k++)
+ if (*k=='\t') putchar(' ');
+ else putchar(*k); /* print the characters already read */
+ putchar('\n');
+ for (k=buffer; k<l; k++) putchar(' '); /* space out the next line */
+}
+for (k=l; k<limit; k++) putchar(*k); /* print the part not yet read */
+if (*limit=='|') putchar('|'); /* end of \CEE/ text in section names */
+putchar(' '); /* to separate the message from future asterisks */
+}
+
+@ When no recovery from some error has been provided, we have to wrap
+up and quit as graciously as possible. This is done by calling the
+function |wrap_up| at the end of the code.
+
+\.{CTANGLE} and \.{CWEAVE} have their own notions about how to
+print the job statistics.
+
+@<Prede...@>=
+int wrap_up();
+extern void print_stats();
+
+@ Some implementations may wish to pass the |history| value to the
+operating system so that it can be used to govern whether or not other
+programs are started. Here, for instance, we pass the operating system
+a status of 0 if and only if only harmless messages were printed.
+@^system dependencies@>
+
+@c
+int wrap_up() {
+ putchar('\n');
+ if (show_stats)
+ print_stats(); /* print statistics about memory usage */
+ @<Print the job |history|@>;
+ if (history > harmless_message) return(1);
+ else return(0);
+}
+
+@ @<Print the job |history|@>=
+switch (history) {
+case spotless: if (show_happiness) printf("(No errors were found.)\n"); break;
+case harmless_message:
+ printf("(Did you see the warning message above?)\n"); break;
+case error_message:
+ printf("(Pardon me, but I think I spotted something wrong.)\n"); break;
+case fatal_message: printf("(That was a fatal error, my friend.)\n");
+} /* there are no other cases */
+
+@ When there is no way to recover from an error, the |fatal| subroutine is
+invoked. This happens most often when |overflow| occurs.
+
+@<Predec...@>=
+void fatal(), overflow();
+
+@ The two parameters to |fatal| are strings that are essentially
+concatenated to print the final error message.
+
+@c void
+fatal(s,t)
+ char *s,*t;
+{
+ if (*s) printf(s);
+ err_print(t);
+ history=fatal_message; exit(wrap_up());
+}
+
+@ An overflow stop occurs if \.{CWEB}'s tables aren't large enough.
+
+@c void
+overflow(t)
+ char *t;
+{
+ printf("\n! Sorry, %s capacity exceeded",t); fatal("","");
+}
+@.Sorry, capacity exceeded@>
+
+@ Sometimes the program's behavior is far different from what it should be,
+and \.{CWEB} prints an error message that is really for the \.{CWEB}
+maintenance person, not the user. In such cases the program says
+|confusion("indication of where we are")|.
+
+@d confusion(s) fatal("! This can't happen: ",s)
+@.This can't happen@>
+
+@** Command line arguments.
+The user calls \.{CWEAVE} and \.{CTANGLE} with arguments on the command line.
+These are either file names or flags to be turned off (beginning with |"-"|)
+or flags to be turned on (beginning with |"+"|).
+The following globals are for communicating the user's desires to the rest
+of the program. The various file name variables contain strings with
+the names of those files. Most of the 128 flags are undefined but available
+for future extensions.
+
+@d show_banner flags['b'] /* should the banner line be printed? */
+@d show_progress flags['p'] /* should progress reports be printed? */
+@d show_stats flags['s'] /* should statistics be printed at end of run? */
+@d show_happiness flags['h'] /* should lack of errors be announced? */
+
+@<Defin...@>=
+int argc; /* copy of |ac| parameter to |main| */
+char **argv; /* copy of |av| parameter to |main| */
+char C_file_name[max_file_name_length]; /* name of |C_file| */
+char tex_file_name[max_file_name_length]; /* name of |tex_file| */
+char idx_file_name[max_file_name_length]; /* name of |idx_file| */
+char scn_file_name[max_file_name_length]; /* name of |scn_file| */
+boolean flags[128]; /* an option for each 7-bit code */
+
+@ The |flags| will be initially zero. Some of them are set to~1 before
+scanning the arguments; if additional flags are 1 by default they
+should be set before calling |common_init|.
+
+@<Set the default options common to \.{CTANGLE} and \.{CWEAVE}@>=
+show_banner=show_happiness=show_progress=1;
+
+@ We now must look at the command line arguments and set the file names
+accordingly. At least one file name must be present: the \.{CWEB}
+file. It may have an extension, or it may omit the extension to get |".w"| or
+|".web"| added. The \TEX/ output file name is formed by replacing the \.{CWEB}
+file name extension by |".tex"|, and the \CEE/ file name by replacing
+the extension by |".c"|, after removing the directory name (if any).
+
+If there is a second file name present among the arguments, it is the
+change file, again either with an extension or without one to get |".ch"|.
+An omitted change file argument means that |"/dev/null"| should be used,
+when no changes are desired.
+@^system dependencies@>
+
+If there's a third file name, it will be the output file.
+
+@<Pred...@>=
+void scan_args();
+
+@ @c
+void
+scan_args()
+{
+ char *dot_pos; /* position of |'.'| in the argument */
+ char *name_pos; /* file name beginning, sans directory */
+ register char *s; /* register for scanning strings */
+ boolean found_web=0,found_change=0,found_out=0;
+ /* have these names have been seen? */
+ boolean flag_change;
+
+ while (--argc > 0) {
+ if ((**(++argv)=='-'||**argv=='+')&&*(*argv+1)) @<Handle flag argument@>@;
+ else {
+ s=name_pos=*argv;@+dot_pos=NULL;
+ while (*s) {
+ if (*s=='.') dot_pos=s++;
+ else if (*s=='/') dot_pos=NULL,name_pos=++s;
+ else s++;
+ }
+ if (!found_web) @<Make
+ |web_file_name|, |tex_file_name| and |C_file_name|@>@;
+ else if (!found_change) @<Make |change_file_name| from |fname|@>@;
+ else if (!found_out) @<Override |tex_file_name| and |C_file_name|@>@;
+ else @<Print usage error message and quit@>;
+ }
+ }
+ if (!found_web) @<Print usage error message and quit@>;
+ if (found_change<=0) strcpy(change_file_name,"/dev/null");
+}
+
+@ We use all of |*argv| for the |web_file_name| if there is a |'.'| in it,
+otherwise we add |".w"|. If this file can't be opened, we prepare an
+|alt_web_file_name| by adding |"web"| after the dot.
+The other file names come from adding other things
+after the dot. We must check that there is enough room in
+|web_file_name| and the other arrays for the argument.
+
+@<Make |web_file_name|...@>=
+{
+ if (s-*argv > max_file_name_length-5)
+ @<Complain about argument length@>;
+ if (dot_pos==NULL)
+ sprintf(web_file_name,"%s.w",*argv);
+ else {
+ strcpy(web_file_name,*argv);
+ *dot_pos=0; /* string now ends where the dot was */
+ }
+ sprintf(alt_web_file_name,"%s.web",*argv);
+ sprintf(tex_file_name,"%s.tex",name_pos); /* strip off directory name */
+ sprintf(idx_file_name,"%s.idx",name_pos);
+ sprintf(scn_file_name,"%s.scn",name_pos);
+ sprintf(C_file_name,"%s.c",name_pos);
+ found_web=1;
+}
+
+@ @<Make |change_file_name|...@>=
+{
+ if (strcmp(*argv,"-")==0) found_change=-1;
+ else {
+ if (s-*argv > max_file_name_length-4)
+ @<Complain about argument length@>;
+ if (dot_pos==NULL)
+ sprintf(change_file_name,"%s.ch",*argv);
+ else strcpy(change_file_name,*argv);
+ found_change=1;
+ }
+}
+
+@ @<Override...@>=
+{
+ if (s-*argv > max_file_name_length-5)
+ @<Complain about argument length@>;
+ if (dot_pos==NULL) {
+ sprintf(tex_file_name,"%s.tex",*argv);
+ sprintf(idx_file_name,"%s.idx",*argv);
+ sprintf(scn_file_name,"%s.scn",*argv);
+ sprintf(C_file_name,"%s.c",*argv);
+ } else {
+ strcpy(tex_file_name,*argv);
+ if (flags['x']) { /* indexes will be generated */
+ if (program==cweave && strcmp(*argv+strlen(*argv)-4,".tex")!=0)
+ fatal("! Output file name should end with .tex\n",*argv);
+@.Output file name...tex@>
+ strcpy(idx_file_name,*argv);
+ strcpy(idx_file_name+strlen(*argv)-4,".idx");
+ strcpy(scn_file_name,*argv);
+ strcpy(scn_file_name+strlen(*argv)-4,".scn");
+ }
+ strcpy(C_file_name,*argv);
+ }
+ found_out=1;
+}
+
+@ @<Handle flag...@>=
+{
+ if (**argv=='-') flag_change=0;
+ else flag_change=1;
+ for(dot_pos=*argv+1;*dot_pos>'\0';dot_pos++)
+ flags[*dot_pos]=flag_change;
+}
+
+@ @<Print usage error message and quit@>=
+{
+if (program==ctangle)
+ fatal(
+"! Usage: ctangle [options] webfile[.w] [{changefile[.ch]|-} [outfile[.c]]]\n"
+ ,"");
+@.Usage:@>
+else fatal(
+"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n"
+ ,"");
+}
+
+@ @<Complain about arg...@>= fatal("! Filename too long\n", *argv);
+@.Filename too long@>
+
+@** Output. Here is the code that opens the output file:
+@^system dependencies@>
+
+@<Defin...@>=
+FILE *C_file; /* where output of \.{CTANGLE} goes */
+FILE *tex_file; /* where output of \.{CWEAVE} goes */
+FILE *idx_file; /* where index from \.{CWEAVE} goes */
+FILE *scn_file; /* where list of sections from \.{CWEAVE} goes */
+FILE *active_file; /* currently active file for \.{CWEAVE} output */
+
+@ @<Scan arguments and open output files@>=
+scan_args();
+if (program==ctangle) {
+ if ((C_file=fopen(C_file_name,"w"))==NULL)
+ fatal("! Cannot open output file ", C_file_name);
+@.Cannot open output file@>
+}
+else {
+ if ((tex_file=fopen(tex_file_name,"w"))==NULL)
+ fatal("! Cannot open output file ", tex_file_name);
+}
+
+@ The |update_terminal| procedure is called when we want
+to make sure that everything we have output to the terminal so far has
+actually left the computer's internal buffers and been sent.
+@^system dependencies@>
+
+@d update_terminal fflush(stdout) /* empty the terminal output buffer */
+
+@ Terminal output uses |putchar| and |putc| when we have to
+translate from \.{CWEB}'s code into the external character code,
+and |printf| when we just want to print strings.
+Several macros make other kinds of output convenient.
+@^system dependencies@>
+@d new_line putchar('\n') @d putxchar putchar
+@d term_write(a,b) fflush(stdout),fwrite(a,sizeof(char),b,stdout)
+@d C_printf(c,a) fprintf(C_file,c,a)
+@d C_putc(c) putc(c,C_file) /* isn't \CEE/ wonderfully consistent? */
+
+@ We predeclare several standard system functions here instead of including
+their system header files, because the names of the header files are not as
+standard as the names of the functions. (For example, some \CEE/ environments
+have \.{<string.h>} where others have \.{<strings.h>}.)
+
+@<Predecl...@>=
+extern int strlen(); /* length of string */
+extern int strcmp(); /* compare strings lexicographically */
+extern char* strcpy(); /* copy one string to another */
+extern int strncmp(); /* compare up to $n$ string characters */
+extern char* strncpy(); /* copy up to $n$ string characters */
+
+@** Index.
diff --git a/web/c_cpp/c2cweb/cweb/cweave.c b/web/c_cpp/c2cweb/cweb/cweave.c
new file mode 100644
index 0000000000..bff742feb7
--- /dev/null
+++ b/web/c_cpp/c2cweb/cweb/cweave.c
@@ -0,0 +1,4543 @@
+/*1:*/
+#line 66 "cweave.w"
+/*6:*/
+#line 38 "common.h"
+
+#include <stdio.h>
+
+/*:6*//*38:*/
+#line 644 "cweave.w"
+
+#include <ctype.h>
+#include <stdlib.h>
+
+/*:38*/
+#line 66 "cweave.w"
+
+#define banner "This is CWEAVE (Version 3.4) modified by Werner Lemberg (V1.5)\n" \
+
+#define max_bytes 225000 \
+
+#define max_names 10000 \
+
+#define max_sections 2000
+#define hash_size 353
+#define buf_size 400
+#define longest_name 1000
+#define long_buf_size (buf_size+longest_name)
+#define line_length 100 \
+
+#define max_refs 20000
+#define max_toks 65000 \
+
+#define max_texts 10200 \
+
+#define max_scraps 65000
+#define stack_size 10000 \
+
+#define ctangle 0
+#define cweave 1 \
+
+#define and_and 04
+#define lt_lt 020
+#define gt_gt 021
+#define plus_plus 013
+#define minus_minus 01
+#define minus_gt 031
+#define not_eq 032
+#define lt_eq 034
+#define gt_eq 035
+#define eq_eq 036
+#define or_or 037
+#define dot_dot_dot 016
+#define colon_colon 06
+#define period_ast 026
+#define minus_gt_ast 027 \
+
+#define xisalpha(c) (isalpha(c) &&((eight_bits) c<0200) )
+#define xisdigit(c) (isdigit(c) &&((eight_bits) c<0200) )
+#define xisspace(c) (isspace(c) &&((eight_bits) c<0200) )
+#define xislower(c) (islower(c) &&((eight_bits) c<0200) )
+#define xisupper(c) (isupper(c) &&((eight_bits) c<0200) )
+#define xisxdigit(c) (isxdigit(c) &&((eight_bits) c<0200) ) \
+
+#define length(c) (c+1) ->byte_start-(c) ->byte_start
+#define print_id(c) term_write((c) ->byte_start,length((c) ) )
+#define llink link
+#define rlink dummy.Rlink
+#define root name_dir->rlink \
+
+#define chunk_marker 0 \
+
+#define spotless 0
+#define harmless_message 1
+#define error_message 2
+#define fatal_message 3
+#define mark_harmless {if(history==spotless) history= harmless_message;}
+#define mark_error history= error_message
+#define confusion(s) fatal("! This can't happen: ",s) \
+
+#define max_file_name_length 60
+#define cur_file file[include_depth]
+#define cur_file_name file_name[include_depth]
+#define web_file_name file_name[0]
+#define cur_line line[include_depth] \
+
+#define show_banner flags['b']
+#define show_progress flags['p']
+#define show_happiness flags['h'] \
+
+#define update_terminal fflush(stdout)
+#define new_line putchar('\n')
+#define putxchar putchar
+#define term_write(a,b) fflush(stdout) ,fwrite(a,sizeof(char) ,b,stdout)
+#define C_printf(c,a) fprintf(C_file,c,a)
+#define C_putc(c) putc(c,C_file) \
+
+#define ilk dummy.dummy1.Ilk
+#define func_flag dummy.dummy1.Func_flag
+#define normal 0
+#define roman 1
+#define wildcard 2
+#define typewriter 3
+#define abnormal(a) (a->ilk>typewriter)
+#define custom 4
+#define unindexed(a) (a->ilk>custom)
+#define quoted 5
+#define else_like 26
+#define public_like 40
+#define operator_like 41
+#define new_like 42
+#define catch_like 43
+#define for_like 45
+#define do_like 46
+#define if_like 47
+#define raw_rpar 48
+#define raw_unorbin 49
+#define const_like 50
+#define raw_int 51
+#define int_like 52
+#define case_like 53
+#define sizeof_like 54
+#define struct_like 55
+#define typedef_like 56
+#define define_like 57 \
+
+#define file_flag (3*cite_flag)
+#define def_flag (2*cite_flag)
+#define cite_flag 10240
+#define xref equiv_or_xref \
+
+#define append_xref(c) if(xref_ptr==xmem_end) overflow("cross-reference") ; \
+else(++xref_ptr) ->num= c;
+#define no_xref (flags['x']==0)
+#define make_xrefs flags['x']
+#define is_tiny(p) ((p+1) ->byte_start==(p) ->byte_start+1) \
+
+#define ignore 00
+#define verbatim 02
+#define begin_short_comment 03
+#define begin_comment '\t'
+#define underline '\n'
+#define noop 0177
+#define xref_roman 0203
+#define xref_wildcard 0204
+#define xref_typewriter 0205
+#define TeX_string 0206
+#define ord 0207
+#define join 0210
+#define thin_space 0211
+#define math_break 0212
+#define line_break 0213
+#define big_line_break 0214
+#define no_line_break 0215
+#define pseudo_semi 0216
+#define macro_arg_open 0220
+#define macro_arg_close 0221
+#define trace 0222
+#define translit_code 0223
+#define output_defs_code 0224
+#define format_code 0225
+#define definition 0226
+#define begin_C 0227
+#define section_name 0230
+#define new_section 0231
+#define pseudo_lbrace 022
+#define pseudo_rbrace 023 \
+
+#define constant 0200
+#define string 0201
+#define identifier 0202 \
+
+#define isxalpha(c) ((c) =='_'||(c) =='$') \
+
+#define ishigh(c) ((eight_bits) (c) >0177) \
+ \
+
+#define left_preproc ord
+#define right_preproc 0217
+#define preproc_space '\b'
+#define numb_numb '\f' \
+
+#define compress(c) if(loc++<=limit) return(c) \
+
+#define c_line_write(c) fflush(active_file) ,fwrite(out_buf+1,sizeof(char) ,c,active_file)
+#define tex_putc(c) putc(c,active_file)
+#define tex_new_line putc('\n',active_file)
+#define tex_printf(c) fprintf(active_file,c) \
+
+#define app_tok(c) {if(tok_ptr+2>tok_mem_end) overflow("token") ;*(tok_ptr++) = c;} \
+
+#define exp 1
+#define unop 2
+#define binop 3
+#define unorbinop 4 \
+
+#define cast 5
+#define question 6
+#define lbrace 7
+#define rbrace 8
+#define decl_head 9
+#define comma 10
+#define lpar 11
+#define rpar 12
+#define prelangle 13
+#define prerangle 14
+#define langle 15
+#define colcol 18
+#define base 19
+#define decl 20
+#define struct_head 21
+#define stmt 23
+#define function 24
+#define fn_decl 25
+#define semi 27
+#define colon 28
+#define tag 29 \
+
+#define if_head 30
+#define else_head 31
+#define if_clause 32
+#define lproc 35
+#define rproc 36
+#define insert 37
+#define section_scrap 38
+#define dead 39
+#define begin_arg 58
+#define end_arg 59
+#define label 60
+#define do_head 61
+#define pp_space 62 \
+
+#define math_rel 0206
+#define big_cancel 0210
+#define cancel 0211
+#define indent 0212
+#define outdent 0213
+#define opt 0214
+#define backup 0215
+#define break_space 0216
+#define force 0217
+#define big_force 0220
+#define preproc_line 0221 \
+
+#define quoted_char 0222 \
+
+#define end_translation 0223
+#define inserted 0224 \
+
+#define trans trans_plus.Trans \
+
+#define id_flag 10240
+#define res_flag 2*id_flag
+#define section_flag 3*id_flag
+#define tok_flag 4*id_flag
+#define inner_tok_flag 5*id_flag \
+
+#define no_math 2
+#define yes_math 1
+#define maybe_math 0
+#define big_app2(a) big_app1(a) ;big_app1(a+1)
+#define big_app3(a) big_app2(a) ;big_app1(a+2)
+#define big_app4(a) big_app3(a) ;big_app1(a+3)
+#define app(a) *(tok_ptr++) = a
+#define app1(a) *(tok_ptr++) = tok_flag+(int) ((a) ->trans-tok_start) \
+
+#define cat1 (pp+1) ->cat
+#define cat2 (pp+2) ->cat
+#define cat3 (pp+3) ->cat
+#define lhs_not_simple (pp->cat!=semi&&pp->cat!=raw_int&&pp->cat!=raw_unorbin \
+&&pp->cat!=raw_rpar&&pp->cat!=const_like) \
+
+#define no_ident_found 0 \
+
+#define force_lines flags['f']
+#define freeze_text *(++text_ptr) = tok_ptr \
+
+#define safe_tok_incr 20
+#define safe_text_incr 10
+#define safe_scrap_incr 10 \
+
+#define app_scrap(c,b) { \
+(++scrap_ptr) ->cat= (c) ;scrap_ptr->trans= text_ptr; \
+scrap_ptr->mathness= 5*(b) ; \
+freeze_text; \
+} \
+
+#define alternative flags['a']
+#define func_index flags['i'] \
+ \
+
+#define inner 0
+#define outer 1 \
+
+#define cur_end cur_state.end_field
+#define cur_tok cur_state.tok_field
+#define cur_mode cur_state.mode_field
+#define init_stack stack_ptr= stack;cur_mode= outer \
+
+#define res_word 0201
+#define section_code 0200 \
+
+#define save_position save_line= out_line;save_place= out_ptr
+#define emit_space_if_needed if(save_line!=out_line||save_place!=out_ptr) \
+out_str("\\Y") ; \
+space_checked= 1 \
+ \
+
+#define depth cat
+#define head trans_plus.Head
+#define sort_pointer scrap_pointer
+#define sort_ptr scrap_ptr
+#define max_sorts max_scraps \
+
+#define infinity 255 \
+
+
+#line 67 "cweave.w"
+
+/*5:*/
+#line 32 "common.h"
+
+typedef short boolean;
+typedef char unsigned eight_bits;
+extern boolean program;
+extern int phase;
+
+/*:5*//*7:*/
+#line 60 "common.h"
+
+char section_text[longest_name+1];
+char*section_text_end= section_text+longest_name;
+char*id_first;
+char*id_loc;
+
+/*:7*//*8:*/
+#line 75 "common.h"
+
+extern char buffer[];
+extern char*buffer_end;
+extern char*loc;
+extern char*limit;
+
+/*:8*//*9:*/
+#line 90 "common.h"
+
+typedef struct name_info{
+char*byte_start;
+struct name_info*link;
+union{
+struct name_info*Rlink;
+
+struct{
+char Ilk;
+boolean Func_flag;
+}dummy1;
+}dummy;
+char*equiv_or_xref;
+}name_info;
+typedef name_info*name_pointer;
+typedef name_pointer*hash_pointer;
+extern char byte_mem[];
+extern char*byte_mem_end;
+extern name_info name_dir[];
+extern name_pointer name_dir_end;
+extern name_pointer name_ptr;
+extern char*byte_ptr;
+extern name_pointer hash[];
+extern hash_pointer hash_end;
+extern hash_pointer h;
+extern name_pointer id_lookup();
+extern name_pointer section_lookup();
+extern void print_section_name(),sprint_section_name();
+
+/*:9*//*10:*/
+#line 128 "common.h"
+
+extern history;
+extern err_print();
+extern wrap_up();
+extern void fatal();
+extern void overflow();
+
+/*:10*//*11:*/
+#line 143 "common.h"
+
+extern include_depth;
+extern FILE*file[];
+extern FILE*change_file;
+extern char C_file_name[];
+extern char tex_file_name[];
+extern char idx_file_name[];
+extern char scn_file_name[];
+extern char file_name[][max_file_name_length];
+
+extern char change_file_name[];
+extern line[];
+extern change_line;
+extern boolean input_has_ended;
+extern boolean changing;
+extern boolean web_file_open;
+extern reset_input();
+extern get_line();
+extern check_complete();
+
+/*:11*//*12:*/
+#line 164 "common.h"
+
+typedef unsigned short sixteen_bits;
+extern sixteen_bits section_count;
+extern boolean changed_section[];
+extern boolean change_pending;
+extern boolean print_where;
+
+/*:12*//*13:*/
+#line 176 "common.h"
+
+extern int argc;
+extern char**argv;
+extern boolean flags[];
+
+/*:13*//*14:*/
+#line 188 "common.h"
+
+extern FILE*C_file;
+extern FILE*tex_file;
+extern FILE*idx_file;
+extern FILE*scn_file;
+extern FILE*active_file;
+
+/*:14*//*15:*/
+#line 197 "common.h"
+
+extern void common_init();
+
+
+
+#line 140 "cweave.w"
+
+/*:15*/
+#line 68 "cweave.w"
+
+/*18:*/
+#line 222 "cweave.w"
+
+typedef struct xref_info{
+sixteen_bits num;
+struct xref_info*xlink;
+}xref_info;
+typedef xref_info*xref_pointer;
+
+/*:18*//*24:*/
+#line 332 "cweave.w"
+
+typedef sixteen_bits token;
+typedef token*token_pointer;
+typedef token_pointer*text_pointer;
+
+/*:24*//*103:*/
+#line 2012 "cweave.w"
+
+typedef struct{
+eight_bits cat;
+eight_bits mathness;
+union{
+text_pointer Trans;
+/*231:*/
+#line 4257 "cweave.w"
+
+name_pointer Head;
+
+/*:231*/
+#line 2018 "cweave.w"
+
+}trans_plus;
+}scrap;
+typedef scrap*scrap_pointer;
+
+/*:103*//*185:*/
+#line 3412 "cweave.w"
+typedef int mode;
+typedef struct{
+token_pointer end_field;
+token_pointer tok_field;
+boolean mode_field;
+}output_state;
+typedef output_state*stack_pointer;
+
+/*:185*/
+#line 69 "cweave.w"
+
+/*17:*/
+#line 197 "cweave.w"
+
+boolean change_exists;
+
+/*:17*//*19:*/
+#line 229 "cweave.w"
+
+xref_info xmem[max_refs];
+xref_pointer xmem_end= xmem+max_refs-1;
+xref_pointer xref_ptr;
+sixteen_bits xref_switch,section_xref_switch;
+
+/*:19*//*25:*/
+#line 342 "cweave.w"
+
+token tok_mem[max_toks];
+token_pointer tok_mem_end= tok_mem+max_toks-1;
+token_pointer tok_start[max_texts];
+token_pointer tok_ptr;
+text_pointer text_ptr;
+text_pointer tok_start_end= tok_start+max_texts-1;
+token_pointer max_tok_ptr;
+text_pointer max_text_ptr;
+
+/*:25*//*31:*/
+#line 521 "cweave.w"
+
+eight_bits ccode[256];
+
+/*:31*//*37:*/
+#line 640 "cweave.w"
+
+name_pointer cur_section;
+char cur_section_char;
+
+/*:37*//*41:*/
+#line 214 "cweave.ch"
+
+boolean preprocessing= 0;
+int define_pos= 0;
+
+#line 695 "cweave.w"
+
+/*:41*//*43:*/
+#line 706 "cweave.w"
+
+boolean sharp_include_line= 0;
+
+/*:43*//*58:*/
+#line 980 "cweave.w"
+
+eight_bits next_control;
+
+/*:58*//*68:*/
+#line 1136 "cweave.w"
+
+name_pointer lhs,rhs;
+
+/*:68*//*73:*/
+#line 1219 "cweave.w"
+
+xref_pointer cur_xref;
+boolean an_output;
+
+/*:73*//*77:*/
+#line 1261 "cweave.w"
+
+char out_buf[line_length+1];
+char*out_ptr;
+char*out_buf_end= out_buf+line_length;
+#line 268 "cweave.ch"
+int out_line;
+
+boolean in_math= 0;
+boolean escape= 0;
+int math_brace_count= 0;
+#line 1266 "cweave.w"
+
+/*:77*//*97:*/
+#line 1670 "cweave.w"
+
+char cat_name[256][12];
+eight_bits cat_index;
+
+/*:97*//*104:*/
+#line 2025 "cweave.w"
+
+scrap scrap_info[max_scraps];
+scrap_pointer scrap_info_end= scrap_info+max_scraps-1;
+scrap_pointer pp;
+scrap_pointer scrap_base;
+scrap_pointer scrap_ptr;
+scrap_pointer lo_ptr;
+scrap_pointer hi_ptr;
+scrap_pointer max_scr_ptr;
+
+/*:104*//*108:*/
+#line 2184 "cweave.w"
+
+int cur_mathness,init_mathness;
+
+/*:108*//*167:*/
+#line 2962 "cweave.w"
+
+int tracing;
+
+/*:167*//*186:*/
+#line 3425 "cweave.w"
+
+output_state cur_state;
+output_state stack[stack_size];
+stack_pointer stack_ptr;
+stack_pointer stack_end= stack+stack_size-1;
+stack_pointer max_stack_ptr;
+
+/*:186*//*190:*/
+#line 3475 "cweave.w"
+
+name_pointer cur_name;
+
+/*:190*//*206:*/
+#line 3831 "cweave.w"
+
+int save_line;
+char*save_place;
+int sec_depth;
+boolean space_checked;
+boolean format_visible;
+boolean doing_format= 0;
+boolean group_found= 0;
+
+/*:206*//*215:*/
+#line 4014 "cweave.w"
+
+name_pointer this_section;
+
+/*:215*//*226:*/
+#line 4198 "cweave.w"
+
+sixteen_bits k_section;
+
+/*:226*//*228:*/
+#line 4224 "cweave.w"
+
+name_pointer bucket[256];
+name_pointer next_name;
+name_pointer blink[max_names];
+
+/*:228*//*232:*/
+#line 4267 "cweave.w"
+
+eight_bits cur_depth;
+char*cur_byte;
+sixteen_bits cur_val;
+sort_pointer max_sort_ptr;
+
+/*:232*//*234:*/
+#line 4279 "cweave.w"
+
+eight_bits collate[102+128];
+
+
+/*:234*//*243:*/
+#line 4432 "cweave.w"
+
+xref_pointer next_xref,this_xref;
+
+
+/*:243*/
+#line 70 "cweave.w"
+
+/*2:*/
+#line 78 "cweave.w"
+
+extern int strlen();
+extern int strcmp();
+extern char*strcpy();
+extern int strncmp();
+extern char*strncpy();
+
+/*:2*//*34:*/
+#line 562 "cweave.w"
+
+void skip_limbo();
+
+/*:34*//*39:*/
+#line 655 "cweave.w"
+
+eight_bits get_next();
+
+/*:39*//*55:*/
+#line 933 "cweave.w"
+
+void skip_restricted();
+
+/*:55*//*59:*/
+#line 986 "cweave.w"
+
+void phase_one();
+
+/*:59*//*62:*/
+#line 1038 "cweave.w"
+
+void C_xref();
+
+/*:62*//*64:*/
+#line 1066 "cweave.w"
+
+void outer_xref();
+
+/*:64*//*74:*/
+#line 1227 "cweave.w"
+
+void section_check();
+
+/*:74*//*83:*/
+#line 1363 "cweave.w"
+
+void break_out();
+
+/*:83*//*91:*/
+#line 1506 "cweave.w"
+
+int copy_comment();
+
+/*:91*//*114:*/
+#line 2388 "cweave.w"
+
+void underline_xref();
+
+/*:114*//*180:*/
+#line 3289 "cweave.w"
+
+void app_cur_id();
+
+/*:180*//*193:*/
+#line 3544 "cweave.w"
+
+void make_output();
+
+/*:193*//*204:*/
+#line 3804 "cweave.w"
+
+void phase_two();
+
+/*:204*//*211:*/
+#line 3927 "cweave.w"
+
+void finish_C();
+
+/*:211*//*220:*/
+#line 4098 "cweave.w"
+
+void footnote();
+
+/*:220*//*224:*/
+#line 4147 "cweave.w"
+
+void phase_three();
+
+/*:224*//*236:*/
+#line 4327 "cweave.w"
+
+void unbucket();
+
+/*:236*//*245:*/
+#line 4447 "cweave.w"
+
+void section_print();
+
+/*:245*/
+#line 71 "cweave.w"
+
+
+/*:1*//*3:*/
+#line 93 "cweave.w"
+
+int main(ac,av)
+int ac;
+char**av;
+{
+argc= ac;argv= av;
+program= cweave;
+make_xrefs= force_lines= 1;
+common_init();
+/*20:*/
+#line 243 "cweave.w"
+
+xref_ptr= xmem;name_dir->xref= (char*)xmem;xref_switch= 0;section_xref_switch= 0;
+xmem->num= 0;
+
+/*:20*//*26:*/
+#line 352 "cweave.w"
+
+tok_ptr= tok_mem+1;text_ptr= tok_start+1;tok_start[0]= tok_mem+1;
+tok_start[1]= tok_mem+1;
+max_tok_ptr= tok_mem+1;max_text_ptr= tok_start+1;
+
+/*:26*//*32:*/
+#line 524 "cweave.w"
+
+{int c;for(c= 0;c<256;c++)ccode[c]= 0;}
+ccode[' ']= ccode['\t']= ccode['\n']= ccode['\v']= ccode['\r']= ccode['\f']
+= ccode['*']= new_section;
+ccode['@']= '@';
+ccode['=']= verbatim;
+ccode['d']= ccode['D']= definition;
+ccode['f']= ccode['F']= ccode['s']= ccode['S']= format_code;
+ccode['c']= ccode['C']= ccode['p']= ccode['P']= begin_C;
+ccode['t']= ccode['T']= TeX_string;
+ccode['l']= ccode['L']= translit_code;
+ccode['q']= ccode['Q']= noop;
+ccode['h']= ccode['H']= output_defs_code;
+ccode['&']= join;ccode['<']= ccode['(']= section_name;
+ccode['!']= underline;ccode['^']= xref_roman;
+ccode[':']= xref_wildcard;ccode['.']= xref_typewriter;ccode[',']= thin_space;
+ccode['|']= math_break;ccode['/']= line_break;ccode['#']= big_line_break;
+#line 117 "cweave.ch"
+ccode['+']= no_line_break;ccode[';']= pseudo_semi;
+ccode['{']= pseudo_lbrace;ccode['}']= pseudo_rbrace;
+ccode['[']= macro_arg_open;ccode[']']= macro_arg_close;
+#line 543 "cweave.w"
+ccode['\'']= ord;
+/*33:*/
+#line 550 "cweave.w"
+
+ccode['0']= ccode['1']= ccode['2']= trace;
+
+/*:33*/
+#line 544 "cweave.w"
+
+
+/*:32*//*52:*/
+#line 888 "cweave.w"
+section_text[0]= ' ';
+
+/*:52*//*80:*/
+#line 1330 "cweave.w"
+
+#line 281 "cweave.ch"
+out_ptr= out_buf+1;out_line= 1;active_file= tex_file;
+if(alternative){
+*out_ptr= 'a';
+tex_printf("\\input cwebmac");
+}else{
+*out_ptr= 'c';
+tex_printf("\\input cwebma");
+}
+#line 1333 "cweave.w"
+
+/*:80*//*82:*/
+#line 1356 "cweave.w"
+
+out_buf[0]= '\\';
+
+/*:82*//*98:*/
+#line 1674 "cweave.w"
+
+for(cat_index= 0;cat_index<255;cat_index++)
+strcpy(cat_name[cat_index],"UNKNOWN");
+strcpy(cat_name[exp],"exp");
+strcpy(cat_name[unop],"unop");
+strcpy(cat_name[binop],"binop");
+strcpy(cat_name[unorbinop],"unorbinop");
+strcpy(cat_name[cast],"cast");
+strcpy(cat_name[question],"?");
+strcpy(cat_name[lbrace],"{");
+strcpy(cat_name[rbrace],"}");
+strcpy(cat_name[decl_head],"decl_head");
+strcpy(cat_name[comma],",");
+strcpy(cat_name[lpar],"(");
+strcpy(cat_name[rpar],")");
+strcpy(cat_name[prelangle],"<");
+strcpy(cat_name[prerangle],">");
+strcpy(cat_name[langle],"\\<");
+strcpy(cat_name[colcol],"::");
+strcpy(cat_name[base],"\\:");
+strcpy(cat_name[decl],"decl");
+strcpy(cat_name[struct_head],"struct_head");
+strcpy(cat_name[stmt],"stmt");
+strcpy(cat_name[function],"function");
+strcpy(cat_name[fn_decl],"fn_decl");
+strcpy(cat_name[else_like],"else_like");
+strcpy(cat_name[semi],";");
+strcpy(cat_name[colon],":");
+strcpy(cat_name[tag],"tag");
+strcpy(cat_name[if_head],"if_head");
+strcpy(cat_name[else_head],"else_head");
+strcpy(cat_name[if_clause],"if()");
+strcpy(cat_name[lproc],"#{");
+strcpy(cat_name[rproc],"#}");
+strcpy(cat_name[insert],"insert");
+strcpy(cat_name[section_scrap],"section");
+strcpy(cat_name[dead],"@d");
+strcpy(cat_name[public_like],"public");
+strcpy(cat_name[operator_like],"operator");
+strcpy(cat_name[new_like],"new");
+strcpy(cat_name[catch_like],"catch");
+strcpy(cat_name[for_like],"for");
+strcpy(cat_name[do_like],"do");
+strcpy(cat_name[if_like],"if");
+strcpy(cat_name[raw_rpar],")?");
+strcpy(cat_name[raw_unorbin],"unorbinop?");
+strcpy(cat_name[const_like],"const");
+strcpy(cat_name[raw_int],"raw");
+strcpy(cat_name[int_like],"int");
+strcpy(cat_name[case_like],"case");
+strcpy(cat_name[sizeof_like],"sizeof");
+strcpy(cat_name[struct_like],"struct");
+strcpy(cat_name[typedef_like],"typedef");
+strcpy(cat_name[define_like],"define");
+strcpy(cat_name[begin_arg],"@[");
+#line 362 "cweave.ch"
+strcpy(cat_name[end_arg],"@]");
+strcpy(cat_name[label],"label");
+strcpy(cat_name[do_head],"do_head");
+strcpy(cat_name[pp_space],"#_");
+#line 1730 "cweave.w"
+strcpy(cat_name[0],"zero");
+
+/*:98*//*105:*/
+#line 2035 "cweave.w"
+
+scrap_base= scrap_info+1;
+max_scr_ptr= scrap_ptr= scrap_info;
+
+/*:105*//*187:*/
+#line 3432 "cweave.w"
+
+max_stack_ptr= stack;
+
+/*:187*//*233:*/
+#line 4273 "cweave.w"
+
+max_sort_ptr= scrap_info;
+
+/*:233*//*235:*/
+#line 4292 "cweave.w"
+
+collate[0]= 0;
+strcpy(collate+1," \1\2\3\4\5\6\7\10\11\12\13\14\15\16\17");
+
+strcpy(collate+17,"\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37");
+
+strcpy(collate+33,"!\42#$%&'()*+,-./:;<=>?@[\\]^`{|}~_");
+
+strcpy(collate+65,"abcdefghijklmnopqrstuvwxyz0123456789");
+
+strcpy(collate+101,"\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217");
+
+strcpy(collate+117,"\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237");
+
+strcpy(collate+133,"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257");
+
+strcpy(collate+149,"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277");
+
+strcpy(collate+165,"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317");
+
+strcpy(collate+181,"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337");
+
+strcpy(collate+197,"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357");
+
+strcpy(collate+213,"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377");
+
+
+/*:235*/
+#line 102 "cweave.w"
+;
+if(show_banner)printf(banner);
+/*28:*/
+#line 392 "cweave.w"
+
+id_lookup("asm",NULL,sizeof_like);
+id_lookup("auto",NULL,int_like);
+id_lookup("break",NULL,case_like);
+id_lookup("case",NULL,case_like);
+id_lookup("catch",NULL,catch_like);
+id_lookup("char",NULL,raw_int);
+id_lookup("class",NULL,struct_like);
+id_lookup("clock_t",NULL,raw_int);
+id_lookup("const",NULL,const_like);
+id_lookup("continue",NULL,case_like);
+id_lookup("default",NULL,case_like);
+id_lookup("define",NULL,define_like);
+id_lookup("defined",NULL,sizeof_like);
+id_lookup("delete",NULL,sizeof_like);
+id_lookup("div_t",NULL,raw_int);
+id_lookup("do",NULL,do_like);
+id_lookup("double",NULL,raw_int);
+id_lookup("elif",NULL,if_like);
+id_lookup("else",NULL,else_like);
+id_lookup("endif",NULL,if_like);
+id_lookup("enum",NULL,struct_like);
+id_lookup("error",NULL,if_like);
+id_lookup("extern",NULL,int_like);
+id_lookup("FILE",NULL,raw_int);
+id_lookup("float",NULL,raw_int);
+id_lookup("for",NULL,for_like);
+id_lookup("fpos_t",NULL,raw_int);
+id_lookup("friend",NULL,int_like);
+id_lookup("goto",NULL,case_like);
+id_lookup("if",NULL,if_like);
+id_lookup("ifdef",NULL,if_like);
+id_lookup("ifndef",NULL,if_like);
+id_lookup("include",NULL,if_like);
+id_lookup("inline",NULL,int_like);
+id_lookup("int",NULL,raw_int);
+id_lookup("jmp_buf",NULL,raw_int);
+id_lookup("ldiv_t",NULL,raw_int);
+id_lookup("line",NULL,if_like);
+id_lookup("long",NULL,raw_int);
+id_lookup("new",NULL,new_like);
+id_lookup("NULL",NULL,quoted);
+id_lookup("offsetof",NULL,sizeof_like);
+id_lookup("operator",NULL,operator_like);
+id_lookup("pragma",NULL,if_like);
+id_lookup("private",NULL,public_like);
+id_lookup("protected",NULL,public_like);
+id_lookup("ptrdiff_t",NULL,raw_int);
+id_lookup("public",NULL,public_like);
+id_lookup("register",NULL,int_like);
+id_lookup("return",NULL,case_like);
+id_lookup("short",NULL,raw_int);
+id_lookup("sig_atomic_t",NULL,raw_int);
+id_lookup("signed",NULL,raw_int);
+id_lookup("size_t",NULL,raw_int);
+id_lookup("sizeof",NULL,sizeof_like);
+id_lookup("static",NULL,int_like);
+id_lookup("struct",NULL,struct_like);
+id_lookup("switch",NULL,for_like);
+id_lookup("template",NULL,int_like);
+id_lookup("TeX",NULL,custom);
+id_lookup("this",NULL,quoted);
+id_lookup("throw",NULL,case_like);
+id_lookup("time_t",NULL,raw_int);
+id_lookup("try",NULL,else_like);
+id_lookup("typedef",NULL,typedef_like);
+id_lookup("undef",NULL,if_like);
+id_lookup("union",NULL,struct_like);
+id_lookup("unsigned",NULL,raw_int);
+id_lookup("va_dcl",NULL,decl);
+id_lookup("va_list",NULL,raw_int);
+id_lookup("virtual",NULL,int_like);
+id_lookup("void",NULL,raw_int);
+id_lookup("volatile",NULL,const_like);
+id_lookup("wchar_t",NULL,raw_int);
+id_lookup("while",NULL,for_like);
+
+/*:28*/
+#line 104 "cweave.w"
+;
+phase_one();
+phase_two();
+phase_three();
+return wrap_up();
+}
+
+/*:3*//*21:*/
+#line 262 "cweave.w"
+
+void
+new_xref(p)
+name_pointer p;
+{
+xref_pointer q;
+sixteen_bits m,n;
+if(no_xref)return;
+if((unindexed(p)||is_tiny(p))&&xref_switch==0)return;
+m= section_count+xref_switch;xref_switch= 0;q= (xref_pointer)p->xref;
+if(q!=xmem){
+n= q->num;
+if(n==m||n==m+def_flag)return;
+else if(m==n+def_flag){
+q->num= m;return;
+}
+}
+append_xref(m);xref_ptr->xlink= q;p->xref= (char*)xref_ptr;
+}
+
+/*:21*//*22:*/
+#line 293 "cweave.w"
+
+void
+new_section_xref(p)
+name_pointer p;
+{
+xref_pointer q,r;
+q= (xref_pointer)p->xref;r= xmem;
+if(q>xmem)
+while(q->num>section_xref_switch){r= q;q= q->xlink;}
+if(r->num==section_count+section_xref_switch)
+return;
+append_xref(section_count+section_xref_switch);
+xref_ptr->xlink= q;section_xref_switch= 0;
+if(r==xmem)p->xref= (char*)xref_ptr;
+else r->xlink= xref_ptr;
+}
+
+/*:22*//*23:*/
+#line 313 "cweave.w"
+
+void
+set_file_flag(p)
+name_pointer p;
+{
+xref_pointer q;
+q= (xref_pointer)p->xref;
+if(q->num==file_flag)return;
+append_xref(file_flag);
+xref_ptr->xlink= q;
+p->xref= (char*)xref_ptr;
+}
+
+/*:23*//*27:*/
+#line 358 "cweave.w"
+
+int names_match(p,first,l,t)
+name_pointer p;
+char*first;
+int l;
+eight_bits t;
+{
+if(length(p)!=l)return 0;
+if(p->ilk!=t&&!(t==normal&&abnormal(p)))return 0;
+return!strncmp(first,p->byte_start,l);
+}
+
+void
+init_p(p,t)
+name_pointer p;
+eight_bits t;
+{
+p->ilk= t;p->xref= (char*)xmem;
+}
+
+void
+init_node(p)
+name_pointer p;
+{
+p->xref= (char*)xmem;
+}
+
+/*:27*//*35:*/
+#line 565 "cweave.w"
+
+void
+skip_limbo(){
+while(1){
+if(loc>limit&&get_line()==0)return;
+*(limit+1)= '@';
+while(*loc!='@')loc++;
+if(loc++<=limit){int c= ccode[(eight_bits)*loc++];
+if(c==new_section)return;
+if(c==noop)skip_restricted();
+else if(c==format_code)/*71:*/
+#line 1180 "cweave.w"
+
+{
+if(get_next()!=identifier)
+err_print("! Missing left identifier of @s");
+
+else{
+lhs= id_lookup(id_first,id_loc,normal);
+if(get_next()!=identifier)
+err_print("! Missing right identifier of @s");
+
+else{
+rhs= id_lookup(id_first,id_loc,normal);
+lhs->ilk= rhs->ilk;
+}
+}
+}
+
+/*:71*/
+#line 575 "cweave.w"
+;
+}
+}
+}
+
+/*:35*//*36:*/
+#line 587 "cweave.w"
+
+unsigned
+skip_TeX()
+{
+while(1){
+if(loc>limit&&get_line()==0)return(new_section);
+*(limit+1)= '@';
+while(*loc!='@'&&*loc!='|')loc++;
+if(*loc++=='|')return('|');
+if(loc<=limit)return(ccode[(eight_bits)*(loc++)]);
+}
+}
+
+/*:36*//*40:*/
+#line 658 "cweave.w"
+
+#line 155 "cweave.ch"
+eight_bits
+get_next()
+{eight_bits c;
+int blank_count= 0;
+
+if(loc<limit&&preprocessing&&(define_pos==2||define_pos==4)&&
+xisspace(*loc)){
+define_pos= 5;
+return(preproc_space);
+}
+
+while(1){
+/*45:*/
+#line 717 "cweave.w"
+
+while(loc==limit-1&&preprocessing&&*loc=='\\')
+if(get_line()==0)return(new_section);
+#line 228 "cweave.ch"
+if(loc>=limit&&preprocessing){
+preprocessing= sharp_include_line= define_pos= 0;
+return(right_preproc);
+}
+#line 724 "cweave.w"
+
+/*:45*/
+#line 167 "cweave.ch"
+;
+if(loc>limit&&get_line()==0)return(new_section);
+
+if(loc==buffer){
+blank_count= 0;
+while((*loc==' '||*loc=='\t')&&loc<limit){
+blank_count++;loc++;
+}
+}
+
+c= *(loc++);
+if(xisdigit(c)||c=='\\'||c=='.')/*48:*/
+#line 775 "cweave.w"
+{
+id_first= id_loc= section_text+1;
+if(*(loc-1)=='\\'){*id_loc++= '~';
+while(xisdigit(*loc))*id_loc++= *loc++;}
+else if(*(loc-1)=='0'){
+if(*loc=='x'||*loc=='X'){*id_loc++= '^';loc++;
+while(xisxdigit(*loc))*id_loc++= *loc++;}
+else if(xisdigit(*loc)){*id_loc++= '~';
+while(xisdigit(*loc))*id_loc++= *loc++;}
+else goto dec;
+}
+else{
+if(*(loc-1)=='.'&&!xisdigit(*loc))goto mistake;
+dec:*id_loc++= *(loc-1);
+while(xisdigit(*loc)||*loc=='.')*id_loc++= *loc++;
+if(*loc=='e'||*loc=='E'){
+*id_loc++= '_';loc++;
+if(*loc=='+'||*loc=='-')*id_loc++= *loc++;
+while(xisdigit(*loc))*id_loc++= *loc++;
+}
+}
+while(*loc=='u'||*loc=='U'||*loc=='l'||*loc=='L'
+||*loc=='f'||*loc=='F'){
+*id_loc++= '$';*id_loc++= toupper(*loc);loc++;
+}
+return(constant);
+}
+
+/*:48*/
+#line 178 "cweave.ch"
+
+else if(c=='\''||c=='"'||(c=='L'&&(*loc=='\''||*loc=='"'))
+||(c=='<'&&sharp_include_line==1))
+/*49:*/
+#line 808 "cweave.w"
+{
+char delim= c;
+id_first= section_text+1;
+id_loc= section_text;
+if(delim=='\''&&*(loc-2)=='@'){*++id_loc= '@';*++id_loc= '@';}
+*++id_loc= delim;
+if(delim=='L'){
+delim= *loc++;*++id_loc= delim;
+}
+if(delim=='<')delim= '>';
+while(1){
+if(loc>=limit){
+if(*(limit-1)!='\\'){
+err_print("! String didn't end");loc= limit;break;
+
+}
+if(get_line()==0){
+err_print("! Input ended in middle of string");loc= buffer;break;
+
+}
+}
+if((c= *loc++)==delim){
+if(++id_loc<=section_text_end)*id_loc= c;
+break;
+}
+if(c=='\\')if(loc>=limit)continue;
+else if(++id_loc<=section_text_end){
+*id_loc= '\\';c= *loc++;
+}
+if(++id_loc<=section_text_end)*id_loc= c;
+}
+if(id_loc>=section_text_end){
+printf("\n! String too long: ");
+
+term_write(section_text+1,25);
+printf("...");mark_error;
+}
+id_loc++;
+return(string);
+}
+
+/*:49*/
+#line 181 "cweave.ch"
+
+else if(xisalpha(c)||isxalpha(c)||ishigh(c))
+/*47:*/
+#line 758 "cweave.w"
+{
+#line 250 "cweave.ch"
+id_first= --loc;
+
+if(preprocessing){
+if(define_pos==1)
+define_pos= 2;
+else if(strncmp(loc,"define",6)==0&&xisspace(*(loc+6)))
+define_pos= 1;
+}
+
+while(isalpha(*++loc)||isdigit(*loc)||isxalpha(*loc)||ishigh(*loc));
+id_loc= loc;return(identifier);
+#line 762 "cweave.w"
+}
+
+/*:47*/
+#line 183 "cweave.ch"
+
+else if(c=='@')/*50:*/
+#line 852 "cweave.w"
+{
+c= *loc++;
+switch(ccode[(eight_bits)c]){
+case translit_code:err_print("! Use @l in limbo only");continue;
+
+case underline:xref_switch= def_flag;continue;
+case trace:tracing= c-'0';continue;
+case xref_roman:case xref_wildcard:case xref_typewriter:
+case noop:case TeX_string:c= ccode[c];skip_restricted();return(c);
+case section_name:
+/*51:*/
+#line 872 "cweave.w"
+{
+char*k;
+cur_section_char= *(loc-1);
+/*53:*/
+#line 890 "cweave.w"
+
+k= section_text;
+while(1){
+if(loc>limit&&get_line()==0){
+err_print("! Input ended in section name");
+
+loc= buffer+1;break;
+}
+c= *loc;
+/*54:*/
+#line 914 "cweave.w"
+
+if(c=='@'){
+c= *(loc+1);
+if(c=='>'){
+loc+= 2;break;
+}
+if(ccode[(eight_bits)c]==new_section){
+err_print("! Section name didn't end");break;
+
+}
+if(c!='@'){
+err_print("! Control codes are forbidden in section name");break;
+
+}
+*(++k)= '@';loc++;
+}
+
+/*:54*/
+#line 899 "cweave.w"
+;
+loc++;if(k<section_text_end)k++;
+if(xisspace(c)){
+c= ' ';if(*(k-1)==' ')k--;
+}
+*k= c;
+}
+if(k>=section_text_end){
+printf("\n! Section name too long: ");
+
+term_write(section_text+1,25);
+printf("...");mark_harmless;
+}
+if(*k==' '&&k>section_text)k--;
+
+/*:53*/
+#line 875 "cweave.w"
+;
+if(k-section_text>3&&strncmp(k-2,"...",3)==0)
+cur_section= section_lookup(section_text+1,k-3,1);
+else cur_section= section_lookup(section_text+1,k,0);
+xref_switch= 0;return(section_name);
+}
+
+/*:51*/
+#line 862 "cweave.w"
+;
+case verbatim:/*57:*/
+#line 961 "cweave.w"
+{
+id_first= loc++;*(limit+1)= '@';*(limit+2)= '>';
+while(*loc!='@'||*(loc+1)!='>')loc++;
+if(loc>=limit)err_print("! Verbatim string didn't end");
+
+id_loc= loc;loc+= 2;
+return(verbatim);
+}
+
+/*:57*/
+#line 863 "cweave.w"
+;
+case ord:/*49:*/
+#line 808 "cweave.w"
+{
+char delim= c;
+id_first= section_text+1;
+id_loc= section_text;
+if(delim=='\''&&*(loc-2)=='@'){*++id_loc= '@';*++id_loc= '@';}
+*++id_loc= delim;
+if(delim=='L'){
+delim= *loc++;*++id_loc= delim;
+}
+if(delim=='<')delim= '>';
+while(1){
+if(loc>=limit){
+if(*(limit-1)!='\\'){
+err_print("! String didn't end");loc= limit;break;
+
+}
+if(get_line()==0){
+err_print("! Input ended in middle of string");loc= buffer;break;
+
+}
+}
+if((c= *loc++)==delim){
+if(++id_loc<=section_text_end)*id_loc= c;
+break;
+}
+if(c=='\\')if(loc>=limit)continue;
+else if(++id_loc<=section_text_end){
+*id_loc= '\\';c= *loc++;
+}
+if(++id_loc<=section_text_end)*id_loc= c;
+}
+if(id_loc>=section_text_end){
+printf("\n! String too long: ");
+
+term_write(section_text+1,25);
+printf("...");mark_error;
+}
+id_loc++;
+return(string);
+}
+
+/*:49*/
+#line 864 "cweave.w"
+;
+default:return(ccode[(eight_bits)c]);
+}
+}
+
+/*:50*/
+#line 184 "cweave.ch"
+
+else if(xisspace(c))continue;
+if(c=='#'&&loc==buffer+1+blank_count&&!preprocessing)
+/*42:*/
+#line 696 "cweave.w"
+{
+preprocessing= 1;
+/*44:*/
+#line 709 "cweave.w"
+
+while(loc<=buffer_end-7&&xisspace(*loc))loc++;
+if(loc<=buffer_end-6&&strncmp(loc,"include",7)==0)sharp_include_line= 1;
+
+/*:44*/
+#line 698 "cweave.w"
+;
+return(left_preproc);
+}
+
+/*:42*/
+#line 187 "cweave.ch"
+;
+mistake:/*46:*/
+#line 734 "cweave.w"
+
+switch(c){
+case'/':if(*loc=='*'){compress(begin_comment);}
+else if(*loc=='/')compress(begin_short_comment);break;
+case'+':if(*loc=='+')compress(plus_plus);break;
+case'-':if(*loc=='-'){compress(minus_minus);}
+else if(*loc=='>')if(*(loc+1)=='*'){loc++;compress(minus_gt_ast);}
+else compress(minus_gt);break;
+case'.':if(*loc=='*'){compress(period_ast);}
+else if(*loc=='.'&&*(loc+1)=='.'){
+loc++;compress(dot_dot_dot);
+}
+break;
+case':':if(*loc==':')compress(colon_colon);break;
+case'=':if(*loc=='=')compress(eq_eq);break;
+case'>':if(*loc=='='){compress(gt_eq);}
+else if(*loc=='>')compress(gt_gt);break;
+case'<':if(*loc=='='){compress(lt_eq);}
+else if(*loc=='<')compress(lt_lt);break;
+case'&':if(*loc=='&')compress(and_and);break;
+case'|':if(*loc=='|')compress(or_or);break;
+#line 239 "cweave.ch"
+case'!':if(*loc=='=')compress(not_eq);break;
+case'#':if(*loc=='#')compress(numb_numb);break;
+#line 756 "cweave.w"
+}
+
+/*:46*/
+#line 188 "cweave.ch"
+
+if(preprocessing){
+if(c=='('&&define_pos==2&&!xisspace(*(loc-2)))
+define_pos= 3;
+else if(c==')'&&define_pos==3)
+define_pos= 4;
+}
+return(c);
+}
+}
+#line 679 "cweave.w"
+
+/*:40*//*56:*/
+#line 936 "cweave.w"
+
+void
+skip_restricted()
+{
+id_first= loc;*(limit+1)= '@';
+false_alarm:
+while(*loc!='@')loc++;
+id_loc= loc;
+if(loc++>limit){
+err_print("! Control text didn't end");loc= limit;
+
+}
+else{
+if(*loc=='@'&&loc<=limit){loc++;goto false_alarm;}
+if(*loc++!='>')
+err_print("! Control codes are forbidden in control text");
+
+}
+}
+
+/*:56*//*60:*/
+#line 989 "cweave.w"
+
+void
+phase_one(){
+phase= 1;reset_input();section_count= 0;
+skip_limbo();change_exists= 0;
+while(!input_has_ended)
+/*61:*/
+#line 1002 "cweave.w"
+
+{
+if(++section_count==max_sections)overflow("section number");
+changed_section[section_count]= changing;
+
+if(*(loc-1)=='*'&&show_progress){
+printf("*%d",section_count);
+update_terminal;
+}
+/*66:*/
+#line 1093 "cweave.w"
+
+while(1){
+switch(next_control= skip_TeX()){
+case translit_code:err_print("! Use @l in limbo only");continue;
+
+case underline:xref_switch= def_flag;continue;
+case trace:tracing= *(loc-1)-'0';continue;
+case'|':C_xref(section_name);break;
+case xref_roman:case xref_wildcard:case xref_typewriter:
+case noop:case section_name:
+loc-= 2;next_control= get_next();
+if(next_control>=xref_roman&&next_control<=xref_typewriter){
+/*67:*/
+#line 1113 "cweave.w"
+
+{
+char*src= id_first,*dst= id_first;
+while(src<id_loc){
+if(*src=='@')src++;
+*dst++= *src++;
+}
+id_loc= dst;
+while(dst<src)*dst++= ' ';
+}
+
+/*:67*/
+#line 1105 "cweave.w"
+
+new_xref(id_lookup(id_first,id_loc,next_control-identifier));
+}
+break;
+}
+if(next_control>=format_code)break;
+}
+
+/*:66*/
+#line 1011 "cweave.w"
+;
+/*69:*/
+#line 1141 "cweave.w"
+
+while(next_control<=definition){
+if(next_control==definition){
+xref_switch= def_flag;
+next_control= get_next();
+}else/*70:*/
+#line 1155 "cweave.w"
+{
+next_control= get_next();
+if(next_control==identifier){
+lhs= id_lookup(id_first,id_loc,normal);lhs->ilk= normal;
+if(xref_switch)new_xref(lhs);
+next_control= get_next();
+if(next_control==identifier){
+rhs= id_lookup(id_first,id_loc,normal);
+lhs->ilk= rhs->ilk;
+if(unindexed(lhs)){
+xref_pointer q,r= NULL;
+for(q= (xref_pointer)lhs->xref;q>xmem;q= q->xlink)
+if(q->num<def_flag)
+if(r)r->xlink= q->xlink;
+else lhs->xref= (char*)q->xlink;
+else r= q;
+}
+next_control= get_next();
+}
+}
+}
+
+/*:70*/
+#line 1146 "cweave.w"
+;
+outer_xref();
+}
+
+/*:69*/
+#line 1012 "cweave.w"
+;
+/*72:*/
+#line 1200 "cweave.w"
+
+if(next_control<=section_name){
+if(next_control==begin_C)section_xref_switch= 0;
+else{
+section_xref_switch= def_flag;
+if(cur_section_char=='('&&cur_section!=name_dir)
+set_file_flag(cur_section);
+}
+do{
+if(next_control==section_name&&cur_section!=name_dir)
+new_section_xref(cur_section);
+next_control= get_next();outer_xref();
+}while(next_control<=section_name);
+}
+
+/*:72*/
+#line 1013 "cweave.w"
+;
+if(changed_section[section_count])change_exists= 1;
+}
+
+/*:61*/
+#line 995 "cweave.w"
+;
+changed_section[section_count]= change_exists;
+
+phase= 2;
+/*76:*/
+#line 1253 "cweave.w"
+section_check(root)
+
+/*:76*/
+#line 999 "cweave.w"
+;
+}
+
+/*:60*//*63:*/
+#line 1041 "cweave.w"
+
+void
+C_xref(spec_ctrl)
+eight_bits spec_ctrl;
+{
+name_pointer p;
+while(next_control<format_code||next_control==spec_ctrl){
+if(next_control>=identifier&&next_control<=xref_typewriter){
+if(next_control>identifier)/*67:*/
+#line 1113 "cweave.w"
+
+{
+char*src= id_first,*dst= id_first;
+while(src<id_loc){
+if(*src=='@')src++;
+*dst++= *src++;
+}
+id_loc= dst;
+while(dst<src)*dst++= ' ';
+}
+
+/*:67*/
+#line 1049 "cweave.w"
+
+p= id_lookup(id_first,id_loc,next_control-identifier);new_xref(p);
+}
+if(next_control==section_name){
+section_xref_switch= cite_flag;
+new_section_xref(cur_section);
+}
+next_control= get_next();
+if(next_control=='|'||next_control==begin_comment||
+next_control==begin_short_comment)return;
+}
+}
+
+/*:63*//*65:*/
+#line 1069 "cweave.w"
+
+void
+outer_xref()
+{
+int bal;
+while(next_control<format_code)
+if(next_control!=begin_comment&&next_control!=begin_short_comment)
+C_xref(ignore);
+else{
+boolean is_long_comment= (next_control==begin_comment);
+bal= copy_comment(is_long_comment,1);next_control= '|';
+while(bal>0){
+C_xref(section_name);
+if(next_control=='|')bal= copy_comment(is_long_comment,bal);
+else bal= 0;
+}
+}
+}
+
+/*:65*//*75:*/
+#line 1230 "cweave.w"
+
+void
+section_check(p)
+name_pointer p;
+{
+if(p){
+section_check(p->llink);
+cur_xref= (xref_pointer)p->xref;
+if(cur_xref->num==file_flag){an_output= 1;cur_xref= cur_xref->xlink;}
+else an_output= 0;
+if(cur_xref->num<def_flag){
+printf("\n! Never defined: <");print_section_name(p);putchar('>');mark_harmless;
+
+}
+while(cur_xref->num>=cite_flag)cur_xref= cur_xref->xlink;
+if(cur_xref==xmem&&!an_output){
+printf("\n! Never used: <");print_section_name(p);putchar('>');mark_harmless;
+
+}
+section_check(p->rlink);
+}
+}
+
+/*:75*//*78:*/
+#line 1283 "cweave.w"
+
+void
+flush_buffer(b,per_cent,carryover)
+char*b;
+boolean per_cent,carryover;
+{
+char*j;j= b;
+if(!per_cent)
+while(j>out_buf&&*j==' ')j--;
+c_line_write(j-out_buf);
+if(per_cent)tex_putc('%');
+tex_new_line;out_line++;
+if(carryover)
+while(j>out_buf)
+if(*j--=='%'&&(j==out_buf||*j!='\\')){
+*b--= '%';break;
+}
+if(b<out_ptr)strncpy(out_buf+1,b+1,out_ptr-b);
+out_ptr-= b-out_buf;
+}
+
+/*:78*//*79:*/
+#line 1312 "cweave.w"
+
+void
+finish_line()
+{
+char*k;
+if(out_ptr>out_buf)flush_buffer(out_ptr,0,0);
+else{
+for(k= buffer;k<=limit;k++)
+if(!(xisspace(*k)))return;
+flush_buffer(out_buf,0,0);
+}
+}
+
+/*:79*//*81:*/
+#line 298 "cweave.ch"
+
+void
+out(c)
+char c;
+{
+if(out_ptr>=out_buf_end)
+break_out();
+
+if(!escape){
+if(in_math){
+if(c=='{')
+math_brace_count++;
+else if(c=='}'){
+math_brace_count--;
+if(math_brace_count<0){
+math_brace_count= 0;
+return;
+}
+}
+}
+if(c=='$'){
+while(math_brace_count>0){
+*(++out_ptr)= '}';
+math_brace_count--;
+}
+in_math= 1-in_math;
+}
+}
+
+if(c=='\\'&&!escape)
+escape= 1;
+else
+escape= 0;
+
+*(++out_ptr)= c;
+return;
+}
+#line 1345 "cweave.w"
+void
+out_str(s)
+char*s;
+{
+while(*s)out(*s++);
+}
+
+/*:81*//*84:*/
+#line 1366 "cweave.w"
+
+void
+break_out()
+{
+char*k= out_ptr;
+while(1){
+if(k==out_buf)/*85:*/
+#line 1387 "cweave.w"
+
+{
+printf("\n! Line had to be broken (output l. %d):\n",out_line);
+
+term_write(out_buf+1,out_ptr-out_buf-1);
+new_line;mark_harmless;
+flush_buffer(out_ptr-1,1,1);return;
+}
+
+/*:85*/
+#line 1372 "cweave.w"
+;
+if(*k==' '){
+flush_buffer(k,0,1);return;
+}
+if(*(k--)=='\\'&&*k!='\\'){
+flush_buffer(k,1,1);return;
+}
+}
+}
+
+/*:84*//*86:*/
+#line 1401 "cweave.w"
+
+void
+out_section(n)
+sixteen_bits n;
+{
+char s[6];
+sprintf(s,"%d",n);out_str(s);
+if(changed_section[n])out_str("\\*");
+
+}
+
+/*:86*//*87:*/
+#line 1415 "cweave.w"
+
+void
+out_name(p)
+name_pointer p;
+{
+char*k,*k_end= (p+1)->byte_start;
+out('{');
+for(k= p->byte_start;k<k_end;k++){
+if(isxalpha(*k))out('\\');
+out(*k);
+}
+out('}');
+}
+
+/*:87*//*88:*/
+#line 1442 "cweave.w"
+
+void
+copy_limbo()
+{
+char c;
+while(1){
+if(loc>limit&&(finish_line(),get_line()==0))return;
+*(limit+1)= '@';
+while(*loc!='@')out(*(loc++));
+if(loc++<=limit){
+c= *loc++;
+if(ccode[(eight_bits)c]==new_section)break;
+switch(ccode[(eight_bits)c]){
+case translit_code:out_str("\\ATL");break;
+
+case'@':out('@');break;
+case noop:skip_restricted();break;
+case format_code:if(get_next()==identifier)get_next();
+if(loc>=limit)get_line();
+break;
+default:err_print("! Double @ should be used in limbo");
+
+out('@');
+}
+}
+}
+}
+
+/*:88*//*90:*/
+#line 1477 "cweave.w"
+
+eight_bits
+copy_TeX()
+{
+char c;
+while(1){
+if(loc>limit&&(finish_line(),get_line()==0))return(new_section);
+*(limit+1)= '@';
+while((c= *(loc++))!='|'&&c!='@'){
+out(c);
+if(out_ptr==out_buf+1&&(xisspace(c)))out_ptr--;
+}
+if(c=='|')return('|');
+if(loc<=limit)return(ccode[(eight_bits)*(loc++)]);
+}
+}
+
+/*:90*//*92:*/
+#line 1509 "cweave.w"
+
+int copy_comment(is_long_comment,bal)
+boolean is_long_comment;
+int bal;
+{
+char c;
+while(1){
+if(loc>limit){
+if(is_long_comment){
+if(get_line()==0){
+err_print("! Input ended in mid-comment");
+
+loc= buffer+1;goto done;
+}
+}
+else{
+if(bal>1)err_print("! Missing } in comment");
+
+goto done;
+}
+}
+c= *(loc++);
+if(c=='|')return(bal);
+if(is_long_comment)/*93:*/
+#line 1550 "cweave.w"
+
+if(c=='*'&&*loc=='/'){
+loc++;
+if(bal>1)err_print("! Missing } in comment");
+
+goto done;
+}
+
+/*:93*/
+#line 1532 "cweave.w"
+;
+if(phase==2){
+if(ishigh(c))app_tok(quoted_char);
+app_tok(c);
+}
+/*94:*/
+#line 1558 "cweave.w"
+
+if(c=='@'){
+if(*(loc++)!='@'){
+err_print("! Illegal use of @ in comment");
+
+loc-= 2;if(phase==2)*(tok_ptr-1)= ' ';goto done;
+}
+}
+else if(c=='\\'&&*loc!='@')
+if(phase==2)app_tok(*(loc++))else loc++;
+
+/*:94*/
+#line 1537 "cweave.w"
+;
+if(c=='{')bal++;
+else if(c=='}'){
+if(bal>1)bal--;
+else{err_print("! Extra } in comment");
+
+if(phase==2)tok_ptr--;
+}
+}
+}
+done:/*95:*/
+#line 1572 "cweave.w"
+
+if(phase==2)while(bal-->0)app_tok('}');
+return(0);
+
+/*:95*/
+#line 1547 "cweave.w"
+;
+}
+
+/*:92*//*99:*/
+#line 1734 "cweave.w"
+
+void
+print_cat(c)
+eight_bits c;
+{
+printf(cat_name[c]);
+}
+
+/*:99*//*106:*/
+#line 2062 "cweave.w"
+
+void
+print_text(p)
+text_pointer p;
+{
+token_pointer j;
+sixteen_bits r;
+if(p>=text_ptr)printf("BAD");
+else for(j= *p;j<*(p+1);j++){
+r= *j%id_flag;
+switch(*j/id_flag){
+case 1:printf("\\\\{");print_id((name_dir+r));printf("}");
+break;
+case 2:printf("\\&{");print_id((name_dir+r));printf("}");
+break;
+case 3:printf("<");print_section_name((name_dir+r));printf(">");
+break;
+case 4:printf("[[%d]]",r);break;
+case 5:printf("|[[%d]]|",r);break;
+default:/*107:*/
+#line 2087 "cweave.w"
+
+switch(r){
+case math_rel:printf("\\mathrel{");break;
+case big_cancel:printf("[ccancel]");break;
+case cancel:printf("[cancel]");break;
+case indent:printf("[indent]");break;
+case outdent:printf("[outdent]");break;
+case backup:printf("[backup]");break;
+case opt:printf("[opt]");break;
+case break_space:printf("[break]");break;
+case force:printf("[force]");break;
+case big_force:printf("[fforce]");break;
+case preproc_line:printf("[preproc]");break;
+case quoted_char:j++;printf("[%o]",(unsigned)*j);break;
+case end_translation:printf("[quit]");break;
+case inserted:printf("[inserted]");break;
+default:putxchar(r);
+}
+
+/*:107*/
+#line 2081 "cweave.w"
+;
+}
+}
+fflush(stdout);
+}
+
+/*:106*//*109:*/
+#line 2187 "cweave.w"
+
+void
+app_str(s)
+char*s;
+{
+while(*s)app_tok(*(s++));
+}
+
+void
+big_app(a)
+token a;
+{
+if(a==' '||(a>=big_cancel&&a<=big_force)){
+if(cur_mathness==maybe_math)init_mathness= no_math;
+else if(cur_mathness==yes_math)app_str("{}$");
+cur_mathness= no_math;
+}
+else{
+if(cur_mathness==maybe_math)init_mathness= yes_math;
+else if(cur_mathness==no_math)app_str("${}");
+cur_mathness= yes_math;
+}
+app(a);
+}
+
+void
+big_app1(a)
+scrap_pointer a;
+{
+switch(a->mathness%4){
+case(no_math):
+if(cur_mathness==maybe_math)init_mathness= no_math;
+else if(cur_mathness==yes_math)app_str("{}$");
+cur_mathness= a->mathness/4;
+break;
+case(yes_math):
+if(cur_mathness==maybe_math)init_mathness= yes_math;
+else if(cur_mathness==no_math)app_str("${}");
+cur_mathness= a->mathness/4;
+break;
+case(maybe_math):break;
+}
+app(tok_flag+(int)((a)->trans-tok_start));
+}
+
+/*:109*//*111:*/
+#line 2312 "cweave.w"
+
+token_pointer
+find_first_ident(p)
+text_pointer p;
+{
+token_pointer q;
+token_pointer j;
+sixteen_bits r;
+if(p>=text_ptr)confusion("find_first_ident");
+for(j= *p;j<*(p+1);j++){
+r= *j%id_flag;
+switch(*j/id_flag){
+case 1:case 2:return j;
+case 4:case 5:
+if((q= find_first_ident(tok_start+r))!=no_ident_found)
+return q;
+default:;
+if(*j==inserted)return no_ident_found;
+}
+}
+return no_ident_found;
+}
+
+/*:111*//*112:*/
+#line 2339 "cweave.w"
+
+#line 421 "cweave.ch"
+void
+make_reserved(p,cat)
+scrap_pointer p;
+eight_bits cat;
+{
+sixteen_bits tok_value;
+token_pointer tok_loc;
+if((tok_loc= find_first_ident(p->trans))==no_ident_found)
+return;
+tok_value= *tok_loc;
+for(;p<=scrap_ptr;p==lo_ptr?p= hi_ptr:p++){
+if(p->cat==exp||p->cat==int_like||p->cat==const_like){
+if(**(p->trans)==tok_value){
+p->cat= cat;
+**(p->trans)= tok_value%id_flag+res_flag;
+}
+}
+}
+(name_dir+(sixteen_bits)(tok_value%id_flag))->ilk= cat;
+*tok_loc= tok_value%id_flag+res_flag;
+}
+#line 2360 "cweave.w"
+
+/*:112*//*113:*/
+#line 2370 "cweave.w"
+
+void
+make_underlined(p)
+
+scrap_pointer p;
+{
+token_pointer tok_loc;
+if((tok_loc= find_first_ident(p->trans))==no_ident_found)
+return;
+xref_switch= def_flag;
+underline_xref(*tok_loc%id_flag+name_dir);
+}
+
+/*:113*//*115:*/
+#line 2391 "cweave.w"
+
+void
+underline_xref(p)
+name_pointer p;
+{
+xref_pointer q= (xref_pointer)p->xref;
+xref_pointer r;
+sixteen_bits m;
+sixteen_bits n;
+if(no_xref)return;
+m= section_count+xref_switch;
+while(q!=xmem){
+n= q->num;
+if(n==m)return;
+else if(m==n+def_flag){
+q->num= m;return;
+}
+else if(n>=def_flag&&n<m)break;
+q= q->xlink;
+}
+/*116:*/
+#line 2421 "cweave.w"
+
+append_xref(0);
+xref_ptr->xlink= (xref_pointer)p->xref;r= xref_ptr;
+p->xref= (char*)xref_ptr;
+while(r->xlink!=q){r->num= r->xlink->num;r= r->xlink;}
+r->num= m;
+
+/*:116*/
+#line 2411 "cweave.w"
+;
+}
+
+/*:115*//*162:*/
+#line 2868 "cweave.w"
+
+void
+reduce(j,k,c,d,n)
+scrap_pointer j;
+eight_bits c;
+short k,d,n;
+{
+scrap_pointer i,i1;
+j->cat= c;j->trans= text_ptr;
+j->mathness= 4*cur_mathness+init_mathness;
+freeze_text;
+if(k>1){
+for(i= j+k,i1= j+1;i<=lo_ptr;i++,i1++){
+i1->cat= i->cat;i1->trans= i->trans;
+i1->mathness= i->mathness;
+}
+lo_ptr= lo_ptr-k+1;
+}
+/*163:*/
+#line 2891 "cweave.w"
+
+if(pp+d>=scrap_base)pp= pp+d;
+else pp= scrap_base;
+
+/*:163*/
+#line 2886 "cweave.w"
+;
+/*168:*/
+#line 2965 "cweave.w"
+
+{scrap_pointer k;
+#line 806 "cweave.ch"
+if(tracing==2){
+printf("\n%3d:",n);
+#line 2969 "cweave.w"
+for(k= scrap_base;k<=lo_ptr;k++){
+if(k==pp)putxchar('*');else putxchar(' ');
+if(k->mathness%4==yes_math)putchar('+');
+else if(k->mathness%4==no_math)putchar('-');
+print_cat(k->cat);
+if(k->mathness/4==yes_math)putchar('+');
+else if(k->mathness/4==no_math)putchar('-');
+}
+if(hi_ptr<=scrap_ptr)printf("...");
+}
+}
+
+/*:168*/
+#line 2887 "cweave.w"
+;
+pp--;
+}
+
+/*:162*//*164:*/
+#line 2898 "cweave.w"
+
+void
+squash(j,k,c,d,n)
+scrap_pointer j;
+eight_bits c;
+short k,d,n;
+{
+scrap_pointer i;
+if(k==1){
+j->cat= c;/*163:*/
+#line 2891 "cweave.w"
+
+if(pp+d>=scrap_base)pp= pp+d;
+else pp= scrap_base;
+
+/*:163*/
+#line 2907 "cweave.w"
+;
+/*168:*/
+#line 2965 "cweave.w"
+
+{scrap_pointer k;
+#line 806 "cweave.ch"
+if(tracing==2){
+printf("\n%3d:",n);
+#line 2969 "cweave.w"
+for(k= scrap_base;k<=lo_ptr;k++){
+if(k==pp)putxchar('*');else putxchar(' ');
+if(k->mathness%4==yes_math)putchar('+');
+else if(k->mathness%4==no_math)putchar('-');
+print_cat(k->cat);
+if(k->mathness/4==yes_math)putchar('+');
+else if(k->mathness/4==no_math)putchar('-');
+}
+if(hi_ptr<=scrap_ptr)printf("...");
+}
+}
+
+/*:168*/
+#line 2908 "cweave.w"
+;
+pp--;
+return;
+}
+for(i= j;i<j+k;i++)big_app1(i);
+reduce(j,k,c,d,n);
+}
+
+/*:164*//*169:*/
+#line 2994 "cweave.w"
+
+text_pointer
+translate()
+{
+scrap_pointer i,
+j;
+pp= scrap_base;lo_ptr= pp-1;hi_ptr= pp;
+/*172:*/
+#line 3033 "cweave.w"
+
+if(tracing==2){
+printf("\nTracing after l. %d:\n",cur_line);mark_harmless;
+
+if(loc>buffer+50){
+printf("...");
+term_write(loc-51,51);
+}
+else term_write(buffer,loc-buffer);
+}
+
+/*:172*/
+#line 3001 "cweave.w"
+;
+/*165:*/
+#line 2929 "cweave.w"
+
+while(1){
+/*166:*/
+#line 2948 "cweave.w"
+
+if(lo_ptr<pp+3){
+while(hi_ptr<=scrap_ptr&&lo_ptr!=pp+3){
+(++lo_ptr)->cat= hi_ptr->cat;lo_ptr->mathness= (hi_ptr)->mathness;
+lo_ptr->trans= (hi_ptr++)->trans;
+}
+for(i= lo_ptr+1;i<=pp+3;i++)i->cat= 0;
+}
+
+/*:166*/
+#line 2931 "cweave.w"
+;
+if(tok_ptr+safe_tok_incr>tok_mem_end){
+if(tok_ptr>max_tok_ptr)max_tok_ptr= tok_ptr;
+overflow("token");
+}
+if(text_ptr+safe_text_incr>tok_start_end){
+if(text_ptr>max_text_ptr)max_text_ptr= text_ptr;
+overflow("text");
+}
+if(pp>lo_ptr)break;
+init_mathness= cur_mathness= maybe_math;
+/*110:*/
+#line 2243 "cweave.w"
+{
+if(cat1==end_arg&&lhs_not_simple)
+if(pp->cat==begin_arg)squash(pp,2,exp,-2,110);
+else squash(pp,2,end_arg,-1,111);
+else if(cat1==insert)squash(pp,2,pp->cat,-2,0);
+else if(cat2==insert)squash(pp+1,2,(pp+1)->cat,-1,0);
+else if(cat3==insert)squash(pp+2,2,(pp+2)->cat,0,0);
+else
+switch(pp->cat){
+case exp:/*117:*/
+#line 2433 "cweave.w"
+
+if(cat1==lbrace||cat1==int_like||cat1==decl){
+make_underlined(pp);big_app1(pp);big_app(indent);app(indent);
+reduce(pp,1,fn_decl,0,1);
+}
+else if(cat1==unop)squash(pp,2,exp,-2,2);
+else if((cat1==binop||cat1==unorbinop)&&cat2==exp)
+squash(pp,3,exp,-2,3);
+else if(cat1==comma&&cat2==exp){
+big_app2(pp);
+app(opt);app('9');big_app1(pp+2);reduce(pp,3,exp,-2,4);
+}
+else if(cat1==exp||cat1==cast)squash(pp,2,exp,-2,5);
+else if(cat1==semi)squash(pp,2,stmt,-1,6);
+else if(cat1==colon){
+#line 449 "cweave.ch"
+make_underlined(pp);
+if(alternative)
+squash(pp,2,label,0,7);
+else
+squash(pp,2,tag,0,7);
+#line 2449 "cweave.w"
+}
+else if(cat1==base){
+if(cat2==int_like&&cat3==comma){
+big_app1(pp+1);big_app(' ');big_app2(pp+2);
+app(opt);app('9');reduce(pp+1,3,base,0,8);
+}
+else if(cat2==int_like&&cat3==lbrace){
+big_app1(pp);big_app(' ');big_app1(pp+1);big_app(' ');big_app1(pp+2);
+reduce(pp,3,exp,-1,9);
+}
+}
+else if(cat1==rbrace)squash(pp,1,stmt,-1,10);
+
+/*:117*/
+#line 2252 "cweave.w"
+;break;
+case lpar:/*118:*/
+#line 2462 "cweave.w"
+
+if((cat1==exp||cat1==unorbinop)&&cat2==rpar)squash(pp,3,exp,-2,11);
+else if(cat1==rpar){
+big_app1(pp);app('\\');app(',');big_app1(pp+1);
+
+reduce(pp,2,exp,-2,12);
+}
+else if(cat1==decl_head||cat1==int_like||cat1==exp){
+if(cat2==rpar)squash(pp,3,cast,-2,13);
+else if(cat2==comma){
+big_app3(pp);app(opt);app('9');reduce(pp,3,lpar,0,14);
+}
+}
+else if(cat1==stmt||cat1==decl){
+big_app2(pp);big_app(' ');reduce(pp,2,lpar,0,15);
+}
+
+/*:118*/
+#line 2253 "cweave.w"
+;break;
+case question:/*119:*/
+#line 2479 "cweave.w"
+
+if(cat1==exp&&cat2==colon)squash(pp,3,binop,-2,16);
+
+/*:119*/
+#line 2254 "cweave.w"
+;break;
+case unop:/*120:*/
+#line 2482 "cweave.w"
+
+if(cat1==exp||cat1==int_like)squash(pp,2,cat1,-2,17);
+
+/*:120*/
+#line 2255 "cweave.w"
+;break;
+case unorbinop:/*121:*/
+#line 2485 "cweave.w"
+
+if(cat1==exp||cat1==int_like){
+big_app('{');big_app1(pp);big_app('}');big_app1(pp+1);
+reduce(pp,2,cat1,-2,18);
+}
+else if(cat1==binop){
+big_app(math_rel);big_app1(pp);big_app('{');big_app1(pp+1);big_app('}');
+big_app('}');reduce(pp,2,binop,-1,19);
+}
+
+/*:121*/
+#line 2256 "cweave.w"
+;break;
+case binop:/*122:*/
+#line 2495 "cweave.w"
+
+if(cat1==binop){
+big_app(math_rel);big_app('{');big_app1(pp);big_app('}');
+big_app('{');big_app1(pp+1);big_app('}');
+big_app('}');reduce(pp,2,binop,-1,20);
+}
+
+/*:122*/
+#line 2257 "cweave.w"
+;break;
+case cast:/*123:*/
+#line 2502 "cweave.w"
+
+if(cat1==exp){
+big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,exp,-2,21);
+}
+else if(cat1==semi)squash(pp,1,exp,-2,22);
+
+/*:123*/
+#line 2258 "cweave.w"
+;break;
+case sizeof_like:/*124:*/
+#line 2508 "cweave.w"
+
+if(cat1==cast)squash(pp,2,exp,-2,23);
+else if(cat1==exp){
+big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,exp,-2,24);
+}
+
+/*:124*/
+#line 2259 "cweave.w"
+;break;
+case int_like:/*125:*/
+#line 2514 "cweave.w"
+
+if(cat1==int_like||cat1==struct_like){
+big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,cat1,-2,25);
+}
+else if(cat1==exp&&(cat2==raw_int||cat2==struct_like))
+squash(pp,2,int_like,-2,26);
+else if(cat1==exp||cat1==unorbinop||cat1==semi){
+big_app1(pp);
+if(cat1!=semi)big_app(' ');
+reduce(pp,1,decl_head,-1,27);
+}
+else if(cat1==colon){
+big_app1(pp);big_app(' ');reduce(pp,1,decl_head,0,28);
+}
+else if(cat1==prelangle)squash(pp+1,1,langle,1,29);
+else if(cat1==colcol&&(cat2==exp||cat2==int_like))squash(pp,3,cat2,-2,30);
+else if(cat1==cast){
+if(cat2==lbrace){
+big_app2(pp);big_app(indent);big_app(indent);
+reduce(pp,2,fn_decl,1,31);
+}
+#line 462 "cweave.ch"
+else squash(pp,2,int_like,-2,32);
+}
+else if(cat1==binop&&cat2==exp)squash(pp,3,int_like,-2,117);
+#line 2537 "cweave.w"
+
+/*:125*/
+#line 2260 "cweave.w"
+;break;
+case decl_head:/*126:*/
+#line 2538 "cweave.w"
+
+if(cat1==comma){
+big_app2(pp);big_app(' ');reduce(pp,2,decl_head,-1,33);
+}
+else if(cat1==unorbinop){
+big_app1(pp);big_app('{');big_app1(pp+1);big_app('}');
+reduce(pp,2,decl_head,-1,34);
+}
+else if(cat1==exp&&cat2!=lpar&&cat2!=exp){
+make_underlined(pp+1);squash(pp,2,decl_head,-1,35);
+}
+else if((cat1==binop||cat1==colon)&&cat2==exp&&(cat3==comma||
+cat3==semi||cat3==rpar))
+squash(pp,3,decl_head,-1,36);
+else if(cat1==cast)squash(pp,2,decl_head,-1,37);
+else if(cat1==lbrace||(cat1==int_like&&cat2!=colcol)||cat1==decl){
+big_app1(pp);big_app(indent);app(indent);reduce(pp,1,fn_decl,0,38);
+}
+else if(cat1==semi)squash(pp,2,decl,-1,39);
+
+/*:126*/
+#line 2261 "cweave.w"
+;break;
+case decl:/*127:*/
+#line 2558 "cweave.w"
+
+if(cat1==decl){
+big_app1(pp);big_app(force);big_app1(pp+1);
+reduce(pp,2,decl,-1,40);
+}
+else if(cat1==stmt||cat1==function){
+big_app1(pp);big_app(big_force);
+big_app1(pp+1);reduce(pp,2,cat1,-1,41);
+}
+
+/*:127*/
+#line 2262 "cweave.w"
+;break;
+case typedef_like:/*128:*/
+#line 2568 "cweave.w"
+
+#line 479 "cweave.ch"
+if(cat1==decl_head){
+if((cat2==exp&&cat3!=lpar&&cat3!=exp)||cat2==int_like){
+make_underlined(pp+2);make_reserved(pp+2,raw_int);
+big_app2(pp+1);reduce(pp+1,2,decl_head,0,42);
+}
+else if(cat2==semi){
+big_app1(pp);big_app(' ');big_app2(pp+1);reduce(pp,3,decl,-1,43);
+}
+}
+else if(cat1==exp&&!preprocessing&&cat2!=lpar){
+make_reserved(pp+1,raw_int);
+squash(pp+1,1,raw_int,-2,116);
+}
+#line 2577 "cweave.w"
+
+/*:128*/
+#line 2263 "cweave.w"
+;break;
+case struct_like:/*129:*/
+#line 2578 "cweave.w"
+
+#line 515 "cweave.ch"
+if(cat1==lbrace){
+if(alternative){
+big_app1(pp);big_app(indent);big_app(force);big_app(backup);
+big_app1(pp+1);reduce(pp,2,struct_head,0,44);
+}else{
+big_app1(pp);big_app(' ');big_app1(pp+1);
+reduce(pp,2,struct_head,0,44);
+}
+}
+else if(cat1==exp||cat1==int_like){
+if(cat2==lbrace||cat2==semi){
+make_underlined(pp+1);make_reserved(pp+1,raw_int);
+big_app1(pp);big_app(' ');big_app1(pp+1);
+if(cat2==semi)reduce(pp,2,decl_head,-1,45);
+else{
+if(alternative){
+big_app(indent);big_app(force);big_app(backup);big_app1(pp+2);
+reduce(pp,3,struct_head,0,46);
+}else{
+big_app(' ');big_app1(pp+2);reduce(pp,3,struct_head,0,46);
+}
+}
+}
+else if(cat2==colon)squash(pp+2,1,base,-1,47);
+else if(!(cat2==base||cat2==raw_int||
+cat2==int_like||cat2==const_like)){
+big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,int_like,-2,48);
+}
+}
+#line 2596 "cweave.w"
+
+/*:129*/
+#line 2264 "cweave.w"
+;break;
+case struct_head:/*130:*/
+#line 2597 "cweave.w"
+
+if((cat1==decl||cat1==stmt||cat1==function)&&cat2==rbrace){
+#line 553 "cweave.ch"
+if(alternative){
+big_app1(pp);big_app1(pp+1);
+big_app(force);big_app(backup);big_app1(pp+2);big_app(' ');
+big_app(outdent);reduce(pp,3,int_like,-2,49);
+}else{
+big_app1(pp);big_app(indent);big_app(force);big_app1(pp+1);
+big_app(outdent);big_app(force);big_app1(pp+2);
+reduce(pp,3,int_like,-2,49);
+}
+#line 2602 "cweave.w"
+}
+else if(cat1==rbrace){
+big_app1(pp);app_str("\\,");big_app1(pp+1);
+
+reduce(pp,2,int_like,-2,50);
+}
+
+/*:130*/
+#line 2265 "cweave.w"
+;break;
+case fn_decl:/*131:*/
+#line 2609 "cweave.w"
+
+if(cat1==decl){
+big_app1(pp);big_app(force);big_app1(pp+1);reduce(pp,2,fn_decl,0,51);
+}
+else if(cat1==stmt){
+big_app1(pp);app(outdent);app(outdent);big_app(force);
+big_app1(pp+1);reduce(pp,2,function,-1,52);
+}
+
+/*:131*/
+#line 2266 "cweave.w"
+;break;
+case function:/*132:*/
+#line 2618 "cweave.w"
+
+if(cat1==function||cat1==decl||cat1==stmt){
+big_app1(pp);big_app(big_force);big_app1(pp+1);reduce(pp,2,cat1,-1,53);
+}
+
+/*:132*/
+#line 2267 "cweave.w"
+;break;
+case lbrace:/*133:*/
+#line 2623 "cweave.w"
+
+if(cat1==rbrace){
+big_app1(pp);app('\\');app(',');big_app1(pp+1);
+
+reduce(pp,2,stmt,-1,54);
+}
+else if((cat1==stmt||cat1==decl||cat1==function)&&cat2==rbrace){
+#line 571 "cweave.ch"
+if(alternative){
+big_app(indent);big_app(force);big_app(backup);big_app1(pp);
+app(noop);big_app(cancel);big_app1(pp+1);big_app(force);big_app(backup);
+big_app1(pp+2);big_app(outdent);big_app(force);reduce(pp,3,stmt,-2,55);
+}else{
+big_app(force);big_app1(pp);big_app(indent);big_app(force);
+big_app1(pp+1);big_app(force);big_app(backup);big_app1(pp+2);
+big_app(outdent);big_app(force);reduce(pp,3,stmt,-1,55);
+}
+#line 2633 "cweave.w"
+}
+else if(cat1==exp){
+if(cat2==rbrace)squash(pp,3,exp,-2,56);
+else if(cat2==comma&&cat3==rbrace)squash(pp,4,exp,-2,56);
+}
+
+/*:133*/
+#line 2268 "cweave.w"
+;break;
+case do_like:/*140:*/
+#line 2689 "cweave.w"
+
+#line 669 "cweave.ch"
+if(alternative){
+if(cat1==lbrace)squash(pp,1,do_head,0,114);
+else if(cat1==stmt&&cat2==else_like&&cat3==semi){
+big_app(force);big_app1(pp);big_app(indent);big_app(force);
+big_app1(pp+1);big_app(cancel);app(noop);
+big_app(break_space);big_app2(pp+2);big_app(outdent);big_app(force);
+reduce(pp,4,stmt,-1,69);
+}
+}else{
+if(cat1==stmt&&cat2==else_like&&cat3==semi){
+big_app1(pp);big_app(break_space);app(noop);big_app(cancel);
+big_app1(pp+1);big_app(cancel);app(noop);big_app(break_space);
+big_app2(pp+2);reduce(pp,4,stmt,-1,69);
+}
+}
+#line 2695 "cweave.w"
+
+/*:140*/
+#line 2269 "cweave.w"
+;break;
+case if_like:/*134:*/
+#line 2639 "cweave.w"
+
+if(cat1==exp){
+big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,if_clause,0,57);
+}
+
+/*:134*/
+#line 2270 "cweave.w"
+;break;
+case for_like:/*135:*/
+#line 2644 "cweave.w"
+
+if(cat1==exp){
+big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,else_like,-2,58);
+}
+
+/*:135*/
+#line 2271 "cweave.w"
+;break;
+case else_like:/*136:*/
+#line 2649 "cweave.w"
+
+if(cat1==lbrace)squash(pp,1,else_head,0,59);
+else if(cat1==stmt){
+#line 589 "cweave.ch"
+if(alternative){
+big_app(force);big_app1(pp);big_app(indent);big_app(force);
+big_app1(pp+1);big_app(outdent);big_app(force);
+reduce(pp,2,stmt,-1,60);
+}else{
+big_app(force);big_app1(pp);big_app(indent);big_app(break_space);
+big_app1(pp+1);big_app(outdent);big_app(force);
+reduce(pp,2,stmt,-1,60);
+}
+#line 2655 "cweave.w"
+}
+
+/*:136*/
+#line 2272 "cweave.w"
+;break;
+case if_clause:/*138:*/
+#line 2664 "cweave.w"
+
+if(cat1==lbrace)squash(pp,1,if_head,0,62);
+else if(cat1==stmt){
+if(cat2==else_like){
+#line 627 "cweave.ch"
+if(alternative){
+big_app(force);big_app1(pp);big_app(indent);big_app(force);
+big_app1(pp+1);big_app(outdent);big_app(force);big_app1(pp+2);
+}else{
+big_app(force);big_app1(pp);big_app(indent);big_app(break_space);
+big_app1(pp+1);big_app(outdent);big_app(force);big_app1(pp+2);
+}
+if(cat3==if_like){
+big_app(' ');big_app1(pp+3);reduce(pp,4,if_like,0,63);
+}else reduce(pp,3,else_like,0,64);
+#line 2673 "cweave.w"
+}
+else squash(pp,1,else_like,0,65);
+}
+
+/*:138*/
+#line 2273 "cweave.w"
+;break;
+case if_head:/*139:*/
+#line 2677 "cweave.w"
+
+if(cat1==stmt||cat1==exp){
+if(cat2==else_like){
+#line 648 "cweave.ch"
+if(alternative){
+big_app(force);big_app1(pp);big_app(break_space);
+big_app1(pp+1);big_app(force);big_app1(pp+2);
+}else{
+big_app(force);big_app1(pp);big_app(break_space);app(noop);
+big_app(cancel);big_app1(pp+1);big_app(force);big_app1(pp+2);
+}
+if(cat3==if_like){
+big_app(' ');big_app1(pp+3);reduce(pp,4,if_like,0,66);
+}else reduce(pp,3,else_like,0,67);
+#line 2685 "cweave.w"
+}
+else squash(pp,1,else_head,0,68);
+}
+
+/*:139*/
+#line 2274 "cweave.w"
+;break;
+case else_head:/*137:*/
+#line 2657 "cweave.w"
+
+if(cat1==stmt||cat1==exp){
+#line 607 "cweave.ch"
+if(alternative){
+big_app(force);big_app1(pp);big_app(break_space);
+big_app1(pp+1);big_app(force);
+reduce(pp,2,stmt,-1,61);
+}else{
+big_app(force);big_app1(pp);big_app(break_space);app(noop);
+big_app(cancel);big_app1(pp+1);big_app(force);
+reduce(pp,2,stmt,-1,61);
+}
+#line 2662 "cweave.w"
+}
+
+/*:137*/
+#line 2275 "cweave.w"
+;break;
+case case_like:/*141:*/
+#line 2696 "cweave.w"
+
+#line 692 "cweave.ch"
+if(cat1==semi)squash(pp,2,stmt,-3,70);
+else if(cat1==colon)squash(pp,2,tag,-2,71);
+#line 2699 "cweave.w"
+else if(cat1==exp){
+if(cat2==semi){
+big_app1(pp);big_app(' ');big_app1(pp+1);big_app1(pp+2);
+reduce(pp,3,stmt,-1,72);
+}
+else if(cat2==colon){
+big_app1(pp);big_app(' ');big_app1(pp+1);big_app1(pp+2);
+#line 701 "cweave.ch"
+reduce(pp,3,tag,-2,73);
+#line 2707 "cweave.w"
+}
+}
+
+/*:141*/
+#line 2276 "cweave.w"
+;break;
+case stmt:/*143:*/
+#line 2723 "cweave.w"
+
+if(cat1==stmt||cat1==decl||cat1==function){
+big_app1(pp);
+if(cat1==function)big_app(big_force);
+else if(cat1==decl)big_app(big_force);
+else if(force_lines)big_app(force);
+else big_app(break_space);
+big_app1(pp+1);reduce(pp,2,cat1,-1,76);
+}
+
+/*:143*/
+#line 2277 "cweave.w"
+;break;
+case tag:/*142:*/
+#line 2710 "cweave.w"
+
+#line 715 "cweave.ch"
+if(alternative){
+if(cat1==tag){
+big_app1(pp);big_app(force);big_app1(pp+1);reduce(pp,2,tag,-1,74);
+}
+else if((cat1==stmt||cat1==decl||cat1==function)&&
+(cat2==rbrace||cat2==tag)){
+big_app(force);big_app1(pp);big_app(indent);big_app(force);
+big_app1(pp+1);big_app(outdent);reduce(pp,2,cat1,-1,75);
+}
+}else{
+if(cat1==tag){
+big_app1(pp);big_app(break_space);big_app1(pp+1);reduce(pp,2,tag,-1,74);
+}
+else if(cat1==stmt||cat1==decl||cat1==function){
+big_app(force);big_app(backup);big_app1(pp);big_app(break_space);
+big_app1(pp+1);reduce(pp,2,cat1,-1,75);
+}
+}
+#line 2718 "cweave.w"
+
+/*:142*/
+#line 2278 "cweave.w"
+;break;
+case semi:/*144:*/
+#line 2733 "cweave.w"
+
+big_app(' ');big_app1(pp);reduce(pp,1,stmt,-1,77);
+
+/*:144*/
+#line 2279 "cweave.w"
+;break;
+case lproc:/*145:*/
+#line 2736 "cweave.w"
+
+if(cat1==define_like)make_underlined(pp+2);
+if(cat1==else_like||cat1==if_like||cat1==define_like)
+squash(pp,2,lproc,0,78);
+else if(cat1==rproc){
+app(inserted);big_app2(pp);reduce(pp,2,insert,-1,79);
+#line 750 "cweave.ch"
+}else if((cat1==exp||cat1==function||cat1==int_like)&&cat2==rproc){
+app(inserted);big_app1(pp);big_app(' ');big_app2(pp+1);
+reduce(pp,3,insert,-1,80);
+}else if((cat1==exp||cat1==int_like||cat1==const_like)&&
+cat2==pp_space){
+if(cat3==int_like||cat3==const_like||cat3==raw_int)
+make_reserved(pp+1,(pp+3)->cat);
+big_app1(pp);big_app(' ');big_app1(pp+1);app_str(" \\5");
+
+reduce(pp,3,lproc,-1,119);
+}else if(cat1==exp&&cat2==exp&&cat3==pp_space){
+big_app1(pp);big_app(' ');big_app2(pp+1);app_str(" \\5");
+reduce(pp,4,lproc,-1,120);
+}
+#line 2753 "cweave.w"
+
+/*:145*/
+#line 2280 "cweave.w"
+;break;
+case section_scrap:/*146:*/
+#line 2754 "cweave.w"
+
+if(cat1==semi){
+big_app2(pp);big_app(force);reduce(pp,2,stmt,-2,81);
+}
+else squash(pp,1,exp,-2,82);
+
+/*:146*/
+#line 2281 "cweave.w"
+;break;
+case insert:/*147:*/
+#line 2760 "cweave.w"
+
+if(cat1)
+squash(pp,2,cat1,0,83);
+
+/*:147*/
+#line 2282 "cweave.w"
+;break;
+case prelangle:/*148:*/
+#line 2764 "cweave.w"
+
+init_mathness= cur_mathness= yes_math;
+app('<');reduce(pp,1,binop,-2,84);
+
+/*:148*/
+#line 2283 "cweave.w"
+;break;
+case prerangle:/*149:*/
+#line 2768 "cweave.w"
+
+init_mathness= cur_mathness= yes_math;
+app('>');reduce(pp,1,binop,-2,85);
+
+/*:149*/
+#line 2284 "cweave.w"
+;break;
+case langle:/*150:*/
+#line 2772 "cweave.w"
+
+if(cat1==exp&&cat2==prerangle)squash(pp,3,cast,-1,86);
+else if(cat1==prerangle){
+big_app1(pp);app('\\');app(',');big_app1(pp+1);
+
+reduce(pp,2,cast,-1,87);
+}
+else if(cat1==decl_head||cat1==int_like){
+if(cat2==prerangle)squash(pp,3,cast,-1,88);
+else if(cat2==comma){
+big_app3(pp);app(opt);app('9');reduce(pp,3,langle,0,89);
+}
+}
+
+/*:150*/
+#line 2285 "cweave.w"
+;break;
+case public_like:/*151:*/
+#line 2786 "cweave.w"
+
+#line 771 "cweave.ch"
+if(cat1==colon)squash(pp,2,tag,-2,90);
+#line 2788 "cweave.w"
+else squash(pp,1,int_like,-2,91);
+
+/*:151*/
+#line 2286 "cweave.w"
+;break;
+case colcol:/*152:*/
+#line 2790 "cweave.w"
+
+if(cat1==exp||cat1==int_like)squash(pp,2,cat1,-2,92);
+
+/*:152*/
+#line 2287 "cweave.w"
+;break;
+case new_like:/*153:*/
+#line 2793 "cweave.w"
+
+if(cat1==exp||(cat1==raw_int&&cat2!=prelangle&&cat2!=langle)){
+big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,new_like,0,93);
+}
+else if(cat1==raw_unorbin||cat1==colcol)
+squash(pp,2,new_like,0,94);
+else if(cat1==cast)squash(pp,2,exp,-2,95);
+else if(cat1!=lpar&&cat1!=raw_int&&cat1!=struct_like)
+squash(pp,1,exp,-2,96);
+
+/*:153*/
+#line 2288 "cweave.w"
+;break;
+case operator_like:/*154:*/
+#line 2803 "cweave.w"
+
+#line 786 "cweave.ch"
+if(cat1==binop||cat1==unop||cat1==unorbinop||cat1==raw_unorbin){
+if(cat2==binop)break;
+big_app1(pp);big_app('{');big_app1(pp+1);big_app('}');
+reduce(pp,2,exp,-2,97);
+}
+else if(cat1==new_like||cat1==sizeof_like){
+big_app1(pp);big_app(' ');big_app1(pp+1);reduce(pp,2,exp,-2,98);
+}
+else if(cat1==raw_int||cat1==int_like||cat1==const_like){
+big_app1(pp);big_app(' ');big_app1(pp+1);
+reduce(pp,2,operator_like,-2,118);
+}
+#line 2812 "cweave.w"
+else squash(pp,1,new_like,0,99);
+
+/*:154*/
+#line 2289 "cweave.w"
+;break;
+case catch_like:/*155:*/
+#line 2814 "cweave.w"
+
+if(cat1==cast||cat1==exp){
+big_app2(pp);big_app(indent);big_app(indent);
+reduce(pp,2,fn_decl,0,100);
+}
+
+/*:155*/
+#line 2290 "cweave.w"
+;break;
+case base:/*156:*/
+#line 2820 "cweave.w"
+
+if(cat1==public_like&&cat2==exp){
+if(cat3==comma){
+big_app2(pp);big_app(' ');big_app2(pp+2);
+reduce(pp,4,base,0,101);
+}else{
+big_app1(pp+1);big_app(' ');big_app1(pp+2);
+reduce(pp+1,2,int_like,-1,102);
+}
+}
+
+/*:156*/
+#line 2291 "cweave.w"
+;break;
+case raw_rpar:/*157:*/
+#line 2831 "cweave.w"
+
+if(cat1==const_like&&
+(cat2==semi||cat2==lbrace||cat2==comma||cat2==binop
+||cat2==const_like)){
+big_app1(pp);big_app(' ');
+big_app1(pp+1);reduce(pp,2,raw_rpar,0,103);
+}else squash(pp,1,rpar,-3,104);
+
+/*:157*/
+#line 2292 "cweave.w"
+;break;
+case raw_unorbin:/*158:*/
+#line 2839 "cweave.w"
+
+if(cat1==const_like){
+big_app2(pp);app_str("\\ ");reduce(pp,2,raw_unorbin,0,105);
+
+}else squash(pp,1,unorbinop,-2,106);
+
+/*:158*/
+#line 2293 "cweave.w"
+;break;
+case const_like:/*159:*/
+#line 2845 "cweave.w"
+
+squash(pp,1,int_like,-2,107);
+
+/*:159*/
+#line 2294 "cweave.w"
+;break;
+#line 392 "cweave.ch"
+case raw_int:/*160:*/
+#line 2848 "cweave.w"
+
+if(cat1==lpar)squash(pp,1,exp,-2,108);
+else squash(pp,1,int_like,-3,109);
+
+/*:160*/
+#line 392 "cweave.ch"
+;break;
+case label:/*249:*/
+#line 1075 "cweave.ch"
+
+if(cat1==label){
+big_app1(pp);big_app(force);big_app1(pp+1);reduce(pp,2,label,-1,112);
+}
+else if(cat1==stmt||cat1==decl||cat1==function){
+big_app(cancel);app(noop);
+big_app(outdent);big_app(outdent);big_app(force);
+big_app1(pp);big_app(indent);big_app(indent);big_app(force);
+big_app1(pp+1);reduce(pp,2,cat1,-1,113);
+}
+
+/*:249*/
+#line 393 "cweave.ch"
+;break;
+case do_head:/*250:*/
+#line 1086 "cweave.ch"
+
+if(cat1==stmt&&cat2==else_like&&cat3==semi){
+big_app1(pp);big_app(break_space);big_app1(pp+1);big_app(cancel);
+app(noop);big_app(break_space);big_app2(pp+2);reduce(pp,4,stmt,-1,115);
+}
+
+/*:250*/
+#line 394 "cweave.ch"
+;break;
+#line 2296 "cweave.w"
+}
+pp++;
+}
+
+/*:110*/
+#line 2942 "cweave.w"
+;
+}
+
+/*:165*/
+#line 3002 "cweave.w"
+;
+/*170:*/
+#line 3011 "cweave.w"
+{
+/*171:*/
+#line 3023 "cweave.w"
+
+if(lo_ptr>scrap_base&&tracing==1){
+printf("\nIrreducible scrap sequence in section %d:",section_count);
+
+mark_harmless;
+for(j= scrap_base;j<=lo_ptr;j++){
+printf(" ");print_cat(j->cat);
+}
+}
+
+/*:171*/
+#line 3012 "cweave.w"
+;
+for(j= scrap_base;j<=lo_ptr;j++){
+if(j!=scrap_base)app(' ');
+if(j->mathness%4==yes_math)app('$');
+app1(j);
+if(j->mathness/4==yes_math)app('$');
+if(tok_ptr+6>tok_mem_end)overflow("token");
+}
+freeze_text;return(text_ptr-1);
+}
+
+/*:170*/
+#line 3003 "cweave.w"
+;
+}
+
+/*:169*//*173:*/
+#line 3059 "cweave.w"
+
+void
+C_parse(spec_ctrl)
+eight_bits spec_ctrl;
+{
+int count;
+while(next_control<format_code||next_control==spec_ctrl){
+/*175:*/
+#line 821 "cweave.ch"
+
+/*176:*/
+#line 3156 "cweave.w"
+
+if(scrap_ptr+safe_scrap_incr>scrap_info_end||
+tok_ptr+safe_tok_incr>tok_mem_end||
+text_ptr+safe_text_incr>tok_start_end){
+if(scrap_ptr>max_scr_ptr)max_scr_ptr= scrap_ptr;
+if(tok_ptr>max_tok_ptr)max_tok_ptr= tok_ptr;
+if(text_ptr>max_text_ptr)max_text_ptr= text_ptr;
+overflow("scrap/token/text");
+}
+
+/*:176*/
+#line 822 "cweave.ch"
+;
+#line 3084 "cweave.w"
+switch(next_control){
+case section_name:
+app(section_flag+(int)(cur_section-name_dir));
+app_scrap(section_scrap,maybe_math);
+app_scrap(exp,yes_math);break;
+case string:case constant:case verbatim:/*178:*/
+#line 3211 "cweave.w"
+
+count= -1;
+if(next_control==constant)app_str("\\T{");
+
+else if(next_control==string){
+count= 20;app_str("\\.{");
+}
+
+else app_str("\\vb{");
+
+while(id_first<id_loc){
+if(count==0){
+app_str("}\\)\\.{");count= 20;
+
+}
+
+if((eight_bits)(*id_first)>0177){
+app_tok(quoted_char);
+app_tok((eight_bits)(*id_first++));
+}
+else{
+switch(*id_first){
+case' ':case'\\':case'#':case'%':case'$':case'^':
+case'{':case'}':case'~':case'&':case'_':app('\\');break;
+
+
+
+#line 913 "cweave.ch"
+
+
+
+#line 3241 "cweave.w"
+
+
+
+
+
+case'@':if(*(id_first+1)=='@')id_first++;
+else err_print("! Double @ should be used in strings");
+
+}
+app_tok(*id_first++);
+}
+count--;
+}
+app('}');
+app_scrap(exp,maybe_math);
+
+/*:178*/
+#line 3089 "cweave.w"
+;
+break;
+case identifier:app_cur_id(1);break;
+case TeX_string:/*179:*/
+#line 3272 "cweave.w"
+
+app_str("\\hbox{");
+
+while(id_first<id_loc)
+if((eight_bits)(*id_first)>0177){
+app_tok(quoted_char);
+app_tok((eight_bits)(*id_first++));
+}
+else{
+if(*id_first=='@')id_first++;
+app_tok(*id_first++);
+}
+app('}');
+
+/*:179*/
+#line 3092 "cweave.w"
+;break;
+case'/':case'.':
+app(next_control);app_scrap(binop,yes_math);break;
+case'<':app_str("\\langle");app_scrap(prelangle,yes_math);break;
+
+case'>':app_str("\\rangle");app_scrap(prerangle,yes_math);break;
+
+case'=':app_str("\\K");app_scrap(binop,yes_math);break;
+
+case'|':app_str("\\OR");app_scrap(binop,yes_math);break;
+
+case'^':app_str("\\XOR");app_scrap(binop,yes_math);break;
+
+case'%':app_str("\\MOD");app_scrap(binop,yes_math);break;
+
+case'!':app_str("\\R");app_scrap(unop,yes_math);break;
+
+case'~':app_str("\\CM");app_scrap(unop,yes_math);break;
+
+case'+':case'-':app(next_control);app_scrap(unorbinop,yes_math);break;
+case'*':app(next_control);app_scrap(raw_unorbin,yes_math);break;
+case'&':app_str("\\AND");app_scrap(raw_unorbin,yes_math);break;
+
+case'?':app_str("\\?");app_scrap(question,yes_math);break;
+
+case'#':app_str("\\#");app_scrap(unorbinop,yes_math);break;
+
+case ignore:case xref_roman:case xref_wildcard:
+case xref_typewriter:case noop:break;
+#line 835 "cweave.ch"
+case'(':if(func_index)
+if(*(tok_ptr-1)>=id_flag&&*(tok_ptr-1)<res_flag)
+
+(name_dir+*(tok_ptr-1)%10240)->func_flag= 1;
+case'[':app(next_control);app_scrap(lpar,maybe_math);break;
+case')':case']':app(next_control);app_scrap(raw_rpar,maybe_math);break;
+case'{':if(alternative)
+app_str("\\LBR");
+else
+app_str("\\{");
+app_scrap(lbrace,yes_math);break;
+
+case'}':if(alternative)
+app_str("\\RBR");
+else
+app_str("\\}");
+app_scrap(rbrace,yes_math);break;
+
+#line 3127 "cweave.w"
+case',':app(',');app_scrap(comma,yes_math);break;
+case';':app(';');app_scrap(semi,maybe_math);break;
+case':':app(':');app_scrap(colon,maybe_math);break;
+/*177:*/
+#line 3170 "cweave.w"
+
+case not_eq:app_str("\\I");app_scrap(binop,yes_math);break;
+
+case lt_eq:app_str("\\Z");app_scrap(binop,yes_math);break;
+
+case gt_eq:app_str("\\G");app_scrap(binop,yes_math);break;
+
+case eq_eq:app_str("\\E");app_scrap(binop,yes_math);break;
+
+case and_and:app_str("\\W");app_scrap(binop,yes_math);break;
+
+case or_or:app_str("\\V");app_scrap(binop,yes_math);break;
+
+case plus_plus:app_str("\\PP");app_scrap(unop,yes_math);break;
+
+case minus_minus:app_str("\\MM");app_scrap(unop,yes_math);break;
+
+case minus_gt:app_str("\\MG");app_scrap(binop,yes_math);break;
+
+case gt_gt:app_str("\\GG");app_scrap(binop,yes_math);break;
+
+case lt_lt:app_str("\\LL");app_scrap(binop,yes_math);break;
+
+case dot_dot_dot:app_str("\\,\\ldots\\,");app_scrap(exp,yes_math);break;
+
+
+case colon_colon:app_str("\\DC");app_scrap(colcol,maybe_math);break;
+
+case period_ast:app_str("\\PA");app_scrap(binop,yes_math);break;
+
+#line 900 "cweave.ch"
+case minus_gt_ast:app_str("\\MGA");app_scrap(binop,yes_math);break;
+
+case numb_numb:app_str("\\NN");app_scrap(binop,yes_math);break;
+
+#line 3202 "cweave.w"
+
+/*:177*/
+#line 3130 "cweave.w"
+
+case thin_space:app_str("\\,");app_scrap(insert,maybe_math);break;
+
+case math_break:app(opt);app_str("0");
+app_scrap(insert,maybe_math);break;
+case line_break:app(force);app_scrap(insert,no_math);break;
+#line 863 "cweave.ch"
+case left_preproc:app(force);app(preproc_line);
+app_str("\\#");app_scrap(lproc,no_math);break;
+
+case preproc_space:app(' ');app_scrap(pp_space,maybe_math);break;
+case right_preproc:app(force);app_scrap(rproc,no_math);break;
+#line 3140 "cweave.w"
+case big_line_break:app(big_force);app_scrap(insert,no_math);break;
+case no_line_break:app(big_cancel);app(noop);app(break_space);
+app(noop);app(big_cancel);
+app_scrap(insert,no_math);break;
+#line 875 "cweave.ch"
+case pseudo_semi:app_scrap(semi,maybe_math);break;
+case pseudo_lbrace:app_str("\\phantom{");
+if(alternative)
+app_str("\\LBR");
+else
+app_str("\\{");
+app_str("}");
+app_scrap(lbrace,yes_math);
+break;
+case pseudo_rbrace:app_str("\\phantom{");
+if(alternative)
+app_str("\\RBR");
+else
+app_str("\\}");
+app_str("}");
+app_scrap(rbrace,yes_math);
+break;
+#line 3145 "cweave.w"
+case macro_arg_open:app_scrap(begin_arg,maybe_math);break;
+case macro_arg_close:app_scrap(end_arg,maybe_math);break;
+case join:app_str("\\J");app_scrap(insert,no_math);break;
+
+case output_defs_code:app(force);app_str("\\ATH");app(force);
+app_scrap(insert,no_math);break;
+
+default:app(inserted);app(next_control);
+app_scrap(insert,maybe_math);break;
+}
+
+/*:175*/
+#line 3066 "cweave.w"
+;
+next_control= get_next();
+if(next_control=='|'||next_control==begin_comment||
+next_control==begin_short_comment)return;
+}
+}
+
+/*:173*//*181:*/
+#line 3292 "cweave.w"
+
+void
+app_cur_id(scrapping)
+boolean scrapping;
+{
+name_pointer p= id_lookup(id_first,id_loc,normal);
+if(p->ilk<=quoted){
+app(id_flag+(int)(p-name_dir));
+if(scrapping)app_scrap(exp,p->ilk>=custom?yes_math:maybe_math);
+
+}else{
+app(res_flag+(int)(p-name_dir));
+if(scrapping)app_scrap(p->ilk,maybe_math);
+}
+}
+
+/*:181*//*182:*/
+#line 3313 "cweave.w"
+
+text_pointer
+C_translate()
+{
+text_pointer p;
+scrap_pointer save_base;
+save_base= scrap_base;scrap_base= scrap_ptr+1;
+C_parse(section_name);
+if(next_control!='|')err_print("! Missing '|' after C text");
+
+app_tok(cancel);app_scrap(insert,maybe_math);
+
+p= translate();
+if(scrap_ptr>max_scr_ptr)max_scr_ptr= scrap_ptr;
+scrap_ptr= scrap_base-1;scrap_base= save_base;
+return(p);
+}
+
+/*:182*//*183:*/
+#line 3335 "cweave.w"
+
+void
+outer_parse()
+{
+int bal;
+text_pointer p,q;
+while(next_control<format_code)
+if(next_control!=begin_comment&&next_control!=begin_short_comment)
+C_parse(ignore);
+else{
+boolean is_long_comment= (next_control==begin_comment);
+/*176:*/
+#line 3156 "cweave.w"
+
+if(scrap_ptr+safe_scrap_incr>scrap_info_end||
+tok_ptr+safe_tok_incr>tok_mem_end||
+text_ptr+safe_text_incr>tok_start_end){
+if(scrap_ptr>max_scr_ptr)max_scr_ptr= scrap_ptr;
+if(tok_ptr>max_tok_ptr)max_tok_ptr= tok_ptr;
+if(text_ptr>max_text_ptr)max_text_ptr= text_ptr;
+overflow("scrap/token/text");
+}
+
+/*:176*/
+#line 3346 "cweave.w"
+;
+app(cancel);app(inserted);
+if(is_long_comment)app_str("\\C{");
+
+else app_str("\\SHC{");
+
+bal= copy_comment(is_long_comment,1);next_control= ignore;
+while(bal>0){
+p= text_ptr;freeze_text;q= C_translate();
+
+app(tok_flag+(int)(p-tok_start));
+app_str("\\PB{");app(inner_tok_flag+(int)(q-tok_start));app_tok('}');
+
+if(next_control=='|'){
+bal= copy_comment(is_long_comment,bal);
+next_control= ignore;
+}
+else bal= 0;
+}
+app(force);app_scrap(insert,no_math);
+
+}
+}
+
+/*:183*//*188:*/
+#line 3439 "cweave.w"
+
+void
+push_level(p)
+text_pointer p;
+{
+if(stack_ptr==stack_end)overflow("stack");
+if(stack_ptr>stack){
+stack_ptr->end_field= cur_end;
+stack_ptr->tok_field= cur_tok;
+stack_ptr->mode_field= cur_mode;
+}
+stack_ptr++;
+if(stack_ptr>max_stack_ptr)max_stack_ptr= stack_ptr;
+cur_tok= *p;cur_end= *(p+1);
+}
+
+/*:188*//*189:*/
+#line 3459 "cweave.w"
+
+void
+pop_level()
+{
+cur_end= (--stack_ptr)->end_field;
+cur_tok= stack_ptr->tok_field;cur_mode= stack_ptr->mode_field;
+}
+
+/*:189*//*191:*/
+#line 3481 "cweave.w"
+
+eight_bits
+get_output()
+{
+sixteen_bits a;
+restart:while(cur_tok==cur_end)pop_level();
+a= *(cur_tok++);
+if(a>=0400){
+cur_name= a%id_flag+name_dir;
+switch(a/id_flag){
+case 2:return(res_word);
+case 3:return(section_code);
+case 4:push_level(a%id_flag+tok_start);goto restart;
+
+case 5:push_level(a%id_flag+tok_start);cur_mode= inner;goto restart;
+
+default:return(identifier);
+}
+}
+return(a);
+}
+
+/*:191*//*192:*/
+#line 3523 "cweave.w"
+
+void
+output_C()
+{
+token_pointer save_tok_ptr;
+text_pointer save_text_ptr;
+sixteen_bits save_next_control;
+text_pointer p;
+save_tok_ptr= tok_ptr;save_text_ptr= text_ptr;
+save_next_control= next_control;next_control= ignore;p= C_translate();
+app(inner_tok_flag+(int)(p-tok_start));
+out_str("\\PB{");make_output();out('}');
+
+if(text_ptr>max_text_ptr)max_text_ptr= text_ptr;
+if(tok_ptr>max_tok_ptr)max_tok_ptr= tok_ptr;
+text_ptr= save_text_ptr;tok_ptr= save_tok_ptr;
+next_control= save_next_control;
+}
+
+/*:192*//*194:*/
+#line 3547 "cweave.w"
+
+void
+make_output()
+{
+eight_bits a,
+b;
+int c;
+char scratch[longest_name];
+char*k,*k_limit;
+char*j;
+char*p;
+char delim;
+char*save_loc,*save_limit;
+name_pointer cur_section_name;
+boolean save_mode;
+app(end_translation);
+freeze_text;push_level(text_ptr-1);
+while(1){
+a= get_output();
+reswitch:switch(a){
+case end_translation:return;
+case identifier:case res_word:/*195:*/
+#line 3597 "cweave.w"
+
+out('\\');
+if(a==identifier){
+if(cur_name->ilk>=custom&&cur_name->ilk<=quoted&&!doing_format){
+for(p= cur_name->byte_start;p<(cur_name+1)->byte_start;p++)
+out(isxalpha(*p)?'x':*p);
+break;
+#line 923 "cweave.ch"
+}else if(is_tiny(cur_name))out('|');
+#line 3605 "cweave.w"
+
+else{delim= '.';
+for(p= cur_name->byte_start;p<(cur_name+1)->byte_start;p++)
+if(xislower(*p)){
+delim= '\\';break;
+}
+out(delim);
+}
+
+
+}
+#line 931 "cweave.ch"
+else out('&');
+#line 3617 "cweave.w"
+
+if(is_tiny(cur_name)){
+if(isxalpha((cur_name->byte_start)[0]))
+out('\\');
+out((cur_name->byte_start)[0]);
+}
+else out_name(cur_name);
+
+/*:195*/
+#line 3568 "cweave.w"
+;break;
+case section_code:/*199:*/
+#line 3695 "cweave.w"
+{
+out_str("\\X");
+
+cur_xref= (xref_pointer)cur_name->xref;
+if(cur_xref->num==file_flag){an_output= 1;cur_xref= cur_xref->xlink;}
+else an_output= 0;
+if(cur_xref->num>=def_flag){
+out_section(cur_xref->num-def_flag);
+if(phase==3){
+cur_xref= cur_xref->xlink;
+while(cur_xref->num>=def_flag){
+out_str(", ");
+out_section(cur_xref->num-def_flag);
+cur_xref= cur_xref->xlink;
+}
+}
+}
+else out('0');
+out(':');
+if(an_output)out_str("\\.{");
+
+/*200:*/
+#line 3721 "cweave.w"
+
+sprint_section_name(scratch,cur_name);
+k= scratch;
+k_limit= scratch+strlen(scratch);
+cur_section_name= cur_name;
+while(k<k_limit){
+b= *(k++);
+if(b=='@')/*201:*/
+#line 3756 "cweave.w"
+
+if(*k++!='@'){
+printf("\n! Illegal control code in section name: <");
+
+print_section_name(cur_section_name);printf("> ");mark_error;
+}
+
+/*:201*/
+#line 3728 "cweave.w"
+;
+if(an_output)
+switch(b){
+case' ':case'\\':case'#':case'%':case'$':case'^':
+case'{':case'}':case'~':case'&':case'_':
+out('\\');
+
+
+
+#line 949 "cweave.ch"
+
+
+
+#line 3740 "cweave.w"
+
+
+
+
+
+default:out(b);
+}
+#line 959 "cweave.ch"
+else if(b!='|')out(b);
+#line 3748 "cweave.w"
+else{
+/*202:*/
+#line 3769 "cweave.w"
+
+j= limit+1;*j= '|';delim= 0;
+while(1){
+if(k>=k_limit){
+printf("\n! C text in section name didn't end: <");
+
+print_section_name(cur_section_name);printf("> ");mark_error;break;
+}
+b= *(k++);
+if(b=='@'||(b=='\\'&&delim!=0))
+/*203:*/
+#line 3792 "cweave.w"
+{
+if(j>buffer+long_buf_size-4)overflow("buffer");
+*(++j)= b;*(++j)= *(k++);
+}
+
+/*:203*/
+#line 3779 "cweave.w"
+
+else{
+if(b=='\''||b=='"')
+if(delim==0)delim= b;
+else if(delim==b)delim= 0;
+if(b!='|'||delim!=0){
+if(j>buffer+long_buf_size-3)overflow("buffer");
+*(++j)= b;
+}
+else break;
+}
+}
+
+/*:202*/
+#line 3749 "cweave.w"
+;
+save_loc= loc;save_limit= limit;loc= limit+2;limit= j+1;
+*limit= '|';output_C();
+loc= save_loc;limit= save_limit;
+}
+}
+
+/*:200*/
+#line 3716 "cweave.w"
+;
+if(an_output)out_str(" }");
+out_str("\\X");
+}
+
+/*:199*/
+#line 3569 "cweave.w"
+;break;
+case math_rel:out_str("\\MRL{");
+
+case noop:case inserted:break;
+case cancel:case big_cancel:c= 0;b= a;
+while(1){
+a= get_output();
+if(a==inserted)continue;
+if((a<indent&&!(b==big_cancel&&a==' '))||a>big_force)break;
+if(a==indent)c++;else if(a==outdent)c--;
+else if(a==opt)a= get_output();
+}
+/*198:*/
+#line 3682 "cweave.w"
+
+for(;c>0;c--)out_str("\\1");
+
+for(;c<0;c++)out_str("\\2");
+
+
+/*:198*/
+#line 3581 "cweave.w"
+;
+goto reswitch;
+case indent:case outdent:case opt:case backup:case break_space:
+case force:case big_force:case preproc_line:/*196:*/
+#line 3628 "cweave.w"
+
+if(a<break_space||a==preproc_line){
+if(cur_mode==outer){
+out('\\');out(a-cancel+'0');
+
+
+
+
+
+if(a==opt){
+b= get_output();
+#line 939 "cweave.ch"
+if(b!='0'||force_lines==0)out(b);
+#line 3640 "cweave.w"
+else out_str("{-1}");
+}
+}else if(a==opt)b= get_output();
+}
+else/*197:*/
+#line 3652 "cweave.w"
+{
+b= a;save_mode= cur_mode;c= 0;
+while(1){
+a= get_output();
+if(a==inserted)continue;
+if(a==cancel||a==big_cancel){
+/*198:*/
+#line 3682 "cweave.w"
+
+for(;c>0;c--)out_str("\\1");
+
+for(;c<0;c++)out_str("\\2");
+
+
+/*:198*/
+#line 3658 "cweave.w"
+;
+goto reswitch;
+}
+if((a!=' '&&a<indent)||a==backup||a>big_force){
+if(save_mode==outer){
+if(out_ptr>out_buf+3&&strncmp(out_ptr-3,"\\Y\\B",4)==0)
+goto reswitch;
+/*198:*/
+#line 3682 "cweave.w"
+
+for(;c>0;c--)out_str("\\1");
+
+for(;c<0;c++)out_str("\\2");
+
+
+/*:198*/
+#line 3665 "cweave.w"
+;
+out('\\');out(b-cancel+'0');
+
+
+
+if(a!=end_translation)finish_line();
+}
+else if(a!=end_translation&&cur_mode==inner)out(' ');
+goto reswitch;
+}
+if(a==indent)c++;
+else if(a==outdent)c--;
+else if(a==opt)a= get_output();
+else if(a>b)b= a;
+}
+}
+
+/*:197*/
+#line 3644 "cweave.w"
+
+
+/*:196*/
+#line 3585 "cweave.w"
+;break;
+case quoted_char:out(*(cur_tok++));break;
+default:out(a);
+}
+}
+}
+
+/*:194*//*205:*/
+#line 3807 "cweave.w"
+
+void
+phase_two(){
+reset_input();if(show_progress)printf("\nWriting the output file...");
+
+section_count= 0;format_visible= 1;copy_limbo();
+finish_line();flush_buffer(out_buf,0,0);
+while(!input_has_ended)/*207:*/
+#line 3840 "cweave.w"
+{
+section_count++;
+/*208:*/
+#line 3858 "cweave.w"
+
+if(*(loc-1)!='*')out_str("\\M");
+
+else{
+while(*loc==' ')loc++;
+if(*loc=='*'){
+sec_depth= -1;
+loc++;
+}
+else{
+for(sec_depth= 0;xisdigit(*loc);loc++)
+sec_depth= sec_depth*10+(*loc)-'0';
+}
+while(*loc==' ')loc++;
+group_found= 1;
+out_str("\\N");
+
+{char s[32];sprintf(s,"{%d}",sec_depth+1);out_str(s);}
+if(show_progress)
+printf("*%d",section_count);update_terminal;
+}
+out_str("{");out_section(section_count);out_str("}");
+
+/*:208*/
+#line 3842 "cweave.w"
+;
+save_position;
+/*209:*/
+#line 3884 "cweave.w"
+do{
+next_control= copy_TeX();
+switch(next_control){
+case'|':init_stack;output_C();break;
+case'@':out('@');break;
+case TeX_string:case noop:
+case xref_roman:case xref_wildcard:case xref_typewriter:
+case section_name:loc-= 2;next_control= get_next();
+if(next_control==TeX_string)
+err_print("! TeX string should be in C text only");break;
+
+#line 972 "cweave.ch"
+case thin_space:case math_break:case ord:
+case line_break:case big_line_break:case no_line_break:case join:
+case pseudo_semi:case macro_arg_open:case macro_arg_close:
+case pseudo_lbrace:case pseudo_rbrace:
+case output_defs_code:
+err_print("! You can't do that in TeX text");break;
+
+#line 3901 "cweave.w"
+}
+}while(next_control<format_code);
+
+/*:209*/
+#line 3844 "cweave.w"
+;
+/*210:*/
+#line 3907 "cweave.w"
+
+space_checked= 0;
+while(next_control<=definition){
+init_stack;
+if(next_control==definition)/*213:*/
+#line 3965 "cweave.w"
+{
+if(save_line!=out_line||save_place!=out_ptr||space_checked)app(backup);
+if(!space_checked){emit_space_if_needed;save_position;}
+app_str("\\D");
+
+if((next_control= get_next())!=identifier)
+err_print("! Improper macro definition");
+
+else{
+app('$');app_cur_id(0);
+#line 992 "cweave.ch"
+if(*loc=='('){
+if(func_index)
+(name_dir+*(tok_ptr-1)%10240)->func_flag= 1;
+reswitch:switch(next_control= get_next()){
+case'(':case',':app(next_control);goto reswitch;
+case identifier:app_cur_id(0);goto reswitch;
+case')':app(next_control);next_control= get_next();break;
+default:err_print("! Improper macro definition");break;
+}
+}
+#line 3982 "cweave.w"
+else next_control= get_next();
+app_str("$ ");app(break_space);
+app_scrap(dead,no_math);
+}
+}
+
+/*:213*/
+#line 3911 "cweave.w"
+
+else/*214:*/
+#line 3988 "cweave.w"
+{
+doing_format= 1;
+if(*(loc-1)=='s'||*(loc-1)=='S')format_visible= 0;
+if(!space_checked){emit_space_if_needed;save_position;}
+app_str("\\F");
+
+next_control= get_next();
+if(next_control==identifier){
+app(id_flag+(int)(id_lookup(id_first,id_loc,normal)-name_dir));
+app(' ');
+app(break_space);
+next_control= get_next();
+if(next_control==identifier){
+app(id_flag+(int)(id_lookup(id_first,id_loc,normal)-name_dir));
+app_scrap(exp,maybe_math);app_scrap(semi,maybe_math);
+next_control= get_next();
+}
+}
+if(scrap_ptr!=scrap_info+2)err_print("! Improper format definition");
+
+}
+
+/*:214*/
+#line 3912 "cweave.w"
+;
+outer_parse();finish_C(format_visible);format_visible= 1;
+doing_format= 0;
+}
+
+/*:210*/
+#line 3845 "cweave.w"
+;
+/*216:*/
+#line 4017 "cweave.w"
+
+this_section= name_dir;
+if(next_control<=section_name){
+emit_space_if_needed;init_stack;
+if(next_control==begin_C)next_control= get_next();
+else{
+this_section= cur_section;
+/*217:*/
+#line 4037 "cweave.w"
+
+do next_control= get_next();
+while(next_control=='+');
+if(next_control!='='&&next_control!=eq_eq)
+err_print("! You need an = sign after the section name");
+
+else next_control= get_next();
+if(out_ptr>out_buf+1&&*out_ptr=='Y'&&*(out_ptr-1)=='\\')app(backup);
+
+
+app(section_flag+(int)(this_section-name_dir));
+cur_xref= (xref_pointer)this_section->xref;
+if(cur_xref->num==file_flag)cur_xref= cur_xref->xlink;
+app_str("${}");
+if(cur_xref->num!=section_count+def_flag){
+app_str("\\mathrel+");
+this_section= name_dir;
+}
+app_str("\\E");
+
+app_str("{}$");
+app(force);app_scrap(dead,no_math);
+
+
+/*:217*/
+#line 4025 "cweave.w"
+;
+}
+while(next_control<=section_name){
+outer_parse();
+/*218:*/
+#line 4061 "cweave.w"
+
+if(next_control<section_name){
+err_print("! You can't do that in C text");
+
+next_control= get_next();
+}
+else if(next_control==section_name){
+app(section_flag+(int)(cur_section-name_dir));
+app_scrap(section_scrap,maybe_math);
+next_control= get_next();
+}
+
+/*:218*/
+#line 4029 "cweave.w"
+;
+}
+finish_C(1);
+}
+
+/*:216*/
+#line 3846 "cweave.w"
+;
+/*219:*/
+#line 4076 "cweave.w"
+
+if(this_section>name_dir){
+cur_xref= (xref_pointer)this_section->xref;
+if(cur_xref->num==file_flag){an_output= 1;cur_xref= cur_xref->xlink;}
+else an_output= 0;
+if(cur_xref->num>def_flag)
+cur_xref= cur_xref->xlink;
+footnote(def_flag);footnote(cite_flag);footnote(0);
+}
+
+/*:219*/
+#line 3847 "cweave.w"
+;
+/*223:*/
+#line 4134 "cweave.w"
+
+out_str("\\fi");finish_line();
+
+flush_buffer(out_buf,0,0);
+
+/*:223*/
+#line 3848 "cweave.w"
+;
+}
+
+/*:207*/
+#line 3814 "cweave.w"
+;
+}
+
+/*:205*//*212:*/
+#line 3930 "cweave.w"
+
+void
+finish_C(visible)
+boolean visible;
+{
+text_pointer p;
+if(visible){
+out_str("\\B");app_tok(force);app_scrap(insert,no_math);
+p= translate();
+
+app(tok_flag+(int)(p-tok_start));make_output();
+if(out_ptr>out_buf+1)
+if(*(out_ptr-1)=='\\')
+
+
+
+if(*out_ptr=='6')out_ptr-= 2;
+else if(*out_ptr=='7')*out_ptr= 'Y';
+out_str("\\par");finish_line();
+}
+if(text_ptr>max_text_ptr)max_text_ptr= text_ptr;
+if(tok_ptr>max_tok_ptr)max_tok_ptr= tok_ptr;
+if(scrap_ptr>max_scr_ptr)max_scr_ptr= scrap_ptr;
+tok_ptr= tok_mem+1;text_ptr= tok_start+1;scrap_ptr= scrap_info;
+
+}
+
+/*:212*//*221:*/
+#line 4101 "cweave.w"
+
+void
+footnote(flag)
+sixteen_bits flag;
+{
+xref_pointer q;
+if(cur_xref->num<=flag)return;
+finish_line();out('\\');
+
+
+
+out(flag==0?'U':flag==cite_flag?'Q':'A');
+/*222:*/
+#line 4121 "cweave.w"
+
+q= cur_xref;if(q->xlink->num>flag)out('s');
+while(1){
+out_section(cur_xref->num-flag);
+cur_xref= cur_xref->xlink;
+if(cur_xref->num<=flag)break;
+if(cur_xref->xlink->num>flag)out_str(", ");
+else{out_str("\\ET");
+
+if(cur_xref!=q->xlink)out('s');
+}
+}
+
+/*:222*/
+#line 4113 "cweave.w"
+;
+out('.');
+}
+
+/*:221*//*225:*/
+#line 4150 "cweave.w"
+
+void
+phase_three(){
+if(no_xref){
+finish_line();
+out_str("\\end");
+
+finish_line();
+}
+else{
+phase= 3;if(show_progress)printf("\nWriting the index...");
+
+finish_line();
+if((idx_file= fopen(idx_file_name,"w"))==NULL)
+fatal("! Cannot open index file ",idx_file_name);
+
+if(change_exists){
+/*227:*/
+#line 4201 "cweave.w"
+{
+
+k_section= 0;
+while(!changed_section[++k_section]);
+out_str("\\ch ");
+
+out_section(k_section);
+while(k_section<section_count){
+while(!changed_section[++k_section]);
+out_str(", ");out_section(k_section);
+}
+out('.');
+}
+
+/*:227*/
+#line 4167 "cweave.w"
+;finish_line();finish_line();
+}
+out_str("\\inx");finish_line();
+
+active_file= idx_file;
+/*229:*/
+#line 4232 "cweave.w"
+{
+int c;
+for(c= 0;c<=255;c++)bucket[c]= NULL;
+for(h= hash;h<=hash_end;h++){
+next_name= *h;
+while(next_name){
+cur_name= next_name;next_name= cur_name->link;
+if(cur_name->xref!=(char*)xmem){
+c= (eight_bits)((cur_name->byte_start)[0]);
+if(xisupper(c))c= tolower(c);
+blink[cur_name-name_dir]= bucket[c];bucket[c]= cur_name;
+}
+}
+}
+}
+
+/*:229*/
+#line 4172 "cweave.w"
+;
+/*238:*/
+#line 4348 "cweave.w"
+
+sort_ptr= scrap_info;unbucket(1);
+while(sort_ptr>scrap_info){
+cur_depth= sort_ptr->depth;
+if(blink[sort_ptr->head-name_dir]==0||cur_depth==infinity)
+/*240:*/
+#line 4373 "cweave.w"
+{
+cur_name= sort_ptr->head;
+do{
+out_str("\\I");
+
+/*241:*/
+#line 4385 "cweave.w"
+
+#line 1036 "cweave.ch"
+switch(cur_name->ilk){
+case normal:
+if(is_tiny(cur_name)&&!cur_name->func_flag)
+out_str("\\|");
+else{char*j;
+for(j= cur_name->byte_start;j<(cur_name+1)->byte_start;j++)
+if(xislower(*j))goto lowcase;
+out_str("\\.");break;
+lowcase:out_str("\\\\");
+}
+break;
+
+
+
+case roman:break;
+case wildcard:out_str("\\9");break;
+
+case typewriter:out_str("\\.");break;
+
+case custom:case quoted:{char*j;out_str("$\\");
+for(j= cur_name->byte_start;j<(cur_name+1)->byte_start;j++)
+out(isxalpha(*j)?'x':*j);
+out('$');
+goto name_done;
+}
+default:out_str("\\&");
+
+}
+out_name(cur_name);
+name_done:
+if(cur_name->func_flag)
+out_str("(\\,)");
+#line 4414 "cweave.w"
+
+/*:241*/
+#line 4378 "cweave.w"
+;
+/*242:*/
+#line 4418 "cweave.w"
+
+/*244:*/
+#line 4436 "cweave.w"
+
+this_xref= (xref_pointer)cur_name->xref;cur_xref= xmem;
+do{
+next_xref= this_xref->xlink;this_xref->xlink= cur_xref;
+cur_xref= this_xref;this_xref= next_xref;
+}while(this_xref!=xmem);
+
+/*:244*/
+#line 4419 "cweave.w"
+;
+do{
+out_str(", ");cur_val= cur_xref->num;
+if(cur_val<def_flag)out_section(cur_val);
+else{out_str("\\[");out_section(cur_val-def_flag);out(']');}
+
+cur_xref= cur_xref->xlink;
+}while(cur_xref!=xmem);
+out('.');finish_line();
+
+/*:242*/
+#line 4379 "cweave.w"
+;
+cur_name= blink[cur_name-name_dir];
+}while(cur_name);
+--sort_ptr;
+}
+
+/*:240*/
+#line 4353 "cweave.w"
+
+else/*239:*/
+#line 4357 "cweave.w"
+{
+eight_bits c;
+next_name= sort_ptr->head;
+do{
+cur_name= next_name;next_name= blink[cur_name-name_dir];
+cur_byte= cur_name->byte_start+cur_depth;
+if(cur_byte==(cur_name+1)->byte_start)c= 0;
+else{
+c= (eight_bits)*cur_byte;
+if(xisupper(c))c= tolower(c);
+}
+blink[cur_name-name_dir]= bucket[c];bucket[c]= cur_name;
+}while(next_name);
+--sort_ptr;unbucket(cur_depth+1);
+}
+
+/*:239*/
+#line 4354 "cweave.w"
+;
+}
+
+/*:238*/
+#line 4173 "cweave.w"
+;
+finish_line();fclose(active_file);
+active_file= tex_file;
+out_str("\\fin");finish_line();
+
+if((scn_file= fopen(scn_file_name,"w"))==NULL)
+fatal("! Cannot open section file ",scn_file_name);
+
+active_file= scn_file;
+/*247:*/
+#line 4467 "cweave.w"
+section_print(root)
+
+/*:247*/
+#line 4182 "cweave.w"
+;
+finish_line();fclose(active_file);
+active_file= tex_file;
+if(group_found)out_str("\\con");else out_str("\\end");
+
+
+finish_line();
+fclose(active_file);
+}
+if(show_happiness)printf("\nDone.");
+check_complete();
+}
+
+/*:225*//*237:*/
+#line 4330 "cweave.w"
+
+void
+unbucket(d)
+eight_bits d;
+{
+int c;
+
+for(c= 100+128;c>=0;c--)if(bucket[collate[c]]){
+
+if(sort_ptr>=scrap_info_end)overflow("sorting");
+sort_ptr++;
+if(sort_ptr>max_sort_ptr)max_sort_ptr= sort_ptr;
+if(c==0)sort_ptr->depth= infinity;
+else sort_ptr->depth= d;
+sort_ptr->head= bucket[collate[c]];bucket[collate[c]]= NULL;
+}
+}
+
+/*:237*//*246:*/
+#line 4450 "cweave.w"
+
+void
+section_print(p)
+name_pointer p;
+{
+if(p){
+section_print(p->llink);out_str("\\I");
+
+tok_ptr= tok_mem+1;text_ptr= tok_start+1;scrap_ptr= scrap_info;init_stack;
+app(p-name_dir+section_flag);make_output();
+footnote(cite_flag);
+footnote(0);
+finish_line();
+section_print(p->rlink);
+}
+}
+
+/*:246*//*248:*/
+#line 4472 "cweave.w"
+
+void
+print_stats(){
+printf("\nMemory usage statistics:\n");
+
+printf("%ld names (out of %ld)\n",
+(long)(name_ptr-name_dir),(long)max_names);
+printf("%ld cross-references (out of %ld)\n",
+(long)(xref_ptr-xmem),(long)max_refs);
+printf("%ld bytes (out of %ld)\n",
+(long)(byte_ptr-byte_mem),(long)max_bytes);
+printf("Parsing:\n");
+printf("%ld scraps (out of %ld)\n",
+(long)(max_scr_ptr-scrap_info),(long)max_scraps);
+printf("%ld texts (out of %ld)\n",
+(long)(max_text_ptr-tok_start),(long)max_texts);
+printf("%ld tokens (out of %ld)\n",
+(long)(max_tok_ptr-tok_mem),(long)max_toks);
+printf("%ld levels (out of %ld)\n",
+(long)(max_stack_ptr-stack),(long)stack_size);
+printf("Sorting:\n");
+printf("%ld levels (out of %ld)\n",
+(long)(max_sort_ptr-scrap_info),(long)max_scraps);
+}
+
+#line 1075 "cweave.ch"
+/*:248*/
diff --git a/web/c_cpp/c2cweb/cweb/cweave.ch b/web/c_cpp/c2cweb/cweb/cweave.ch
new file mode 100644
index 0000000000..035de5a5e3
--- /dev/null
+++ b/web/c_cpp/c2cweb/cweb/cweave.ch
@@ -0,0 +1,1095 @@
+This file is part of the c2cweb package Version 1.5
+
+This is a change file for CWEB's CWEAVE (Ver. 3.4g June 1996)
+
+modified by Werner Lemberg (a7971428@@unet.univie.ac.at) 10-Nov-1996
+
+===============================================================================
+
+An exclamation mark (!) removes a bug in the original CWEAVE which caused
+unbalanced braces sometimes.
+
+One star (*) marks changes of the productions if switch a is set --
+please look at an output to see what. Additionally cwebmaca.tex will be used
+by TeX instead of cwebmac.tex .
+
+Two stars (**) mark changes to the index routines: function definitions will
+now have () after the identifier if the i switch is on (this will work properly
+only if you don't have function names identical to names of variables,
+structures etc.).
+
+Three stars (***) change the debugging output slightly.
+
+A (+) enables the dollar sign `$' in identifiers; some compilers allow it,
+and it doesn't harm in the output.
+
+Two plus (++) improve the processing of #define statements (weird things
+like '#define short int'). Two new control codes are introduced: @{ and @}
+(i.e. invisible braces). You will need this if you have unbalanced braces due
+to #ifdef ... #endif statements. The concatenation operator ## will be now
+recognized.
+
+Three plus (+++) implement exotic cases of C++ (look e.g. for "iostream.h").
+
+
+These changes are not perfect yet; if you don't like some things, remove the
+specified sections. (Or better, improve them and send the new change file(s)
+to me :-)
+
+
+@x in limbo
+\let\maybe=\iftrue
+@y
+\let\maybe=\iffalse
+@z
+
+@x section 1
+@d banner "This is CWEAVE (Version 3.4)\n"
+@y
+@d banner "This is CWEAVE (Version 3.4) modified by Werner Lemberg (V1.5)\n"
+@z
+
+@x section 4
+@d max_bytes 90000 /* the number of bytes in identifiers,
+ index entries, and section names */
+@d max_names 4000 /* number of identifiers, strings, section names;
+ must be less than 10240; used in |"common.w"| */
+@d max_sections 2000 /* greater than the total number of sections */
+@d hash_size 353 /* should be prime */
+@d buf_size 100 /* maximum length of input line, plus one */
+@d longest_name 1000 /* section names and strings shouldn't be longer than this */
+@d long_buf_size (buf_size+longest_name)
+@d line_length 80 /* lines of \TEX/ output have at most this many characters;
+ should be less than 256 */
+@d max_refs 20000 /* number of cross-references; must be less than 65536 */
+@d max_toks 20000 /* number of symbols in \CEE/ texts being parsed;
+ must be less than 65536 */
+@d max_texts 4000 /* number of phrases in \CEE/ texts being parsed;
+ must be less than 10240 */
+@d max_scraps 2000 /* number of tokens in \CEE/ texts being parsed */
+@d stack_size 400 /* number of simultaneous output levels */
+@y
+@d max_bytes 225000 /* the number of bytes in identifiers,
+ index entries, and section names */
+@d max_names 10000 /* number of identifiers, strings, section names;
+ must be less than 10240; used in |"common.w"| */
+@d max_sections 2000 /* greater than the total number of sections */
+@d hash_size 353 /* should be prime */
+@d buf_size 400 /* maximum length of input line, plus one */
+@d longest_name 1000 /* section names and strings shouldn't be longer than this */
+@d long_buf_size (buf_size+longest_name)
+@d line_length 100 /* lines of \TEX/ output have at most this many characters;
+ should be less than 256 */
+@d max_refs 20000 /* number of cross-references; must be less than 65536 */
+@d max_toks 65000 /* number of symbols in \CEE/ texts being parsed;
+ must be less than 65536 */
+@d max_texts 10200 /* number of phrases in \CEE/ texts being parsed;
+ must be less than 10240 */
+@d max_scraps 65000 /* number of tokens in \CEE/ texts being parsed */
+@d stack_size 10000 /* number of simultaneous output levels */
+@z
+
+**
+
+@x section 16
+@d ilk dummy.Ilk
+@y
+@d ilk dummy.dummy1.Ilk
+@d func_flag dummy.dummy1.Func_flag
+@z
+
+++
+
+@x section 30
+@d new_section 0231 /* control code for `\.{@@\ }' and `\.{@@*}' */
+@y
+@d new_section 0231 /* control code for `\.{@@\ }' and `\.{@@*}' */
+@d pseudo_lbrace 022 /* control code for `\.{@@\{}' */
+@d pseudo_rbrace 023 /* control code for `\.{@@\}}' */
+@z
+
+++
+
+@x section 32
+ccode['+']=no_line_break; ccode[';']=pseudo_semi;
+ccode['[']=macro_arg_open; ccode[']']=macro_arg_close;
+@y
+ccode['+']=no_line_break; ccode[';']=pseudo_semi;
+ccode['{']=pseudo_lbrace; ccode['}']=pseudo_rbrace;
+ccode['[']=macro_arg_open; ccode[']']=macro_arg_close;
+@z
+
++
+
+@x section 39
+@d isxalpha(c) ((c)=='_') /* non-alpha character allowed in identifier */
+@y
+@d isxalpha(c) ((c)=='_' || (c)=='$')
+ /* non-alpha characters allowed in identifier */
+@z
+
+++
+
+@x section 40
+eight_bits
+get_next() /* produces the next input token */
+{@+eight_bits c; /* the current character */
+ while (1) {
+ @<Check if we're at the end of a preprocessor command@>;
+ if (loc>limit && get_line()==0) return(new_section);
+ c=*(loc++);
+ if (xisdigit(c) || c=='\\' || c=='.') @<Get a constant@>@;
+ else if (c=='\'' || c=='"' || (c=='L'&&(*loc=='\'' || *loc=='"'))@|
+ || (c=='<' && sharp_include_line==1))
+ @<Get a string@>@;
+ else if (xisalpha(c) || isxalpha(c) || ishigh(c))
+ @<Get an identifier@>@;
+ else if (c=='@@') @<Get control code and possible section name@>@;
+ else if (xisspace(c)) continue; /* ignore spaces and tabs */
+ if (c=='#' && loc==buffer+1) @<Raise preprocessor flag@>;
+ mistake: @<Compress two-symbol operator@>@;
+ return(c);
+ }
+}
+@y
+eight_bits
+get_next() /* produces the next input token */
+{@+eight_bits c; /* the current character */
+ int blank_count=0; /* number of leading blanks */
+
+ if (loc<limit && preprocessing && (define_pos==2 || define_pos==4) &&
+ xisspace(*loc)) {
+ define_pos=5;
+ return(preproc_space);
+ }
+
+ while (1) {
+ @<Check if we're at the end of a preprocessor command@>;
+ if (loc>limit && get_line()==0) return(new_section);
+
+ if(loc==buffer) {
+ blank_count=0;
+ while((*loc==' ' || *loc=='\t') && loc<limit) {
+ blank_count++; loc++;
+ }
+ }
+
+ c=*(loc++);
+ if (xisdigit(c) || c=='\\' || c=='.') @<Get a constant@>@;
+ else if (c=='\'' || c=='"' || (c=='L'&&(*loc=='\'' || *loc=='"'))@|
+ || (c=='<' && sharp_include_line==1))
+ @<Get a string@>@;
+ else if (xisalpha(c) || isxalpha(c) || ishigh(c))
+ @<Get an identifier@>@;
+ else if (c=='@@') @<Get control code and possible section name@>@;
+ else if (xisspace(c)) continue; /* ignore spaces and tabs */
+ if (c=='#' && loc==buffer+1+blank_count && !preprocessing)
+ @<Raise preprocessor flag@>;
+ mistake: @<Compress two-symbol operator@>@;
+ if(preprocessing) {
+ if (c=='(' && define_pos==2 && !xisspace(*(loc-2)))
+ define_pos=3;
+ else if (c==')' && define_pos==3)
+ define_pos=4;
+ }
+ return(c);
+ }
+}
+@z
+
+++
+
+@x section 41
+@d left_preproc ord /* begins a preprocessor command */
+@d right_preproc 0217 /* ends a preprocessor command */
+
+@<Glob...@>=
+boolean preprocessing=0; /* are we scanning a preprocessor command? */
+@y
+@d left_preproc ord /* begins a preprocessor command */
+@d right_preproc 0217 /* ends a preprocessor command */
+@d preproc_space '\b' /* emitted before the macro sustitution */
+@d numb_numb '\f' /* `\.{\#\#}'\,; the concatenation operator */
+
+@<Glob...@>=
+boolean preprocessing=0; /* are we scanning a preprocessor command? */
+int define_pos=0;
+ /* at which position we are while scanning a macro definition */
+@z
+
+++
+
+@x section 45
+ if (loc>=limit && preprocessing) {
+ preprocessing=sharp_include_line=0;
+ return(right_preproc);
+ }
+@y
+ if (loc>=limit && preprocessing) {
+ preprocessing=sharp_include_line=define_pos=0;
+ return(right_preproc);
+ }
+@z
+
+++
+
+@x section 46
+ case '!': if (*loc=='=') compress(not_eq); break;
+@y
+ case '!': if (*loc=='=') compress(not_eq); break;
+ case '#': if (*loc=='#') compress(numb_numb); break;
+@z
+
+++
+
+@x section 47
+ id_first=--loc;
+ while (isalpha(*++loc) || isdigit(*loc) || isxalpha(*loc) || ishigh(*loc));
+ id_loc=loc; return(identifier);
+@y
+ id_first=--loc;
+
+ if (preprocessing) {
+ if (define_pos==1)
+ define_pos=2;
+ else if (strncmp(loc, "define", 6)==0 && xisspace(*(loc+6)))
+ define_pos=1;
+ }
+
+ while (isalpha(*++loc) || isdigit(*loc) || isxalpha(*loc) || ishigh(*loc));
+ id_loc=loc; return(identifier);
+@z
+
+!
+
+@x section 77
+int out_line; /* number of next line to be output */
+@y
+int out_line; /* number of next line to be output */
+
+boolean in_math = 0;
+boolean escape = 0;
+int math_brace_count = 0;
+@z
+
+*
+
+@x section 80
+out_ptr=out_buf+1; out_line=1; active_file=tex_file;
+*out_ptr='c'; tex_printf("\\input cwebma");
+@y
+out_ptr=out_buf+1; out_line=1; active_file=tex_file;
+if(alternative) {
+ *out_ptr='a';
+ tex_printf("\\input cwebmac");
+} else {
+ *out_ptr='c';
+ tex_printf("\\input cwebma");
+}
+@z
+
+!
+
+@x section 81
+@d out(c) {if (out_ptr>=out_buf_end) break_out(); *(++out_ptr)=c;}
+
+@c
+@y
+@c
+void
+out(c)
+char c;
+{
+ if (out_ptr >= out_buf_end)
+ break_out();
+
+ if(!escape) {
+ if(in_math) {
+ if(c == '{')
+ math_brace_count++;
+ else if(c == '}') {
+ math_brace_count--;
+ if(math_brace_count < 0) {
+ math_brace_count = 0;
+ return;
+ }
+ }
+ }
+ if(c == '$') {
+ while(math_brace_count > 0) {
+ *(++out_ptr) = '}';
+ math_brace_count--;
+ }
+ in_math = 1 - in_math;
+ }
+ }
+
+ if(c == '\\' && !escape)
+ escape = 1;
+ else
+ escape = 0;
+
+ *(++out_ptr) = c;
+ return;
+}
+@z
+
+*
+
+@x section 97
+@d tag 29 /* denotes a statement label */
+@y
+@d tag 29
+ /* denotes a statement label (if |alternative| is set, only a case label) */
+@z
+
+*, ++
+
+@x section 97
+@d end_arg 59 /* \.{@@]} */
+@y
+@d end_arg 59 /* \.{@@]} */
+@d label 60 /* denotes a label; used if |alternative| is set */
+@d do_head 61 /* used if |alternative| is set */
+@d pp_space 62 /* denotes the start point of a macro replacement text */
+@z
+
+*, ++
+
+@x section 98
+ strcpy(cat_name[end_arg],@q[@>"@@]");
+@y
+ strcpy(cat_name[end_arg],@q[@>"@@]");
+ strcpy(cat_name[label],"label"); /* used if |alternative| is set */
+ strcpy(cat_name[do_head], "do_head"); /* used if |alternative| is set */
+ strcpy(cat_name[pp_space], "#_");
+@z
+
+++ section 101
+
+@x
+\.:&|colon|: \.:&maybe\cr
+\.\# (within line)&|unorbinop|: \.{\\\#}&yes\cr
+@y
+\.:&|colon|: \.:&maybe\cr
+\.{\#\#}&|binop|: \.{\\NN}&yes\cr
+\.\# (within line)&|unorbinop|: \.{\\\#}&yes\cr
+@z
+
+*
+
+@x section 101
+@i prod.w
+@y
+@i prod-alt.w
+@z
+
+*
+
+@x section 110
+ case raw_int: @<Cases for |raw_int|@>; @+break;
+@y
+ case raw_int: @<Cases for |raw_int|@>; @+break;
+ case label: @<Cases for |label|@>; @+break;
+ case do_head: @<Cases for |do_head|@>; @+break;
+@z
+
+++
+
+@x section 112
+void
+make_reserved(p) /* make the first identifier in |p->trans| like |int| */
+scrap_pointer p;
+{
+ sixteen_bits tok_value; /* the name of this identifier, plus its flag*/
+ token_pointer tok_loc; /* pointer to |tok_value| */
+ if ((tok_loc=find_first_ident(p->trans))==no_ident_found)
+ return; /* this should not happen */
+ tok_value=*tok_loc;
+ for (;p<=scrap_ptr; p==lo_ptr? p=hi_ptr: p++) {
+ if (p->cat==exp) {
+ if (**(p->trans)==tok_value) {
+ p->cat=raw_int;
+ **(p->trans)=tok_value%id_flag+res_flag;
+ }
+ }
+ }
+ (name_dir+(sixteen_bits)(tok_value%id_flag))->ilk=raw_int;
+ *tok_loc=tok_value%id_flag+res_flag;
+}
+@y
+void
+make_reserved(p, cat) /* make the first identifier in |p->trans| like |cat| */
+scrap_pointer p;
+eight_bits cat;
+{
+ sixteen_bits tok_value; /* the name of this identifier, plus its flag*/
+ token_pointer tok_loc; /* pointer to |tok_value| */
+ if ((tok_loc=find_first_ident(p->trans))==no_ident_found)
+ return; /* this should not happen */
+ tok_value=*tok_loc;
+ for (;p<=scrap_ptr; p==lo_ptr? p=hi_ptr: p++) {
+ if (p->cat==exp || p->cat==int_like || p->cat==const_like) {
+ if (**(p->trans)==tok_value) {
+ p->cat=cat;
+ **(p->trans)=tok_value%id_flag+res_flag;
+ }
+ }
+ }
+ (name_dir+(sixteen_bits)(tok_value%id_flag))->ilk=cat;
+ *tok_loc=tok_value%id_flag+res_flag;
+}
+@z
+
+*
+
+@x section 117
+ make_underlined (pp); squash(pp,2,tag,0,7);
+@y
+ make_underlined (pp);
+ if(alternative)
+ squash(pp,2,label,0,7);
+ else
+ squash(pp,2,tag,0,7);
+@z
+
++++
+
+@x section 125
+ else squash(pp,2,int_like,-2,32);
+}
+@y
+ else squash(pp,2,int_like,-2,32);
+}
+else if (cat1==binop && cat2==exp) squash(pp,3,int_like,-2,117);
+@z
+
+++
+
+@x section 128
+if (cat1==decl_head)
+ if ((cat2==exp&&cat3!=lpar&&cat3!=exp)||cat2==int_like) {
+ make_underlined(pp+2); make_reserved(pp+2);
+ big_app2(pp+1); reduce(pp+1,2,decl_head,0,42);
+ }
+ else if (cat2==semi) {
+ big_app1(pp); big_app(' '); big_app2(pp+1); reduce(pp,3,decl,-1,43);
+ }
+@y
+if (cat1==decl_head) {
+ if ((cat2==exp&&cat3!=lpar&&cat3!=exp)||cat2==int_like) {
+ make_underlined(pp+2); make_reserved(pp+2, raw_int);
+ big_app2(pp+1); reduce(pp+1,2,decl_head,0,42);
+ }
+ else if (cat2==semi) {
+ big_app1(pp); big_app(' '); big_app2(pp+1); reduce(pp,3,decl,-1,43);
+ }
+}
+else if (cat1==exp && !preprocessing && cat2!=lpar) {
+ make_reserved(pp+1, raw_int);
+ squash(pp+1,1,raw_int,-2,116);
+}
+@z
+
+*
+
+@x section 129
+if (cat1==lbrace) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,struct_head,0,44);
+}
+else if (cat1==exp||cat1==int_like) {
+ if (cat2==lbrace || cat2==semi) {
+ make_underlined(pp+1); make_reserved(pp+1);
+ big_app1(pp); big_app(' '); big_app1(pp+1);
+ if (cat2==semi) reduce(pp,2,decl_head,0,45);
+ else {
+ big_app(' '); big_app1(pp+2);reduce(pp,3,struct_head,0,46);
+ }
+ }
+ else if (cat2==colon) squash(pp+2,1,base,-1,47);
+ else if (cat2!=base) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,int_like,-2,48);
+ }
+}
+@y
+if (cat1==lbrace) {
+ if(alternative) {
+ big_app1(pp); big_app(indent); big_app(force); big_app(backup);
+ big_app1(pp+1); reduce(pp,2,struct_head,0,44);
+ } else {
+ big_app1(pp); big_app(' '); big_app1(pp+1);
+ reduce(pp,2,struct_head,0,44);
+ }
+}
+else if (cat1==exp||cat1==int_like) {
+ if (cat2==lbrace || cat2==semi) {
+ make_underlined(pp+1); make_reserved(pp+1, raw_int);
+ big_app1(pp); big_app(' '); big_app1(pp+1);
+ if (cat2==semi) reduce(pp,2,decl_head,-1,45);
+ else {
+ if(alternative) {
+ big_app(indent); big_app(force); big_app(backup); big_app1(pp+2);
+ reduce(pp,3,struct_head,0,46);
+ } else {
+ big_app(' '); big_app1(pp+2); reduce(pp,3,struct_head,0,46);
+ }
+ }
+ }
+ else if (cat2==colon) squash(pp+2,1,base,-1,47);
+ else if (!(cat2==base || cat2==raw_int ||
+ cat2==int_like || cat2==const_like)) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,int_like,-2,48);
+ }
+}
+@z
+
+*
+
+@x section 130
+ big_app1(pp); big_app(indent); big_app(force); big_app1(pp+1);
+ big_app(outdent); big_app(force); big_app1(pp+2);
+ reduce(pp,3,int_like,-2,49);
+@y
+ if(alternative) {
+ big_app1(pp); big_app1(pp+1);
+ big_app(force); big_app(backup); big_app1(pp+2); big_app(' ');
+ big_app(outdent); reduce(pp,3,int_like,-2,49);
+ } else {
+ big_app1(pp); big_app(indent); big_app(force); big_app1(pp+1);
+ big_app(outdent); big_app(force); big_app1(pp+2);
+ reduce(pp,3,int_like,-2,49);
+ }
+@z
+
+*
+
+@x section 133
+ big_app(force); big_app1(pp); big_app(indent); big_app(force);
+ big_app1(pp+1); big_app(force); big_app(backup); big_app1(pp+2);
+ big_app(outdent); big_app(force); reduce(pp,3,stmt,-1,55);
+@y
+ if(alternative) {
+ big_app(indent); big_app(force); big_app(backup); big_app1(pp);
+ app(noop); big_app(cancel); big_app1(pp+1); big_app(force); big_app(backup);
+ big_app1(pp+2); big_app(outdent); big_app(force); reduce(pp,3,stmt,-2,55);
+ } else {
+ big_app(force); big_app1(pp); big_app(indent); big_app(force);
+ big_app1(pp+1); big_app(force); big_app(backup); big_app1(pp+2);
+ big_app(outdent); big_app(force); reduce(pp,3,stmt,-1,55);
+ }
+@z
+
+*
+
+@x section 136
+ big_app(force); big_app1(pp); big_app(indent); big_app(break_space);
+ big_app1(pp+1); big_app(outdent); big_app(force);
+ reduce(pp,2,stmt,-1,60);
+@y
+ if(alternative) {
+ big_app(force); big_app1(pp); big_app(indent); big_app(force);
+ big_app1(pp+1); big_app(outdent); big_app(force);
+ reduce(pp,2,stmt,-1,60);
+ } else {
+ big_app(force); big_app1(pp); big_app(indent); big_app(break_space);
+ big_app1(pp+1); big_app(outdent); big_app(force);
+ reduce(pp,2,stmt,-1,60);
+ }
+@z
+
+*
+
+@x section 137
+ big_app(force); big_app1(pp); big_app(break_space); app(noop);
+ big_app(cancel); big_app1(pp+1); big_app(force);
+ reduce(pp,2,stmt,-1,61);
+@y
+ if(alternative) {
+ big_app(force); big_app1(pp); big_app(break_space);
+ big_app1(pp+1); big_app(force);
+ reduce(pp,2,stmt,-1,61);
+ } else {
+ big_app(force); big_app1(pp); big_app(break_space); app(noop);
+ big_app(cancel); big_app1(pp+1); big_app(force);
+ reduce(pp,2,stmt,-1,61);
+ }
+@z
+
+*
+
+@x section 138
+ big_app(force); big_app1(pp); big_app(indent); big_app(break_space);
+ big_app1(pp+1); big_app(outdent); big_app(force); big_app1(pp+2);
+ if (cat3==if_like) {
+ big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,63);
+ }@+else reduce(pp,3,else_like,0,64);
+@y
+ if(alternative) {
+ big_app(force); big_app1(pp); big_app(indent); big_app(force);
+ big_app1(pp+1); big_app(outdent); big_app(force); big_app1(pp+2);
+ } else {
+ big_app(force); big_app1(pp); big_app(indent); big_app(break_space);
+ big_app1(pp+1); big_app(outdent); big_app(force); big_app1(pp+2);
+ }
+ if (cat3==if_like) {
+ big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,63);
+ }@+else reduce(pp,3,else_like,0,64);
+@z
+
+*
+
+@x section 139
+ big_app(force); big_app1(pp); big_app(break_space); app(noop);
+ big_app(cancel); big_app1(pp+1); big_app(force); big_app1(pp+2);
+ if (cat3==if_like) {
+ big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,66);
+ }@+else reduce(pp,3,else_like,0,67);
+@y
+ if(alternative) {
+ big_app(force); big_app1(pp); big_app(break_space);
+ big_app1(pp+1); big_app(force); big_app1(pp+2);
+ } else {
+ big_app(force); big_app1(pp); big_app(break_space); app(noop);
+ big_app(cancel); big_app1(pp+1); big_app(force); big_app1(pp+2);
+ }
+ if (cat3==if_like) {
+ big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,66);
+ }@+else reduce(pp,3,else_like,0,67);
+@z
+
+*
+
+@x section 140
+if (cat1==stmt && cat2==else_like && cat3==semi) {
+ big_app1(pp); big_app(break_space); app(noop); big_app(cancel);
+ big_app1(pp+1); big_app(cancel); app(noop); big_app(break_space);
+ big_app2(pp+2); reduce(pp,4,stmt,-1,69);
+}
+@y
+if(alternative) {
+ if (cat1==lbrace) squash(pp,1,do_head,0,114);
+ else if (cat1==stmt && cat2==else_like && cat3==semi) {
+ big_app(force); big_app1(pp); big_app(indent); big_app(force);
+ big_app1(pp+1); big_app(cancel); app(noop);
+ big_app(break_space); big_app2(pp+2); big_app(outdent); big_app(force);
+ reduce(pp,4,stmt,-1,69);
+ }
+} else {
+ if (cat1==stmt && cat2==else_like && cat3==semi) {
+ big_app1(pp); big_app(break_space); app(noop); big_app(cancel);
+ big_app1(pp+1); big_app(cancel); app(noop); big_app(break_space);
+ big_app2(pp+2); reduce(pp,4,stmt,-1,69);
+ }
+}
+@z
+
+*
+
+@x section 141
+if (cat1==semi) squash(pp,2,stmt,-1,70);
+else if (cat1==colon) squash(pp,2,tag,-1,71);
+@y
+if (cat1==semi) squash(pp,2,stmt,-3,70);
+else if (cat1==colon) squash(pp,2,tag,-2,71);
+@z
+
+*
+
+@x section 141
+ reduce(pp,3,tag,-1,73);
+@y
+ reduce(pp,3,tag,-2,73);
+@z
+
+*
+
+@x section 142
+if (cat1==tag) {
+ big_app1(pp); big_app(break_space); big_app1(pp+1); reduce(pp,2,tag,-1,74);
+}
+else if (cat1==stmt||cat1==decl||cat1==function) {
+ big_app(force); big_app(backup); big_app1(pp); big_app(break_space);
+ big_app1(pp+1); reduce(pp,2,cat1,-1,75);
+}
+@y
+if(alternative) {
+ if (cat1==tag) {
+ big_app1(pp); big_app(force); big_app1(pp+1); reduce(pp,2,tag,-1,74);
+ }
+ else if ((cat1==stmt||cat1==decl||cat1==function) &&
+ (cat2==rbrace||cat2==tag)) {
+ big_app(force); big_app1(pp); big_app(indent); big_app(force);
+ big_app1(pp+1); big_app(outdent); reduce(pp,2,cat1,-1,75);
+ }
+} else {
+ if (cat1==tag) {
+ big_app1(pp); big_app(break_space); big_app1(pp+1); reduce(pp,2,tag,-1,74);
+ }
+ else if (cat1==stmt||cat1==decl||cat1==function) {
+ big_app(force); big_app(backup); big_app1(pp); big_app(break_space);
+ big_app1(pp+1); reduce(pp,2,cat1,-1,75);
+ }
+}
+@z
+
+++
+
+@x section 145
+} else if (cat1==exp || cat1==function) {
+ if (cat2==rproc) {
+ app(inserted); big_app1(pp); big_app(' '); big_app2(pp+1);
+ reduce(pp,3,insert,-1,80);
+ }
+ else if (cat2==exp && cat3==rproc && cat1==exp) {
+ app(inserted); big_app1(pp); big_app(' '); big_app1(pp+1); app_str(" \\5");
+@.\\5@>
+ big_app2(pp+2); reduce(pp,4,insert,-1,80);
+ }
+}
+@y
+} else if ((cat1==exp || cat1==function || cat1==int_like) && cat2==rproc) {
+ app(inserted); big_app1(pp); big_app(' '); big_app2(pp+1);
+ reduce(pp,3,insert,-1,80);
+} else if ((cat1==exp || cat1==int_like || cat1==const_like) &&
+ cat2==pp_space) {
+ if(cat3==int_like || cat3==const_like || cat3==raw_int)
+ make_reserved(pp+1, (pp+3)->cat);
+ big_app1(pp); big_app(' '); big_app1(pp+1); app_str(" \\5");
+@.\\5@>
+ reduce(pp,3,lproc,-1,119);
+} else if (cat1==exp && cat2==exp && cat3==pp_space) {
+ big_app1(pp); big_app(' '); big_app2(pp+1); app_str(" \\5");
+ reduce(pp,4,lproc,-1,120);
+}
+@z
+
+*
+
+@x section 151
+if (cat1==colon) squash(pp,2,tag,-1,90);
+@y
+if (cat1==colon) squash(pp,2,tag,-2,90);
+@z
+
++++
+
+@x section 154
+if (cat1==binop || cat1==unop || cat1==unorbinop) {
+ if (cat2==binop) break;
+ big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
+ reduce(pp,2,exp,-2,97);
+}
+else if (cat1==new_like || cat1==sizeof_like) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,98);
+}
+@y
+if (cat1==binop || cat1==unop || cat1==unorbinop || cat1==raw_unorbin) {
+ if (cat2==binop) break;
+ big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
+ reduce(pp,2,exp,-2,97);
+}
+else if (cat1==new_like || cat1==sizeof_like) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,98);
+}
+else if (cat1==raw_int || cat1==int_like || cat1==const_like) {
+ big_app1(pp); big_app(' '); big_app1(pp+1);
+ reduce(pp,2,operator_like,-2,118);
+}
+@z
+
+*** This makes the tracing info looking smoother
+
+@x section 168
+ if (tracing==2) {
+ printf("\n%d:",n);
+@y
+ if (tracing==2) {
+ printf("\n%3d:",n);
+@z
+
+**, ++
+
+@x section 175
+@ @<Append the scr...@>=
+@<Make sure that there is room for the new scraps, tokens, and texts@>;
+@y
+@
+@d alternative flags['a'] /* if set, an alternative format is produced */
+@d func_index flags['i']
+ /* should functions in the index have |()| appended? */
+
+@<Append the scr...@>=
+@<Make sure that there is room for the new scraps, tokens, and texts@>;
+@z
+
+*, **
+
+@x section 175
+ case '(': case '[': app(next_control); app_scrap(lpar,maybe_math);@+break;
+ case ')': case ']': app(next_control); app_scrap(raw_rpar,maybe_math);@+break;
+ case '{': app_str("\\{"@q}@>); app_scrap(lbrace,yes_math);@+break;
+@.\\\{@>@q}@>
+ case '}': app_str(@q{@>"\\}"); app_scrap(rbrace,yes_math);@+break;
+@q{@>@.\\\}@>
+@y
+ case '(': if(func_index)
+ if(*(tok_ptr-1)>=id_flag && *(tok_ptr-1)<res_flag)
+ /* an identifier? */
+ (name_dir+ *(tok_ptr-1)%10240)->func_flag=1;
+ case '[': app(next_control); app_scrap(lpar,maybe_math);@+break;
+ case ')': case ']': app(next_control); app_scrap(raw_rpar,maybe_math);@+break;
+ case '{': if(alternative)
+ app_str("\\LBR");
+ else
+ app_str("\\{"@q}@>);
+ app_scrap(lbrace,yes_math);@+break;
+@.\\\{@>@q}@>
+ case '}': if(alternative)
+ app_str("\\RBR");
+ else
+ app_str(@q{@>"\\}");
+ app_scrap(rbrace,yes_math);@+break;
+@q{@>@.\\\}@>
+@z
+
+++
+
+@x section 175
+ case left_preproc: app(force); app(preproc_line);
+ app_str("\\#"); app_scrap(lproc,no_math);@+break;
+@.\\\#@>
+ case right_preproc: app(force); app_scrap(rproc,no_math);@+break;
+@y
+ case left_preproc: app(force); app(preproc_line);
+ app_str("\\#"); app_scrap(lproc,no_math);@+break;
+@.\\\#@>
+ case preproc_space: app(' '); app_scrap(pp_space, maybe_math);@+break;
+ case right_preproc: app(force); app_scrap(rproc,no_math);@+break;
+@z
+
+++
+
+@x section 175
+ case pseudo_semi: app_scrap(semi,maybe_math);@+break;
+@y
+ case pseudo_semi: app_scrap(semi,maybe_math);@+break;
+ case pseudo_lbrace: app_str("\\phantom{");
+ if(alternative)
+ app_str("\\LBR");
+ else
+ app_str("\\{"@q}@>);
+ app_str("}");
+ app_scrap(lbrace,yes_math);
+ break;
+ case pseudo_rbrace: app_str("\\phantom{");
+ if(alternative)
+ app_str("\\RBR");
+ else
+ app_str(@q{@>"\\}");
+ app_str("}");
+ app_scrap(rbrace,yes_math);
+ break;
+@z
+
+++
+
+@x section 177
+case minus_gt_ast: app_str("\\MGA");@+app_scrap(binop,yes_math);@+break;
+@.\\MGA@>
+@y
+case minus_gt_ast: app_str("\\MGA");@+app_scrap(binop,yes_math);@+break;
+@.\\MGA@>
+case numb_numb: app_str("\\NN");@+app_scrap(binop,yes_math);@+break;
+@.\\NN@>
+@z
+
+**
+
+@x section 178
+@.\\\%@>
+@.\\\$@>
+@.\\\^@>
+@y
+@.\\\%@>
+@.\\$@> @q CWEAVE quotes a dollar sign! @>
+@.\\\^@>
+@z
+
+!
+
+@x section 195
+ } else if (is_tiny(cur_name)) out('|')
+@y
+ } else if (is_tiny(cur_name)) out('|');
+@z
+
+!
+
+@x section 195
+else out('&') /* |a==res_word| */
+@y
+else out('&'); /* |a==res_word| */
+@z
+
+!
+
+@x section 196
+ if (b!='0' || force_lines==0) out(b)@;
+@y
+ if (b!='0' || force_lines==0) out(b);
+@z
+
+**
+
+@x section 200
+@.\\\%@>
+@.\\\$@>
+@.\\\^@>
+@y
+@.\\\%@>
+@.\\$@> @q CWEAVE quotes a dollar symbol! @>
+@.\\\^@>
+@z
+
+!
+
+@x section 200
+ else if (b!='|') out(b)
+@y
+ else if (b!='|') out(b);
+@z
+
+++
+
+@x section 209
+ case thin_space: case math_break: case ord:
+ case line_break: case big_line_break: case no_line_break: case join:
+ case pseudo_semi: case macro_arg_open: case macro_arg_close:
+ case output_defs_code:
+ err_print("! You can't do that in TeX text"); break;
+@.You can't do that...@>
+@y
+ case thin_space: case math_break: case ord:
+ case line_break: case big_line_break: case no_line_break: case join:
+ case pseudo_semi: case macro_arg_open: case macro_arg_close:
+ case pseudo_lbrace: case pseudo_rbrace:
+ case output_defs_code:
+ err_print("! You can't do that in TeX text"); break;
+@.You can't do that...@>
+@z
+
+**
+
+@x section 213
+ if (*loc=='(')
+ reswitch: switch (next_control=get_next()) {
+ case '(': case ',': app(next_control); goto reswitch;
+ case identifier: app_cur_id(0); goto reswitch;
+ case ')': app(next_control); next_control=get_next(); break;
+ default: err_print("! Improper macro definition"); break;
+ }
+@y
+ if (*loc=='(') {
+ if(func_index)
+ (name_dir+ *(tok_ptr-1)%10240)->func_flag=1;
+ reswitch: switch (next_control=get_next()) {
+ case '(': case ',': app(next_control); goto reswitch;
+ case identifier: app_cur_id(0); goto reswitch;
+ case ')': app(next_control); next_control=get_next(); break;
+ default: err_print("! Improper macro definition"); break;
+ }
+ }
+@z
+
+**
+
+@x section 241
+switch (cur_name->ilk) {
+ case normal: if (is_tiny(cur_name)) out_str("\\|");
+ else {char *j;
+ for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++)
+ if (xislower(*j)) goto lowcase;
+ out_str("\\."); break;
+lowcase: out_str("\\\\");
+ }
+ break;
+@.\\|@>
+@.\\.@>
+@.\\\\@>
+ case roman: break;
+ case wildcard: out_str("\\9"); break;
+@.\\9@>
+ case typewriter: out_str("\\."); break;
+@.\\.@>
+ case custom: case quoted: {char *j; out_str("$\\");
+ for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++)
+ out(isxalpha(*j)? 'x' : *j);
+ out('$');
+ goto name_done;
+ }
+ default: out_str("\\&");
+@.\\\&@>
+}
+out_name(cur_name);
+name_done:
+@y
+switch (cur_name->ilk) {
+ case normal:
+ if (is_tiny(cur_name) && !cur_name->func_flag)
+ out_str("\\|");
+ else {char *j;
+ for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++)
+ if (xislower(*j)) goto lowcase;
+ out_str("\\."); break;
+lowcase: out_str("\\\\");
+ }
+ break;
+@.\\|@>
+@.\\.@>
+@.\\\\@>
+ case roman: break;
+ case wildcard: out_str("\\9"); break;
+@.\\9@>
+ case typewriter: out_str("\\."); break;
+@.\\.@>
+ case custom: case quoted: {char *j; out_str("$\\");
+ for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++)
+ out(isxalpha(*j)? 'x' : *j);
+ out('$');
+ goto name_done;
+ }
+ default: out_str("\\&");
+@.\\\&@>
+}
+out_name(cur_name);
+name_done:
+ if(cur_name->func_flag)
+ out_str("(\\,)");
+@z
+
+*
+
+@x section 249
+@** Index.
+@y
+@ @<Cases for |label|@>=
+if (cat1==label) {
+ big_app1(pp); big_app(force); big_app1(pp+1); reduce(pp,2,label,-1,112);
+}
+else if (cat1==stmt||cat1==decl||cat1==function) {
+ big_app(cancel); app(noop);
+ big_app(outdent); big_app(outdent); big_app(force);
+ big_app1(pp); big_app(indent); big_app(indent); big_app(force);
+ big_app1(pp+1); reduce(pp,2,cat1,-1,113);
+}
+
+@ @<Cases for |do_head|@>=
+if (cat1==stmt && cat2==else_like && cat3==semi) {
+ big_app1(pp); big_app(break_space); big_app1(pp+1); big_app(cancel);
+ app(noop); big_app(break_space); big_app2(pp+2); reduce(pp,4,stmt,-1,115);
+}
+
+@** Index.
+@z
+
+--- end of cweave.ch ---
diff --git a/web/c_cpp/c2cweb/cweb/cweave.def b/web/c_cpp/c2cweb/cweb/cweave.def
new file mode 100644
index 0000000000..71fd302fae
--- /dev/null
+++ b/web/c_cpp/c2cweb/cweb/cweave.def
@@ -0,0 +1,3 @@
+NAME CWEAVE WINDOWCOMPAT
+DESCRIPTION 'CWEAVE 3.2'
+STACKSIZE 0x80000
diff --git a/web/c_cpp/c2cweb/cweb/cweave.w b/web/c_cpp/c2cweb/cweb/cweave.w
new file mode 100644
index 0000000000..6c08b6bc80
--- /dev/null
+++ b/web/c_cpp/c2cweb/cweb/cweave.w
@@ -0,0 +1,4505 @@
+% This file is part of CWEB.
+% This program by Silvio Levy and Donald E. Knuth
+% is based on a program by Knuth.
+% It is distributed WITHOUT ANY WARRANTY, express or implied.
+% Version 3.4 --- April 1995
+
+% Copyright (C) 1987,1990,1993 Silvio Levy and Donald E. Knuth
+
+% Permission is granted to make and distribute verbatim copies of this
+% document provided that the copyright notice and this permission notice
+% are preserved on all copies.
+
+% Permission is granted to copy and distribute modified versions of this
+% document under the conditions for verbatim copying, provided that the
+% entire resulting derived work is given a different name and distributed
+% under the terms of a permission notice identical to this one.
+
+% Here is TeX material that gets inserted after \input cwebmac
+\def\hang{\hangindent 3em\indent\ignorespaces}
+\def\pb{$\.|\ldots\.|$} % C brackets (|...|)
+\def\v{\char'174} % vertical (|) in typewriter font
+\def\dleft{[\![} \def\dright{]\!]} % double brackets
+\mathchardef\RA="3221 % right arrow
+\mathchardef\BA="3224 % double arrow
+\def\({} % ) kludge for alphabetizing certain section names
+\def\TeXxstring{\\{\TEX/\_string}}
+\def\skipxTeX{\\{skip\_\TEX/}}
+\def\copyxTeX{\\{copy\_\TEX/}}
+
+\def\title{CWEAVE (Version 3.4)}
+\def\topofcontents{\null\vfill
+ \centerline{\titlefont The {\ttitlefont CWEAVE} processor}
+ \vskip 15pt
+ \centerline{(Version 3.4)}
+ \vfill}
+\def\botofcontents{\vfill
+\noindent
+Copyright \copyright\ 1987, 1990, 1993 Silvio Levy and Donald E. Knuth
+\bigskip\noindent
+Permission is granted to make and distribute verbatim copies of this
+document provided that the copyright notice and this permission notice
+are preserved on all copies.
+
+\smallskip\noindent
+Permission is granted to copy and distribute modified versions of this
+document under the conditions for verbatim copying, provided that the
+entire resulting derived work is given a different name and distributed
+under the terms of a permission notice identical to this one.
+}
+\pageno=\contentspagenumber \advance\pageno by 1
+\let\maybe=\iftrue
+
+@** Introduction.
+This is the \.{CWEAVE} program by Silvio Levy and Donald E. Knuth,
+based on \.{WEAVE} by Knuth.
+We are thankful to Steve Avery,
+Nelson Beebe, Hans-Hermann Bode (to whom the \CPLUSPLUS/ adaptation is due),
+Klaus Guntermann, Norman Ramsey, Tomas Rokicki, Joachim Schnitter,
+Joachim Schrod, Lee Wittenberg, and others who have contributed improvements.
+
+The ``banner line'' defined here should be changed whenever \.{CWEAVE}
+is modified.
+
+@d banner "This is CWEAVE (Version 3.4)\n"
+
+@c @<Include files@>@/
+@h
+@<Common code for \.{CWEAVE} and \.{CTANGLE}@>@/
+@<Typedef declarations@>@/
+@<Global variables@>@/
+@<Predeclaration of procedures@>
+
+@ We predeclare several standard system functions here instead of including
+their system header files, because the names of the header files are not as
+standard as the names of the functions. (For example, some \CEE/ environments
+have \.{<string.h>} where others have \.{<strings.h>}.)
+
+@<Predecl...@>=
+extern int strlen(); /* length of string */
+extern int strcmp(); /* compare strings lexicographically */
+extern char* strcpy(); /* copy one string to another */
+extern int strncmp(); /* compare up to $n$ string characters */
+extern char* strncpy(); /* copy up to $n$ string characters */
+
+@ \.{CWEAVE} has a fairly straightforward outline. It operates in
+three phases: First it inputs the source file and stores cross-reference
+data, then it inputs the source once again and produces the \TEX/ output
+file, finally it sorts and outputs the index.
+
+Please read the documentation for \.{common}, the set of routines common
+to \.{CTANGLE} and \.{CWEAVE}, before proceeding further.
+
+@c
+int main (ac, av)
+int ac; /* argument count */
+char **av; /* argument values */
+{
+ argc=ac; argv=av;
+ program=cweave;
+ make_xrefs=force_lines=1; /* controlled by command-line options */
+ common_init();
+ @<Set initial values@>;
+ if (show_banner) printf(banner); /* print a ``banner line'' */
+ @<Store all the reserved words@>;
+ phase_one(); /* read all the user's text and store the cross-references */
+ phase_two(); /* read all the text again and translate it to \TEX/ form */
+ phase_three(); /* output the cross-reference index */
+ return wrap_up(); /* and exit gracefully */
+}
+
+@ The following parameters were sufficient in the original \.{WEAVE} to
+handle \TEX/, so they should be sufficient for most applications of \.{CWEAVE}.
+If you change |max_bytes|, |max_names|, |hash_size| or |buf_size|
+you have to change them also in the file |"common.w"|.
+
+@d max_bytes 90000 /* the number of bytes in identifiers,
+ index entries, and section names */
+@d max_names 4000 /* number of identifiers, strings, section names;
+ must be less than 10240; used in |"common.w"| */
+@d max_sections 2000 /* greater than the total number of sections */
+@d hash_size 353 /* should be prime */
+@d buf_size 100 /* maximum length of input line, plus one */
+@d longest_name 1000 /* section names and strings shouldn't be longer than this */
+@d long_buf_size (buf_size+longest_name)
+@d line_length 80 /* lines of \TEX/ output have at most this many characters;
+ should be less than 256 */
+@d max_refs 20000 /* number of cross-references; must be less than 65536 */
+@d max_toks 20000 /* number of symbols in \CEE/ texts being parsed;
+ must be less than 65536 */
+@d max_texts 4000 /* number of phrases in \CEE/ texts being parsed;
+ must be less than 10240 */
+@d max_scraps 2000 /* number of tokens in \CEE/ texts being parsed */
+@d stack_size 400 /* number of simultaneous output levels */
+
+@ The next few sections contain stuff from the file |"common.w"| that must
+be included in both |"ctangle.w"| and |"cweave.w"|. It appears in
+file |"common.h"|, which needs to be updated when |"common.w"| changes.
+
+@i common.h
+
+@* Data structures exclusive to {\tt CWEAVE}.
+As explained in \.{common.w}, the field of a |name_info| structure
+that contains the |rlink| of a section name is used for a completely
+different purpose in the case of identifiers. It is then called the
+|ilk| of the identifier, and it is used to
+distinguish between various types of identifiers, as follows:
+
+\yskip\hang |normal| identifiers are part of the \CEE/ program and
+will appear in italic type.
+
+\yskip\hang |roman| identifiers are index entries that appear after
+\.{@@\^} in the \.{CWEB} file.
+
+\yskip\hang |wildcard| identifiers are index entries that appear after
+\.{@@:} in the \.{CWEB} file.
+
+\yskip\hang |typewriter| identifiers are index entries that appear after
+\.{@@.} in the \.{CWEB} file.
+
+\yskip\hang |else_like|, \dots, |typedef_like|
+identifiers are \CEE/ reserved words whose |ilk| explains how they are
+to be treated when \CEE/ code is being formatted.
+
+@d ilk dummy.Ilk
+@d normal 0 /* ordinary identifiers have |normal| ilk */
+@d roman 1 /* normal index entries have |roman| ilk */
+@d wildcard 2 /* user-formatted index entries have |wildcard| ilk */
+@d typewriter 3 /* `typewriter type' entries have |typewriter| ilk */
+@d abnormal(a) (a->ilk>typewriter) /* tells if a name is special */
+@d custom 4 /* identifiers with user-given control sequence */
+@d unindexed(a) (a->ilk>custom) /* tells if uses of a name are to be indexed */
+@d quoted 5 /* \.{NULL} */
+@d else_like 26 /* \&{else} */
+@d public_like 40 /* \&{public}, \&{private}, \&{protected} */
+@d operator_like 41 /* \&{operator} */
+@d new_like 42 /* \&{new} */
+@d catch_like 43 /* \&{catch} */
+@d for_like 45 /* \.{for}, \&{switch}, \&{while} */
+@d do_like 46 /* \&{do} */
+@d if_like 47 /* \&{if}, \&{ifdef}, \&{endif}, \&{pragma}, \dots */
+@d raw_rpar 48 /* `\.)' or `\.]' when looking for \&{const} following */
+@d raw_unorbin 49 /* `\.\&' or `\.*' when looking for \&{const} following */
+@d const_like 50 /* \&{const}, \&{volatile} */
+@d raw_int 51 /* \&{int}, \&{char}, \&{extern}, \dots */
+@d int_like 52 /* same, when not followed by left parenthesis */
+@d case_like 53 /* \&{case}, \&{return}, \&{goto}, \&{break}, \&{continue} */
+@d sizeof_like 54 /* \&{sizeof} */
+@d struct_like 55 /* \&{struct}, \&{union}, \&{enum}, \&{class} */
+@d typedef_like 56 /* \&{typedef} */
+@d define_like 57 /* \&{define} */
+
+@ We keep track of the current section number in |section_count|, which
+is the total number of sections that have started. Sections which have
+been altered by a change file entry have their |changed_section| flag
+turned on during the first phase.
+
+@<Global...@>=
+boolean change_exists; /* has any section changed? */
+
+@ The other large memory area in \.{CWEAVE} keeps the cross-reference data.
+All uses of the name |p| are recorded in a linked list beginning at
+|p->xref|, which points into the |xmem| array. The elements of |xmem|
+are structures consisting of an integer, |num|, and a pointer |xlink|
+to another element of |xmem|. If |x=p->xref| is a pointer into |xmem|,
+the value of |x->num| is either a section number where |p| is used,
+or |cite_flag| plus a section number where |p| is mentioned,
+or |def_flag| plus a section number where |p| is defined;
+and |x->xlink| points to the next such cross-reference for |p|,
+if any. This list of cross-references is in decreasing order by
+section number. The next unused slot in |xmem| is |xref_ptr|.
+The linked list ends at |&xmem[0]|.
+
+The global variable |xref_switch| is set either to |def_flag| or to zero,
+depending on whether the next cross-reference to an identifier is to be
+underlined or not in the index. This switch is set to |def_flag| when
+\.{@@!} or \.{@@d} is scanned, and it is cleared to zero when
+the next identifier or index entry cross-reference has been made.
+Similarly, the global variable |section_xref_switch| is either
+|def_flag| or |cite_flag| or zero, depending
+on whether a section name is being defined, cited or used in \CEE/ text.
+
+@<Type...@>=
+typedef struct xref_info {
+ sixteen_bits num; /* section number plus zero or |def_flag| */
+ struct xref_info *xlink; /* pointer to the previous cross-reference */
+} xref_info;
+typedef xref_info *xref_pointer;
+
+@ @<Global...@>=
+xref_info xmem[max_refs]; /* contains cross-reference information */
+xref_pointer xmem_end = xmem+max_refs-1;
+xref_pointer xref_ptr; /* the largest occupied position in |xmem| */
+sixteen_bits xref_switch,section_xref_switch; /* either zero or |def_flag| */
+
+@ A section that is used for multi-file output (with the \.{@@(} feature)
+has a special first cross-reference whose |num| field is |file_flag|.
+
+@d file_flag (3*cite_flag)
+@d def_flag (2*cite_flag)
+@d cite_flag 10240 /* must be strictly larger than |max_sections| */
+@d xref equiv_or_xref
+
+@<Set init...@>=
+xref_ptr=xmem; name_dir->xref=(char*)xmem; xref_switch=0; section_xref_switch=0;
+xmem->num=0; /* sentinel value */
+
+@ A new cross-reference for an identifier is formed by calling |new_xref|,
+which discards duplicate entries and ignores non-underlined references
+to one-letter identifiers or \CEE/'s reserved words.
+
+If the user has sent the |no_xref| flag (the \.{-x} option of the command line),
+it is unnecessary to keep track of cross-references for identifiers.
+If one were careful, one could probably make more changes around section
+100 to avoid a lot of identifier looking up.
+
+@d append_xref(c) if (xref_ptr==xmem_end) overflow("cross-reference");
+ else (++xref_ptr)->num=c;
+@d no_xref (flags['x']==0)
+@d make_xrefs flags['x'] /* should cross references be output? */
+@d is_tiny(p) ((p+1)->byte_start==(p)->byte_start+1)
+
+@c
+void
+new_xref(p)
+name_pointer p;
+{
+ xref_pointer q; /* pointer to previous cross-reference */
+ sixteen_bits m, n; /* new and previous cross-reference value */
+ if (no_xref) return;
+ if ((unindexed(p) || is_tiny(p)) && xref_switch==0) return;
+ m=section_count+xref_switch; xref_switch=0; q=(xref_pointer)p->xref;
+ if (q != xmem) {
+ n=q->num;
+ if (n==m || n==m+def_flag) return;
+ else if (m==n+def_flag) {
+ q->num=m; return;
+ }
+ }
+ append_xref(m); xref_ptr->xlink=q; p->xref=(char*)xref_ptr;
+}
+
+@ The cross-reference lists for section names are slightly different.
+Suppose that a section name is defined in sections $m_1$, \dots,
+$m_k$, cited in sections $n_1$, \dots, $n_l$, and used in sections
+$p_1$, \dots, $p_j$. Then its list will contain $m_1+|def_flag|$,
+\dots, $m_k+|def_flag|$, $n_1+|cite_flag|$, \dots,
+$n_l+|cite_flag|$, $p_1$, \dots, $p_j$, in this order.
+
+Although this method of storage take quadratic time on the length of
+the list, under foreseeable uses of \.{CWEAVE} this inefficiency is
+insignificant.
+
+@c
+void
+new_section_xref(p)
+name_pointer p;
+{
+ xref_pointer q,r; /* pointers to previous cross-references */
+ q=(xref_pointer)p->xref; r=xmem;
+ if (q>xmem)
+ while (q->num>section_xref_switch) {r=q; q=q->xlink;}
+ if (r->num==section_count+section_xref_switch)
+ return; /* don't duplicate entries */
+ append_xref(section_count+section_xref_switch);
+ xref_ptr->xlink=q; section_xref_switch=0;
+ if (r==xmem) p->xref=(char*)xref_ptr;
+ else r->xlink=xref_ptr;
+}
+
+@ The cross-reference list for a section name may also begin with
+|file_flag|. Here's how that flag gets put~in.
+
+@c
+void
+set_file_flag(p)
+name_pointer p;
+{
+ xref_pointer q;
+ q=(xref_pointer)p->xref;
+ if (q->num==file_flag) return;
+ append_xref(file_flag);
+ xref_ptr->xlink = q;
+ p->xref = (char *)xref_ptr;
+}
+
+@ A third large area of memory is used for sixteen-bit `tokens', which appear
+in short lists similar to the strings of characters in |byte_mem|. Token lists
+are used to contain the result of \CEE/ code translated into \TEX/ form;
+further details about them will be explained later. A |text_pointer| variable
+is an index into |tok_start|.
+
+@<Typed...@>=
+typedef sixteen_bits token;
+typedef token *token_pointer;
+typedef token_pointer *text_pointer;
+
+@ The first position of |tok_mem|
+that is unoccupied by replacement text is called |tok_ptr|, and the first
+unused location of |tok_start| is called |text_ptr|.
+Thus, we usually have |*text_ptr==tok_ptr|.
+
+@<Global...@>=
+token tok_mem[max_toks]; /* tokens */
+token_pointer tok_mem_end = tok_mem+max_toks-1; /* end of |tok_mem| */
+token_pointer tok_start[max_texts]; /* directory into |tok_mem| */
+token_pointer tok_ptr; /* first unused position in |tok_mem| */
+text_pointer text_ptr; /* first unused position in |tok_start| */
+text_pointer tok_start_end = tok_start+max_texts-1; /* end of |tok_start| */
+token_pointer max_tok_ptr; /* largest value of |tok_ptr| */
+text_pointer max_text_ptr; /* largest value of |text_ptr| */
+
+@ @<Set init...@>=
+tok_ptr=tok_mem+1; text_ptr=tok_start+1; tok_start[0]=tok_mem+1;
+tok_start[1]=tok_mem+1;
+max_tok_ptr=tok_mem+1; max_text_ptr=tok_start+1;
+
+@ Here are the three procedures needed to complete |id_lookup|:
+@c
+int names_match(p,first,l,t)
+name_pointer p; /* points to the proposed match */
+char *first; /* position of first character of string */
+int l; /* length of identifier */
+eight_bits t; /* desired ilk */
+{
+ if (length(p)!=l) return 0;
+ if (p->ilk!=t && !(t==normal && abnormal(p))) return 0;
+ return !strncmp(first,p->byte_start,l);
+}
+
+void
+init_p(p,t)
+name_pointer p;
+eight_bits t;
+{
+ p->ilk=t; p->xref=(char*)xmem;
+}
+
+void
+init_node(p)
+name_pointer p;
+{
+ p->xref=(char*)xmem;
+}
+
+@ We have to get \CEE/'s
+reserved words into the hash table, and the simplest way to do this is
+to insert them every time \.{CWEAVE} is run. Fortunately there are relatively
+few reserved words. (Some of these are not strictly ``reserved,'' but
+are defined in header files of the ISO Standard \CEE/ Library.)
+@^reserved words@>
+
+@<Store all the reserved words@>=
+id_lookup("asm",NULL,sizeof_like);
+id_lookup("auto",NULL,int_like);
+id_lookup("break",NULL,case_like);
+id_lookup("case",NULL,case_like);
+id_lookup("catch",NULL,catch_like);
+id_lookup("char",NULL,raw_int);
+id_lookup("class",NULL,struct_like);
+id_lookup("clock_t",NULL,raw_int);
+id_lookup("const",NULL,const_like);
+id_lookup("continue",NULL,case_like);
+id_lookup("default",NULL,case_like);
+id_lookup("define",NULL,define_like);
+id_lookup("defined",NULL,sizeof_like);
+id_lookup("delete",NULL,sizeof_like);
+id_lookup("div_t",NULL,raw_int);
+id_lookup("do",NULL,do_like);
+id_lookup("double",NULL,raw_int);
+id_lookup("elif",NULL,if_like);
+id_lookup("else",NULL,else_like);
+id_lookup("endif",NULL,if_like);
+id_lookup("enum",NULL,struct_like);
+id_lookup("error",NULL,if_like);
+id_lookup("extern",NULL,int_like);
+id_lookup("FILE",NULL,raw_int);
+id_lookup("float",NULL,raw_int);
+id_lookup("for",NULL,for_like);
+id_lookup("fpos_t",NULL,raw_int);
+id_lookup("friend",NULL,int_like);
+id_lookup("goto",NULL,case_like);
+id_lookup("if",NULL,if_like);
+id_lookup("ifdef",NULL,if_like);
+id_lookup("ifndef",NULL,if_like);
+id_lookup("include",NULL,if_like);
+id_lookup("inline",NULL,int_like);
+id_lookup("int",NULL,raw_int);
+id_lookup("jmp_buf",NULL,raw_int);
+id_lookup("ldiv_t",NULL,raw_int);
+id_lookup("line",NULL,if_like);
+id_lookup("long",NULL,raw_int);
+id_lookup("new",NULL,new_like);
+id_lookup("NULL",NULL,quoted);
+id_lookup("offsetof",NULL,sizeof_like);
+id_lookup("operator",NULL,operator_like);
+id_lookup("pragma",NULL,if_like);
+id_lookup("private",NULL,public_like);
+id_lookup("protected",NULL,public_like);
+id_lookup("ptrdiff_t",NULL,raw_int);
+id_lookup("public",NULL,public_like);
+id_lookup("register",NULL,int_like);
+id_lookup("return",NULL,case_like);
+id_lookup("short",NULL,raw_int);
+id_lookup("sig_atomic_t",NULL,raw_int);
+id_lookup("signed",NULL,raw_int);
+id_lookup("size_t",NULL,raw_int);
+id_lookup("sizeof",NULL,sizeof_like);
+id_lookup("static",NULL,int_like);
+id_lookup("struct",NULL,struct_like);
+id_lookup("switch",NULL,for_like);
+id_lookup("template",NULL,int_like);
+id_lookup("TeX",NULL,custom);
+id_lookup("this",NULL,quoted);
+id_lookup("throw",NULL,case_like);
+id_lookup("time_t",NULL,raw_int);
+id_lookup("try",NULL,else_like);
+id_lookup("typedef",NULL,typedef_like);
+id_lookup("undef",NULL,if_like);
+id_lookup("union",NULL,struct_like);
+id_lookup("unsigned",NULL,raw_int);
+id_lookup("va_dcl",NULL,decl); /* Berkeley's variable-arg-list convention */
+id_lookup("va_list",NULL,raw_int); /* ditto */
+id_lookup("virtual",NULL,int_like);
+id_lookup("void",NULL,raw_int);
+id_lookup("volatile",NULL,const_like);
+id_lookup("wchar_t",NULL,raw_int);
+id_lookup("while",NULL,for_like);
+
+@* Lexical scanning.
+Let us now consider the subroutines that read the \.{CWEB} source file
+and break it into meaningful units. There are four such procedures:
+One simply skips to the next `\.{@@\ }' or `\.{@@*}' that begins a
+section; another passes over the \TEX/ text at the beginning of a
+section; the third passes over the \TEX/ text in a \CEE/ comment;
+and the last, which is the most interesting, gets the next token of
+a \CEE/ text. They all use the pointers |limit| and |loc| into
+the line of input currently being studied.
+
+@ Control codes in \.{CWEB}, which begin with `\.{@@}', are converted
+into a numeric code designed to simplify \.{CWEAVE}'s logic; for example,
+larger numbers are given to the control codes that denote more significant
+milestones, and the code of |new_section| should be the largest of
+all. Some of these numeric control codes take the place of |char|
+control codes that will not otherwise appear in the output of the
+scanning routines.
+@^ASCII code dependencies@>
+
+@d ignore 00 /* control code of no interest to \.{CWEAVE} */
+@d verbatim 02 /* takes the place of extended ASCII \.{\char2} */
+@d begin_short_comment 03 /* \CPLUSPLUS/ short comment */
+@d begin_comment '\t' /* tab marks will not appear */
+@d underline '\n' /* this code will be intercepted without confusion */
+@d noop 0177 /* takes the place of ASCII delete */
+@d xref_roman 0203 /* control code for `\.{@@\^}' */
+@d xref_wildcard 0204 /* control code for `\.{@@:}' */
+@d xref_typewriter 0205 /* control code for `\.{@@.}' */
+@d TeX_string 0206 /* control code for `\.{@@t}' */
+@f TeX_string TeX
+@d ord 0207 /* control code for `\.{@@'}' */
+@d join 0210 /* control code for `\.{@@\&}' */
+@d thin_space 0211 /* control code for `\.{@@,}' */
+@d math_break 0212 /* control code for `\.{@@\v}' */
+@d line_break 0213 /* control code for `\.{@@/}' */
+@d big_line_break 0214 /* control code for `\.{@@\#}' */
+@d no_line_break 0215 /* control code for `\.{@@+}' */
+@d pseudo_semi 0216 /* control code for `\.{@@;}' */
+@d macro_arg_open 0220 /* control code for `\.{@@[}' */
+@d macro_arg_close 0221 /* control code for `\.{@@]}' */
+@d trace 0222 /* control code for `\.{@@0}', `\.{@@1}' and `\.{@@2}' */
+@d translit_code 0223 /* control code for `\.{@@l}' */
+@d output_defs_code 0224 /* control code for `\.{@@h}' */
+@d format_code 0225 /* control code for `\.{@@f}' and `\.{@@s}' */
+@d definition 0226 /* control code for `\.{@@d}' */
+@d begin_C 0227 /* control code for `\.{@@c}' */
+@d section_name 0230 /* control code for `\.{@@<}' */
+@d new_section 0231 /* control code for `\.{@@\ }' and `\.{@@*}' */
+
+@ Control codes are converted to \.{CWEAVE}'s internal
+representation by means of the table |ccode|.
+
+@<Global...@>=
+eight_bits ccode[256]; /* meaning of a char following \.{@@} */
+
+@ @<Set ini...@>=
+{int c; for (c=0; c<256; c++) ccode[c]=0;}
+ccode[' ']=ccode['\t']=ccode['\n']=ccode['\v']=ccode['\r']=ccode['\f']
+ =ccode['*']=new_section;
+ccode['@@']='@@'; /* `quoted' at sign */
+ccode['=']=verbatim;
+ccode['d']=ccode['D']=definition;
+ccode['f']=ccode['F']=ccode['s']=ccode['S']=format_code;
+ccode['c']=ccode['C']=ccode['p']=ccode['P']=begin_C;
+ccode['t']=ccode['T']=TeX_string;
+ccode['l']=ccode['L']=translit_code;
+ccode['q']=ccode['Q']=noop;
+ccode['h']=ccode['H']=output_defs_code;
+ccode['&']=join; ccode['<']=ccode['(']=section_name;
+ccode['!']=underline; ccode['^']=xref_roman;
+ccode[':']=xref_wildcard; ccode['.']=xref_typewriter; ccode[',']=thin_space;
+ccode['|']=math_break; ccode['/']=line_break; ccode['#']=big_line_break;
+ccode['+']=no_line_break; ccode[';']=pseudo_semi;
+ccode['[']=macro_arg_open; ccode[']']=macro_arg_close;
+ccode['\'']=ord;
+@<Special control codes for debugging@>@;
+
+@ Users can write
+\.{@@2}, \.{@@1}, and \.{@@0} to turn tracing fully on, partly on,
+and off, respectively.
+
+@<Special control codes...@>=
+ccode['0']=ccode['1']=ccode['2']=trace;
+
+@ The |skip_limbo| routine is used on the first pass to skip through
+portions of the input that are not in any sections, i.e., that precede
+the first section. After this procedure has been called, the value of
+|input_has_ended| will tell whether or not a section has actually been found.
+
+There's a complication that we will postpone until later: If the \.{@@s}
+operation appears in limbo, we want to use it to adjust the default
+interpretation of identifiers.
+
+@<Predec...@>=
+void skip_limbo();
+
+@ @c
+void
+skip_limbo() {
+ while(1) {
+ if (loc>limit && get_line()==0) return;
+ *(limit+1)='@@';
+ while (*loc!='@@') loc++; /* look for '@@', then skip two chars */
+ if (loc++ <=limit) { int c=ccode[(eight_bits)*loc++];
+ if (c==new_section) return;
+ if (c==noop) skip_restricted();
+ else if (c==format_code) @<Process simple format in limbo@>;
+ }
+ }
+}
+
+@ The |skip_TeX| routine is used on the first pass to skip through
+the \TEX/ code at the beginning of a section. It returns the next
+control code or `\.{\v}' found in the input. A |new_section| is
+assumed to exist at the very end of the file.
+
+@f skip_TeX TeX
+
+@c
+unsigned
+skip_TeX() /* skip past pure \TEX/ code */
+{
+ while (1) {
+ if (loc>limit && get_line()==0) return(new_section);
+ *(limit+1)='@@';
+ while (*loc!='@@' && *loc!='|') loc++;
+ if (*loc++ =='|') return('|');
+ if (loc<=limit) return(ccode[(eight_bits)*(loc++)]);
+ }
+}
+
+@*1 Inputting the next token.
+As stated above, \.{CWEAVE}'s most interesting lexical scanning routine is the
+|get_next| function that inputs the next token of \CEE/ input. However,
+|get_next| is not especially complicated.
+
+The result of |get_next| is either a |char| code for some special character,
+or it is a special code representing a pair of characters (e.g., `\.{!=}'),
+or it is the numeric value computed by the |ccode|
+table, or it is one of the following special codes:
+
+\yskip\hang |identifier|: In this case the global variables |id_first| and
+|id_loc| will have been set to the beginning and ending-plus-one locations
+in the buffer, as required by the |id_lookup| routine.
+
+\yskip\hang |string|: The string will have been copied into the array
+|section_text|; |id_first| and |id_loc| are set as above (now they are
+pointers into |section_text|).
+
+\yskip\hang |constant|: The constant is copied into |section_text|, with
+slight modifications; |id_first| and |id_loc| are set.
+
+\yskip\noindent Furthermore, some of the control codes cause
+|get_next| to take additional actions:
+
+\yskip\hang |xref_roman|, |xref_wildcard|, |xref_typewriter|, |TeX_string|,
+|verbatim|: The values of |id_first| and |id_loc| will have been set to
+the beginning and ending-plus-one locations in the buffer.
+
+\yskip\hang |section_name|: In this case the global variable |cur_section| will
+point to the |byte_start| entry for the section name that has just been scanned.
+The value of |cur_section_char| will be |'('| if the section name was
+preceded by \.{@@(} instead of \.{@@<}.
+
+\yskip\noindent If |get_next| sees `\.{@@!}'
+it sets |xref_switch| to |def_flag| and goes on to the next token.
+
+@d constant 0200 /* \CEE/ constant */
+@d string 0201 /* \CEE/ string */
+@d identifier 0202 /* \CEE/ identifier or reserved word */
+
+@<Global...@>=
+name_pointer cur_section; /* name of section just scanned */
+char cur_section_char; /* the character just before that name */
+
+@ @<Include...@>=
+#include <ctype.h> /* definition of |isalpha|, |isdigit| and so on */
+#include <stdlib.h> /* definition of |exit| */
+
+@ As one might expect, |get_next| consists mostly of a big switch
+that branches to the various special cases that can arise.
+
+@d isxalpha(c) ((c)=='_') /* non-alpha character allowed in identifier */
+@d ishigh(c) ((eight_bits)(c)>0177)
+@^high-bit character handling@>
+
+@<Predecl...@>=
+eight_bits get_next();
+
+@ @c
+eight_bits
+get_next() /* produces the next input token */
+{@+eight_bits c; /* the current character */
+ while (1) {
+ @<Check if we're at the end of a preprocessor command@>;
+ if (loc>limit && get_line()==0) return(new_section);
+ c=*(loc++);
+ if (xisdigit(c) || c=='\\' || c=='.') @<Get a constant@>@;
+ else if (c=='\'' || c=='"' || (c=='L'&&(*loc=='\'' || *loc=='"'))@|
+ || (c=='<' && sharp_include_line==1))
+ @<Get a string@>@;
+ else if (xisalpha(c) || isxalpha(c) || ishigh(c))
+ @<Get an identifier@>@;
+ else if (c=='@@') @<Get control code and possible section name@>@;
+ else if (xisspace(c)) continue; /* ignore spaces and tabs */
+ if (c=='#' && loc==buffer+1) @<Raise preprocessor flag@>;
+ mistake: @<Compress two-symbol operator@>@;
+ return(c);
+ }
+}
+
+@ Because preprocessor commands do not fit in with the rest of the syntax
+of \CEE/,
+we have to deal with them separately. One solution is to enclose such
+commands between special markers. Thus, when a \.\# is seen as the
+first character of a line, |get_next| returns a special code
+|left_preproc| and raises a flag |preprocessing|.
+
+We can use the same internal code number for |left_preproc| as we do
+for |ord|, since |get_next| changes |ord| into a string.
+
+@d left_preproc ord /* begins a preprocessor command */
+@d right_preproc 0217 /* ends a preprocessor command */
+
+@<Glob...@>=
+boolean preprocessing=0; /* are we scanning a preprocessor command? */
+
+@ @<Raise prep...@>= {
+ preprocessing=1;
+ @<Check if next token is |include|@>;
+ return (left_preproc);
+}
+
+@ An additional complication is the freakish use of \.< and \.> to delimit
+a file name in lines that start with \.{\#include}. We must treat this file
+name as a string.
+
+@<Glob...@>=
+boolean sharp_include_line=0; /* are we scanning a |#include| line? */
+
+@ @<Check if next token is |include|@>=
+while (loc<=buffer_end-7 && xisspace(*loc)) loc++;
+if (loc<=buffer_end-6 && strncmp(loc,"include",7)==0) sharp_include_line=1;
+
+@ When we get to the end of a preprocessor line,
+we lower the flag and send a code |right_preproc|, unless
+the last character was a \.\\.
+
+@<Check if we're at...@>=
+ while (loc==limit-1 && preprocessing && *loc=='\\')
+ if (get_line()==0) return(new_section); /* still in preprocessor mode */
+ if (loc>=limit && preprocessing) {
+ preprocessing=sharp_include_line=0;
+ return(right_preproc);
+ }
+
+@ The following code assigns values to the combinations \.{++},
+\.{--}, \.{->}, \.{>=}, \.{<=}, \.{==}, \.{<<}, \.{>>}, \.{!=}, \.{\v\v}, and
+\.{\&\&}, and to the \CPLUSPLUS/
+combinations \.{...}, \.{::}, \.{.*} and \.{->*}.
+The compound assignment operators (e.g., \.{+=}) are
+treated as separate tokens.
+
+@d compress(c) if (loc++<=limit) return(c)
+
+@<Compress tw...@>=
+switch(c) {
+ case '/': if (*loc=='*') {compress(begin_comment);}
+ else if (*loc=='/') compress(begin_short_comment); break;
+ case '+': if (*loc=='+') compress(plus_plus); break;
+ case '-': if (*loc=='-') {compress(minus_minus);}
+ else if (*loc=='>') if (*(loc+1)=='*') {loc++; compress(minus_gt_ast);}
+ else compress(minus_gt); break;
+ case '.': if (*loc=='*') {compress(period_ast);}
+ else if (*loc=='.' && *(loc+1)=='.') {
+ loc++; compress(dot_dot_dot);
+ }
+ break;
+ case ':': if (*loc==':') compress(colon_colon); break;
+ case '=': if (*loc=='=') compress(eq_eq); break;
+ case '>': if (*loc=='=') {compress(gt_eq);}
+ else if (*loc=='>') compress(gt_gt); break;
+ case '<': if (*loc=='=') {compress(lt_eq);}
+ else if (*loc=='<') compress(lt_lt); break;
+ case '&': if (*loc=='&') compress(and_and); break;
+ case '|': if (*loc=='|') compress(or_or); break;
+ case '!': if (*loc=='=') compress(not_eq); break;
+}
+
+@ @<Get an identifier@>= {
+ id_first=--loc;
+ while (isalpha(*++loc) || isdigit(*loc) || isxalpha(*loc) || ishigh(*loc));
+ id_loc=loc; return(identifier);
+}
+
+@ Different conventions are followed by \TEX/ and \CEE/ to express octal
+and hexadecimal numbers; it is reasonable to stick to each convention
+within its realm. Thus the \CEE/ part of a \.{CWEB} file has octals
+introduced by \.0 and hexadecimals by \.{0x}, but \.{CWEAVE} will print
+in italics or typewriter font, respectively, and introduced by single
+or double quotes. In order to simplify the \TEX/ macro used to print
+such constants, we replace some of the characters.
+
+Notice that in this section and the next, |id_first| and |id_loc|
+are pointers into the array |section_text|, not into |buffer|.
+
+@<Get a constant@>= {
+ id_first=id_loc=section_text+1;
+ if (*(loc-1)=='\\') {*id_loc++='~';
+ while (xisdigit(*loc)) *id_loc++=*loc++;} /* octal constant */
+ else if (*(loc-1)=='0') {
+ if (*loc=='x' || *loc=='X') {*id_loc++='^'; loc++;
+ while (xisxdigit(*loc)) *id_loc++=*loc++;} /* hex constant */
+ else if (xisdigit(*loc)) {*id_loc++='~';
+ while (xisdigit(*loc)) *id_loc++=*loc++;} /* octal constant */
+ else goto dec; /* decimal constant */
+ }
+ else { /* decimal constant */
+ if (*(loc-1)=='.' && !xisdigit(*loc)) goto mistake; /* not a constant */
+ dec: *id_loc++=*(loc-1);
+ while (xisdigit(*loc) || *loc=='.') *id_loc++=*loc++;
+ if (*loc=='e' || *loc=='E') { /* float constant */
+ *id_loc++='_'; loc++;
+ if (*loc=='+' || *loc=='-') *id_loc++=*loc++;
+ while (xisdigit(*loc)) *id_loc++=*loc++;
+ }
+ }
+ while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L'
+ || *loc=='f' || *loc=='F') {
+ *id_loc++='$'; *id_loc++=toupper(*loc); loc++;
+ }
+ return(constant);
+}
+
+@ \CEE/ strings and character constants, delimited by double and single
+quotes, respectively, can contain newlines or instances of their own
+delimiters if they are protected by a backslash. We follow this
+convention, but do not allow the string to be longer than |longest_name|.
+
+@<Get a string@>= {
+ char delim = c; /* what started the string */
+ id_first = section_text+1;
+ id_loc = section_text;
+ if (delim=='\'' && *(loc-2)=='@@') {*++id_loc='@@'; *++id_loc='@@';}
+ *++id_loc=delim;
+ if (delim=='L') { /* wide character constant */
+ delim=*loc++; *++id_loc=delim;
+ }
+ if (delim=='<') delim='>'; /* for file names in |#include| lines */
+ while (1) {
+ if (loc>=limit) {
+ if(*(limit-1)!='\\') {
+ err_print("! String didn't end"); loc=limit; break;
+@.String didn't end@>
+ }
+ if(get_line()==0) {
+ err_print("! Input ended in middle of string"); loc=buffer; break;
+@.Input ended in middle of string@>
+ }
+ }
+ if ((c=*loc++)==delim) {
+ if (++id_loc<=section_text_end) *id_loc=c;
+ break;
+ }
+ if (c=='\\') if (loc>=limit) continue;
+ else if (++id_loc<=section_text_end) {
+ *id_loc = '\\'; c=*loc++;
+ }
+ if (++id_loc<=section_text_end) *id_loc=c;
+ }
+ if (id_loc>=section_text_end) {
+ printf("\n! String too long: ");
+@.String too long@>
+ term_write(section_text+1,25);
+ printf("..."); mark_error;
+ }
+ id_loc++;
+ return(string);
+}
+
+@ After an \.{@@} sign has been scanned, the next character tells us
+whether there is more work to do.
+
+@<Get control code and possible section name@>= {
+ c=*loc++;
+ switch(ccode[(eight_bits)c]) {
+ case translit_code: err_print("! Use @@l in limbo only"); continue;
+@.Use @@l in limbo...@>
+ case underline: xref_switch=def_flag; continue;
+ case trace: tracing=c-'0'; continue;
+ case xref_roman: case xref_wildcard: case xref_typewriter:
+ case noop: case TeX_string: c=ccode[c]; skip_restricted(); return(c);
+ case section_name:
+ @<Scan the section name and make |cur_section| point to it@>;
+ case verbatim: @<Scan a verbatim string@>;
+ case ord: @<Get a string@>;
+ default: return(ccode[(eight_bits)c]);
+ }
+}
+
+@ The occurrence of a section name sets |xref_switch| to zero,
+because the section name might (for example) follow \&{int}.
+
+@<Scan the section name...@>= {
+ char *k; /* pointer into |section_text| */
+ cur_section_char=*(loc-1);
+ @<Put section name into |section_text|@>;
+ if (k-section_text>3 && strncmp(k-2,"...",3)==0)
+ cur_section=section_lookup(section_text+1,k-3,1); /* 1 indicates a prefix */
+ else cur_section=section_lookup(section_text+1,k,0);
+ xref_switch=0; return(section_name);
+}
+
+@ Section names are placed into the |section_text| array with consecutive spaces,
+tabs, and carriage-returns replaced by single spaces. There will be no
+spaces at the beginning or the end. (We set |section_text[0]=' '| to facilitate
+this, since the |section_lookup| routine uses |section_text[1]| as the first
+character of the name.)
+
+@<Set init...@>=section_text[0]=' ';
+
+@ @<Put section name...@>=
+k=section_text;
+while (1) {
+ if (loc>limit && get_line()==0) {
+ err_print("! Input ended in section name");
+@.Input ended in section name@>
+ loc=buffer+1; break;
+ }
+ c=*loc;
+ @<If end of name or erroneous control code, |break|@>;
+ loc++; if (k<section_text_end) k++;
+ if (xisspace(c)) {
+ c=' '; if (*(k-1)==' ') k--;
+ }
+*k=c;
+}
+if (k>=section_text_end) {
+ printf("\n! Section name too long: ");
+@.Section name too long@>
+ term_write(section_text+1,25);
+ printf("..."); mark_harmless;
+}
+if (*k==' ' && k>section_text) k--;
+
+@ @<If end of name...@>=
+if (c=='@@') {
+ c=*(loc+1);
+ if (c=='>') {
+ loc+=2; break;
+ }
+ if (ccode[(eight_bits)c]==new_section) {
+ err_print("! Section name didn't end"); break;
+@.Section name didn't end@>
+ }
+ if (c!='@@') {
+ err_print("! Control codes are forbidden in section name"); break;
+@.Control codes are forbidden...@>
+ }
+ *(++k)='@@'; loc++; /* now |c==*loc| again */
+}
+
+@ This function skips over a restricted context at relatively high speed.
+
+@<Predecl...@>=
+void skip_restricted();
+
+@ @c
+void
+skip_restricted()
+{
+ id_first=loc; *(limit+1)='@@';
+false_alarm:
+ while (*loc!='@@') loc++;
+ id_loc=loc;
+ if (loc++>limit) {
+ err_print("! Control text didn't end"); loc=limit;
+@.Control text didn't end@>
+ }
+ else {
+ if (*loc=='@@'&&loc<=limit) {loc++; goto false_alarm;}
+ if (*loc++!='>')
+ err_print("! Control codes are forbidden in control text");
+@.Control codes are forbidden...@>
+ }
+}
+
+@ At the present point in the program we
+have |*(loc-1)==verbatim|; we set |id_first| to the beginning
+of the string itself, and |id_loc| to its ending-plus-one location in the
+buffer. We also set |loc| to the position just after the ending delimiter.
+
+@<Scan a verbatim string@>= {
+ id_first=loc++; *(limit+1)='@@'; *(limit+2)='>';
+ while (*loc!='@@' || *(loc+1)!='>') loc++;
+ if (loc>=limit) err_print("! Verbatim string didn't end");
+@.Verbatim string didn't end@>
+ id_loc=loc; loc+=2;
+ return (verbatim);
+}
+
+@** Phase one processing.
+We now have accumulated enough subroutines to make it possible to carry out
+\.{CWEAVE}'s first pass over the source file. If everything works right,
+both phase one and phase two of \.{CWEAVE} will assign the same numbers to
+sections, and these numbers will agree with what \.{CTANGLE} does.
+
+The global variable |next_control| often contains the most recent output of
+|get_next|; in interesting cases, this will be the control code that
+ended a section or part of a section.
+
+@<Global...@>=
+eight_bits next_control; /* control code waiting to be acting upon */
+
+@ The overall processing strategy in phase one has the following
+straightforward outline.
+
+@<Predecl...@>=
+void phase_one();
+
+@ @c
+void
+phase_one() {
+ phase=1; reset_input(); section_count=0;
+ skip_limbo(); change_exists=0;
+ while (!input_has_ended)
+ @<Store cross-reference data for the current section@>;
+ changed_section[section_count]=change_exists;
+ /* the index changes if anything does */
+ phase=2; /* prepare for second phase */
+ @<Print error messages about unused or undefined section names@>;
+}
+
+@ @<Store cross-reference data...@>=
+{
+ if (++section_count==max_sections) overflow("section number");
+ changed_section[section_count]=changing;
+ /* it will become 1 if any line changes */
+ if (*(loc-1)=='*' && show_progress) {
+ printf("*%d",section_count);
+ update_terminal; /* print a progress report */
+ }
+ @<Store cross-references in the \TEX/ part of a section@>;
+ @<Store cross-references in the definition part of a section@>;
+ @<Store cross-references in the \CEE/ part of a section@>;
+ if (changed_section[section_count]) change_exists=1;
+}
+
+@ The |C_xref| subroutine stores references to identifiers in
+\CEE/ text material beginning with the current value of |next_control|
+and continuing until |next_control| is `\.\{' or `\.{\v}', or until the next
+``milestone'' is passed (i.e., |next_control>=format_code|). If
+|next_control>=format_code| when |C_xref| is called, nothing will happen;
+but if |next_control=='|'| upon entry, the procedure assumes that this is
+the `\.{\v}' preceding \CEE/ text that is to be processed.
+
+The parameter |spec_ctrl| is used to change this behavior. In most cases
+|C_xref| is called with |spec_ctrl==ignore|, which triggers the default
+processing described above. If |spec_ctrl==section_name|, section names will
+be gobbled. This is used when \CEE/ text in the \TEX/ part or inside comments
+is parsed: It allows for section names to appear in \pb, but these
+strings will not be entered into the cross reference lists since they are not
+definitions of section names.
+
+The program uses the fact that our internal code numbers satisfy
+the relations |xref_roman==identifier+roman| and |xref_wildcard==identifier
++wildcard| and |xref_typewriter==identifier+typewriter|,
+as well as |normal==0|.
+
+@<Predecl...@>=
+void C_xref();
+
+@ @c
+void
+C_xref( spec_ctrl ) /* makes cross-references for \CEE/ identifiers */
+ eight_bits spec_ctrl;
+{
+ name_pointer p; /* a referenced name */
+ while (next_control<format_code || next_control==spec_ctrl) {
+ if (next_control>=identifier && next_control<=xref_typewriter) {
+ if (next_control>identifier) @<Replace |"@@@@"| by |"@@"| @>@;
+ p=id_lookup(id_first, id_loc,next_control-identifier); new_xref(p);
+ }
+ if (next_control==section_name) {
+ section_xref_switch=cite_flag;
+ new_section_xref(cur_section);
+ }
+ next_control=get_next();
+ if (next_control=='|' || next_control==begin_comment ||
+ next_control==begin_short_comment) return;
+ }
+}
+
+@ The |outer_xref| subroutine is like |C_xref| except that it begins
+with |next_control!='|'| and ends with |next_control>=format_code|. Thus, it
+handles \CEE/ text with embedded comments.
+
+@<Predecl...@>=
+void outer_xref();
+
+@ @c
+void
+outer_xref() /* extension of |C_xref| */
+{
+ int bal; /* brace level in comment */
+ while (next_control<format_code)
+ if (next_control!=begin_comment && next_control!=begin_short_comment)
+ C_xref(ignore);
+ else {
+ boolean is_long_comment=(next_control==begin_comment);
+ bal=copy_comment(is_long_comment,1); next_control='|';
+ while (bal>0) {
+ C_xref(section_name); /* do not reference section names in comments */
+ if (next_control=='|') bal=copy_comment(is_long_comment,bal);
+ else bal=0; /* an error message will occur in phase two */
+ }
+ }
+}
+
+@ In the \TEX/ part of a section, cross-reference entries are made only for
+the identifiers in \CEE/ texts enclosed in \pb, or for control texts
+enclosed in \.{@@\^}$\,\ldots\,$\.{@@>} or \.{@@.}$\,\ldots\,$\.{@@>}
+or \.{@@:}$\,\ldots\,$\.{@@>}.
+
+@<Store cross-references in the \T...@>=
+while (1) {
+ switch (next_control=skip_TeX()) {
+ case translit_code: err_print("! Use @@l in limbo only"); continue;
+@.Use @@l in limbo...@>
+ case underline: xref_switch=def_flag; continue;
+ case trace: tracing=*(loc-1)-'0'; continue;
+ case '|': C_xref(section_name); break;
+ case xref_roman: case xref_wildcard: case xref_typewriter:
+ case noop: case section_name:
+ loc-=2; next_control=get_next(); /* scan to \.{@@>} */
+ if (next_control>=xref_roman && next_control<=xref_typewriter) {
+ @<Replace |"@@@@"| by |"@@"| @>@;
+ new_xref(id_lookup(id_first, id_loc,next_control-identifier));
+ }
+ break;
+ }
+ if (next_control>=format_code) break;
+}
+
+@ @<Replace |"@@@@"| by |"@@"| @>=
+{
+ char *src=id_first,*dst=id_first;
+ while(src<id_loc){
+ if(*src=='@@') src++;
+ *dst++=*src++;
+ }
+ id_loc=dst;
+ while (dst<src) *dst++=' '; /* clean up in case of error message display */
+}
+
+@ During the definition and \CEE/ parts of a section, cross-references
+are made for all identifiers except reserved words. However, the right
+identifier in a format definition is not referenced, and the left
+identifier is referenced only if it has been explicitly
+underlined (preceded by \.{@@!}).
+The \TEX/ code in comments is, of course, ignored, except for
+\CEE/ portions enclosed in \pb; the text of a section name is skipped
+entirely, even if it contains \pb\ constructions.
+
+The variables |lhs| and |rhs| point to the respective identifiers involved
+in a format definition.
+
+@<Global...@>=
+name_pointer lhs, rhs; /* pointers to |byte_start| for format identifiers */
+
+@ When we get to the following code we have |next_control>=format_code|.
+
+@<Store cross-references in the d...@>=
+while (next_control<=definition) { /* |format_code| or |definition| */
+ if (next_control==definition) {
+ xref_switch=def_flag; /* implied \.{@@!} */
+ next_control=get_next();
+ } else @<Process a format definition@>;
+ outer_xref();
+}
+
+@ Error messages for improper format definitions will be issued in phase
+two. Our job in phase one is to define the |ilk| of a properly formatted
+identifier, and to remove cross-references to identifiers that we now
+discover should be unindexed.
+
+@<Process a form...@>= {
+ next_control=get_next();
+ if (next_control==identifier) {
+ lhs=id_lookup(id_first, id_loc,normal); lhs->ilk=normal;
+ if (xref_switch) new_xref(lhs);
+ next_control=get_next();
+ if (next_control==identifier) {
+ rhs=id_lookup(id_first, id_loc,normal);
+ lhs->ilk=rhs->ilk;
+ if (unindexed(lhs)) { /* retain only underlined entries */
+ xref_pointer q,r=NULL;
+ for (q=(xref_pointer)lhs->xref;q>xmem;q=q->xlink)
+ if (q->num<def_flag)
+ if (r) r->xlink=q->xlink;
+ else lhs->xref=(char*)q->xlink;
+ else r=q;
+ }
+ next_control=get_next();
+ }
+ }
+}
+
+@ A much simpler processing of format definitions occurs when the
+definition is found in limbo.
+
+@<Process simple format in limbo@>=
+{
+ if (get_next()!=identifier)
+ err_print("! Missing left identifier of @@s");
+@.Missing left identifier...@>
+ else {
+ lhs=id_lookup(id_first,id_loc,normal);
+ if (get_next()!=identifier)
+ err_print("! Missing right identifier of @@s");
+@.Missing right identifier...@>
+ else {
+ rhs=id_lookup(id_first,id_loc,normal);
+ lhs->ilk=rhs->ilk;
+ }
+ }
+}
+
+@ Finally, when the \TEX/ and definition parts have been treated, we have
+|next_control>=begin_C|.
+
+@<Store cross-references in the \CEE/...@>=
+if (next_control<=section_name) { /* |begin_C| or |section_name| */
+ if (next_control==begin_C) section_xref_switch=0;
+ else {
+ section_xref_switch=def_flag;
+ if(cur_section_char=='(' && cur_section!=name_dir)
+ set_file_flag(cur_section);
+ }
+ do {
+ if (next_control==section_name && cur_section!=name_dir)
+ new_section_xref(cur_section);
+ next_control=get_next(); outer_xref();
+ } while ( next_control<=section_name);
+}
+
+@ After phase one has looked at everything, we want to check that each
+section name was both defined and used. The variable |cur_xref| will point
+to cross-references for the current section name of interest.
+
+@<Global...@>=
+xref_pointer cur_xref; /* temporary cross-reference pointer */
+boolean an_output; /* did |file_flag| precede |cur_xref|? */
+
+@ The following recursive procedure
+walks through the tree of section names and prints out anomalies.
+@^recursion@>
+
+@<Predecl...@>=
+void section_check();
+
+@ @c
+void
+section_check(p)
+name_pointer p; /* print anomalies in subtree |p| */
+{
+ if (p) {
+ section_check(p->llink);
+ cur_xref=(xref_pointer)p->xref;
+ if (cur_xref->num==file_flag) {an_output=1; cur_xref=cur_xref->xlink;}
+ else an_output=0;
+ if (cur_xref->num <def_flag) {
+ printf("\n! Never defined: <"); print_section_name(p); putchar('>'); mark_harmless;
+@.Never defined: <section name>@>
+ }
+ while (cur_xref->num >=cite_flag) cur_xref=cur_xref->xlink;
+ if (cur_xref==xmem && !an_output) {
+ printf("\n! Never used: <"); print_section_name(p); putchar('>'); mark_harmless;
+@.Never used: <section name>@>
+ }
+ section_check(p->rlink);
+ }
+}
+
+@ @<Print error messages about un...@>=section_check(root)
+
+@* Low-level output routines.
+The \TEX/ output is supposed to appear in lines at most |line_length|
+characters long, so we place it into an output buffer. During the output
+process, |out_line| will hold the current line number of the line about to
+be output.
+
+@<Global...@>=
+char out_buf[line_length+1]; /* assembled characters */
+char *out_ptr; /* just after last character in |out_buf| */
+char *out_buf_end = out_buf+line_length; /* end of |out_buf| */
+int out_line; /* number of next line to be output */
+
+@ The |flush_buffer| routine empties the buffer up to a given breakpoint,
+and moves any remaining characters to the beginning of the next line.
+If the |per_cent| parameter is 1 a |'%'| is appended to the line
+that is being output; in this case the breakpoint |b| should be strictly
+less than |out_buf_end|. If the |per_cent| parameter is |0|,
+trailing blanks are suppressed.
+The characters emptied from the buffer form a new line of output;
+if the |carryover| parameter is true, a |"%"| in that line will be
+carried over to the next line (so that \TEX/ will ignore the completion
+of commented-out text).
+
+@d c_line_write(c) fflush(active_file),fwrite(out_buf+1,sizeof(char),c,active_file)
+@d tex_putc(c) putc(c,active_file)
+@d tex_new_line putc('\n',active_file)
+@d tex_printf(c) fprintf(active_file,c)
+
+@c
+void
+flush_buffer(b,per_cent,carryover)
+char *b; /* outputs from |out_buf+1| to |b|,where |b<=out_ptr| */
+boolean per_cent,carryover;
+{
+ char *j; j=b; /* pointer into |out_buf| */
+ if (! per_cent) /* remove trailing blanks */
+ while (j>out_buf && *j==' ') j--;
+ c_line_write(j-out_buf);
+ if (per_cent) tex_putc('%');
+ tex_new_line; out_line++;
+ if (carryover)
+ while (j>out_buf)
+ if (*j--=='%' && (j==out_buf || *j!='\\')) {
+ *b--='%'; break;
+ }
+ if (b<out_ptr) strncpy(out_buf+1,b+1,out_ptr-b);
+ out_ptr-=b-out_buf;
+}
+
+@ When we are copying \TEX/ source material, we retain line breaks
+that occur in the input, except that an empty line is not
+output when the \TEX/ source line was nonempty. For example, a line
+of the \TEX/ file that contains only an index cross-reference entry
+will not be copied. The |finish_line| routine is called just before
+|get_line| inputs a new line, and just after a line break token has
+been emitted during the output of translated \CEE/ text.
+
+@c
+void
+finish_line() /* do this at the end of a line */
+{
+ char *k; /* pointer into |buffer| */
+ if (out_ptr>out_buf) flush_buffer(out_ptr,0,0);
+ else {
+ for (k=buffer; k<=limit; k++)
+ if (!(xisspace(*k))) return;
+ flush_buffer(out_buf,0,0);
+ }
+}
+
+@ In particular, the |finish_line| procedure is called near the very
+beginning of phase two. We initialize the output variables in a slightly
+tricky way so that the first line of the output file will be
+`\.{\\input cwebmac}'.
+
+@<Set init...@>=
+out_ptr=out_buf+1; out_line=1; active_file=tex_file;
+*out_ptr='c'; tex_printf("\\input cwebma");
+
+@ When we wish to append one character |c| to the output buffer, we write
+`|out(c)|'; this will cause the buffer to be emptied if it was already
+full. If we want to append more than one character at once, we say
+|out_str(s)|, where |s| is a string containing the characters.
+
+A line break will occur at a space or after a single-nonletter
+\TEX/ control sequence.
+
+@d out(c) {if (out_ptr>=out_buf_end) break_out(); *(++out_ptr)=c;}
+
+@c
+void
+out_str(s) /* output characters from |s| to end of string */
+char *s;
+{
+ while (*s) out(*s++);
+}
+
+@ The |break_out| routine is called just before the output buffer is about
+to overflow. To make this routine a little faster, we initialize position
+0 of the output buffer to `\.\\'; this character isn't really output.
+
+@<Set init...@>=
+out_buf[0]='\\';
+
+@ A long line is broken at a blank space or just before a backslash that isn't
+preceded by another backslash. In the latter case, a |'%'| is output at
+the break.
+
+@<Predecl...@>=
+void break_out();
+
+@ @c
+void
+break_out() /* finds a way to break the output line */
+{
+ char *k=out_ptr; /* pointer into |out_buf| */
+ while (1) {
+ if (k==out_buf) @<Print warning message, break the line, |return|@>;
+ if (*k==' ') {
+ flush_buffer(k,0,1); return;
+ }
+ if (*(k--)=='\\' && *k!='\\') { /* we've decreased |k| */
+ flush_buffer(k,1,1); return;
+ }
+ }
+}
+
+@ We get to this section only in the unusual case that the entire output line
+consists of a string of backslashes followed by a string of nonblank
+non-backslashes. In such cases it is almost always safe to break the
+line by putting a |'%'| just before the last character.
+
+@<Print warning message...@>=
+{
+ printf("\n! Line had to be broken (output l. %d):\n",out_line);
+@.Line had to be broken@>
+ term_write(out_buf+1, out_ptr-out_buf-1);
+ new_line; mark_harmless;
+ flush_buffer(out_ptr-1,1,1); return;
+}
+
+@ Here is a macro that outputs a section number in decimal notation.
+The number to be converted by |out_section| is known to be less than
+|def_flag|, so it cannot have more than five decimal digits. If
+the section is changed, we output `\.{\\*}' just after the number.
+
+@c
+void
+out_section(n)
+sixteen_bits n;
+{
+ char s[6];
+ sprintf(s,"%d",n); out_str(s);
+ if(changed_section[n]) out_str ("\\*");
+@.\\*@>
+}
+
+@ The |out_name| procedure is used to output an identifier or index
+entry, enclosing it in braces.
+
+@c
+void
+out_name(p)
+name_pointer p;
+{
+ char *k, *k_end=(p+1)->byte_start; /* pointers into |byte_mem| */
+ out('{');
+ for (k=p->byte_start; k<k_end; k++) {
+ if (isxalpha(*k)) out('\\');
+ out(*k);
+ }
+ out('}');
+}
+
+@* Routines that copy \TEX/ material.
+During phase two, we use subroutines |copy_limbo|, |copy_TeX|, and
+|copy_comment| in place of the analogous |skip_limbo|, |skip_TeX|, and
+|skip_comment| that were used in phase one. (Well, |copy_comment|
+was actually written in such a way that it functions as |skip_comment|
+in phase one.)
+
+The |copy_limbo| routine, for example, takes \TEX/ material that is not
+part of any section and transcribes it almost verbatim to the output file.
+The use of `\.{@@}' signs is severely restricted in such material:
+`\.{@@@@}' pairs are replaced by singletons; `\.{@@l}' and `\.{@@q}' and
+`\.{@@s}' are interpreted.
+
+@c
+void
+copy_limbo()
+{
+ char c;
+ while (1) {
+ if (loc>limit && (finish_line(), get_line()==0)) return;
+ *(limit+1)='@@';
+ while (*loc!='@@') out(*(loc++));
+ if (loc++<=limit) {
+ c=*loc++;
+ if (ccode[(eight_bits)c]==new_section) break;
+ switch (ccode[(eight_bits)c]) {
+ case translit_code: out_str("\\ATL"); break;
+@.\\ATL@>
+ case '@@': out('@@'); break;
+ case noop: skip_restricted(); break;
+ case format_code: if (get_next()==identifier) get_next();
+ if (loc>=limit) get_line(); /* avoid blank lines in output */
+ break; /* the operands of \.{@@s} are ignored on this pass */
+ default: err_print("! Double @@ should be used in limbo");
+@.Double @@ should be used...@>
+ out('@@');
+ }
+ }
+ }
+}
+
+@ The |copy_TeX| routine processes the \TEX/ code at the beginning of a
+section; for example, the words you are now reading were copied in this
+way. It returns the next control code or `\.{\v}' found in the input.
+We don't copy spaces or tab marks into the beginning of a line. This
+makes the test for empty lines in |finish_line| work.
+
+@ @f copy_TeX TeX
+@c
+eight_bits
+copy_TeX()
+{
+ char c; /* current character being copied */
+ while (1) {
+ if (loc>limit && (finish_line(), get_line()==0)) return(new_section);
+ *(limit+1)='@@';
+ while ((c=*(loc++))!='|' && c!='@@') {
+ out(c);
+ if (out_ptr==out_buf+1 && (xisspace(c))) out_ptr--;
+ }
+ if (c=='|') return('|');
+ if (loc<=limit) return(ccode[(eight_bits)*(loc++)]);
+ }
+}
+
+@ The |copy_comment| function issues a warning if more braces are opened than
+closed, and in the case of a more serious error it supplies enough
+braces to keep \TEX/ from complaining about unbalanced braces.
+Instead of copying the \TEX/ material
+into the output buffer, this function copies it into the token memory
+(in phase two only).
+The abbreviation |app_tok(t)| is used to append token |t| to the current
+token list, and it also makes sure that it is possible to append at least
+one further token without overflow.
+
+@d app_tok(c) {if (tok_ptr+2>tok_mem_end) overflow("token"); *(tok_ptr++)=c;}
+
+@<Predec...@>=
+int copy_comment();
+
+@ @c
+int copy_comment(is_long_comment,bal) /* copies \TEX/ code in comments */
+boolean is_long_comment; /* is this a traditional \CEE/ comment? */
+int bal; /* brace balance */
+{
+ char c; /* current character being copied */
+ while (1) {
+ if (loc>limit) {
+ if (is_long_comment) {
+ if (get_line()==0) {
+ err_print("! Input ended in mid-comment");
+@.Input ended in mid-comment@>
+ loc=buffer+1; goto done;
+ }
+ }
+ else {
+ if (bal>1) err_print("! Missing } in comment");
+@.Missing \} in comment@>
+ goto done;
+ }
+ }
+ c=*(loc++);
+ if (c=='|') return(bal);
+ if (is_long_comment) @<Check for end of comment@>;
+ if (phase==2) {
+ if (ishigh(c)) app_tok(quoted_char);
+ app_tok(c);
+ }
+ @<Copy special things when |c=='@@', '\\'|@>;
+ if (c=='{') bal++;
+ else if (c=='}') {
+ if(bal>1) bal--;
+ else {err_print("! Extra } in comment");
+@.Extra \} in comment@>
+ if (phase==2) tok_ptr--;
+ }
+ }
+ }
+done:@<Clear |bal| and |return|@>;
+}
+
+@ @<Check for end of comment@>=
+if (c=='*' && *loc=='/') {
+ loc++;
+ if (bal>1) err_print("! Missing } in comment");
+@.Missing \} in comment@>
+ goto done;
+}
+
+@ @<Copy special things when |c=='@@'...@>=
+if (c=='@@') {
+ if (*(loc++)!='@@') {
+ err_print("! Illegal use of @@ in comment");
+@.Illegal use of @@...@>
+ loc-=2; if (phase==2) *(tok_ptr-1)=' '; goto done;
+ }
+}
+else if (c=='\\' && *loc!='@@')
+ if (phase==2) app_tok(*(loc++)) else loc++;
+
+@ We output
+enough right braces to keep \TEX/ happy.
+
+@<Clear |bal|...@>=
+if (phase==2) while (bal-- >0) app_tok('}');
+return(0);
+
+@** Parsing.
+The most intricate part of \.{CWEAVE} is its mechanism for converting
+\CEE/-like code into \TEX/ code, and we might as well plunge into this
+aspect of the program now. A ``bottom up'' approach is used to parse the
+\CEE/-like material, since \.{CWEAVE} must deal with fragmentary
+constructions whose overall ``part of speech'' is not known.
+
+At the lowest level, the input is represented as a sequence of entities
+that we shall call {\it scraps}, where each scrap of information consists
+of two parts, its {\it category} and its {\it translation}. The category
+is essentially a syntactic class, and the translation is a token list that
+represents \TEX/ code. Rules of syntax and semantics tell us how to
+combine adjacent scraps into larger ones, and if we are lucky an entire
+\CEE/ text that starts out as hundreds of small scraps will join
+together into one gigantic scrap whose translation is the desired \TEX/
+code. If we are unlucky, we will be left with several scraps that don't
+combine; their translations will simply be output, one by one.
+
+The combination rules are given as context-sensitive productions that are
+applied from left to right. Suppose that we are currently working on the
+sequence of scraps $s_1\,s_2\ldots s_n$. We try first to find the longest
+production that applies to an initial substring $s_1\,s_2\ldots\,$; but if
+no such productions exist, we try to find the longest production
+applicable to the next substring $s_2\,s_3\ldots\,$; and if that fails, we
+try to match $s_3\,s_4\ldots\,$, etc.
+
+A production applies if the category codes have a given pattern. For
+example, one of the productions (see rule~3) is
+$$\hbox{|exp| }\left\{\matrix{\hbox{|binop|}\cr\hbox{|unorbinop|}}\right\}
+\hbox{ |exp| }\RA\hbox{ |exp|}$$
+and it means that three consecutive scraps whose respective categories are
+|exp|, |binop| (or |unorbinop|),
+and |exp| are converted to one scrap whose category
+is |exp|. The translations of the original
+scraps are simply concatenated. The case of
+$$\hbox{|exp| |comma| |exp| $\RA$ |exp|} \hskip4emE_1C\,\\{opt}9\,E_2$$
+(rule 4) is only slightly more complicated:
+Here the resulting |exp| translation
+consists not only of the three original translations, but also of the
+tokens |opt| and 9 between the translations of the
+|comma| and the following |exp|.
+In the \TEX/ file, this will specify an optional line break after the
+comma, with penalty 90.
+
+At each opportunity the longest possible production is applied. For
+example, if the current sequence of scraps is |int_like| |cast|
+|lbrace|, rule 31 is applied; but if the sequence is |int_like| |cast|
+followed by anything other than |lbrace|, rule 32 takes effect.
+
+Translation rules such as `$E_1C\,\\{opt}9\,E_2$' above use subscripts
+to distinguish between translations of scraps whose categories have the
+same initial letter; these subscripts are assigned from left to right.
+
+@ Here is a list of the category codes that scraps can have.
+(A few others, like |int_like|, have already been defined; the
+|cat_name| array contains a complete list.)
+
+@d exp 1 /* denotes an expression, including perhaps a single identifier */
+@d unop 2 /* denotes a unary operator */
+@d binop 3 /* denotes a binary operator */
+@d unorbinop 4
+ /* denotes an operator that can be unary or binary, depending on context */
+@d cast 5 /* denotes a cast */
+@d question 6 /* denotes a question mark and possibly the expressions flanking it */
+@d lbrace 7 /* denotes a left brace */
+@d rbrace 8 /* denotes a right brace */
+@d decl_head 9 /* denotes an incomplete declaration */
+@d comma 10 /* denotes a comma */
+@d lpar 11 /* denotes a left parenthesis or left bracket */
+@d rpar 12 /* denotes a right parenthesis or right bracket */
+@d prelangle 13 /* denotes `$<$' before we know what it is */
+@d prerangle 14 /* denotes `$>$' before we know what it is */
+@d langle 15 /* denotes `$<$' when it's used as angle bracket in a template */
+@d colcol 18 /* denotes `::' */
+@d base 19 /* denotes a colon that introduces a base specifier */
+@d decl 20 /* denotes a complete declaration */
+@d struct_head 21 /* denotes the beginning of a structure specifier */
+@d stmt 23 /* denotes a complete statement */
+@d function 24 /* denotes a complete function */
+@d fn_decl 25 /* denotes a function declarator */
+@d semi 27 /* denotes a semicolon */
+@d colon 28 /* denotes a colon */
+@d tag 29 /* denotes a statement label */
+@d if_head 30 /* denotes the beginning of a compound conditional */
+@d else_head 31 /* denotes a prefix for a compound statement */
+@d if_clause 32 /* pending \.{if} together with a condition */
+@d lproc 35 /* begins a preprocessor command */
+@d rproc 36 /* ends a preprocessor command */
+@d insert 37 /* a scrap that gets combined with its neighbor */
+@d section_scrap 38 /* section name */
+@d dead 39 /* scrap that won't combine */
+@d begin_arg 58 /* \.{@@[} */
+@d end_arg 59 /* \.{@@]} */
+
+@<Glo...@>=
+char cat_name[256][12];
+eight_bits cat_index;
+
+@ @<Set in...@>=
+ for (cat_index=0;cat_index<255;cat_index++)
+ strcpy(cat_name[cat_index],"UNKNOWN");
+ strcpy(cat_name[exp],"exp");
+ strcpy(cat_name[unop],"unop");
+ strcpy(cat_name[binop],"binop");
+ strcpy(cat_name[unorbinop],"unorbinop");
+ strcpy(cat_name[cast],"cast");
+ strcpy(cat_name[question],"?");
+ strcpy(cat_name[lbrace],"{"@q}@>);
+ strcpy(cat_name[rbrace],@q{@>"}");
+ strcpy(cat_name[decl_head],"decl_head");
+ strcpy(cat_name[comma],",");
+ strcpy(cat_name[lpar],"(");
+ strcpy(cat_name[rpar],")");
+ strcpy(cat_name[prelangle],"<");
+ strcpy(cat_name[prerangle],">");
+ strcpy(cat_name[langle],"\\<");
+ strcpy(cat_name[colcol],"::");
+ strcpy(cat_name[base],"\\:");
+ strcpy(cat_name[decl],"decl");
+ strcpy(cat_name[struct_head],"struct_head");
+ strcpy(cat_name[stmt],"stmt");
+ strcpy(cat_name[function],"function");
+ strcpy(cat_name[fn_decl],"fn_decl");
+ strcpy(cat_name[else_like],"else_like");
+ strcpy(cat_name[semi],";");
+ strcpy(cat_name[colon],":");
+ strcpy(cat_name[tag],"tag");
+ strcpy(cat_name[if_head],"if_head");
+ strcpy(cat_name[else_head],"else_head");
+ strcpy(cat_name[if_clause],"if()");
+ strcpy(cat_name[lproc],"#{"@q}@>);
+ strcpy(cat_name[rproc],@q{@>"#}");
+ strcpy(cat_name[insert],"insert");
+ strcpy(cat_name[section_scrap],"section");
+ strcpy(cat_name[dead],"@@d");
+ strcpy(cat_name[public_like],"public");
+ strcpy(cat_name[operator_like],"operator");
+ strcpy(cat_name[new_like],"new");
+ strcpy(cat_name[catch_like],"catch");
+ strcpy(cat_name[for_like],"for");
+ strcpy(cat_name[do_like],"do");
+ strcpy(cat_name[if_like],"if");
+ strcpy(cat_name[raw_rpar],")?");
+ strcpy(cat_name[raw_unorbin],"unorbinop?");
+ strcpy(cat_name[const_like],"const");
+ strcpy(cat_name[raw_int],"raw");
+ strcpy(cat_name[int_like],"int");
+ strcpy(cat_name[case_like],"case");
+ strcpy(cat_name[sizeof_like],"sizeof");
+ strcpy(cat_name[struct_like],"struct");
+ strcpy(cat_name[typedef_like],"typedef");
+ strcpy(cat_name[define_like],"define");
+ strcpy(cat_name[begin_arg],"@@["@q]@>);
+ strcpy(cat_name[end_arg],@q[@>"@@]");
+ strcpy(cat_name[0],"zero");
+
+@ This code allows \.{CWEAVE} to display its parsing steps.
+
+@c
+void
+print_cat(c) /* symbolic printout of a category */
+eight_bits c;
+{
+ printf(cat_name[c]);
+}
+
+@ The token lists for translated \TEX/ output contain some special control
+symbols as well as ordinary characters. These control symbols are
+interpreted by \.{CWEAVE} before they are written to the output file.
+
+\yskip\hang |break_space| denotes an optional line break or an en space;
+
+\yskip\hang |force| denotes a line break;
+
+\yskip\hang |big_force| denotes a line break with additional vertical space;
+
+\yskip\hang |preproc_line| denotes that the line will be printed flush left;
+
+\yskip\hang |opt| denotes an optional line break (with the continuation
+line indented two ems with respect to the normal starting position)---this
+code is followed by an integer |n|, and the break will occur with penalty
+$10n$;
+
+\yskip\hang |backup| denotes a backspace of one em;
+
+\yskip\hang |cancel| obliterates any |break_space|, |opt|, |force|, or
+|big_force| tokens that immediately precede or follow it and also cancels any
+|backup| tokens that follow it;
+
+\yskip\hang |indent| causes future lines to be indented one more em;
+
+\yskip\hang |outdent| causes future lines to be indented one less em.
+
+\yskip\noindent All of these tokens are removed from the \TEX/ output that
+comes from \CEE/ text between \pb\ signs; |break_space| and |force| and
+|big_force| become single spaces in this mode. The translation of other
+\CEE/ texts results in \TEX/ control sequences \.{\\1}, \.{\\2},
+\.{\\3}, \.{\\4}, \.{\\5}, \.{\\6}, \.{\\7}, \.{\\8}
+corresponding respectively to
+|indent|, |outdent|, |opt|, |backup|, |break_space|, |force|,
+|big_force| and |preproc_line|.
+However, a sequence of consecutive `\.\ ', |break_space|,
+|force|, and/or |big_force| tokens is first replaced by a single token
+(the maximum of the given ones).
+
+The token |math_rel| will be translated into
+\.{\\MRL\{}, and it will get a matching \.\} later.
+Other control sequences in the \TEX/ output will be
+`\.{\\\\\{}$\,\ldots\,$\.\}'
+surrounding identifiers, `\.{\\\&\{}$\,\ldots\,$\.\}' surrounding
+reserved words, `\.{\\.\{}$\,\ldots\,$\.\}' surrounding strings,
+`\.{\\C\{}$\,\ldots\,$\.\}$\,$|force|' surrounding comments, and
+`\.{\\X$n$:}$\,\ldots\,$\.{\\X}' surrounding section names, where
+|n| is the section number.
+
+@d math_rel 0206
+@d big_cancel 0210 /* like |cancel|, also overrides spaces */
+@d cancel 0211 /* overrides |backup|, |break_space|, |force|, |big_force| */
+@d indent 0212 /* one more tab (\.{\\1}) */
+@d outdent 0213 /* one less tab (\.{\\2}) */
+@d opt 0214 /* optional break in mid-statement (\.{\\3}) */
+@d backup 0215 /* stick out one unit to the left (\.{\\4}) */
+@d break_space 0216 /* optional break between statements (\.{\\5}) */
+@d force 0217 /* forced break between statements (\.{\\6}) */
+@d big_force 0220 /* forced break with additional space (\.{\\7}) */
+@d preproc_line 0221 /* begin line without indentation (\.{\\8}) */
+@^high-bit character handling@>
+@d quoted_char 0222
+ /* introduces a character token in the range |0200|--|0377| */
+@d end_translation 0223 /* special sentinel token at end of list */
+@d inserted 0224 /* sentinel to mark translations of inserts */
+
+@ The raw input is converted into scraps according to the following table,
+which gives category codes followed by the translations.
+\def\stars {\.{**}}%
+The symbol `\stars' stands for `\.{\\\&\{{\rm identifier}\}}',
+i.e., the identifier itself treated as a reserved word.
+The right-hand column is the so-called |mathness|, which is explained
+further below.
+
+An identifier |c| of length 1 is translated as \.{\\\v c} instead of
+as \.{\\\\\{c\}}. An identifier \.{CAPS} in all caps is translated as
+\.{\\.\{CAPS\}} instead of as \.{\\\\\{CAPS\}}. An identifier that has
+become a reserved word via |typedef| is translated with \.{\\\&} replacing
+\.{\\\\} and |raw_int| replacing |exp|.
+
+A string of length greater than 20 is broken into pieces of size at most~20
+with discretionary breaks in between.
+
+\yskip\halign{\quad#\hfil&\quad#\hfil&\quad\hfil#\hfil\cr
+\.{!=}&|binop|: \.{\\I}&yes\cr
+\.{<=}&|binop|: \.{\\Z}&yes\cr
+\.{>=}&|binop|: \.{\\G}&yes\cr
+\.{==}&|binop|: \.{\\E}&yes\cr
+\.{\&\&}&|binop|: \.{\\W}&yes\cr
+\.{\v\v}&|binop|: \.{\\V}&yes\cr
+\.{++}&|binop|: \.{\\PP}&yes\cr
+\.{--}&|binop|: \.{\\MM}&yes\cr
+\.{->}&|binop|: \.{\\MG}&yes\cr
+\.{>>}&|binop|: \.{\\GG}&yes\cr
+\.{<<}&|binop|: \.{\\LL}&yes\cr
+\.{::}&|colcol|: \.{\\DC}&maybe\cr
+\.{.*}&|binop|: \.{\\PA}&yes\cr
+\.{->*}&|binop|: \.{\\MGA}&yes\cr
+\.{...}&|exp|: \.{\\,\\ldots\\,}&yes\cr
+\."string\."&|exp|: \.{\\.\{}string with special characters quoted\.\}&maybe\cr
+\.{@@=}string\.{@@>}&|exp|: \.{\\vb\{}string with special characters
+ quoted\.\}&maybe\cr
+\.{@@'7'}&|exp|: \.{\\.\{@@'7'\}}&maybe\cr
+\.{077} or \.{\\77}&|exp|: \.{\\T\{\\\~77\}}&maybe\cr
+\.{0x7f}&|exp|: \.{\\T\{\\\^7f\}}&maybe\cr
+\.{77}&|exp|: \.{\\T\{77\}}&maybe\cr
+\.{77L}&|exp|: \.{\\T\{77\\\$L\}}&maybe\cr
+\.{0.1E5}&|exp|: \.{\\T\{0.1\\\_5\}}&maybe\cr
+\.+&|unorbinop|: \.+&yes\cr
+\.-&|unorbinop|: \.-&yes\cr
+\.*&|raw_unorbin|: \.*&yes\cr
+\./&|binop|: \./&yes\cr
+\.<&|prelangle|: \.{\\langle}&yes\cr
+\.=&|binop|: \.{\\K}&yes\cr
+\.>&|prerangle|: \.{\\rangle}&yes\cr
+\..&|binop|: \..&yes\cr
+\.{\v}&|binop|: \.{\\OR}&yes\cr
+\.\^&|binop|: \.{\\XOR}&yes\cr
+\.\%&|binop|: \.{\\MOD}&yes\cr
+\.?&|question|: \.{\\?}&yes\cr
+\.!&|unop|: \.{\\R}&yes\cr
+\.\~&|unop|: \.{\\CM}&yes\cr
+\.\&&|raw_unorbin|: \.{\\AND}&yes\cr
+\.(&|lpar|: \.(&maybe\cr
+\.[&|lpar|: \.[&maybe\cr
+\.)&|raw_rpar|: \.)&maybe\cr
+\.]&|raw_rpar|: \.]&maybe\cr
+\.\{&|lbrace|: \.\{&yes\cr
+\.\}&|lbrace|: \.\}&yes\cr
+\.,&|comma|: \.,&yes\cr
+\.;&|semi|: \.;&maybe\cr
+\.:&|colon|: \.:&maybe\cr
+\.\# (within line)&|unorbinop|: \.{\\\#}&yes\cr
+\.\# (at beginning)&|lproc|: |force| |preproc_line| \.{\\\#}&no\cr
+end of \.\# line&|rproc|: |force|&no\cr
+identifier&|exp|: \.{\\\\\{}identifier with underlines quoted\.\}&maybe\cr
+\.{asm}&|sizeof_like|: \stars&maybe\cr
+\.{auto}&|int_like|: \stars&maybe\cr
+\.{break}&|case_like|: \stars&maybe\cr
+\.{case}&|case_like|: \stars&maybe\cr
+\.{catch}&|catch_like|: \stars&maybe\cr
+\.{char}&|raw_int|: \stars&maybe\cr
+\.{class}&|struct_like|: \stars&maybe\cr
+\.{clock\_t}&|raw_int|: \stars&maybe\cr
+\.{const}&|const_like|: \stars&maybe\cr
+\.{continue}&|case_like|: \stars&maybe\cr
+\.{default}&|case_like|: \stars&maybe\cr
+\.{define}&|define_like|: \stars&maybe\cr
+\.{defined}&|sizeof_like|: \stars&maybe\cr
+\.{delete}&|sizeof_like|: \stars&maybe\cr
+\.{div\_t}&|raw_int|: \stars&maybe\cr
+\.{do}&|do_like|: \stars&maybe\cr
+\.{double}&|raw_int|: \stars&maybe\cr
+\.{elif}&|if_like|: \stars&maybe\cr
+\.{else}&|else_like|: \stars&maybe\cr
+\.{endif}&|if_like|: \stars&maybe\cr
+\.{enum}&|struct_like|: \stars&maybe\cr
+\.{error}&|if_like|: \stars&maybe\cr
+\.{extern}&|int_like|: \stars&maybe\cr
+\.{FILE}&|raw_int|: \stars&maybe\cr
+\.{float}&|raw_int|: \stars&maybe\cr
+\.{for}&|for_like|: \stars&maybe\cr
+\.{fpos\_t}&|raw_int|: \stars&maybe\cr
+\.{friend}&|int_like|: \stars&maybe\cr
+\.{goto}&|case_like|: \stars&maybe\cr
+\.{if}&|if_like|: \stars&maybe\cr
+\.{ifdef}&|if_like|: \stars&maybe\cr
+\.{ifndef}&|if_like|: \stars&maybe\cr
+\.{include}&|if_like|: \stars&maybe\cr
+\.{inline}&|int_like|: \stars&maybe\cr
+\.{int}&|raw_int|: \stars&maybe\cr
+\.{jmp\_buf}&|raw_int|: \stars&maybe\cr
+\.{ldiv\_t}&|raw_int|: \stars&maybe\cr
+\.{line}&|if_like|: \stars&maybe\cr
+\.{long}&|raw_int|: \stars&maybe\cr
+\.{new}&|new_like|: \stars&maybe\cr
+\.{NULL}&|exp|: \.{\\NULL}&yes\cr
+\.{offsetof}&|sizeof_like|: \stars&maybe\cr
+\.{operator}&|operator_like|: \stars&maybe\cr
+\.{pragma}&|if_like|: \stars&maybe\cr
+\.{private}&|public_like|: \stars&maybe\cr
+\.{protected}&|public_like|: \stars&maybe\cr
+\.{ptrdiff\_t}&|raw_int|: \stars&maybe\cr
+\.{public}&|public_like|: \stars&maybe\cr
+\.{register}&|int_like|: \stars&maybe\cr
+\.{return}&|case_like|: \stars&maybe\cr
+\.{short}&|raw_int|: \stars&maybe\cr
+\.{sig\_atomic\_t}&|raw_int|: \stars&maybe\cr
+\.{signed}&|raw_int|: \stars&maybe\cr
+\.{size\_t}&|raw_int|: \stars&maybe\cr
+\.{sizeof}&|sizeof_like|: \stars&maybe\cr
+\.{static}&|int_like|: \stars&maybe\cr
+\.{struct}&|struct_like|: \stars&maybe\cr
+\.{switch}&|if_like|: \stars&maybe\cr
+\.{template}&|int_like|: \stars&maybe\cr
+\.{TeX}&|exp|: \.{\\TeX}&yes\cr
+\.{this}&|exp|: \.{\\this}&yes\cr
+\.{throw}&|case_like|: \stars&maybe\cr
+\.{time\_t}&|raw_int|: \stars&maybe\cr
+\.{try}&|else_like|: \stars&maybe\cr
+\.{typedef}&|typedef_like|: \stars&maybe\cr
+\.{undef}&|if_like|: \stars&maybe\cr
+\.{union}&|struct_like|: \stars&maybe\cr
+\.{unsigned}&|raw_int|: \stars&maybe\cr
+\.{va\_dcl}&|decl|: \stars&maybe\cr
+\.{va\_list}&|raw_int|: \stars&maybe\cr
+\.{virtual}&|int_like|: \stars&maybe\cr
+\.{void}&|raw_int|: \stars&maybe\cr
+\.{volatile}&|const_like|: \stars&maybe\cr
+\.{wchar\_t}&|raw_int|: \stars&maybe\cr
+\.{while}&|if_like|: \stars&maybe\cr
+\.{@@,}&|insert|: \.{\\,}&maybe\cr
+\.{@@\v}&|insert|: |opt| \.0&maybe\cr
+\.{@@/}&|insert|: |force|&no\cr
+\.{@@\#}&|insert|: |big_force|&no\cr
+\.{@@+}&|insert|: |big_cancel| \.{\{\}} |break_space|
+ \.{\{\}} |big_cancel|&no\cr
+\.{@@;}&|semi|: &maybe\cr
+\.{@@[@q]@>}&|begin_arg|: &maybe\cr
+\.{@q[@>@@]}&|end_arg|: &maybe\cr
+\.{@@\&}&|insert|: \.{\\J}&maybe\cr
+\.{@@h}&|insert|: |force| \.{\\ATH} |force|&no\cr
+\.{@@<}\thinspace section name\thinspace\.{@@>}&|section_scrap|:
+ \.{\\X}$n$\.:translated section name\.{\\X}&maybe\cr
+\.{@@(@q)@>}\thinspace section name\thinspace\.{@@>}&|section_scrap|:
+ \.{\\X}$n$\.{:\\.\{}section name with special characters
+ quoted\.{\ \}\\X}&maybe\cr
+\.{/*}comment\.{*/}&|insert|: |cancel|
+ \.{\\C\{}translated comment\.\} |force|&no\cr
+\.{//}comment&|insert|: |cancel|
+ \.{\\SHC\{}translated comment\.\} |force|&no\cr
+}
+
+The construction \.{@@t}\thinspace stuff\/\thinspace\.{@@>} contributes
+\.{\\hbox\{}\thinspace stuff\/\thinspace\.\} to the following scrap.
+
+@i prod.w
+
+@* Implementing the productions.
+More specifically, a scrap is a structure consisting of a category
+|cat| and a |text_pointer| |trans|, which points to the translation in
+|tok_start|. When \CEE/ text is to be processed with the grammar above,
+we form an array |scrap_info| containing the initial scraps.
+Our production rules have the nice property that the right-hand side is never
+longer than the left-hand side. Therefore it is convenient to use sequential
+allocation for the current sequence of scraps. Five pointers are used to
+manage the parsing:
+
+\yskip\hang |pp| is a pointer into |scrap_info|. We will try to match
+the category codes |pp->cat,@,@,(pp+1)->cat|$,\,\,\ldots\,$
+to the left-hand sides of productions.
+
+\yskip\hang |scrap_base|, |lo_ptr|, |hi_ptr|, and |scrap_ptr| are such that
+the current sequence of scraps appears in positions |scrap_base| through
+|lo_ptr| and |hi_ptr| through |scrap_ptr|, inclusive, in the |cat| and
+|trans| arrays. Scraps located between |scrap_base| and |lo_ptr| have
+been examined, while those in positions |>=hi_ptr| have not yet been
+looked at by the parsing process.
+
+\yskip\noindent Initially |scrap_ptr| is set to the position of the final
+scrap to be parsed, and it doesn't change its value. The parsing process
+makes sure that |lo_ptr>=pp+3|, since productions have as many as four terms,
+by moving scraps from |hi_ptr| to |lo_ptr|. If there are
+fewer than |pp+3| scraps left, the positions up to |pp+3| are filled with
+blanks that will not match in any productions. Parsing stops when
+|pp==lo_ptr+1| and |hi_ptr==scrap_ptr+1|.
+
+Since the |scrap| structure will later be used for other purposes, we
+declare its second element as unions.
+
+@<Type...@>=
+typedef struct {
+ eight_bits cat;
+ eight_bits mathness;
+ union {
+ text_pointer Trans;
+ @<Rest of |trans_plus| union@>@;
+ } trans_plus;
+} scrap;
+typedef scrap *scrap_pointer;
+
+@ @d trans trans_plus.Trans /* translation texts of scraps */
+
+@<Global...@>=
+scrap scrap_info[max_scraps]; /* memory array for scraps */
+scrap_pointer scrap_info_end=scrap_info+max_scraps -1; /* end of |scrap_info| */
+scrap_pointer pp; /* current position for reducing productions */
+scrap_pointer scrap_base; /* beginning of the current scrap sequence */
+scrap_pointer scrap_ptr; /* ending of the current scrap sequence */
+scrap_pointer lo_ptr; /* last scrap that has been examined */
+scrap_pointer hi_ptr; /* first scrap that has not been examined */
+scrap_pointer max_scr_ptr; /* largest value assumed by |scrap_ptr| */
+
+@ @<Set init...@>=
+scrap_base=scrap_info+1;
+max_scr_ptr=scrap_ptr=scrap_info;
+
+@ Token lists in |@!tok_mem| are composed of the following kinds of
+items for \TEX/ output.
+
+\yskip\item{$\bullet$}Character codes and special codes like |force| and
+|math_rel| represent themselves;
+
+\item{$\bullet$}|id_flag+p| represents \.{\\\\\{{\rm identifier $p$}\}};
+
+\item{$\bullet$}|res_flag+p| represents \.{\\\&\{{\rm identifier $p$}\}};
+
+\item{$\bullet$}|section_flag+p| represents section name |p|;
+
+\item{$\bullet$}|tok_flag+p| represents token list number |p|;
+
+\item{$\bullet$}|inner_tok_flag+p| represents token list number |p|, to be
+translated without line-break controls.
+
+@d id_flag 10240 /* signifies an identifier */
+@d res_flag 2*id_flag /* signifies a reserved word */
+@d section_flag 3*id_flag /* signifies a section name */
+@d tok_flag 4*id_flag /* signifies a token list */
+@d inner_tok_flag 5*id_flag /* signifies a token list in `\pb' */
+
+@c
+void
+print_text(p) /* prints a token list for debugging; not used in |main| */
+text_pointer p;
+{
+ token_pointer j; /* index into |tok_mem| */
+ sixteen_bits r; /* remainder of token after the flag has been stripped off */
+ if (p>=text_ptr) printf("BAD");
+ else for (j=*p; j<*(p+1); j++) {
+ r=*j%id_flag;
+ switch (*j/id_flag) {
+ case 1: printf("\\\\{"@q}@>); print_id((name_dir+r)); printf(@q{@>"}");
+ break; /* |id_flag| */
+ case 2: printf("\\&{"@q}@>); print_id((name_dir+r)); printf(@q{@>"}");
+ break; /* |res_flag| */
+ case 3: printf("<"); print_section_name((name_dir+r)); printf(">");
+ break; /* |section_flag| */
+ case 4: printf("[[%d]]",r); break; /* |tok_flag| */
+ case 5: printf("|[[%d]]|",r); break; /* |inner_tok_flag| */
+ default: @<Print token |r| in symbolic form@>;
+ }
+ }
+ fflush(stdout);
+}
+
+@ @<Print token |r|...@>=
+switch (r) {
+ case math_rel: printf("\\mathrel{"@q}@>); break;
+ case big_cancel: printf("[ccancel]"); break;
+ case cancel: printf("[cancel]"); break;
+ case indent: printf("[indent]"); break;
+ case outdent: printf("[outdent]"); break;
+ case backup: printf("[backup]"); break;
+ case opt: printf("[opt]"); break;
+ case break_space: printf("[break]"); break;
+ case force: printf("[force]"); break;
+ case big_force: printf("[fforce]"); break;
+ case preproc_line: printf("[preproc]"); break;
+ case quoted_char: j++; printf("[%o]",(unsigned)*j); break;
+ case end_translation: printf("[quit]"); break;
+ case inserted: printf("[inserted]"); break;
+ default: putxchar(r);
+}
+
+@ The production rules listed above are embedded directly into \.{CWEAVE},
+since it is easier to do this than to write an interpretive system
+that would handle production systems in general. Several macros are defined
+here so that the program for each production is fairly short.
+
+All of our productions conform to the general notion that some |k|
+consecutive scraps starting at some position |j| are to be replaced by a
+single scrap of some category |c| whose translation is composed from the
+translations of the disappearing scraps. After this production has been
+applied, the production pointer |pp| should change by an amount |d|. Such
+a production can be represented by the quadruple |(j,k,c,d)|. For example,
+the production `|exp@,comma@,exp| $\RA$ |exp|' would be represented by
+`|(pp,3,exp,-2)|'; in this case the pointer |pp| should decrease by 2
+after the production has been applied, because some productions with
+|exp| in their second or third positions might now match,
+but no productions have
+|exp| in the fourth position of their left-hand sides. Note that
+the value of |d| is determined by the whole collection of productions, not
+by an individual one.
+The determination of |d| has been
+done by hand in each case, based on the full set of productions but not on
+the grammar of \CEE/ or on the rules for constructing the initial
+scraps.
+
+We also attach a serial number to each production, so that additional
+information is available when debugging. For example, the program below
+contains the statement `|reduce(pp,3,exp,-2,4)|' when it implements
+the production just mentioned.
+
+Before calling |reduce|, the program should have appended the tokens of
+the new translation to the |tok_mem| array. We commonly want to append
+copies of several existing translations, and macros are defined to
+simplify these common cases. For example, \\{app2}|(pp)| will append the
+translations of two consecutive scraps, |pp->trans| and |(pp+1)->trans|, to
+the current token list. If the entire new translation is formed in this
+way, we write `|squash(j,k,c,d,n)|' instead of `|reduce(j,k,c,d,n)|'. For
+example, `|squash(pp,3,exp,-2,3)|' is an abbreviation for `\\{app3}|(pp);
+reduce(pp,3,exp,-2,3)|'.
+
+A couple more words of explanation:
+Both |big_app| and |app| append a token (while |big_app1| to |big_app4|
+append the specified number of scrap translations) to the current token list.
+The difference between |big_app| and |app| is simply that |big_app|
+checks whether there can be a conflict between math and non-math
+tokens, and intercalates a `\.{\$}' token if necessary. When in
+doubt what to use, use |big_app|.
+
+The |mathness| is an attribute of scraps that says whether they are
+to be printed in a math mode context or not. It is separate from the
+``part of speech'' (the |cat|) because to make each |cat| have
+a fixed |mathness| (as in the original \.{WEAVE}) would multiply the
+number of necessary production rules.
+
+The low two bits (i.e. |mathness % 4|) control the left boundary.
+(We need two bits because we allow cases |yes_math|, |no_math| and
+|maybe_math|, which can go either way.)
+The next two bits (i.e. |mathness / 4|) control the right boundary.
+If we combine two scraps and the right boundary of the first has
+a different mathness from the left boundary of the second, we
+insert a \.{\$} in between. Similarly, if at printing time some
+irreducible scrap has a |yes_math| boundary the scrap gets preceded
+or followed by a \.{\$}. The left boundary is |maybe_math| if and
+only if the right boundary is.
+
+The code below is an exact translation of the production rules into
+\CEE/, using such macros, and the reader should have no difficulty
+understanding the format by comparing the code with the symbolic
+productions as they were listed earlier.
+
+@d no_math 2 /* should be in horizontal mode */
+@d yes_math 1 /* should be in math mode */
+@d maybe_math 0 /* works in either horizontal or math mode */
+@d big_app2(a) big_app1(a);big_app1(a+1)
+@d big_app3(a) big_app2(a);big_app1(a+2)
+@d big_app4(a) big_app3(a);big_app1(a+3)
+@d app(a) *(tok_ptr++)=a
+@d app1(a) *(tok_ptr++)=tok_flag+(int)((a)->trans-tok_start)
+
+@<Global...@>=
+int cur_mathness, init_mathness;
+
+@ @c
+void
+app_str(s)
+char *s;
+{
+ while (*s) app_tok(*(s++));
+}
+
+void
+big_app(a)
+token a;
+{
+ if (a==' ' || (a>=big_cancel && a<=big_force)) /* non-math token */ {
+ if (cur_mathness==maybe_math) init_mathness=no_math;
+ else if (cur_mathness==yes_math) app_str("{}$");
+ cur_mathness=no_math;
+ }
+ else {
+ if (cur_mathness==maybe_math) init_mathness=yes_math;
+ else if (cur_mathness==no_math) app_str("${}");
+ cur_mathness=yes_math;
+ }
+ app(a);
+}
+
+void
+big_app1(a)
+scrap_pointer a;
+{
+ switch (a->mathness % 4) { /* left boundary */
+ case (no_math):
+ if (cur_mathness==maybe_math) init_mathness=no_math;
+ else if (cur_mathness==yes_math) app_str("{}$");
+ cur_mathness=a->mathness / 4; /* right boundary */
+ break;
+ case (yes_math):
+ if (cur_mathness==maybe_math) init_mathness=yes_math;
+ else if (cur_mathness==no_math) app_str("${}");
+ cur_mathness=a->mathness / 4; /* right boundary */
+ break;
+ case (maybe_math): /* no changes */ break;
+ }
+ app(tok_flag+(int)((a)->trans-tok_start));
+}
+
+@ Let us consider the big switch for productions now, before looking
+at its context. We want to design the program so that this switch
+works, so we might as well not keep ourselves in suspense about exactly what
+code needs to be provided with a proper environment.
+
+@d cat1 (pp+1)->cat
+@d cat2 (pp+2)->cat
+@d cat3 (pp+3)->cat
+@d lhs_not_simple (pp->cat!=semi && pp->cat!=raw_int && pp->cat!=raw_unorbin
+ && pp->cat!=raw_rpar && pp->cat!=const_like)
+
+@<Match a production at |pp|, or increase |pp| if there is no match@>= {
+ if (cat1==end_arg && lhs_not_simple)
+ if (pp->cat==begin_arg) squash(pp,2,exp,-2,110);
+ else squash(pp,2,end_arg,-1,111);
+ else if (cat1==insert) squash(pp,2,pp->cat,-2,0);
+ else if (cat2==insert) squash(pp+1,2,(pp+1)->cat,-1,0);
+ else if (cat3==insert) squash(pp+2,2,(pp+2)->cat,0,0);
+ else
+ switch (pp->cat) {
+ case exp: @<Cases for |exp|@>; @+break;
+ case lpar: @<Cases for |lpar|@>; @+break;
+ case question: @<Cases for |question|@>; @+break;
+ case unop: @<Cases for |unop|@>; @+break;
+ case unorbinop: @<Cases for |unorbinop|@>; @+break;
+ case binop: @<Cases for |binop|@>; @+break;
+ case cast: @<Cases for |cast|@>; @+break;
+ case sizeof_like: @<Cases for |sizeof_like|@>; @+break;
+ case int_like: @<Cases for |int_like|@>; @+break;
+ case decl_head: @<Cases for |decl_head|@>; @+break;
+ case decl: @<Cases for |decl|@>; @+break;
+ case typedef_like: @<Cases for |typedef_like|@>; @+break;
+ case struct_like: @<Cases for |struct_like|@>; @+break;
+ case struct_head: @<Cases for |struct_head|@>; @+break;
+ case fn_decl: @<Cases for |fn_decl|@>; @+break;
+ case function: @<Cases for |function|@>; @+break;
+ case lbrace: @<Cases for |lbrace|@>; @+break;
+ case do_like: @<Cases for |do_like|@>; @+break;
+ case if_like: @<Cases for |if_like|@>; @+break;
+ case for_like: @<Cases for |for_like|@>; @+break;
+ case else_like: @<Cases for |else_like|@>; @+break;
+ case if_clause: @<Cases for |if_clause|@>; @+break;
+ case if_head: @<Cases for |if_head|@>; @+break;
+ case else_head: @<Cases for |else_head|@>; @+break;
+ case case_like: @<Cases for |case_like|@>; @+break;
+ case stmt: @<Cases for |stmt|@>; @+break;
+ case tag: @<Cases for |tag|@>; @+break;
+ case semi: @<Cases for |semi|@>; @+break;
+ case lproc: @<Cases for |lproc|@>; @+break;
+ case section_scrap: @<Cases for |section_scrap|@>; @+break;
+ case insert: @<Cases for |insert|@>; @+break;
+ case prelangle: @<Cases for |prelangle|@>; @+break;
+ case prerangle: @<Cases for |prerangle|@>; @+break;
+ case langle: @<Cases for |langle|@>; @+break;
+ case public_like: @<Cases for |public_like|@>; @+break;
+ case colcol: @<Cases for |colcol|@>; @+break;
+ case new_like: @<Cases for |new_like|@>; @+break;
+ case operator_like: @<Cases for |operator_like|@>; @+break;
+ case catch_like: @<Cases for |catch_like|@>; @+break;
+ case base: @<Cases for |base|@>; @+break;
+ case raw_rpar: @<Cases for |raw_rpar|@>; @+break;
+ case raw_unorbin: @<Cases for |raw_unorbin|@>; @+break;
+ case const_like: @<Cases for |const_like|@>; @+break;
+ case raw_int: @<Cases for |raw_int|@>; @+break;
+ }
+ pp++; /* if no match was found, we move to the right */
+}
+
+@ In \CEE/, new specifier names can be defined via |typedef|, and we want
+to make the parser recognize future occurrences of the identifier thus
+defined as specifiers. This is done by the procedure |make_reserved|,
+which changes the |ilk| of the relevant identifier.
+
+We first need a procedure to recursively seek the first
+identifier in a token list, because the identifier might
+be enclosed in parentheses, as when one defines a function
+returning a pointer.
+
+@d no_ident_found 0 /* distinct from any identifier token */
+
+@c
+token_pointer
+find_first_ident(p)
+text_pointer p;
+{
+ token_pointer q; /* token to be returned */
+ token_pointer j; /* token being looked at */
+ sixteen_bits r; /* remainder of token after the flag has been stripped off */
+ if (p>=text_ptr) confusion("find_first_ident");
+ for (j=*p; j<*(p+1); j++) {
+ r=*j%id_flag;
+ switch (*j/id_flag) {
+ case 1: case 2: return j;
+ case 4: case 5: /* |tok_flag| or |inner_tok_flag| */
+ if ((q=find_first_ident(tok_start+r))!=no_ident_found)
+ return q;
+ default: ; /* char, |section_flag|, fall thru: move on to next token */
+ if (*j==inserted) return no_ident_found; /* ignore inserts */
+ }
+ }
+ return no_ident_found;
+}
+
+@ The scraps currently being parsed must be inspected for any
+occurrence of the identifier that we're making reserved; hence
+the |for| loop below.
+
+@c
+void
+make_reserved(p) /* make the first identifier in |p->trans| like |int| */
+scrap_pointer p;
+{
+ sixteen_bits tok_value; /* the name of this identifier, plus its flag*/
+ token_pointer tok_loc; /* pointer to |tok_value| */
+ if ((tok_loc=find_first_ident(p->trans))==no_ident_found)
+ return; /* this should not happen */
+ tok_value=*tok_loc;
+ for (;p<=scrap_ptr; p==lo_ptr? p=hi_ptr: p++) {
+ if (p->cat==exp) {
+ if (**(p->trans)==tok_value) {
+ p->cat=raw_int;
+ **(p->trans)=tok_value%id_flag+res_flag;
+ }
+ }
+ }
+ (name_dir+(sixteen_bits)(tok_value%id_flag))->ilk=raw_int;
+ *tok_loc=tok_value%id_flag+res_flag;
+}
+
+@ In the following situations we want to mark the occurrence of
+an identifier as a definition: when |make_reserved| is just about to be
+used; after a specifier, as in |char **argv|;
+before a colon, as in \\{found}:; and in the declaration of a function,
+as in \\{main}()$\{\ldots;\}$. This is accomplished by the invocation
+of |make_underlined| at appropriate times. Notice that, in the declaration
+of a function, we only find out that the identifier is being defined after
+it has been swallowed up by an |exp|.
+
+@c
+void
+make_underlined(p)
+/* underline the entry for the first identifier in |p->trans| */
+scrap_pointer p;
+{
+ token_pointer tok_loc; /* where the first identifier appears */
+ if ((tok_loc=find_first_ident(p->trans))==no_ident_found)
+ return; /* this happens after parsing the |()| in |double f();| */
+ xref_switch=def_flag;
+ underline_xref(*tok_loc%id_flag+name_dir);
+}
+
+@ We cannot use |new_xref| to underline a cross-reference at this point
+because this would just make a new cross-reference at the end of the list.
+We actually have to search through the list for the existing
+cross-reference.
+
+@<Predecl...@>=
+void underline_xref();
+
+@ @c
+void
+underline_xref(p)
+name_pointer p;
+{
+ xref_pointer q=(xref_pointer)p->xref; /* pointer to cross-reference being examined */
+ xref_pointer r; /* temporary pointer for permuting cross-references */
+ sixteen_bits m; /* cross-reference value to be installed */
+ sixteen_bits n; /* cross-reference value being examined */
+ if (no_xref) return;
+ m=section_count+xref_switch;
+ while (q != xmem) {
+ n=q->num;
+ if (n==m) return;
+ else if (m==n+def_flag) {
+ q->num=m; return;
+ }
+ else if (n>=def_flag && n<m) break;
+ q=q->xlink;
+ }
+ @<Insert new cross-reference at |q|, not at beginning of list@>;
+}
+
+@ We get to this section only when the identifier is one letter long,
+so it didn't get a non-underlined entry during phase one. But it may
+have got some explicitly underlined entries in later sections, so in order
+to preserve the numerical order of the entries in the index, we have
+to insert the new cross-reference not at the beginning of the list
+(namely, at |p->xref|), but rather right before |q|.
+
+@<Insert new cross-reference at |q|...@>=
+ append_xref(0); /* this number doesn't matter */
+ xref_ptr->xlink=(xref_pointer)p->xref; r=xref_ptr;
+ p->xref=(char*)xref_ptr;
+ while (r->xlink!=q) {r->num=r->xlink->num; r=r->xlink;}
+ r->num=m; /* everything from |q| on is left undisturbed */
+
+@ Now comes the code that tries to match each production starting
+with a particular type of scrap. Whenever a match is discovered,
+the |squash| or |reduce| macro will cause the appropriate action
+to be performed, followed by |goto found|.
+
+@<Cases for |exp|@>=
+if (cat1==lbrace || cat1==int_like || cat1==decl) {
+ make_underlined(pp); big_app1(pp); big_app(indent); app(indent);
+ reduce(pp,1,fn_decl,0,1);
+}
+else if (cat1==unop) squash(pp,2,exp,-2,2);
+else if ((cat1==binop || cat1==unorbinop) && cat2==exp)
+ squash(pp,3,exp,-2,3);
+else if (cat1==comma && cat2==exp) {
+ big_app2(pp);
+ app(opt); app('9'); big_app1(pp+2); reduce(pp,3,exp,-2,4);
+}
+else if (cat1==exp || cat1==cast) squash(pp,2,exp,-2,5);
+else if (cat1==semi) squash(pp,2,stmt,-1,6);
+else if (cat1==colon) {
+ make_underlined (pp); squash(pp,2,tag,0,7);
+}
+else if (cat1==base) {
+ if (cat2==int_like && cat3==comma) {
+ big_app1(pp+1); big_app(' '); big_app2(pp+2);
+ app(opt); app('9'); reduce(pp+1,3,base,0,8);
+ }
+ else if (cat2==int_like && cat3==lbrace) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); big_app(' '); big_app1(pp+2);
+ reduce(pp,3,exp,-1,9);
+ }
+}
+else if (cat1==rbrace) squash(pp,1,stmt,-1,10);
+
+@ @<Cases for |lpar|@>=
+if ((cat1==exp||cat1==unorbinop) && cat2==rpar) squash(pp,3,exp,-2,11);
+else if (cat1==rpar) {
+ big_app1(pp); app('\\'); app(','); big_app1(pp+1);
+@.\\,@>
+ reduce(pp,2,exp,-2,12);
+}
+else if (cat1==decl_head || cat1==int_like || cat1==exp) {
+ if (cat2==rpar) squash(pp,3,cast,-2,13);
+ else if (cat2==comma) {
+ big_app3(pp); app(opt); app('9'); reduce(pp,3,lpar,0,14);
+ }
+}
+else if (cat1==stmt || cat1==decl) {
+ big_app2(pp); big_app(' '); reduce(pp,2,lpar,0,15);
+}
+
+@ @<Cases for |question|@>=
+if (cat1==exp && cat2==colon) squash(pp,3,binop,-2,16);
+
+@ @<Cases for |unop|@>=
+if (cat1==exp || cat1==int_like) squash(pp,2,cat1,-2,17);
+
+@ @<Cases for |unorbinop|@>=
+if (cat1==exp || cat1==int_like) {
+ big_app('{'); big_app1(pp); big_app('}'); big_app1(pp+1);
+ reduce(pp,2,cat1,-2,18);
+}
+else if (cat1==binop) {
+ big_app(math_rel); big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
+ big_app('}'); reduce(pp,2,binop,-1,19);
+}
+
+@ @<Cases for |binop|@>=
+if (cat1==binop) {
+ big_app(math_rel); big_app('{'); big_app1(pp); big_app('}');
+ big_app('{'); big_app1(pp+1); big_app('}');
+ big_app('}'); reduce(pp,2,binop,-1,20);
+}
+
+@ @<Cases for |cast|@>=
+if (cat1==exp) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,21);
+}
+else if (cat1==semi) squash(pp,1,exp,-2,22);
+
+@ @<Cases for |sizeof_like|@>=
+if (cat1==cast) squash(pp,2,exp,-2,23);
+else if (cat1==exp) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,24);
+}
+
+@ @<Cases for |int_like|@>=
+if (cat1==int_like|| cat1==struct_like) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,cat1,-2,25);
+}
+else if (cat1==exp && (cat2==raw_int||cat2==struct_like))
+ squash(pp,2,int_like,-2,26);
+else if (cat1==exp || cat1==unorbinop || cat1==semi) {
+ big_app1(pp);
+ if (cat1!=semi) big_app(' ');
+ reduce(pp,1,decl_head,-1,27);
+}
+else if (cat1==colon) {
+ big_app1(pp); big_app(' '); reduce(pp,1,decl_head,0,28);
+}
+else if (cat1==prelangle) squash(pp+1,1,langle,1,29);
+else if (cat1==colcol && (cat2==exp||cat2==int_like)) squash(pp,3,cat2,-2,30);
+else if (cat1==cast) {
+ if (cat2==lbrace) {
+ big_app2(pp); big_app(indent); big_app(indent);
+ reduce(pp,2,fn_decl,1,31);
+ }
+ else squash(pp,2,int_like,-2,32);
+}
+
+@ @<Cases for |decl_head|@>=
+if (cat1==comma) {
+ big_app2(pp); big_app(' '); reduce(pp,2,decl_head,-1,33);
+}
+else if (cat1==unorbinop) {
+ big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
+ reduce(pp,2,decl_head,-1,34);
+}
+else if (cat1==exp && cat2!=lpar && cat2!=exp) {
+ make_underlined(pp+1); squash(pp,2,decl_head,-1,35);
+}
+else if ((cat1==binop||cat1==colon) && cat2==exp && (cat3==comma ||
+ cat3==semi || cat3==rpar))
+ squash(pp,3,decl_head,-1,36);
+else if (cat1==cast) squash(pp,2,decl_head,-1,37);
+else if (cat1==lbrace || (cat1==int_like&&cat2!=colcol) || cat1==decl) {
+ big_app1(pp); big_app(indent); app(indent); reduce(pp,1,fn_decl,0,38);
+}
+else if (cat1==semi) squash(pp,2,decl,-1,39);
+
+@ @<Cases for |decl|@>=
+if (cat1==decl) {
+ big_app1(pp); big_app(force); big_app1(pp+1);
+ reduce(pp,2,decl,-1,40);
+}
+else if (cat1==stmt || cat1==function) {
+ big_app1(pp); big_app(big_force);
+ big_app1(pp+1); reduce(pp,2,cat1,-1,41);
+}
+
+@ @<Cases for |typedef_like|@>=
+if (cat1==decl_head)
+ if ((cat2==exp&&cat3!=lpar&&cat3!=exp)||cat2==int_like) {
+ make_underlined(pp+2); make_reserved(pp+2);
+ big_app2(pp+1); reduce(pp+1,2,decl_head,0,42);
+ }
+ else if (cat2==semi) {
+ big_app1(pp); big_app(' '); big_app2(pp+1); reduce(pp,3,decl,-1,43);
+ }
+
+@ @<Cases for |struct_like|@>=
+if (cat1==lbrace) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,struct_head,0,44);
+}
+else if (cat1==exp||cat1==int_like) {
+ if (cat2==lbrace || cat2==semi) {
+ make_underlined(pp+1); make_reserved(pp+1);
+ big_app1(pp); big_app(' '); big_app1(pp+1);
+ if (cat2==semi) reduce(pp,2,decl_head,0,45);
+ else {
+ big_app(' '); big_app1(pp+2);reduce(pp,3,struct_head,0,46);
+ }
+ }
+ else if (cat2==colon) squash(pp+2,1,base,-1,47);
+ else if (cat2!=base) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,int_like,-2,48);
+ }
+}
+
+@ @<Cases for |struct_head|@>=
+if ((cat1==decl || cat1==stmt || cat1==function) && cat2==rbrace) {
+ big_app1(pp); big_app(indent); big_app(force); big_app1(pp+1);
+ big_app(outdent); big_app(force); big_app1(pp+2);
+ reduce(pp,3,int_like,-2,49);
+}
+else if (cat1==rbrace) {
+ big_app1(pp); app_str("\\,"); big_app1(pp+1);
+@.\\,@>
+ reduce(pp,2,int_like,-2,50);
+}
+
+@ @<Cases for |fn_decl|@>=
+if (cat1==decl) {
+ big_app1(pp); big_app(force); big_app1(pp+1); reduce(pp,2,fn_decl,0,51);
+}
+else if (cat1==stmt) {
+ big_app1(pp); app(outdent); app(outdent); big_app(force);
+ big_app1(pp+1); reduce(pp,2,function,-1,52);
+}
+
+@ @<Cases for |function|@>=
+if (cat1==function || cat1==decl || cat1==stmt) {
+ big_app1(pp); big_app(big_force); big_app1(pp+1); reduce(pp,2,cat1,-1,53);
+}
+
+@ @<Cases for |lbrace|@>=
+if (cat1==rbrace) {
+ big_app1(pp); app('\\'); app(','); big_app1(pp+1);
+@.\\,@>
+ reduce(pp,2,stmt,-1,54);
+}
+else if ((cat1==stmt||cat1==decl||cat1==function) && cat2==rbrace) {
+ big_app(force); big_app1(pp); big_app(indent); big_app(force);
+ big_app1(pp+1); big_app(force); big_app(backup); big_app1(pp+2);
+ big_app(outdent); big_app(force); reduce(pp,3,stmt,-1,55);
+}
+else if (cat1==exp) {
+ if (cat2==rbrace) squash(pp,3,exp,-2,56);
+ else if (cat2==comma && cat3==rbrace) squash(pp,4,exp,-2,56);
+}
+
+@ @<Cases for |if_like|@>=
+if (cat1==exp) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,if_clause,0,57);
+}
+
+@ @<Cases for |for_like|@>=
+if (cat1==exp) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,else_like,-2,58);
+}
+
+@ @<Cases for |else_like|@>=
+if (cat1==lbrace) squash(pp,1,else_head,0,59);
+else if (cat1==stmt) {
+ big_app(force); big_app1(pp); big_app(indent); big_app(break_space);
+ big_app1(pp+1); big_app(outdent); big_app(force);
+ reduce(pp,2,stmt,-1,60);
+}
+
+@ @<Cases for |else_head|@>=
+if (cat1==stmt || cat1==exp) {
+ big_app(force); big_app1(pp); big_app(break_space); app(noop);
+ big_app(cancel); big_app1(pp+1); big_app(force);
+ reduce(pp,2,stmt,-1,61);
+}
+
+@ @<Cases for |if_clause|@>=
+if (cat1==lbrace) squash(pp,1,if_head,0,62);
+else if (cat1==stmt) {
+ if (cat2==else_like) {
+ big_app(force); big_app1(pp); big_app(indent); big_app(break_space);
+ big_app1(pp+1); big_app(outdent); big_app(force); big_app1(pp+2);
+ if (cat3==if_like) {
+ big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,63);
+ }@+else reduce(pp,3,else_like,0,64);
+ }
+ else squash(pp,1,else_like,0,65);
+}
+
+@ @<Cases for |if_head|@>=
+if (cat1==stmt || cat1==exp) {
+ if (cat2==else_like) {
+ big_app(force); big_app1(pp); big_app(break_space); app(noop);
+ big_app(cancel); big_app1(pp+1); big_app(force); big_app1(pp+2);
+ if (cat3==if_like) {
+ big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,66);
+ }@+else reduce(pp,3,else_like,0,67);
+ }
+ else squash(pp,1,else_head,0,68);
+}
+
+@ @<Cases for |do_like|@>=
+if (cat1==stmt && cat2==else_like && cat3==semi) {
+ big_app1(pp); big_app(break_space); app(noop); big_app(cancel);
+ big_app1(pp+1); big_app(cancel); app(noop); big_app(break_space);
+ big_app2(pp+2); reduce(pp,4,stmt,-1,69);
+}
+
+@ @<Cases for |case_like|@>=
+if (cat1==semi) squash(pp,2,stmt,-1,70);
+else if (cat1==colon) squash(pp,2,tag,-1,71);
+else if (cat1==exp) {
+ if (cat2==semi) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); big_app1(pp+2);
+ reduce(pp,3,stmt,-1,72);
+ }
+ else if (cat2==colon) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); big_app1(pp+2);
+ reduce(pp,3,tag,-1,73);
+ }
+}
+
+@ @<Cases for |tag|@>=
+if (cat1==tag) {
+ big_app1(pp); big_app(break_space); big_app1(pp+1); reduce(pp,2,tag,-1,74);
+}
+else if (cat1==stmt||cat1==decl||cat1==function) {
+ big_app(force); big_app(backup); big_app1(pp); big_app(break_space);
+ big_app1(pp+1); reduce(pp,2,cat1,-1,75);
+}
+
+@ The user can decide at run-time whether short statements should be
+grouped together on the same line.
+
+@d force_lines flags['f'] /* should each statement be on its own line? */
+@<Cases for |stmt|@>=
+if (cat1==stmt||cat1==decl||cat1==function) {
+ big_app1(pp);
+ if (cat1==function) big_app(big_force);
+ else if (cat1==decl) big_app(big_force);
+ else if (force_lines) big_app(force);
+ else big_app(break_space);
+ big_app1(pp+1); reduce(pp,2,cat1,-1,76);
+}
+
+@ @<Cases for |semi|@>=
+big_app(' '); big_app1(pp); reduce(pp,1,stmt,-1,77);
+
+@ @<Cases for |lproc|@>=
+if (cat1==define_like) make_underlined(pp+2);
+if (cat1==else_like || cat1==if_like ||cat1==define_like)
+ squash(pp,2,lproc,0,78);
+else if (cat1==rproc) {
+ app(inserted); big_app2(pp); reduce(pp,2,insert,-1,79);
+} else if (cat1==exp || cat1==function) {
+ if (cat2==rproc) {
+ app(inserted); big_app1(pp); big_app(' '); big_app2(pp+1);
+ reduce(pp,3,insert,-1,80);
+ }
+ else if (cat2==exp && cat3==rproc && cat1==exp) {
+ app(inserted); big_app1(pp); big_app(' '); big_app1(pp+1); app_str(" \\5");
+@.\\5@>
+ big_app2(pp+2); reduce(pp,4,insert,-1,80);
+ }
+}
+
+@ @<Cases for |section_scrap|@>=
+if (cat1==semi) {
+ big_app2(pp); big_app(force); reduce(pp,2,stmt,-2,81);
+}
+else squash(pp,1,exp,-2,82);
+
+@ @<Cases for |insert|@>=
+if (cat1)
+ squash(pp,2,cat1,0,83);
+
+@ @<Cases for |prelangle|@>=
+init_mathness=cur_mathness=yes_math;
+app('<'); reduce(pp,1,binop,-2,84);
+
+@ @<Cases for |prerangle|@>=
+init_mathness=cur_mathness=yes_math;
+app('>'); reduce(pp,1,binop,-2,85);
+
+@ @<Cases for |langle|@>=
+if (cat1==exp && cat2==prerangle) squash(pp,3,cast,-1,86);
+else if (cat1==prerangle) {
+ big_app1(pp); app('\\'); app(','); big_app1(pp+1);
+@.\\,@>
+ reduce(pp,2,cast,-1,87);
+}
+else if (cat1==decl_head || cat1==int_like) {
+ if (cat2==prerangle) squash(pp,3,cast,-1,88);
+ else if (cat2==comma) {
+ big_app3(pp); app(opt); app('9'); reduce(pp,3,langle,0,89);
+ }
+}
+
+@ @<Cases for |public_like|@>=
+if (cat1==colon) squash(pp,2,tag,-1,90);
+else squash(pp,1,int_like,-2,91);
+
+@ @<Cases for |colcol|@>=
+if (cat1==exp||cat1==int_like) squash(pp,2,cat1,-2,92);
+
+@ @<Cases for |new_like|@>=
+if (cat1==exp || (cat1==raw_int&&cat2!=prelangle&&cat2!=langle)) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,new_like,0,93);
+}
+else if (cat1==raw_unorbin || cat1==colcol)
+ squash(pp,2,new_like,0,94);
+else if (cat1==cast) squash(pp,2,exp,-2,95);
+else if (cat1!=lpar && cat1!=raw_int && cat1!=struct_like)
+ squash(pp,1,exp,-2,96);
+
+@ @<Cases for |operator_like|@>=
+if (cat1==binop || cat1==unop || cat1==unorbinop) {
+ if (cat2==binop) break;
+ big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
+ reduce(pp,2,exp,-2,97);
+}
+else if (cat1==new_like || cat1==sizeof_like) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,98);
+}
+else squash(pp,1,new_like,0,99);
+
+@ @<Cases for |catch_like|@>=
+if (cat1==cast || cat1==exp) {
+ big_app2(pp); big_app(indent); big_app(indent);
+ reduce(pp,2,fn_decl,0,100);
+}
+
+@ @<Cases for |base|@>=
+if (cat1==public_like && cat2==exp) {
+ if (cat3==comma) {
+ big_app2(pp); big_app(' '); big_app2(pp+2);
+ reduce(pp,4,base,0,101);
+ } else {
+ big_app1(pp+1); big_app(' '); big_app1(pp+2);
+ reduce(pp+1,2,int_like,-1,102);
+ }
+}
+
+@ @<Cases for |raw_rpar|@>=
+if (cat1==const_like && @|
+ (cat2==semi || cat2==lbrace || cat2==comma || cat2==binop
+ || cat2==const_like)) {
+ big_app1(pp); big_app(' ');
+ big_app1(pp+1); reduce(pp,2,raw_rpar,0,103);
+} else squash(pp,1,rpar,-3,104);
+
+@ @<Cases for |raw_unorbin|@>=
+if (cat1==const_like) {
+ big_app2(pp); app_str("\\ "); reduce(pp,2,raw_unorbin,0,105);
+@.\\ @>
+} else squash(pp,1,unorbinop,-2,106);
+
+@ @<Cases for |const_like|@>=
+squash(pp,1,int_like,-2,107);
+
+@ @<Cases for |raw_int|@>=
+if (cat1==lpar) squash(pp,1,exp,-2,108);
+else squash(pp,1,int_like,-3,109);
+
+@ The `|freeze_text|' macro is used to give official status to a token list.
+Before saying |freeze_text|, items are appended to the current token list,
+and we know that the eventual number of this token list will be the current
+value of |text_ptr|. But no list of that number really exists as yet,
+because no ending point for the current list has been
+stored in the |tok_start| array. After saying |freeze_text|, the
+old current token list becomes legitimate, and its number is the current
+value of |text_ptr-1| since |text_ptr| has been increased. The new
+current token list is empty and ready to be appended to.
+Note that |freeze_text| does not check to see that |text_ptr| hasn't gotten
+too large, since it is assumed that this test was done beforehand.
+
+@d freeze_text *(++text_ptr)=tok_ptr
+
+@ Here's the |reduce| procedure used in our code for productions:
+
+@c
+void
+reduce(j,k,c,d,n)
+scrap_pointer j;
+eight_bits c;
+short k, d, n;
+{
+ scrap_pointer i, i1; /* pointers into scrap memory */
+ j->cat=c; j->trans=text_ptr;
+ j->mathness=4*cur_mathness+init_mathness;
+ freeze_text;
+ if (k>1) {
+ for (i=j+k, i1=j+1; i<=lo_ptr; i++, i1++) {
+ i1->cat=i->cat; i1->trans=i->trans;
+ i1->mathness=i->mathness;
+ }
+ lo_ptr=lo_ptr-k+1;
+ }
+ @<Change |pp| to $\max(|scrap_base|,|pp|+d)$@>;
+ @<Print a snapshot of the scrap list if debugging @>;
+ pp--; /* we next say |pp++| */
+}
+
+@ @<Change |pp| to $\max...@>=
+if (pp+d>=scrap_base) pp=pp+d;
+else pp=scrap_base;
+
+@ Here's the |squash| procedure, which
+takes advantage of the simplification that occurs when |k==1|.
+
+@c
+void
+squash(j,k,c,d,n)
+scrap_pointer j;
+eight_bits c;
+short k, d, n;
+{
+ scrap_pointer i; /* pointers into scrap memory */
+ if (k==1) {
+ j->cat=c; @<Change |pp|...@>;
+ @<Print a snapshot...@>;
+ pp--; /* we next say |pp++| */
+ return;
+ }
+ for (i=j; i<j+k; i++) big_app1(i);
+ reduce(j,k,c,d,n);
+}
+
+@ Here now is the code that applies productions as long as possible.
+Before applying the production mechanism, we must make sure
+it has good input (at least four scraps, the length of the lhs of the
+longest rules), and that there is enough room in the memory arrays
+to hold the appended tokens and texts. Here we use a very
+conservative test: it's more important to make sure the program
+will still work if we change the production rules (within reason)
+than to squeeze the last bit of space from the memory arrays.
+
+@d safe_tok_incr 20
+@d safe_text_incr 10
+@d safe_scrap_incr 10
+
+@<Reduce the scraps using the productions until no more rules apply@>=
+while (1) {
+ @<Make sure the entries |pp| through |pp+3| of |cat| are defined@>;
+ if (tok_ptr+safe_tok_incr>tok_mem_end) {
+ if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
+ overflow("token");
+ }
+ if (text_ptr+safe_text_incr>tok_start_end) {
+ if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
+ overflow("text");
+ }
+ if (pp>lo_ptr) break;
+ init_mathness=cur_mathness=maybe_math;
+ @<Match a production...@>;
+}
+
+@ If we get to the end of the scrap list, category codes equal to zero are
+stored, since zero does not match anything in a production.
+
+@<Make sure the entries...@>=
+if (lo_ptr<pp+3) {
+ while (hi_ptr<=scrap_ptr && lo_ptr!=pp+3) {
+ (++lo_ptr)->cat=hi_ptr->cat; lo_ptr->mathness=(hi_ptr)->mathness;
+ lo_ptr->trans=(hi_ptr++)->trans;
+ }
+ for (i=lo_ptr+1;i<=pp+3;i++) i->cat=0;
+}
+
+@ If \.{CWEAVE} is being run in debugging mode, the production numbers and
+current stack categories will be printed out when |tracing| is set to 2;
+a sequence of two or more irreducible scraps will be printed out when
+|tracing| is set to 1.
+
+@<Global...@>=
+int tracing; /* can be used to show parsing details */
+
+@ @<Print a snapsh...@>=
+{ scrap_pointer k; /* pointer into |scrap_info| */
+ if (tracing==2) {
+ printf("\n%d:",n);
+ for (k=scrap_base; k<=lo_ptr; k++) {
+ if (k==pp) putxchar('*'); else putxchar(' ');
+ if (k->mathness %4 == yes_math) putchar('+');
+ else if (k->mathness %4 == no_math) putchar('-');
+ print_cat(k->cat);
+ if (k->mathness /4 == yes_math) putchar('+');
+ else if (k->mathness /4 == no_math) putchar('-');
+ }
+ if (hi_ptr<=scrap_ptr) printf("..."); /* indicate that more is coming */
+ }
+}
+
+@ The |translate| function assumes that scraps have been stored in
+positions |scrap_base| through |scrap_ptr| of |cat| and |trans|. It
+applies productions as much as
+possible. The result is a token list containing the translation of
+the given sequence of scraps.
+
+After calling |translate|, we will have |text_ptr+3<=max_texts| and
+|tok_ptr+6<=max_toks|, so it will be possible to create up to three token
+lists with up to six tokens without checking for overflow. Before calling
+|translate|, we should have |text_ptr<max_texts| and |scrap_ptr<max_scraps|,
+since |translate| might add a new text and a new scrap before it checks
+for overflow.
+
+@c
+text_pointer
+translate() /* converts a sequence of scraps */
+{
+ scrap_pointer i, /* index into |cat| */
+ j; /* runs through final scraps */
+ pp=scrap_base; lo_ptr=pp-1; hi_ptr=pp;
+ @<If tracing, print an indication of where we are@>;
+ @<Reduce the scraps...@>;
+ @<Combine the irreducible scraps that remain@>;
+}
+
+@ If the initial sequence of scraps does not reduce to a single scrap,
+we concatenate the translations of all remaining scraps, separated by
+blank spaces, with dollar signs surrounding the translations of scraps
+where appropriate.
+
+@<Combine the irreducible...@>= {
+ @<If semi-tracing, show the irreducible scraps@>;
+ for (j=scrap_base; j<=lo_ptr; j++) {
+ if (j!=scrap_base) app(' ');
+ if (j->mathness % 4 == yes_math) app('$');
+ app1(j);
+ if (j->mathness / 4 == yes_math) app('$');
+ if (tok_ptr+6>tok_mem_end) overflow("token");
+ }
+ freeze_text; return(text_ptr-1);
+}
+
+@ @<If semi-tracing, show the irreducible scraps@>=
+if (lo_ptr>scrap_base && tracing==1) {
+ printf("\nIrreducible scrap sequence in section %d:",section_count);
+@.Irreducible scrap sequence...@>
+ mark_harmless;
+ for (j=scrap_base; j<=lo_ptr; j++) {
+ printf(" "); print_cat(j->cat);
+ }
+}
+
+@ @<If tracing,...@>=
+if (tracing==2) {
+ printf("\nTracing after l. %d:\n",cur_line); mark_harmless;
+@.Tracing after...@>
+ if (loc>buffer+50) {
+ printf("...");
+ term_write(loc-51,51);
+ }
+ else term_write(buffer,loc-buffer);
+}
+
+@* Initializing the scraps.
+If we are going to use the powerful production mechanism just developed, we
+must get the scraps set up in the first place, given a \CEE/ text. A table
+of the initial scraps corresponding to \CEE/ tokens appeared above in the
+section on parsing; our goal now is to implement that table. We shall do this
+by implementing a subroutine called |C_parse| that is analogous to the
+|C_xref| routine used during phase one.
+
+Like |C_xref|, the |C_parse| procedure starts with the current
+value of |next_control| and it uses the operation |next_control=get_next()|
+repeatedly to read \CEE/ text until encountering the next `\.{\v}' or
+`\.{/*}', or until |next_control>=format_code|. The scraps corresponding to
+what it reads are appended into the |cat| and |trans| arrays, and |scrap_ptr|
+is advanced.
+
+@c
+void
+C_parse(spec_ctrl) /* creates scraps from \CEE/ tokens */
+ eight_bits spec_ctrl;
+{
+ int count; /* characters remaining before string break */
+ while (next_control<format_code || next_control==spec_ctrl) {
+ @<Append the scrap appropriate to |next_control|@>;
+ next_control=get_next();
+ if (next_control=='|' || next_control==begin_comment ||
+ next_control==begin_short_comment) return;
+ }
+}
+
+@ The following macro is used to append a scrap whose tokens have just
+been appended:
+
+@d app_scrap(c,b) {
+ (++scrap_ptr)->cat=(c); scrap_ptr->trans=text_ptr;
+ scrap_ptr->mathness=5*(b); /* no no, yes yes, or maybe maybe */
+ freeze_text;
+}
+
+@ @<Append the scr...@>=
+@<Make sure that there is room for the new scraps, tokens, and texts@>;
+switch (next_control) {
+ case section_name:
+ app(section_flag+(int)(cur_section-name_dir));
+ app_scrap(section_scrap,maybe_math);
+ app_scrap(exp,yes_math);@+break;
+ case string: case constant: case verbatim: @<Append a string or constant@>;
+ @+break;
+ case identifier: app_cur_id(1);@+break;
+ case TeX_string: @<Append a \TEX/ string, without forming a scrap@>;@+break;
+ case '/': case '.':
+ app(next_control); app_scrap(binop,yes_math);@+break;
+ case '<': app_str("\\langle");@+app_scrap(prelangle,yes_math);@+break;
+@.\\langle@>
+ case '>': app_str("\\rangle");@+app_scrap(prerangle,yes_math);@+break;
+@.\\rangle@>
+ case '=': app_str("\\K"); app_scrap(binop,yes_math);@+break;
+@.\\K@>
+ case '|': app_str("\\OR"); app_scrap(binop,yes_math);@+break;
+@.\\OR@>
+ case '^': app_str("\\XOR"); app_scrap(binop,yes_math);@+break;
+@.\\XOR@>
+ case '%': app_str("\\MOD"); app_scrap(binop,yes_math);@+break;
+@.\\MOD@>
+ case '!': app_str("\\R"); app_scrap(unop,yes_math);@+break;
+@.\\R@>
+ case '~': app_str("\\CM"); app_scrap(unop,yes_math);@+break;
+@.\\CM@>
+ case '+': case '-': app(next_control); app_scrap(unorbinop,yes_math);@+break;
+ case '*': app(next_control); app_scrap(raw_unorbin,yes_math);@+break;
+ case '&': app_str("\\AND"); app_scrap(raw_unorbin,yes_math);@+break;
+@.\\AND@>
+ case '?': app_str("\\?"); app_scrap(question,yes_math);@+break;
+@.\\?@>
+ case '#': app_str("\\#"); app_scrap(unorbinop,yes_math);@+break;
+@.\\\#@>
+ case ignore: case xref_roman: case xref_wildcard:
+ case xref_typewriter: case noop:@+break;
+ case '(': case '[': app(next_control); app_scrap(lpar,maybe_math);@+break;
+ case ')': case ']': app(next_control); app_scrap(raw_rpar,maybe_math);@+break;
+ case '{': app_str("\\{"@q}@>); app_scrap(lbrace,yes_math);@+break;
+@.\\\{@>@q}@>
+ case '}': app_str(@q{@>"\\}"); app_scrap(rbrace,yes_math);@+break;
+@q{@>@.\\\}@>
+ case ',': app(','); app_scrap(comma,yes_math);@+break;
+ case ';': app(';'); app_scrap(semi,maybe_math);@+break;
+ case ':': app(':'); app_scrap(colon,maybe_math);@+break;@/
+ @t\4@> @<Cases involving nonstandard characters@>@;
+ case thin_space: app_str("\\,"); app_scrap(insert,maybe_math);@+break;
+@.\\,@>
+ case math_break: app(opt); app_str("0");
+ app_scrap(insert,maybe_math);@+break;
+ case line_break: app(force); app_scrap(insert,no_math);@+break;
+ case left_preproc: app(force); app(preproc_line);
+ app_str("\\#"); app_scrap(lproc,no_math);@+break;
+@.\\\#@>
+ case right_preproc: app(force); app_scrap(rproc,no_math);@+break;
+ case big_line_break: app(big_force); app_scrap(insert,no_math);@+break;
+ case no_line_break: app(big_cancel); app(noop); app(break_space);
+ app(noop); app(big_cancel);
+ app_scrap(insert,no_math);@+break;
+ case pseudo_semi: app_scrap(semi,maybe_math);@+break;
+ case macro_arg_open: app_scrap(begin_arg,maybe_math);@+break;
+ case macro_arg_close: app_scrap(end_arg,maybe_math);@+break;
+ case join: app_str("\\J"); app_scrap(insert,no_math);@+break;
+@.\\J@>
+ case output_defs_code: app(force); app_str("\\ATH"); app(force);
+ app_scrap(insert,no_math);@+break;
+@.\\ATH@>
+ default: app(inserted); app(next_control);
+ app_scrap(insert,maybe_math);@+break;
+}
+
+@ @<Make sure that there is room for the new...@>=
+if (scrap_ptr+safe_scrap_incr>scrap_info_end ||
+ tok_ptr+safe_tok_incr>tok_mem_end @| ||
+ text_ptr+safe_text_incr>tok_start_end) {
+ if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
+ if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
+ if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
+ overflow("scrap/token/text");
+}
+
+@ Some nonstandard characters may have entered \.{CWEAVE} by means of
+standard ones. They are converted to \TEX/ control sequences so that it is
+possible to keep \.{CWEAVE} from outputting unusual |char| codes.
+
+@<Cases involving nonstandard...@>=
+case not_eq: app_str("\\I");@+app_scrap(binop,yes_math);@+break;
+@.\\I@>
+case lt_eq: app_str("\\Z");@+app_scrap(binop,yes_math);@+break;
+@.\\Z@>
+case gt_eq: app_str("\\G");@+app_scrap(binop,yes_math);@+break;
+@.\\G@>
+case eq_eq: app_str("\\E");@+app_scrap(binop,yes_math);@+break;
+@.\\E@>
+case and_and: app_str("\\W");@+app_scrap(binop,yes_math);@+break;
+@.\\W@>
+case or_or: app_str("\\V");@+app_scrap(binop,yes_math);@+break;
+@.\\V@>
+case plus_plus: app_str("\\PP");@+app_scrap(unop,yes_math);@+break;
+@.\\PP@>
+case minus_minus: app_str("\\MM");@+app_scrap(unop,yes_math);@+break;
+@.\\MM@>
+case minus_gt: app_str("\\MG");@+app_scrap(binop,yes_math);@+break;
+@.\\MG@>
+case gt_gt: app_str("\\GG");@+app_scrap(binop,yes_math);@+break;
+@.\\GG@>
+case lt_lt: app_str("\\LL");@+app_scrap(binop,yes_math);@+break;
+@.\\LL@>
+case dot_dot_dot: app_str("\\,\\ldots\\,");@+app_scrap(exp,yes_math);@+break;
+@.\\,@>
+@.\\ldots@>
+case colon_colon: app_str("\\DC");@+app_scrap(colcol,maybe_math);@+break;
+@.\\DC@>
+case period_ast: app_str("\\PA");@+app_scrap(binop,yes_math);@+break;
+@.\\PA@>
+case minus_gt_ast: app_str("\\MGA");@+app_scrap(binop,yes_math);@+break;
+@.\\MGA@>
+
+@ The following code must use |app_tok| instead of |app| in order to
+protect against overflow. Note that |tok_ptr+1<=max_toks| after |app_tok|
+has been used, so another |app| is legitimate before testing again.
+
+Many of the special characters in a string must be prefixed by `\.\\' so that
+\TEX/ will print them properly.
+@^special string characters@>
+
+@<Append a string or...@>=
+count= -1;
+if (next_control==constant) app_str("\\T{"@q}@>);
+@.\\T@>
+else if (next_control==string) {
+ count=20; app_str("\\.{"@q}@>);
+}
+@.\\.@>
+else app_str("\\vb{"@q}@>);
+@.\\vb@>
+while (id_first<id_loc) {
+ if (count==0) { /* insert a discretionary break in a long string */
+ app_str(@q(@>@q{@>"}\\)\\.{"@q}@>); count=20;
+@q(@>@.\\)@>
+ }
+@^high-bit character handling@>
+ if((eight_bits)(*id_first)>0177) {
+ app_tok(quoted_char);
+ app_tok((eight_bits)(*id_first++));
+ }
+ else {
+ switch (*id_first) {
+ case ' ':case '\\':case '#':case '%':case '$':case '^':
+ case '{': case '}': case '~': case '&': case '_': app('\\'); break;
+@.\\\ @>
+@.\\\\@>
+@.\\\#@>
+@.\\\%@>
+@.\\\$@>
+@.\\\^@>
+@.\\\{@>@q}@>
+@q{@>@.\\\}@>
+@.\\\~@>
+@.\\\&@>
+@.\\_@> @q CWEAVE does quote an underscore! @>
+ case '@@': if (*(id_first+1)=='@@') id_first++;
+ else err_print("! Double @@ should be used in strings");
+@.Double @@ should be used...@>
+ }
+ app_tok(*id_first++);
+ }
+ count--;
+}
+app(@q{@>'}');
+app_scrap(exp,maybe_math);
+
+@ We do not make the \TEX/ string into a scrap, because there is no
+telling what the user will be putting into it; instead we leave it
+open, to be picked up by the next scrap. If it comes at the end of a
+section, it will be made into a scrap when |finish_C| is called.
+
+There's a known bug here, in cases where an adjacent scrap is
+|prelangle| or |prerangle|. Then the \TEX/ string can disappear
+when the \.{\\langle} or \.{\\rangle} becomes \.{<} or \.{>}.
+For example, if the user writes \.{\v x<@@ty@@>\v}, the \TEX/ string
+\.{\\hbox\{y\}} eventually becomes part of an |insert| scrap, which is combined
+with a |prelangle| scrap and eventually lost. The best way to work around
+this bug is probably to enclose the \.{@@t...@@>} in \.{@@[...@@]} so that
+the \TEX/ string is treated as an expression.
+@^bug, known@>
+
+@<Append a \TEX/ string, without forming a scrap@>=
+app_str("\\hbox{"@q}@>);
+@^high-bit character handling@>
+while (id_first<id_loc)
+ if((eight_bits)(*id_first)>0177) {
+ app_tok(quoted_char);
+ app_tok((eight_bits)(*id_first++));
+ }
+ else {
+ if (*id_first=='@@') id_first++;
+ app_tok(*id_first++);
+ }
+app(@q{@>'}');
+
+@ The function |app_cur_id| appends the current identifier to the
+token list; it also builds a new scrap if |scrapping==1|.
+
+@<Predec...@>=
+void app_cur_id();
+
+@ @c
+void
+app_cur_id(scrapping)
+boolean scrapping; /* are we making this into a scrap? */
+{
+ name_pointer p=id_lookup(id_first,id_loc,normal);
+ if (p->ilk<=quoted) { /* not a reserved word */
+ app(id_flag+(int)(p-name_dir));
+ if (scrapping) app_scrap(exp,p->ilk>=custom? yes_math: maybe_math);
+@.\\NULL@>
+ } else {
+ app(res_flag+(int)(p-name_dir));
+ if (scrapping) app_scrap(p->ilk,maybe_math);
+ }
+}
+
+@ When the `\.{\v}' that introduces \CEE/ text is sensed, a call on
+|C_translate| will return a pointer to the \TEX/ translation of
+that text. If scraps exist in |scrap_info|, they are
+unaffected by this translation process.
+
+@c
+text_pointer
+C_translate()
+{
+ text_pointer p; /* points to the translation */
+ scrap_pointer save_base; /* holds original value of |scrap_base| */
+ save_base=scrap_base; scrap_base=scrap_ptr+1;
+ C_parse(section_name); /* get the scraps together */
+ if (next_control!='|') err_print("! Missing '|' after C text");
+@.Missing '|'...@>
+ app_tok(cancel); app_scrap(insert,maybe_math);
+ /* place a |cancel| token as a final ``comment'' */
+ p=translate(); /* make the translation */
+ if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
+ scrap_ptr=scrap_base-1; scrap_base=save_base; /* scrap the scraps */
+ return(p);
+}
+
+@ The |outer_parse| routine is to |C_parse| as |outer_xref|
+is to |C_xref|: it constructs a sequence of scraps for \CEE/ text
+until |next_control>=format_code|. Thus, it takes care of embedded comments.
+
+@c
+void
+outer_parse() /* makes scraps from \CEE/ tokens and comments */
+{
+ int bal; /* brace level in comment */
+ text_pointer p, q; /* partial comments */
+ while (next_control<format_code)
+ if (next_control!=begin_comment && next_control!=begin_short_comment)
+ C_parse(ignore);
+ else {
+ boolean is_long_comment=(next_control==begin_comment);
+ @<Make sure that there is room for the new...@>;
+ app(cancel); app(inserted);
+ if (is_long_comment) app_str("\\C{"@q}@>);
+@.\\C@>
+ else app_str("\\SHC{"@q}@>);
+@.\\SHC@>
+ bal=copy_comment(is_long_comment,1); next_control=ignore;
+ while (bal>0) {
+ p=text_ptr; freeze_text; q=C_translate();
+ /* at this point we have |tok_ptr+6<=max_toks| */
+ app(tok_flag+(int)(p-tok_start));
+ app_str("\\PB{"); app(inner_tok_flag+(int)(q-tok_start)); app_tok('}');
+@.\\PB@>
+ if (next_control=='|') {
+ bal=copy_comment(is_long_comment,bal);
+ next_control=ignore;
+ }
+ else bal=0; /* an error has been reported */
+ }
+ app(force); app_scrap(insert,no_math);
+ /* the full comment becomes a scrap */
+ }
+}
+
+@* Output of tokens.
+So far our programs have only built up multi-layered token lists in
+\.{CWEAVE}'s internal memory; we have to figure out how to get them into
+the desired final form. The job of converting token lists to characters in
+the \TEX/ output file is not difficult, although it is an implicitly
+recursive process. Four main considerations had to be kept in mind when
+this part of \.{CWEAVE} was designed. (a) There are two modes of output:
+|outer| mode, which translates tokens like |force| into line-breaking
+control sequences, and |inner| mode, which ignores them except that blank
+spaces take the place of line breaks. (b) The |cancel| instruction applies
+to adjacent token or tokens that are output, and this cuts across levels
+of recursion since `|cancel|' occurs at the beginning or end of a token
+list on one level. (c) The \TEX/ output file will be semi-readable if line
+breaks are inserted after the result of tokens like |break_space| and
+|force|. (d) The final line break should be suppressed, and there should
+be no |force| token output immediately after `\.{\\Y\\B}'.
+
+@ The output process uses a stack to keep track of what is going on at
+different ``levels'' as the token lists are being written out. Entries on
+this stack have three parts:
+
+\yskip\hang |end_field| is the |tok_mem| location where the token list of a
+particular level will end;
+
+\yskip\hang |tok_field| is the |tok_mem| location from which the next token
+on a particular level will be read;
+
+\yskip\hang |mode_field| is the current mode, either |inner| or |outer|.
+
+\yskip\noindent The current values of these quantities are referred to
+quite frequently, so they are stored in a separate place instead of in the
+|stack| array. We call the current values |cur_end|, |cur_tok|, and
+|cur_mode|.
+
+The global variable |stack_ptr| tells how many levels of output are
+currently in progress. The end of output occurs when an |end_translation|
+token is found, so the stack is never empty except when we first begin the
+output process.
+
+@d inner 0 /* value of |mode| for \CEE/ texts within \TEX/ texts */
+@d outer 1 /* value of |mode| for \CEE/ texts in sections */
+
+@<Typed...@>= typedef int mode;
+typedef struct {
+ token_pointer end_field; /* ending location of token list */
+ token_pointer tok_field; /* present location within token list */
+ boolean mode_field; /* interpretation of control tokens */
+} output_state;
+typedef output_state *stack_pointer;
+
+@ @d cur_end cur_state.end_field /* current ending location in |tok_mem| */
+@d cur_tok cur_state.tok_field /* location of next output token in |tok_mem| */
+@d cur_mode cur_state.mode_field /* current mode of interpretation */
+@d init_stack stack_ptr=stack;cur_mode=outer /* initialize the stack */
+
+@<Global...@>=
+output_state cur_state; /* |cur_end|, |cur_tok|, |cur_mode| */
+output_state stack[stack_size]; /* info for non-current levels */
+stack_pointer stack_ptr; /* first unused location in the output state stack */
+stack_pointer stack_end=stack+stack_size-1; /* end of |stack| */
+stack_pointer max_stack_ptr; /* largest value assumed by |stack_ptr| */
+
+@ @<Set init...@>=
+max_stack_ptr=stack;
+
+@ To insert token-list |p| into the output, the |push_level| subroutine
+is called; it saves the old level of output and gets a new one going.
+The value of |cur_mode| is not changed.
+
+@c
+void
+push_level(p) /* suspends the current level */
+text_pointer p;
+{
+ if (stack_ptr==stack_end) overflow("stack");
+ if (stack_ptr>stack) { /* save current state */
+ stack_ptr->end_field=cur_end;
+ stack_ptr->tok_field=cur_tok;
+ stack_ptr->mode_field=cur_mode;
+ }
+ stack_ptr++;
+ if (stack_ptr>max_stack_ptr) max_stack_ptr=stack_ptr;
+ cur_tok=*p; cur_end=*(p+1);
+}
+
+@ Conversely, the |pop_level| routine restores the conditions that were in
+force when the current level was begun. This subroutine will never be
+called when |stack_ptr==1|.
+
+@c
+void
+pop_level()
+{
+ cur_end=(--stack_ptr)->end_field;
+ cur_tok=stack_ptr->tok_field; cur_mode=stack_ptr->mode_field;
+}
+
+@ The |get_output| function returns the next byte of output that is not a
+reference to a token list. It returns the values |identifier| or |res_word|
+or |section_code| if the next token is to be an identifier (typeset in
+italics), a reserved word (typeset in boldface) or a section name (typeset
+by a complex routine that might generate additional levels of output).
+In these cases |cur_name| points to the identifier or section name in
+question.
+
+@<Global...@>=
+name_pointer cur_name;
+
+@ @d res_word 0201 /* returned by |get_output| for reserved words */
+@d section_code 0200 /* returned by |get_output| for section names */
+
+@c
+eight_bits
+get_output() /* returns the next token of output */
+{
+ sixteen_bits a; /* current item read from |tok_mem| */
+ restart: while (cur_tok==cur_end) pop_level();
+ a=*(cur_tok++);
+ if (a>=0400) {
+ cur_name=a % id_flag + name_dir;
+ switch (a / id_flag) {
+ case 2: return(res_word); /* |a==res_flag+cur_name| */
+ case 3: return(section_code); /* |a==section_flag+cur_name| */
+ case 4: push_level(a % id_flag + tok_start); goto restart;
+ /* |a==tok_flag+cur_name| */
+ case 5: push_level(a % id_flag + tok_start); cur_mode=inner; goto restart;
+ /* |a==inner_tok_flag+cur_name| */
+ default: return(identifier); /* |a==id_flag+cur_name| */
+ }
+ }
+ return(a);
+}
+
+@ The real work associated with token output is done by |make_output|.
+This procedure appends an |end_translation| token to the current token list,
+and then it repeatedly calls |get_output| and feeds characters to the output
+buffer until reaching the |end_translation| sentinel. It is possible for
+|make_output| to be called recursively, since a section name may include
+embedded \CEE/ text; however, the depth of recursion never exceeds one
+level, since section names cannot be inside of section names.
+
+A procedure called |output_C| does the scanning, translation, and
+output of \CEE/ text within `\pb' brackets, and this procedure uses
+|make_output| to output the current token list. Thus, the recursive call
+of |make_output| actually occurs when |make_output| calls |output_C|
+while outputting the name of a section.
+@^recursion@>
+
+The token list created from within `\pb' brackets is output as an argument
+to \.{\\PB}. Although \.{cwebmac} ignores \.{\\PB}, other macro packages
+might use it to localize the special meaning of the macros that mark up
+program text.
+
+@c
+void
+output_C() /* outputs the current token list */
+{
+ token_pointer save_tok_ptr;
+ text_pointer save_text_ptr;
+ sixteen_bits save_next_control; /* values to be restored */
+ text_pointer p; /* translation of the \CEE/ text */
+ save_tok_ptr=tok_ptr; save_text_ptr=text_ptr;
+ save_next_control=next_control; next_control=ignore; p=C_translate();
+ app(inner_tok_flag+(int)(p-tok_start));
+ out_str("\\PB{"); make_output(); out('}'); /* output the list */
+@.\\PB@>
+ if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
+ if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
+ text_ptr=save_text_ptr; tok_ptr=save_tok_ptr; /* forget the tokens */
+ next_control=save_next_control; /* restore |next_control| to original state */
+}
+
+@ Here is \.{CWEAVE}'s major output handler.
+
+@<Predecl...@>=
+void make_output();
+
+@ @c
+void
+make_output() /* outputs the equivalents of tokens */
+{
+ eight_bits a, /* current output byte */
+ b; /* next output byte */
+ int c; /* count of |indent| and |outdent| tokens */
+ char scratch[longest_name]; /* scratch area for section names */
+ char *k, *k_limit; /* indices into |scratch| */
+ char *j; /* index into |buffer| */
+ char *p; /* index into |byte_mem| */
+ char delim; /* first and last character of string being copied */
+ char *save_loc, *save_limit; /* |loc| and |limit| to be restored */
+ name_pointer cur_section_name; /* name of section being output */
+ boolean save_mode; /* value of |cur_mode| before a sequence of breaks */
+ app(end_translation); /* append a sentinel */
+ freeze_text; push_level(text_ptr-1);
+ while (1) {
+ a=get_output();
+ reswitch: switch(a) {
+ case end_translation: return;
+ case identifier: case res_word: @<Output an identifier@>; break;
+ case section_code: @<Output a section name@>; break;
+ case math_rel: out_str("\\MRL{"@q}@>);
+@.\\MRL@>
+ case noop: case inserted: break;
+ case cancel: case big_cancel: c=0; b=a;
+ while (1) {
+ a=get_output();
+ if (a==inserted) continue;
+ if ((a<indent && !(b==big_cancel&&a==' ')) || a>big_force) break;
+ if (a==indent) c++; else if (a==outdent) c--;
+ else if (a==opt) a=get_output();
+ }
+ @<Output saved |indent| or |outdent| tokens@>;
+ goto reswitch;
+ case indent: case outdent: case opt: case backup: case break_space:
+ case force: case big_force: case preproc_line: @<Output a control,
+ look ahead in case of line breaks, possibly |goto reswitch|@>; break;
+ case quoted_char: out(*(cur_tok++)); break;
+ default: out(a); /* otherwise |a| is an ordinary character */
+ }
+ }
+}
+
+@ An identifier of length one does not have to be enclosed in braces, and it
+looks slightly better if set in a math-italic font instead of a (slightly
+narrower) text-italic font. Thus we output `\.{\\\v}\.{a}' but
+`\.{\\\\\{aa\}}'.
+
+@<Output an identifier@>=
+out('\\');
+if (a==identifier) {
+ if (cur_name->ilk>=custom && cur_name->ilk<=quoted && !doing_format) {
+ for (p=cur_name->byte_start;p<(cur_name+1)->byte_start;p++)
+ out(isxalpha(*p)? 'x':*p);
+ break;
+ } else if (is_tiny(cur_name)) out('|')
+@.\\|@>
+ else { delim='.';
+ for (p=cur_name->byte_start;p<(cur_name+1)->byte_start;p++)
+ if (xislower(*p)) { /* not entirely uppercase */
+ delim='\\'; break;
+ }
+ out(delim);
+ }
+@.\\\\@>
+@.\\.@>
+}
+else out('&') /* |a==res_word| */
+@.\\\&@>
+if (is_tiny(cur_name)) {
+ if (isxalpha((cur_name->byte_start)[0]))
+ out('\\');
+ out((cur_name->byte_start)[0]);
+}
+else out_name(cur_name);
+
+@ The current mode does not affect the behavior of \.{CWEAVE}'s output routine
+except when we are outputting control tokens.
+
+@<Output a control...@>=
+if (a<break_space || a==preproc_line) {
+ if (cur_mode==outer) {
+ out('\\'); out(a-cancel+'0');
+@.\\1@>
+@.\\2@>
+@.\\3@>
+@.\\4@>
+@.\\8@>
+ if (a==opt) {
+ b=get_output(); /* |opt| is followed by a digit */
+ if (b!='0' || force_lines==0) out(b)@;
+ else out_str("{-1}"); /* |force_lines| encourages more \.{@@\v} breaks */
+ }
+ } else if (a==opt) b=get_output(); /* ignore digit following |opt| */
+ }
+else @<Look ahead for strongest line break, |goto reswitch|@>
+
+@ If several of the tokens |break_space|, |force|, |big_force| occur in a
+row, possibly mixed with blank spaces (which are ignored),
+the largest one is used. A line break also occurs in the output file,
+except at the very end of the translation. The very first line break
+is suppressed (i.e., a line break that follows `\.{\\Y\\B}').
+
+@<Look ahead for st...@>= {
+ b=a; save_mode=cur_mode; c=0;
+ while (1) {
+ a=get_output();
+ if (a==inserted) continue;
+ if (a==cancel || a==big_cancel) {
+ @<Output saved |indent| or |outdent| tokens@>;
+ goto reswitch; /* |cancel| overrides everything */
+ }
+ if ((a!=' ' && a<indent) || a==backup || a>big_force) {
+ if (save_mode==outer) {
+ if (out_ptr>out_buf+3 && strncmp(out_ptr-3,"\\Y\\B",4)==0)
+ goto reswitch;
+ @<Output saved |indent| or |outdent| tokens@>;
+ out('\\'); out(b-cancel+'0');
+@.\\5@>
+@.\\6@>
+@.\\7@>
+ if (a!=end_translation) finish_line();
+ }
+ else if (a!=end_translation && cur_mode==inner) out(' ');
+ goto reswitch;
+ }
+ if (a==indent) c++;
+ else if (a==outdent) c--;
+ else if (a==opt) a=get_output();
+ else if (a>b) b=a; /* if |a==' '| we have |a<b| */
+ }
+}
+
+@ @<Output saved...@>=
+ for (;c>0;c--) out_str("\\1");
+@.\\1@>
+ for (;c<0;c++) out_str("\\2");
+@.\\2@>
+
+@ The remaining part of |make_output| is somewhat more complicated. When we
+output a section name, we may need to enter the parsing and translation
+routines, since the name may contain \CEE/ code embedded in
+\pb\ constructions. This \CEE/ code is placed at the end of the active
+input buffer and the translation process uses the end of the active
+|tok_mem| area.
+
+@<Output a section name@>= {
+ out_str("\\X");
+@.\\X@>
+ cur_xref=(xref_pointer)cur_name->xref;
+ if (cur_xref->num==file_flag) {an_output=1; cur_xref=cur_xref->xlink;}
+ else an_output=0;
+ if (cur_xref->num>=def_flag) {
+ out_section(cur_xref->num-def_flag);
+ if (phase==3) {
+ cur_xref=cur_xref->xlink;
+ while (cur_xref->num>=def_flag) {
+ out_str(", ");
+ out_section(cur_xref->num-def_flag);
+ cur_xref=cur_xref->xlink;
+ }
+ }
+ }
+ else out('0'); /* output the section number, or zero if it was undefined */
+ out(':');
+ if (an_output) out_str("\\.{"@q}@>);
+@.\\.@>
+ @<Output the text of the section name@>;
+ if (an_output) out_str(@q{@>" }");
+ out_str("\\X");
+}
+
+@ @<Output the text...@>=
+sprint_section_name(scratch,cur_name);
+k=scratch;
+k_limit=scratch+strlen(scratch);
+cur_section_name=cur_name;
+while (k<k_limit) {
+ b=*(k++);
+ if (b=='@@') @<Skip next character, give error if not `\.{@@}'@>;
+ if (an_output)
+ switch (b) {
+ case ' ':case '\\':case '#':case '%':case '$':case '^':
+ case '{': case '}': case '~': case '&': case '_':
+ out('\\'); /* falls through */
+@.\\\ @>
+@.\\\\@>
+@.\\\#@>
+@.\\\%@>
+@.\\\$@>
+@.\\\^@>
+@.\\\{@>@q}@>
+@q{@>@.\\\}@>
+@.\\\~@>
+@.\\\&@>
+@.\\_@> @q CWEAVE does quote an underscore! @>
+ default: out(b);
+ }
+ else if (b!='|') out(b)
+ else {
+ @<Copy the \CEE/ text into the |buffer| array@>;
+ save_loc=loc; save_limit=limit; loc=limit+2; limit=j+1;
+ *limit='|'; output_C();
+ loc=save_loc; limit=save_limit;
+ }
+}
+
+@ @<Skip next char...@>=
+if (*k++!='@@') {
+ printf("\n! Illegal control code in section name: <");
+@.Illegal control code...@>
+ print_section_name(cur_section_name); printf("> "); mark_error;
+}
+
+@ The \CEE/ text enclosed in \pb\ should not contain `\.{\v}' characters,
+except within strings. We put a `\.{\v}' at the front of the buffer, so that an
+error message that displays the whole buffer will look a little bit sensible.
+The variable |delim| is zero outside of strings, otherwise it
+equals the delimiter that began the string being copied.
+
+@<Copy the \CEE/ text into...@>=
+j=limit+1; *j='|'; delim=0;
+while (1) {
+ if (k>=k_limit) {
+ printf("\n! C text in section name didn't end: <");
+@.C text...didn't end@>
+ print_section_name(cur_section_name); printf("> "); mark_error; break;
+ }
+ b=*(k++);
+ if (b=='@@' || (b=='\\' && delim!=0))
+ @<Copy a quoted character into the buffer@>
+ else {
+ if (b=='\'' || b=='"')
+ if (delim==0) delim=b;
+ else if (delim==b) delim=0;
+ if (b!='|' || delim!=0) {
+ if (j>buffer+long_buf_size-3) overflow("buffer");
+ *(++j)=b;
+ }
+ else break;
+ }
+}
+
+@ @<Copy a quoted char...@>= {
+ if (j>buffer+long_buf_size-4) overflow("buffer");
+ *(++j)=b; *(++j)=*(k++);
+}
+
+@** Phase two processing.
+We have assembled enough pieces of the puzzle in order to be ready to specify
+the processing in \.{CWEAVE}'s main pass over the source file. Phase two
+is analogous to phase one, except that more work is involved because we must
+actually output the \TEX/ material instead of merely looking at the
+\.{CWEB} specifications.
+
+@<Predecl...@>=
+void phase_two();
+
+@ @c
+void
+phase_two() {
+reset_input(); if (show_progress) printf("\nWriting the output file...");
+@.Writing the output file...@>
+section_count=0; format_visible=1; copy_limbo();
+finish_line(); flush_buffer(out_buf,0,0); /* insert a blank line, it looks nice */
+while (!input_has_ended) @<Translate the current section@>;
+}
+
+@ The output file will contain the control sequence \.{\\Y} between non-null
+sections of a section, e.g., between the \TEX/ and definition parts if both
+are nonempty. This puts a little white space between the parts when they are
+printed. However, we don't want \.{\\Y} to occur between two definitions
+within a single section. The variables |out_line| or |out_ptr| will
+change if a section is non-null, so the following macros `|save_position|'
+and `|emit_space_if_needed|' are able to handle the situation:
+
+@d save_position save_line=out_line; save_place=out_ptr
+@d emit_space_if_needed if (save_line!=out_line || save_place!=out_ptr)
+ out_str("\\Y");
+ space_checked=1
+@.\\Y@>
+
+@<Global...@>=
+int save_line; /* former value of |out_line| */
+char *save_place; /* former value of |out_ptr| */
+int sec_depth; /* the integer, if any, following \.{@@*} */
+boolean space_checked; /* have we done |emit_space_if_needed|? */
+boolean format_visible; /* should the next format declaration be output? */
+boolean doing_format=0; /* are we outputting a format declaration? */
+boolean group_found=0; /* has a starred section occurred? */
+
+@ @<Translate the current section@>= {
+ section_count++;
+ @<Output the code for the beginning of a new section@>;
+ save_position;
+ @<Translate the \TEX/ part of the current section@>;
+ @<Translate the definition part of the current section@>;
+ @<Translate the \CEE/ part of the current section@>;
+ @<Show cross-references to this section@>;
+ @<Output the code for the end of a section@>;
+}
+
+@ Sections beginning with the \.{CWEB} control sequence `\.{@@\ }' start in the
+output with the \TEX/ control sequence `\.{\\M}', followed by the section
+number. Similarly, `\.{@@*}' sections lead to the control sequence `\.{\\N}'.
+In this case there's an additional parameter, representing one plus the
+specified depth, immediately after the \.{\\N}.
+If the section has changed, we put \.{\\*} just after the section number.
+
+@<Output the code for the beginning...@>=
+if (*(loc-1)!='*') out_str("\\M");
+@.\\M@>
+else {
+ while (*loc == ' ') loc++;
+ if (*loc=='*') { /* ``top'' level */
+ sec_depth = -1;
+ loc++;
+ }
+ else {
+ for (sec_depth=0; xisdigit(*loc);loc++)
+ sec_depth = sec_depth*10 + (*loc) -'0';
+ }
+ while (*loc == ' ') loc++; /* remove spaces before group title */
+ group_found=1;
+ out_str("\\N");
+@.\\N@>
+ {@+ char s[32];@+sprintf(s,"{%d}",sec_depth+1);@+out_str(s);@+}
+ if (show_progress)
+ printf("*%d",section_count); update_terminal; /* print a progress report */
+}
+out_str("{");out_section(section_count); out_str("}");
+
+@ In the \TEX/ part of a section, we simply copy the source text, except that
+index entries are not copied and \CEE/ text within \pb\ is translated.
+
+@<Translate the \T...@>= do {
+ next_control=copy_TeX();
+ switch (next_control) {
+ case '|': init_stack; output_C(); break;
+ case '@@': out('@@'); break;
+ case TeX_string: case noop:
+ case xref_roman: case xref_wildcard: case xref_typewriter:
+ case section_name: loc-=2; next_control=get_next(); /* skip to \.{@@>} */
+ if (next_control==TeX_string)
+ err_print("! TeX string should be in C text only"); break;
+@.TeX string should be...@>
+ case thin_space: case math_break: case ord:
+ case line_break: case big_line_break: case no_line_break: case join:
+ case pseudo_semi: case macro_arg_open: case macro_arg_close:
+ case output_defs_code:
+ err_print("! You can't do that in TeX text"); break;
+@.You can't do that...@>
+ }
+} while (next_control<format_code);
+
+@ When we get to the following code we have |next_control>=format_code|, and
+the token memory is in its initial empty state.
+
+@<Translate the d...@>=
+space_checked=0;
+while (next_control<=definition) { /* |format_code| or |definition| */
+ init_stack;
+ if (next_control==definition) @<Start a macro definition@>@;
+ else @<Start a format definition@>;
+ outer_parse(); finish_C(format_visible); format_visible=1;
+ doing_format=0;
+}
+
+@ The |finish_C| procedure outputs the translation of the current
+scraps, preceded by the control sequence `\.{\\B}' and followed by the
+control sequence `\.{\\par}'. It also restores the token and scrap
+memories to their initial empty state.
+
+A |force| token is appended to the current scraps before translation
+takes place, so that the translation will normally end with \.{\\6} or
+\.{\\7} (the \TEX/ macros for |force| and |big_force|). This \.{\\6} or
+\.{\\7} is replaced by the concluding \.{\\par} or by \.{\\Y\\par}.
+
+@<Predecl...@>=
+void finish_C();
+
+@ @c
+void
+finish_C(visible) /* finishes a definition or a \CEE/ part */
+ boolean visible; /* nonzero if we should produce \TEX/ output */
+{
+ text_pointer p; /* translation of the scraps */
+ if (visible) {
+ out_str("\\B"); app_tok(force); app_scrap(insert,no_math);
+ p=translate();
+@.\\B@>
+ app(tok_flag+(int)(p-tok_start)); make_output(); /* output the list */
+ if (out_ptr>out_buf+1)
+ if (*(out_ptr-1)=='\\')
+@.\\6@>
+@.\\7@>
+@.\\Y@>
+ if (*out_ptr=='6') out_ptr-=2;
+ else if (*out_ptr=='7') *out_ptr='Y';
+ out_str("\\par"); finish_line();
+ }
+ if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
+ if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
+ if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
+ tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrap_ptr=scrap_info;
+ /* forget the tokens and the scraps */
+}
+
+@ Keeping in line with the conventions of the \CEE/ preprocessor (and
+otherwise contrary to the rules of \.{CWEB}) we distinguish here
+between the case that `\.(' immediately follows an identifier and the
+case that the two are separated by a space. In the latter case, and
+if the identifier is not followed by `\.(' at all, the replacement
+text starts immediately after the identifier. In the former case,
+it starts after we scan the matching `\.)'.
+
+@<Start a macro...@>= {
+ if (save_line!=out_line || save_place!=out_ptr || space_checked) app(backup);
+ if(!space_checked){emit_space_if_needed;save_position;}
+ app_str("\\D"); /* this will produce `\&{define }' */
+@.\\D@>
+ if ((next_control=get_next())!=identifier)
+ err_print("! Improper macro definition");
+@.Improper macro definition@>
+ else {
+ app('$'); app_cur_id(0);
+ if (*loc=='(')
+ reswitch: switch (next_control=get_next()) {
+ case '(': case ',': app(next_control); goto reswitch;
+ case identifier: app_cur_id(0); goto reswitch;
+ case ')': app(next_control); next_control=get_next(); break;
+ default: err_print("! Improper macro definition"); break;
+ }
+ else next_control=get_next();
+ app_str("$ "); app(break_space);
+ app_scrap(dead,no_math); /* scrap won't take part in the parsing */
+ }
+}
+
+@ @<Start a format...@>= {
+ doing_format=1;
+ if(*(loc-1)=='s' || *(loc-1)=='S') format_visible=0;
+ if(!space_checked){emit_space_if_needed;save_position;}
+ app_str("\\F"); /* this will produce `\&{format }' */
+@.\\F@>
+ next_control=get_next();
+ if (next_control==identifier) {
+ app(id_flag+(int)(id_lookup(id_first, id_loc,normal)-name_dir));
+ app(' ');
+ app(break_space); /* this is syntactically separate from what follows */
+ next_control=get_next();
+ if (next_control==identifier) {
+ app(id_flag+(int)(id_lookup(id_first, id_loc,normal)-name_dir));
+ app_scrap(exp,maybe_math); app_scrap(semi,maybe_math);
+ next_control=get_next();
+ }
+ }
+ if (scrap_ptr!=scrap_info+2) err_print("! Improper format definition");
+@.Improper format definition@>
+}
+
+@ Finally, when the \TEX/ and definition parts have been treated, we have
+|next_control>=begin_C|. We will make the global variable |this_section|
+point to the current section name, if it has a name.
+
+@<Global...@>=
+name_pointer this_section; /* the current section name, or zero */
+
+@ @<Translate the \CEE/...@>=
+this_section=name_dir;
+if (next_control<=section_name) {
+ emit_space_if_needed; init_stack;
+ if (next_control==begin_C) next_control=get_next();
+ else {
+ this_section=cur_section;
+ @<Check that '=' or '==' follows this section name, and
+ emit the scraps to start the section definition@>;
+ }
+ while (next_control<=section_name) {
+ outer_parse();
+ @<Emit the scrap for a section name if present@>;
+ }
+ finish_C(1);
+}
+
+@ The title of the section and an $\E$ or $\mathrel+\E$ are made
+into a scrap that should not take part in the parsing.
+
+@<Check that '='...@>=
+do next_control=get_next();
+ while (next_control=='+'); /* allow optional `\.{+=}' */
+if (next_control!='=' && next_control!=eq_eq)
+ err_print("! You need an = sign after the section name");
+@.You need an = sign...@>
+ else next_control=get_next();
+if (out_ptr>out_buf+1 && *out_ptr=='Y' && *(out_ptr-1)=='\\') app(backup);
+ /* the section name will be flush left */
+@.\\Y@>
+app(section_flag+(int)(this_section-name_dir));
+cur_xref=(xref_pointer)this_section->xref;
+if(cur_xref->num==file_flag) cur_xref=cur_xref->xlink;
+app_str("${}");
+if (cur_xref->num!=section_count+def_flag) {
+ app_str("\\mathrel+"); /*section name is multiply defined*/
+ this_section=name_dir; /*so we won't give cross-reference info here*/
+}
+app_str("\\E"); /* output an equivalence sign */
+@.\\E@>
+app_str("{}$");
+app(force); app_scrap(dead,no_math);
+ /* this forces a line break unless `\.{@@+}' follows */
+
+@ @<Emit the scrap...@>=
+if (next_control<section_name) {
+ err_print("! You can't do that in C text");
+@.You can't do that...@>
+ next_control=get_next();
+}
+else if (next_control==section_name) {
+ app(section_flag+(int)(cur_section-name_dir));
+ app_scrap(section_scrap,maybe_math);
+ next_control=get_next();
+}
+
+@ Cross references relating to a named section are given
+after the section ends.
+
+@<Show cross...@>=
+if (this_section>name_dir) {
+ cur_xref=(xref_pointer)this_section->xref;
+ if (cur_xref->num==file_flag){an_output=1;cur_xref=cur_xref->xlink;}
+ else an_output=0;
+ if (cur_xref->num>def_flag)
+ cur_xref=cur_xref->xlink; /* bypass current section number */
+ footnote(def_flag); footnote(cite_flag); footnote(0);
+}
+
+@ The |footnote| procedure gives cross-reference information about
+multiply defined section names (if the |flag| parameter is
+|def_flag|), or about references to a section name
+(if |flag==cite_flag|), or to its uses (if |flag==0|). It assumes that
+|cur_xref| points to the first cross-reference entry of interest, and it
+leaves |cur_xref| pointing to the first element not printed. Typical outputs:
+`\.{\\A101.}'; `\.{\\Us 370\\ET1009.}';
+`\.{\\As 8, 27\\*\\ETs64.}'.
+
+Note that the output of \.{CWEAVE} is not English-specific; users may
+supply new definitions for the macros \.{\\A}, \.{\\As}, etc.
+
+@<Predecl...@>=
+void footnote();
+
+@ @c
+void
+footnote(flag) /* outputs section cross-references */
+sixteen_bits flag;
+{
+ xref_pointer q; /* cross-reference pointer variable */
+ if (cur_xref->num<=flag) return;
+ finish_line(); out('\\');
+@.\\A@>
+@.\\Q@>
+@.\\U@>
+ out(flag==0? 'U': flag==cite_flag? 'Q': 'A');
+ @<Output all the section numbers on the reference list |cur_xref|@>;
+ out('.');
+}
+
+@ The following code distinguishes three cases, according as the number
+of cross-references is one, two, or more than two. Variable |q| points
+to the first cross-reference, and the last link is a zero.
+
+@<Output all the section numbers...@>=
+q=cur_xref; if (q->xlink->num>flag) out('s'); /* plural */
+while (1) {
+ out_section(cur_xref->num-flag);
+ cur_xref=cur_xref->xlink; /* point to the next cross-reference to output */
+ if (cur_xref->num<=flag) break;
+ if (cur_xref->xlink->num>flag) out_str(", "); /* not the last */
+ else {out_str("\\ET"); /* the last */
+@.\\ET@>
+ if (cur_xref != q->xlink) out('s'); /* the last of more than two */
+ }
+}
+
+@ @<Output the code for the end of a section@>=
+out_str("\\fi"); finish_line();
+@.\\fi@>
+flush_buffer(out_buf,0,0); /* insert a blank line, it looks nice */
+
+@** Phase three processing.
+We are nearly finished! \.{CWEAVE}'s only remaining task is to write out the
+index, after sorting the identifiers and index entries.
+
+If the user has set the |no_xref| flag (the \.{-x} option on the command line),
+just finish off the page, omitting the index, section name list, and table of
+contents.
+
+@<Predecl...@>=
+void phase_three();
+
+@ @c
+void
+phase_three() {
+if (no_xref) {
+ finish_line();
+ out_str("\\end");
+@.\\end@>
+ finish_line();
+}
+else {
+ phase=3; if (show_progress) printf("\nWriting the index...");
+@.Writing the index...@>
+ finish_line();
+ if ((idx_file=fopen(idx_file_name,"w"))==NULL)
+ fatal("! Cannot open index file ",idx_file_name);
+@.Cannot open index file@>
+ if (change_exists) {
+ @<Tell about changed sections@>; finish_line(); finish_line();
+ }
+ out_str("\\inx"); finish_line();
+@.\\inx@>
+ active_file=idx_file; /* change active file to the index file */
+ @<Do the first pass of sorting@>;
+ @<Sort and output the index@>;
+ finish_line(); fclose(active_file); /* finished with |idx_file| */
+ active_file=tex_file; /* switch back to |tex_file| for a tic */
+ out_str("\\fin"); finish_line();
+@.\\fin@>
+ if ((scn_file=fopen(scn_file_name,"w"))==NULL)
+ fatal("! Cannot open section file ",scn_file_name);
+@.Cannot open section file@>
+ active_file=scn_file; /* change active file to section listing file */
+ @<Output all the section names@>;
+ finish_line(); fclose(active_file); /* finished with |scn_file| */
+ active_file=tex_file;
+ if (group_found) out_str("\\con");@+else out_str("\\end");
+@.\\con@>
+@.\\end@>
+ finish_line();
+ fclose(active_file);
+}
+if (show_happiness) printf("\nDone.");
+check_complete(); /* was all of the change file used? */
+}
+
+@ Just before the index comes a list of all the changed sections, including
+the index section itself.
+
+@<Global...@>=
+sixteen_bits k_section; /* runs through the sections */
+
+@ @<Tell about changed sections@>= {
+ /* remember that the index is already marked as changed */
+ k_section=0;
+ while (!changed_section[++k_section]);
+ out_str("\\ch ");
+@.\\ch@>
+ out_section(k_section);
+ while (k_section<section_count) {
+ while (!changed_section[++k_section]);
+ out_str(", "); out_section(k_section);
+ }
+ out('.');
+}
+
+@ A left-to-right radix sorting method is used, since this makes it easy to
+adjust the collating sequence and since the running time will be at worst
+proportional to the total length of all entries in the index. We put the
+identifiers into 102 different lists based on their first characters.
+(Uppercase letters are put into the same list as the corresponding lowercase
+letters, since we want to have `$t<\\{TeX}<\&{to}$'.) The
+list for character |c| begins at location |bucket[c]| and continues through
+the |blink| array.
+
+@<Global...@>=
+name_pointer bucket[256];
+name_pointer next_name; /* successor of |cur_name| when sorting */
+name_pointer blink[max_names]; /* links in the buckets */
+
+@ To begin the sorting, we go through all the hash lists and put each entry
+having a nonempty cross-reference list into the proper bucket.
+
+@<Do the first pass...@>= {
+int c;
+for (c=0; c<=255; c++) bucket[c]=NULL;
+for (h=hash; h<=hash_end; h++) {
+ next_name=*h;
+ while (next_name) {
+ cur_name=next_name; next_name=cur_name->link;
+ if (cur_name->xref!=(char*)xmem) {
+ c=(eight_bits)((cur_name->byte_start)[0]);
+ if (xisupper(c)) c=tolower(c);
+ blink[cur_name-name_dir]=bucket[c]; bucket[c]=cur_name;
+ }
+ }
+}
+}
+
+@ During the sorting phase we shall use the |cat| and |trans| arrays from
+\.{CWEAVE}'s parsing algorithm and rename them |depth| and |head|. They now
+represent a stack of identifier lists for all the index entries that have
+not yet been output. The variable |sort_ptr| tells how many such lists are
+present; the lists are output in reverse order (first |sort_ptr|, then
+|sort_ptr-1|, etc.). The |j|th list starts at |head[j]|, and if the first
+|k| characters of all entries on this list are known to be equal we have
+|depth[j]==k|.
+
+@ @<Rest of |trans_plus| union@>=
+name_pointer Head;
+
+@ @d depth cat /* reclaims memory that is no longer needed for parsing */
+@d head trans_plus.Head /* ditto */
+@f sort_pointer int
+@d sort_pointer scrap_pointer /* ditto */
+@d sort_ptr scrap_ptr /* ditto */
+@d max_sorts max_scraps /* ditto */
+
+@<Global...@>=
+eight_bits cur_depth; /* depth of current buckets */
+char *cur_byte; /* index into |byte_mem| */
+sixteen_bits cur_val; /* current cross-reference number */
+sort_pointer max_sort_ptr; /* largest value of |sort_ptr| */
+
+@ @<Set init...@>=
+max_sort_ptr=scrap_info;
+
+@ The desired alphabetic order is specified by the |collate| array; namely,
+$|collate|[0]<|collate|[1]<\cdots<|collate|[100]$.
+
+@<Global...@>=
+eight_bits collate[102+128]; /* collation order */
+@^high-bit character handling@>
+
+@ We use the order $\hbox{null}<\.\ <\hbox{other characters}<{}$\.\_${}<
+\.A=\.a<\cdots<\.Z=\.z<\.0<\cdots<\.9.$ Warning: The collation mapping
+needs to be changed if ASCII code is not being used.
+@^ASCII code dependencies@>
+@^high-bit character handling@>
+
+We initialize |collate| by copying a few characters at a time, because
+some \CEE/ compilers choke on long strings.
+
+@<Set init...@>=
+collate[0]=0;
+strcpy(collate+1," \1\2\3\4\5\6\7\10\11\12\13\14\15\16\17");
+/* 16 characters + 1 = 17 */
+strcpy(collate+17,"\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37");
+/* 16 characters + 17 = 33 */
+strcpy(collate+33,"!\42#$%&'()*+,-./:;<=>?@@[\\]^`{|}~_");
+/* 32 characters + 33 = 65 */
+strcpy(collate+65,"abcdefghijklmnopqrstuvwxyz0123456789");
+/* (26 + 10) characters + 65 = 101 */
+strcpy(collate+101,"\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217");
+/* 16 characters + 101 = 117 */
+strcpy(collate+117,"\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237");
+/* 16 characters + 117 = 133 */
+strcpy(collate+133,"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257");
+/* 16 characters + 133 = 149 */
+strcpy(collate+149,"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277");
+/* 16 characters + 149 = 165 */
+strcpy(collate+165,"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317");
+/* 16 characters + 165 = 181 */
+strcpy(collate+181,"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337");
+/* 16 characters + 181 = 197 */
+strcpy(collate+197,"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357");
+/* 16 characters + 197 = 213 */
+strcpy(collate+213,"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377");
+/* 16 characters + 213 = 229 */
+
+@ Procedure |unbucket| goes through the buckets and adds nonempty lists
+to the stack, using the collating sequence specified in the |collate| array.
+The parameter to |unbucket| tells the current depth in the buckets.
+Any two sequences that agree in their first 255 character positions are
+regarded as identical.
+
+@d infinity 255 /* $\infty$ (approximately) */
+
+@<Predecl...@>=
+void unbucket();
+
+@ @c
+void
+unbucket(d) /* empties buckets having depth |d| */
+eight_bits d;
+{
+ int c; /* index into |bucket|; cannot be a simple |char| because of sign
+ comparison below*/
+ for (c=100+128; c>= 0; c--) if (bucket[collate[c]]) {
+@^high-bit character handling@>
+ if (sort_ptr>=scrap_info_end) overflow("sorting");
+ sort_ptr++;
+ if (sort_ptr>max_sort_ptr) max_sort_ptr=sort_ptr;
+ if (c==0) sort_ptr->depth=infinity;
+ else sort_ptr->depth=d;
+ sort_ptr->head=bucket[collate[c]]; bucket[collate[c]]=NULL;
+ }
+}
+
+@ @<Sort and output...@>=
+sort_ptr=scrap_info; unbucket(1);
+while (sort_ptr>scrap_info) {
+ cur_depth=sort_ptr->depth;
+ if (blink[sort_ptr->head-name_dir]==0 || cur_depth==infinity)
+ @<Output index entries for the list at |sort_ptr|@>@;
+ else @<Split the list at |sort_ptr| into further lists@>;
+}
+
+@ @<Split the list...@>= {
+ eight_bits c;
+ next_name=sort_ptr->head;
+ do {
+ cur_name=next_name; next_name=blink[cur_name-name_dir];
+ cur_byte=cur_name->byte_start+cur_depth;
+ if (cur_byte==(cur_name+1)->byte_start) c=0; /* hit end of the name */
+ else {
+ c=(eight_bits) *cur_byte;
+ if (xisupper(c)) c=tolower(c);
+ }
+ blink[cur_name-name_dir]=bucket[c]; bucket[c]=cur_name;
+ } while (next_name);
+ --sort_ptr; unbucket(cur_depth+1);
+}
+
+@ @<Output index...@>= {
+ cur_name=sort_ptr->head;
+ do {
+ out_str("\\I");
+@.\\I@>
+ @<Output the name at |cur_name|@>;
+ @<Output the cross-references at |cur_name|@>;
+ cur_name=blink[cur_name-name_dir];
+ } while (cur_name);
+ --sort_ptr;
+}
+
+@ @<Output the name...@>=
+switch (cur_name->ilk) {
+ case normal: if (is_tiny(cur_name)) out_str("\\|");
+ else {char *j;
+ for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++)
+ if (xislower(*j)) goto lowcase;
+ out_str("\\."); break;
+lowcase: out_str("\\\\");
+ }
+ break;
+@.\\|@>
+@.\\.@>
+@.\\\\@>
+ case roman: break;
+ case wildcard: out_str("\\9"); break;
+@.\\9@>
+ case typewriter: out_str("\\."); break;
+@.\\.@>
+ case custom: case quoted: {char *j; out_str("$\\");
+ for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++)
+ out(isxalpha(*j)? 'x' : *j);
+ out('$');
+ goto name_done;
+ }
+ default: out_str("\\&");
+@.\\\&@>
+}
+out_name(cur_name);
+name_done:
+
+@ Section numbers that are to be underlined are enclosed in
+`\.{\\[}$\,\ldots\,$\.]'.
+
+@<Output the cross-references...@>=
+@<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>;
+do {
+ out_str(", "); cur_val=cur_xref->num;
+ if (cur_val<def_flag) out_section(cur_val);
+ else {out_str("\\["); out_section(cur_val-def_flag); out(']');}
+@.\\[@>
+ cur_xref=cur_xref->xlink;
+} while (cur_xref!=xmem);
+out('.'); finish_line();
+
+@ List inversion is best thought of as popping elements off one stack and
+pushing them onto another. In this case |cur_xref| will be the head of
+the stack that we push things onto.
+@<Global...@>=
+xref_pointer next_xref, this_xref;
+ /* pointer variables for rearranging a list */
+
+@ @<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>=
+this_xref=(xref_pointer)cur_name->xref; cur_xref=xmem;
+do {
+ next_xref=this_xref->xlink; this_xref->xlink=cur_xref;
+ cur_xref=this_xref; this_xref=next_xref;
+} while (this_xref!=xmem);
+
+@ The following recursive procedure walks through the tree of section names and
+prints them.
+@^recursion@>
+
+@<Predecl...@>=
+void section_print();
+
+@ @c
+void
+section_print(p) /* print all section names in subtree |p| */
+name_pointer p;
+{
+ if (p) {
+ section_print(p->llink); out_str("\\I");
+@.\\I@>
+ tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrap_ptr=scrap_info; init_stack;
+ app(p-name_dir+section_flag); make_output();
+ footnote(cite_flag);
+ footnote(0); /* |cur_xref| was set by |make_output| */
+ finish_line();@/
+ section_print(p->rlink);
+ }
+}
+
+@ @<Output all the section names@>=section_print(root)
+
+@ Because on some systems the difference between two pointers is a |long|
+rather than an |int|, we use \.{\%ld} to print these quantities.
+
+@c
+void
+print_stats() {
+ printf("\nMemory usage statistics:\n");
+@.Memory usage statistics:@>
+ printf("%ld names (out of %ld)\n",
+ (long)(name_ptr-name_dir),(long)max_names);
+ printf("%ld cross-references (out of %ld)\n",
+ (long)(xref_ptr-xmem),(long)max_refs);
+ printf("%ld bytes (out of %ld)\n",
+ (long)(byte_ptr-byte_mem),(long)max_bytes);
+ printf("Parsing:\n");
+ printf("%ld scraps (out of %ld)\n",
+ (long)(max_scr_ptr-scrap_info),(long)max_scraps);
+ printf("%ld texts (out of %ld)\n",
+ (long)(max_text_ptr-tok_start),(long)max_texts);
+ printf("%ld tokens (out of %ld)\n",
+ (long)(max_tok_ptr-tok_mem),(long)max_toks);
+ printf("%ld levels (out of %ld)\n",
+ (long)(max_stack_ptr-stack),(long)stack_size);
+ printf("Sorting:\n");
+ printf("%ld levels (out of %ld)\n",
+ (long)(max_sort_ptr-scrap_info),(long)max_scraps);
+}
+
+@** Index.
+If you have read and understood the code for Phase III above, you know what
+is in this index and how it got here. All sections in which an identifier is
+used are listed with that identifier, except that reserved words are
+indexed only when they appear in format definitions, and the appearances
+of identifiers in section names are not indexed. Underlined entries
+correspond to where the identifier was declared. Error messages, control
+sequences put into the output, and a few
+other things like ``recursion'' are indexed here too.
diff --git a/web/c_cpp/c2cweb/cweb/cwebmac.ori b/web/c_cpp/c2cweb/cweb/cwebmac.ori
new file mode 100644
index 0000000000..331a2eff46
--- /dev/null
+++ b/web/c_cpp/c2cweb/cweb/cwebmac.ori
@@ -0,0 +1,346 @@
+% This file is part of c2cweb package Version 1.5
+
+% standard macros for CWEB listings (in addition to plain.tex)
+% Version 3.0 --- June 1993
+
+% modified by Werner Lemberg (a7971428@unet.univie.ac.at) 10-Nov-1996
+
+\ifx\documentstyle\undefined\else\endinput\fi % LaTeX will use other macros
+\xdef\fmtversion{\fmtversion+CWEB3.0}
+
+\let\:=\. % preserve a way to get the dot accent
+ % (all other accents will still work as usual)
+
+\parskip 0pt % no stretch between paragraphs
+\parindent 1em % for paragraphs and for the first line of C text
+
+\font\ninerm=cmr9
+\let\mc=\ninerm % medium caps
+\def\CEE/{{\mc C\spacefactor1000}}
+\def\UNIX/{{\mc U\kern-.05emNIX\spacefactor1000}}
+\def\TEX/{\TeX}
+\def\CPLUSPLUS/{{\mc C\PP\spacefactor1000}}
+\def\Cee{\CEE/} % for backward compatibility
+\def\9#1{}
+\font\eightrm=cmr8
+\let\sc=\eightrm % small caps (NOT a caps-and-small-caps font)
+\let\mainfont=\tenrm
+\let\cmntfont\tenrm
+%\font\tenss=cmss10 \let\cmntfont\tenss % alternative comment font
+\font\titlefont=cmr7 scaled\magstep4 % title on the contents page
+\font\ttitlefont=cmtt10 scaled\magstep2 % typewriter type in title
+\font\tentex=cmtex10 % TeX extended character set (used in strings)
+\fontdimen7\tentex=0pt % no double space after sentences
+
+\def\${\ifmmode \hbox{\sl \char`\$}
+ \else \hbox{\ifdim \fontdimen1\font > 0pt \sl \fi \char`\$}\fi}
+
+\def\\#1{\leavevmode\hbox{\it#1\/\kern.05em}} % italic type for identifiers
+\def\|#1{\leavevmode\hbox{$#1$}} % one-letter identifiers look better this way
+\def\&#1{\leavevmode\hbox{\bf
+ \def\_{\kern.04em\vbox{\hrule width.3em height .6pt}\kern.08em}%
+ #1\/\kern.05em}} % boldface type for reserved words
+\def\.#1{\leavevmode\hbox{\tentex % typewriter type for strings
+ \let\\=\BS % backslash in a string
+ \let\{=\LB % left brace in a string
+ \let\}=\RB % right brace in a string
+ \let\~=\TL % tilde in a string
+ \let\ =\SP % space in a string
+ \let\_=\UL % underline in a string
+ \let\&=\AM % ampersand in a string
+ \let\^=\CF % circumflex in a string
+ #1\kern.05em}}
+\def\){\discretionary{\hbox{\tentex\BS}}{}{}}
+\def\AT{@} % at sign for control text (not needed in versions >= 2.9)
+\def\ATL{\par\noindent\bgroup\catcode`\_=12 \postATL} % print @l in limbo
+\def\postATL#1 #2 {\bf letter \\{\uppercase{\char"#1}}
+ tangles as \tentex "#2"\egroup\par}
+\def\noATL#1 #2 {}
+\def\noatl{\let\ATL=\noATL} % suppress output from @l
+\def\ATH{\X\kern-.5em:Preprocessor definitions\X}
+\let\PB=\relax % hook for program brackets |...| in TeX part or section name
+
+\chardef\AM=`\& % ampersand character in a string
+\chardef\BS=`\\ % backslash in a string
+\chardef\LB=`\{ % left brace in a string
+\chardef\RB=`\} % right brace in a string
+\def\SP{{\tt\char`\ }} % (visible) space in a string
+\chardef\TL=`\~ % tilde in a string
+\chardef\UL=`\_ % underline character in a string
+\chardef\CF=`\^ % circumflex character in a string
+
+\newbox\PPbox % symbol for ++
+\setbox\PPbox=\hbox{\kern.5pt\raise1pt\hbox{\sevenrm+\kern-1pt+}\kern.5pt}
+\def\PP{\copy\PPbox}
+\newbox\MMbox \setbox\MMbox=\hbox{\kern.5pt\raise1pt\hbox{\sevensy\char0
+ \kern-1pt\char0}\kern.5pt}
+\def\MM{\copy\MMbox}
+\newbox\MGbox % symbol for ->
+\setbox\MGbox=\hbox{\kern-2pt\lower3pt\hbox{\teni\char'176}\kern1pt}
+\def\MG{\copy\MGbox}
+\newbox\NNbox % symbol for ##
+\setbox\NNbox=\hbox{\kern.5pt\raise2pt\hbox{\#}\kern-4pt
+ \lower2pt\hbox{\#}\kern.5pt}
+\def\NN{\copy\NNbox}
+\def\MRL#1{\mathrel{\let\K==#1}}
+%\def\MRL#1{\KK#1}\def\KK#1#2{\buildrel\;#1\over{#2}}
+\let\GG=\gg
+\let\LL=\ll
+\let\NULL=\Lambda
+\mathchardef\AND="2026 % bitwise and; also \& (unary operator)
+\let\OR=\mid % bitwise or
+\let\XOR=\oplus % bitwise exclusive or
+\def\CM{{\sim}} % bitwise complement
+\newbox\MODbox \setbox\MODbox=\hbox{\eightrm\%}
+\def\MOD{\mathbin{\copy\MODbox}}
+\def\DC{\kern.1em{::}\kern.1em} % symbol for ::
+\def\PA{\mathbin{.*}} % symbol for .*
+\def\MGA{\mathbin{\MG*}} % symbol for ->*
+\def\this{\&{this}}
+
+\newbox\bak \setbox\bak=\hbox to -1em{} % backspace one em
+\newbox\bakk\setbox\bakk=\hbox to -2em{} % backspace two ems
+
+\newcount\ind % current indentation in ems
+\def\1{\global\advance\ind by1\hangindent\ind em} % indent one more notch
+\def\2{\global\advance\ind by-1} % indent one less notch
+\def\3#1{\hfil\penalty#10\hfilneg} % optional break within a statement
+\def\4{\copy\bak} % backspace one notch
+\def\5{\hfil\penalty-1\hfilneg\kern2.5em\copy\bakk\ignorespaces}% optional break
+\def\6{\ifmmode\else\par % forced break
+ \hangindent\ind em\noindent\kern\ind em\copy\bakk\ignorespaces\fi}
+\def\7{\Y\6} % forced break and a little extra space
+\def\8{\hskip-\ind em\hskip 2em} % no indentation
+
+\newcount\gdepth % depth of current major group, plus one
+\newcount\secpagedepth
+\secpagedepth=3 % page breaks will occur for depths -1, 0, and 1
+\newtoks\gtitle % title of current major group
+\newskip\intersecskip \intersecskip=12pt minus 3pt % space between sections
+\let\yskip=\smallskip
+\def\?{\mathrel?}
+\def\note#1#2.{\Y\noindent{\hangindent2em\baselineskip10pt\eightrm#1~#2.\par}}
+\def\lapstar{\rlap{*}}
+\def\stsec{\rightskip=0pt % get out of C mode (cf. \B)
+ \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50
+ \noindent{\let\*=\lapstar\bf\secstar.\quad}}
+\let\startsection=\stsec
+\def\defin#1{\global\advance\ind by 2 \1\&{#1 } } % begin `define' or `format'
+\def\A{\note{See also section}} % xref for doubly defined section name
+\def\As{\note{See also sections}} % xref for multiply defined section name
+\def\B{\rightskip=0pt plus 100pt minus 10pt % go into C mode
+ \sfcode`;=3000
+ \pretolerance 10000
+ \hyphenpenalty 9999 % so strings can be broken (discretionary \ is inserted)
+ \exhyphenpenalty 10000
+ \global\ind=2 \1\ \unskip}
+\def\C#1{\5\5\quad$/\ast\,${\cmntfont #1}$\,\ast/$}
+\let\SHC\C % "// short comments" treated like "/* ordinary comments */"
+%\def\C#1{\5\5\quad$\triangleright\,${\cmntfont#1}$\,\triangleleft$}
+%\def\SHC#1{\5\5\quad$\diamond\,${\cmntfont#1}}
+\def\D{\defin{\#define}} % macro definition
+\let\E=\equiv % equivalence sign
+\def\ET{ and~} % conjunction between two section numbers
+\def\ETs{, and~} % conjunction between the last two of several section numbers
+\def\F{\defin{format}} % format definition
+\let\G=\ge % greater than or equal sign
+% \H is long Hungarian umlaut accent
+\let\I=\ne % unequal sign
+\def\J{\.{@\&}} % TANGLE's join operation
+\let\K== % assignment operator
+%\let\K=\leftarrow % "honest" alternative to standard assignment operator
+% \L is Polish letter suppressed-L
+\outer\def\M#1{\MN{#1}\ifon\vfil\penalty-100\vfilneg % beginning of section
+ \vskip\intersecskip\startsection\ignorespaces}
+\outer\def\N#1#2#3.{\gdepth=#1\gtitle={#3}\MN{#2}% beginning of starred section
+ \ifon\ifnum#1<\secpagedepth \vfil\eject % force page break if depth is small
+ \else\vfil\penalty-100\vfilneg\vskip\intersecskip\fi\fi
+ \message{*\secno} % progress report
+ \edef\next{\write\cont{\ZZ{#3}{#1}{\secno}% write to contents file
+ {\noexpand\the\pageno}}}\next % \ZZ{title}{depth}{sec}{page}
+ \ifon\startsection{\bf#3.\quad}\ignorespaces}
+\def\MN#1{\par % common code for \M, \N
+ {\xdef\secstar{#1}\let\*=\empty\xdef\secno{#1}}% remove \* from section name
+ \ifx\secno\secstar \onmaybe \else\ontrue \fi
+ \mark{{{\tensy x}\secno}{\the\gdepth}{\the\gtitle}}}
+% each \mark is {section reference or null}{depth plus 1}{group title}
+% \O is Scandinavian letter O-with-slash
+% \P is paragraph sign
+\def\Q{\note{This code is cited in section}} % xref for mention of a section
+\def\Qs{\note{This code is cited in sections}} % xref for mentions of a section
+\let\R=\lnot % logical not
+% \S is section sign
+\def\T#1{\leavevmode % octal, hex or decimal constant
+ \hbox{$\def\?{\kern.2em}%
+ \def\$##1{\egroup_{\,\rm##1}\bgroup}% suffix to constant
+ \def\_{\cdot 10^{\aftergroup}}% power of ten (via dirty trick)
+ \let\~=\oct \let\^=\hex {#1}$}}
+\def\U{\note{This code is used in section}} % xref for use of a section
+\def\Us{\note{This code is used in sections}} % xref for uses of a section
+\let\V=\lor % logical or
+\let\W=\land % logical and
+\def\X#1:#2\X{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % section name
+ \XX$\langle\,${#2\eightrm\kern.5em#1}$\,\rangle$\XX}
+\def\Y{\par\yskip}
+\let\Z=\le
+\let\ZZ=\let % now you can \write the control sequence \ZZ
+\let\*=*
+
+%\def\oct{\hbox{\rm\char'23\kern-.2em\it\aftergroup\?\aftergroup}} % WEB style
+%\def\hex{\hbox{\rm\char"7D\tt\aftergroup}} % WEB style
+\def\oct{\hbox{$^\circ$\kern-.1em\it\aftergroup\?\aftergroup}}% CWEB style
+\def\hex{\hbox{$^{\scriptscriptstyle\#}$\tt\aftergroup}} % CWEB style
+\def\vb#1{\leavevmode\hbox{\kern2pt\vrule\vtop{\vbox{\hrule
+ \hbox{\strut\kern2pt\.{#1}\kern2pt}}
+ \hrule}\vrule\kern2pt}} % verbatim string
+
+\def\onmaybe{\let\ifon=\maybe} \let\maybe=\iftrue
+\newif\ifon \newif\iftitle \newif\ifpagesaved
+
+\def\lheader{\mainfont\the\pageno\eightrm\qquad\grouptitle\hfill\title\qquad
+ \mainfont\topsecno} % top line on left-hand pages
+\def\rheader{\mainfont\topsecno\eightrm\qquad\title\hfill\grouptitle
+ \qquad\mainfont\the\pageno} % top line on right-hand pages
+\def\grouptitle{\let\i=I\let\j=J\uppercase\expandafter{\expandafter
+ \takethree\topmark}}
+\def\topsecno{\expandafter\takeone\topmark}
+\def\takeone#1#2#3{#1}
+\def\taketwo#1#2#3{#2}
+\def\takethree#1#2#3{#3}
+\def\nullsec{\eightrm\kern-2em} % the \kern-2em cancels \qquad in headers
+
+\let\page=\pagebody \raggedbottom
+% \def\page{\box255 }\normalbottom % faster, but loses plain TeX footnotes
+\def\normaloutput#1#2#3{\ifodd\pageno\hoffset=\pageshift\fi
+ \shipout\vbox{
+ \vbox to\fullpageheight{
+ \iftitle\global\titlefalse
+ \else\hbox to\pagewidth{\vbox to10pt{}\ifodd\pageno #3\else#2\fi}\fi
+ \vfill#1}} % parameter #1 is the page itself
+ \global\advance\pageno by1}
+
+\gtitle={\.{CWEB} output} % this running head is reset by starred sections
+\mark{\noexpand\nullsec0{\the\gtitle}}
+\def\title{\expandafter\uppercase\expandafter{\jobname}}
+\def\topofcontents{\centerline{\titlefont\title}\vskip.7in
+ \vfill} % this material will start the table of contents page
+\def\botofcontents{\vfill
+ \centerline{\covernote}} % this material will end the table of contents page
+\def\covernote{}
+\def\contentspagenumber{0} % default page number for table of contents
+\newdimen\pagewidth \pagewidth=6.5in % the width of each page
+\newdimen\pageheight \pageheight=8.7in % the height of each page
+\newdimen\fullpageheight \fullpageheight=9in % page height including headlines
+\newdimen\pageshift \pageshift=0in % shift righthand pages wrt lefthand ones
+\def\magnify#1{\mag=#1\pagewidth=6.5truein\pageheight=8.7truein
+ \fullpageheight=9truein\setpage}
+\def\setpage{\hsize\pagewidth\vsize\pageheight} % use after changing page size
+\def\contentsfile{\jobname.toc} % file that gets table of contents info
+\def\readcontents{\input \contentsfile}
+\def\readindex{\input \jobname.idx}
+\def\readsections{\input \jobname.scn}
+
+\newwrite\cont
+\output{\setbox0=\page % the first page is garbage
+ \openout\cont=\contentsfile
+ \write\cont{\catcode `\noexpand\@=11\relax} % \makeatletter
+ \global\output{\normaloutput\page\lheader\rheader}}
+\setpage
+\vbox to \vsize{} % the first \topmark won't be null
+
+\def\ch{\note{The following sections were changed by the change file:}
+ \let\*=\relax}
+\newbox\sbox % saved box preceding the index
+\newbox\lbox % lefthand column in the index
+\def\inx{\par\vskip6pt plus 1fil % we are beginning the index
+ \def\page{\box255 } \normalbottom
+ \write\cont{} % ensure that the contents file isn't empty
+ \write\cont{\catcode `\noexpand\@=12\relax} % \makeatother
+ \closeout\cont % the contents information has been fully gathered
+ \output{\ifpagesaved\normaloutput{\box\sbox}\lheader\rheader\fi
+ \global\setbox\sbox=\page \global\pagesavedtrue}
+ \pagesavedfalse \eject % eject the page-so-far and predecessors
+ \setbox\sbox\vbox{\unvbox\sbox} % take it out of its box
+ \vsize=\pageheight \advance\vsize by -\ht\sbox % the remaining height
+ \hsize=.5\pagewidth \advance\hsize by -10pt
+ % column width for the index (20pt between cols)
+ \parfillskip 0pt plus .6\hsize % try to avoid almost empty lines
+ \def\lr{L} % this tells whether the left or right column is next
+ \output{\if L\lr\global\setbox\lbox=\page \gdef\lr{R}
+ \else\normaloutput{\vbox to\pageheight{\box\sbox\vss
+ \hbox to\pagewidth{\box\lbox\hfil\page}}}\lheader\rheader
+ \global\vsize\pageheight\gdef\lr{L}\global\pagesavedfalse\fi}
+ \message{Index:}
+ \parskip 0pt plus .5pt
+ \outer\def\I##1, {\par\hangindent2em\noindent##1:\kern1em} % index entry
+ \def\[##1]{$\underline{##1}$} % underlined index item
+ \rm \rightskip0pt plus 2.5em \tolerance 10000 \let\*=\lapstar
+ \hyphenpenalty 10000 \parindent0pt
+ \readindex}
+\def\fin{\par\vfill\eject % this is done when we are ending the index
+ \ifpagesaved\null\vfill\eject\fi % output a null index column
+ \if L\lr\else\null\vfill\eject\fi % finish the current page
+ \parfillskip 0pt plus 1fil
+ \def\grouptitle{NAMES OF THE SECTIONS}
+ \let\topsecno=\nullsec
+ \message{Section names:}
+ \output={\normaloutput\page\lheader\rheader}
+ \setpage
+ \def\note##1##2.{\quad{\eightrm##1~##2.}}
+ \def\Q{\note{Cited in section}} % crossref for mention of a section
+ \def\Qs{\note{Cited in sections}} % crossref for mentions of a section
+ \def\U{\note{Used in section}} % crossref for use of a section
+ \def\Us{\note{Used in sections}} % crossref for uses of a section
+ \def\I{\par\hangindent 2em}\let\*=*
+ \readsections}
+\def\con{\par\vfill\eject % finish the section names
+% \ifodd\pageno\else\titletrue\null\vfill\eject\fi % for duplex printers
+ \rightskip 0pt \hyphenpenalty 50 \tolerance 200
+ \setpage \output={\normaloutput\page\lheader\rheader}
+ \titletrue % prepare to output the table of contents
+ \pageno=\contentspagenumber
+ \def\grouptitle{TABLE OF CONTENTS}
+ \message{Table of contents:}
+ \topofcontents
+ \line{\hfil Section\hbox to3em{\hss Page}}
+ \let\ZZ=\contentsline
+ \readcontents\relax % read the contents info
+ \botofcontents \end} % print the contents page(s) and terminate
+\def\contentsline#1#2#3#4{\ifnum#2=0 \smallbreak\fi
+ \line{\consetup{#2}#1
+ \rm\leaders\hbox to .5em{.\hfil}\hfil\ #3\hbox to3em{\hss#4}}}
+\def\consetup#1{\ifcase#1 \bf % depth -1 (@**)
+ \or % depth 0 (@*)
+ \or \hskip2em % depth 1 (@*1)
+ \or \hskip4em % depth 2 (@*2)
+ \or \hskip6em % depth 3 (@*3)
+ \or \hskip8em % depth 4 (@*4)
+ \or \hskip10em % depth 5 (@*5)
+ \else \hskip12em \fi} % depth 6 or more
+\def\noinx{\let\inx=\end} % no indexes or table of contents
+\def\nosecs{\let\FIN=\fin \def\fin{\let\parfillskip=\end \FIN}}
+ % no index of section names or table of contents
+\def\nocon{\let\con=\end} % no table of contents
+\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}
+\newcount\twodigits
+\def\hours{\twodigits=\time \divide\twodigits by 60 \printtwodigits
+ \multiply\twodigits by-60 \advance\twodigits by\time :\printtwodigits}
+\def\gobbleone1{}
+\def\printtwodigits{\advance\twodigits100
+ \expandafter\gobbleone\number\twodigits
+ \advance\twodigits-100 }
+\def\TeX{{\ifmmode\it\fi
+ \leavevmode\hbox{T\kern-.1667em\lower.424ex\hbox{E}\hskip-.125em X}}}
+\def\,{\relax\ifmmode\mskip\thinmuskip\else\thinspace\fi}
+\def\datethis{\def\startsection{\leftline{\sc\today\ at \hours}\bigskip
+ \let\startsection=\stsec\stsec}}
+ % say `\datethis' in limbo, to get your listing timestamped before section 1
+\def\datecontentspage{%
+ \def\topofcontents{\leftline{\sc\today\ at \hours}\bigskip
+ \centerline{\titlefont\title}\vfill}} % timestamps the contents page
+
+
+% end of cwebmac.tex
diff --git a/web/c_cpp/c2cweb/cweb/cwebmac.tex b/web/c_cpp/c2cweb/cweb/cwebmac.tex
new file mode 100644
index 0000000000..8682fb7372
--- /dev/null
+++ b/web/c_cpp/c2cweb/cweb/cwebmac.tex
@@ -0,0 +1,375 @@
+% This file is part of c2cweb package Version 1.5
+
+% standard macros for CWEB listings (in addition to plain.tex)
+% Version 3.0 --- June 1993
+
+% modified by Werner Lemberg (a7971428@unet.univie.ac.at) 10-Nov-1996
+
+\ifx\documentstyle\undefined\else\endinput\fi % LaTeX will use other macros
+\xdef\fmtversion{\fmtversion+CWEB3.2}
+
+\let\:=\. % preserve a way to get the dot accent
+ % (all other accents will still work as usual)
+
+%\parskip 0pt % no stretch between paragraphs
+%\parindent 1em % for paragraphs and for the first line of C text
+
+\font\ninerm=cmr9
+\let\mc=\ninerm % medium caps
+\def\CEE/{{\mc C\spacefactor1000}}
+\def\UNIX/{{\mc U\kern-.05emNIX\spacefactor1000}}
+\def\TEX/{\TeX}
+\def\CPLUSPLUS/{{\mc C\PP\spacefactor1000}}
+\def\Cee{\CEE/} % for backward compatibility
+\def\9#1{}
+\font\eightrm=cmr8
+\let\sc=\eightrm % small caps (NOT a caps-and-small-caps font)
+\let\mainfont=\tenrm
+\let\cmntfont\tenrm
+%\font\tenss=cmss10 \let\cmntfont\tenss % alternative comment font
+%\font\titlefont=cmr7 scaled\magstep4 % title on the contents page
+\font\titlefont=cmssbx10 scaled\magstep2 % title on the contents page
+\font\ttitlefont=cmtt10 scaled\magstep2 % typewriter type in title
+\font\tentex=cmtex10 % TeX extended character set (used in strings)
+\fontdimen7\tentex=0pt % no double space after sentences
+
+\font\sectionfont=cmssbx10 scaled\magstephalf
+
+\def\${\ifmmode \hbox{\sl \char`\$}
+ \else \hbox{\ifdim \fontdimen1\font > 0pt \sl \fi \char`\$}\fi}
+
+\def\\#1{\leavevmode\hbox{\it#1\/\kern.05em}} % italic type for identifiers
+\def\|#1{\leavevmode\hbox{$#1$}} % one-letter identifiers look better this way
+\def\&#1{\leavevmode\hbox{\bf
+ \def\_{\kern.04em\vbox{\hrule width.3em height .6pt}\kern.08em}%
+ #1\/\kern.05em}} % boldface type for reserved words
+\def\.#1{\leavevmode\hbox{\tentex % typewriter type for strings
+ \let\\=\BS % backslash in a string
+ \let\{=\LB % left brace in a string
+ \let\}=\RB % right brace in a string
+ \let\~=\TL % tilde in a string
+ \let\ =\SP % space in a string
+ \let\_=\UL % underline in a string
+ \let\&=\AM % ampersand in a string
+ \let\^=\CF % circumflex in a string
+ #1\kern.05em}}
+\def\){\discretionary{\hbox{\tentex\BS}}{}{}}
+\def\AT{@} % at sign for control text (not needed in versions >= 2.9)
+\def\ATL{\par\noindent\bgroup\catcode`\_=12 \postATL} % print @l in limbo
+\def\postATL#1 #2 {\bf letter \\{\uppercase{\char"#1}}
+ tangles as \tentex "#2"\egroup\par}
+\def\noATL#1 #2 {}
+\def\noatl{\let\ATL=\noATL} % suppress output from @l
+\def\ATH{\X\kern-.5em:Preprocessor definitions\X}
+\let\PB=\relax % hook for program brackets |...| in TeX part or section name
+
+\chardef\AM=`\& % ampersand character in a string
+\chardef\BS=`\\ % backslash in a string
+\chardef\LB=`\{ % left brace in a string
+\chardef\RB=`\} % right brace in a string
+\def\SP{{\tt\char`\ }} % (visible) space in a string
+\chardef\TL=`\~ % tilde in a string
+\chardef\UL=`\_ % underline character in a string
+\chardef\CF=`\^ % circumflex character in a string
+
+\newbox\PPbox % symbol for ++
+\setbox\PPbox=\hbox{\kern.5pt\raise1pt\hbox{\sevenrm+\kern-1pt+}\kern.5pt}
+\def\PP{\copy\PPbox}
+\newbox\MMbox \setbox\MMbox=\hbox{\kern.5pt\raise1pt\hbox{\sevensy\char0
+ \kern-1pt\char0}\kern.5pt}
+\def\MM{\copy\MMbox}
+\newbox\MGbox % symbol for ->
+\setbox\MGbox=\hbox{\kern-2pt\lower3pt\hbox{\teni\char'176}\kern1pt}
+\def\MG{\copy\MGbox}
+\newbox\NNbox % symbol for ##
+\setbox\NNbox=\hbox{\kern.5pt\raise2pt\hbox{\#}\kern-4pt
+ \lower2pt\hbox{\#}\kern.5pt}
+\def\NN{\copy\NNbox}
+\def\MRL#1{\mathrel{\let\K==#1}}
+%\def\MRL#1{\KK#1}\def\KK#1#2{\buildrel\;#1\over{#2}}
+\let\GG=\gg
+\let\LL=\ll
+\let\NULL=\Lambda
+\mathchardef\AND="2026 % bitwise and; also \& (unary operator)
+\let\OR=\mid % bitwise or
+\let\XOR=\oplus % bitwise exclusive or
+\def\CM{{\sim}} % bitwise complement
+\newbox\MODbox \setbox\MODbox=\hbox{\eightrm\%}
+\def\MOD{\mathbin{\copy\MODbox}}
+\def\DC{\kern.1em{::}\kern.1em} % symbol for ::
+\def\PA{\mathbin{.*}} % symbol for .*
+\def\MGA{\mathbin{\MG*}} % symbol for ->*
+\def\this{\&{this}}
+
+\newbox\bak \setbox\bak=\hbox to -1em{} % backspace one em
+\newbox\bakk\setbox\bakk=\hbox to -2em{} % backspace two ems
+
+\newcount\ind % current indentation in ems
+\def\1{\global\advance\ind by1\hangindent\ind em} % indent one more notch
+\def\2{\global\advance\ind by-1} % indent one less notch
+\def\3#1{\hfil\penalty#10\hfilneg} % optional break within a statement
+\def\4{\copy\bak} % backspace one notch
+\def\5{\hfil\penalty-1\hfilneg\kern2.5em\copy\bakk\ignorespaces}% optional break
+\def\6{\ifmmode\else\par % forced break
+ \hangindent\ind em\noindent\kern\ind em\copy\bakk\ignorespaces\fi}
+%\def\7{\Y\6} % forced break and a little extra space
+\def\7{\Y\penalty-150\6} % forced break and a little extra space
+\def\8{\hskip-\ind em\hskip 2em} % no indentation
+
+\newcount\gdepth % depth of current major group, plus one
+\newcount\secpagedepth
+\secpagedepth=3 % page breaks will occur for depths -1, 0, and 1
+\newtoks\gtitle % title of current major group
+\newskip\intersecskip \intersecskip=12pt minus 3pt % space between sections
+%\let\yskip=\smallskip
+\def\yskip{\vskip 5pt plus 1pt minus 1pt}
+\def\?{\mathrel?}
+\def\note#1#2.{\Y\noindent{\hangindent2em\baselineskip10pt\eightrm#1~#2.\par}}
+\def\lapstar{\rlap{*}}
+%\def\stsec{\rightskip=0pt % get out of C mode (cf. \B)
+% \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50
+% \noindent{\let\*=\lapstar\bf\secstar.\quad}}
+\def\stsec{\rightskip=0pt % get out of C mode (cf. \B)
+ \parskip=4pt \parindent=0pt
+ \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50
+ \noindent{\let\*=\lapstar\sectionfont\secstar.\quad}}
+\let\startsection=\stsec
+\def\defin#1{\global\advance\ind by 2 \1\&{#1 } } % begin `define' or `format'
+\def\A{\note{See also section}} % xref for doubly defined section name
+\def\As{\note{See also sections}} % xref for multiply defined section name
+%\def\B{\rightskip=0pt plus 100pt minus 10pt % go into C mode
+% \sfcode`;=3000
+% \pretolerance 10000
+% \hyphenpenalty 9999 % so strings can be broken (discretionary \ is inserted)
+% \exhyphenpenalty 10000
+% \global\ind=2 \1\ \unskip}
+\def\B{\rightskip=0pt plus 100pt minus 10pt % go into C mode
+ \parskip=0pt \parindent=1em
+ \sfcode`;=3000
+ \pretolerance 10000
+ \hyphenpenalty 9999 % so strings can be broken (discretionary \ is inserted)
+ \exhyphenpenalty 10000
+ \global\ind=2 \1\ \unskip}
+%\def\C#1{\5\5\quad$/\ast\,${\cmntfont #1}$\,\ast/$}
+\def\C#1{\5\5\hfill$/\ast\,${\cmntfont #1}$\,\ast/$}
+\let\SHC\C % "// short comments" treated like "/* ordinary comments */"
+%\def\C#1{\5\5\quad$\triangleright\,${\cmntfont#1}$\,\triangleleft$}
+%\def\SHC#1{\5\5\quad$\diamond\,${\cmntfont#1}}
+\def\D{\defin{\#define}} % macro definition
+\let\E=\equiv % equivalence sign
+\def\ET{ and~} % conjunction between two section numbers
+\def\ETs{, and~} % conjunction between the last two of several section numbers
+\def\F{\defin{format}} % format definition
+\let\G=\ge % greater than or equal sign
+% \H is long Hungarian umlaut accent
+\let\I=\ne % unequal sign
+\def\J{\.{@\&}} % TANGLE's join operation
+\let\K== % assignment operator
+%\let\K=\leftarrow % "honest" alternative to standard assignment operator
+% \L is Polish letter suppressed-L
+%\outer\def\M#1{\MN{#1}\ifon\vfil\penalty-100\vfilneg % beginning of section
+% \vskip\intersecskip\startsection\ignorespaces}
+\outer\def\M#1{\MN{#1}\ifon\vfil\penalty-100\vfilneg % beginning of section
+ \vskip\intersecskip\startsection\smallskip\noindent\ignorespaces}
+%\outer\def\N#1#2#3.{\gdepth=#1\gtitle={#3}\MN{#2}% beginning of starred section
+% \ifon\ifnum#1<\secpagedepth \vfil\eject % force page break if depth is small
+% \else\vfil\penalty-100\vfilneg\vskip\intersecskip\fi\fi
+% \message{*\secno} % progress report
+% \edef\next{\write\cont{\ZZ{#3}{#1}{\secno}% write to contents file
+% {\noexpand\the\pageno}}}\next % \ZZ{title}{depth}{sec}{page}
+% \ifon\startsection{\bf#3.\quad}\ignorespaces}
+\outer\def\N#1#2#3.{\gdepth=#1\gtitle={#3}\MN{#2}% beginning of starred section
+ \ifon\ifnum#1<\secpagedepth \vfil\eject % force page break if depth is small
+ \else\vfil\penalty-100\vfilneg\vskip\intersecskip\fi\fi
+ \message{*\secno} % progress report
+ \edef\next{\write\cont{\ZZ{#3}{#1}{\secno}% write to contents file
+ {\noexpand\the\pageno}}}\next % \ZZ{title}{depth}{sec}{page}
+ \ifon\startsection{\sectionfont#3.}\bigskip\noindent\ignorespaces}
+\def\MN#1{\par % common code for \M, \N
+ {\xdef\secstar{#1}\let\*=\empty\xdef\secno{#1}}% remove \* from section name
+ \ifx\secno\secstar \onmaybe \else\ontrue \fi
+ \mark{{{\tensy x}\secno}{\the\gdepth}{\the\gtitle}}}
+% each \mark is {section reference or null}{depth plus 1}{group title}
+% \O is Scandinavian letter O-with-slash
+% \P is paragraph sign
+\def\Q{\note{This code is cited in section}} % xref for mention of a section
+\def\Qs{\note{This code is cited in sections}} % xref for mentions of a section
+%\let\R=\lnot % logical not
+\def\R{\mathord ! \,} % logical not
+% \S is section sign
+\def\T#1{\leavevmode % octal, hex or decimal constant
+ \hbox{$\def\?{\kern.2em}%
+ \def\$##1{\egroup_{\,\rm##1}\bgroup}% suffix to constant
+ \def\_{\cdot 10^{\aftergroup}}% power of ten (via dirty trick)
+ \let\~=\oct \let\^=\hex {#1}$}}
+\def\U{\note{This code is used in section}} % xref for use of a section
+\def\Us{\note{This code is used in sections}} % xref for uses of a section
+\let\V=\lor % logical or
+\let\W=\land % logical and
+\def\X#1:#2\X{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % section name
+ \XX$\langle\,${#2\eightrm\kern.5em#1}$\,\rangle$\XX}
+\def\Y{\par\yskip}
+\let\Z=\le
+\let\ZZ=\let % now you can \write the control sequence \ZZ
+\let\*=*
+
+%\def\oct{\hbox{\rm\char'23\kern-.2em\it\aftergroup\?\aftergroup}} % WEB style
+%\def\hex{\hbox{\rm\char"7D\tt\aftergroup}} % WEB style
+\def\oct{\hbox{$^\circ$\kern-.1em\it\aftergroup\?\aftergroup}}% CWEB style
+\def\hex{\hbox{$^{\scriptscriptstyle\#}$\tt\aftergroup}} % CWEB style
+\def\vb#1{\leavevmode\hbox{\kern2pt\vrule\vtop{\vbox{\hrule
+ \hbox{\strut\kern2pt\.{#1}\kern2pt}}
+ \hrule}\vrule\kern2pt}} % verbatim string
+
+\def\onmaybe{\let\ifon=\maybe} \let\maybe=\iftrue
+\newif\ifon \newif\iftitle \newif\ifpagesaved
+
+\def\lheader{\mainfont\the\pageno\eightrm\qquad\grouptitle\hfill\title\qquad
+ \mainfont\topsecno} % top line on left-hand pages
+\def\rheader{\mainfont\topsecno\eightrm\qquad\title\hfill\grouptitle
+ \qquad\mainfont\the\pageno} % top line on right-hand pages
+\def\grouptitle{\let\i=I\let\j=J\uppercase\expandafter{\expandafter
+ \takethree\topmark}}
+\def\topsecno{\expandafter\takeone\topmark}
+\def\takeone#1#2#3{#1}
+\def\taketwo#1#2#3{#2}
+\def\takethree#1#2#3{#3}
+\def\nullsec{\eightrm\kern-2em} % the \kern-2em cancels \qquad in headers
+
+\let\page=\pagebody \raggedbottom
+% \def\page{\box255 }\normalbottom % faster, but loses plain TeX footnotes
+\def\normaloutput#1#2#3{\ifodd\pageno\hoffset=\pageshift\fi
+ \shipout\vbox{
+ \vbox to\fullpageheight{
+ \iftitle\global\titlefalse
+ \else\hbox to\pagewidth{\vbox to10pt{}\ifodd\pageno #3\else#2\fi}\fi
+ \vfill#1}} % parameter #1 is the page itself
+ \global\advance\pageno by1}
+
+\gtitle={\.{CWEB} output} % this running head is reset by starred sections
+\mark{\noexpand\nullsec0{\the\gtitle}}
+\def\title{\expandafter\uppercase\expandafter{\jobname}}
+\def\topofcontents{\centerline{\titlefont\title}\vskip.7in
+ \vfill} % this material will start the table of contents page
+\def\botofcontents{\vfill
+ \centerline{\covernote}} % this material will end the table of contents page
+\def\covernote{}
+\def\contentspagenumber{0} % default page number for table of contents
+\newdimen\pagewidth \pagewidth=6.5in % the width of each page
+\newdimen\pageheight \pageheight=8.7in % the height of each page
+\newdimen\fullpageheight \fullpageheight=9in % page height including headlines
+\newdimen\pageshift \pageshift=0in % shift righthand pages wrt lefthand ones
+\def\magnify#1{\mag=#1\pagewidth=6.5truein\pageheight=8.7truein
+ \fullpageheight=9truein\setpage}
+\def\setpage{\hsize\pagewidth\vsize\pageheight} % use after changing page size
+\def\contentsfile{\jobname.toc} % file that gets table of contents info
+\def\readcontents{\input \contentsfile}
+\def\readindex{\input \jobname.idx}
+\def\readsections{\input \jobname.scn}
+
+\newwrite\cont
+\output{\setbox0=\page % the first page is garbage
+ \openout\cont=\contentsfile
+ \write\cont{\catcode `\noexpand\@=11\relax} % \makeatletter
+ \global\output{\normaloutput\page\lheader\rheader}}
+\setpage
+\vbox to \vsize{} % the first \topmark won't be null
+
+\def\ch{\note{The following sections were changed by the change file:}
+ \let\*=\relax}
+\newbox\sbox % saved box preceding the index
+\newbox\lbox % lefthand column in the index
+\def\inx{\par\vskip6pt plus 1fil % we are beginning the index
+ \def\page{\box255 } \normalbottom
+ \write\cont{} % ensure that the contents file isn't empty
+ \write\cont{\catcode `\noexpand\@=12\relax} % \makeatother
+ \closeout\cont % the contents information has been fully gathered
+ \output{\ifpagesaved\normaloutput{\box\sbox}\lheader\rheader\fi
+ \global\setbox\sbox=\page \global\pagesavedtrue}
+ \pagesavedfalse \eject % eject the page-so-far and predecessors
+ \setbox\sbox\vbox{\unvbox\sbox} % take it out of its box
+ \vsize=\pageheight \advance\vsize by -\ht\sbox % the remaining height
+ \hsize=.5\pagewidth \advance\hsize by -10pt
+ % column width for the index (20pt between cols)
+ \parfillskip 0pt plus .6\hsize % try to avoid almost empty lines
+ \def\lr{L} % this tells whether the left or right column is next
+ \output{\if L\lr\global\setbox\lbox=\page \gdef\lr{R}
+ \else\normaloutput{\vbox to\pageheight{\box\sbox\vss
+ \hbox to\pagewidth{\box\lbox\hfil\page}}}\lheader\rheader
+ \global\vsize\pageheight\gdef\lr{L}\global\pagesavedfalse\fi}
+ \message{Index:}
+ \parskip 0pt plus .5pt
+ \outer\def\I##1, {\par\hangindent2em\noindent##1:\kern1em} % index entry
+ \def\[##1]{$\underline{##1}$} % underlined index item
+ \rm \rightskip0pt plus 2.5em \tolerance 10000 \let\*=\lapstar
+ \hyphenpenalty 10000 \parindent0pt
+ \readindex}
+\def\fin{\par\vfill\eject % this is done when we are ending the index
+ \ifpagesaved\null\vfill\eject\fi % output a null index column
+ \if L\lr\else\null\vfill\eject\fi % finish the current page
+ \parfillskip 0pt plus 1fil
+ \def\grouptitle{NAMES OF THE SECTIONS}
+ \let\topsecno=\nullsec
+ \message{Section names:}
+ \output={\normaloutput\page\lheader\rheader}
+ \setpage
+ \def\note##1##2.{\quad{\eightrm##1~##2.}}
+ \def\Q{\note{Cited in section}} % crossref for mention of a section
+ \def\Qs{\note{Cited in sections}} % crossref for mentions of a section
+ \def\U{\note{Used in section}} % crossref for use of a section
+ \def\Us{\note{Used in sections}} % crossref for uses of a section
+ \def\I{\par\hangindent 2em}\let\*=*
+ \readsections}
+\def\con{\par\vfill\eject % finish the section names
+% \ifodd\pageno\else\titletrue\null\vfill\eject\fi % for duplex printers
+ \rightskip 0pt \hyphenpenalty 50 \tolerance 200
+ \setpage \output={\normaloutput\page\lheader\rheader}
+ \titletrue % prepare to output the table of contents
+ \pageno=\contentspagenumber
+ \def\grouptitle{TABLE OF CONTENTS}
+ \message{Table of contents:}
+ \topofcontents
+ \line{\hfil Section\hbox to3em{\hss Page}}
+ \let\ZZ=\contentsline
+ \readcontents\relax % read the contents info
+ \botofcontents \end} % print the contents page(s) and terminate
+\def\contentsline#1#2#3#4{\ifnum#2=0 \smallbreak\fi
+ \line{\consetup{#2}#1
+ \rm\leaders\hbox to .5em{.\hfil}\hfil\ #3\hbox to3em{\hss#4}}}
+\def\consetup#1{\ifcase#1 \bf % depth -1 (@**)
+ \or % depth 0 (@*)
+ \or \hskip2em % depth 1 (@*1)
+ \or \hskip4em % depth 2 (@*2)
+ \or \hskip6em % depth 3 (@*3)
+ \or \hskip8em % depth 4 (@*4)
+ \or \hskip10em % depth 5 (@*5)
+ \else \hskip12em \fi} % depth 6 or more
+\def\noinx{\let\inx=\end} % no indexes or table of contents
+\def\nosecs{\let\FIN=\fin \def\fin{\let\parfillskip=\end \FIN}}
+ % no index of section names or table of contents
+\def\nocon{\let\con=\end} % no table of contents
+\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}
+\newcount\twodigits
+\def\hours{\twodigits=\time \divide\twodigits by 60 \printtwodigits
+ \multiply\twodigits by-60 \advance\twodigits by\time :\printtwodigits}
+\def\gobbleone1{}
+\def\printtwodigits{\advance\twodigits100
+ \expandafter\gobbleone\number\twodigits
+ \advance\twodigits-100 }
+\def\TeX{{\ifmmode\it\fi
+ \leavevmode\hbox{T\kern-.1667em\lower.424ex\hbox{E}\hskip-.125em X}}}
+\def\,{\relax\ifmmode\mskip\thinmuskip\else\thinspace\fi}
+\def\datethis{\def\startsection{\leftline{\sc\today\ at \hours}\bigskip
+ \let\startsection=\stsec\stsec}}
+ % say `\datethis' in limbo, to get your listing timestamped before section 1
+\def\datecontentspage{%
+ \def\topofcontents{\leftline{\sc\today\ at \hours}\bigskip
+ \centerline{\titlefont\title}\vfill}} % timestamps the contents page
+
+\endinput
+
+
+% end of cwebmac.tex
diff --git a/web/c_cpp/c2cweb/cweb/cwebmaca.tex b/web/c_cpp/c2cweb/cweb/cwebmaca.tex
new file mode 100644
index 0000000000..307063f863
--- /dev/null
+++ b/web/c_cpp/c2cweb/cweb/cwebmaca.tex
@@ -0,0 +1,381 @@
+% This file is part of c2cweb package Version 1.5
+
+% standard macros for CWEB listings (in addition to plain.tex)
+% Version 3.0 --- June 1993
+
+% modified by Werner Lemberg (a7971428@unet.univie.ac.at) 10-Nov-1996
+% to use with CWEAVE +a
+
+\ifx\documentstyle\undefined\else\endinput\fi % LaTeX will use other macros
+\xdef\fmtversion{\fmtversion+CWEB3.2}
+
+\let\:=\. % preserve a way to get the dot accent
+ % (all other accents will still work as usual)
+
+%\parskip 0pt % no stretch between paragraphs
+%\parindent 1em % for paragraphs and for the first line of C text
+
+\font\ninerm=cmr9
+\let\mc=\ninerm % medium caps
+\def\CEE/{{\mc C\spacefactor1000}}
+\def\UNIX/{{\mc U\kern-.05emNIX\spacefactor1000}}
+\def\TEX/{\TeX}
+\def\CPLUSPLUS/{{\mc C\PP\spacefactor1000}}
+\def\Cee{\CEE/} % for backward compatibility
+\def\9#1{}
+\font\eightrm=cmr8
+\let\sc=\eightrm % small caps (NOT a caps-and-small-caps font)
+\let\mainfont=\tenrm
+\let\cmntfont\tenrm
+%\font\tenss=cmss10 \let\cmntfont\tenss % alternative comment font
+%\font\titlefont=cmr7 scaled\magstep4 % title on the contents page
+\font\titlefont=cmssbx10 scaled\magstep2 % title on the contents page
+\font\ttitlefont=cmtt10 scaled\magstep2 % typewriter type in title
+\font\tentex=cmtex10 % TeX extended character set (used in strings)
+\fontdimen7\tentex=0pt % no double space after sentences
+
+\font\sectionfont=cmssbx10 scaled\magstephalf
+
+\def\${\ifmmode \hbox{\sl \char`\$}
+ \else \hbox{\ifdim \fontdimen1\font > 0pt \sl \fi \char`\$}\fi}
+
+\def\\#1{\leavevmode\hbox{\it#1\/\kern.05em}} % italic type for identifiers
+\def\|#1{\leavevmode\hbox{$#1$}} % one-letter identifiers look better this way
+\def\&#1{\leavevmode\hbox{\bf
+ \def\_{\kern.04em\vbox{\hrule width.3em height .6pt}\kern.08em}%
+ #1\/\kern.05em}} % boldface type for reserved words
+\def\.#1{\leavevmode\hbox{\tentex % typewriter type for strings
+ \let\\=\BS % backslash in a string
+ \let\{=\LB % left brace in a string
+ \let\}=\RB % right brace in a string
+ \let\~=\TL % tilde in a string
+ \let\ =\SP % space in a string
+ \let\_=\UL % underline in a string
+ \let\&=\AM % ampersand in a string
+ \let\^=\CF % circumflex in a string
+ #1\kern.05em}}
+\def\){\discretionary{\hbox{\tentex\BS}}{}{}}
+\def\AT{@} % at sign for control text (not needed in versions >= 2.9)
+\def\ATL{\par\noindent\bgroup\catcode`\_=12 \postATL} % print @l in limbo
+\def\postATL#1 #2 {\bf letter \\{\uppercase{\char"#1}}
+ tangles as \tentex "#2"\egroup\par}
+\def\noATL#1 #2 {}
+\def\noatl{\let\ATL=\noATL} % suppress output from @l
+\def\ATH{\X\kern-.5em:Preprocessor definitions\X}
+%\let\PB=\relax % hook for program brackets |...| in TeX part or section name
+\def\PB#1{{\def\LBR{\LB}\def\RBR{\RB}#1}}
+
+\chardef\AM=`\& % ampersand character in a string
+\chardef\BS=`\\ % backslash in a string
+\chardef\LB=`\{ % left brace in a string
+\chardef\RB=`\} % right brace in a string
+\def\SP{{\tt\char`\ }} % (visible) space in a string
+\chardef\TL=`\~ % tilde in a string
+\chardef\UL=`\_ % underline character in a string
+\chardef\CF=`\^ % circumflex character in a string
+
+\newbox\PPbox % symbol for ++
+\setbox\PPbox=\hbox{\kern.5pt\raise1pt\hbox{\sevenrm+\kern-1pt+}\kern.5pt}
+\def\PP{\copy\PPbox}
+\newbox\MMbox \setbox\MMbox=\hbox{\kern.5pt\raise1pt\hbox{\sevensy\char0
+ \kern-1pt\char0}\kern.5pt}
+\def\MM{\copy\MMbox}
+\newbox\MGbox % symbol for ->
+\setbox\MGbox=\hbox{\kern-2pt\lower3pt\hbox{\teni\char'176}\kern1pt}
+\def\MG{\copy\MGbox}
+\newbox\NNbox % symbol for ##
+\setbox\NNbox=\hbox{\kern.5pt\raise2pt\hbox{\#}\kern-4pt
+ \lower2pt\hbox{\#}\kern.5pt}
+\def\NN{\copy\NNbox}
+\def\MRL#1{\mathrel{\let\K==#1}}
+%\def\MRL#1{\KK#1}\def\KK#1#2{\buildrel\;#1\over{#2}}
+\let\GG=\gg
+\let\LL=\ll
+\let\NULL=\Lambda
+\mathchardef\AND="2026 % bitwise and; also \& (unary operator)
+\let\OR=\mid % bitwise or
+\let\XOR=\oplus % bitwise exclusive or
+\def\CM{{\sim}} % bitwise complement
+\newbox\MODbox \setbox\MODbox=\hbox{\eightrm\%}
+\def\MOD{\mathbin{\copy\MODbox}}
+\def\DC{\kern.1em{::}\kern.1em} % symbol for ::
+\def\PA{\mathbin{.*}} % symbol for .*
+\def\MGA{\mathbin{\MG*}} % symbol for ->*
+\def\this{\&{this}}
+
+\newbox\bak \setbox\bak=\hbox to -1em{} % backspace one em
+\newbox\bakk\setbox\bakk=\hbox to -2em{} % backspace two ems
+
+\newbox\LBRbox \setbox\LBRbox=\hbox to 1em{\hss$\{$}
+\newbox\RBRbox \setbox\RBRbox=\hbox to 1em{\hss$\}$}
+\def\LBR{\copy\LBRbox}
+\def\RBR{\copy\RBRbox}
+
+\newcount\ind % current indentation in ems
+\def\1{\global\advance\ind by1\hangindent\ind em} % indent one more notch
+\def\2{\global\advance\ind by-1} % indent one less notch
+\def\3#1{\hfil\penalty#10\hfilneg} % optional break within a statement
+\def\4{\copy\bak} % backspace one notch
+\def\5{\hfil\penalty-1\hfilneg\kern2.5em\copy\bakk\ignorespaces}% optional break
+\def\6{\ifmmode\else\par % forced break
+ \hangindent\ind em\noindent\kern\ind em\copy\bakk\ignorespaces\fi}
+%\def\7{\Y\6} % forced break and a little extra space
+\def\7{\Y\penalty-150\6} % forced break and a little extra space
+\def\8{\hskip-\ind em\hskip 2em} % no indentation
+
+\newcount\gdepth % depth of current major group, plus one
+\newcount\secpagedepth
+\secpagedepth=3 % page breaks will occur for depths -1, 0, and 1
+\newtoks\gtitle % title of current major group
+\newskip\intersecskip \intersecskip=12pt minus 3pt % space between sections
+%\let\yskip=\smallskip
+\def\yskip{\vskip 5pt plus 1pt minus 1pt}
+\def\?{\mathrel?}
+\def\note#1#2.{\Y\noindent{\hangindent2em\baselineskip10pt\eightrm#1~#2.\par}}
+\def\lapstar{\rlap{*}}
+%\def\stsec{\rightskip=0pt % get out of C mode (cf. \B)
+% \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50
+% \noindent{\let\*=\lapstar\bf\secstar.\quad}}
+\def\stsec{\rightskip=0pt % get out of C mode (cf. \B)
+ \parskip=4pt \parindent=0pt
+ \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50
+ \noindent{\let\*=\lapstar\sectionfont\secstar.\quad}}
+\let\startsection=\stsec
+\def\defin#1{\global\advance\ind by 2 \1\&{#1 } } % begin `define' or `format'
+\def\A{\note{See also section}} % xref for doubly defined section name
+\def\As{\note{See also sections}} % xref for multiply defined section name
+%\def\B{\rightskip=0pt plus 100pt minus 10pt % go into C mode
+% \sfcode`;=3000
+% \pretolerance 10000
+% \hyphenpenalty 9999 % so strings can be broken (discretionary \ is inserted)
+% \exhyphenpenalty 10000
+% \global\ind=2 \1\ \unskip}
+\def\B{\rightskip=0pt plus 100pt minus 10pt % go into C mode
+ \parskip=0pt \parindent=1em
+ \sfcode`;=3000
+ \pretolerance 10000
+ \hyphenpenalty 9999 % so strings can be broken (discretionary \ is inserted)
+ \exhyphenpenalty 10000
+ \global\ind=2 \1\ \unskip}
+%\def\C#1{\5\5\quad$/\ast\,${\cmntfont #1}$\,\ast/$}
+\def\C#1{\5\5\hfill$/\ast\,${\cmntfont #1}$\,\ast/$}
+\let\SHC\C % "// short comments" treated like "/* ordinary comments */"
+%\def\C#1{\5\5\quad$\triangleright\,${\cmntfont#1}$\,\triangleleft$}
+%\def\SHC#1{\5\5\quad$\diamond\,${\cmntfont#1}}
+\def\D{\defin{\#define}} % macro definition
+\let\E=\equiv % equivalence sign
+\def\ET{ and~} % conjunction between two section numbers
+\def\ETs{, and~} % conjunction between the last two of several section numbers
+\def\F{\defin{format}} % format definition
+\let\G=\ge % greater than or equal sign
+% \H is long Hungarian umlaut accent
+\let\I=\ne % unequal sign
+\def\J{\.{@\&}} % TANGLE's join operation
+\let\K== % assignment operator
+%\let\K=\leftarrow % "honest" alternative to standard assignment operator
+% \L is Polish letter suppressed-L
+%\outer\def\M#1{\MN{#1}\ifon\vfil\penalty-100\vfilneg % beginning of section
+% \vskip\intersecskip\startsection\ignorespaces}
+\outer\def\M#1{\MN{#1}\ifon\vfil\penalty-100\vfilneg % beginning of section
+ \vskip\intersecskip\startsection\smallskip\noindent\ignorespaces}
+%\outer\def\N#1#2#3.{\gdepth=#1\gtitle={#3}\MN{#2}% beginning of starred section
+% \ifon\ifnum#1<\secpagedepth \vfil\eject % force page break if depth is small
+% \else\vfil\penalty-100\vfilneg\vskip\intersecskip\fi\fi
+% \message{*\secno} % progress report
+% \edef\next{\write\cont{\ZZ{#3}{#1}{\secno}% write to contents file
+% {\noexpand\the\pageno}}}\next % \ZZ{title}{depth}{sec}{page}
+% \ifon\startsection{\bf#3.\quad}\ignorespaces}
+\outer\def\N#1#2#3.{\gdepth=#1\gtitle={#3}\MN{#2}% beginning of starred section
+ \ifon\ifnum#1<\secpagedepth \vfil\eject % force page break if depth is small
+ \else\vfil\penalty-100\vfilneg\vskip\intersecskip\fi\fi
+ \message{*\secno} % progress report
+ \edef\next{\write\cont{\ZZ{#3}{#1}{\secno}% write to contents file
+ {\noexpand\the\pageno}}}\next % \ZZ{title}{depth}{sec}{page}
+ \ifon\startsection{\sectionfont#3.}\bigskip\noindent\ignorespaces}
+\def\MN#1{\par % common code for \M, \N
+ {\xdef\secstar{#1}\let\*=\empty\xdef\secno{#1}}% remove \* from section name
+ \ifx\secno\secstar \onmaybe \else\ontrue \fi
+ \mark{{{\tensy x}\secno}{\the\gdepth}{\the\gtitle}}}
+% each \mark is {section reference or null}{depth plus 1}{group title}
+% \O is Scandinavian letter O-with-slash
+% \P is paragraph sign
+\def\Q{\note{This code is cited in section}} % xref for mention of a section
+\def\Qs{\note{This code is cited in sections}} % xref for mentions of a section
+%\let\R=\lnot % logical not
+\def\R{\mathord ! \,} % logical not
+% \S is section sign
+\def\T#1{\leavevmode % octal, hex or decimal constant
+ \hbox{$\def\?{\kern.2em}%
+ \def\$##1{\egroup_{\,\rm##1}\bgroup}% suffix to constant
+ \def\_{\cdot 10^{\aftergroup}}% power of ten (via dirty trick)
+ \let\~=\oct \let\^=\hex {#1}$}}
+\def\U{\note{This code is used in section}} % xref for use of a section
+\def\Us{\note{This code is used in sections}} % xref for uses of a section
+\let\V=\lor % logical or
+\let\W=\land % logical and
+\def\X#1:#2\X{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi % section name
+ \XX$\langle\,${#2\eightrm\kern.5em#1}$\,\rangle$\XX}
+\def\Y{\par\yskip}
+\let\Z=\le
+\let\ZZ=\let % now you can \write the control sequence \ZZ
+\let\*=*
+
+%\def\oct{\hbox{\rm\char'23\kern-.2em\it\aftergroup\?\aftergroup}} % WEB style
+%\def\hex{\hbox{\rm\char"7D\tt\aftergroup}} % WEB style
+\def\oct{\hbox{$^\circ$\kern-.1em\it\aftergroup\?\aftergroup}}% CWEB style
+\def\hex{\hbox{$^{\scriptscriptstyle\#}$\tt\aftergroup}} % CWEB style
+\def\vb#1{\leavevmode\hbox{\kern2pt\vrule\vtop{\vbox{\hrule
+ \hbox{\strut\kern2pt\.{#1}\kern2pt}}
+ \hrule}\vrule\kern2pt}} % verbatim string
+
+\def\onmaybe{\let\ifon=\maybe} \let\maybe=\iftrue
+\newif\ifon \newif\iftitle \newif\ifpagesaved
+
+\def\lheader{\mainfont\the\pageno\eightrm\qquad\grouptitle\hfill\title\qquad
+ \mainfont\topsecno} % top line on left-hand pages
+\def\rheader{\mainfont\topsecno\eightrm\qquad\title\hfill\grouptitle
+ \qquad\mainfont\the\pageno} % top line on right-hand pages
+\def\grouptitle{\let\i=I\let\j=J\uppercase\expandafter{\expandafter
+ \takethree\topmark}}
+\def\topsecno{\expandafter\takeone\topmark}
+\def\takeone#1#2#3{#1}
+\def\taketwo#1#2#3{#2}
+\def\takethree#1#2#3{#3}
+\def\nullsec{\eightrm\kern-2em} % the \kern-2em cancels \qquad in headers
+
+\let\page=\pagebody \raggedbottom
+% \def\page{\box255 }\normalbottom % faster, but loses plain TeX footnotes
+\def\normaloutput#1#2#3{\ifodd\pageno\hoffset=\pageshift\fi
+ \shipout\vbox{
+ \vbox to\fullpageheight{
+ \iftitle\global\titlefalse
+ \else\hbox to\pagewidth{\vbox to10pt{}\ifodd\pageno #3\else#2\fi}\fi
+ \vfill#1}} % parameter #1 is the page itself
+ \global\advance\pageno by1}
+
+\gtitle={\.{CWEB} output} % this running head is reset by starred sections
+\mark{\noexpand\nullsec0{\the\gtitle}}
+\def\title{\expandafter\uppercase\expandafter{\jobname}}
+\def\topofcontents{\centerline{\titlefont\title}\vskip.7in
+ \vfill} % this material will start the table of contents page
+\def\botofcontents{\vfill
+ \centerline{\covernote}} % this material will end the table of contents page
+\def\covernote{}
+\def\contentspagenumber{0} % default page number for table of contents
+\newdimen\pagewidth \pagewidth=6.5in % the width of each page
+\newdimen\pageheight \pageheight=8.7in % the height of each page
+\newdimen\fullpageheight \fullpageheight=9in % page height including headlines
+\newdimen\pageshift \pageshift=0in % shift righthand pages wrt lefthand ones
+\def\magnify#1{\mag=#1\pagewidth=6.5truein\pageheight=8.7truein
+ \fullpageheight=9truein\setpage}
+\def\setpage{\hsize\pagewidth\vsize\pageheight} % use after changing page size
+\def\contentsfile{\jobname.toc} % file that gets table of contents info
+\def\readcontents{\input \contentsfile}
+\def\readindex{\input \jobname.idx}
+\def\readsections{\input \jobname.scn}
+
+\newwrite\cont
+\output{\setbox0=\page % the first page is garbage
+ \openout\cont=\contentsfile
+ \write\cont{\catcode `\noexpand\@=11\relax} % \makeatletter
+ \global\output{\normaloutput\page\lheader\rheader}}
+\setpage
+\vbox to \vsize{} % the first \topmark won't be null
+
+\def\ch{\note{The following sections were changed by the change file:}
+ \let\*=\relax}
+\newbox\sbox % saved box preceding the index
+\newbox\lbox % lefthand column in the index
+\def\inx{\par\vskip6pt plus 1fil % we are beginning the index
+ \def\page{\box255 } \normalbottom
+ \write\cont{} % ensure that the contents file isn't empty
+ \write\cont{\catcode `\noexpand\@=12\relax} % \makeatother
+ \closeout\cont % the contents information has been fully gathered
+ \output{\ifpagesaved\normaloutput{\box\sbox}\lheader\rheader\fi
+ \global\setbox\sbox=\page \global\pagesavedtrue}
+ \pagesavedfalse \eject % eject the page-so-far and predecessors
+ \setbox\sbox\vbox{\unvbox\sbox} % take it out of its box
+ \vsize=\pageheight \advance\vsize by -\ht\sbox % the remaining height
+ \hsize=.5\pagewidth \advance\hsize by -10pt
+ % column width for the index (20pt between cols)
+ \parfillskip 0pt plus .6\hsize % try to avoid almost empty lines
+ \def\lr{L} % this tells whether the left or right column is next
+ \output{\if L\lr\global\setbox\lbox=\page \gdef\lr{R}
+ \else\normaloutput{\vbox to\pageheight{\box\sbox\vss
+ \hbox to\pagewidth{\box\lbox\hfil\page}}}\lheader\rheader
+ \global\vsize\pageheight\gdef\lr{L}\global\pagesavedfalse\fi}
+ \message{Index:}
+ \parskip 0pt plus .5pt
+ \outer\def\I##1, {\par\hangindent2em\noindent##1:\kern1em} % index entry
+ \def\[##1]{$\underline{##1}$} % underlined index item
+ \rm \rightskip0pt plus 2.5em \tolerance 10000 \let\*=\lapstar
+ \hyphenpenalty 10000 \parindent0pt
+ \readindex}
+\def\fin{\par\vfill\eject % this is done when we are ending the index
+ \ifpagesaved\null\vfill\eject\fi % output a null index column
+ \if L\lr\else\null\vfill\eject\fi % finish the current page
+ \parfillskip 0pt plus 1fil
+ \def\grouptitle{NAMES OF THE SECTIONS}
+ \let\topsecno=\nullsec
+ \message{Section names:}
+ \output={\normaloutput\page\lheader\rheader}
+ \setpage
+ \def\note##1##2.{\quad{\eightrm##1~##2.}}
+ \def\Q{\note{Cited in section}} % crossref for mention of a section
+ \def\Qs{\note{Cited in sections}} % crossref for mentions of a section
+ \def\U{\note{Used in section}} % crossref for use of a section
+ \def\Us{\note{Used in sections}} % crossref for uses of a section
+ \def\I{\par\hangindent 2em}\let\*=*
+ \readsections}
+\def\con{\par\vfill\eject % finish the section names
+% \ifodd\pageno\else\titletrue\null\vfill\eject\fi % for duplex printers
+ \rightskip 0pt \hyphenpenalty 50 \tolerance 200
+ \setpage \output={\normaloutput\page\lheader\rheader}
+ \titletrue % prepare to output the table of contents
+ \pageno=\contentspagenumber
+ \def\grouptitle{TABLE OF CONTENTS}
+ \message{Table of contents:}
+ \topofcontents
+ \line{\hfil Section\hbox to3em{\hss Page}}
+ \let\ZZ=\contentsline
+ \readcontents\relax % read the contents info
+ \botofcontents \end} % print the contents page(s) and terminate
+\def\contentsline#1#2#3#4{\ifnum#2=0 \smallbreak\fi
+ \line{\consetup{#2}#1
+ \rm\leaders\hbox to .5em{.\hfil}\hfil\ #3\hbox to3em{\hss#4}}}
+\def\consetup#1{\ifcase#1 \bf % depth -1 (@**)
+ \or % depth 0 (@*)
+ \or \hskip2em % depth 1 (@*1)
+ \or \hskip4em % depth 2 (@*2)
+ \or \hskip6em % depth 3 (@*3)
+ \or \hskip8em % depth 4 (@*4)
+ \or \hskip10em % depth 5 (@*5)
+ \else \hskip12em \fi} % depth 6 or more
+\def\noinx{\let\inx=\end} % no indexes or table of contents
+\def\nosecs{\let\FIN=\fin \def\fin{\let\parfillskip=\end \FIN}}
+ % no index of section names or table of contents
+\def\nocon{\let\con=\end} % no table of contents
+\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}
+\newcount\twodigits
+\def\hours{\twodigits=\time \divide\twodigits by 60 \printtwodigits
+ \multiply\twodigits by-60 \advance\twodigits by\time :\printtwodigits}
+\def\gobbleone1{}
+\def\printtwodigits{\advance\twodigits100
+ \expandafter\gobbleone\number\twodigits
+ \advance\twodigits-100 }
+\def\TeX{{\ifmmode\it\fi
+ \leavevmode\hbox{T\kern-.1667em\lower.424ex\hbox{E}\hskip-.125em X}}}
+\def\,{\relax\ifmmode\mskip\thinmuskip\else\thinspace\fi}
+\def\datethis{\def\startsection{\leftline{\sc\today\ at \hours}\bigskip
+ \let\startsection=\stsec\stsec}}
+ % say `\datethis' in limbo, to get your listing timestamped before section 1
+\def\datecontentspage{%
+ \def\topofcontents{\leftline{\sc\today\ at \hours}\bigskip
+ \centerline{\titlefont\title}\vfill}} % timestamps the contents page
+
+\endinput
+
+% end of cwebmaca.tex
diff --git a/web/c_cpp/c2cweb/cweb/prod-alt.w b/web/c_cpp/c2cweb/cweb/prod-alt.w
new file mode 100644
index 0000000000..f7849d830a
--- /dev/null
+++ b/web/c_cpp/c2cweb/cweb/prod-alt.w
@@ -0,0 +1,303 @@
+% This file is part of CWEB.
+% This program by Silvio Levy and Donald E. Knuth
+% is based on a program by Knuth.
+% It is distributed WITHOUT ANY WARRANTY, express or implied.
+% Version 3.0 --- June 1993
+
+% this file is part of the c2cweb package Version 1.5
+% modified by Werner Lemberg (a7971428@@unet.univie.ac.at) 10-Nov-1996
+
+@
+\def\v{\char'174}
+\mathchardef\RA="3221 % right arrow
+\mathchardef\BA="3224 % double arrow
+Here is a table of all the productions if you use the \.{a} switch.
+Each production that combines two or more consecutive scraps implicitly
+inserts a {\tt \$} where necessary, that is, between scraps whose abutting
+boundaries have different |mathness|. In this way we never get double
+{\tt\$\$}.
+
+A translation is provided when the resulting scrap is not merely a
+juxtaposition of the scraps it comes from. An asterisk$^*$ next to a scrap
+means that its first identifier gets an underlined entry in the index,
+via the function |make_underlined|. Two asterisks$^{**}$ means that both
+|make_underlined| and |make_reserved| are called; that is, the
+identifier's ilk becomes |raw_int|. A dagger \dag\ before the
+production number refers to the notes at the end of this section,
+which deal with various exceptional cases.
+
+We use \\{in}, \\{out}, \\{back} and
+\\{bsp} as shorthands for |indent|, |outdent|, |backup| and
+|break_space|, respectively.
+
+\begingroup \lineskip=4pt
+\def\alt #1 #2
+{$\displaystyle\Bigl\{\!\matrix{\strut\hbox{#1}\cr
+ \strut\hbox{#2}\cr}\!\Bigr\}$ }
+\def\altt #1 #2 #3
+{$\displaystyle\Biggl\{\!\matrix{\strut\hbox{#1}\cr\hbox{#2}\cr
+ \strut\hbox{#3}\cr}\!\Biggr\}$ }
+\def\altq #1 #2 #3 #4
+{$\displaystyle\left\{\!\matrix{\strut\hbox{#1}\cr\hbox{#2}\cr
+ \hbox{#3}\cr\strut\hbox{#4}\cr}\!\right\}$ }
+\def\malt #1 #2
+{$\displaystyle\matrix{\strut\hbox{#1}\hfill\cr\strut\hbox{#2}\hfill\cr}$}
+\def\maltt #1 #2 #3
+{$\displaystyle\matrix{\strut\hbox{#1}\hfill\cr\hbox{#2}\hfill\cr
+ \strut\hbox{#3}\hfill\cr}$}
+\yskip\newcount\prodno\prodno=0
+\newdimen\midcol \midcol=2.5in
+\def\theprodno{\number\prodno \global\advance\prodno by1\enspace}
+\def\+#1&#2&#3&#4\cr{\def\next{#1}%
+ \line{\hbox to 2em{\hss
+ \ifx\next\empty\theprodno\else\next\fi}\strut
+ \ignorespaces#2\hfil\hbox to\midcol{$\RA$
+ \ignorespaces#3\hfil}\quad \hbox to1.45in{\ignorespaces#4\hfil}}}
+\+\relax & LHS & RHS \hfill Translation & Example\cr
+\yskip
+\+& \altt\\{any} {\\{any} \\{any}} {\\{any} \\{any} \\{any}}
+|insert| & \altt\\{any} {\\{any} \\{any}} {\\{any} \\{any} \\{any}}
+& stmt; \ /$\ast\,$comment$\,*$/\cr
+\+& |exp| \altt|lbrace| |int_like| |decl|
+ & |fn_decl| \altt|lbrace| |int_like| |decl|
+ \hfill $F=E^*\,|in|\,|in|$ & \malt {\\{main}()$\{$}
+ {\\{main}$(\\{ac},\\{av})$ \&{int} \\{ac};} \cr
+\+& |exp| |unop| & |exp| & |x++|\cr
+\+& |exp| \alt |binop| |unorbinop| |exp| & |exp| & \malt {|x/y|} {|x+y|} \cr
+\+& |exp| |comma| |exp| & |exp| \hfill $EC\,|opt|9\,E$& |f(x,y)|\cr
+\+& |exp| \alt |exp| |cast| & |exp| & |time()|\cr
+\+& |exp| |semi| & |stmt| & |x=0;|\cr
+\+& |exp| |colon| & |label| \hfill $E^*C$ & |found:|\cr
+\+& |exp| |base| |int_like| |comma| & |base| \hfill $B\.\ IC$\,|opt|9
+ & \&D : \&C,\cr
+\+& |exp| |base| |int_like| |lbrace| & |exp| |lbrace| \hfill
+ $E=E\.\ B\.\ I$ & \&D : \&C $\{$\cr
+\+& |exp| |rbrace| & |stmt| |rbrace| & end of \&{enum} list\cr
+\+& |lpar| \alt |exp| |unorbinop| |rpar| & |exp| & \malt{|(x)|} {|(*)|} \cr
+\+& |lpar| |rpar| & |exp| \hfill $L\.{\\,}R$ & functions, declarations\cr
+\+& |lpar| \alt |decl_head| |int_like| |rpar| & |cast| & |(char*)|\cr
+\+& |lpar| \altt |decl_head| |int_like| |exp| |comma| & |lpar| \hfill
+ L\,\altt $D$ $I$ $E$ C\,|opt|9 & |(int,|\cr
+\+& |lpar| \alt |stmt| |decl| & |lpar| \hfill \alt {$LS\.\ $} {$LD\.\ $} &
+ \alt {|(k=5;|} {|(int k=5;|} \cr
+\+& |question| |exp| |colon| & |binop| & |?x:|\cr
+\+& |unop| \alt |exp| |int_like| & \alt |exp| |int_like| &
+ \malt |!x| |~|\&C \cr
+\+& |unorbinop| \alt|exp| |int_like| & \alt|exp| |int_like| \hfill
+ $\.\{U\.\}E$ & |*x|\cr
+\+& |unorbinop| |binop| & |binop| \hfill $|math_rel|\,U\.\{B\.\}\.\}$ & |*=|\cr
+\+& |binop| |binop| & |binop| \hfill
+ $|math_rel|\,\.\{B_1\.\}\.\{B_2\.\}\.\}$ & |>>=|\cr
+\+& |cast| |exp| & |exp| \hfill $C\.\ E$ & |(double)x|\cr
+\+& |cast| |semi| & |exp| |semi| & |(int);|\cr
+\+& |sizeof_like| |cast| & |exp| & |sizeof (double)|\cr
+\+& |sizeof_like| |exp| & |exp| \hfill $S\.\ E$ & |sizeof x|\cr
+\+& |int_like| \alt|int_like| |struct_like| &
+ \alt|int_like| |struct_like| \hfill $I\.\ $\alt $I$ $S$
+ \unskip& |extern char|\cr
+\+& |int_like| |exp| \alt|raw_int| |struct_like| &
+ |int_like| \alt|int_like| |struct_like| & |extern "Ada" int|\cr
+\+& |int_like| \altt|exp| |unorbinop| |semi| & |decl_head|
+ \altt|exp| |unorbinop| |semi| \hfill
+ $D=I$\altt{\.\ } {\.\ } {} \unskip & |int x|\cr
+\+& |int_like| |colon| & |decl_head| |colon| \hfill $D=I\.\ $ & |unsigned:|\cr
+\+& |int_like| |prelangle| & |int_like| |langle| & \&C$\langle$\cr
+\+& |int_like| |colcol| \alt |exp| |int_like| & \alt |exp| |int_like| &
+ \malt {\&C\DC$x$} {\&C\DC\&B} \cr
+\+& |int_like| |cast| |lbrace| & |fn_decl| |lbrace| \hfill $IC\,|in|\,|in|$&
+ \&C$\langle\&{void}\ast\rangle\{$\cr
+\+& |int_like| |cast| & |int_like| & \&C$\langle\&{class}\ \&T\rangle$\cr
+\+& |decl_head| |comma| & |decl_head| \hfill $DC\.\ $ & |int x,|\cr
+\+& |decl_head| |unorbinop| & |decl_head| \hfill $D\.\{U\.\}$ & |int *|\cr
+\+\dag\theprodno& |decl_head| |exp| & |decl_head| \hfill $DE^*$ & |int x|\cr
+\+& |decl_head| \alt|binop| |colon| |exp| \altt|comma| |semi| |rpar| &
+ |decl_head| \altt|comma| |semi| |rpar| \hfill
+ $D=D$\alt $B$ $C$ \unskip$E$ & \maltt initialization {fields or}
+ {default argument} \cr
+\+& |decl_head| |cast| & |decl_head| & |int f(int)|\cr
+\+\dag\theprodno& |decl_head| \altt|int_like| |lbrace| |decl| & |fn_decl|
+ \altt|int_like| |lbrace| |decl| \hfill $F=D\,|in|\,|in|$
+ & |long time () {|\cr
+\+& |decl_head| |semi| & |decl| & |int n;|\cr
+\+& |decl| |decl| & |decl| \hfill $D\,|force|\,D$ & |int n;double x;|\cr
+\+& |decl| \alt|stmt| |function| & \alt|stmt| |function|
+ \hfill $D\,|big_force|\,$\alt $S$ $F$ \unskip& \&{extern} $n$;
+ \\{main} ()|{}|\cr
+\+\dag\theprodno& |typedef_like| |decl_head| \alt|exp| |int_like| &
+ |typedef_like| |decl_head| \hfill $D=D$\alt $E^{**}$ $I^{**}$ \unskip &
+ \&{typedef} \&{char} \&{ch};\cr
+\+& |typedef_like| |decl_head| |semi| & |decl| \hfill $T\.\ D$ &
+ \&{typedef} \&{int} $\&x,\&y$;\cr
+\+& |struct_like| |lbrace| & |struct_head| \hfill
+ $S\,\\{in}\,|force|\\{back}\,L$ & |struct {|\cr
+\+& |struct_like| \alt|exp| |int_like| |semi| & |decl_head|
+ \hfill $S\.\ $\alt $E^{**}$ $I^{**}$ & \&{struct} \&{forward};\cr
+\+& |struct_like| \alt|exp| |int_like| |lbrace| & |struct_head| \hfill
+ $S\.\ $\alt $E^{**}$ $I^{**}$ \unskip $\\{in}\,|force|\,\\{back}\,L$ &
+ \&{struct} \&{name\_info} $\{$\cr
+\+& |struct_like| \alt|exp| |int_like| |colon| &
+ |struct_like| \alt|exp| |int_like| |base| & |class| \&C :\cr
+\+\dag\theprodno& |struct_like| \alt|exp| |int_like| & |int_like|
+ \hfill $S\.\ $\alt$E$ $I$ & \&{struct} \&{name\_info} $z$;\cr
+\+& |struct_head| \altt|decl| |stmt| |function| |rbrace| & |int_like|\hfill
+ $SD\,|force|\,\\{back}\,R\,\.\ |out|$ &
+ |struct {| declaration |}|\cr
+\+& |struct_head| |rbrace| & |int_like|\hfill $S\.{\\,}R$ & |class C{}|\cr
+\+& |fn_decl| |decl| & |fn_decl| \hfill $F\,|force|\,D$
+ & $f(z)$ \&{double} $z$; \cr
+\+& |fn_decl| |stmt| & |function| \hfill $F\,|out|\,|out|\,|force|\,S$
+ & \\{main}() {\dots}\cr
+\+& |function| \altt|stmt| |decl| |function| & \altt |stmt| |decl| |function|
+ \hfill $F\,|big_force|\,$\altt $S$ $D$ $F$ & outer block\cr
+\+& |lbrace| |rbrace| & |stmt| \hfill $L\.{\\,}R$ & empty statement\cr
+\advance\midcol15pt
+\+& |lbrace| \altt|stmt| |decl| |function| |rbrace| & |stmt| \hfill
+ $\matrix{\\{in}\,|force|\,\\{back}\,L\,|noop|\,|cancel|\,S\cr
+ |force|\,\\{back}\,R\,\\{out}\,|force|}$ & compound statement\cr
+\+& |lbrace| |exp| [|comma|] |rbrace| & |exp| & initializer\cr
+\+& |if_like| |exp| & |if_clause| \hfill $I\.{\ }E$ & |if (z)|\cr
+\+& |for_like| |exp| & |else_like| \hfill $F\.{\ }E$ & |while (1)|\cr
+\+& |else_like| |lbrace| & |else_head| |lbrace| & \&{else} $\{$\cr
+\+& |else_like| |stmt| & |stmt| \hfill
+ $|force|\,E\,\\{in}\,|force|\,S\,\\{out}\,|force|$ & |else x=0;|\cr
+\+& |else_head| \alt|stmt| |exp| & |stmt| \hfill
+ $|force|\,E\,\\{bsp}\,S\,\\{force}$ & |else{x=0;}|\cr
+\+& |if_clause| |lbrace| & |if_head| |lbrace| & |if (x) {|\cr
+\+& |if_clause| |stmt| |else_like| |if_like| & |if_like| \hfill
+ $|force|\,I\,\\{in}\,|force|\,S\,\\{out}\,|force|\,E\,\.\ I$ &
+ |if (x) y; else if|\cr
+\+& |if_clause| |stmt| |else_like| & |else_like| \hfill
+ $|force|\,I\,\\{in}\,|force|\,S\,\\{out}\,|force|\,E$ &
+ |if (x) y; else|\cr
+\+& |if_clause| |stmt| & |else_like| |stmt| & |if (x)|\cr
+\+& |if_head| \alt|stmt| |exp| |else_like| |if_like| & |if_like| \hfill
+ $|force|\,I\,\\{bsp}\,S\,|force|\,E\,\.\ I$ &
+ |if (x){y;}else if|\cr
+\+& |if_head| \alt|stmt| |exp| |else_like| & |else_like| \hfill
+ $|force|\,I\,\\{bsp}\,S\,|force|\,E$ &
+ |if (x){y;}else|\cr
+\+& |if_head| \alt|stmt| |exp| & |else_head| \alt|stmt| |exp| & |if (x){y;}|\cr
+\+& |do_like| |stmt| |else_like| |semi| & |stmt| \hfill
+ $\matrix{|force|\,D\,\\{in}\,|force|\,S\,|cancel|\,|noop|\cr
+ \,\\{bsp}\,ES\,\\{out}\,|force|}$ & |do f(x); while (g(x));|\cr
+\+& |case_like| |semi| & |stmt| & |return;|\cr
+\+& |case_like| |colon| & |tag| & |default:|\cr
+\+& |case_like| |exp| |semi| & |stmt| \hfill $C\.\ ES$ & |return 0;|\cr
+\+& |case_like| |exp| |colon| & |tag| \hfill $C\.\ EC$ & |case 0:|\cr
+\+& |tag| |tag| & |tag| \hfill $T_1\,|force|\,T_2$ & |case 0: case 1:|\cr
+\advance\midcol20pt
+\+& |tag| \altt|stmt| |decl| |function| \alt|rbrace| |tag|
+ & \altt|stmt| |decl| |function| \alt|rbrace| |tag|
+ \hfill $|force|\,T\,\\{in}\,|force|\,S\,\\{out}$ & |case 0: z=0;|\cr
+\advance\midcol-20pt
+\+\dag\theprodno& |stmt| \altt|stmt| |decl| |function| &
+ \altt|stmt| |decl| |function|
+ \hfill $S\,$\altt$|force|\,S$ $|big_force|\,D$ $|big_force|\,F$ &
+ |x=1;y=2;|\cr
+\+& |semi| & |stmt| \hfill \.\ $S$& empty statement\cr
+\+\dag\theprodno& |lproc| \altt |if_like| |else_like| |define_like| & |lproc| &
+ \maltt {{\bf \#include}} {\bf\#else} {\bf\#define} \cr
+\+& |lproc| |rproc| & |insert| & {\bf\#endif} \cr
+\+\dag\theprodno& |lproc| \altt|exp| |function| |int_like| |rproc| &
+ |insert| \hfill
+ $I$\.\ \altt {$E$} {$F$} {$I$} & {\bf\#define} $a$\enspace 1 \cr
+\+& |section_scrap| |semi| & |stmt|\hfill $MS$ |force|
+ &$\langle\,$section name$\,\rangle$;\cr
+\+& |section_scrap| & |exp| &$\langle\,$section name$\,\rangle$\cr
+\+& |insert| |any| & |any| & \.{\v\#include\v}\cr
+\+& |prelangle| & |binop| \hfill $<$ & $<$ not in template\cr
+\+& |prerangle| & |binop| \hfill $>$ & $>$ not in template\cr
+\+& |langle| |exp| |prerangle| & |cast| & $\langle\,0\,\rangle$\cr
+\+& |langle| |prerangle| & |cast| \hfill $L\.{\\,}P$ & $\langle\,\rangle$\cr
+\+& |langle| \alt|decl_head| |int_like| |prerangle| & |cast| &
+ $\langle\&{class}\,\&C\rangle$\cr
+\+& |langle| \alt|decl_head| |int_like| |comma| & |langle| \hfill
+ L\,\alt $D$ $I$ C\,|opt|9 & $\langle\&{class}\,\&C,$\cr
+\+& |public_like| |colon| & |tag| & \&{private}:\cr
+\+& |public_like| & |int_like| & \&{private}\cr
+\+& |colcol| \alt|exp| |int_like| & \alt|exp| |int_like| & |::x|\cr
+\+\dag\theprodno&
+ |new_like| \alt|exp| |raw_int| & |new_like| \hfill $N\.\ E$ & |new(1)|\cr
+\+& |new_like| \alt|raw_unorbin| |colcol| & |new_like| & |new ::*|\cr
+\+& |new_like| |cast| & |exp| & |new(*)|\cr
+\+\dag\theprodno& |new_like| & |exp| & |new|\cr
+\+\dag\theprodno& |operator_like| \altq|binop| |unop| |unorbinop| |raw_unorbin|
+ & |exp| \hfill $O$\.\{\altq $B$ $U$ $U$ $R$ \unskip \.\} & |operator+|\cr
+\+& |operator_like| \alt|new_like| |sizeof_like| & |exp| \hfill $O\.\ N$
+ & |operator delete|\cr
+\+& |operator_like| & |new_like| & conversion operator\cr
+\+& |catch_like| \alt|cast| |exp| & |fn_decl| \hfill $CE\,\\{in}\,\\{in}$ &
+ |catch (...)|\cr
+\+& |base| |public_like| |exp| |comma| & |base| \hfill $BP\.\ EC$ &
+ : \&{public} $a$,\cr
+\+& |base| |public_like| |exp| & |base| |int_like| \hfill $I=P\.\ E$ &
+ : \&{public} $a$\cr
+\+& |raw_rpar| |const_like| & |raw_rpar| \hfill $R\.\ C$ & ) \&{const};\cr
+\+& |raw_rpar| & |rpar| & );\cr
+\+& |raw_unorbin| |const_like| & |raw_unorbin| \hfill $RC$\.{\\\ }
+ & $*$\&{const} |x|\cr
+\+& |raw_unorbin| & |unorbinop| & $*$ |x|\cr
+\+& |const_like| & |int_like| & \&{const} |x|\cr
+\+& |raw_int| |lpar| & |exp| |lpar| & \&{complex}$(x,y)$\cr
+\+& |raw_int| & |int_like| & \&{complex} |z|\cr
+\+& |begin_arg| |end_arg| & |exp| & \.{@@[}\&{char}$*$\.{@@]}\cr
+\+& |any_other| |end_arg| & |end_arg| & \&{char}$*$\.{@@]}\cr
+\+& |label| |label| & |label| \hfill $L_1\,|force|\,L_2$ & cf. tags\cr
+\+& |label| \altt|stmt| |decl| |function| & \altt|stmt| |decl| |function|
+ \hfill $\matrix{|cancel|\,|noop|\,\\{out}\,\\{out}\,|force|\cr
+ L\,\\{in}\,\\{in}\,|force|\,S}$ & cf. tags\cr
+\+& |do_like| |lbrace| & |do_head| |lbrace| & \&{do} $\{$ \cr
+\+& |do_head| |stmt| |else_like| |semi| & |stmt| \hfill
+ $D\,\\{bsp}\,S\,|cancel|\,|noop|\,\\{bsp}\,ES$ & |do {x;} while(y);|\cr
+\+\dag\theprodno& |typedef_like| |exp| & |typedef_like| |raw_int| &
+ \&{typedef} \&{?} \&{type} \cr
+\+& |int_like| |binop| |exp| & |int_like| & ? (\CPLUSPLUS/)\cr
+\+& |operator_like| \altt|raw_int| |int_like| |const_like| &
+ |operator_like| \hfill $O$\.{\ }$R$ & \&{operator} \&{name\_info} \cr
+\+\dag\theprodno& |lproc| \altt|exp| |int_like| |const_like| |pp_space| &
+ |lproc| \hfill $I\.\ E\.{\ \\5}$ & {\bf\#define} $a$ $\ldots$ \cr
+\+& |lproc| |exp| |exp| |pp_space| & |lproc| \hfill $I\.\ E_1 E_2\.{\ \\5}$
+ & {\bf\#define} $a(b)$ $\ldots$\cr
+\yskip
+\yskip
+\yskip
+\parindent=0pt
+\dag{\bf Notes}
+\yskip
+Rule 35: The |exp| must not be immediately followed by |lpar| or~|exp|.
+
+Rule 38: The |int_like| must not be immediately followed by |colcol|.
+
+Rule 42: The |exp| must not be immediately followed by |lpar| or~|exp|.
+
+Rule 48: The |exp| or |int_like| must not be immediately followed by |base|,
+|raw_int|, |int_like|, or |const_like|.
+
+Rule 76: The |force| in the |stmt| line becomes \\{bsp} if \.{CWEAVE} has
+been invoked with the \.{-f} option.
+
+Rule 78: The |define_like| case calls |make_underlined| on the following scrap.
+
+Rule 80: Makes the scrap following |lproc| reserved without changing the
+category.
+
+Rule 93: The |raw_int| must not be immediately followed by
+|prelangle| or |langle|.
+
+Rule 96: The |new_like| must not be immediately followed by |lpar|,
+|raw_int|, or |struct_like|.
+
+Rule 97: The operator after |operator_like|
+must not be immediately followed by a |binop|.
+
+Rule 116: This rule only holds outside of {\bf\#define} lines; |exp| must not
+be followed by a |lpar|.
+
+Rule 119: Makes the scrap following |lproc| reserved using the category
+of the scrap following |pp_space| if this scrap is |int_like|, |const_like|,
+or |raw_int|.
+
+\endgroup
+
+
+@q end of prod-alt.w @>
diff --git a/web/c_cpp/c2cweb/example.c b/web/c_cpp/c2cweb/example.c
new file mode 100644
index 0000000000..5d3529fa33
--- /dev/null
+++ b/web/c_cpp/c2cweb/example.c
@@ -0,0 +1,98 @@
+/* This file is part of the c2cweb package Version 1.5 */
+/* written by Werner Lemberg (a7971428@unet.univie.ac.at) 10-Nov-1996 */
+
+/* Grá Gott! */
+
+/* this is an artificial example C-file to demonstrate how c2cweb works. Please
+ note the insertions of @ and @@ `commands' into the C code. You should try
+ the various switches to see how they influence the output */
+
+/* Say
+
+ c2cweb [options] example.h example.c
+
+ to process this example. */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "example.h"
+
+/*@*/
+
+#define MAX_ARRAY 123
+#define test_function(a, b, c) (a+b+c)
+
+int dummy1; /* two dummy variables */
+float dummy2;
+
+/*@*/
+
+/* Two stupid functions */
+
+#ifdef HELLO
+void say_hello(void);
+#else
+void say_goodbye(void);
+#endif
+
+/*@@*/
+
+
+void main(void)
+ {int i=10000;
+ struct Test test;
+
+ while(i--)
+ test.array[i]=i;
+
+ do_nothing(1000);
+
+#ifdef HELLO
+ say_hello();
+#else
+ say_goodbye();
+#endif
+ }
+
+/*@*/
+
+union {
+ float another_dummy1;
+ int another_dummy2;
+} AnotherTest;
+
+/*@*/
+
+#ifdef HELLO
+void say_hello(void)
+ {printf("\nHello\n");
+
+// look at the unbalanced braces!
+// without insertion of /*}*/ right here c2cweb and CWEAVE would be confused
+/*}*/
+#else
+void say_goodbye(void)
+ {printf("\nGoodbye!\n");
+#endif
+ }
+
+/*@*/
+
+// the following piece of code can often be found in source files written for
+// multiple compilers. Before the |#else| statement a /*{}*/ command is
+// inserted
+
+#ifdef __STDC__
+void do_nothing(int count)
+/*{}*/
+#else
+void do_nothing(count)
+ int count;
+#endif
+ {while(count--)
+ ;
+ }
+
+
+/* end of example.c */
diff --git a/web/c_cpp/c2cweb/example.h b/web/c_cpp/c2cweb/example.h
new file mode 100644
index 0000000000..8ab55c02a3
--- /dev/null
+++ b/web/c_cpp/c2cweb/example.h
@@ -0,0 +1,20 @@
+/* This file is part of the c2cweb package Version 1.5 */
+/* written by Werner Lemberg (a7971428@unet.univie.ac.at) 10-Nov-1996 */
+
+// Grá Gott!
+// Hello!
+
+/* this is an example header file to demonstrate how c2cweb works. */
+
+/* Say
+
+ c2cweb [options] example.h example.c
+
+ to process this example. */
+
+
+struct Test {char *pointer;
+ int array[MAX_ARRAY];}; /* a dummy structure */
+
+
+/* end of example.h */
diff --git a/web/c_cpp/c2cweb/history.txt b/web/c_cpp/c2cweb/history.txt
new file mode 100644
index 0000000000..0fc04f18d5
--- /dev/null
+++ b/web/c_cpp/c2cweb/history.txt
@@ -0,0 +1,122 @@
+This file is part of the c2cweb package 1.5
+written by Werner Lemberg (a7971428@unet.univie.ac.at) 10-Nov-1996
+
+
+
+History of the c2cweb package
+=============================
+
+
+Version 1.0 :
+1-Mar-1994 only two persons got it :-)
+
+Version 1.1 :
+8-Mar-1994 initial release
+
+ new:
+ $ in identifiers are now allowed (CWEAVE)
+
+ whitespaces before preprocessor commands are now allowed
+ (CWEAVE)
+
+ the concatenation operator ## added (CWEAVE)
+
+ option -1 added (one-sided output) (c2cweb)
+
+ minor changes affecting documentation only
+
+ errors:
+ Ver 1.0 erroneously reported `@' outside of a string
+ (c2cweb)
+
+ /*}*/ started a new code section at function block level
+ if in /*@*/-mode (c2cweb)
+
+ tabs were not handled correctly (c2cweb)
+
+Version 1.2:
+13-Apr-1994 new:
+ c2cweb and cweave should now compile smoothly under UNIX
+ (tested with Linux)
+
+ paper format definition moved from c2cweb to compiler.w
+
+ some files renamed; makefile for c2cweb added
+ errors:
+ A serious bug introduced in Ver. 1.1 caused whitespaces
+ be swallowed (c2cweb)
+
+Version 1.3:
+20-June-1994: new:
+ Makefiles enhanced
+
+ new patchlevel of emx.exe
+
+ c2cweb.dvi added
+
+ c2cweb.txt updated
+ errors:
+ '"' couldn't be used; corrected (c2cweb)
+
+ sometimes the macro `\e' was concatenated with the next
+ word; '\e ' now written (c2cweb)
+
+ wrong index entry for dollar sign corrected (CWEAVE)
+
+ bug in original CWEAVE corrected:
+ you couldn't write e.g. @<Cases for |'\''|@>
+
+Version 1.4:
+20-Aug-1994: new:
+ based now on CWEB 3.2 (July 1994)
+
+ original CWEB source files for CWEAVE added
+
+ additional cwebmac.tex style; original cwebmac.tex
+ renamed in cwebmac.ori
+
+ c2cweb.txt has now an installation section
+
+ C-code example modified
+ errors:
+ \ at the end of the line in multi-line strings will now
+ be treated correctly (c2cweb)
+
+ from 1.3 : '\e ' is of course wrong. It must be '\e{}'
+ (and sometimes '\e{}%') (c2cweb)
+
+ //-comment handling was buggy (c2cweb)
+
+ braces in comments could cause an error (c2cweb)
+
+ email address changed (same host; old address became
+ unreachable)
+
+Version 1.5:
+10-Nov-1996: new:
+ now based on CWEB 3.4g (June 1996)
+
+ option -f (to include a format file) added
+
+ new command /*{}*/ added
+
+ Makefiles enhanced (a compiling run under djgpp is
+ likely to fail since it's untested. Additionally
+ wildcard expansion is missing---any volunteers to add
+ it are welcome)
+
+ c2cweb.w more structured
+
+ new email address
+ changed:
+ runtime binaries has been removed. You should get the
+ emxrsx.zip package of the emTeX distribution instead.
+
+ minor optical corrections.
+
+Version 1.5.1:
+28-Jun-1997: errors:
+ a `char' variable corrected to `int'.
+
+
+--- end of history.txt ---
diff --git a/web/c_cpp/cnoweb/README b/web/c_cpp/cnoweb/README
new file mode 100644
index 0000000000..d78ceb03be
--- /dev/null
+++ b/web/c_cpp/cnoweb/README
@@ -0,0 +1,4 @@
+This is the cnoweb `literate programming'
+demonstration program (pf.c) and macro package (cnoweb.tex).
+
+Comments to Jim Fox, fox@cac.washington.edu
diff --git a/web/c_cpp/cnoweb/cnoweb.tex b/web/c_cpp/cnoweb/cnoweb.tex
new file mode 100644
index 0000000000..c9de58413e
--- /dev/null
+++ b/web/c_cpp/cnoweb/cnoweb.tex
@@ -0,0 +1,511 @@
+% c-NO_WEB (a c program pretty printer)
+% by Jim Fox, February 1987
+% version 1.1, August 10, 1989
+% version 1.2, October 30, 1989
+% fixed spacing after ?, :, etc.
+% version 1.3, June 28, 1990
+% added OOdent and IIdent, added \|typewriter|
+% version 1.4, January 4, 1991
+% allow /* and */ in strings
+% version 1.5, December 11, 1991
+% page offset shift for two-sided page print alignment
+% nicer setting of too-long code lines
+% add \listfile and \includefile macros
+% version 1.6, March 17, 1992
+% Restore plain-tex meaning of right quote in math
+%
+%------------------------------------------------------------------
+%
+% The TeX input file is a c source program. It is assumed to have
+% this structure:
+%
+% /* comments ignored by c-no-web
+% \input cnoweb
+% \title{A one line title of the program (optional) }
+% \synopsis{Synopsis of the program (optional) }
+% \section{Name of the first section}
+% rest of comments */
+%
+% The rest of the file is normal c code.
+% Within the title a \\ may be used to separate lines.
+%
+% Each major section begins with
+% /* \section{name of the section} .... */
+% The section names are printed boldface, marked for reference in
+% the page headline, and written to the table of contents.
+%
+% Each minor section begins with
+% /* \subsection{name of the subsection} .... */
+% The subsection names are written to the table of contents.
+%
+% A new page can be forced by
+% /* \newpage */
+%
+% Code and other text containing special characters may be
+% typed in text mode if it is bracked by *< ... >*
+% e.g. /* *<inactive c-code>* */
+% but this may not be used in a macro argument.
+%
+% You can print in bold by enclosing text in double quotes: \"text".
+% You can print in typewriter by enclosing text in vertical bars: \|text|.
+% You can print in italics by enclosing text in single quotes: \'text'.
+%
+% You can include a verbatim listing of a file with \listfile, e.g.,
+% ... \listfile{program.h} ...
+% You can include a c file to be formatted with \includefile, e.g.,
+% ... \includefile{program.h} ...
+%
+% The file must end with \endc in a comment. e.g.,
+% ... last c code statement ...
+% /* \endc */
+%
+%-----------------------------------------------------------------
+%
+% Make sure macros loaded only once
+%
+\expandafter\ifx\csname cnoweb loaded\endcsname\relax
+ \expandafter\let\csname cnoweb loaded\endcsname*
+ \else\endinput\fi
+%
+\catcode`\@=11
+%
+\message{[c-no-web vers 1.6]}
+%
+%
+% page parameters -- most of these can be changed without harm
+% The default setup is for 12 point type on an 8.5 x 11 inch page.
+% Two side printing is assumed, 1-inch margins on the inside.
+%
+\vsize=55pc
+\hsize=37pc
+\topskip=2pc
+\parindent=0pt
+\parskip=6pt
+\overfullrule=0pt
+\newdimen\oddsideshift \oddsideshift=0pc % adjustment to odd, left margins
+\newdimen\evensideshift \evensideshift=2pc % adjustment to even, left margins
+\newdimen\rightmarginslop \rightmarginslop=3pc % right margin slop in code
+\newdimen\blockindent \blockindent=18pt % '{' block indentation
+\newdimen\longblockindent \longblockindent=30pt % '(' indentation
+\newskip\sectionskip \sectionskip2pc
+%
+% fonts
+%
+\font\titles=cmr10 scaled\magstep3 % for titles
+%
+% normal commentary size is 12 point
+%
+\font\twelverm=cmr12 % roman text
+\font\twelvei=cmmi12 % math italic
+\font\twelvesy=cmsy10 scaled\magstep1 % math symbols
+\font\twelvebf=cmbx12 % boldface extended
+\font\twelvett=cmtt12 % typewriter
+\font\twelvesl=cmsl12 % slanted roman
+\font\twelveit=cmti12 % text italic
+\font\twelveex=cmex10 scaled\magstep1 % math symbols
+%
+\font\ninerm=cmr9 % roman text
+\font\ninei=cmmi9 % math italic
+\font\ninesy=cmsy9 % math symbols
+%
+\def\normaltype{%
+ \def\rm{\fam0\twelverm}%
+ \textfont0=\twelverm \scriptfont0=\ninerm \scriptscriptfont0=\sevenrm
+ \textfont1=\twelvei \scriptfont1=\ninei \scriptscriptfont1=\seveni
+ \textfont2=\twelvesy \scriptfont2=\ninesy \scriptscriptfont2=\sevensy
+ \textfont3=\twelveex \scriptfont3=\twelveex \scriptscriptfont3=\twelveex
+ \textfont\itfam=\twelveit \def\it{\fam\itfam\twelveit}%
+ \textfont\slfam=\twelvesl \def\sl{\fam\slfam\twelvesl}%
+ \textfont\bffam=\twelvebf \def\bf{\fam\bffam\twelvebf}%
+ \textfont\ttfam=\twelvett \def\tt{\fam\ttfam\twelvett}%
+ \normalbaselineskip 14\p@
+ \setbox\strutbox=\hbox{\vrule height10\p@ depth4\p@
+ width0\p@}%
+ \normalbaselines\rm}
+\normaltype
+%
+% normal code size is 11 point
+%
+\font\elevenrm=cmr10 scaled\magstephalf % roman text
+\font\eleveni=cmmi10 scaled\magstephalf % math italic
+\font\elevensy=cmsy10 scaled\magstephalf % math symbols
+\font\elevenbf=cmbx10 scaled\magstephalf % boldface extended
+\font\eleventt=cmtt10 scaled\magstephalf % typewriter
+\font\elevensl=cmsl10 scaled\magstephalf % slanted roman
+\font\elevenit=cmti10 scaled\magstephalf % text italic
+%
+\def\codetype{%
+ \def\rm{\fam0\elevenrm}%
+ \textfont0=\elevenrm \scriptfont0=\sevenrm \scriptscriptfont0=\fiverm
+ \textfont1=\eleveni \scriptfont1=\seveni \scriptscriptfont1=\fivei
+ \textfont2=\elevensy \scriptfont2=\sevensy \scriptscriptfont2=\fivesy
+ \textfont3=\tenex \scriptfont3=\tenex \scriptscriptfont3=\tenex
+ \textfont\itfam=\elevenit \def\it{\fam\itfam\elevenit}%
+ \textfont\slfam=\elevensl \def\sl{\fam\slfam\elevensl}%
+ \textfont\bffam=\elevenbf \def\bf{\fam\bffam\elevenbf}%
+ \textfont\ttfam=\eleventt \def\tt{\fam\ttfam\eleventt}%
+ \normalbaselineskip 13\p@
+ \setbox\strutbox=\hbox{\vrule height9.5\p@ depth3.5\p@ width0\p@}%
+ \normalbaselines\rm}
+%
+% restricted code size is 10 point
+%
+\def\rcodetype{%
+ \def\rm{\fam0\tenrm}%
+ \textfont0=\tenrm \scriptfont0=\sevenrm \scriptscriptfont0=\fiverm
+ \textfont1=\teni \scriptfont1=\seveni \scriptscriptfont1=\fivei
+ \textfont2=\tensy \scriptfont2=\sevensy \scriptscriptfont2=\fivesy
+ \textfont3=\tenex \scriptfont3=\tenex \scriptscriptfont3=\tenex
+ \textfont\itfam=\tenit \def\it{\fam\itfam\tenit}%
+ \textfont\slfam=\tensl \def\sl{\fam\slfam\tensl}%
+ \textfont\bffam=\tenbf \def\bf{\fam\bffam\tenbf}%
+ \textfont\ttfam=\tentt \def\tt{\fam\ttfam\tentt}%
+ \normalbaselineskip 13\p@
+ \setbox\strutbox=\hbox{\vrule height9.5\p@ depth3.5\p@ width0\p@}%
+ \normalbaselines\rm}
+%
+% try using 11pt for text also
+%
+\let\normaltype\codetype
+\let\smalltype\rcodetype
+\normaltype
+%
+% allow underscore as char in non-math text
+\def\oldun{_}
+\def\specialunderscore{\ifmmode_\else{\tt\char"5F}\fi}
+\catcode`\_=\active
+\let_\specialunderscore
+%
+\def\\{{\tt\char"5C}} % for \ in comments
+\def\section#1{\mark{#1}%
+ {\let\folio=\relax\let_=\oldun \edef\\{\write\cfile{\endgraf
+ \tocnormaltype#1\cdots\cpageno\endgraf}}\\}%
+ {\bf#1.\ }}
+\def\subsection#1{%
+ {\let\folio=\relax\let_=\oldun \edef\\{\write\cfile{\endgraf
+ \toccodetype\hskip12pt#1\cdots\cpageno\endgraf}}\\}%
+ {#1.\ }}
+\def\subsubsection#1{%
+ {\let\folio=\relax\let_=\oldun \edef\\{\write\cfile{\endgraf
+ \tocrcodetype\hskip18pt#1\cdots\cpageno\endgraf}}\\}%
+ {#1.\ }}
+%
+%
+% headline contains (title, page number, section)
+%
+\def\makeheadline{\vbox to0pt{\vskip-30pt
+ \ifnum\pageno=-1\else\line{\strut\normaltype
+ \ifodd\pageno\firstmark\hfill\bf\the\job\rlap{\ -- \folio}%
+ \else\bf\llap{\folio\ -- }\the\job\rm\hfill\firstmark\fi}\fi
+ \vss}\nointerlineskip}
+\def\makefootline{\line{\tenrm\vrule height30pt depth0pt width0pt
+ \ifodd\pageno\today\ @\rightnow\ by \cnoweb\hfill
+ \else\hfill\today\ @\rightnow\ by \cnoweb\fi}}
+%
+\def\plainoutput{\shipout\vbox{%
+ \ifodd\pageno\moveright\oddsideshift\else\moveright\evensideshift\fi
+ \vbox{\makeheadline\pagebody\makefootline}}%
+ \advancepageno
+ \ifnum\outputpenalty>-\@MM \else\dosupereject\fi}
+
+\let\oldpagebody\pagebody
+\def\toprules{\vrule height4pt width.4pt\kern-.4pt\hskip\blockindent}
+\def\pagebody{\ifnum\pageno>0\vbox to0pt{\hrule height.3pt width\hsize
+ \leftline{\leaders\hbox{\toprules}}%
+ \vss}\nointerlineskip
+ \hbox{\llap{\vrule height\vsize width.3pt\hskip3pt}%
+ \oldpagebody}%
+ \else\oldpagebody\fi}
+
+%
+% table of contents
+%
+\newwrite\cfile
+\immediate\openout\cfile=\jobname.toc
+\def\cdots{\nobreak\leaders\hbox to1pc{\hss.\hss}
+ \hskip24pt plus1fill}
+\def\cpageno{\rlap{\hbox to18pt{\hfill\folio}}}
+%
+% these set the type size in toc entries
+%
+\let\tocnormaltype\relax % de-activate
+\let\toccodetype\relax
+\let\tocrcodetype\relax
+%
+%
+%-------------------------------------------------------------------
+%
+%
+% All comment fields are formatted normally (plain TeX style).
+% All c code is scanned and formatted verbatim.
+%
+% '/*' triggers TeX mode, '*/' triggers verbatim mode
+%
+\let\star=* % a catcode 11 star
+\let\slash=/ % a catcode 11 slash
+\let\rarrow=> % a catcode 11 right arrow
+%
+% ---------------------------------------------------------------
+%
+% In TeX mode the * is active and looks for */ or *<
+% \setex sets TeX mode
+%
+\newif\ifrestricted\restrictedfalse
+\def\setex{% begins TeX mode
+ \ifrestricted\rcodetype
+ \else\ifvmode\normaltype\filbreak\else\codetype\fi\fi
+ \catcode`\*=\active
+ {\tt/* }\ignorespaces}
+%
+{\catcode`\*=\active
+ \gdef*{\futurelet\next\checkslash}
+ }
+\def\checkslash{%
+ \ifx\next/\ifrestricted\let\next\resetrcc\else\let\next\setcc\fi
+ \else\ifx\next<\let\next\setrcc
+ \else\let\next\star\fi\fi\next}
+%
+%
+% In code mode / is active and looks for /*
+% \setcc sets the active code mode
+%
+\def\setcc/{\@setcc}
+\def\@setcc{% set code mode
+ \begingroup\ccverbatim\catcode`\/=\active
+ */
+ \parskip=0pt}
+%
+{\catcode`\/=\active
+ \gdef/{\futurelet\next\checkstar}
+ }
+\def\checkstar{\ifx\next*\let\next\endcc
+ \else\let\next\slash\fi\next}
+\def\endcc*{\@endcc}
+\def\@endcc{\endgroup\ifvmode\filbreak\fi\setex}
+%
+%
+% In restricted code mode > is active and looks for >*
+% \setrcc sets the restricted code mode
+%
+\def\setrcc<{% set little code mode
+ \begingroup\restrictedtrue
+ \begingroup\ccverbatim\rccverbatim\tt\catcode`\>=\active
+ \catcode`\/=\active
+ \parskip=0pt}
+%
+\def\resetrcc/{% reset little code mode
+ \begingroup\ccverbatim\rccverbatim\tt\catcode`\>=\active
+ \catcode`\/=\active
+ */
+ \parskip=0pt}
+%
+{\catcode`\>=\active
+ \gdef>{\futurelet\next\checkrstar}
+ }
+\def\checkrstar{\ifx\next*\let\next\endrcc
+ \else\let\next\rarrow\fi\next}
+\def\endrcc*{\endgroup\endgroup}
+%
+%
+% ---------------------------------------------------------------
+%
+% \leftskip is controlled by the presence of '{', '}',
+% '(', and ')' in the code text.
+%
+% \Ident increases \leftskip and takes effect after the current line
+% \Odent decreases \leftskip and takes effect on the current line
+% \IIdent and \OOdent do the same but use the long indentation
+%
+\newdimen\leftadjust % leftskip adjustment at next par
+\def\Ident{\global\advance\leftadjust\blockindent}
+\def\Odent{\global\advance\leftadjust-\blockindent\doOdent}
+\def\IIdent{\global\advance\leftadjust\longblockindent}
+\def\OOdent{\global\advance\leftadjust-\longblockindent\doOdent}
+\def\doOdent{%
+ \ifvmode\ifdim\leftadjust<\z@\global\advance\leftskip\leftadjust
+ \global\leftadjust0pt\fi\fi}
+%
+\def\codepar{% this is \par in code mode
+ \ifvmode\bigskip % this way blank lines are ignored at page tops
+ \else\endgraf
+ \ifdim\leftadjust=\z@\else\global\advance\leftskip\leftadjust
+ \global\leftadjust0pt\fi\fi}
+%
+% ---------------------------------------------------------------
+%
+% Here are the catcodes and definitions for c-code verbatim
+%
+\chardef\other=12
+\def\ccverbatim{% set all chars to type `other' or `active'
+ \catcode`\\=\other
+ \catcode`\{=\active
+ \catcode`\}=\active
+ \catcode`\(=\active
+ \catcode`\)=\active
+ \catcode`\$=\other
+ \catcode`\*=\other
+ \catcode`\&=\other
+ \catcode`\#=\active
+ \catcode`\%=\other
+ \catcode`\~=\other
+ \catcode`\_=\other
+ \catcode`\^=\other
+ \catcode`\|=\other
+ \catcode`\`=\active
+ \catcode`\'=\active
+ \catcode`\"=\active
+ \let\par\codepar
+ \obeyspaces \obeylines \frenchspacing \codetype
+ \pretolerance10000 % don't hyphenate variable names, etc.
+ \everypar{\hangindent\longblockindent\hangafter1}% indent wrapped
+ \rightskip0pt minus\rightmarginslop % allow some extension
+ \tt}
+\def\rccverbatim{% additional \other chars for restricted mode
+ \catcode`\{=\other
+ \catcode`\}=\other
+ \catcode`\(=\other
+ \catcode`\)=\other
+ \catcode`\#=\other
+ \catcode`\'=\other
+ \catcode`\"=\other
+ \rcodetype \tt}
+%
+% And here are the definitions for the c-code active characters.
+% These perform the little formatting we do on c-code.
+% {, }, (, ), and # adjust the indentation
+% `, ', ", and / trigger more complete verbatim
+%
+% Note that the right quote already has a plain-tex definition
+%
+{ \catcode`\<=1\catcode`\>=2
+ \catcode`\{=\active \gdef{<<\Ident\char`\{>>
+ \catcode`\}=\active \gdef}<<\Odent\char`\}>>
+ \catcode`\(=\active \gdef(<<\IIdent\char`\(>>
+ \catcode`\)=\active \gdef)<<\OOdent\char`\)>>
+ \catcode`\|=0
+ \catcode`\\=\active
+ |catcode`|"=|active
+ |gdef"<|char`|"|bgroup
+ |catcode`|{=|other |catcode`|}=|other
+ |catcode`|(=|other |catcode`|)=|other
+ |catcode`|'=|other |catcode`|/=|other
+ |catcode`|\=|active |let\|verbslash
+ |def"<<|char`|"|egroup>>>
+ |catcode`|'=|active
+ |global|let|plain@rquote'
+ |gdef|cnoweb@rquote<|char`|'|bgroup
+ |catcode`|{=|other |catcode`|}=|other
+ |catcode`|(=|other |catcode`|)=|other
+ |catcode`|"=|other |catcode`|/=|other
+ |catcode`|\=|active |let\|verbslash
+ |def'<<|char`|'|egroup>>>
+ |gdef'<|ifmmode|let|next|plain@rquote
+ |else|let|next|cnoweb@rquote|fi|next>
+ >
+\def\verbslash{\begingroup\catcode`\'=\other\catcode`\"=\other\doverbslash}
+\def\doverbslash#1{\\#1\endgroup}
+{\catcode`\`=\active\gdef`{\relax\lq}}
+{\catcode`\#=\active\gdef#{\ifvmode\ifdim\leftskip>\z@
+ \noindent\llap{\hbox to\leftskip{\#\hss}}\ignorespaces
+ \else\#\fi\else\#\fi}}
+%
+%
+% ---------------------------------------------------------------
+%
+% \listfile produces a verbatim listing of a file
+% \includefile formats the file (assumed to be c-code)
+%
+{\obeyspaces\gdef\hardspaces{\global\let =\ }}
+\def\listfile#1{\par\begingroup\leftskip\blockindent\parskip0pt
+ \ccverbatim\rccverbatim\hardspaces\input#1\par\endgroup}
+\def\includefile#1{\@setcc\par\input#1\par\@endcc}
+%
+% ---------------------------------------------------------------
+%
+% \endc signals end of the c program
+%
+\def\endc{{\it end~\tt*/}\vfill\eject\dotitle\docontents\end}
+%
+% ---------------------------------------------------------------
+%
+% /* \newpage */ should give nice new page
+\def\newpage{\vadjust{\vfill\eject}}
+%
+% some ebcdic systems get 05 for tabs
+\catcode`\^^E=10 % make them spaces
+%
+% \"bold text" and \|typewriter text| and \'italic text'
+%
+\def\"#1"{{\bf#1}}
+\def\|#1|{{\tt#1}}
+\def\'#1'{{\it#1}}
+%
+% fix \item, etc. to work without \parindent
+%
+\newdimen\itemindent\itemindent2\blockindent
+\def\hang{\hangindent\itemindent}
+\def\textindent#1{\indent\hbox to\itemindent{\hss#1\enspace}\ignorespaces}
+\def\item{\par\hang\textindent}
+\def\textiindent#1{\indent\hbox to2\itemindent{\hss#1\enspace}\ignorespaces}
+\def\itemitem{\par\indent\hangindent2\itemindent\textiindent}
+\def\narrower{\advance\leftskip\itemindent
+ \advance\rightskip\itemindent}
+%
+% c-no-web name
+%
+\def\cnoweb{\hbox{c-\setbox0=\hbox{web}%
+ \vrule depth-.25\ht0 height.33\ht0 width\wd0\kern-\wd0\box0}}
+%
+% print the title and table of contents
+%
+\newtoks\job\job={\jobname}
+\newtoks\title\title={}
+\newtoks\synopsis\synopsis={}
+\def\dotitle{
+ \ifodd\pageno\else
+ \message{page alignment}Intentionally blank \vfill\eject\fi
+ \pageno=-1
+ \vglue2pc
+ \centerline{\titles\the\job}
+ \vskip18pt
+ \centerline{\bf\the\title}
+ {\openup3pt\narrower\noindent\the\synopsis\par}
+ \vfill}
+\def\docontents{% print table of contents
+ \mark{Contents}
+ \immediate\closeout\cfile
+ \begingroup
+ \catcode`\@=11
+ \leftskip=18pt\rightskip=\leftskip
+ \everypar={\hang}
+ \rightline{Page}
+ \medskip
+ \let\tocnormaltype\normaltype % activate these type size macros
+ \let\toccodetype\codetype
+ \let\tocrcodetype\rcodetype
+ \input \jobname.toc
+ \catcode`\@=12
+ \endgroup
+ \vfill
+ \eject}
+\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}
+\def\today{\ifcase\month\or
+ Jan\or Feb\or Mar\or Apr\or May\or Jun\or
+ Jul\or Aug\or Sep\or Oct\or Nov\or Dec\fi
+ \space\number\day, \number\year}
+\def\rightnow{\count0=\time\count1=\count0 \divide\count0by60
+ \ifnum\count0<10 0\fi\number\count0:% hours
+ \multiply\count0by60 \advance\count1by-\count0
+ \ifnum\count1<10 0\fi\number\count1% minutes
+ }
+%
+\catcode`\@=11
+%
+{\hsize\maxdimen
+ \output={\setbox0=\box255}\eject} % delete all before \input cnoweb
+\setex % begin with TeX mode
+
+% end of cnoweb.tex
diff --git a/web/c_cpp/cnoweb/pf.c b/web/c_cpp/cnoweb/pf.c
new file mode 100644
index 0000000000..5fb0af98de
--- /dev/null
+++ b/web/c_cpp/cnoweb/pf.c
@@ -0,0 +1,371 @@
+/*
+ pf.c in c-no-web format. (8/10/89)
+ by Jim Fox, University of Washington
+
+ \input cnoweb % load the c-no-web system
+%
+% \nweb ... \bewn = \cnoweb commentary
+ \def\nweb{\leavevmode\begingroup\codetype$\lbrack\!\lbrack\;$}
+ \def\bewn{$\;\rbrack\!\rbrack$\ \endgroup}
+%
+ \title{Printing factorials: a demonstration of \cnoweb}
+ \synopsis{You are reading a program listing that was formatted
+ with \par\item{}{\tt \% tex pf.c}\par
+ The same program is compiled
+ with \par\item{}{\tt \% cc pf.c}\par
+ The key to this dual function source file is a \TeX\ macro
+ package called \cnoweb\ that treats all comments as `\TeX-text'
+ and all else as `verbatim-text.' The C compiler naturally
+ does the opposite and interprets only the text outside the comments.
+
+ \nweb In this program comments about
+ \cnoweb\ itself look like this.\bewn}
+ \section{Introduction}
+
+ This program prints factorials of positive integers.
+ It uses this definition of $n!$
+ $$ n! = \prod_{i=1}^n i$$
+
+ {\narrower
+ \nweb \"pf.c" begins with a comment which
+ is treated as \TeX-text by \cnoweb.
+
+ The first comment contains the
+ string *<\input cnoweb>*. This begins the \cnoweb\ listing.
+ Included also in this leading comment section is
+ *<\title{Printing ...}>*,
+ *<\synopsis{You are reading ...}>*,
+ and
+ *<\section{Introduction}>*.\bewn\par}
+
+ The program is invoked with the command
+ \item{}\"pf $[$-l$]$ $[$-e$]$ $n$"
+
+ where
+ \item{\bf -l} prints the factorials of all numbers
+ up to and including the limit $n$.
+ \item{\bf -e} includes an exponential notation approximation.
+ \item{$n$} is the number whose factorial will be printed.
+ */
+
+#define GOODEXIT 0 /* exit with this if factorial OK */
+#define BADEXIT 1 /* exit with this if error */
+
+#include <stdio.h> /* standard io stuff */
+#include <math.h> /* math stuff */
+char *malloc(); /* memory allocator */
+
+/* \section{Big-integer routines}
+
+ \"pf" would be trivial were it not for the rapid
+ growth of $n!$, which is much greater than exponential
+ and quickly surpasses even the real number capacity of most machines.
+ We therefore define a new data type (\"Int") to hold big integers.
+ */
+
+ typedef struct Int_ {
+ int radix; /* $2^1 \le \hbox{radix} \le 2^8$ */
+ char *digits; /* the \"Int"'s digits */
+ int length; /* number of digits available */
+ int limit; /* number of digits in use */
+ } Int;
+
+/* We do not need many operations on \"Int"s to compute factorials:
+ only `set' and `multiply'.
+ */
+
+/* \subsection{\"Set(I,\ i)"}
+ Return \"I" initialized to \"i". */
+
+Set(I,i)
+Int *I;
+int i;
+{
+ int d;
+ I->digits[0] = (i?1:0);
+ for (d=1; d<I->length; I->digits[d++]=0);
+ I->limit = 0;
+ if ((i!=0)&&(i!=1)) Product(I,i);
+ return (0);
+}
+
+/* \subsection{\"Product(I,\ i)"}
+ Return \"I" multiplied by \"i".
+ Returns true if the product is OK. */
+
+Product(I,i)
+Int *I;
+int i;
+{
+ int d,n;
+ int l = I->limit+1;
+ int r = I->radix;
+ int carry = 0;
+
+ for (d=0; ((d<l)||(carry!=0)); d++) {
+ if (d>=I->length) return (0); /* not enough digits */
+ n = I->digits[d] * i + carry;
+ if ((I->digits[d] = n % r)>0) I->limit = d;
+ carry = n / r;
+ }
+ return (1);
+}
+
+
+
+/* \section{\"main()"} Print the factorial of the integer
+ found on the command line.
+
+ \item{1.} Parse command line arguments.
+ \item{2.} Compute number of digits needed and allocate space.
+ \item{3.} Calculate the factorial.
+ \item{4.} Print the factorial.
+
+ \nweb \cnoweb\ breaks pages only before comments.\hfill\break
+ You can control pagination with this knowledge.\bewn
+
+ The higher the radix the fewer digits needed, but
+ we use an internal radix of 10
+ to save a lot of division when printing the number.
+ Also, we already have a log$_{10}$ function.
+
+ */
+
+#define RADIX 10
+
+Int nfactorial; /* place for the factorial */
+Int *nf = &nfactorial;
+
+/* command line parameters */
+
+ int limit_mode = 0; /* true if printing all factorials */
+ int expon_mode = 0; /* true if printing exponential notation */
+
+/* start of the program */
+
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int n;
+ int i;
+
+ /* 1. Parse the command line */
+
+ n = parse_args(argc,argv); /* we will print $n!$ */
+
+ /* 2. Compute digits needed and allocate space */
+
+ nf->radix = RADIX;
+ nf->length = digits(n,RADIX);
+
+ if ((nf->digits = malloc(nf->length))==NULL) {
+ printf("Sorry, cannot allocate space for %d digits\n",
+ nf->length);
+ exit (BADEXIT);
+ }
+
+ /* 3. Calculate the factorial. */
+
+ Set(nf,1); /* initialize \"nf" */
+
+ for (i=1; i<=n; i++) {
+ if (Product(nf,i)==0) {
+ printf("Sorry, miscalculated the number of digits.\n");
+ exit (BADEXIT);
+ }
+ if (limit_mode) print_Int(nf,i);
+ }
+
+ /* 4. Print the result, if it hasn't been printed yet. */
+
+ if (!limit_mode) print_Int(nf,n);
+ exit (GOODEXIT);
+}
+
+/* \subsection{\"parse_args(argc,argv)"}
+
+ This is a standard UNIX idiom.
+ See Kernighan \& Ritchie.
+
+ \nweb \cnoweb\ automatically indents after
+ {\tt\char`\{} and {\tt\char`\(}.\bewn */
+
+parse_args(argc,argv)
+int argc;
+char *argv[];
+{
+ int n = (-1);
+
+ while (--argc > 0) {
+ argv++;
+ if (argv[0][0]=='-') { /* is an option flag */
+ switch (argv[0][1]) {
+ case 'l': {
+ limit_mode = 1;
+ break;
+ }
+ case 'e': {
+ expon_mode = 1;
+ break;
+ }
+ default: show_usage();
+ }
+ } else { /* is the number */
+ sscanf(argv[0],"%d",&n);
+ }
+ }
+
+ if (n<=0) show_usage();
+ return (n);
+}
+
+/* \subsection{\"digits(n,r)"} Returns number of digits in \"n"
+ using a radix of \"r".
+
+ A factorial can be approximated by the Sterling formula
+ $$ n! \approx e^{-n} n^{n} \sqrt{2\pi n}$$
+ What we want is the number of digits, which is
+ $$ \hbox{\# digits} \approx \log_r(n!)=\log(n!)/\log(r) \approx
+ (-n \log e + n \log n + {1\over2}\log (2\pi n))/\log(r)$$
+
+ We will add a couple of digits to this value
+ to allow for the approximations and assure that we
+ have enough.
+ */
+
+#define PI 3.141592653589793238462643 /* $\pi$ */
+#define E 2.718281828459045235360287 /* $e$ */
+
+digits(n,r)
+int n;
+int r;
+{
+ double dn = n;
+ int nd;
+
+ nd = (int)((-dn * log10(E)) +
+ (dn * log10(dn)) + (.5 * log10(2*PI*dn)))/log10((double)r) + 2;
+ /* *<printf("requires %d digits\n",nd);>* */
+
+ /* \nweb The
+ `Commented out' code above was typed:
+ {\tt/{}* *{}<printf...;>{}* *{}/}.\bewn */
+
+ return (nd);
+}
+
+/* \subsection{\"print_Int(I,\ i)"}
+ Print {\tt{\it value(}i{\it)} = {\it value(}I{\it)}}.
+ The internal radix that matches the display radix
+ clearly makes this procedure easier.
+
+ This display uses the convention that separates each
+ three-digit set with commas.
+*/
+
+#define MAX_WIDTH 80 /* maximum width of the output */
+
+print_Int(I,i)
+Int *I;
+int i;
+{
+ int d;
+ int lp,bp;
+ char line[MAX_WIDTH];
+
+ sprintf(line,"%d! = ",i);
+ bp = lp = strlen(line);
+ for (d=I->limit; d>=0; d--) {
+ line[lp++] = I->digits[d] + '0'; /* assumes radix $\le 10$ */
+ if ((d%3)==0) {
+ line[lp++] = (d?',':'.');
+ if ((d==0) || (lp>MAX_WIDTH-5)) {
+ line[lp] = '\0';
+ printf("%s\n",line);
+ for (lp=0; lp<bp; line[lp++]=' ');
+ }
+ }
+ }
+
+ /* If the exponential notation was desired, print it now.
+ */
+
+ if (expon_mode) {
+ int d = I->limit; /* the most significant digit */
+ sprintf(line+bp,"approximately = %d.%d x 10e%d",
+ I->digits[d],d?I->digits[d-1]:0,d);
+ printf("%s\n",line);
+ }
+ return (0);
+}
+
+/* \section{\"show_usage()"} invocation syntax error---show
+ correct usage */
+
+int show_usage()
+{
+ printf("usage: pf [-l] [-e] positive_integer\n");
+ exit (BADEXIT);
+}
+
+/* \section{Summary of \cnoweb\ commands}
+
+ These control sequences are defined in the \cnoweb\ macro package.
+
+ \begingroup
+ \def\{{{\tt\char`\{}}
+ \def\}{{\tt\char`\}}}
+ \def\cs#1{\smallskip\noindent\hangindent7\blockindent\hangafter1
+ \hbox to7\blockindent{\bf#1\qquad\hss}\ignorespaces}
+
+ \cs{\\title\{ ... \}} Titles the program.
+ \cs{\\job\{ ... \}} Another title area. Defaults to input filename.
+ \cs{\\section\{ ... \}} Begins a section. The section title
+ is also included in the table of contents and
+ in the page header.
+ \cs{\\subsection\{ ... \}} Begins a subsection. The subsection title
+ is also included in the table of contents.
+ \cs{\\subsubsection\{ ... \}} Begins a subsubsection.
+ The subsubsection title
+ is also included in the table of contents.
+ \cs{\\newpage} Causes a page eject after the current line. This
+ is usually used in a comment by itself, e.g.,
+ \hbox{\tt /{}* \\newpage *{}/}.
+ \cs{\\endc} Ends the \cnoweb\ listing. This
+ is usually the last line in the file, e.g.,
+ \hbox{\tt /{}* \\endc *{}/}.
+ \cs{\\{\tt"} ... {\tt"}} Prints {\bf bold} text.
+ \cs{\\{\tt'} ... {\tt'}} Prints {\it italic} text.
+ \cs{\\{\tt|} ... {\tt|}} Prints {\tt typewriter} text.
+ \cs{*{\tt<} ... {\tt>}*} Allows C code to be included in comments.
+ You can nest comments within the `commented out' C code, e.g.,
+ \hfill\break
+ {\tt/{}* comment out this section *{}<} \hfill\break
+ \hglue\blockindent{\tt i = 0; /{}* initialize \"i" *{}/} \hfill\break
+ \hglue\blockindent{\tt ...} \hfill\break
+ \hglue\blockindent{\tt >{}* end of the commented out section *{}/}
+
+ \cs{\\item, \\hang, {\rm etc.}} Work as you hope they would.
+ \endgroup
+
+ */
+
+/* \section{How to obtain \cnoweb}
+
+ You may obtain \cnoweb\ by anonymous ftp to
+ {\tt u.washington.edu}.
+
+ It is in the directory: {\tt pub/tex/cnoweb}
+
+ \bigskip
+ \rightline{--- Jim Fox,
+ University of Washington}
+ \rightline{\strut \tt fox@cac.washington.edu}
+
+ \medskip
+
+ The file ends with the comment
+ `{\tt /{}* \\endc *{}/}' */
+
+/* \endc */
diff --git a/web/c_cpp/ctie/ChangeLog b/web/c_cpp/ctie/ChangeLog
new file mode 100644
index 0000000000..1f78f20ebd
--- /dev/null
+++ b/web/c_cpp/ctie/ChangeLog
@@ -0,0 +1,25 @@
+2003-04-20 Julian Gilbey <jdg@debian.org>
+
+ * Remove documented need for any change files - they're not
+ actually necessary (thanks to Hartmut Henkel
+ <hartmut_henkel@gmx.de> for this observation)
+
+ * Use kpathsea 3.4.5 modified functions, losing some backward
+ compatibility if the kpathsea library is used
+
+ * Match current Web2C/Kpathsea modifications to cweb, and modify
+ to more closely match cweb 3.64 behaviour
+
+ * Release as version 1.1
+
+2002-02-03 Julian Gilbey <jdg@debian.org>
+
+ * Make success message appear on a new line at end of run
+
+ * Improve formatted output for ctie-k.ch
+
+ * Release as version 1.0
+
+2002-01-13 Julian Gilbey <jdg@debian.org>
+
+ * Initial release (version 0.9)
diff --git a/web/c_cpp/ctie/Makefile b/web/c_cpp/ctie/Makefile
new file mode 100644
index 0000000000..8edc24225c
--- /dev/null
+++ b/web/c_cpp/ctie/Makefile
@@ -0,0 +1,51 @@
+#
+# Makefile for ctie distribution - 21 Dec 92
+#
+# This file makes CTIE and needs ctangle from cweb distribution.
+#
+
+CTANGLE=ctangle
+BINDIR=.
+CTIE=$(BINDIR)/ctie
+
+# directory for CWEB inputs in @i files
+CWEBINPUTS= /usr/local/lib/cweb
+
+CFLAGS=
+LDFLAGS=
+KPATHSEAFLAGS=-lkpathsea
+
+default: ctie
+
+
+# CTIE
+ctie.o: ctie.c
+ $(CC) $(LDFLAGS) $(CFLAGS) -DCWEBINPUTS=\"$(CWEBINPUTS)\" -c ctie.c
+
+ctie: ctie.o
+ $(CC) $(LDFLAGS) $(CFLAGS) -o $(CTIE) ctie.o
+
+ctie.c: ctie.w
+ $(CTANGLE) ctie
+
+ctie-k.o: ctie-k.c
+
+ctie-k: ctie-k.o
+ $(CC) $(LDFLAGS) $(CFLAGS) -o $(BINDIR)/ctie-k ctie-k.o $(KPATHSEAFLAGS)
+
+ctie-k.c: ctie.w ctie-k.ch
+ ctangle ctie.w ctie-k.ch ctie-k.c
+
+clean:
+ rm -f ctie.o ctie-k.o ctie.outc ctie.outm ctie.tex
+ rm -f ctie.log ctie.toc ctie.scn ctie.idx
+ rm -f ctiedoc.aux ctiedoc.log
+
+veryclean: clean
+ rm -f $(BINDIR)/ctie $(BINDIR)/ctie-k ctie.dvi ctiedoc.dvi
+
+ttest: $(CTIE)
+ $(CTIE) -c ctie.outc ctie.tie ctie.cf?
+ diff ctie.outc ctie.chf.gen
+ $(CTIE) -m ctie.outm ctie.tie ctie.cf?
+ diff ctie.outm ctie.master.gen
diff --git a/web/c_cpp/ctie/README b/web/c_cpp/ctie/README
new file mode 100644
index 0000000000..48aab880ee
--- /dev/null
+++ b/web/c_cpp/ctie/README
@@ -0,0 +1,75 @@
+This is the README file of the `CTIE' distribution, version 1.1
+---------------------------------------------------------------
+
+CTIE is based on the `TIE' program, a program which was first
+developed to allow WEB programmers to use more than one change file
+with their WEB programs.
+
+CWEB introduced a new command, @i, to handle "include files". The
+original TIE program was not designed to handle this situation, and so
+could not be used for all CWEB programs. CTIE behaves essentially
+identically to the original TIE, and identical results will be
+generated when TIE is applied to traditional WEB files with changes,
+as long as there are no errors. (Errors may lead to different output,
+but then the errors need correcting, anyway.)
+
+CTIE can be used to either create a new version of the (C)WEB file
+which incorporates the changes, or to merge multiple change files into
+a single change file. This program does not depend in an essential
+way on any special WEB dialect, nor on using WEB at all, as the only
+controls to be interpreted are the change requests in the change files
+(delimited by @x, @y and @z) and file include commands (indicated by @i).
+This makes `CTIE' also usable for any other language, or even
+data files. See the documentation ctiedoc.tex and the example file
+ctie.tie for more information.
+
+
+REQUIREMENTS:
+
+This version of `CTIE' is written in CWEB. To preprocess and compile
+the source you will need a working `ctangle'. A pretangled ctie.c is
+supplied if you do not have a working ctangle available.
+
+Please note, that the CWEB by Silvio Levy and Donald E. Knuth must
+probably be at least at version 2.8, to process and compile `ctie'
+without problems.
+
+Furthermore, a ctie-k.ch file is provided which links ctie against
+Karl Berry's kpathsea library. A tangled version of this file is
+provided as ctie-k.c. To use this, you will need to link against
+version 3.4.5 or higher of the kpathsea library. This version
+searches for files, both from the command line and included (@i) files
+using the CWEBINPUTS search path.
+
+
+DISTRIBUTION:
+
+This package has been uploaded to CTAN, and appears in the directory
+web/c_cpp/ctie/.
+
+
+LICENCE:
+
+This program is based on tie.w and common.w (part of CWEB). It is
+distributed with the following licence.
+
+Copyright (c) 2002,2003 by Julian Gilbey
+All rights reserved.
+
+This program is distributed WITHOUT ANY WARRANTY, express or implied.
+
+Permission is granted to make and distribute verbatim copies of this
+program provided that the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+program 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.
+
+
+BUGS/ENHANCEMENTS:
+
+If you detect bugs in the implementation of CTIE or have suggestions
+to enhance functionality or improve portability, please send a message
+to Julian Gilbey <jdg@debian.org>.
diff --git a/web/c_cpp/ctie/ctie-k.c b/web/c_cpp/ctie/ctie-k.c
new file mode 100644
index 0000000000..bfa74483d5
--- /dev/null
+++ b/web/c_cpp/ctie/ctie-k.c
@@ -0,0 +1,1166 @@
+#define version_number "1.1"
+#define banner "This is CTIE, Version 1.1"
+#define copyright \
+"Copyright 2002,2003 Julian Gilbey. All rights reserved. There is no warranty.\n\
+Run with the --version option for other important information." \
+ \
+
+#define kpse_find_cweb(name) kpse_find_file(name,kpse_cweb_format,true) \
+
+#define buf_size 1024
+#define max_file_index 32 \
+
+#define xisupper(c) (isupper(c) &&((unsigned char) c<0200) ) \
+ \
+
+#define spotless 0
+#define troublesome 1
+#define fatal 2 \
+
+#define max_include_files 20 \
+
+#define max_file_name_length 1024 \
+
+#define too_long() {total_include_files--;free(new_inc) ; \
+err_print(i,"! Include file name too long") ;goto restart;} \
+
+#define fatal_error(i,s,t) { \
+fprintf(stderr,"\n%s",s) ; \
+err_print(i,t) ; \
+history= fatal; \
+exit(wrap_up() ) ; \
+} \
+ \
+
+#define none (-1) \
+
+/*2:*/
+#line 89 "./ctie.w"
+
+/*10:*/
+#line 172 "./ctie.w"
+
+#include <stdio.h>
+
+
+#line 126 "./ctie-k.ch"
+/*:10*//*39:*/
+#line 715 "./ctie.w"
+
+#include <errno.h>
+
+
+/*:39*//*72:*/
+#line 454 "./ctie-k.ch"
+
+#include <kpathsea/kpathsea.h>
+
+/*:72*/
+#line 90 "./ctie.w"
+
+/*12:*/
+#line 211 "./ctie.w"
+
+#define search 0
+#define test 1
+#define reading 2
+#define ignore 3
+typedef int in_file_modes;
+#define unknown 0
+#define master 1
+#define chf 2
+typedef int file_types;
+
+
+/*:12*//*13:*/
+#line 229 "./ctie.w"
+
+#define normal 0
+#define pre 1
+#define post 2
+typedef int out_md_type;
+
+
+/*:13*//*14:*/
+#line 239 "./ctie.w"
+
+typedef int file_index;
+
+
+/*:14*//*15:*/
+#line 246 "./ctie.w"
+
+typedef struct _indsc{
+char file_name[max_file_name_length];
+long line;
+FILE*the_file;
+struct _indsc*parent;
+}include_description;
+
+
+/*:15*//*16:*/
+#line 259 "./ctie.w"
+
+typedef struct _idsc{
+string file_name;
+char buffer[buf_size];
+in_file_modes mode;
+long line;
+file_types type_of_file;
+include_description*current_include;
+char*buffer_end;
+char*limit;
+char*loc;
+FILE*the_file;
+int dont_match;
+}input_description;
+
+
+/*:16*/
+#line 91 "./ctie.w"
+
+/*30:*/
+#line 584 "./ctie.w"
+
+#line 223 "./ctie-k.ch"
+void err_print P2H(file_index,char*);
+#line 586 "./ctie.w"
+
+/*:30*//*35:*/
+#line 673 "./ctie.w"
+
+#line 243 "./ctie-k.ch"
+int wrap_up P1H(void);
+#line 675 "./ctie.w"
+
+/*:35*//*37:*/
+#line 696 "./ctie.w"
+
+#line 249 "./ctie-k.ch"
+void pfatal_error P2H(char*,char*);
+#line 698 "./ctie.w"
+
+/*:37*//*69:*/
+#line 1232 "./ctie.w"
+
+#line 392 "./ctie-k.ch"
+void usage_help P1H(void);
+void print_version_and_exit P2H(string,string);
+#line 1235 "./ctie.w"
+
+
+/*:69*/
+#line 92 "./ctie.w"
+
+/*9:*/
+#line 162 "./ctie.w"
+
+int history= spotless;
+
+
+/*:9*//*17:*/
+#line 286 "./ctie.w"
+
+int total_include_files= 0;
+
+/*:17*//*18:*/
+#line 292 "./ctie.w"
+
+file_index actual_input,test_input,no_ch;
+file_types prod_chf= unknown;
+out_md_type out_mode;
+
+/*:18*//*20:*/
+#line 309 "./ctie.w"
+
+input_description*input_organisation[max_file_index+1];
+
+
+/*:20*//*24:*/
+#line 406 "./ctie.w"
+
+boolean input_has_ended= false;
+
+
+/*:24*//*41:*/
+#line 742 "./ctie.w"
+
+FILE*out_file;
+string out_name;
+
+
+#line 273 "./ctie-k.ch"
+/*:41*//*68:*/
+#line 1217 "./ctie.w"
+
+string CTIEHELP[]= {
+"Usage: ctie -[mc] outfile master changefile(s)",
+" Create a new master file or change file from the given",
+" master (C)WEB file and changefiles.",
+" All filenames are taken literally; no suffixes are added.",
+"",
+"-m create a new master file from original (C)WEB and change file(s)",
+"-c create a master change file for original (C)WEB file from changefile(s)",
+"--help display this help and exit",
+"--version display version information and exit",
+NULL
+};
+
+
+/*:68*//*73:*/
+#line 459 "./ctie-k.ch"
+
+string file_open_mode;
+#line 1278 "./ctie.w"
+
+
+/*:73*/
+#line 93 "./ctie.w"
+
+/*31:*/
+#line 589 "./ctie.w"
+
+#line 230 "./ctie-k.ch"
+void err_print P2C(file_index,i,char*,s)
+
+#line 592 "./ctie.w"
+{
+char*k,*l;
+fprintf(stderr,*s=='!'?"\n%s":"%s",s);
+if(i>=0)/*32:*/
+#line 611 "./ctie.w"
+
+{
+register input_description*inp_desc= input_organisation[i];
+register include_description*inc_desc= inp_desc->current_include;
+
+if(inc_desc!=NULL){
+fprintf(stderr,". (l. %ld of include file %s",inc_desc->line,
+inc_desc->file_name);
+fprintf(stderr," included from l. %ld of %s file %s)\n",
+inp_desc->line,
+inp_desc->type_of_file==master?"master":"change",
+inp_desc->file_name);
+}
+else
+fprintf(stderr,". (l. %ld of %s file %s)\n",inp_desc->line,
+inp_desc->type_of_file==master?"master":"change",
+inp_desc->file_name);
+l= (inp_desc->loc>=inp_desc->limit?inp_desc->limit:inp_desc->loc);
+if(l> inp_desc->buffer){
+for(k= inp_desc->buffer;k<l;k++)
+if(*k=='\t')putc(' ',stderr);
+else putc(*k,stderr);
+putc('\n',stderr);
+for(k= inp_desc->buffer;k<l;k++)
+putc(' ',stderr);
+}
+for(k= l;k<inp_desc->limit;k++)
+putc(*k,stderr);
+putc('\n',stderr);
+}
+
+
+/*:32*/
+#line 595 "./ctie.w"
+
+else putc('\n',stderr);
+fflush(stderr);
+history= troublesome;
+}
+
+/*:31*//*38:*/
+#line 699 "./ctie.w"
+
+#line 256 "./ctie-k.ch"
+void pfatal_error P2C(char*,s,char*,t)
+#line 702 "./ctie.w"
+{
+char*strerr= strerror(errno);
+
+fprintf(stderr,"\n%s%s",s,t);
+if(strerr)fprintf(stderr," (%s)\n",strerr);
+else fprintf(stderr,"\n");
+history= fatal;
+exit(wrap_up());
+}
+
+
+/*:38*/
+#line 94 "./ctie.w"
+
+/*21:*/
+#line 328 "./ctie.w"
+
+#line 143 "./ctie-k.ch"
+boolean get_line P2C(file_index,i,boolean,do_includes)
+#line 331 "./ctie.w"
+{
+register input_description*inp_desc= input_organisation[i];
+register FILE*fp;
+
+if(inp_desc->mode==ignore)return false;
+
+restart:
+if(inp_desc->current_include!=NULL){
+register include_description*inc_desc= inp_desc->current_include;
+
+fp= inc_desc->the_file;
+/*26:*/
+#line 426 "./ctie.w"
+
+{
+register int c;
+register char*k;
+
+if(feof(fp))
+/*27:*/
+#line 452 "./ctie.w"
+
+{
+include_description*temp= inc_desc->parent;
+
+fclose(fp);
+free(inc_desc);
+total_include_files--;
+inp_desc->current_include= temp;
+goto restart;
+}
+
+
+/*:27*/
+#line 432 "./ctie.w"
+
+
+inp_desc->limit= k= inp_desc->buffer;
+while(k<=inp_desc->buffer_end&&(c= getc(fp))!=EOF&&c!='\n')
+if((*(k++)= c)!=' ')inp_desc->limit= k;
+if(k> inp_desc->buffer_end)
+if((c= getc(fp))!=EOF&&c!='\n'){
+ungetc(c,fp);inp_desc->loc= inp_desc->buffer;
+err_print(i,"! Input line too long");
+
+}
+if(c==EOF&&inp_desc->limit==inp_desc->buffer)
+/*27:*/
+#line 452 "./ctie.w"
+
+{
+include_description*temp= inc_desc->parent;
+
+fclose(fp);
+free(inc_desc);
+total_include_files--;
+inp_desc->current_include= temp;
+goto restart;
+}
+
+
+/*:27*/
+#line 444 "./ctie.w"
+
+
+inc_desc->line++;
+}
+
+/*:26*/
+#line 342 "./ctie.w"
+
+}
+else{
+fp= inp_desc->the_file;
+/*22:*/
+#line 366 "./ctie.w"
+
+{
+register int c;
+register char*k;
+
+if(feof(fp))
+/*23:*/
+#line 394 "./ctie.w"
+
+{
+inp_desc->mode= ignore;
+inp_desc->limit= NULL;
+if(inp_desc->type_of_file==master)input_has_ended= true;
+fclose(fp);
+return false;
+}
+
+
+/*:23*/
+#line 372 "./ctie.w"
+
+
+inp_desc->limit= k= inp_desc->buffer;
+while(k<=inp_desc->buffer_end&&(c= getc(fp))!=EOF&&c!='\n')
+if((*(k++)= c)!=' ')inp_desc->limit= k;
+if(k> inp_desc->buffer_end)
+if((c= getc(fp))!=EOF&&c!='\n'){
+ungetc(c,fp);inp_desc->loc= inp_desc->buffer;
+err_print(i,"! Input line too long");
+
+}
+if(c==EOF&&inp_desc->limit==inp_desc->buffer)
+/*23:*/
+#line 394 "./ctie.w"
+
+{
+inp_desc->mode= ignore;
+inp_desc->limit= NULL;
+if(inp_desc->type_of_file==master)input_has_ended= true;
+fclose(fp);
+return false;
+}
+
+
+/*:23*/
+#line 384 "./ctie.w"
+
+
+/*25:*/
+#line 414 "./ctie.w"
+
+inp_desc->line++;
+if(inp_desc->type_of_file==master&&inp_desc->line%100==0){
+if(inp_desc->line%500==0)printf("%ld",inp_desc->line);
+else putchar('.');
+fflush(stdout);
+}
+
+
+/*:25*/
+#line 387 "./ctie.w"
+
+}
+
+
+/*:22*/
+#line 346 "./ctie.w"
+
+}
+
+if(do_includes)
+/*28:*/
+#line 467 "./ctie.w"
+
+{
+inp_desc->loc= inp_desc->buffer;
+*inp_desc->limit= ' ';
+if(*inp_desc->buffer=='@'&&
+(inp_desc->buffer[1]=='i'||inp_desc->buffer[1]=='I')){
+inp_desc->loc= inp_desc->buffer+2;
+*inp_desc->limit= '"';
+while(*inp_desc->loc==' '||*inp_desc->loc=='\t')
+inp_desc->loc++;
+if(inp_desc->loc>=inp_desc->limit){
+err_print(i,"! Include file name not given");
+
+goto restart;
+}
+if(total_include_files>=max_include_files){
+err_print(i,"! Too many nested includes");
+
+goto restart;
+}
+total_include_files++;
+/*29:*/
+#line 507 "./ctie.w"
+
+{
+include_description*new_inc;
+#line 166 "./ctie-k.ch"
+char*file_name_end;
+string fullname;
+char*k;
+#line 514 "./ctie.w"
+
+new_inc= (include_description*)malloc(sizeof(include_description));
+if(new_inc==NULL)
+fatal_error(i,"! No memory for new include descriptor","");
+new_inc->line= 0;
+k= new_inc->file_name;
+file_name_end= k+max_file_name_length-1;
+
+if(*inp_desc->loc=='"'){
+inp_desc->loc++;
+while(*inp_desc->loc!='"'&&k<=file_name_end)
+*k++= *inp_desc->loc++;
+if(inp_desc->loc==inp_desc->limit)
+k= file_name_end+1;
+}else
+while(*inp_desc->loc!=' '&&*inp_desc->loc!='\t'&&
+*inp_desc->loc!='"'&&k<=file_name_end)*k++= *inp_desc->loc++;
+if(k> file_name_end)too_long();
+
+*k= '\0';
+#line 174 "./ctie-k.ch"
+fullname= kpse_find_cweb(new_inc->file_name);
+if(fullname)
+new_inc->the_file= fopen(fullname,"r");
+if(fullname!=NULL&&new_inc->the_file!=NULL){
+free(fullname);
+#line 535 "./ctie.w"
+new_inc->parent= inp_desc->current_include;
+inp_desc->current_include= new_inc;
+goto restart;
+}
+#line 563 "./ctie.w"
+total_include_files--;
+free(new_inc);
+#line 212 "./ctie-k.ch"
+if(fullname){
+free(fullname);
+err_print(i,"! Cannot open include file");
+}else
+err_print(i,"! Cannot find include file");
+#line 566 "./ctie.w"
+
+goto restart;
+}
+
+
+
+/*:29*/
+#line 488 "./ctie.w"
+;
+}
+}
+
+
+/*:28*/
+#line 351 "./ctie.w"
+
+return true;
+}
+
+
+/*:21*//*34:*/
+#line 663 "./ctie.w"
+
+#line 237 "./ctie-k.ch"
+int wrap_up P1H(void)
+#line 665 "./ctie.w"
+{
+/*36:*/
+#line 682 "./ctie.w"
+
+switch(history){
+case spotless:
+printf("\n(No errors were found.)\n");break;
+case troublesome:
+printf("\n(Pardon me, but I think I spotted something wrong.)\n");break;
+case fatal:printf("(That was a fatal error, my friend.)\n");
+}
+
+
+/*:36*/
+#line 666 "./ctie.w"
+;
+if(history> spotless)return 1;
+else return 0;
+}
+
+/*:34*//*44:*/
+#line 791 "./ctie.w"
+
+#line 342 "./ctie-k.ch"
+boolean lines_dont_match P2C(file_index,i,file_index,j)
+#line 794 "./ctie.w"
+{
+register input_description*iptr= input_organisation[i],
+*jptr= input_organisation[j];
+
+if(iptr->limit-iptr->buffer!=jptr->limit-jptr->buffer)
+return true;
+return strncmp(iptr->buffer,jptr->buffer,iptr->limit-iptr->buffer);
+}
+
+
+/*:44*//*45:*/
+#line 808 "./ctie.w"
+
+#line 349 "./ctie-k.ch"
+void init_change_file P1C(file_index,i)
+#line 811 "./ctie.w"
+{
+register input_description*inp_desc= input_organisation[i];
+char ccode;
+
+inp_desc->limit= inp_desc->buffer;
+/*46:*/
+#line 827 "./ctie.w"
+
+while(1){
+if(!get_line(i,false))return;
+if(inp_desc->limit<inp_desc->buffer+2)continue;
+if(inp_desc->buffer[0]!='@')continue;
+ccode= inp_desc->buffer[1];
+if(xisupper(ccode))ccode= tolower(ccode);
+if(ccode=='x')break;
+if(ccode=='y'||ccode=='z'||ccode=='i'){
+inp_desc->loc= inp_desc->buffer+2;
+err_print(i,"! Missing @x in change file");
+
+}
+}
+
+/*:46*/
+#line 816 "./ctie.w"
+
+/*47:*/
+#line 844 "./ctie.w"
+
+do{
+if(!get_line(i,true)){
+err_print(i,"! Change file ended after @x");
+
+return;
+}
+}while(inp_desc->limit==inp_desc->buffer);
+
+
+/*:47*/
+#line 817 "./ctie.w"
+
+inp_desc->dont_match= 0;
+}
+
+
+/*:45*//*48:*/
+#line 857 "./ctie.w"
+
+#line 356 "./ctie-k.ch"
+void put_line P1C(file_index,j)
+#line 860 "./ctie.w"
+{
+char*ptr= input_organisation[j]->buffer;
+char*lmt= input_organisation[j]->limit;
+
+while(ptr<lmt)putc(*ptr++,out_file);
+putc('\n',out_file);
+}
+
+
+/*:48*//*49:*/
+#line 872 "./ctie.w"
+
+#line 363 "./ctie-k.ch"
+boolean e_of_ch_module P1C(file_index,i)
+#line 875 "./ctie.w"
+{
+register input_description*inp_desc= input_organisation[i];
+
+if(inp_desc->limit==NULL){
+err_print(i,"! Change file ended without @z");
+
+return true;
+}else if(inp_desc->limit>=inp_desc->buffer+2)
+if(inp_desc->buffer[0]=='@'&&
+(inp_desc->buffer[1]=='Z'||inp_desc->buffer[1]=='z'))
+return true;
+return false;
+}
+
+
+/*:49*//*50:*/
+#line 893 "./ctie.w"
+
+#line 370 "./ctie-k.ch"
+boolean e_of_ch_preamble P1C(file_index,i)
+#line 896 "./ctie.w"
+{
+register input_description*inp_desc= input_organisation[i];
+
+if(inp_desc->limit>=inp_desc->buffer+2&&inp_desc->buffer[0]=='@')
+if(inp_desc->buffer[1]=='Y'||inp_desc->buffer[1]=='y'){
+if(inp_desc->dont_match> 0){
+inp_desc->loc= inp_desc->buffer+2;
+fprintf(stderr,"\n! Hmm... %d ",inp_desc->dont_match);
+err_print(i,"of the preceding lines failed to match");
+}
+return true;
+}
+return false;
+}
+
+
+
+/*:50*//*61:*/
+#line 1105 "./ctie.w"
+
+#line 376 "./ctie-k.ch"
+void usage_error P1H(void)
+#line 1107 "./ctie.w"
+{
+/*62:*/
+#line 1118 "./ctie.w"
+
+#line 382 "./ctie-k.ch"
+{
+extern KPSEDLL string kpathsea_version_string;
+printf("%s (%s)\n",banner,kpathsea_version_string);
+}
+#line 1120 "./ctie.w"
+printf("%s\n",copyright);
+
+
+/*:62*/
+#line 1108 "./ctie.w"
+;
+fprintf(stderr,"Usage: ctie -[mc] outfile master changefile(s)\n");
+fprintf(stderr,"Type ctie --help for more information\n");
+exit(1);
+}
+
+
+/*:61*/
+#line 95 "./ctie.w"
+
+/*3:*/
+#line 101 "./ctie.w"
+
+#line 32 "./ctie-k.ch"
+int main P2C(int,argc,string*,argv)
+#line 104 "./ctie.w"
+{
+#line 38 "./ctie-k.ch"
+/*5:*/
+#line 84 "./ctie-k.ch"
+
+kpse_set_program_name(argv[0],"ctie");
+
+/*:5*/
+#line 38 "./ctie-k.ch"
+;
+/*19:*/
+#line 300 "./ctie.w"
+
+actual_input= 0;
+out_mode= normal;
+
+/*:19*/
+#line 39 "./ctie-k.ch"
+;
+#line 106 "./ctie.w"
+/*63:*/
+#line 1135 "./ctie.w"
+
+{
+if(argc> max_file_index+5-1)usage_error();
+no_ch= -1;
+while(--argc> 0){
+argv++;
+if(strcmp("-help",*argv)==0||strcmp("--help",*argv)==0)
+/*66:*/
+#line 1202 "./ctie.w"
+
+usage_help();
+
+
+
+/*:66*/
+#line 1142 "./ctie.w"
+;
+if(strcmp("-version",*argv)==0||strcmp("--version",*argv)==0)
+/*67:*/
+#line 1208 "./ctie.w"
+
+{
+print_version_and_exit("CTIE",version_number);
+
+}
+
+
+/*:67*/
+#line 1144 "./ctie.w"
+;
+if(**argv=='-')/*64:*/
+#line 1158 "./ctie.w"
+
+if(prod_chf!=unknown)usage_error();
+else
+switch(*(*argv+1)){
+case'c':case'C':prod_chf= chf;break;
+case'm':case'M':prod_chf= master;break;
+default:usage_error();
+}
+
+
+/*:64*/
+#line 1145 "./ctie.w"
+
+else/*65:*/
+#line 1172 "./ctie.w"
+
+{
+if(no_ch==(-1)){
+out_name= *argv;
+}else{
+register input_description*inp_desc;
+
+inp_desc= (input_description*)malloc(sizeof(input_description));
+if(inp_desc==NULL)
+fatal_error(-1,"! No memory for input descriptor","");
+
+inp_desc->mode= search;
+inp_desc->line= 0;
+inp_desc->type_of_file= chf;
+inp_desc->limit= inp_desc->buffer;
+inp_desc->buffer[0]= ' ';
+inp_desc->loc= inp_desc->buffer+1;
+inp_desc->buffer_end= inp_desc->buffer+buf_size-2;
+inp_desc->file_name= *argv;
+inp_desc->current_include= NULL;
+input_organisation[no_ch]= inp_desc;
+}
+no_ch++;
+}
+
+
+/*:65*/
+#line 1146 "./ctie.w"
+
+}
+if(no_ch<=0||prod_chf==unknown)usage_error();
+}
+
+
+/*:63*/
+#line 106 "./ctie.w"
+
+/*62:*/
+#line 1118 "./ctie.w"
+
+#line 382 "./ctie-k.ch"
+{
+extern KPSEDLL string kpathsea_version_string;
+printf("%s (%s)\n",banner,kpathsea_version_string);
+}
+#line 1120 "./ctie.w"
+printf("%s\n",copyright);
+
+
+/*:62*/
+#line 107 "./ctie.w"
+;
+/*42:*/
+#line 277 "./ctie-k.ch"
+
+{
+string fullname;
+
+fullname= kpse_find_cweb(input_organisation[0]->file_name);
+if(fullname)
+input_organisation[0]->the_file= fopen(fullname,"r");
+
+if(fullname==NULL||input_organisation[0]->the_file==NULL){
+if(fullname){
+pfatal_error("! Cannot open master file ",
+input_organisation[0]->file_name);
+}else{
+fatal_error(-1,"! Cannot find master file ",
+input_organisation[0]->file_name);
+}
+}
+else free(fullname);
+
+
+#line 759 "./ctie.w"
+printf("(%s)\n",input_organisation[0]->file_name);
+input_organisation[0]->type_of_file= master;
+get_line(0,true);
+}
+
+
+/*:42*/
+#line 108 "./ctie.w"
+
+/*43:*/
+#line 313 "./ctie-k.ch"
+
+{
+file_index i;
+string fullname;
+
+i= 1;
+while(i<no_ch){
+fullname= kpse_find_cweb(input_organisation[i]->file_name);
+if(fullname)
+input_organisation[i]->the_file= fopen(fullname,"r");
+
+if(fullname==NULL||input_organisation[i]->the_file==NULL){
+if(fullname){
+pfatal_error("! Cannot open change file ",
+input_organisation[i]->file_name);
+}else{
+fatal_error(-1,"! Cannot find change file ",
+input_organisation[i]->file_name);
+}
+}
+else free(fullname);
+
+
+#line 780 "./ctie.w"
+printf("(%s)\n",input_organisation[i]->file_name);
+init_change_file(i);
+i++;
+}
+}
+
+
+/*:43*/
+#line 109 "./ctie.w"
+
+/*40:*/
+#line 729 "./ctie.w"
+
+{
+out_file= fopen(out_name,"w");
+if(out_file==NULL){
+pfatal_error("! Cannot open/create output file","");
+
+}
+}
+
+
+/*:40*/
+#line 110 "./ctie.w"
+
+/*59:*/
+#line 1074 "./ctie.w"
+
+actual_input= 0;
+input_has_ended= false;
+while(input_has_ended==false||actual_input!=0)
+/*51:*/
+#line 917 "./ctie.w"
+
+{
+file_index test_file;
+
+/*52:*/
+#line 934 "./ctie.w"
+
+{
+register input_description*inp_desc;
+while(actual_input> 0&&e_of_ch_module(actual_input)){
+inp_desc= input_organisation[actual_input];
+if(inp_desc->type_of_file==master){
+
+fatal_error(-1,"! This can't happen: change file is master file","");
+
+}
+inp_desc->mode= search;
+init_change_file(actual_input);
+while((input_organisation[actual_input]->mode!=reading
+&&actual_input> 0))
+actual_input--;
+}
+}
+
+
+/*:52*/
+#line 921 "./ctie.w"
+
+if(input_has_ended&&actual_input==0)break;
+/*53:*/
+#line 960 "./ctie.w"
+
+test_input= none;
+test_file= actual_input;
+while(test_input==none&&test_file<no_ch-1){
+test_file++;
+switch(input_organisation[test_file]->mode){
+case search:
+if(lines_dont_match(actual_input,test_file)==false){
+input_organisation[test_file]->mode= test;
+test_input= test_file;
+}
+break;
+case test:
+if(lines_dont_match(actual_input,test_file)){
+
+input_organisation[test_file]->dont_match++;
+}
+test_input= test_file;
+break;
+case reading:
+break;
+case ignore:
+break;
+}
+}
+
+
+/*:53*/
+#line 923 "./ctie.w"
+
+/*54:*/
+#line 993 "./ctie.w"
+
+if(prod_chf==chf){
+while(1){
+/*55:*/
+#line 1007 "./ctie.w"
+
+if(out_mode==normal){
+if(test_input!=none){
+fprintf(out_file,"@x\n");
+out_mode= pre;
+}else break;
+}
+
+
+/*:55*/
+#line 996 "./ctie.w"
+
+/*56:*/
+#line 1021 "./ctie.w"
+
+if(out_mode==pre){
+if(test_input==none){
+fprintf(out_file,"@y\n");
+out_mode= post;
+}else{
+if(input_organisation[actual_input]->type_of_file==master)
+put_line(actual_input);
+break;
+}
+}
+
+
+/*:56*/
+#line 997 "./ctie.w"
+
+/*57:*/
+#line 1040 "./ctie.w"
+
+if(out_mode==post){
+if(input_organisation[actual_input]->type_of_file==chf){
+if(test_input==none)put_line(actual_input);
+break;
+}else{
+fprintf(out_file,"@z\n\n");
+out_mode= normal;
+}
+}
+
+
+/*:57*/
+#line 998 "./ctie.w"
+
+}
+}else
+if(test_input==none)put_line(actual_input);
+
+
+/*:54*/
+#line 924 "./ctie.w"
+
+/*58:*/
+#line 1055 "./ctie.w"
+
+get_line(actual_input,true);
+if(test_input!=none){
+get_line(test_input,true);
+if(e_of_ch_preamble(test_input)==true){
+get_line(test_input,true);
+input_organisation[test_input]->mode= reading;
+actual_input= test_input;
+test_input= none;
+}
+}
+
+
+/*:58*/
+#line 925 "./ctie.w"
+
+}
+
+
+/*:51*/
+#line 1078 "./ctie.w"
+
+if(out_mode==post)
+fprintf(out_file,"@z\n");
+
+
+/*:59*/
+#line 111 "./ctie.w"
+
+/*60:*/
+#line 1087 "./ctie.w"
+
+{
+file_index i;
+
+for(i= 1;i<no_ch;i++){
+if(input_organisation[i]->mode!=ignore){
+input_organisation[i]->loc= input_organisation[i]->buffer;
+err_print(i,"! Change file entry did not match");
+
+}
+}
+}
+
+
+/*:60*/
+#line 112 "./ctie.w"
+
+exit(wrap_up());
+}
+
+#line 57 "./ctie-k.ch"
+/*:3*/
+#line 96 "./ctie.w"
+
+
+/*:2*//*70:*/
+#line 1237 "./ctie.w"
+
+#line 399 "./ctie-k.ch"
+void usage_help P1H(void)
+#line 1239 "./ctie.w"
+{
+string*message= CTIEHELP;
+
+while(*message){
+fputs(*message,stdout);
+putchar('\n');
+++message;
+}
+putchar('\n');
+exit(0);
+}
+
+
+/*:70*//*71:*/
+#line 1252 "./ctie.w"
+
+#line 416 "./ctie-k.ch"
+void print_version_and_exit P2C(string,name,string,version)
+{
+extern KPSEDLL string kpathsea_version_string;
+printf("%s %s\n",name,version);
+puts(kpathsea_version_string);
+
+puts("Copyright (C) 2002,2003 Julian Gilbey.");
+puts("Kpathsea is copyright (C) 1999 Free Software Foundation, Inc.");
+
+puts("There is NO warranty. This is free software.");
+puts("Redistribution of this software is covered by the terms of");
+puts("both the CTIE copyright and the GNU General Public Licence.");
+puts("For more information about these matters, see the files");
+puts("named COPYING and the CTIE source.");
+puts("Primary authors of CTIE: Julian Gilbey.");
+puts("Kpathsea written by Karl Berry and others.\n");
+
+exit(0);
+}
+#line 1265 "./ctie.w"
+
+
+#line 450 "./ctie-k.ch"
+/*:71*/
diff --git a/web/c_cpp/ctie/ctie-k.ch b/web/c_cpp/ctie/ctie-k.ch
new file mode 100644
index 0000000000..88e8d840b5
--- /dev/null
+++ b/web/c_cpp/ctie/ctie-k.ch
@@ -0,0 +1,461 @@
+% Changes to adapt CTIE to web2c.
+% Copyright 2002,2003 Julian Gilbey
+% All rights reserved.
+%
+% This file is distributed WITHOUT ANY WARRANTY, express or implied.
+%
+% Permission is granted to make and distribute verbatim copies of this
+% file provided that the copyright notice and this permission notice
+% are preserved on all copies.
+%
+% Permission is granted to copy and distribute modified versions of this
+% file 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.
+%
+% This file is based heavily on tie.ch by Olaf Weber to adapt tie.w to
+% the web2c system and on comm-w2c.ch from the Web2C 7.4.5 distribution
+% by Wlodek Bzyl and Olaf Weber.
+
+@x l.19 Add macro definitions
+\def\title{The CTIE processor}
+@y
+\def\Kpathsea/{{\mc KPATHSEA\spacefactor1000}}
+
+\def\title{The CTIE processor}
+@z
+
+@x l.102
+main(argc, argv)
+ int argc; string *argv;
+@y
+int main @,P2C(int, argc, string *, argv)
+@z
+
+@x l.105 Set up kpathsea stuff
+ @<Initialise parameters@>;
+@y
+ @<Set up |PROGNAME| feature and initialize the search path mechanism@>;
+ @<Initialise parameters@>;
+@z
+
+These are defined by kpathsea; we replace this by the path-searching
+initialisation code taken almost verbatim from comm-w2c.ch.
+@x l.116
+@ We include the additional types |boolean| and |string|. \.{CTIE}
+replaces the complex \.{TIE} character set handling (based on that of
+the original \.{WEB} system) with the standard \.{CWEB} behaviour, and
+so uses the |char| type for input and output.
+
+@d false 0
+@d true 1
+
+@<Global types@>=
+typedef int boolean;
+typedef char* string;
+@y
+@ The \.{ctie} program from the original \.{CTIE} package uses the
+compile-time default directory or the value of the environment
+variable \.{CWEBINPUTS} as an alternative place to be searched for
+files, if they could not be found in the current directory.
+
+This version uses the \Kpathsea/ mechanism for searching files.
+The directories to be searched for come from three sources:
+
+ (a)~a user-set environment variable \.{CWEBINPUTS}
+ (overriden by \.{CWEBINPUTS\_ctie});\par
+ (b)~a line in \Kpathsea/ configuration file \.{texmf.cnf},\hfil\break
+ e.g. \.{CWEBINPUTS=.:$TEXMF/texmf/cweb//}
+ or \.{CWEBINPUTS.ctie=.:$TEXMF/texmf/cweb//};\hangindent=2\parindent\par
+ (c)~compile-time default directories \.{.:$TEXMF/texmf/cweb//}
+ (specified in \.{texmf.in}).
+
+@d kpse_find_cweb(name) kpse_find_file(name, kpse_cweb_format, true)
+
+@ The simple file searching is replaced by the `path searching'
+mechanism that the \Kpathsea/ library provides.
+
+We set |kpse_program_name| to |"ctie"|. This means if the variable
+|CWEBINPUTS.ctie| is present in \.{texmf.cnf} (or |CWEBINPUTS_ctie| in
+the environment) its value will be used as the search path for
+filenames. This allows different flawors of \.{CTIE} to have
+different search paths.
+
+@<Set up |PROGNAME| feature and initialize the search path mechanism@>=
+kpse_set_program_name(argv[0], "ctie");
+
+@ We include the additional types |boolean| and |string|. \.{CTIE}
+replaces the complex \.{TIE} character set handling (based on that of
+the original \.{WEB} system) with the standard \.{CWEB} behaviour, and
+so uses the |char| type for input and output.
+
+The |kpathsea| library (version 3.4.5) defines the |true|, |false|,
+|boolean| and |string| types in \.{kpathsea/types.h}, so we do not
+actually need to define them here.
+@z
+
+@x l.129 The kpathsea include files find the right header file for these.
+@ We predeclare some standard string-handling functions here instead of
+including their system header files, because the names of the header files
+are not as standard as the names of the functions. (There's confusion
+between \.{<string.h>} and \.{<strings.h>}.)
+
+@<Predecl...@>=
+extern int strlen(); /* length of string */
+extern char* strcpy(); /* copy one string to another */
+extern int strncmp(); /* compare up to $n$ string characters */
+extern char* strncpy(); /* copy up to $n$ string characters */
+extern char *strerror();
+@y
+@ We don't need to predeclare any string handling functions here, as
+the \.{kpathsea} headers do the right thing.
+@z
+
+@x l.176 And this.
+@ And we need dynamic memory allocation.
+This should cause no trouble in any \CEE/ program.
+@^system dependencies@>
+
+@<Global \&{\#include}s@>=
+#ifdef __STDC__
+#include <stdlib.h>
+#else
+#include <malloc.h>
+#endif
+@y
+@ And we need dynamic memory allocation.
+This should cause no trouble in any \CEE/ program.
+The \.{kpathsea} include files handle the definition of |malloc()|,
+too.
+@^system dependencies@>
+@z
+
+@x l.284 way too short!
+@d max_file_name_length 60
+@y
+@d max_file_name_length 1024
+@z
+
+@x l.329
+boolean get_line(i, do_includes)
+ file_index i; boolean do_includes;
+@y
+boolean get_line @,P2C(file_index, i, boolean, do_includes)
+@z
+
+The next piece is simplified using the kpathsea kpse_find_file
+function.
+
+@x l.497
+If the environment variable \.{CWEBINPUTS} is set, or if the compiler flag
+of the same name was defined at compile time,
+\.{CWEB} will look for include files in the directory thus named, if
+it cannot find them in the current directory.
+(Colon-separated paths are not supported.)
+@y
+We use the \Kpathsea/ library (in particular, the \.{CWEBINPUTS}
+variable) to search for this file.
+@z
+
+@x l.510 Don't need the same variables any longer
+ char temp_file_name[max_file_name_length];
+ char *file_name_end;
+ char *k, *kk;
+ int l; /* length of file name */
+@y
+ char *file_name_end;
+ string fullname;
+ char *k;
+@z
+
+@x l.534 Replace with kpse_find_file
+ if ((new_inc->the_file=fopen(new_inc->file_name, "r"))!=NULL) {
+@y
+ fullname=kpse_find_cweb(new_inc->file_name);
+ if (fullname)
+ new_inc->the_file=fopen(fullname, "r");
+ if (fullname!=NULL && new_inc->the_file!=NULL) {
+ free(fullname);
+@z
+
+@x l.539 And this part is replaced by kpse_find_file
+ kk=getenv("CWEBINPUTS");
+ if (kk!=NULL) {
+ if ((l=strlen(kk))>max_file_name_length-2) too_long();
+ strcpy(temp_file_name, kk);
+ }
+ else {
+#ifdef CWEBINPUTS
+ if ((l=strlen(CWEBINPUTS))>max_file_name_length-2) too_long();
+ strcpy(temp_file_name, CWEBINPUTS);
+#else
+ l=0;
+#endif /* |CWEBINPUTS| */
+ }
+ if (l>0) {
+ if (k+l+2>=file_name_end) too_long();
+ for (; k>= new_inc->file_name; k--) *(k+l+1)=*k;
+ strcpy(new_inc->file_name, temp_file_name);
+ new_inc->file_name[l]='/'; /* \UNIX/ pathname separator */
+ if ((new_inc->the_file=fopen(new_inc->file_name, "r"))!=NULL) {
+ new_inc->parent=inp_desc->current_include; /* link it in */
+ inp_desc->current_include=new_inc;
+ goto restart; /* success */
+ }
+ }
+@y
+@z
+
+@x l.565 slightly more useful error message
+ err_print(i, "! Cannot open include file");
+@y
+ if (fullname) {
+ free(fullname);
+ err_print(i, "! Cannot open include file");
+ } else
+ err_print(i, "! Cannot find include file");
+@z
+
+
+@x l.585
+void err_print();
+@y
+void err_print @,P2H(file_index, char *);
+@z
+
+@x l.590
+void err_print(i, s) /* prints `\..' and location of error message */
+file_index i; char *s;
+@y
+void err_print @,P2C(file_index, i, char *, s)
+/* prints `\..' and location of error message */
+@z
+
+@x l.664
+int wrap_up()
+@y
+int wrap_up @,P1H(void)
+@z
+
+@x l.674
+int wrap_up();
+@y
+int wrap_up @,P1H(void);
+@z
+
+@x l.697
+void pfatal_error();
+@y
+void pfatal_error @,P2H(char *, char *);
+@z
+
+@x l.700
+void pfatal_error(s, t)
+char *s, *t;
+@y
+void pfatal_error @,P2C(char *, s, char *, t)
+@z
+
+@x l.747 Use the kpathsea library to do this
+@ For the master file we start by reading its first line into the
+buffer, if we could open it.
+
+@<Get the master file started@>=
+{
+ input_organisation[0]->the_file=
+ fopen(input_organisation[0]->file_name, "r");
+
+ if (input_organisation[0]->the_file==NULL)
+ pfatal_error("! Cannot open master file ",
+ input_organisation[0]->file_name);
+@.Cannot open master file@>
+@y
+@ For the master file we start by reading its first line into the
+buffer, if we could open it. We use the \.{kpathsea} library to find
+the file.
+
+@<Get the master file started@>=
+{
+ string fullname;
+
+ fullname = kpse_find_cweb(input_organisation[0]->file_name);
+ if (fullname)
+ input_organisation[0]->the_file = fopen(fullname, "r");
+
+ if (fullname==NULL || input_organisation[0]->the_file==NULL) {
+ if (fullname) {
+ pfatal_error("! Cannot open master file ",
+ input_organisation[0]->file_name);
+ } else {
+ fatal_error(-1, "! Cannot find master file ",
+ input_organisation[0]->file_name);
+ }
+ }
+ else free(fullname);
+@.Cannot open master file@>
+@.Cannot find master file@>
+@z
+
+@x l.768 And this
+@<Prepare the change files@>=
+{
+ file_index i;
+
+ i=1;
+ while (i<no_ch) {
+ input_organisation[i]->the_file=
+ fopen(input_organisation[i]->file_name, "r");
+ if (input_organisation[i]->the_file==NULL)
+ pfatal_error("! Cannot open change file ",
+ input_organisation[i]->file_name);
+@.Cannot open change file@>
+@y
+@<Prepare the change files@>=
+{
+ file_index i;
+ string fullname;
+
+ i=1;
+ while (i<no_ch) {
+ fullname = kpse_find_cweb(input_organisation[i]->file_name);
+ if (fullname)
+ input_organisation[i]->the_file = fopen(fullname, "r");
+
+ if (fullname==NULL || input_organisation[i]->the_file==NULL) {
+ if (fullname) {
+ pfatal_error("! Cannot open change file ",
+ input_organisation[i]->file_name);
+ } else {
+ fatal_error(-1, "! Cannot find change file ",
+ input_organisation[i]->file_name);
+ }
+ }
+ else free(fullname);
+@.Cannot open change file@>
+@.Cannot find change file@>
+@z
+
+@x l.792
+boolean lines_dont_match(i, j)
+ file_index i, j;
+@y
+boolean lines_dont_match @,P2C(file_index, i, file_index, j)
+@z
+
+@x l.809
+void init_change_file(i)
+ file_index i;
+@y
+void init_change_file @,P1C(file_index, i)
+@z
+
+@x l.858
+void put_line(j)
+ file_index j;
+@y
+void put_line @,P1C(file_index, j)
+@z
+
+@x l.873
+boolean e_of_ch_module(i)
+ file_index i;
+@y
+boolean e_of_ch_module @,P1C(file_index, i)
+@z
+
+@x l.894
+boolean e_of_ch_preamble(i)
+ file_index i;
+@y
+boolean e_of_ch_preamble @,P1C(file_index, i)
+@z
+
+@x l.1106
+void usage_error()
+@y
+void usage_error @,P1H(void)
+@z
+
+@x l.1119 Add Web2C version to banner string
+printf("%s\n", banner); /* print a ``banner line'' */
+@y
+{
+ extern KPSEDLL string kpathsea_version_string; /* from kpathsea/version.c */
+ printf("%s (%s)\n", banner, kpathsea_version_string); /* print a ``banner line'' */
+}
+@z
+
+@x l.1233
+void usage_help();
+void print_version_and_exit();
+@y
+void usage_help @,P1H(void);
+void print_version_and_exit @,P2H(string, string);
+@z
+
+@x l.1238
+void usage_help()
+@y
+void usage_help @,P1H(void)
+@z
+
+@x l.1253
+void print_version_and_exit(name, version)
+ string name, version;
+{
+ printf ("%s %s\n", name, version);
+
+ puts ("Copyright (C) 2002,2003 Julian Gilbey.");
+
+ puts ("There is NO warranty. This is free software. See the source");
+ puts ("code of CTIE for redistribution conditions.");
+
+ exit (0);
+}
+@y
+void print_version_and_exit @,P2C(string, name, string, version)
+{
+ extern KPSEDLL string kpathsea_version_string; /* from kpathsea/version.c */
+ printf ("%s %s\n", name, version);
+ puts (kpathsea_version_string);
+
+ puts ("Copyright (C) 2002,2003 Julian Gilbey.");
+ puts ("Kpathsea is copyright (C) 1999 Free Software Foundation, Inc.");
+
+ puts ("There is NO warranty. This is free software.");
+ puts ("Redistribution of this software is covered by the terms of");
+ puts ("both the CTIE copyright and the GNU General Public Licence.");
+ puts ("For more information about these matters, see the files");
+ puts ("named COPYING and the CTIE source.");
+ puts ("Primary authors of CTIE: Julian Gilbey.");
+ puts ("Kpathsea written by Karl Berry and others.\n");
+
+ exit (0);
+}
+@z
+
+@x l.1267
+@* System-dependent changes.
+This section should be replaced, if necessary, by
+changes to the program that are necessary to make \.{CTIE}
+work at a particular installation. It is usually best to
+design your change file so that all changes to previous
+modules preserve the module numbering; then everybody's
+version will be consistent with the printed program. More
+extensive changes, which introduce new modules, can be
+inserted here; then only the index itself will get a new
+module number.
+@^system dependencies@>
+@y
+@* System-dependent changes.
+We modify the program to use the \.{kpathsea} library.
+We need to include the headers first.
+
+@<Global \&{\#include}s@>=
+#include <kpathsea/kpathsea.h>
+
+@ A global variable for the file read mode.
+
+@<Global variables@>=
+string file_open_mode;
+@z
diff --git a/web/c_cpp/ctie/ctie.1 b/web/c_cpp/ctie/ctie.1
new file mode 100644
index 0000000000..17f7f1e8c8
--- /dev/null
+++ b/web/c_cpp/ctie/ctie.1
@@ -0,0 +1,58 @@
+.TH TIE 1 20/04/2003
+.SH NAME
+ctie \- merge or apply CWEB change files
+.SH SYNOPSIS
+.B ctie
+.B \-c|\-m
+.I outputfile masterfile changefile1
+[
+.I ... changefile32
+]
+
+.SH DESCRIPTION
+The
+.I CTIE
+program is used to process multiple change files used with the CWEB
+system for literate programming. The CWEB programs allow one to apply
+patches to a source file (the
+.IR masterfile )
+by means of a single change file.
+.I CTIE
+can be used to either merge up to 32 change files into a single one or
+to apply the changes to the
+.I masterfile
+in order to create a new master file. Output of either the new change
+file or the patched master file goes into
+.IR outputfile .
+Any include files (indicated using the CWEB
+.I @i
+command) are fully expanded during
+.I CTIE
+processing, which means that the change files are able to modify the
+contents of any included files. Also, if this program has been
+compiled using the
+.I kpathsea
+library, then files are searched for using the
+.I CWEBINPUTS
+environment variable, as described in the
+.I kpathsea
+documentation.
+.SH OPTIONS
+.TP
+.B \-c
+Create a single change file from the given
+.IR changefiles .
+.TP
+.B \-m
+Create a new master file by applying the given
+.IR changefiles .
+.SH "SEE ALSO"
+.BR cweb (1),
+.IR ctiedoc.tex ,
+.BR tie (1),
+.BR web (1).
+.SH "AUTHOR"
+Julian Gilbey, jdg@debian.org. The original TIE program was by Klaus
+Guntermann, TH Darmstadt, Institut f. Theoretische Informatik. The
+TIE man page was by Joachim Schnitter, TH Darmstadt, Phys. Chemie I,
+and was modified for CTIE by Julian Gilbey.
diff --git a/web/c_cpp/ctie/ctie.c b/web/c_cpp/ctie/ctie.c
new file mode 100644
index 0000000000..840c780014
--- /dev/null
+++ b/web/c_cpp/ctie/ctie.c
@@ -0,0 +1,1111 @@
+#define version_number "1.1"
+#define banner "This is CTIE, Version 1.1"
+#define copyright \
+"Copyright 2002,2003 Julian Gilbey. All rights reserved. There is no warranty.\n\
+Run with the --version option for other important information." \
+ \
+
+#define false 0
+#define true 1 \
+
+#define buf_size 1024
+#define max_file_index 32 \
+
+#define xisupper(c) (isupper(c) &&((unsigned char) c<0200) ) \
+ \
+
+#define spotless 0
+#define troublesome 1
+#define fatal 2 \
+
+#define max_include_files 20 \
+
+#define max_file_name_length 60 \
+
+#define too_long() {total_include_files--;free(new_inc) ; \
+err_print(i,"! Include file name too long") ;goto restart;} \
+
+#define fatal_error(i,s,t) { \
+fprintf(stderr,"\n%s",s) ; \
+err_print(i,t) ; \
+history= fatal; \
+exit(wrap_up() ) ; \
+} \
+ \
+
+#define none (-1) \
+
+/*2:*/
+#line 89 "./ctie.w"
+
+/*8:*/
+#line 172 "./ctie.w"
+
+#include <stdio.h>
+
+
+/*:8*//*9:*/
+#line 180 "./ctie.w"
+
+#ifdef __STDC__
+#include <stdlib.h>
+#else
+#include <malloc.h>
+#endif
+
+
+/*:9*//*37:*/
+#line 715 "./ctie.w"
+
+#include <errno.h>
+
+
+/*:37*/
+#line 90 "./ctie.w"
+
+/*4:*/
+#line 124 "./ctie.w"
+
+typedef int boolean;
+typedef char*string;
+
+
+/*:4*//*10:*/
+#line 211 "./ctie.w"
+
+#define search 0
+#define test 1
+#define reading 2
+#define ignore 3
+typedef int in_file_modes;
+#define unknown 0
+#define master 1
+#define chf 2
+typedef int file_types;
+
+
+/*:10*//*11:*/
+#line 229 "./ctie.w"
+
+#define normal 0
+#define pre 1
+#define post 2
+typedef int out_md_type;
+
+
+/*:11*//*12:*/
+#line 239 "./ctie.w"
+
+typedef int file_index;
+
+
+/*:12*//*13:*/
+#line 246 "./ctie.w"
+
+typedef struct _indsc{
+char file_name[max_file_name_length];
+long line;
+FILE*the_file;
+struct _indsc*parent;
+}include_description;
+
+
+/*:13*//*14:*/
+#line 259 "./ctie.w"
+
+typedef struct _idsc{
+string file_name;
+char buffer[buf_size];
+in_file_modes mode;
+long line;
+file_types type_of_file;
+include_description*current_include;
+char*buffer_end;
+char*limit;
+char*loc;
+FILE*the_file;
+int dont_match;
+}input_description;
+
+
+/*:14*/
+#line 91 "./ctie.w"
+
+/*5:*/
+#line 134 "./ctie.w"
+
+extern int strlen();
+extern char*strcpy();
+extern int strncmp();
+extern char*strncpy();
+extern char*strerror();
+
+
+/*:5*//*28:*/
+#line 584 "./ctie.w"
+
+void err_print();
+
+/*:28*//*33:*/
+#line 673 "./ctie.w"
+
+int wrap_up();
+
+/*:33*//*35:*/
+#line 696 "./ctie.w"
+
+void pfatal_error();
+
+/*:35*//*67:*/
+#line 1232 "./ctie.w"
+
+void usage_help();
+void print_version_and_exit();
+
+
+/*:67*/
+#line 92 "./ctie.w"
+
+/*7:*/
+#line 162 "./ctie.w"
+
+int history= spotless;
+
+
+/*:7*//*15:*/
+#line 286 "./ctie.w"
+
+int total_include_files= 0;
+
+/*:15*//*16:*/
+#line 292 "./ctie.w"
+
+file_index actual_input,test_input,no_ch;
+file_types prod_chf= unknown;
+out_md_type out_mode;
+
+/*:16*//*18:*/
+#line 309 "./ctie.w"
+
+input_description*input_organisation[max_file_index+1];
+
+
+/*:18*//*22:*/
+#line 406 "./ctie.w"
+
+boolean input_has_ended= false;
+
+
+/*:22*//*39:*/
+#line 742 "./ctie.w"
+
+FILE*out_file;
+string out_name;
+
+
+/*:39*//*66:*/
+#line 1217 "./ctie.w"
+
+string CTIEHELP[]= {
+"Usage: ctie -[mc] outfile master changefile(s)",
+" Create a new master file or change file from the given",
+" master (C)WEB file and changefiles.",
+" All filenames are taken literally; no suffixes are added.",
+"",
+"-m create a new master file from original (C)WEB and change file(s)",
+"-c create a master change file for original (C)WEB file from changefile(s)",
+"--help display this help and exit",
+"--version display version information and exit",
+NULL
+};
+
+
+/*:66*/
+#line 93 "./ctie.w"
+
+/*29:*/
+#line 589 "./ctie.w"
+
+void err_print(i,s)
+file_index i;char*s;
+{
+char*k,*l;
+fprintf(stderr,*s=='!'?"\n%s":"%s",s);
+if(i>=0)/*30:*/
+#line 611 "./ctie.w"
+
+{
+register input_description*inp_desc= input_organisation[i];
+register include_description*inc_desc= inp_desc->current_include;
+
+if(inc_desc!=NULL){
+fprintf(stderr,". (l. %ld of include file %s",inc_desc->line,
+inc_desc->file_name);
+fprintf(stderr," included from l. %ld of %s file %s)\n",
+inp_desc->line,
+inp_desc->type_of_file==master?"master":"change",
+inp_desc->file_name);
+}
+else
+fprintf(stderr,". (l. %ld of %s file %s)\n",inp_desc->line,
+inp_desc->type_of_file==master?"master":"change",
+inp_desc->file_name);
+l= (inp_desc->loc>=inp_desc->limit?inp_desc->limit:inp_desc->loc);
+if(l> inp_desc->buffer){
+for(k= inp_desc->buffer;k<l;k++)
+if(*k=='\t')putc(' ',stderr);
+else putc(*k,stderr);
+putc('\n',stderr);
+for(k= inp_desc->buffer;k<l;k++)
+putc(' ',stderr);
+}
+for(k= l;k<inp_desc->limit;k++)
+putc(*k,stderr);
+putc('\n',stderr);
+}
+
+
+/*:30*/
+#line 595 "./ctie.w"
+
+else putc('\n',stderr);
+fflush(stderr);
+history= troublesome;
+}
+
+/*:29*//*36:*/
+#line 699 "./ctie.w"
+
+void pfatal_error(s,t)
+char*s,*t;
+{
+char*strerr= strerror(errno);
+
+fprintf(stderr,"\n%s%s",s,t);
+if(strerr)fprintf(stderr," (%s)\n",strerr);
+else fprintf(stderr,"\n");
+history= fatal;
+exit(wrap_up());
+}
+
+
+/*:36*/
+#line 94 "./ctie.w"
+
+/*19:*/
+#line 328 "./ctie.w"
+
+boolean get_line(i,do_includes)
+file_index i;boolean do_includes;
+{
+register input_description*inp_desc= input_organisation[i];
+register FILE*fp;
+
+if(inp_desc->mode==ignore)return false;
+
+restart:
+if(inp_desc->current_include!=NULL){
+register include_description*inc_desc= inp_desc->current_include;
+
+fp= inc_desc->the_file;
+/*24:*/
+#line 426 "./ctie.w"
+
+{
+register int c;
+register char*k;
+
+if(feof(fp))
+/*25:*/
+#line 452 "./ctie.w"
+
+{
+include_description*temp= inc_desc->parent;
+
+fclose(fp);
+free(inc_desc);
+total_include_files--;
+inp_desc->current_include= temp;
+goto restart;
+}
+
+
+/*:25*/
+#line 432 "./ctie.w"
+
+
+inp_desc->limit= k= inp_desc->buffer;
+while(k<=inp_desc->buffer_end&&(c= getc(fp))!=EOF&&c!='\n')
+if((*(k++)= c)!=' ')inp_desc->limit= k;
+if(k> inp_desc->buffer_end)
+if((c= getc(fp))!=EOF&&c!='\n'){
+ungetc(c,fp);inp_desc->loc= inp_desc->buffer;
+err_print(i,"! Input line too long");
+
+}
+if(c==EOF&&inp_desc->limit==inp_desc->buffer)
+/*25:*/
+#line 452 "./ctie.w"
+
+{
+include_description*temp= inc_desc->parent;
+
+fclose(fp);
+free(inc_desc);
+total_include_files--;
+inp_desc->current_include= temp;
+goto restart;
+}
+
+
+/*:25*/
+#line 444 "./ctie.w"
+
+
+inc_desc->line++;
+}
+
+/*:24*/
+#line 342 "./ctie.w"
+
+}
+else{
+fp= inp_desc->the_file;
+/*20:*/
+#line 366 "./ctie.w"
+
+{
+register int c;
+register char*k;
+
+if(feof(fp))
+/*21:*/
+#line 394 "./ctie.w"
+
+{
+inp_desc->mode= ignore;
+inp_desc->limit= NULL;
+if(inp_desc->type_of_file==master)input_has_ended= true;
+fclose(fp);
+return false;
+}
+
+
+/*:21*/
+#line 372 "./ctie.w"
+
+
+inp_desc->limit= k= inp_desc->buffer;
+while(k<=inp_desc->buffer_end&&(c= getc(fp))!=EOF&&c!='\n')
+if((*(k++)= c)!=' ')inp_desc->limit= k;
+if(k> inp_desc->buffer_end)
+if((c= getc(fp))!=EOF&&c!='\n'){
+ungetc(c,fp);inp_desc->loc= inp_desc->buffer;
+err_print(i,"! Input line too long");
+
+}
+if(c==EOF&&inp_desc->limit==inp_desc->buffer)
+/*21:*/
+#line 394 "./ctie.w"
+
+{
+inp_desc->mode= ignore;
+inp_desc->limit= NULL;
+if(inp_desc->type_of_file==master)input_has_ended= true;
+fclose(fp);
+return false;
+}
+
+
+/*:21*/
+#line 384 "./ctie.w"
+
+
+/*23:*/
+#line 414 "./ctie.w"
+
+inp_desc->line++;
+if(inp_desc->type_of_file==master&&inp_desc->line%100==0){
+if(inp_desc->line%500==0)printf("%ld",inp_desc->line);
+else putchar('.');
+fflush(stdout);
+}
+
+
+/*:23*/
+#line 387 "./ctie.w"
+
+}
+
+
+/*:20*/
+#line 346 "./ctie.w"
+
+}
+
+if(do_includes)
+/*26:*/
+#line 467 "./ctie.w"
+
+{
+inp_desc->loc= inp_desc->buffer;
+*inp_desc->limit= ' ';
+if(*inp_desc->buffer=='@'&&
+(inp_desc->buffer[1]=='i'||inp_desc->buffer[1]=='I')){
+inp_desc->loc= inp_desc->buffer+2;
+*inp_desc->limit= '"';
+while(*inp_desc->loc==' '||*inp_desc->loc=='\t')
+inp_desc->loc++;
+if(inp_desc->loc>=inp_desc->limit){
+err_print(i,"! Include file name not given");
+
+goto restart;
+}
+if(total_include_files>=max_include_files){
+err_print(i,"! Too many nested includes");
+
+goto restart;
+}
+total_include_files++;
+/*27:*/
+#line 507 "./ctie.w"
+
+{
+include_description*new_inc;
+char temp_file_name[max_file_name_length];
+char*file_name_end;
+char*k,*kk;
+int l;
+
+new_inc= (include_description*)malloc(sizeof(include_description));
+if(new_inc==NULL)
+fatal_error(i,"! No memory for new include descriptor","");
+new_inc->line= 0;
+k= new_inc->file_name;
+file_name_end= k+max_file_name_length-1;
+
+if(*inp_desc->loc=='"'){
+inp_desc->loc++;
+while(*inp_desc->loc!='"'&&k<=file_name_end)
+*k++= *inp_desc->loc++;
+if(inp_desc->loc==inp_desc->limit)
+k= file_name_end+1;
+}else
+while(*inp_desc->loc!=' '&&*inp_desc->loc!='\t'&&
+*inp_desc->loc!='"'&&k<=file_name_end)*k++= *inp_desc->loc++;
+if(k> file_name_end)too_long();
+
+*k= '\0';
+if((new_inc->the_file= fopen(new_inc->file_name,"r"))!=NULL){
+new_inc->parent= inp_desc->current_include;
+inp_desc->current_include= new_inc;
+goto restart;
+}
+kk= getenv("CWEBINPUTS");
+if(kk!=NULL){
+if((l= strlen(kk))> max_file_name_length-2)too_long();
+strcpy(temp_file_name,kk);
+}
+else{
+#ifdef CWEBINPUTS
+if((l= strlen(CWEBINPUTS))> max_file_name_length-2)too_long();
+strcpy(temp_file_name,CWEBINPUTS);
+#else
+l= 0;
+#endif
+}
+if(l> 0){
+if(k+l+2>=file_name_end)too_long();
+for(;k>=new_inc->file_name;k--)*(k+l+1)= *k;
+strcpy(new_inc->file_name,temp_file_name);
+new_inc->file_name[l]= '/';
+if((new_inc->the_file= fopen(new_inc->file_name,"r"))!=NULL){
+new_inc->parent= inp_desc->current_include;
+inp_desc->current_include= new_inc;
+goto restart;
+}
+}
+total_include_files--;
+free(new_inc);
+err_print(i,"! Cannot open include file");
+
+goto restart;
+}
+
+
+
+/*:27*/
+#line 488 "./ctie.w"
+;
+}
+}
+
+
+/*:26*/
+#line 351 "./ctie.w"
+
+return true;
+}
+
+
+/*:19*//*32:*/
+#line 663 "./ctie.w"
+
+int wrap_up()
+{
+/*34:*/
+#line 682 "./ctie.w"
+
+switch(history){
+case spotless:
+printf("\n(No errors were found.)\n");break;
+case troublesome:
+printf("\n(Pardon me, but I think I spotted something wrong.)\n");break;
+case fatal:printf("(That was a fatal error, my friend.)\n");
+}
+
+
+/*:34*/
+#line 666 "./ctie.w"
+;
+if(history> spotless)return 1;
+else return 0;
+}
+
+/*:32*//*42:*/
+#line 791 "./ctie.w"
+
+boolean lines_dont_match(i,j)
+file_index i,j;
+{
+register input_description*iptr= input_organisation[i],
+*jptr= input_organisation[j];
+
+if(iptr->limit-iptr->buffer!=jptr->limit-jptr->buffer)
+return true;
+return strncmp(iptr->buffer,jptr->buffer,iptr->limit-iptr->buffer);
+}
+
+
+/*:42*//*43:*/
+#line 808 "./ctie.w"
+
+void init_change_file(i)
+file_index i;
+{
+register input_description*inp_desc= input_organisation[i];
+char ccode;
+
+inp_desc->limit= inp_desc->buffer;
+/*44:*/
+#line 827 "./ctie.w"
+
+while(1){
+if(!get_line(i,false))return;
+if(inp_desc->limit<inp_desc->buffer+2)continue;
+if(inp_desc->buffer[0]!='@')continue;
+ccode= inp_desc->buffer[1];
+if(xisupper(ccode))ccode= tolower(ccode);
+if(ccode=='x')break;
+if(ccode=='y'||ccode=='z'||ccode=='i'){
+inp_desc->loc= inp_desc->buffer+2;
+err_print(i,"! Missing @x in change file");
+
+}
+}
+
+/*:44*/
+#line 816 "./ctie.w"
+
+/*45:*/
+#line 844 "./ctie.w"
+
+do{
+if(!get_line(i,true)){
+err_print(i,"! Change file ended after @x");
+
+return;
+}
+}while(inp_desc->limit==inp_desc->buffer);
+
+
+/*:45*/
+#line 817 "./ctie.w"
+
+inp_desc->dont_match= 0;
+}
+
+
+/*:43*//*46:*/
+#line 857 "./ctie.w"
+
+void put_line(j)
+file_index j;
+{
+char*ptr= input_organisation[j]->buffer;
+char*lmt= input_organisation[j]->limit;
+
+while(ptr<lmt)putc(*ptr++,out_file);
+putc('\n',out_file);
+}
+
+
+/*:46*//*47:*/
+#line 872 "./ctie.w"
+
+boolean e_of_ch_module(i)
+file_index i;
+{
+register input_description*inp_desc= input_organisation[i];
+
+if(inp_desc->limit==NULL){
+err_print(i,"! Change file ended without @z");
+
+return true;
+}else if(inp_desc->limit>=inp_desc->buffer+2)
+if(inp_desc->buffer[0]=='@'&&
+(inp_desc->buffer[1]=='Z'||inp_desc->buffer[1]=='z'))
+return true;
+return false;
+}
+
+
+/*:47*//*48:*/
+#line 893 "./ctie.w"
+
+boolean e_of_ch_preamble(i)
+file_index i;
+{
+register input_description*inp_desc= input_organisation[i];
+
+if(inp_desc->limit>=inp_desc->buffer+2&&inp_desc->buffer[0]=='@')
+if(inp_desc->buffer[1]=='Y'||inp_desc->buffer[1]=='y'){
+if(inp_desc->dont_match> 0){
+inp_desc->loc= inp_desc->buffer+2;
+fprintf(stderr,"\n! Hmm... %d ",inp_desc->dont_match);
+err_print(i,"of the preceding lines failed to match");
+}
+return true;
+}
+return false;
+}
+
+
+
+/*:48*//*59:*/
+#line 1105 "./ctie.w"
+
+void usage_error()
+{
+/*60:*/
+#line 1118 "./ctie.w"
+
+printf("%s\n",banner);
+printf("%s\n",copyright);
+
+
+/*:60*/
+#line 1108 "./ctie.w"
+;
+fprintf(stderr,"Usage: ctie -[mc] outfile master changefile(s)\n");
+fprintf(stderr,"Type ctie --help for more information\n");
+exit(1);
+}
+
+
+/*:59*/
+#line 95 "./ctie.w"
+
+/*3:*/
+#line 101 "./ctie.w"
+
+main(argc,argv)
+int argc;string*argv;
+{
+/*17:*/
+#line 300 "./ctie.w"
+
+actual_input= 0;
+out_mode= normal;
+
+/*:17*/
+#line 105 "./ctie.w"
+;
+/*61:*/
+#line 1135 "./ctie.w"
+
+{
+if(argc> max_file_index+5-1)usage_error();
+no_ch= -1;
+while(--argc> 0){
+argv++;
+if(strcmp("-help",*argv)==0||strcmp("--help",*argv)==0)
+/*64:*/
+#line 1202 "./ctie.w"
+
+usage_help();
+
+
+
+/*:64*/
+#line 1142 "./ctie.w"
+;
+if(strcmp("-version",*argv)==0||strcmp("--version",*argv)==0)
+/*65:*/
+#line 1208 "./ctie.w"
+
+{
+print_version_and_exit("CTIE",version_number);
+
+}
+
+
+/*:65*/
+#line 1144 "./ctie.w"
+;
+if(**argv=='-')/*62:*/
+#line 1158 "./ctie.w"
+
+if(prod_chf!=unknown)usage_error();
+else
+switch(*(*argv+1)){
+case'c':case'C':prod_chf= chf;break;
+case'm':case'M':prod_chf= master;break;
+default:usage_error();
+}
+
+
+/*:62*/
+#line 1145 "./ctie.w"
+
+else/*63:*/
+#line 1172 "./ctie.w"
+
+{
+if(no_ch==(-1)){
+out_name= *argv;
+}else{
+register input_description*inp_desc;
+
+inp_desc= (input_description*)malloc(sizeof(input_description));
+if(inp_desc==NULL)
+fatal_error(-1,"! No memory for input descriptor","");
+
+inp_desc->mode= search;
+inp_desc->line= 0;
+inp_desc->type_of_file= chf;
+inp_desc->limit= inp_desc->buffer;
+inp_desc->buffer[0]= ' ';
+inp_desc->loc= inp_desc->buffer+1;
+inp_desc->buffer_end= inp_desc->buffer+buf_size-2;
+inp_desc->file_name= *argv;
+inp_desc->current_include= NULL;
+input_organisation[no_ch]= inp_desc;
+}
+no_ch++;
+}
+
+
+/*:63*/
+#line 1146 "./ctie.w"
+
+}
+if(no_ch<=0||prod_chf==unknown)usage_error();
+}
+
+
+/*:61*/
+#line 106 "./ctie.w"
+
+/*60:*/
+#line 1118 "./ctie.w"
+
+printf("%s\n",banner);
+printf("%s\n",copyright);
+
+
+/*:60*/
+#line 107 "./ctie.w"
+;
+/*40:*/
+#line 750 "./ctie.w"
+
+{
+input_organisation[0]->the_file=
+fopen(input_organisation[0]->file_name,"r");
+
+if(input_organisation[0]->the_file==NULL)
+pfatal_error("! Cannot open master file ",
+input_organisation[0]->file_name);
+
+printf("(%s)\n",input_organisation[0]->file_name);
+input_organisation[0]->type_of_file= master;
+get_line(0,true);
+}
+
+
+/*:40*/
+#line 108 "./ctie.w"
+
+/*41:*/
+#line 768 "./ctie.w"
+
+{
+file_index i;
+
+i= 1;
+while(i<no_ch){
+input_organisation[i]->the_file=
+fopen(input_organisation[i]->file_name,"r");
+if(input_organisation[i]->the_file==NULL)
+pfatal_error("! Cannot open change file ",
+input_organisation[i]->file_name);
+
+printf("(%s)\n",input_organisation[i]->file_name);
+init_change_file(i);
+i++;
+}
+}
+
+
+/*:41*/
+#line 109 "./ctie.w"
+
+/*38:*/
+#line 729 "./ctie.w"
+
+{
+out_file= fopen(out_name,"w");
+if(out_file==NULL){
+pfatal_error("! Cannot open/create output file","");
+
+}
+}
+
+
+/*:38*/
+#line 110 "./ctie.w"
+
+/*57:*/
+#line 1074 "./ctie.w"
+
+actual_input= 0;
+input_has_ended= false;
+while(input_has_ended==false||actual_input!=0)
+/*49:*/
+#line 917 "./ctie.w"
+
+{
+file_index test_file;
+
+/*50:*/
+#line 934 "./ctie.w"
+
+{
+register input_description*inp_desc;
+while(actual_input> 0&&e_of_ch_module(actual_input)){
+inp_desc= input_organisation[actual_input];
+if(inp_desc->type_of_file==master){
+
+fatal_error(-1,"! This can't happen: change file is master file","");
+
+}
+inp_desc->mode= search;
+init_change_file(actual_input);
+while((input_organisation[actual_input]->mode!=reading
+&&actual_input> 0))
+actual_input--;
+}
+}
+
+
+/*:50*/
+#line 921 "./ctie.w"
+
+if(input_has_ended&&actual_input==0)break;
+/*51:*/
+#line 960 "./ctie.w"
+
+test_input= none;
+test_file= actual_input;
+while(test_input==none&&test_file<no_ch-1){
+test_file++;
+switch(input_organisation[test_file]->mode){
+case search:
+if(lines_dont_match(actual_input,test_file)==false){
+input_organisation[test_file]->mode= test;
+test_input= test_file;
+}
+break;
+case test:
+if(lines_dont_match(actual_input,test_file)){
+
+input_organisation[test_file]->dont_match++;
+}
+test_input= test_file;
+break;
+case reading:
+break;
+case ignore:
+break;
+}
+}
+
+
+/*:51*/
+#line 923 "./ctie.w"
+
+/*52:*/
+#line 993 "./ctie.w"
+
+if(prod_chf==chf){
+while(1){
+/*53:*/
+#line 1007 "./ctie.w"
+
+if(out_mode==normal){
+if(test_input!=none){
+fprintf(out_file,"@x\n");
+out_mode= pre;
+}else break;
+}
+
+
+/*:53*/
+#line 996 "./ctie.w"
+
+/*54:*/
+#line 1021 "./ctie.w"
+
+if(out_mode==pre){
+if(test_input==none){
+fprintf(out_file,"@y\n");
+out_mode= post;
+}else{
+if(input_organisation[actual_input]->type_of_file==master)
+put_line(actual_input);
+break;
+}
+}
+
+
+/*:54*/
+#line 997 "./ctie.w"
+
+/*55:*/
+#line 1040 "./ctie.w"
+
+if(out_mode==post){
+if(input_organisation[actual_input]->type_of_file==chf){
+if(test_input==none)put_line(actual_input);
+break;
+}else{
+fprintf(out_file,"@z\n\n");
+out_mode= normal;
+}
+}
+
+
+/*:55*/
+#line 998 "./ctie.w"
+
+}
+}else
+if(test_input==none)put_line(actual_input);
+
+
+/*:52*/
+#line 924 "./ctie.w"
+
+/*56:*/
+#line 1055 "./ctie.w"
+
+get_line(actual_input,true);
+if(test_input!=none){
+get_line(test_input,true);
+if(e_of_ch_preamble(test_input)==true){
+get_line(test_input,true);
+input_organisation[test_input]->mode= reading;
+actual_input= test_input;
+test_input= none;
+}
+}
+
+
+/*:56*/
+#line 925 "./ctie.w"
+
+}
+
+
+/*:49*/
+#line 1078 "./ctie.w"
+
+if(out_mode==post)
+fprintf(out_file,"@z\n");
+
+
+/*:57*/
+#line 111 "./ctie.w"
+
+/*58:*/
+#line 1087 "./ctie.w"
+
+{
+file_index i;
+
+for(i= 1;i<no_ch;i++){
+if(input_organisation[i]->mode!=ignore){
+input_organisation[i]->loc= input_organisation[i]->buffer;
+err_print(i,"! Change file entry did not match");
+
+}
+}
+}
+
+
+/*:58*/
+#line 112 "./ctie.w"
+
+exit(wrap_up());
+}
+
+/*:3*/
+#line 96 "./ctie.w"
+
+
+/*:2*//*68:*/
+#line 1237 "./ctie.w"
+
+void usage_help()
+{
+string*message= CTIEHELP;
+
+while(*message){
+fputs(*message,stdout);
+putchar('\n');
+++message;
+}
+putchar('\n');
+exit(0);
+}
+
+
+/*:68*//*69:*/
+#line 1252 "./ctie.w"
+
+void print_version_and_exit(name,version)
+string name,version;
+{
+printf("%s %s\n",name,version);
+
+puts("Copyright (C) 2002,2003 Julian Gilbey.");
+
+puts("There is NO warranty. This is free software. See the source");
+puts("code of CTIE for redistribution conditions.");
+
+exit(0);
+}
+
+
+/*:69*/
diff --git a/web/c_cpp/ctie/ctie.cf1 b/web/c_cpp/ctie/ctie.cf1
new file mode 100644
index 0000000000..5b1165435c
--- /dev/null
+++ b/web/c_cpp/ctie/ctie.cf1
@@ -0,0 +1,14 @@
+@x
+line 2
+line 3
+@y
+changed line 2
+changed line 3
+inserted line
+@z
+
+@x
+line 7
+@y
+changed line 7
+@z
diff --git a/web/c_cpp/ctie/ctie.cf2 b/web/c_cpp/ctie/ctie.cf2
new file mode 100644
index 0000000000..d9a5fbaf67
--- /dev/null
+++ b/web/c_cpp/ctie/ctie.cf2
@@ -0,0 +1,26 @@
+@x
+line 1
+changed line 2
+changed line 3
+inserted line
+line 4
+@y
+final line 2
+final line 3
+changed line 4
+@z
+
+@x
+include line 1
+@y
+changed include line 1
+inserted include line
+@z
+
+@x
+changed line 7
+line 8
+@y
+final line 7
+final line 8
+@z
diff --git a/web/c_cpp/ctie/ctie.cf3 b/web/c_cpp/ctie/ctie.cf3
new file mode 100644
index 0000000000..95c7ff6353
--- /dev/null
+++ b/web/c_cpp/ctie/ctie.cf3
@@ -0,0 +1,13 @@
+@x
+changed line 4
+@y
+final line 4
+@z
+
+@x
+changed include line 1
+inserted include line
+@y
+final include line 1
+@i ctie.inc2
+@z
diff --git a/web/c_cpp/ctie/ctie.chf.gen b/web/c_cpp/ctie/ctie.chf.gen
new file mode 100644
index 0000000000..d07e9280c0
--- /dev/null
+++ b/web/c_cpp/ctie/ctie.chf.gen
@@ -0,0 +1,26 @@
+@x
+line 1
+line 2
+line 3
+line 4
+@y
+final line 2
+final line 3
+final line 4
+@z
+
+@x
+include line 1
+@y
+final include line 1
+final inserted include line
+@z
+
+@x
+line 7
+line 8
+@y
+final line 7
+final line 8
+@z
+
diff --git a/web/c_cpp/ctie/ctie.inc b/web/c_cpp/ctie/ctie.inc
new file mode 100644
index 0000000000..435c17d8a1
--- /dev/null
+++ b/web/c_cpp/ctie/ctie.inc
@@ -0,0 +1,4 @@
+include line 1
+include line 2
+@i ctie.inc1
+include line 3
diff --git a/web/c_cpp/ctie/ctie.inc1 b/web/c_cpp/ctie/ctie.inc1
new file mode 100644
index 0000000000..79b0114e1e
--- /dev/null
+++ b/web/c_cpp/ctie/ctie.inc1
@@ -0,0 +1 @@
+included include line
diff --git a/web/c_cpp/ctie/ctie.inc2 b/web/c_cpp/ctie/ctie.inc2
new file mode 100644
index 0000000000..bb83f8a671
--- /dev/null
+++ b/web/c_cpp/ctie/ctie.inc2
@@ -0,0 +1 @@
+final inserted include line
diff --git a/web/c_cpp/ctie/ctie.master.gen b/web/c_cpp/ctie/ctie.master.gen
new file mode 100644
index 0000000000..4c00f38314
--- /dev/null
+++ b/web/c_cpp/ctie/ctie.master.gen
@@ -0,0 +1,19 @@
+final line 2
+final line 3
+final line 4
+line 5
+final include line 1
+final inserted include line
+include line 2
+included include line
+include line 3
+line 6
+final line 7
+final line 8
+line 9
+line 10
+The character set:
+abcdefghijklmnopqrstuvwxyz
+ABCDEFGHIJKLMNOPQRSTUVWXYZ
+=!"#$%&/()?'`^~|-+[]{}@\;:
+ 0123456789<>.,*_
diff --git a/web/c_cpp/ctie/ctie.tie b/web/c_cpp/ctie/ctie.tie
new file mode 100644
index 0000000000..649b26d551
--- /dev/null
+++ b/web/c_cpp/ctie/ctie.tie
@@ -0,0 +1,16 @@
+line 1
+line 2
+line 3
+line 4
+line 5
+@i "ctie.inc"
+line 6
+line 7
+line 8
+line 9
+line 10
+The character set:
+abcdefghijklmnopqrstuvwxyz
+ABCDEFGHIJKLMNOPQRSTUVWXYZ
+=!"#$%&/()?'`^~|-+[]{}@\;:
+ 0123456789<>.,*_
diff --git a/web/c_cpp/ctie/ctie.w b/web/c_cpp/ctie/ctie.w
new file mode 100644
index 0000000000..33abf6312c
--- /dev/null
+++ b/web/c_cpp/ctie/ctie.w
@@ -0,0 +1,1280 @@
+% This is ctie.w
+% Copyright (c) 2002,2003 by Julian Gilbey
+% All rights reserved.
+%
+% This program is distributed WITHOUT ANY WARRANTY, express or implied.
+%
+% Permission is granted to make and distribute verbatim copies of this
+% program provided that the copyright notice and this permission notice
+% are preserved on all copies.
+%
+% Permission is granted to copy and distribute modified versions of this
+% program 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.
+%
+% This program is based heavily on tie.w and common.w, part of the
+% CWEB source.
+
+\def\title{The CTIE processor}
+\def\botofcontents{%
+\vfill
+$\copyright$ 2002,2003 Julian Gilbey
+
+All rights reserved.
+
+This program is distributed WITHOUT ANY WARRANTY, express or implied.
+
+Permission is granted to make and distribute verbatim copies of this
+program provided that the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+program 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.
+}
+
+
+@* Introduction.
+Whenever a programmer wants to change a given \.{WEB} or \.{CWEB}
+program (referred to as a \.{WEB} program throughout this program)
+because of system dependencies, she or he will create a new change
+file. In addition there may be a second change file to modify system
+independent modules of the program. But the \.{WEB} file cannot be
+tangled and weaved with more than one change file simultaneously.
+The \.{TIE} program was designed to merge a \.{WEB} file
+and several change files producing a new \.{WEB} file, and since the
+input files are tied together, the program was called \.{TIE}.
+Furthermore, the program could be used to merge several change files
+giving a new single change file. This method seems to be more
+important because it doesn't modify the original source file.
+
+However, the introduction of \.{CWEB} has meant that \.{TIE} is not
+quite able to perform its task correctly any longer: \.{CWEB}
+introduced the idea of include files, which are input into \.{CWEB}
+files using the \.{@@i} command, and \.{TIE} is unable to handle such
+constructs if the change files modify lines included in those files.
+The present program, \.{CTIE}, is designed to overcome this lack.
+Like \.{TIE}, upon which it is based, it can either output a single
+master \.{WEB} file or a master change file. However, in both cases,
+any include commands will be totally expanded and the files included
+in the output rather than the \.{@@i} commands being left; this makes
+this code feasible, which it would not necessarily be otherwise.
+Other than this difference, \.{CTIE} should function identically to
+\.{TIE} on files which do not involve any \.{CWEB} include commands.
+
+The algorithm used is essentially the same as that of \.{TIE}, with
+modifications to check for and handle \.{@@i} commands. Thus, as with
+\.{TIE}, the method used only needs one buffer line for each input
+file. Thus the storage requirement of \.{CTIE} does not depend on the
+sizes of the input files but only on their number.
+
+The program is written in \CEE/ and has few system dependencies.
+
+The ``banner line'' defined here should be changed whenever
+\.{CTIE} is modified. We also keep the version number here separately
+for ease; it is used below.
+
+@d version_number "1.1"
+@d banner "This is CTIE, Version 1.1"
+@d copyright
+ "Copyright 2002,2003 Julian Gilbey. All rights reserved. There is no warranty.\n\
+Run with the --version option for other important information."
+
+
+@ The main outline of the program is now given.
+This can be used more or less for any \CEE/ program.
+
+@c
+@<Global \&{\#include}s@>@;
+@<Global types@>@;
+@<Predeclaration of functions@>@;
+@<Global variables@>@;
+@<Error handling functions@>@;
+@<Internal functions@>@;
+@<The main function@>@;
+
+@ And this is the structure of the |main| function: this is where
+\.{CTIE} starts, and where it ends.
+
+@<The main function@>=
+main(argc, argv)
+ int argc; string *argv;
+{
+ @<Initialise parameters@>;
+ @<Scan the parameters@>@;
+ @<Print the banners@>;
+ @<Get the master file started@>@;
+ @<Prepare the change files@>@;
+ @<Prepare the output file@>@;
+ @<Process the input@>@;
+ @<Check that all changes have been read@>@;
+ exit(wrap_up());
+}
+
+@ We include the additional types |boolean| and |string|. \.{CTIE}
+replaces the complex \.{TIE} character set handling (based on that of
+the original \.{WEB} system) with the standard \.{CWEB} behaviour, and
+so uses the |char| type for input and output.
+
+@d false 0
+@d true 1
+
+@<Global types@>=
+typedef int boolean;
+typedef char* string;
+
+
+@ We predeclare some standard string-handling functions here instead of
+including their system header files, because the names of the header files
+are not as standard as the names of the functions. (There's confusion
+between \.{<string.h>} and \.{<strings.h>}.)
+
+@<Predecl...@>=
+extern int strlen(); /* length of string */
+extern char* strcpy(); /* copy one string to another */
+extern int strncmp(); /* compare up to $n$ string characters */
+extern char* strncpy(); /* copy up to $n$ string characters */
+extern char *strerror();
+
+
+@ The following parameters should be sufficient for most
+applications of \.{CTIE}.
+@^system dependencies@>
+
+@d buf_size 1024 /* maximum length of one input line */
+@d max_file_index 32
+/* we don't think that anyone needs more than 32 change files */
+@d xisupper(c) (isupper(c)&&((unsigned char)c<0200))
+
+
+@ We introduce a history variable that allows us to set a
+return code if the operating system can use it.
+First we introduce the coded values for the history.
+This variable must be initialized.
+(We do this even if the value given may be the default for
+variables, just to document the need for the initial value.)
+@d spotless 0
+@d troublesome 1
+@d fatal 2
+
+@<Global variables@>=
+int history=spotless;
+
+
+@* Input and output.
+Standard output for the user is done by writing on |stdout|. Error
+messages are written to |stderr|. Terminal input is not needed in
+this version of \.{CTIE}. |stdin|, |stdout| and |stderr| are
+predefined as we include the \.{stdio.h} definitions.
+
+@<Global \&{\#include}s@>=
+#include <stdio.h>
+
+
+@ And we need dynamic memory allocation.
+This should cause no trouble in any \CEE/ program.
+@^system dependencies@>
+
+@<Global \&{\#include}s@>=
+#ifdef __STDC__
+#include <stdlib.h>
+#else
+#include <malloc.h>
+#endif
+
+
+@* Data structures.
+The multiple primary input files (master file and change
+files) are treated the same way. To organize the
+simultaneous usage of several input files, we introduce the
+data type \&{in\_file\_modes}.
+
+The mode |search| indicates that \.{CTIE} searches for a
+match of the input line with any line of an input file in
+|reading| mode. |test| is used whenever a match is found
+and it has to be tested if the next input lines do match
+also. |reading| describes that the lines can be read without
+any check for matching other lines. |ignore| denotes
+that the file cannot be used. This may happen because an
+error has been detected or because the end of the file has
+been found.
+
+\leavevmode |file_types| is used to describe whether a file
+is a master file or a change file. The value |unknown| is added
+to this type to set an initial mode for the output file.
+This enables us to check whether any option was used to select
+the kind of output. (this would even be necessary if we
+would assume a default action for missing options.)
+
+@<Global types@>=
+#define search 0
+#define test 1
+#define reading 2
+#define ignore 3
+typedef int in_file_modes; /* should be |enum(search, test, reading, ignore)| */
+#define unknown 0
+#define master 1
+#define chf 2
+typedef int file_types; /* should be |enum(unknown, master, chf)| */
+
+
+@ A variable of type |out_md_type| will tell us in what state the output
+change file is during processing. |normal| will be the state, when we
+did not yet start a change, |pre| will be set when we write the lines
+to be changes and |post| will indicate that the replacement lines are
+written.
+
+@<Global types@>=
+#define normal 0
+#define pre 1
+#define post 2
+typedef int out_md_type; /* should be |enum(normal, pre, post)| */
+
+
+@ The next type will indicate variables used as an index into the file
+table.
+
+@<Global types@>=
+typedef int file_index; /* |-1..max_file_index+1| */
+
+
+@ This is the data structure in which we collect information about
+each include file.
+
+@<Global types@>=
+typedef struct _indsc {
+ char file_name[max_file_name_length];
+ long line;
+ FILE *the_file;
+ struct _indsc *parent;
+} include_description;
+
+
+@ The following data structure contains all of the information needed
+to use these input files.
+%`line' is a normal identifier throughout this program
+@f line dummy
+@<Global types@>=
+typedef struct _idsc{
+ string file_name;
+ char buffer[buf_size];
+ in_file_modes mode;
+ long line;
+ file_types type_of_file;
+ include_description *current_include;
+ char *buffer_end;
+ char *limit;
+ char *loc;
+ FILE *the_file;
+ int dont_match;
+ } input_description;
+
+
+@ Every one of the primary input files might include another file
+using the \.{@@i} include mechanism. In turn, each of these might
+include other files, and so on. We allow a limited number of these
+files to be opened simultaneously, and we store information about the
+currently open include files as a linked list attached to each primary
+file.
+
+@d max_include_files 20
+ /* maximum number of include files open simultaneously */
+@d max_file_name_length 60
+
+@<Global variables@>=
+int total_include_files = 0; /* count 'em */
+
+@ The following variables refer to the files in action, the number of
+change files, the mode of operation and the current output state.
+
+@<Global variables@>=
+file_index actual_input, test_input, no_ch;
+file_types prod_chf=unknown;
+out_md_type out_mode;
+
+@ And the |actual_input| and |out_mode| variables need to be
+initialised sensibly.
+
+@<Initialise parameters@>=
+actual_input=0;
+out_mode=normal;
+
+@ All primary input files (including the master file) are recorded
+in the following structure.
+The components are usually accessed through a local pointer variable,
+requiring only a one-time-computation of the index expression.
+
+@<Global variables@>=
+input_description *input_organisation[max_file_index+1];
+
+
+@* File I/O.
+The basic function |get_line| can be used to get a line from
+an input file. The line is stored in the |buffer| part of the
+descriptor. The components |limit| and |line| are updated. If the
+end of the file is reached |mode| is set to |ignore|. On some systems
+it might be useful to replace tab characters by a proper number of
+spaces since several editors used to create change files insert tab
+characters into a source file not under control of the user. So it
+might be a problem to create a matching change file.
+@^tab character expansion@>
+
+We define |get_line| to read a line from a file specified by the
+corresponding file descriptor. This function returns |true| if it is
+successful and |false| if the end of the file has been reached.
+
+@<Internal functions@>=
+boolean get_line(i, do_includes)
+ file_index i; boolean do_includes;
+{
+ register input_description *inp_desc=input_organisation[i];
+ register FILE *fp;
+
+ if (inp_desc->mode==ignore) return false;
+
+ restart:
+ if (inp_desc->current_include != NULL) {
+ register include_description *inc_desc=inp_desc->current_include;
+
+ fp=inc_desc->the_file;
+ @<Get include line into buffer or |goto restart| if end of file@>@;
+ }
+ else {
+ fp=inp_desc->the_file;
+ @<Get line into buffer, |return false| if end of file@>@;
+ }
+
+ if (do_includes)
+ @<Check for \.{@@i} in newly read line, |goto restart| if
+ include fails@>@;
+ return true;
+}
+
+
+@ Lines must fit into the buffer completely.
+We read all characters sequentially until an end of line is found
+(but do not forget to check for |EOF|!).
+Too long input lines will be truncated.
+This will result in a damaged output if they occur in the
+replacement part of a change file, or in an incomplerte check if the
+matching part is concerned.
+Tab character expansion might be done here.
+@^tab character expansion@>
+
+@<Get line into buffer,...@>=
+{
+ register int c; /* the actual character read */
+ register char *k; /* where the next character goes */
+
+ if (feof(fp))
+ @<Handle end of file and return@>@;
+
+ inp_desc->limit = k = inp_desc->buffer; /* beginning of buffer */
+ while (k<=inp_desc->buffer_end && (c=getc(fp)) != EOF && c!='\n')
+ if ((*(k++) = c) != ' ') inp_desc->limit = k;
+ if (k>inp_desc->buffer_end)
+ if ((c=getc(fp))!=EOF && c!='\n') {
+ ungetc(c, fp); inp_desc->loc=inp_desc->buffer;
+ err_print(i, "! Input line too long");
+@.Input line too long@>
+ }
+ if (c==EOF && inp_desc->limit==inp_desc->buffer)
+ @<Handle end of file...@>@;
+
+ @<Increment the line number and print a progess report at
+ certain times@>@;
+}
+
+
+@ End of file is special if this file is the master file.
+Then we set the global flag variable |input_has_ended|.
+
+@<Handle end of file ...@>=
+{
+ inp_desc->mode=ignore;
+ inp_desc->limit=NULL; /* mark end-of-file */
+ if (inp_desc->type_of_file==master) input_has_ended=true;
+ fclose(fp);
+ return false;
+}
+
+
+@ This variable must be declared for global access.
+
+@<Global variables@>=
+boolean input_has_ended=false;
+
+
+@ This section does what its name says. Every 100 lines
+in the master file we print a dot, every 500 lines the number
+of lines is shown.
+
+@<Increment the line number and print ...@>=
+inp_desc->line++;
+if (inp_desc->type_of_file==master && inp_desc->line % 100==0) {
+ if (inp_desc->line % 500 == 0) printf("%ld", inp_desc->line);
+ else putchar('.');
+ fflush(stdout);
+}
+
+
+@ The following is very similar to the above, but for the case where
+we are reading from an include file.
+
+@<Get include line into buffer or |goto restart| if end of file@>=
+{
+ register int c; /* the actual character read */
+ register char *k; /* where the next character goes */
+
+ if (feof(fp))
+ @<Handle end of include file and |goto restart|@>@;
+
+ inp_desc->limit = k = inp_desc->buffer; /* beginning of buffer */
+ while (k<=inp_desc->buffer_end && (c=getc(fp)) != EOF && c!='\n')
+ if ((*(k++) = c) != ' ') inp_desc->limit = k;
+ if (k>inp_desc->buffer_end)
+ if ((c=getc(fp))!=EOF && c!='\n') {
+ ungetc(c, fp); inp_desc->loc=inp_desc->buffer;
+ err_print(i, "! Input line too long");
+@.Input line too long@>
+ }
+ if (c==EOF && inp_desc->limit==inp_desc->buffer)
+ @<Handle end of include file...@>@;
+
+ inc_desc->line++;
+}
+
+@ We don't bail out if we find the end of an include file, we just
+return to the parent file.
+
+@<Handle end of include file and |goto restart|@>=
+{
+ include_description *temp=inc_desc->parent;
+
+ fclose(fp);
+ free(inc_desc);
+ total_include_files--;
+ inp_desc->current_include=temp;
+ goto restart;
+}
+
+
+@ Usually, we have to check the line we have just read to see whether
+it begins with \.{@@i} and therefore needs expanding.
+
+@<Check for \.{@@i} in newly read line...@>=
+{
+ inp_desc->loc=inp_desc->buffer;
+ *inp_desc->limit=' ';
+ if (*inp_desc->buffer=='@@' &&
+ (inp_desc->buffer[1]=='i' || inp_desc->buffer[1]=='I')) {
+ inp_desc->loc=inp_desc->buffer+2;
+ *inp_desc->limit='"'; /* this will terminate the search in all cases */
+ while (*inp_desc->loc==' '||*inp_desc->loc=='\t')
+ inp_desc->loc++;
+ if (inp_desc->loc>=inp_desc->limit) {
+ err_print(i, "! Include file name not given");
+@.Include file name ...@>
+ goto restart;
+ }
+ if (total_include_files>=max_include_files) {
+ err_print(i, "! Too many nested includes");
+@.Too many nested includes@>
+ goto restart;
+ }
+ total_include_files++; /* push input stack */
+ @<Try to open include file, abort push if unsuccessful, go to |restart|@>;
+ }
+}
+
+
+@ When an \.{@@i} line is found in the file, we must temporarily
+stop reading it and start reading from the named include file. The
+\.{@@i} line should give a complete file name with or without
+double quotes.
+If the environment variable \.{CWEBINPUTS} is set, or if the compiler flag
+of the same name was defined at compile time,
+\.{CWEB} will look for include files in the directory thus named, if
+it cannot find them in the current directory.
+(Colon-separated paths are not supported.)
+The remainder of the \.{@@i} line after the file name is ignored.
+
+@d too_long() {total_include_files--; free(new_inc);
+ err_print(i, "! Include file name too long"); goto restart;}
+
+@<Try to open...@>=
+{
+ include_description *new_inc;
+ char temp_file_name[max_file_name_length];
+ char *file_name_end;
+ char *k, *kk;
+ int l; /* length of file name */
+
+ new_inc=(include_description *) malloc(sizeof(include_description));
+ if (new_inc==NULL)
+ fatal_error(i, "! No memory for new include descriptor", "");
+ new_inc->line=0;
+ k=new_inc->file_name;
+ file_name_end=k+max_file_name_length-1;
+
+ if (*inp_desc->loc=='"') {
+ inp_desc->loc++;
+ while (*inp_desc->loc!='"' && k<=file_name_end)
+ *k++=*inp_desc->loc++;
+ if (inp_desc->loc==inp_desc->limit)
+ k=file_name_end+1; /* unmatched quote is `too long' */
+ } else
+ while (*inp_desc->loc!=' '&&*inp_desc->loc!='\t'&&
+ *inp_desc->loc!='"'&&k<=file_name_end) *k++=*inp_desc->loc++;
+ if (k>file_name_end) too_long();
+@.Include file name ...@>
+ *k='\0';
+ if ((new_inc->the_file=fopen(new_inc->file_name, "r"))!=NULL) {
+ new_inc->parent=inp_desc->current_include; /* link it in */
+ inp_desc->current_include=new_inc;
+ goto restart; /* success */
+ }
+ kk=getenv("CWEBINPUTS");
+ if (kk!=NULL) {
+ if ((l=strlen(kk))>max_file_name_length-2) too_long();
+ strcpy(temp_file_name, kk);
+ }
+ else {
+#ifdef CWEBINPUTS
+ if ((l=strlen(CWEBINPUTS))>max_file_name_length-2) too_long();
+ strcpy(temp_file_name, CWEBINPUTS);
+#else
+ l=0;
+#endif /* |CWEBINPUTS| */
+ }
+ if (l>0) {
+ if (k+l+2>=file_name_end) too_long();
+ for (; k>= new_inc->file_name; k--) *(k+l+1)=*k;
+ strcpy(new_inc->file_name, temp_file_name);
+ new_inc->file_name[l]='/'; /* \UNIX/ pathname separator */
+ if ((new_inc->the_file=fopen(new_inc->file_name, "r"))!=NULL) {
+ new_inc->parent=inp_desc->current_include; /* link it in */
+ inp_desc->current_include=new_inc;
+ goto restart; /* success */
+ }
+ }
+ total_include_files--;
+ free(new_inc);
+ err_print(i, "! Cannot open include file");
+@.Cannot open include file@>
+ goto restart;
+}
+
+
+
+@* Reporting errors to the user.
+There may be errors if a line in a given change
+file does not match a line in the master file or a
+replacement in a previous change file. Such errors are
+reported to the user by saying
+$$
+ \hbox{|err_print(file_no, "! Error message")|;}
+$$
+where |file_no| is the number of the file which is concerned by the
+error. Please note that no trailing dot is supplied in the error
+message because it is appended by |err_print|.
+
+@<Predecl...@>=
+void err_print();
+
+@ Here is the outline of the |err_print| function.
+
+@<Error handling...@>=
+void err_print(i, s) /* prints `\..' and location of error message */
+file_index i; char *s;
+{
+ char *k, *l; /* pointers into an appropriate |buffer| */
+ fprintf(stderr, *s=='!'? "\n%s" : "%s", s);
+ if(i>=0) @<Print error location based on input buffer@>@;
+ else putc('\n', stderr);
+ fflush(stderr);
+ history=troublesome;
+}
+
+@ The error locations can be indicated by using the variables
+|loc|, |line| and |file_name| within the appropriate file description
+structures, which tell respectively the first
+unlooked-at position in the |buffer|, the current line number and the
+current file. We can determine whether we are looking at an included
+file or not by examining the |current_include| variable.
+This routine should be modified on systems whose standard text editor
+has special line-numbering conventions.
+@^system dependencies@>
+
+@<Print error location based on input buffer@>=
+{
+ register input_description *inp_desc=input_organisation[i];
+ register include_description *inc_desc=inp_desc->current_include;
+
+ if (inc_desc!=NULL) {
+ fprintf(stderr, ". (l. %ld of include file %s", inc_desc->line,
+ inc_desc->file_name);
+ fprintf(stderr, " included from l. %ld of %s file %s)\n",
+ inp_desc->line,
+ inp_desc->type_of_file==master?"master":"change",
+ inp_desc->file_name);
+ }
+ else
+ fprintf(stderr, ". (l. %ld of %s file %s)\n", inp_desc->line,
+ inp_desc->type_of_file==master?"master":"change",
+ inp_desc->file_name);
+ l=(inp_desc->loc>=inp_desc->limit? inp_desc->limit: inp_desc->loc);
+ if (l>inp_desc->buffer) {
+ for (k=inp_desc->buffer; k<l; k++)
+ if (*k=='\t') putc(' ', stderr);
+ else putc(*k, stderr); /* print the characters already read */
+ putc('\n', stderr);
+ for (k=inp_desc->buffer; k<l; k++)
+ putc(' ', stderr); /* space out the next line */
+ }
+ for (k=l; k<inp_desc->limit; k++)
+ putc(*k, stderr); /* print the part not yet read */
+ putc('\n', stderr);
+}
+
+
+@ Non recoverable errors are handled by calling |fatal_error| that
+outputs a message and then calls `|wrap_up|' and exits. |err_print|
+will print the error message followed by an indication of where the
+error was spotted in the source files. |fatal_error| cannot state any
+files because the problem is usually to access these.
+
+@d fatal_error(i, s, t) {
+ fprintf(stderr, "\n%s", s);
+ err_print(i, t);
+ history=fatal;
+ exit(wrap_up());
+ }
+
+
+@ Some implementations may wish to pass the |history| value to the
+operating system so that it can be used to govern whether or not other
+programs are started. Here, for instance, we pass the operating system
+a status of~0 if and only if only harmless messages were printed.
+@^system dependencies@>
+
+@<Internal func...@>=
+int wrap_up()
+{
+ @<Print the job |history|@>;
+ if (history > spotless) return 1;
+ else return 0;
+}
+
+@ Always good to prototype.
+
+@<Predecl...@>=
+int wrap_up();
+
+@ We report the history to the user, although this may not
+be ``\UNIX/'' style---but we are in good company: \.{WEB} and
+\TEX/ do the same. We put this on |stdout| rather than |stderr|, so
+that users can easily filter this away if they wish.
+@^system dependencies@>
+
+@<Print the job |history|@>=
+switch (history) {
+ case spotless:
+ printf("\n(No errors were found.)\n"); break;
+ case troublesome:
+ printf("\n(Pardon me, but I think I spotted something wrong.)\n"); break;
+ case fatal: printf("(That was a fatal error, my friend.)\n");
+} /* there are no other cases */
+
+
+@ If there's a system error, we may be able to give the user more
+information with the |pfatal_error| function. This prints out system
+error information if it is available.
+
+@<Predecl...@>=
+void pfatal_error();
+
+@ @<Error handling...@>=
+void pfatal_error(s, t)
+char *s, *t;
+{
+ char *strerr=strerror(errno);
+
+ fprintf(stderr, "\n%s%s", s, t);
+ if (strerr) fprintf(stderr, " (%s)\n", strerr);
+ else fprintf(stderr, "\n");
+ history=fatal;
+ exit(wrap_up());
+}
+
+
+@ We need an include file for the above.
+
+@<Global \&{\#include}s@>=
+#include <errno.h>
+
+
+@* Handling multiple change files.
+In the standard version we take the name of the
+files from the command line.
+It is assumed that filenames can be used as given in the
+command line without changes.
+
+First there are some sections to open all files.
+If a file is not accessible, the run will be aborted.
+Otherwise the name of the open file will be displayed.
+
+@<Prepare the output file@>=
+{
+ out_file=fopen(out_name, "w");
+ if (out_file==NULL) {
+ pfatal_error("! Cannot open/create output file", "");
+@.Cannot open/create output file@>
+ }
+}
+
+
+@ The name of the file and the file desciptor are stored in
+global variables.
+
+@<Global variables@>=
+FILE *out_file;
+string out_name;
+
+
+@ For the master file we start by reading its first line into the
+buffer, if we could open it.
+
+@<Get the master file started@>=
+{
+ input_organisation[0]->the_file=
+ fopen(input_organisation[0]->file_name, "r");
+
+ if (input_organisation[0]->the_file==NULL)
+ pfatal_error("! Cannot open master file ",
+ input_organisation[0]->file_name);
+@.Cannot open master file@>
+ printf("(%s)\n", input_organisation[0]->file_name);
+ input_organisation[0]->type_of_file=master;
+ get_line(0, true);
+}
+
+
+@ For the change files we must skip any comment part and see whether
+there are any changes in it. This is done by |init_change_file|.
+
+@<Prepare the change files@>=
+{
+ file_index i;
+
+ i=1;
+ while (i<no_ch) {
+ input_organisation[i]->the_file=
+ fopen(input_organisation[i]->file_name, "r");
+ if (input_organisation[i]->the_file==NULL)
+ pfatal_error("! Cannot open change file ",
+ input_organisation[i]->file_name);
+@.Cannot open change file@>
+ printf("(%s)\n", input_organisation[i]->file_name);
+ init_change_file(i);
+ i++;
+ }
+}
+
+
+@*Input/output organisation.
+Here's a simple function that checks if two lines
+are different.
+
+@<Internal functions@>=
+boolean lines_dont_match(i, j)
+ file_index i, j;
+{
+ register input_description *iptr=input_organisation[i],
+ *jptr=input_organisation[j];
+
+ if (iptr->limit-iptr->buffer != jptr->limit-jptr->buffer)
+ return true;
+ return strncmp(iptr->buffer, jptr->buffer, iptr->limit-iptr->buffer);
+}
+
+
+@ Function |init_change_file(i)| is used to ignore all
+lines of the input file with index~|i| until the next change
+module is found.
+
+@<Internal functions@>=
+void init_change_file(i)
+ file_index i;
+{
+ register input_description *inp_desc=input_organisation[i];
+ char ccode;
+
+ inp_desc->limit=inp_desc->buffer;
+ @<Skip over comment lines; |return| if end of file@>@;
+ @<Skip to the next nonblank line; |return| if end of file@>@;
+ inp_desc->dont_match=0;
+}
+
+
+@ While looking for a line that begins with \.{@@x} in the change
+file, we allow lines that begin with \.{@@}, as long as they don't
+begin with \.{@@y}, \.{@@z} or \.{@@i} (which would probably mean that
+the change file is fouled up).
+
+@<Skip over comment lines...@>=
+while(1) {
+ if (!get_line(i, false)) return; /* end of file reached */
+ if (inp_desc->limit<inp_desc->buffer+2) continue;
+ if (inp_desc->buffer[0]!='@@') continue;
+ ccode=inp_desc->buffer[1];
+ if (xisupper(ccode)) ccode=tolower(ccode);
+ if (ccode=='x') break;
+ if (ccode=='y' || ccode=='z' || ccode=='i') {
+ inp_desc->loc=inp_desc->buffer+2;
+ err_print(i, "! Missing @@x in change file");
+@.Missing @@x...@>
+ }
+}
+
+@ Here we are looking at lines following the \.{@@x}.
+
+@<Skip to the next nonblank line...@>=
+do {
+ if (!get_line(i, true)) {
+ err_print(i, "! Change file ended after @@x");
+@.Change file ended...@>
+ return;
+ }
+} while (inp_desc->limit==inp_desc->buffer);
+
+
+@ The |put_line| function is used to write a line from
+input buffer |j| to the output file.
+
+@<Internal functions@>=
+void put_line(j)
+ file_index j;
+{
+ char *ptr=input_organisation[j]->buffer;
+ char *lmt=input_organisation[j]->limit;
+
+ while(ptr<lmt) putc(*ptr++, out_file);
+ putc('\n', out_file);
+}
+
+
+@ The function |e_of_ch_module| returns true if the input
+line from file |i| starts with \.{@@z}.
+
+@<Internal functions@>=
+boolean e_of_ch_module(i)
+ file_index i;
+{
+ register input_description *inp_desc=input_organisation[i];
+
+ if (inp_desc->limit==NULL) {
+ err_print(i, "! Change file ended without @@z");
+@.Change file ended without @@z@>
+ return true;
+ } else if (inp_desc->limit>=inp_desc->buffer+2)
+ if (inp_desc->buffer[0]=='@@' &&
+ (inp_desc->buffer[1]=='Z' || inp_desc->buffer[1]=='z'))
+ return true;
+ return false;
+}
+
+
+@ The function |e_of_ch_preamble| returns |true| if the input
+line from file~|i| starts with \.{@@y}.
+
+@<Internal functions@>=
+boolean e_of_ch_preamble(i)
+ file_index i;
+{
+ register input_description *inp_desc=input_organisation[i];
+
+ if (inp_desc->limit>=inp_desc->buffer+2 && inp_desc->buffer[0]=='@@')
+ if (inp_desc->buffer[1]=='Y'||inp_desc->buffer[1]=='y') {
+ if (inp_desc->dont_match>0) {
+ inp_desc->loc=inp_desc->buffer+2;
+ fprintf(stderr, "\n! Hmm... %d ", inp_desc->dont_match);
+ err_print(i, "of the preceding lines failed to match");
+ }
+ return true;
+ }
+ return false;
+}
+
+
+
+@ To process the input file the next section reads a line of the
+current (actual) input file and updates the |input_organisation| for
+all files with index greater than |actual_input|.
+
+@<Process a line, |break| when end of source reached@>=
+{
+ file_index test_file;
+
+ @<Check the current files for any ends of changes@>@;
+ if (input_has_ended && actual_input==0) break; /* all done */
+ @<Scan all other files for changes to be done@>@;
+ @<Handle output@>@;
+ @<Step to next line@>@;
+}
+
+
+@ Any of the current change files may have reached the end of the
+current change. In such a case, intermediate lines must be skipped
+and the next start of change is to be found. This may make a change
+file become inactive if the end of the file is reached.
+
+@<Check the...@>=
+{
+ register input_description *inp_desc;
+ while (actual_input>0 && e_of_ch_module(actual_input)) {
+ inp_desc=input_organisation[actual_input];
+ if (inp_desc->type_of_file==master) {
+ /* emergency exit, everything mixed up!*/
+ fatal_error(-1, "! This can't happen: change file is master file", "");
+@.This can't happen...@>
+ }
+ inp_desc->mode=search;
+ init_change_file(actual_input);
+ while ((input_organisation[actual_input]->mode!=reading
+ && actual_input>0))
+ actual_input--;
+ }
+}
+
+
+@ Now we will set |test_input| to the first change file that is being
+tested against the current line. If no other file is testing, then
+|actual_input| refers to a line to write and |test_input| is set to
+|none|.
+
+@d none (-1)
+
+@<Scan all other files...@>=
+test_input=none;
+test_file=actual_input;
+while (test_input==none && test_file<no_ch-1){
+ test_file++;
+ switch (input_organisation[test_file]->mode) {
+ case search:
+ if (lines_dont_match(actual_input, test_file)==false) {
+ input_organisation[test_file]->mode=test;
+ test_input=test_file;
+ }
+ break;
+ case test:
+ if (lines_dont_match(actual_input, test_file)) {
+ /* error, sections do not match; just note at this point */
+ input_organisation[test_file]->dont_match++;
+ }
+ test_input=test_file;
+ break;
+ case reading: /* this can't happen */
+ break;
+ case ignore: /* nothing to do */
+ break;
+ }
+}
+
+
+@ For the output we must distinguish between whether we are creating a
+new change file or a new master file. Change file creation requires
+closer inspection because we may be before a change, in the pattern
+(match) part or in the replacement part. For master file creation, we
+simply have to write the line from the current (actual) input.
+
+@<Handle output@>=
+if (prod_chf==chf) {
+ while(1) {
+ @<Test for |normal|, |break| when done@>@;
+ @<Test for |pre|, |break| when done@>@;
+ @<Test for |post|, |break| when done@>@;
+ }
+} else
+ if (test_input==none) put_line(actual_input);
+
+
+@ Check whether we have to start a change file entry.
+Without a match nothing needs to be done.
+
+@<Test for |normal|...@>=
+if (out_mode==normal) {
+ if (test_input!=none) {
+ fprintf(out_file, "@@x\n");
+ out_mode=pre;
+ } else break;
+}
+
+
+@ Check whether we have to start the replacement text. This is the
+case when we are in |pre| mode but have no more matching lines.
+Otherwise the master file source line must be copied to the change
+file.
+
+@<Test for |pre|...@>=
+if (out_mode==pre) {
+ if (test_input==none) {
+ fprintf(out_file, "@@y\n");
+ out_mode=post;
+ } else {
+ if (input_organisation[actual_input]->type_of_file==master)
+ put_line(actual_input);
+ break;
+ }
+}
+
+
+@ Check whether an entry from a change file is complete. If the
+current input is from a change file which is not being tested against
+a later change file, then this change file line must be written. If
+the actual input has been reset to the master file, we can finish this
+change.
+
+@<Test for |post|...@>=
+if (out_mode==post) {
+ if (input_organisation[actual_input]->type_of_file==chf) {
+ if (test_input==none) put_line(actual_input);
+ break;
+ } else {
+ fprintf(out_file, "@@z\n\n");
+ out_mode=normal;
+ }
+}
+
+
+@ If we had a change, we must proceed in the actual file
+to be changed and in the change file in effect.
+
+@<Step to next line@>=
+get_line(actual_input, true);
+if (test_input!=none) {
+ get_line(test_input, true);
+ if (e_of_ch_preamble(test_input)==true) {
+ get_line(test_input, true); /* update current changing file */
+ input_organisation[test_input]->mode=reading;
+ actual_input=test_input;
+ test_input=none;
+ }
+}
+
+
+@ To create the new output file we have to scan the whole
+master file and all changes in effect when it ends.
+At the very end it is wise to check for all changes
+to have completed, in case the last line of the master file
+was to be changed.
+
+@<Process the input@>=
+actual_input=0;
+input_has_ended=false;
+while (input_has_ended==false||actual_input!=0)
+ @<Process a line...@>@;
+if (out_mode==post) /* last line has been changed */
+ fprintf(out_file, "@@z\n");
+
+
+@ At the end of the program, we will tell the user if the
+change file had a line that didn't match any relevant line
+in the master file or any of the change files.
+
+@<Check that all changes have been read@>=
+{
+ file_index i;
+
+ for (i=1;i<no_ch;i++) { /* all change files */
+ if (input_organisation[i]->mode!=ignore) {
+ input_organisation[i]->loc=input_organisation[i]->buffer;
+ err_print(i, "! Change file entry did not match");
+@.Change file entry ...@>
+ }
+ }
+}
+
+
+@ We want to tell the user about our command line options if they made
+a mistake. This is done by the |usage_error()| function. It contains
+merely the necessary print statements and exits afterwards.
+
+@<Intern...@>=
+void usage_error()
+{
+ @<Print the banners@>;
+ fprintf(stderr, "Usage: ctie -[mc] outfile master changefile(s)\n");
+ fprintf(stderr, "Type ctie --help for more information\n");
+ exit(1);
+}
+
+
+@ Printing our welcome banners; we only do this if we are not asked
+for version or help information.
+
+@<Print the banners@>=
+printf("%s\n", banner); /* print a ``banner line'' */
+printf("%s\n", copyright); /* include the copyright notice */
+
+
+@ We must scan through the list of parameters, given in |argv|. The
+number is in |argc|. We must pay attention to the flag parameter. We
+need at least 3~parameters (\.{-m} or \.{-c}, an output file and a
+master file) and can handle up to |max_file_index| change files. The
+names of the file parameters will be inserted into the structure of
+|input_organisation|. The first file is special. It indicates the
+output file. When we allow flags at any position, we must find out
+which name is for what purpose. The master file is already part of
+the |input_organisation| structure (index~0). As long as the number
+of files found (counted in |no_ch|) is |-1| we have not yet found the
+output file name.
+
+@<Scan the parameters@>=
+{
+ if (argc>max_file_index+5-1) usage_error();
+ no_ch = -1; /* fill this part of |input_organisation| */
+ while (--argc>0) {
+ argv++;
+ if (strcmp("-help", *argv)==0 || strcmp("--help", *argv)==0)
+ @<Display help message and exit@>;
+ if (strcmp("-version", *argv)==0 || strcmp("--version", *argv)==0)
+ @<Display version information and exit@>;
+ if (**argv=='-') @<Set a flag@>@;
+ else @<Get a file name@>@;
+ }
+ if (no_ch<=0|| prod_chf==unknown) usage_error();
+}
+
+
+@ The flag is about to determine the processing mode.
+We must make sure that this flag has not been set before.
+Further flags might be introduced to avoid/force overwriting of
+output files.
+Currently we just have to set the processing flag properly.
+
+@<Set a flag@>=
+if (prod_chf!=unknown) usage_error();
+else
+ switch (*(*argv+1)) {
+ case 'c': case 'C': prod_chf=chf; break;
+ case 'm': case 'M': prod_chf=master; break;
+ default: usage_error();
+ }
+
+
+@ We have to distinguish whether this is the very first file name
+(which is the case if |no_ch==(-1)|) or if the next element of
+|input_organisation| must be filled.
+
+@<Get a file name@>=
+{
+ if (no_ch==(-1)) {
+ out_name=*argv;
+ } else {
+ register input_description *inp_desc;
+
+ inp_desc=(input_description *) malloc(sizeof(input_description));
+ if (inp_desc==NULL)
+ fatal_error(-1, "! No memory for input descriptor", "");
+@.No memory for descriptor@>
+ inp_desc->mode=search;
+ inp_desc->line=0;
+ inp_desc->type_of_file=chf;
+ inp_desc->limit=inp_desc->buffer;
+ inp_desc->buffer[0]=' ';
+ inp_desc->loc=inp_desc->buffer+1;
+ inp_desc->buffer_end=inp_desc->buffer+buf_size-2;
+ inp_desc->file_name=*argv;
+ inp_desc->current_include=NULL;
+ input_organisation[no_ch]=inp_desc;
+ }
+ no_ch++;
+}
+
+
+@ Modules for dealing with help messages and version info. We follow
+the \.{kpathsea} standard code here, so that we can easily adapt this
+to work with \.{kpathsea}.
+
+@<Display help message and exit@>=
+usage_help();
+@.--help@>
+
+
+@
+@<Display version information and exit@>=
+{
+ print_version_and_exit("CTIE", version_number);
+@.--version@>
+}
+
+
+@ Here is the usage information for \.{--help}.
+
+@<Global variables@>=
+string CTIEHELP[] = {
+ "Usage: ctie -[mc] outfile master changefile(s)",
+ " Create a new master file or change file from the given",
+ " master (C)WEB file and changefiles.",
+ " All filenames are taken literally; no suffixes are added.",
+ "",
+ "-m create a new master file from original (C)WEB and change file(s)",
+ "-c create a master change file for original (C)WEB file from changefile(s)",
+ "--help display this help and exit",
+ "--version display version information and exit",
+ NULL
+};
+
+
+@ @<Predec...@>=
+void usage_help();
+void print_version_and_exit();
+
+
+@ @c
+void usage_help()
+{
+ string *message=CTIEHELP;
+
+ while (*message) {
+ fputs(*message, stdout);
+ putchar('\n');
+ ++message;
+ }
+ putchar('\n');
+ exit(0);
+}
+
+
+@ @c
+void print_version_and_exit(name, version)
+ string name, version;
+{
+ printf ("%s %s\n", name, version);
+
+ puts ("Copyright (C) 2002,2003 Julian Gilbey.");
+
+ puts ("There is NO warranty. This is free software. See the source");
+ puts ("code of CTIE for redistribution conditions.");
+
+ exit (0);
+}
+
+
+@* System-dependent changes.
+This section should be replaced, if necessary, by
+changes to the program that are necessary to make \.{CTIE}
+work at a particular installation. It is usually best to
+design your change file so that all changes to previous
+modules preserve the module numbering; then everybody's
+version will be consistent with the printed program. More
+extensive changes, which introduce new modules, can be
+inserted here; then only the index itself will get a new
+module number.
+@^system dependencies@>
+
+
+@* Index.
diff --git a/web/c_cpp/ctie/ctiedoc.tex b/web/c_cpp/ctie/ctiedoc.tex
new file mode 100644
index 0000000000..972bfff44d
--- /dev/null
+++ b/web/c_cpp/ctie/ctiedoc.tex
@@ -0,0 +1,242 @@
+% ctiedoc.tex Jan 2002, last updated Apr 2003
+%-----------------------------------------------
+
+% A minor rewrite of tiedoc.tex for the CTIE changes.
+
+
+\documentclass{article}
+
+\let\mc=\small
+\def\CEE/{{\mc C\spacefactor1000}}
+\let\.=\texttt
+
+\begin{document}
+
+\begin{center}
+\Large The \.{CTIE} Processor
+
+\bigskip
+\large
+Julian Gilbey\\
+\.{jdg@debian.org}
+
+\bigskip
+Based on the original \.{TIE} documentation by:\\
+Klaus Guntermann\\
+TH Darmstadt\\
+Fachbereich Informatik\\
+Institut f\"ur Theoretische Informatik
+
+\bigskip
+January 2002, updated April 2003
+
+\end{center}
+
+\bigskip
+
+\section{Introduction}
+
+When installing a program on a particular computer system, certain
+system dependent changes are often needed. The original \.{WEB}
+programs (\.{WEAVE} and \.{TANGLE}) handled this problem by using
+\textit{change files}, which work very much like a patch file and are
+read by \.{WEAVE} and \.{TANGLE} along with the main \.{WEB} file.
+This allows the original \.{WEB} file to remain intact and the
+particular system dependencies to be isolated.
+
+Sometimes it is good practice to develop a set of multiple change
+files for a given \.{WEB} file to distinguish between different
+changes such as program enhancements, bug fixes, system dependent
+changes and output device dependent modifications. Additionally this
+allows combinations of changes that can be used with a set of programs
+that share some common features, such as \.{WEAVE} and \.{TANGLE}
+themselves.
+
+Unfortunately, the processors \.{TANGLE} and \.{WEAVE} can handle only
+one change file. Rather than modifying these processors to handle
+multiple change files, it is easier to combine them in a preprocessing
+step. The \.{TIE} processor was written to perform this task. It is
+able to create either a new master file or a single change file that
+comprises the effect of all change files.
+
+The \.{CWEB} system was later developed in order to open up the
+\.{WEB} system of literate programming to \CEE/ programmers. It
+functions in an essentially identical way to the original Pascal
+\.{WEB} system, and the syntax of change files is the same. So it
+should be possible to use the \.{TIE} processor for \.{CWEB} source
+files. However, one significant enhancement was made to \.{CWEB}
+which makes this sometimes impossible. \.{CWEB} supports
+\textit{include files}, which are introduced by a line beginning
+`\.{@i} \textit{filename}', which includes the \.{CWEB} file
+specified, just like the \CEE/ preprocessor command \.{\#include}. As
+these include commands are effectively expanded before the change file
+is applied, both in the master file and the change file, it is clear
+that \.{TIE} needs to interpret \.{@i} commands in order to work for
+all \.{CWEB} files. Thus \.{CTIE} was born: it essentially combines
+the traditional behaviour of \.{TIE} with the ability to handle
+\.{CWEB} include files.
+
+
+\section{Application}
+
+The current version of \.{CTIE} accepts a master file and up to
+32~change files. In general it is important to use the change files
+in the correct sequence, as later change files may modify the results
+of applying earlier changes. Thus the order of the change files on
+the command line is taken to specify the order in which the change
+files should be applied. Conceptually, each change file is applied to
+the master file in turn to create a new master file, to which the next
+change file is applied; in practice, though, a more space-efficient
+algorithm is used which only requires storage space for one line per
+file, so the lengths of the individual files or changes are irrelevant
+for storage requirements.
+
+Note that \.{CTIE} will expand all \.{@i} include lines, including the
+specified files whether or not they are modified by any change files.
+So another application of \.{CTIE} is to simply expand all of these
+include files, producing an expanded master file. (Thanks to Hartmut
+Henkel \.{<hartmut\_henkel@gmx.de>} for this observation.)
+
+\.{CTIE} must be called with at least 3~parameters as follows:
+$$\texttt{ctie -[cm] outfile master changefile(s)}$$
+where the parameters are (in order):
+\begin{enumerate}
+
+\item Either the option \.{-c} or \.{-m}. This option determines
+ whether an amalgamated change file or a new master file is created.
+
+\item The name of the output file.
+
+\item The name of the master file.
+
+\item The name(s) of the change file(s), if any.
+
+\end{enumerate}
+
+Unlike the \.{CWEB} programs \.{CWEAVE} and \.{CTANGLE}, no attempt to
+add default suffixes such as \.{.w} or \.{.ch} is made; the filenames
+must be the full filenames. If \.{CTIE} has been compiled with
+\.{kpathsea} support, then the \.{kpathsea} library will be used to
+search for the files using the \.{CWEBINPUTS} variable, otherwise just
+the current directory and the directory specified by the
+\.{CWEBINPUTS} environment variable will be searched, in that order.
+
+Also, \.{CTIE} can be called with the single argument \.{--help} or
+\.{--version} to get basic help or version information.
+
+\clearpage
+
+
+\def\eof{$\langle$\textrm{\mc EOF}$\rangle$}
+\tabcolsep=1em
+\parindent=0pt
+
+\section{Example}
+
+To illustrate the actions \.{CTIE} performs you may inspect the
+following example that exercises some of the borderline cases.
+
+\begin{center}
+\ttfamily
+\begin{tabular}{llll}
+\multicolumn1{c}{\textbf{\textrm{ctie.tie}}}&
+ \multicolumn1{c}{\textbf{\textrm{ctie.cf1}}}&
+ \multicolumn1{c}{\textbf{\textrm{ctie.cf2}}}&
+ \multicolumn1{c}{\textbf{\textrm{ctie.cf3}}}\\[1pt]
+\hline
+line 1 &@x &@x &@x\\
+line 2 &line 2 &line 1 &changed line 4\\
+line 3 &line 3 &changed line 2 &@y\\
+line 4 &@y &changed line 3 &final line 4\\
+line 5 &changed line 2 &inserted line &@z\\
+@i ctie.inc &changed line 3 &line 4\\
+line 6 &inserted line &@y &@x\\
+line 7 &@z &final line 2 &changed inc line 1\\
+line 8 & &final line 3 &inserted inc line\\
+line 9 &@x &changed line 4 &@y\\
+line 10 &line 7 &@z &final inc line 1\\
+\eof &@y & &@i "ctie.inc2"\\
+ &changed line 7 &@x &@z\\
+ &@z &inc line 1 &\eof\\
+ &\eof &@y\\
+ & &changed inc line 1\\
+ & &inserted inc line\\
+ & &@z\\
+ & &\\
+ & &@x\\
+ & &changed line 7\\
+ & &line 8\\
+ & &@y\\
+ & &final line 7\\
+ & &final line 8\\
+ & &@z\\
+ & &\eof\\
+\end{tabular}
+\end{center}
+
+The included files are as follows:
+
+\begin{center}
+\ttfamily
+\begin{tabular}{lll}
+\multicolumn1{c}{\textbf{\textrm{ctie.inc}}}&
+ \multicolumn1{c}{\textbf{\textrm{ctie.inc1}}}&
+ \multicolumn1{c}{\textbf{\textrm{ctie.inc2}}}\\[1pt]
+\hline
+inc line 1 &included inc line &final inserted inc line\\
+inc line 2 &\eof &\eof\\
+@i ctie.inc1\\
+inc line 3\\
+\eof\\
+\end{tabular}
+\end{center}
+
+\clearpage
+
+Using these input files and running \.{CTIE} with the following
+commands to create a new master file and a new change file will result
+in the following output files.
+
+\begin{tabbing}
+ \quad For the master file:\qquad\=\texttt{ctie -m ctie.outm ctie.cf1
+ ctie.cf2 ctie.cf3}\\
+ \quad For the change file:\>\texttt{ctie -c ctie.outc ctie.cf1
+ ctie.cf2 ctie.cf3}
+\end{tabbing}
+
+\begin{center}
+\ttfamily
+\begin{tabular}{ll}
+\multicolumn1{c}{\textbf{\textrm{ctie.outm}}}&
+ \multicolumn1{c}{\textbf{\textrm{ctie.outc}}}\\[1pt]
+\hline
+final line 2 &@x\\
+final line 3 &line 1\\
+final line 4 &line 2\\
+line 5 &line 3\\
+final inc line 1 &line 4\\
+final inserted inc line &@y\\
+inc line 2 &final line 2\\
+included inc line &final line 3\\
+inc line 3 &final line 4\\
+line 6 &@z\\
+final line 7 &\\
+final line 8 &@x\\
+line 9 &inc line 1\\
+line 10 &@y\\
+ &final inc line 1\\
+ &final inserted inc line\\
+ &@z\\
+ &\\
+ &@x\\
+ &line 7\\
+ &line 8\\
+ &@y\\
+ &final line 7\\
+ &final line 8\\
+ &@z\\
+\end{tabular}
+\end{center}
+
+
+\end{document}
diff --git a/web/c_cpp/cweb/Makefile b/web/c_cpp/cweb/Makefile
new file mode 100644
index 0000000000..1367d00892
--- /dev/null
+++ b/web/c_cpp/cweb/Makefile
@@ -0,0 +1,197 @@
+# This file is part of CWEB.
+# It is distributed WITHOUT ANY WARRANTY, express or implied.
+# Version 3.64 --- February 2002
+
+# Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth
+
+# Permission is granted to make and distribute verbatim copies of this
+# document provided that the copyright notice and this permission notice
+# are preserved on all copies.
+
+# Permission is granted to copy and distribute modified versions of this
+# document under the conditions for verbatim copying, provided that the
+# entire resulting derived work is given a different name and distributed
+# under the terms of a permission notice identical to this one.
+
+#
+# Read the README file, then edit this file to reflect local conditions
+#
+
+# directory for TeX inputs (cwebmac.tex goes here)
+MACROSDIR= /usr/share/texmf/tex/generic
+
+# directory for CWEB inputs in @i files
+CWEBINPUTS= /usr/local/lib/cweb
+
+# extension for manual pages ("l" distinguishes local from system stuff)
+MANEXT= l
+#MANEXT= 1
+
+# directory for manual pages (cweb.1 goes here)
+MANDIR= /usr/share/man/man$(MANEXT)
+
+# destination directory for executables; must end in /
+DESTDIR= /usr/local/bin/
+
+# directory for GNU EMACS Lisp code (cweb.el goes here)
+EMACSDIR= /usr/share/emacs/site-lisp
+
+# Set DESTPREF to null if you want to call the executables "tangle" and "weave"
+# (probably NOT a good idea; we recommend leaving DESTPREF=c)
+DESTPREF=c
+
+# Set CCHANGES to comm-foo.ch if you need changes to common.w
+CCHANGES=
+
+# Set TCHANGES to ctang-foo.ch if you need changes to ctangle.w
+TCHANGES=
+
+# Set WCHANGES to cweav-foo.ch if you need changes to cweave.w
+WCHANGES=
+
+# We keep debugging info around, for fun, but most users don't need it
+CFLAGS = -g
+#CFLAGS = -O
+LINKFLAGS = -g
+#LINKFLAGS = -s # for smaller (stripped) executables on many UNIX systems
+
+# What C compiler are you using?
+CC = cc
+
+# RM and CP are used below in case rm and cp are aliased
+RM= /bin/rm
+CP= /bin/cp
+
+# uncomment the second line if you use pdftex to bypass .dvi files
+PDFTEX = dvipdfm
+#PDFTEX = pdftex
+
+########## You shouldn't have to change anything after this point #######
+
+CWEAVE = ./cweave
+CTANGLE = ./ctangle
+SOURCES = cweave.w common.w ctangle.w
+ALL = common.w ctangle.w cweave.w prod.w \
+ Makefile common.c common.h ctangle.c \
+ cwebman.tex cwebmac.tex comm-vms.ch ctang-vms.ch \
+ cweav-vms.ch comm-man.ch ctang-man.ch cweav-man.ch \
+ comm-pc.ch ctang-pc.ch cweav-pc.ch comm-amiga.ch \
+ comm-bs.ch ctang-bs.ch cweav-bs.ch makefile.bs \
+ comm-ql.ch ctang-ql.ch cweav-ql.ch readme.ql \
+ comm-w32.ch ctang-w32.ch cweav-w32.ch \
+ comm-os2.ch comm-mac.ch cweb.1 cweb.el c++lib.w README
+
+.SUFFIXES: .dvi .tex .w .pdf
+
+.w.tex:
+ $(CWEAVE) $*
+
+.tex.dvi:
+ tex $<
+
+.w.dvi:
+ make $*.tex
+ make $*.dvi
+
+.w.c:
+ $(CTANGLE) $*
+
+.w.o:
+ make $*.c
+ make $*.o
+
+.w.pdf:
+ make $*.tex
+ case "$(PDFTEX)" in \
+ dvipdfm ) tex "\let\pdf+ \input $*"; dvipdfm $* ;; \
+ pdftex ) pdftex $* ;; \
+ esac
+
+all: ctangle cweave
+
+cautiously: ctangle
+ $(CP) common.c SAVEcommon.c
+ ./ctangle common $(CCHANGES)
+ diff common.c SAVEcommon.c
+ $(RM) SAVEcommon.c
+ $(CP) ctangle.c SAVEctangle.c
+ ./ctangle ctangle $(TCHANGES)
+ diff ctangle.c SAVEctangle.c
+ $(RM) SAVEctangle.c
+
+SAVEctangle.c:
+ $(CP) ctangle.c SAVEctangle.c
+
+SAVEcommon.c:
+ $(CP) common.c SAVEcommon.c
+
+common.c: common.w $(CCHANGES)
+ $(CTANGLE) common $(CCHANGES)
+
+common.o: common.c
+ $(CC) $(CFLAGS) -DCWEBINPUTS=\"$(CWEBINPUTS)\" -c common.c
+
+ctangle: ctangle.o common.o
+ $(CC) $(LINKFLAGS) -o ctangle ctangle.o common.o
+
+ctangle.c: ctangle.w $(TCHANGES)
+ $(CTANGLE) ctangle $(TCHANGES)
+
+cweave: cweave.o common.o
+ $(CC) $(LINKFLAGS) -o cweave cweave.o common.o
+
+cweave.c: cweave.w $(WCHANGES)
+ $(CTANGLE) cweave $(WCHANGES)
+
+doc: $(SOURCES:.w=.dvi)
+
+usermanual: cwebman.tex cwebmac.tex
+ tex cwebman
+
+fullmanual: usermanual $(SOURCES) comm-man.ch ctang-man.ch cweav-man.ch
+ make cweave
+ ./cweave common.w comm-man.ch
+ tex common.tex
+ ./cweave ctangle.w ctang-man.ch
+ tex ctangle.tex
+ ./cweave cweave.w cweav-man.ch
+ tex cweave.tex
+
+# be sure to leave ctangle.c and common.c for bootstrapping
+clean:
+ $(RM) -f -r *~ *.o common.tex cweave.tex cweave.c ctangle.tex \
+ *.log *.dvi *.toc *.idx *.scn *.pdf core cweave ctangle
+
+install: all
+ - mkdir $(DESTDIR)
+ $(CP) cweave $(DESTDIR)$(DESTPREF)weave
+ chmod 755 $(DESTDIR)$(DESTPREF)weave
+ $(CP) ctangle $(DESTDIR)$(DESTPREF)tangle
+ chmod 755 $(DESTDIR)$(DESTPREF)tangle
+ - mkdir $(MANDIR)
+ $(CP) cweb.1 $(MANDIR)/cweb.$(MANEXT)
+ chmod 644 $(MANDIR)/cweb.$(MANEXT)
+ - mkdir $(MACROSDIR)
+ $(CP) cwebmac.tex $(MACROSDIR)
+ chmod 644 $(MACROSDIR)/cwebmac.tex
+ - mkdir $(EMACSDIR)
+ $(CP) cweb.el $(EMACSDIR)
+ chmod 644 $(EMACSDIR)/cweb.el
+ - mkdir $(CWEBINPUTS)
+ $(CP) c++lib.w $(CWEBINPUTS)
+ chmod 644 $(CWEBINPUTS)/c++lib.w
+
+floppy: $(ALL) examples
+ bar cvhf /dev/rfd0 $(ALL) examples
+ bar tvf /dev/rfd0
+ eject
+
+tags: $(ALL)
+ etags -lnone $(ALL)
+
+tarfile: $(ALL) examples
+ tar cvhf /tmp/cweb.tar $(ALL) examples
+ gzip -9 /tmp/cweb.tar
+
+tarball:
+ tar zcvhf /tmp/cweb.tgz $(ALL) examples
diff --git a/web/c_cpp/cweb/README b/web/c_cpp/cweb/README
new file mode 100644
index 0000000000..6429dabfa8
--- /dev/null
+++ b/web/c_cpp/cweb/README
@@ -0,0 +1,110 @@
+% This file is part of CWEB.
+% The CWEB programs by Silvio Levy are based on programs by D. E. Knuth.
+% They are distributed WITHOUT ANY WARRANTY, express or implied.
+% This README file last updated January 2016 by Don Knuth
+
+% Copyright (C) 1987,1990,1993,2000,2016 Silvio Levy and Donald E. Knuth
+
+% Permission is granted to make and distribute verbatim copies of this
+% document provided that the copyright notice and this permission notice
+% are preserved on all copies.
+
+% Permission is granted to copy and distribute modified versions of this
+% document under the conditions for verbatim copying, provided that the
+% entire resulting derived work is given a different name and distributed
+% under the terms of a permission notice identical to this one.
+
+% Please send comments, suggestions, etc. to tex-k@tug.org, and people
+% there will verify and forward bug reports.
+%
+% DEK takes no responsibility for the changefiles; they should be
+% maintained independently. His job is to correct errors in
+% ctangle.w, cweave.w, prod.w, common.w, cwebmac.tex, cwebman.tex,
+% and in the files of examples/*.w, nothing more.
+
+This directory contains the following files:
+
+Makefile
+README
+comm-amiga.ch
+comm-bs.ch
+comm-mac.ch
+comm-man.ch
+comm-pc.ch
+comm-ql.ch
+comm-vms.ch
+comm-w32.ch
+common.c
+common.h
+common.w
+ctang-bs.ch
+ctang-man.ch
+ctang-pc.ch
+ctang-ql.ch
+ctang-vms.ch
+ctang-w32.ch
+ctangle.c
+ctangle.w
+cweav-bs.ch
+cweav-man.ch
+cweav-pc.ch
+cweav-ql.ch
+cweav-vms.ch
+cweave-w32.ch
+cweave.w
+cweb.1
+cweb.el
+cwebmac.tex
+cwebman.tex
+examples/
+makefile.bs
+prod.w
+readme.ql
+c++lib.w
+
+The file cwebman.tex is the user manual.
+The examples directory contains additional examples of the use of CWEB.
+The files common.c and ctangle.c are used for bootstrapping.
+The file cweb.1 is a manual page.
+The file cweb.el is suggested for GNU-Emacs users.
+The file c++lib.w is for C++ users (say `@i c++lib.w' at beginning of program).
+The files *-man.ch are used if you want to make the full 239-page CWEB manual.
+The files *-bs.ch are used instead of *-pc.ch if you are doing BIG programs.
+You can use makefile.bs to make CWEB with *-bs.ch.
+The files *-ql.ch are for QDOS/SMSQ systems; see readme.ql for further info.
+The files *-w32.ch use __fastcall conventions on win32 systems.
+The file comm-mac.ch is for Macintosh conventions.
+The other files named *.ch are sample change files for local customization.
+
+IMPORTANT: Please touch *.c before proceeding.
+Then edit the opening lines of Makefile so that it has the proper
+directory information for your local system.
+
+To make ctangle and cweave say `make all'; this should produce roughly
+the following actions (possibly with harmless warning messages from cc):
+
+cc -g -w -c ctangle.c
+cc -g -w -DCWEBINPUTS=\"/usr/local/lib/cweb\" -c common.c
+cc -g -o ctangle ctangle.o common.o
+./ctangle cweave
+cc -g -w -c cweave.c
+cc -g -w -o cweave cweave.o common.o
+
+To get some reassurance that things are OK, you can say `make cautiously',
+which ensures that CTANGLE will reproduce itself. (Otherwise the source
+files common.w and ctangle.w won't actually have been used.)
+
+To install cweave and ctangle say `make install'. You probably need to
+be superuser to do this; but it's wise to `make all' first, BEFORE
+becoming superuser and saying `make install'.
+
+Note that change files for VMS, AMIGA, MAC, and PCs are provided. When you
+are first bootstrapping to a new system, you may need to edit common.c and
+ctangle.c by hand, but the vast majority of the change-file changes are
+minor refinements that are not necessary for a rudimentary ctangle.
+
+-----------------------------------------
+These archival sources are maintained only to the extent of fixing
+significant bugs that were unintended at the time of writing.
+A multi-decade ongoing project to improve and extend CWEB can be found at
+ https://github.com/ascherer/cwebbin
diff --git a/web/c_cpp/cweb/c++lib.w b/web/c_cpp/cweb/c++lib.w
new file mode 100644
index 0000000000..15e59cc885
--- /dev/null
+++ b/web/c_cpp/cweb/c++lib.w
@@ -0,0 +1,85 @@
+@q This file defines standard C++ namespaces and classes @>
+@q Please send corrections to saroj-tamasa@@worldnet.att.net @>
+@s std int
+@s rel_ops int
+@s bitset int
+@s char_traits int
+@s deque int
+@s list int
+@s map int
+@s multimap int
+@s multiset int
+@s pair int
+@s set int
+@s stack int
+@s exception int
+@s logic_error int
+@s runtime_error int
+@s domain_error int
+@s invalid_argument int
+@s length_error int
+@s out_of_range int
+@s range_error int
+@s overflow_error int
+@s underflow_error int
+@s back_insert_iterator int
+@s front_insert_iterator int
+@s insert_iterator int
+@s reverse_iterator int
+@s istream_iterator int
+@s ostream_iterator int
+@s istreambuf_iterator int
+@s ostreambuf_iterator int
+@s iterator_traits int
+@s queue int
+@s vector int
+@s basic_string int
+@s string int
+@s auto_ptr int
+@s valarray int
+@s ios_base int
+@s basic_ios int
+@s basic_streambuf int
+@s basic_istream int
+@s basic_ostream int
+@s basic_iostream int
+@s basic_stringbuf int
+@s basic_istringstream int
+@s basic_ostringstream int
+@s basic_stringstream int
+@s basic_filebuf int
+@s basic_ifstream int
+@s basic_ofstream int
+@s basic_fstream int
+@s ctype int
+@s collate int
+@s collate_byname int
+@s streambuf int
+@s istream int
+@s ostream int
+@s iostream int
+@s stringbuf int
+@s istringstream int
+@s ostringstream int
+@s stringstream int
+@s filebuf int
+@s ifstream int
+@s ofstream int
+@s fstream int
+@s wstreambuf int
+@s wistream int
+@s wostream int
+@s wiostram int
+@s wstringbuf int
+@s wistringstream int
+@s wostringstream int
+@s wstringstream int
+@s wfilebuf int
+@s wifstream int
+@s wofstream int
+@s wfstream int
+@s streamoff int
+@s streamsize int
+@s fpos int
+@s streampos int
+@s wstreampos int
diff --git a/web/c_cpp/cweb/comm-amiga.ch b/web/c_cpp/cweb/comm-amiga.ch
new file mode 100644
index 0000000000..57e65d1ccd
--- /dev/null
+++ b/web/c_cpp/cweb/comm-amiga.ch
@@ -0,0 +1,17 @@
+This is the change file for CWEB's COMMON on the Amiga
+(Contributed by Tomas Rokicki, June 1993)
+
+With Lattice C 5.1, use compilation switches -b0 -r0, and ignore the
+compiler warnings. With SAS 6.0, use compilation switches Code=far Data=far.
+
+@x section 69
+An omitted change file argument means that |"/dev/null"| should be used,
+@y
+An omitted change file argument means that |"nil:"| should be used,
+@z
+
+@x section 70
+ if (found_change<=0) strcpy(change_file_name,"/dev/null");
+@y
+ if (found_change<=0) strcpy(change_file_name,"nil:");
+@z
diff --git a/web/c_cpp/cweb/comm-bs.ch b/web/c_cpp/cweb/comm-bs.ch
new file mode 100644
index 0000000000..26f79b160d
--- /dev/null
+++ b/web/c_cpp/cweb/comm-bs.ch
@@ -0,0 +1,229 @@
+Changes for code common to CTANGLE and CWEAVE, for MSDOS
+and Borland C++ 3.1 using the following options (and perhaps others):
+
+ -mc -w-pro -Ff=5000 -Z- -O-p
+
+The options -Z- and -O-p explicitly turn off optimizations that seem to be
+dangerous for the style of code in the CWEB sources. (See makefile.bs.)
+
+The main purpose of these changes is to support MSDOS with full-size arrays
+by using "huge" pointers.
+
+(This file contributed by Barry Schwartz, trashman@crud.mn.org, 28 Jun 94;
+ revised 24 Jul 94.)
+
+
+@x Section 23.
+ cur_file_name[l]='/'; /* \UNIX/ pathname separator */
+@y
+ cur_file_name[l]='/'; /* A valid {\mc MSDOS} pathname separator */
+@z
+
+
+@x Section 27.
+@d max_names 4000 /* number of identifiers, strings, section names;
+ must be less than 10240 */
+
+@<Definitions that...@>=
+typedef struct name_info {
+ char *byte_start; /* beginning of the name in |byte_mem| */
+ @<More elements of |name_info| structure@>@;
+} name_info; /* contains information about an identifier or section name */
+typedef name_info *name_pointer; /* pointer into array of |name_info|s */
+char byte_mem[max_bytes]; /* characters of names */
+char *byte_mem_end = byte_mem+max_bytes-1; /* end of |byte_mem| */
+name_info name_dir[max_names]; /* information about names */
+name_pointer name_dir_end = name_dir+max_names-1; /* end of |name_dir| */
+@y
+@d max_names 4000 /* number of identifiers, strings, section names;
+ must be less than 10240 */
+
+@f huge extern
+
+@<Definitions that...@>=
+typedef struct name_info {
+ char huge* byte_start; /* beginning of the name in |byte_mem| */
+ @<More elements of |name_info| structure@>@;
+} name_info; /* contains information about an identifier or section name */
+typedef name_info *name_pointer; /* pointer into array of |name_info|s */
+char huge byte_mem[max_bytes]; /* characters of names */
+char huge* byte_mem_end; /* end of |byte_mem| */
+name_info name_dir[max_names]; /* information about names */
+name_pointer name_dir_end = name_dir+max_names-1;
+@z
+
+
+@x Section 29.
+char *byte_ptr; /* first unused position in |byte_mem| */
+@y
+char huge* byte_ptr; /* first unused position in |byte_mem| */
+@z
+
+
+@x Section 30.
+@ @<Init...@>=
+name_dir->byte_start=byte_ptr=byte_mem; /* position zero in both arrays */
+name_ptr=name_dir+1; /* |name_dir[0]| will be used only for error recovery */
+name_ptr->byte_start=byte_mem; /* this makes name 0 of length zero */
+@y
+@ @<Init...@>=
+name_dir->byte_start=byte_ptr=byte_mem; /* position zero in both arrays */
+name_ptr=name_dir+1; /* |name_dir[0]| will be used only for error recovery */
+name_ptr->byte_start=byte_mem; /* this makes name 0 of length zero */
+byte_mem_end = byte_mem+max_bytes-1;
+@z
+
+
+@x Section 42.
+void
+print_section_name(p)
+name_pointer p;
+{
+ char *ss, *s = first_chunk(p);
+@y
+void
+print_section_name(p)
+name_pointer p;
+{
+ char huge* ss, huge* s = first_chunk(p);
+@z
+
+
+@x Section 43.
+void
+sprint_section_name(dest,p)
+ char*dest;
+ name_pointer p;
+{
+ char *ss, *s = first_chunk(p);
+@y
+void
+sprint_section_name(dest,p)
+ char*dest;
+ name_pointer p;
+{
+ char huge* ss, huge* s = first_chunk(p);
+@z
+
+
+@x Section 44.
+void
+print_prefix_name(p)
+name_pointer p;
+{
+ char *s = first_chunk(p);
+@y
+void
+print_prefix_name(p)
+name_pointer p;
+{
+ char huge* s = first_chunk(p);
+@z
+
+
+@x Section 47.
+name_pointer
+add_section_name(par,c,first,last,ispref) /* install a new node in the tree */
+name_pointer par; /* parent of new node */
+int c; /* right or left? */
+char *first; /* first character of section name */
+char *last; /* last character of section name, plus one */
+int ispref; /* are we adding a prefix or a full name? */
+{
+ name_pointer p=name_ptr; /* new node */
+ char *s=first_chunk(p);
+@y
+name_pointer
+add_section_name(par,c,first,last,ispref) /* install a new node in the tree */
+name_pointer par; /* parent of new node */
+int c; /* right or left? */
+char *first; /* first character of section name */
+char *last; /* last character of section name, plus one */
+int ispref; /* are we adding a prefix or a full name? */
+{
+ name_pointer p=name_ptr; /* new node */
+ char huge* s=first_chunk(p);
+@z
+
+
+@x Section 48.
+void
+extend_section_name(p,first,last,ispref)
+name_pointer p; /* name to be extended */
+char *first; /* beginning of extension text */
+char *last; /* one beyond end of extension text */
+int ispref; /* are we adding a prefix or a full name? */
+{
+ char *s;
+@y
+void
+extend_section_name(p,first,last,ispref)
+name_pointer p; /* name to be extended */
+char *first; /* beginning of extension text */
+char *last; /* one beyond end of extension text */
+int ispref; /* are we adding a prefix or a full name? */
+{
+ char huge* s;
+@z
+
+
+@x Section 54.
+int section_name_cmp(pfirst,len,r)
+char **pfirst; /* pointer to beginning of comparison string */
+int len; /* length of string */
+name_pointer r; /* section name being compared */
+{
+ char *first=*pfirst; /* beginning of comparison string */
+ name_pointer q=r+1; /* access to subsequent chunks */
+ char *ss, *s=first_chunk(r);
+@y
+int section_name_cmp(pfirst,len,r)
+char **pfirst; /* pointer to beginning of comparison string */
+int len; /* length of string */
+name_pointer r; /* section name being compared */
+{
+ char *first=*pfirst; /* beginning of comparison string */
+ name_pointer q=r+1; /* access to subsequent chunks */
+ char huge* ss, huge* s=first_chunk(r);
+@z
+
+
+@x Section 55.
+source files, respectively; here we just declare a common field
+|equiv_or_xref| as a pointer to a |char|.
+
+@<More elements of |name...@>=
+char *equiv_or_xref; /* info corresponding to names */
+@y
+source files, respectively. Here we just declare a common field
+|ptr_union| as a union of pointers to |char|, which happen to have
+different addressing attributes.
+
+@<More elements of |name...@>=
+union {
+ char *equiv_member;
+ char huge* xref_member;
+} ptr_union; /* info corresponding to names */
+@z
+
+
+@x Section 69.
+An omitted change file argument means that |"/dev/null"| should be used,
+@y
+An omitted change file argument means that |"NUL"| should be used,
+@z
+
+
+@x Section 70.
+ else if (*s=='/') dot_pos=NULL,name_pos=++s;
+@y
+ else if (*s == ':' || *s == '\\' || *s == '/')
+ dot_pos=NULL,name_pos=++s;
+@z
+
+
+@x Section 70.
+ if (found_change<=0) strcpy(change_file_name,"/dev/null");
+@y
+ if (found_change<=0) strcpy(change_file_name,"NUL");
+@z
diff --git a/web/c_cpp/cweb/comm-mac.ch b/web/c_cpp/cweb/comm-mac.ch
new file mode 100644
index 0000000000..b9bd408655
--- /dev/null
+++ b/web/c_cpp/cweb/comm-mac.ch
@@ -0,0 +1,150 @@
+This is the change file to CWEB's COMMON for porting to Macintoshes.
+No changes to CTANGLE or CWEAVE are needed.
+
+(Contributed 13 Oct 2000 by AndPio@aol.com; slightly edited by Don Knuth)
+
+@x in limbo, change the title page document to specify Mac version
+ \centerline{(Version 3.64)}
+@y
+ \centerline{(Version 3.64 for MacOS)}
+@z
+
+@x section 9: Make input_ln accept \n, \r, \n\r, or \r\n as line endings
+@ In the unlikely event that your standard I/O library does not
+support |feof|, |getc|, and |ungetc| you may have to change things here.
+@^system dependencies@>
+
+@c
+int input_ln(fp) /* copies a line into |buffer| or returns 0 */
+FILE *fp; /* what file to read from */
+{
+ register int c=EOF; /* character read; initialized so some compilers won't complain */
+ register char *k; /* where next character goes */
+ if (feof(fp)) return(0); /* we have hit end-of-file */
+ limit = k = buffer; /* beginning of buffer */
+ while (k<=buffer_end && (c=getc(fp)) != EOF && c!='\n')
+ if ((*(k++) = c) != ' ') limit = k;
+ if (k>buffer_end)
+ if ((c=getc(fp))!=EOF && c!='\n') {
+ ungetc(c,fp); loc=buffer; err_print("! Input line too long");
+@.Input line too long@>
+ }
+ if (c==EOF && limit==buffer) return(0); /* there was nothing after
+ the last newline */
+ return(1);
+}
+@y
+@ In the unlikely event that your standard I/O library does not
+support |feof|, |getc|, and |ungetc| you may have to change things here.
+
+This |input_ln| function accepts |"\n"|, |"\r"|, |"\n\r"| and |"\r\n"| as
+line endings, so that \.{CWEB} will works with ASCII files stored in
+\UNIX/, {\mc DOS} or {\mc MAC} format.
+@^system dependencies@>
+
+@c
+int input_ln(fp) /* copies a line into |buffer| or returns 0 */
+FILE *fp; /* what file to read from */
+{
+ register int c=EOF; /* character read; initialized so some compilers won't complain */
+ register char *k; /* where next character goes */
+ if (feof(fp)) return(0); /* we have hit end-of-file */
+ limit = k = buffer; /* beginning of buffer */
+ while (1) {
+ c = getc(fp);
+ if (c==EOF) return (limit!=buffer); /* 0, if there was nothing after
+ the last newline */
+ else if (c=='\n' || c=='\r') { /* we have hit end-of-line */
+ int d = getc(fp);
+ if (c+d!='\n'+'\r') /* no combination |"\n\r"| or |"\r\n"| */
+ ungetc(d,fp);
+ return (1);
+ }
+ else if (k>buffer_end) {
+ ungetc(c,fp); loc=buffer; err_print("! Input line too long");
+ return (1);
+@.Input line too long@>
+ }
+ else
+ if ((*(k++)=c) != ' ') limit = k;
+ }
+}
+@z
+
+@x section 12, simply return if no change file was specified
+ change_limit=change_buffer; /* this value is used if the change file ends */
+ @<Skip over comment lines in the change file; |return| if end of file@>;
+@y
+ change_limit=change_buffer; /* this value is used if the change file ends */
+ if (change_file_name[0] == '\0') /* no change file specified */
+ return; /* so we have reached the end of that file */
+ @<Skip over comment lines in the change file; |return| if end of file@>;
+@z
+
+@x section 19, don't try to open a change file if none was specified
+if ((change_file=fopen(change_file_name,"r"))==NULL)
+ fatal("! Cannot open change file ", change_file_name);
+@y
+if (change_file_name[0] == '\0') /* no change file specified */
+ change_file = NULL; /* reset at least the |change_file| */
+else if ((change_file=fopen(change_file_name,"r"))==NULL)
+ fatal("! Cannot open change file ", change_file_name);
+@z
+
+@x section 22, declare colon as Mac's path separator
+(Colon-separated paths are not supported.)
+The remainder of the \.{@@i} line after the file name is ignored.
+
+@y
+(Colon-separated path alternatives in the style of \UNIX/ or Kpathsea
+are not supported. On a Macintosh, colons are used to separate the names on
+different levels of a path.)
+The remainder of the \.{@@i} line after the file name is ignored.
+
+@d PATH_SEP ':' /* MacOS pathname separator */
+@^system dependencies@>
+@z
+
+@x section 23, use the path separator constant
+ cur_file_name[l]='/'; /* \UNIX/ pathname separator */
+@y
+ cur_file_name[l]=PATH_SEP; /* pathname separator */
+@z
+
+@x section 69, explain the convention for omitted change files
+An omitted change file argument means that |"/dev/null"| should be used,
+@y
+An omitted change file argument means that no change file should be used,
+@z
+
+@x section 70, use the Metrowerks |ccommand| to access command lines
+ while (--argc > 0) {
+@y
+ argc = ccommand (&argv); /* use Mac interface to command line */
+@^system dependencies@>
+ while (--argc > 0) {
+@z
+@x section 70, use the path separator constant
+ else if (*s=='/') dot_pos=NULL,name_pos=++s;
+@y
+ else if (*s==PATH_SEP) dot_pos=NULL,name_pos=++s;
+@z
+@x section 70, make change file name empty when it is unspecified
+ if (found_change<=0) strcpy(change_file_name,"/dev/null");
+@y
+ if (found_change<=0) change_file_name[0]='\0'; /* empty string */
+@z
+
+@x section 82, insert an extra module before the index
+@** Index.
+@y by putting the new module here, we preserve all the previous section numbers
+@ We assume an interface to \CEE/ command-line emulation as supplied by
+the |ccommand| function of Metrowerks CodeWarrior, as defined in
+the header file \.{console.h}.
+
+@<Include files@>=
+#include <console.h>
+@^system dependencies@>
+
+@** Index.
+@z
diff --git a/web/c_cpp/cweb/comm-man.ch b/web/c_cpp/cweb/comm-man.ch
new file mode 100644
index 0000000000..c922c03631
--- /dev/null
+++ b/web/c_cpp/cweb/comm-man.ch
@@ -0,0 +1,22 @@
+Change file to help make Appendix D of the full CWEB manual
+@x
+\def\botofcontents{\vfill
+\noindent
+Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth
+\bigskip\noindent
+Permission is granted to make and distribute verbatim copies of this
+document provided that the copyright notice and this permission notice
+are preserved on all copies.
+
+\smallskip\noindent
+Permission is granted to copy and distribute modified versions of this
+document under the conditions for verbatim copying, provided that the
+entire resulting derived work is given a different name and distributed
+under the terms of a permission notice identical to this one.
+}
+@y
+\def\botofcontents{\vfill\titlefalse}
+\def\contentspagenumber{28}
+\def\title{APPENDIX D: COMMON}
+\let\K=\leftarrow
+@z
diff --git a/web/c_cpp/cweb/comm-os2.ch b/web/c_cpp/cweb/comm-os2.ch
new file mode 100644
index 0000000000..5e20a6706c
--- /dev/null
+++ b/web/c_cpp/cweb/comm-os2.ch
@@ -0,0 +1,24 @@
+This is the change file for CWEB's COMMON under OS/2
+(Contributed by Jim Nutt, jnutt@PrimeNet.Com, May 1995)
+
+These changes tested with WATCOM C v10.0a.
+No changes to CTANGLE or CWEAVE are needed with OS/2.
+
+@x section 69
+An omitted change file argument means that |"/dev/null"| should be used,
+@y
+An omitted change file argument means that |"NUL"| should be used,
+@z
+
+@x section 70 (this change copied from comm-pc.ch)
+ else if (*s=='/') dot_pos=NULL,name_pos=++s;
+@y
+ else if (*s == ':' || *s == '\\' || *s == '/')
+ dot_pos=NULL,name_pos=++s;
+@z
+
+@x section 70
+ if (found_change<=0) strcpy(change_file_name,"/dev/null");
+@y
+ if (found_change<=0) strcpy(change_file_name,"NUL");
+@z
diff --git a/web/c_cpp/cweb/comm-pc.ch b/web/c_cpp/cweb/comm-pc.ch
new file mode 100644
index 0000000000..e69bafb524
--- /dev/null
+++ b/web/c_cpp/cweb/comm-pc.ch
@@ -0,0 +1,33 @@
+This is the change file for CWEB's COMMON under DOS
+(Contributed by Lee Wittenberg, March 1993)
+
+Changes necessary for compiling with Borland C/C++
+Use compilation switches -mc -w-pro -Ff=5000
+
+Note: The change to section 27 is not necessary if using a compiler
+that allows >64K arrays.
+
+@x section 27
+@d max_bytes 90000 /* the number of bytes in identifiers,
+@y
+@d max_bytes (unsigned)60000 /* the number of bytes in identifiers,
+@z
+
+@x section 69
+An omitted change file argument means that |"/dev/null"| should be used,
+@y
+An omitted change file argument means that |"NUL"| should be used,
+@z
+
+@x section 70 (this change copied from comm-bs.ch, July 94)
+ else if (*s=='/') dot_pos=NULL,name_pos=++s;
+@y
+ else if (*s == ':' || *s == '\\' || *s == '/')
+ dot_pos=NULL,name_pos=++s;
+@z
+
+@x section 70
+ if (found_change<=0) strcpy(change_file_name,"/dev/null");
+@y
+ if (found_change<=0) strcpy(change_file_name,"NUL");
+@z
diff --git a/web/c_cpp/cweb/comm-ql.ch b/web/c_cpp/cweb/comm-ql.ch
new file mode 100644
index 0000000000..8859e215b2
--- /dev/null
+++ b/web/c_cpp/cweb/comm-ql.ch
@@ -0,0 +1,332 @@
+This is the change file for CWEB's COMMON under QSOD/SMSQ
+(Contributed by Robert H. Klein, September 1994)
+
+This change file is intended for use with C68 v4.13 (or later).
+compile with
+ex <dev_>cc;'-v -h -c -=500000 -DCWEBINPUTS=flp2_ common_c'
+
+
+
+@x
+\def\v{\char'174} % vertical (|) in typewriter font
+
+\def\title{Common code for CTANGLE and CWEAVE (Version 3.64)}
+\def\topofcontents{\null\vfill
+ \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and
+ {\ttitlefont CWEAVE}}
+ \vskip 15pt
+ \centerline{(Version 3.64)}
+ \vfill}
+\def\botofcontents{\vfill
+\noindent
+@y
+\def\v{\char'174} % vertical (|) in typewriter font
+
+\def\title{Common code for CTANGLE and CWEAVE (QL Version 3.64)}
+\def\topofcontents{\null\vfill
+ \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and
+ {\ttitlefont CWEAVE}}
+ \vskip 15pt
+ \centerline{(Version 3.64)}
+ \vfill}
+\def\botofcontents{\vfill
+\noindent
+@z
+
+@x
+The line number of each open file is also kept for error reporting and
+for the benefit of \.{CTANGLE}.
+
+@f line x /* make |line| an unreserved word */
+@d max_include_depth 10 /* maximum number of source files open
+ simultaneously, not counting the change file */
+@d max_file_name_length 60
+@d cur_file file[include_depth] /* current file */
+@d cur_file_name file_name[include_depth] /* current file name */
+@d cur_line line[include_depth] /* number of current line in current file */
+@d web_file file[0] /* main source file */
+@d web_file_name file_name[0] /* main source file name */
+@y
+The line number of each open file is also kept for error reporting and
+for the benefit of \.{CTANGLE}.
+
+For use on QDOS/SMSQ systems the variable |max_file_name_length| is shortened
+to 42 characters, i.e. 5 characters for the device name, 36 characters
+for the file name plus one character as string terminator. (Note that
+(current) QDOS/SMSQ file systems have a limitation of 36 characters as
+maximum length for a file name.
+
+@f line x /* make |line| an unreserved word */
+@d max_include_depth 10 /* maximum number of source files open
+ simultaneously, not counting the change file */
+@d max_file_name_length 42
+@d cur_file file[include_depth] /* current file */
+@d cur_file_name file_name[include_depth] /* current file name */
+@d cur_line line[include_depth] /* number of current line in current file */
+@d web_file file[0] /* main source file */
+@d web_file_name file_name[0] /* main source file name */
+@z
+
+
+@x
+ cur_file_name[l]='/'; /* \UNIX/ pathname separator */
+@y
+ cur_file_name[l]='_'; /* QDOS/SMSQ pathname separator */
+@z
+
+
+@x
+@ We now must look at the command line arguments and set the file names
+accordingly. At least one file name must be present: the \.{CWEB}
+file. It may have an extension, or it may omit the extension to get |".w"| or
+|".web"| added. The \TEX/ output file name is formed by replacing the \.{CWEB}
+file name extension by |".tex"|, and the \CEE/ file name by replacing
+the extension by |".c"|, after removing the directory name (if any).
+
+If there is a second file name present among the arguments, it is the
+change file, again either with an extension or without one to get |".ch"|.
+An omitted change file argument means that |"/dev/null"| should be used,
+when no changes are desired.
+@^system dependencies@>
+
+If there's a third file name, it will be the output file.
+
+@<Pred...@>=
+void scan_args();
+
+@ @c
+void
+scan_args()
+{
+ char *dot_pos; /* position of |'.'| in the argument */
+ char *name_pos; /* file name beginning, sans directory */
+ register char *s; /* register for scanning strings */
+ boolean found_web=0,found_change=0,found_out=0;
+ /* have these names have been seen? */
+ boolean flag_change;
+
+ while (--argc > 0) {
+ if ((**(++argv)=='-'||**argv=='+')&&*(*argv+1)) @<Handle flag argument@>@;
+ else {
+ s=name_pos=*argv;@+dot_pos=NULL;
+ while (*s) {
+ if (*s=='.') dot_pos=s++;
+ else if (*s=='/') dot_pos=NULL,name_pos=++s;
+ else s++;
+ }
+ if (!found_web) @<Make
+ |web_file_name|, |tex_file_name| and |C_file_name|@>@;
+ else if (!found_change) @<Make |change_file_name| from |fname|@>@;
+ else if (!found_out) @<Override |tex_file_name| and |C_file_name|@>@;
+ else @<Print usage error message and quit@>;
+ }
+ }
+ if (!found_web) @<Print usage error message and quit@>;
+ if (found_change<=0) strcpy(change_file_name,"/dev/null");
+}
+
+@ We use all of |*argv| for the |web_file_name| if there is a |'.'| in it,
+otherwise we add |".w"|. If this file can't be opened, we prepare an
+|alt_web_file_name| by adding |"web"| after the dot.
+The other file names come from adding other things
+after the dot. We must check that there is enough room in
+|web_file_name| and the other arrays for the argument.
+
+@<Make |web_file_name|...@>=
+{
+ if (s-*argv > max_file_name_length-5)
+ @<Complain about argument length@>;
+ if (dot_pos==NULL)
+ sprintf(web_file_name,"%s.w",*argv);
+ else {
+ strcpy(web_file_name,*argv);
+ *dot_pos=0; /* string now ends where the dot was */
+ }
+ sprintf(alt_web_file_name,"%s.web",*argv);
+ sprintf(tex_file_name,"%s.tex",name_pos); /* strip off directory name */
+ sprintf(idx_file_name,"%s.idx",name_pos);
+ sprintf(scn_file_name,"%s.scn",name_pos);
+ sprintf(C_file_name,"%s.c",name_pos);
+ found_web=1;
+}
+
+@ @<Make |change_file_name|...@>=
+{
+ if (strcmp(*argv,"-")==0) found_change=-1;
+ else {
+ if (s-*argv > max_file_name_length-4)
+ @<Complain about argument length@>;
+ if (dot_pos==NULL)
+ sprintf(change_file_name,"%s.ch",*argv);
+ else strcpy(change_file_name,*argv);
+ found_change=1;
+ }
+}
+
+@ @<Override...@>=
+{
+ if (s-*argv > max_file_name_length-5)
+ @<Complain about argument length@>;
+ if (dot_pos==NULL) {
+ sprintf(tex_file_name,"%s.tex",*argv);
+ sprintf(idx_file_name,"%s.idx",*argv);
+ sprintf(scn_file_name,"%s.scn",*argv);
+ sprintf(C_file_name,"%s.c",*argv);
+ } else {
+ strcpy(tex_file_name,*argv);
+ strcpy(C_file_name,*argv);
+ if (flags['x']) { /* indexes will be generated */
+ *dot_pos=0;
+ sprintf(idx_file_name,"%s.idx",*argv);
+ sprintf(scn_file_name,"%s.scn",*argv);
+ }
+ }
+ found_out=1;
+}
+@y
+@ We now must look at the command line arguments and set the file names
+accordingly. At least one file name must be present: the \.{CWEB}
+file. It may have an extension, or it may omit the extension to get |"_w"| or
+|"_web"| added. The \TEX/ output file name is formed by replacing the \.{CWEB}
+file name extension by |"_tex"|, and the \CEE/ file name by replacing
+the extension by |"_c"|, after removing the directory name (if any).
+
+If there is a second file name present among the arguments, it is the
+change file, again either with an extension or without one to get |"_ch"|.
+An omitted change file argument means that |"NUL"| should be used,
+when no changes are desired.
+@^system dependencies@>
+
+If there's a third file name, it will be the output file.
+
+Because |"_"| is a directory {\em and} extension separator, \.{CWEB} will
+always use the {\em full} name (i.e. with full path). Fortunately the
+routine has been written to search for the last ``dot'', so the altered
+version will search for the last |"_"| (including directory separators),
+so we have what we want.
+
+@<Pred...@>=
+void scan_args();
+
+@ @c
+void
+scan_args()
+{
+ char *dot_pos; /* position of |'_'| in the argument */
+ char *name_pos; /* file name beginning, sans directory */
+ register char *s; /* register for scanning strings */
+ boolean found_web=0,found_change=0,found_out=0;
+ /* have these names have been seen? */
+ boolean flag_change;
+
+ while (--argc > 0) {
+ if ((**(++argv)=='-'||**argv=='+')&&*(*argv+1)) @<Handle flag argument@>@;
+ else {
+ s=name_pos=*argv;@+dot_pos=NULL;
+ while (*s) {
+ if (*s=='_') dot_pos=s++;
+ else if (*s=='_') dot_pos=NULL,name_pos=++s;
+ else s++;
+ }
+ if (!found_web) @<Make
+ |web_file_name|, |tex_file_name| and |C_file_name|@>@;
+ else if (!found_change) @<Make |change_file_name| from |fname|@>@;
+ else if (!found_out) @<Override |tex_file_name| and |C_file_name|@>@;
+ else @<Print usage error message and quit@>;
+ }
+ }
+ if (!found_web) @<Print usage error message and quit@>;
+ if (found_change<=0) strcpy(change_file_name,"NUL");
+}
+
+@ We use all of |*argv| for the |web_file_name| if there is a |'_'| in it,
+otherwise we add |"_w"|. If this file can't be opened, we prepare an
+|alt_web_file_name| by adding |"web"| after the dot.
+The other file names come from adding other things
+after the dot. We must check that there is enough room in
+|web_file_name| and the other arrays for the argument.
+
+If you've read the section before carefully you'll have noticed, that
+QDOS/SMSQ file names contain almost a |"_"|, so this routine will not work,
+i.e. you'll {\em have} to add the |"_w"| always. Nevertheless I adapted
+the routine as if it would work.
+
+@<Make |web_file_name|...@>=
+{
+ if (s-*argv > max_file_name_length-5)
+ @<Complain about argument length@>;
+ if (dot_pos==NULL)
+ sprintf(web_file_name,"%s_w",*argv);
+ else {
+ strcpy(web_file_name,*argv);
+ *dot_pos=0; /* string now ends where the dot was */
+ }
+ sprintf(alt_web_file_name,"%s_web",*argv);
+ sprintf(tex_file_name,"%s_tex",name_pos); /* strip off directory name */
+ sprintf(idx_file_name,"%s_idx",name_pos);
+ sprintf(scn_file_name,"%s_scn",name_pos);
+ sprintf(C_file_name,"%s_c",name_pos);
+ found_web=1;
+}
+
+@ @<Make |change_file_name|...@>=
+{
+ if (strcmp(*argv,"-")==0) found_change=-1;
+ else {
+ if (s-*argv > max_file_name_length-4)
+ @<Complain about argument length@>;
+ if (dot_pos==NULL)
+ sprintf(change_file_name,"%s_ch",*argv);
+ else strcpy(change_file_name,*argv);
+ found_change=1;
+ }
+}
+
+@ @<Override...@>=
+{
+ if (s-*argv > max_file_name_length-5)
+ @<Complain about argument length@>;
+ if (dot_pos==NULL) {
+ sprintf(tex_file_name,"%s_tex",*argv);
+ sprintf(idx_file_name,"%s_idx",*argv);
+ sprintf(scn_file_name,"%s_scn",*argv);
+ sprintf(C_file_name,"%s_c",*argv);
+ } else {
+ strcpy(tex_file_name,*argv);
+ strcpy(C_file_name,*argv);
+ if (flags['x']) { /* indexes will be generated */
+ *dot_pos=0;
+ sprintf(idx_file_name,"%s_idx",*argv);
+ sprintf(scn_file_name,"%s_scn",*argv);
+ }
+ }
+ found_out=1;
+}
+@z
+
+
+@x
+@ @<Print usage error message and quit@>=
+{
+if (program==ctangle)
+ fatal(
+"! Usage: ctangle [options] webfile[.w] [{changefile[.ch]|-} [outfile[.c]]]\n"
+ ,"");
+@.Usage:@>
+else fatal(
+"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n"
+ ,"");
+}
+@y
+@ @<Print usage error message and quit@>=
+{
+if (program==ctangle)
+ fatal(
+"! Usage: ctangle [options] webfile[_w] [{changefile[_ch]|-} [outfile[_c]]]\n"
+ ,"");
+@.Usage:@>
+else fatal(
+"! Usage: cweave [options] webfile[_w] [{changefile[_ch]|-} [outfile[_tex]]]\n"
+ ,"");
+}
+@z
diff --git a/web/c_cpp/cweb/comm-vms.ch b/web/c_cpp/cweb/comm-vms.ch
new file mode 100644
index 0000000000..cd5fe52439
--- /dev/null
+++ b/web/c_cpp/cweb/comm-vms.ch
@@ -0,0 +1,81 @@
+This is the change file for CWEB's COMMON under VAX/VMS.
+
+created:
+ 1987 BL (Bjorn Larsen, University of Oslo)
+
+modified:
+ 01-FEB-1992 ST (Stephan Trebels <trebels@ams02.dnet.gwdg.de>)
+ > include ctype,stdio,ssdef from textlibrary SYS$SHARE:VAXCDEF.TLB
+ > change error return code to SS$_ABORT
+ (perhaps better than %NONAME-E-NOMSG, Message number 2 )
+
+(also modified by Don Knuth to match changes in the master file)
+(only the two changes by BL are necessary for initial bootstrapping
+ via hand-editing of common.c)
+
+@x section 5 (01-FEB-1992 ST)
+#include <ctype.h>
+@y
+#include ctype /* VMS searches Textlibraries faster */
+@z
+
+@x section 8 (01-FEB-1992 ST)
+#include <stdio.h>
+@y
+#include stdio /* VMS searches Textlibraries faster */
+@z
+
+@x section 61 (01-FEB-1992 ST)
+programs are started. Here, for instance, we pass the operating system
+a status of 0 if and only if only harmless messages were printed.
+@y
+programs are started. Here, for instance, we pass VAX/VMS
+a status of |SS$_NORMAL| if and only if only harmless
+messages have been printed.
+A suitable status to signal an error condition to VAX/VMS could be
+|SS$_ABORT|, telling the operating system to
+print |"%SYSTEM-F-ABORT, abort"|, if |history > harmless_message|.
+@z
+
+@x section 61 (1987 BL) (01-FEB-1992 ST) (11-JAN-1993 DEK)
+ if (history > harmless_message) return(1);
+ else return(0);
+@y
+/*
+ VAX/VMS and UNIX have different error status conventions.
+ VAX/VMS uses odd values (for example |SS$_NORMAL|) to indicate success,
+ even values indicate errors, resulting in messages displayed
+ on the screen. |SS$_ABORT| has been chosen, to indicate an
+ error and display something that's not complete nonsense.
+*/
+ if (history > harmless_message) exit(SS$_ABORT);
+ else exit(SS$_NORMAL);
+@z
+
+@x section 69 (01-FEB-1992 ST)
+An omitted change file argument means that |"/dev/null"| should be used,
+when no changes are desired.
+@y
+An omitted change file argument means that the
+null device |"NL:"| should be used, when no changes are desired.
+@z
+
+@x section 70 (1987 BL) (01-FEB-1992 ST) (05-APR-1992 DEK)
+ if (found_change<=0) strcpy(change_file_name,"/dev/null");
+@y
+ if (found_change<=) strcpy(change_file_name,"NL:");
+ /* {\tt NL:} is the VAX/VMS notation for {\tt /dev/null} */
+@z
+
+@x section 82 (01-FEB-1992 ST)
+@** Index.
+@y
+@* VAX/VMS specific code.
+We have used |SS$_NORMAL| and |SS$_ABORT| as return codes,
+so we have to include the system message codes.
+
+@<Include files@>=
+#include ssdef /* we need VAX/VMS system messages */
+
+@** Index.
+@z
diff --git a/web/c_cpp/cweb/comm-w32.ch b/web/c_cpp/cweb/comm-w32.ch
new file mode 100644
index 0000000000..b300f496d2
--- /dev/null
+++ b/web/c_cpp/cweb/comm-w32.ch
@@ -0,0 +1,94 @@
+This is the change file for CWEB's COMMON under Win32
+(Contributed by Fabrice Popineau, February 2002 <Fabrice.Popineau@supelec.fr>)
+
+The Microsoft C compiler included in Visual Studio allows for different
+parameter passing conventions than the standard one. This is actually
+specified with the Intel IA32 architecture. There exist three
+calling conventions under the IA32 architecture as defined by Intel.
+
+One of them is the standard C calling convention: Parameters are passed on
+the stack, calling function is responsible to unstack arguments. Names are
+decorated with a prefixed underscore. It is called the __cdecl convention.
+
+Another calling convention is the __fastcall convention. The first two 32bits
+arguments are passed on the stack. The called function is responsible for
+stack maintenance. Names are decorated with an @ sign as prefix, and another
+@ sign followed by the size of the arguments as suffix.
+
+The third one is the __stdcall convention and is basically the Pascal calling
+convention.
+
+Using the __fastcall convention is usually faster on Intel architecture. Names
+are decorated because obviously a __cdecl function can't behave the same way
+as a __fastcall one of the same prototype. So the new full prototype includes
+the keyword __cdecl or __fastcall. A compiler option allows to compile all
+functions using one or the other calling convention. If you compile using
+__fastcall, then you are bound to explicitly declare a few functions as
+__cdecl : the ones that are passed to the C library (like function pointers
+for qsort() or signal()) or functions that replace functions from the C
+library, because the standard headers have a __cdecl prototype for these
+functions. Also, you cannot declare a library function without giving it the
+exact prototype used in the library headers files. So you'd better use the
+header files to be safe.
+
+Admittedly, this is not vital for cweb, except that I build the whole texlive
+set of programs using the __fastcall convention.
+
+@x
+@<Include files@>=
+#include <ctype.h>
+@y
+@<Include files@>=
+#include <ctype.h>
+#include <string.h>
+@z
+
+@x
+@ @<Predec...@>=
+extern int names_match();
+@y
+@ @<Predec...@>=
+extern int __cdecl names_match();
+@z
+
+@x
+@<Pred...@>=
+void init_p();
+@y
+@<Pred...@>=
+void __cdecl init_p();
+@z
+
+@x section 69
+An omitted change file argument means that |"/dev/null"| should be used,
+@y
+An omitted change file argument means that |"NUL"| should be used,
+@z
+
+@x section 70 (this change copied from comm-bs.ch, July 94)
+ else if (*s=='/') dot_pos=NULL,name_pos=++s;
+@y
+ else if (*s == ':' || *s == '\\' || *s == '/')
+ dot_pos=NULL,name_pos=++s;
+@z
+
+@x section 70
+ if (found_change<=0) strcpy(change_file_name,"/dev/null");
+@y
+ if (found_change<=0) strcpy(change_file_name,"NUL");
+@z
+
+@x
+@ We predeclare several standard system functions here instead of including
+their system header files, because the names of the header files are not as
+standard as the names of the functions. (For example, some \CEE/ environments
+have \.{<string.h>} where others have \.{<strings.h>}.)
+
+@<Predecl...@>=
+extern int strlen(); /* length of string */
+extern int strcmp(); /* compare strings lexicographically */
+extern char* strcpy(); /* copy one string to another */
+extern int strncmp(); /* compare up to $n$ string characters */
+extern char* strncpy(); /* copy up to $n$ string characters */
+@y
+@z
diff --git a/web/c_cpp/cweb/common.c b/web/c_cpp/cweb/common.c
new file mode 100644
index 0000000000..2bf7a9d4a8
--- /dev/null
+++ b/web/c_cpp/cweb/common.c
@@ -0,0 +1,1242 @@
+/*1:*/
+#line 58 "common.w"
+
+/*5:*/
+#line 102 "common.w"
+
+#include <ctype.h>
+
+/*:5*//*8:*/
+#line 165 "common.w"
+
+#include <stdio.h>
+
+/*:8*//*22:*/
+#line 471 "common.w"
+
+#include <stdlib.h>
+
+/*:22*/
+#line 59 "common.w"
+
+#define ctangle 0
+#define cweave 1 \
+
+#define and_and 04
+#define lt_lt 020
+#define gt_gt 021
+#define plus_plus 013
+#define minus_minus 01
+#define minus_gt 031
+#define not_eq 032
+#define lt_eq 034
+#define gt_eq 035
+#define eq_eq 036
+#define or_or 037
+#define dot_dot_dot 016
+#define colon_colon 06
+#define period_ast 026
+#define minus_gt_ast 027 \
+
+#define buf_size 100
+#define longest_name 10000
+#define long_buf_size (buf_size+longest_name)
+#define xisspace(c) (isspace(c) &&((unsigned char) c<0200) )
+#define xisupper(c) (isupper(c) &&((unsigned char) c<0200) ) \
+
+#define max_include_depth 10 \
+
+#define max_file_name_length 60
+#define cur_file file[include_depth]
+#define cur_file_name file_name[include_depth]
+#define cur_line line[include_depth]
+#define web_file file[0]
+#define web_file_name file_name[0] \
+
+#define lines_dont_match (change_limit-change_buffer!=limit-buffer|| \
+strncmp(buffer,change_buffer,limit-buffer) ) \
+
+#define if_section_start_make_pending(b) {*limit= '!'; \
+for(loc= buffer;xisspace(*loc) ;loc++) ; \
+*limit= ' '; \
+if(*loc=='@'&&(xisspace(*(loc+1) ) ||*(loc+1) =='*') ) change_pending= b; \
+} \
+
+#define max_sections 2000 \
+ \
+
+#define too_long() {include_depth--; \
+err_print("! Include file name too long") ;goto restart;} \
+
+#define max_bytes 90000 \
+
+#define max_names 4000 \
+ \
+
+#define length(c) (c+1) ->byte_start-(c) ->byte_start
+#define print_id(c) term_write((c) ->byte_start,length((c) ) ) \
+
+#define hash_size 353 \
+
+#define llink link
+#define rlink dummy.Rlink
+#define root name_dir->rlink \
+ \
+
+#define first_chunk(p) ((p) ->byte_start+2)
+#define prefix_length(p) (int) ((unsigned char) *((p) ->byte_start) *256+ \
+(unsigned char) *((p) ->byte_start+1) )
+#define set_prefix_length(p,m) (*((p) ->byte_start) = (m) /256, \
+*((p) ->byte_start+1) = (m) %256) \
+
+#define less 0
+#define equal 1
+#define greater 2
+#define prefix 3
+#define extension 4 \
+
+#define bad_extension 5 \
+
+#define spotless 0
+#define harmless_message 1
+#define error_message 2
+#define fatal_message 3
+#define mark_harmless {if(history==spotless) history= harmless_message;}
+#define mark_error history= error_message \
+
+#define confusion(s) fatal("! This can't happen: ",s) \
+ \
+
+#define show_banner flags['b']
+#define show_progress flags['p']
+#define show_stats flags['s']
+#define show_happiness flags['h'] \
+
+#define update_terminal fflush(stdout) \
+
+#define new_line putchar('\n')
+#define putxchar putchar
+#define term_write(a,b) fflush(stdout) ,fwrite(a,sizeof(char) ,b,stdout)
+#define C_printf(c,a) fprintf(C_file,c,a)
+#define C_putc(c) putc(c,C_file) \
+
+
+#line 60 "common.w"
+
+/*2:*/
+#line 73 "common.w"
+
+typedef short boolean;
+boolean program;
+
+/*:2*//*7:*/
+#line 159 "common.w"
+
+char buffer[long_buf_size];
+char*buffer_end= buffer+buf_size-2;
+char*limit= buffer;
+char*loc= buffer;
+
+/*:7*//*10:*/
+#line 214 "common.w"
+
+int include_depth;
+FILE*file[max_include_depth];
+FILE*change_file;
+char file_name[max_include_depth][max_file_name_length];
+
+char change_file_name[max_file_name_length];
+char alt_web_file_name[max_file_name_length];
+int line[max_include_depth];
+int change_line;
+int change_depth;
+boolean input_has_ended;
+boolean changing;
+boolean web_file_open= 0;
+
+/*:10*//*20:*/
+#line 418 "common.w"
+
+typedef unsigned short sixteen_bits;
+sixteen_bits section_count;
+boolean changed_section[max_sections];
+boolean change_pending;
+
+boolean print_where= 0;
+
+/*:20*//*27:*/
+#line 594 "common.w"
+
+typedef struct name_info{
+char*byte_start;
+/*31:*/
+#line 631 "common.w"
+
+struct name_info*link;
+
+/*:31*//*40:*/
+#line 730 "common.w"
+
+union{
+struct name_info*Rlink;
+
+char Ilk;
+}dummy;
+
+/*:40*//*55:*/
+#line 1062 "common.w"
+
+char*equiv_or_xref;
+
+/*:55*/
+#line 597 "common.w"
+
+}name_info;
+typedef name_info*name_pointer;
+char byte_mem[max_bytes];
+char*byte_mem_end= byte_mem+max_bytes-1;
+name_info name_dir[max_names];
+name_pointer name_dir_end= name_dir+max_names-1;
+
+/*:27*//*29:*/
+#line 617 "common.w"
+
+name_pointer name_ptr;
+char*byte_ptr;
+
+/*:29*//*32:*/
+#line 644 "common.w"
+
+typedef name_pointer*hash_pointer;
+name_pointer hash[hash_size];
+hash_pointer hash_end= hash+hash_size-1;
+hash_pointer h;
+
+/*:32*//*56:*/
+#line 1082 "common.w"
+
+int history= spotless;
+
+/*:56*//*67:*/
+#line 1220 "common.w"
+
+int argc;
+char**argv;
+char C_file_name[max_file_name_length];
+char tex_file_name[max_file_name_length];
+char idx_file_name[max_file_name_length];
+char scn_file_name[max_file_name_length];
+boolean flags[128];
+
+/*:67*//*77:*/
+#line 1370 "common.w"
+
+FILE*C_file;
+FILE*tex_file;
+FILE*idx_file;
+FILE*scn_file;
+FILE*active_file;
+
+/*:77*/
+#line 61 "common.w"
+
+/*3:*/
+#line 83 "common.w"
+int phase;
+
+/*:3*//*11:*/
+#line 240 "common.w"
+
+char change_buffer[buf_size];
+char*change_limit;
+
+/*:11*/
+#line 62 "common.w"
+
+/*33:*/
+#line 650 "common.w"
+
+extern int names_match();
+
+/*:33*//*38:*/
+#line 703 "common.w"
+
+void init_p();
+
+/*:38*//*46:*/
+#line 852 "common.w"
+
+extern void init_node();
+
+/*:46*//*53:*/
+#line 1017 "common.w"
+
+int section_name_cmp();
+
+/*:53*//*57:*/
+#line 1092 "common.w"
+
+void err_print();
+
+/*:57*//*60:*/
+#line 1140 "common.w"
+
+int wrap_up();
+extern void print_stats();
+
+/*:60*//*63:*/
+#line 1173 "common.w"
+
+void fatal(),overflow();
+
+/*:63*//*69:*/
+#line 1251 "common.w"
+
+void scan_args();
+
+/*:69*//*81:*/
+#line 1411 "common.w"
+
+extern int strlen();
+extern int strcmp();
+extern char*strcpy();
+extern int strncmp();
+extern char*strncpy();
+
+/*:81*/
+#line 63 "common.w"
+
+
+/*:1*//*4:*/
+#line 89 "common.w"
+
+void
+common_init()
+{
+/*30:*/
+#line 621 "common.w"
+
+name_dir->byte_start= byte_ptr= byte_mem;
+name_ptr= name_dir+1;
+name_ptr->byte_start= byte_mem;
+
+/*:30*//*34:*/
+#line 655 "common.w"
+
+for(h= hash;h<=hash_end;*h++= NULL);
+
+/*:34*//*41:*/
+#line 737 "common.w"
+
+root= NULL;
+
+/*:41*/
+#line 93 "common.w"
+;
+/*68:*/
+#line 1233 "common.w"
+
+show_banner= show_happiness= show_progress= 1;
+
+/*:68*/
+#line 94 "common.w"
+;
+/*78:*/
+#line 1377 "common.w"
+
+scan_args();
+if(program==ctangle){
+if((C_file= fopen(C_file_name,"w"))==NULL)
+fatal("! Cannot open output file ",C_file_name);
+
+}
+else{
+if((tex_file= fopen(tex_file_name,"w"))==NULL)
+fatal("! Cannot open output file ",tex_file_name);
+}
+
+/*:78*/
+#line 95 "common.w"
+;
+}
+
+/*:4*//*9:*/
+#line 172 "common.w"
+
+int input_ln(fp)
+FILE*fp;
+{
+register int c= EOF;
+register char*k;
+if(feof(fp))return(0);
+limit= k= buffer;
+while(k<=buffer_end&&(c= getc(fp))!=EOF&&c!='\n')
+if((*(k++)= c)!=' ')limit= k;
+if(k> buffer_end)
+if((c= getc(fp))!=EOF&&c!='\n'){
+ungetc(c,fp);loc= buffer;err_print("! Input line too long");
+
+}
+if(c==EOF&&limit==buffer)return(0);
+
+return(1);
+}
+
+/*:9*//*12:*/
+#line 251 "common.w"
+
+void
+prime_the_change_buffer()
+{
+change_limit= change_buffer;
+/*13:*/
+#line 265 "common.w"
+
+while(1){
+change_line++;
+if(!input_ln(change_file))return;
+if(limit<buffer+2)continue;
+if(buffer[0]!='@')continue;
+if(xisupper(buffer[1]))buffer[1]= tolower(buffer[1]);
+if(buffer[1]=='x')break;
+if(buffer[1]=='y'||buffer[1]=='z'||buffer[1]=='i'){
+loc= buffer+2;
+err_print("! Missing @x in change file");
+
+}
+}
+
+/*:13*/
+#line 256 "common.w"
+;
+/*14:*/
+#line 282 "common.w"
+
+do{
+change_line++;
+if(!input_ln(change_file)){
+err_print("! Change file ended after @x");
+
+return;
+}
+}while(limit==buffer);
+
+/*:14*/
+#line 257 "common.w"
+;
+/*15:*/
+#line 292 "common.w"
+
+{
+change_limit= change_buffer+(limit-buffer);
+strncpy(change_buffer,buffer,limit-buffer+1);
+}
+
+/*:15*/
+#line 258 "common.w"
+;
+}
+
+/*:12*//*16:*/
+#line 320 "common.w"
+
+void
+check_change()
+{
+int n= 0;
+if(lines_dont_match)return;
+change_pending= 0;
+if(!changed_section[section_count]){
+if_section_start_make_pending(1);
+if(!change_pending)changed_section[section_count]= 1;
+}
+while(1){
+changing= 1;print_where= 1;change_line++;
+if(!input_ln(change_file)){
+err_print("! Change file ended before @y");
+
+change_limit= change_buffer;changing= 0;
+return;
+}
+if(limit> buffer+1&&buffer[0]=='@'){
+char xyz_code= xisupper(buffer[1])?tolower(buffer[1]):buffer[1];
+/*17:*/
+#line 358 "common.w"
+
+if(xyz_code=='x'||xyz_code=='z'){
+loc= buffer+2;err_print("! Where is the matching @y?");
+
+}
+else if(xyz_code=='y'){
+if(n> 0){
+loc= buffer+2;
+printf("\n! Hmm... %d ",n);
+err_print("of the preceding lines failed to match");
+
+}
+change_depth= include_depth;
+return;
+}
+
+/*:17*/
+#line 342 "common.w"
+;
+}
+/*15:*/
+#line 292 "common.w"
+
+{
+change_limit= change_buffer+(limit-buffer);
+strncpy(change_buffer,buffer,limit-buffer+1);
+}
+
+/*:15*/
+#line 344 "common.w"
+;
+changing= 0;cur_line++;
+while(!input_ln(cur_file)){
+if(include_depth==0){
+err_print("! CWEB file ended during a change");
+
+input_has_ended= 1;return;
+}
+include_depth--;cur_line++;
+}
+if(lines_dont_match)n++;
+}
+}
+
+/*:16*//*18:*/
+#line 378 "common.w"
+
+void
+reset_input()
+{
+limit= buffer;loc= buffer+1;buffer[0]= ' ';
+/*19:*/
+#line 393 "common.w"
+
+if((web_file= fopen(web_file_name,"r"))==NULL){
+strcpy(web_file_name,alt_web_file_name);
+if((web_file= fopen(web_file_name,"r"))==NULL)
+fatal("! Cannot open input file ",web_file_name);
+}
+
+
+web_file_open= 1;
+if((change_file= fopen(change_file_name,"r"))==NULL)
+fatal("! Cannot open change file ",change_file_name);
+
+/*:19*/
+#line 383 "common.w"
+;
+include_depth= 0;cur_line= 0;change_line= 0;
+change_depth= include_depth;
+changing= 1;prime_the_change_buffer();changing= !changing;
+limit= buffer;loc= buffer+1;buffer[0]= ' ';input_has_ended= 0;
+}
+
+/*:18*//*21:*/
+#line 426 "common.w"
+
+int get_line()
+{
+restart:
+if(changing&&include_depth==change_depth)
+/*25:*/
+#line 537 "common.w"
+{
+change_line++;
+if(!input_ln(change_file)){
+err_print("! Change file ended without @z");
+
+buffer[0]= '@';buffer[1]= 'z';limit= buffer+2;
+}
+if(limit> buffer){
+if(change_pending){
+if_section_start_make_pending(0);
+if(change_pending){
+changed_section[section_count]= 1;change_pending= 0;
+}
+}
+*limit= ' ';
+if(buffer[0]=='@'){
+if(xisupper(buffer[1]))buffer[1]= tolower(buffer[1]);
+if(buffer[1]=='x'||buffer[1]=='y'){
+loc= buffer+2;
+err_print("! Where is the matching @z?");
+
+}
+else if(buffer[1]=='z'){
+prime_the_change_buffer();changing= !changing;print_where= 1;
+}
+}
+}
+}
+
+/*:25*/
+#line 431 "common.w"
+;
+if(!changing||include_depth> change_depth){
+/*24:*/
+#line 520 "common.w"
+{
+cur_line++;
+while(!input_ln(cur_file)){
+print_where= 1;
+if(include_depth==0){input_has_ended= 1;break;}
+else{
+fclose(cur_file);include_depth--;
+if(changing&&include_depth==change_depth)break;
+cur_line++;
+}
+}
+if(!changing&&!input_has_ended)
+if(limit-buffer==change_limit-change_buffer)
+if(buffer[0]==change_buffer[0])
+if(change_limit> change_buffer)check_change();
+}
+
+/*:24*/
+#line 433 "common.w"
+;
+if(changing&&include_depth==change_depth)goto restart;
+}
+if(input_has_ended)return 0;
+loc= buffer;*limit= ' ';
+if(buffer[0]=='@'&&(buffer[1]=='i'||buffer[1]=='I')){
+loc= buffer+2;*limit= '"';
+while(*loc==' '||*loc=='\t')loc++;
+if(loc>=limit){
+err_print("! Include file name not given");
+
+goto restart;
+}
+if(include_depth>=max_include_depth-1){
+err_print("! Too many nested includes");
+
+goto restart;
+}
+include_depth++;
+/*23:*/
+#line 474 "common.w"
+{
+char temp_file_name[max_file_name_length];
+char*cur_file_name_end= cur_file_name+max_file_name_length-1;
+char*k= cur_file_name,*kk;
+int l;
+
+if(*loc=='"'){
+loc++;
+while(*loc!='"'&&k<=cur_file_name_end)*k++= *loc++;
+if(loc==limit)k= cur_file_name_end+1;
+}else
+while(*loc!=' '&&*loc!='\t'&&*loc!='"'&&k<=cur_file_name_end)*k++= *loc++;
+if(k> cur_file_name_end)too_long();
+
+*k= '\0';
+if((cur_file= fopen(cur_file_name,"r"))!=NULL){
+cur_line= 0;print_where= 1;
+goto restart;
+}
+kk= getenv("CWEBINPUTS");
+if(kk!=NULL){
+if((l= strlen(kk))> max_file_name_length-2)too_long();
+strcpy(temp_file_name,kk);
+}
+else{
+#ifdef CWEBINPUTS
+if((l= strlen(CWEBINPUTS))> max_file_name_length-2)too_long();
+strcpy(temp_file_name,CWEBINPUTS);
+#else
+l= 0;
+#endif
+}
+if(l> 0){
+if(k+l+2>=cur_file_name_end)too_long();
+
+for(;k>=cur_file_name;k--)*(k+l+1)= *k;
+strcpy(cur_file_name,temp_file_name);
+cur_file_name[l]= '/';
+if((cur_file= fopen(cur_file_name,"r"))!=NULL){
+cur_line= 0;print_where= 1;
+goto restart;
+}
+}
+include_depth--;err_print("! Cannot open include file");goto restart;
+}
+
+/*:23*/
+#line 452 "common.w"
+;
+}
+return 1;
+}
+
+/*:21*//*26:*/
+#line 569 "common.w"
+
+void
+check_complete(){
+if(change_limit!=change_buffer){
+strncpy(buffer,change_buffer,change_limit-change_buffer+1);
+limit= buffer+(int)(change_limit-change_buffer);
+changing= 1;change_depth= include_depth;loc= buffer;
+err_print("! Change file entry did not match");
+
+}
+}
+
+/*:26*//*35:*/
+#line 660 "common.w"
+
+name_pointer
+id_lookup(first,last,t)
+char*first;
+char*last;
+char t;
+{
+char*i= first;
+int h;
+int l;
+name_pointer p;
+if(last==NULL)for(last= first;*last!='\0';last++);
+l= last-first;
+/*36:*/
+#line 683 "common.w"
+
+h= (unsigned char)*i;
+while(++i<last)h= (h+h+(int)((unsigned char)*i))%hash_size;
+
+
+/*:36*/
+#line 673 "common.w"
+;
+/*37:*/
+#line 691 "common.w"
+
+p= hash[h];
+while(p&&!names_match(p,first,l,t))p= p->link;
+if(p==NULL){
+p= name_ptr;
+p->link= hash[h];hash[h]= p;
+}
+
+/*:37*/
+#line 674 "common.w"
+;
+if(p==name_ptr)/*39:*/
+#line 706 "common.w"
+{
+if(byte_ptr+l> byte_mem_end)overflow("byte memory");
+if(name_ptr>=name_dir_end)overflow("name");
+strncpy(byte_ptr,first,l);
+(++name_ptr)->byte_start= byte_ptr+= l;
+if(program==cweave)init_p(p,t);
+}
+
+/*:39*/
+#line 675 "common.w"
+;
+return(p);
+}
+
+/*:35*//*42:*/
+#line 764 "common.w"
+
+void
+print_section_name(p)
+name_pointer p;
+{
+char*ss,*s= first_chunk(p);
+name_pointer q= p+1;
+while(p!=name_dir){
+ss= (p+1)->byte_start-1;
+if(*ss==' '&&ss>=s){
+term_write(s,ss-s);p= q->link;q= p;
+}else{
+term_write(s,ss+1-s);p= name_dir;q= NULL;
+}
+s= p->byte_start;
+}
+if(q)term_write("...",3);
+}
+
+/*:42*//*43:*/
+#line 783 "common.w"
+
+void
+sprint_section_name(dest,p)
+char*dest;
+name_pointer p;
+{
+char*ss,*s= first_chunk(p);
+name_pointer q= p+1;
+while(p!=name_dir){
+ss= (p+1)->byte_start-1;
+if(*ss==' '&&ss>=s){
+p= q->link;q= p;
+}else{
+ss++;p= name_dir;
+}
+strncpy(dest,s,ss-s),dest+= ss-s;
+s= p->byte_start;
+}
+*dest= '\0';
+}
+
+/*:43*//*44:*/
+#line 804 "common.w"
+
+void
+print_prefix_name(p)
+name_pointer p;
+{
+char*s= first_chunk(p);
+int l= prefix_length(p);
+term_write(s,l);
+if(s+l<(p+1)->byte_start)term_write("...",3);
+}
+
+/*:44*//*45:*/
+#line 825 "common.w"
+
+int web_strcmp(j,j_len,k,k_len)
+char*j,*k;
+int j_len,k_len;
+{
+char*j1= j+j_len,*k1= k+k_len;
+while(k<k1&&j<j1&&*j==*k)k++,j++;
+if(k==k1)if(j==j1)return equal;
+else return extension;
+else if(j==j1)return prefix;
+else if(*j<*k)return less;
+else return greater;
+}
+
+/*:45*//*47:*/
+#line 855 "common.w"
+
+name_pointer
+add_section_name(par,c,first,last,ispref)
+name_pointer par;
+int c;
+char*first;
+char*last;
+int ispref;
+{
+name_pointer p= name_ptr;
+char*s= first_chunk(p);
+int name_len= last-first+ispref;
+if(s+name_len> byte_mem_end)overflow("byte memory");
+if(name_ptr+1>=name_dir_end)overflow("name");
+(++name_ptr)->byte_start= byte_ptr= s+name_len;
+if(ispref){
+*(byte_ptr-1)= ' ';
+name_len--;
+name_ptr->link= name_dir;
+(++name_ptr)->byte_start= byte_ptr;
+}
+set_prefix_length(p,name_len);
+strncpy(s,first,name_len);
+p->llink= NULL;
+p->rlink= NULL;
+init_node(p);
+return par==NULL?(root= p):c==less?(par->llink= p):(par->rlink= p);
+}
+
+/*:47*//*48:*/
+#line 884 "common.w"
+
+void
+extend_section_name(p,first,last,ispref)
+name_pointer p;
+char*first;
+char*last;
+int ispref;
+{
+char*s;
+name_pointer q= p+1;
+int name_len= last-first+ispref;
+if(name_ptr>=name_dir_end)overflow("name");
+while(q->link!=name_dir)q= q->link;
+q->link= name_ptr;
+s= name_ptr->byte_start;
+name_ptr->link= name_dir;
+if(s+name_len> byte_mem_end)overflow("byte memory");
+(++name_ptr)->byte_start= byte_ptr= s+name_len;
+strncpy(s,first,name_len);
+if(ispref)*(byte_ptr-1)= ' ';
+}
+
+/*:48*//*49:*/
+#line 912 "common.w"
+
+name_pointer
+section_lookup(first,last,ispref)
+char*first,*last;
+int ispref;
+{
+int c= 0;
+name_pointer p= root;
+name_pointer q= NULL;
+name_pointer r= NULL;
+name_pointer par= NULL;
+
+int name_len= last-first+1;
+/*50:*/
+#line 936 "common.w"
+
+while(p){
+c= web_strcmp(first,name_len,first_chunk(p),prefix_length(p));
+if(c==less||c==greater){
+if(r==NULL)
+par= p;
+p= (c==less?p->llink:p->rlink);
+}else{
+if(r!=NULL){
+printf("\n! Ambiguous prefix: matches <");
+
+print_prefix_name(p);
+printf(">\n and <");
+print_prefix_name(r);
+err_print(">");
+return name_dir;
+}
+r= p;
+p= p->llink;
+q= r->rlink;
+}
+if(p==NULL)
+p= q,q= NULL;
+}
+
+/*:50*/
+#line 926 "common.w"
+;
+/*51:*/
+#line 961 "common.w"
+
+if(r==NULL)
+return add_section_name(par,c,first,last+1,ispref);
+
+/*:51*/
+#line 927 "common.w"
+;
+/*52:*/
+#line 969 "common.w"
+
+switch(section_name_cmp(&first,name_len,r)){
+
+case prefix:
+if(!ispref){
+printf("\n! New name is a prefix of <");
+
+print_section_name(r);
+err_print(">");
+}
+else if(name_len<prefix_length(r))set_prefix_length(r,name_len);
+
+case equal:return r;
+case extension:if(!ispref||first<=last)
+extend_section_name(r,first,last+1,ispref);
+return r;
+case bad_extension:
+printf("\n! New name extends <");
+
+print_section_name(r);
+err_print(">");
+return r;
+default:
+printf("\n! Section name incompatible with <");
+
+print_prefix_name(r);
+printf(">,\n which abbreviates <");
+print_section_name(r);
+err_print(">");
+return r;
+}
+
+/*:52*/
+#line 928 "common.w"
+;
+}
+
+/*:49*//*54:*/
+#line 1020 "common.w"
+
+int section_name_cmp(pfirst,len,r)
+char**pfirst;
+int len;
+name_pointer r;
+{
+char*first= *pfirst;
+name_pointer q= r+1;
+char*ss,*s= first_chunk(r);
+int c;
+int ispref;
+while(1){
+ss= (r+1)->byte_start-1;
+if(*ss==' '&&ss>=r->byte_start)ispref= 1,q= q->link;
+else ispref= 0,ss++,q= name_dir;
+switch(c= web_strcmp(first,len,s,ss-s)){
+case equal:if(q==name_dir)
+if(ispref){
+*pfirst= first+(ss-s);
+return extension;
+}else return equal;
+else return(q->byte_start==(q+1)->byte_start)?equal:prefix;
+case extension:
+if(!ispref)return bad_extension;
+first+= ss-s;
+if(q!=name_dir){len-= ss-s;s= q->byte_start;r= q;continue;}
+*pfirst= first;return extension;
+default:return c;
+}
+}
+}
+
+/*:54*//*58:*/
+#line 1095 "common.w"
+
+void
+err_print(s)
+char*s;
+{
+char*k,*l;
+printf(*s=='!'?"\n%s":"%s",s);
+if(web_file_open)/*59:*/
+#line 1115 "common.w"
+
+{if(changing&&include_depth==change_depth)
+printf(". (l. %d of change file)\n",change_line);
+else if(include_depth==0)printf(". (l. %d)\n",cur_line);
+else printf(". (l. %d of include file %s)\n",cur_line,cur_file_name);
+l= (loc>=limit?limit:loc);
+if(l> buffer){
+for(k= buffer;k<l;k++)
+if(*k=='\t')putchar(' ');
+else putchar(*k);
+putchar('\n');
+for(k= buffer;k<l;k++)putchar(' ');
+}
+for(k= l;k<limit;k++)putchar(*k);
+if(*limit=='|')putchar('|');
+putchar(' ');
+}
+
+/*:59*/
+#line 1102 "common.w"
+;
+update_terminal;mark_error;
+}
+
+/*:58*//*61:*/
+#line 1150 "common.w"
+
+int wrap_up(){
+putchar('\n');
+if(show_stats)
+print_stats();
+/*62:*/
+#line 1160 "common.w"
+
+switch(history){
+case spotless:if(show_happiness)printf("(No errors were found.)\n");break;
+case harmless_message:
+printf("(Did you see the warning message above?)\n");break;
+case error_message:
+printf("(Pardon me, but I think I spotted something wrong.)\n");break;
+case fatal_message:printf("(That was a fatal error, my friend.)\n");
+}
+
+/*:62*/
+#line 1155 "common.w"
+;
+if(history> harmless_message)return(1);
+else return(0);
+}
+
+/*:61*//*64:*/
+#line 1179 "common.w"
+void
+fatal(s,t)
+char*s,*t;
+{
+if(*s)printf(s);
+err_print(t);
+history= fatal_message;exit(wrap_up());
+}
+
+/*:64*//*65:*/
+#line 1190 "common.w"
+void
+overflow(t)
+char*t;
+{
+printf("\n! Sorry, %s capacity exceeded",t);fatal("","");
+}
+
+
+/*:65*//*70:*/
+#line 1254 "common.w"
+
+void
+scan_args()
+{
+char*dot_pos;
+char*name_pos;
+register char*s;
+boolean found_web= 0,found_change= 0,found_out= 0;
+
+boolean flag_change;
+
+while(--argc> 0){
+if((**(++argv)=='-'||**argv=='+')&&*(*argv+1))/*74:*/
+#line 1344 "common.w"
+
+{
+if(**argv=='-')flag_change= 0;
+else flag_change= 1;
+for(dot_pos= *argv+1;*dot_pos> '\0';dot_pos++)
+flags[*dot_pos]= flag_change;
+}
+
+/*:74*/
+#line 1266 "common.w"
+
+else{
+s= name_pos= *argv;dot_pos= NULL;
+while(*s){
+if(*s=='.')dot_pos= s++;
+else if(*s=='/')dot_pos= NULL,name_pos= ++s;
+else s++;
+}
+if(!found_web)/*71:*/
+#line 1292 "common.w"
+
+{
+if(s-*argv> max_file_name_length-5)
+/*76:*/
+#line 1364 "common.w"
+fatal("! Filename too long\n",*argv);
+
+
+/*:76*/
+#line 1295 "common.w"
+;
+if(dot_pos==NULL)
+sprintf(web_file_name,"%s.w",*argv);
+else{
+strcpy(web_file_name,*argv);
+*dot_pos= 0;
+}
+sprintf(alt_web_file_name,"%s.web",*argv);
+sprintf(tex_file_name,"%s.tex",name_pos);
+sprintf(idx_file_name,"%s.idx",name_pos);
+sprintf(scn_file_name,"%s.scn",name_pos);
+sprintf(C_file_name,"%s.c",name_pos);
+found_web= 1;
+}
+
+/*:71*/
+#line 1275 "common.w"
+
+else if(!found_change)/*72:*/
+#line 1310 "common.w"
+
+{
+if(strcmp(*argv,"-")==0)found_change= -1;
+else{
+if(s-*argv> max_file_name_length-4)
+/*76:*/
+#line 1364 "common.w"
+fatal("! Filename too long\n",*argv);
+
+
+/*:76*/
+#line 1315 "common.w"
+;
+if(dot_pos==NULL)
+sprintf(change_file_name,"%s.ch",*argv);
+else strcpy(change_file_name,*argv);
+found_change= 1;
+}
+}
+
+/*:72*/
+#line 1276 "common.w"
+
+else if(!found_out)/*73:*/
+#line 1323 "common.w"
+
+{
+if(s-*argv> max_file_name_length-5)
+/*76:*/
+#line 1364 "common.w"
+fatal("! Filename too long\n",*argv);
+
+
+/*:76*/
+#line 1326 "common.w"
+;
+if(dot_pos==NULL){
+sprintf(tex_file_name,"%s.tex",*argv);
+sprintf(idx_file_name,"%s.idx",*argv);
+sprintf(scn_file_name,"%s.scn",*argv);
+sprintf(C_file_name,"%s.c",*argv);
+}else{
+strcpy(tex_file_name,*argv);
+strcpy(C_file_name,*argv);
+if(flags['x']){
+*dot_pos= 0;
+sprintf(idx_file_name,"%s.idx",*argv);
+sprintf(scn_file_name,"%s.scn",*argv);
+}
+}
+found_out= 1;
+}
+
+/*:73*/
+#line 1277 "common.w"
+
+else/*75:*/
+#line 1352 "common.w"
+
+{
+if(program==ctangle)
+fatal(
+"! Usage: ctangle [options] webfile[.w] [{changefile[.ch]|-} [outfile[.c]]]\n"
+,"");
+
+else fatal(
+"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n"
+,"");
+}
+
+/*:75*/
+#line 1278 "common.w"
+;
+}
+}
+if(!found_web)/*75:*/
+#line 1352 "common.w"
+
+{
+if(program==ctangle)
+fatal(
+"! Usage: ctangle [options] webfile[.w] [{changefile[.ch]|-} [outfile[.c]]]\n"
+,"");
+
+else fatal(
+"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n"
+,"");
+}
+
+/*:75*/
+#line 1281 "common.w"
+;
+if(found_change<=0)strcpy(change_file_name,"/dev/null");
+}
+
+/*:70*/
diff --git a/web/c_cpp/cweb/common.h b/web/c_cpp/cweb/common.h
new file mode 100644
index 0000000000..d6c0bfb601
--- /dev/null
+++ b/web/c_cpp/cweb/common.h
@@ -0,0 +1,193 @@
+% This file is part of CWEB.
+% This program by Silvio Levy and Donald E. Knuth
+% is based on a program by Knuth.
+% It is distributed WITHOUT ANY WARRANTY, express or implied.
+% Version 3.64 --- February 2017 (works also with later versions)
+
+% Copyright (C) 1987,1990,1993 Silvio Levy and Donald E. Knuth
+
+% Permission is granted to make and distribute verbatim copies of this
+% document provided that the copyright notice and this permission notice
+% are preserved on all copies.
+
+% Permission is granted to copy and distribute modified versions of this
+% document 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.
+
+% Please send comments, suggestions, etc. to levy@@math.berkeley.edu.
+
+% The next few sections contain stuff from the file |"common.w"| that has
+% to be included in both |"ctangle.w"| and |"cweave.w"|. It appears in this
+% file |"common.h"|, which needs to be updated when |"common.w"| changes.
+
+First comes general stuff:
+
+@d ctangle 0
+@d cweave 1
+
+@<Common code for \.{CWEAVE} and \.{CTANGLE}@>=
+typedef short boolean;
+typedef char unsigned eight_bits;
+extern boolean program; /* \.{CWEAVE} or \.{CTANGLE}? */
+extern int phase; /* which phase are we in? */
+
+@ @<Include files@>=
+#include <stdio.h>
+
+@ Code related to the character set:
+@^ASCII code dependencies@>
+
+@d and_and 04 /* `\.{\&\&}'\,; corresponds to MIT's {\tentex\char'4} */
+@d lt_lt 020 /* `\.{<<}'\,; corresponds to MIT's {\tentex\char'20} */
+@d gt_gt 021 /* `\.{>>}'\,; corresponds to MIT's {\tentex\char'21} */
+@d plus_plus 013 /* `\.{++}'\,; corresponds to MIT's {\tentex\char'13} */
+@d minus_minus 01 /* `\.{--}'\,; corresponds to MIT's {\tentex\char'1} */
+@d minus_gt 031 /* `\.{->}'\,; corresponds to MIT's {\tentex\char'31} */
+@d not_eq 032 /* `\.{!=}'\,; corresponds to MIT's {\tentex\char'32} */
+@d lt_eq 034 /* `\.{<=}'\,; corresponds to MIT's {\tentex\char'34} */
+@d gt_eq 035 /* `\.{>=}'\,; corresponds to MIT's {\tentex\char'35} */
+@d eq_eq 036 /* `\.{==}'\,; corresponds to MIT's {\tentex\char'36} */
+@d or_or 037 /* `\.{\v\v}'\,; corresponds to MIT's {\tentex\char'37} */
+@d dot_dot_dot 016 /* `\.{...}'\,; corresponds to MIT's {\tentex\char'16} */
+@d colon_colon 06 /* `\.{::}'\,; corresponds to MIT's {\tentex\char'6} */
+@d period_ast 026 /* `\.{.*}'\,; corresponds to MIT's {\tentex\char'26} */
+@d minus_gt_ast 027 /* `\.{->*}'\,; corresponds to MIT's {\tentex\char'27} */
+
+@<Common code...@>=
+char section_text[longest_name+1]; /* name being sought for */
+char *section_text_end = section_text+longest_name; /* end of |section_text| */
+char *id_first; /* where the current identifier begins in the buffer */
+char *id_loc; /* just after the current identifier in the buffer */
+
+@ Code related to input routines:
+
+@d xisalpha(c) (isalpha(c)&&((eight_bits)c<0200))
+@d xisdigit(c) (isdigit(c)&&((eight_bits)c<0200))
+@d xisspace(c) (isspace(c)&&((eight_bits)c<0200))
+@d xislower(c) (islower(c)&&((eight_bits)c<0200))
+@d xisupper(c) (isupper(c)&&((eight_bits)c<0200))
+@d xisxdigit(c) (isxdigit(c)&&((eight_bits)c<0200))
+
+@<Common code...@>=
+extern char buffer[]; /* where each line of input goes */
+extern char *buffer_end; /* end of |buffer| */
+extern char *loc; /* points to the next character to be read from the buffer*/
+extern char *limit; /* points to the last character in the buffer */
+
+@ Code related to identifier and section name storage:
+@d length(c) (c+1)->byte_start-(c)->byte_start /* the length of a name */
+@d print_id(c) term_write((c)->byte_start,length((c))) /* print identifier */
+@d llink link /* left link in binary search tree for section names */
+@d rlink dummy.Rlink /* right link in binary search tree for section names */
+@d root name_dir->rlink /* the root of the binary search tree
+ for section names */
+@d chunk_marker 0
+
+@<Common code...@>=
+typedef struct name_info {
+ char *byte_start; /* beginning of the name in |byte_mem| */
+ struct name_info *link;
+ union {
+ struct name_info *Rlink; /* right link in binary search tree for section
+ names */
+ char Ilk; /* used by identifiers in \.{CWEAVE} only */
+ } dummy;
+ char *equiv_or_xref; /* info corresponding to names */
+} name_info; /* contains information about an identifier or section name */
+typedef name_info *name_pointer; /* pointer into array of \&{name\_info}s */
+typedef name_pointer *hash_pointer;
+extern char byte_mem[]; /* characters of names */
+extern char *byte_mem_end; /* end of |byte_mem| */
+extern name_info name_dir[]; /* information about names */
+extern name_pointer name_dir_end; /* end of |name_dir| */
+extern name_pointer name_ptr; /* first unused position in |name_dir| */
+extern char *byte_ptr; /* first unused position in |byte_mem| */
+extern name_pointer hash[]; /* heads of hash lists */
+extern hash_pointer hash_end; /* end of |hash| */
+extern hash_pointer h; /* index into hash-head array */
+extern name_pointer id_lookup(); /* looks up a string in the identifier table */
+extern name_pointer section_lookup(); /* finds section name */
+extern void print_section_name(), sprint_section_name();
+
+@ Code related to error handling:
+@d spotless 0 /* |history| value for normal jobs */
+@d harmless_message 1 /* |history| value when non-serious info was printed */
+@d error_message 2 /* |history| value when an error was noted */
+@d fatal_message 3 /* |history| value when we had to stop prematurely */
+@d mark_harmless {if (history==spotless) history=harmless_message;}
+@d mark_error history=error_message
+@d confusion(s) fatal("! This can't happen: ",s)
+
+@<Common...@>=
+extern history; /* indicates how bad this run was */
+extern err_print(); /* print error message and context */
+extern wrap_up(); /* indicate |history| and exit */
+extern void fatal(); /* issue error message and die */
+extern void overflow(); /* succumb because a table has overflowed */
+
+@ Code related to file handling:
+@f line x /* make |line| an unreserved word */
+@d max_file_name_length 60
+@d cur_file file[include_depth] /* current file */
+@d cur_file_name file_name[include_depth] /* current file name */
+@d web_file_name file_name[0] /* main source file name */
+@d cur_line line[include_depth] /* number of current line in current file */
+
+@<Common code...@>=
+extern include_depth; /* current level of nesting */
+extern FILE *file[]; /* stack of non-change files */
+extern FILE *change_file; /* change file */
+extern char C_file_name[]; /* name of |C_file| */
+extern char tex_file_name[]; /* name of |tex_file| */
+extern char idx_file_name[]; /* name of |idx_file| */
+extern char scn_file_name[]; /* name of |scn_file| */
+extern char file_name[][max_file_name_length];
+ /* stack of non-change file names */
+extern char change_file_name[]; /* name of change file */
+extern line[]; /* number of current line in the stacked files */
+extern change_line; /* number of current line in change file */
+extern change_depth; /* where \.{@@y} originated during a change */
+extern boolean input_has_ended; /* if there is no more input */
+extern boolean changing; /* if the current line is from |change_file| */
+extern boolean web_file_open; /* if the web file is being read */
+extern reset_input(); /* initialize to read the web file and change file */
+extern get_line(); /* inputs the next line */
+extern check_complete(); /* checks that all changes were picked up */
+
+@ Code related to section numbers:
+@<Common code...@>=
+typedef unsigned short sixteen_bits;
+extern sixteen_bits section_count; /* the current section number */
+extern boolean changed_section[]; /* is the section changed? */
+extern boolean change_pending; /* is a decision about change still unclear? */
+extern boolean print_where; /* tells \.{CTANGLE} to print line and file info */
+
+@ Code related to command line arguments:
+@d show_banner flags['b'] /* should the banner line be printed? */
+@d show_progress flags['p'] /* should progress reports be printed? */
+@d show_happiness flags['h'] /* should lack of errors be announced? */
+
+@<Common code...@>=
+extern int argc; /* copy of |ac| parameter to |main| */
+extern char **argv; /* copy of |av| parameter to |main| */
+extern boolean flags[]; /* an option for each 7-bit code */
+
+@ Code relating to output:
+@d update_terminal fflush(stdout) /* empty the terminal output buffer */
+@d new_line putchar('\n') @d putxchar putchar
+@d term_write(a,b) fflush(stdout),fwrite(a,sizeof(char),b,stdout)
+@d C_printf(c,a) fprintf(C_file,c,a)
+@d C_putc(c) putc(c,C_file)
+
+@<Common code...@>=
+extern FILE *C_file; /* where output of \.{CTANGLE} goes */
+extern FILE *tex_file; /* where output of \.{CWEAVE} goes */
+extern FILE *idx_file; /* where index from \.{CWEAVE} goes */
+extern FILE *scn_file; /* where list of sections from \.{CWEAVE} goes */
+extern FILE *active_file; /* currently active file for \.{CWEAVE} output */
+
+@ The procedure that gets everything rolling:
+
+@<Common code...@>=
+extern void common_init();
diff --git a/web/c_cpp/cweb/common.w b/web/c_cpp/cweb/common.w
new file mode 100644
index 0000000000..d8aacfb7b9
--- /dev/null
+++ b/web/c_cpp/cweb/common.w
@@ -0,0 +1,1418 @@
+% This file is part of CWEB.
+% This program by Silvio Levy and Donald E. Knuth
+% is based on a program by Knuth.
+% It is distributed WITHOUT ANY WARRANTY, express or implied.
+% Version 3.64 --- January 2002
+
+% Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth
+
+% Permission is granted to make and distribute verbatim copies of this
+% document provided that the copyright notice and this permission notice
+% are preserved on all copies.
+
+% Permission is granted to copy and distribute modified versions of this
+% document under the conditions for verbatim copying, provided that the
+% entire resulting derived work is given a different name and distributed
+% under the terms of a permission notice identical to this one.
+
+\def\v{\char'174} % vertical (|) in typewriter font
+
+\def\title{Common code for CTANGLE and CWEAVE (Version 3.64)}
+\def\topofcontents{\null\vfill
+ \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and
+ {\ttitlefont CWEAVE}}
+ \vskip 15pt
+ \centerline{(Version 3.64)}
+ \vfill}
+\def\botofcontents{\vfill
+\noindent
+Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth
+\bigskip\noindent
+Permission is granted to make and distribute verbatim copies of this
+document provided that the copyright notice and this permission notice
+are preserved on all copies.
+
+\smallskip\noindent
+Permission is granted to copy and distribute modified versions of this
+document under the conditions for verbatim copying, provided that the
+entire resulting derived work is given a different name and distributed
+under the terms of a permission notice identical to this one.
+}
+
+\pageno=\contentspagenumber \advance\pageno by 1
+\let\maybe=\iftrue
+@s not_eq normal @q unreserve a C++ keyword @>
+
+@** Introduction. This file contains code common
+to both \.{CTANGLE} and \.{CWEAVE}, which roughly concerns the following
+problems: character uniformity, input routines, error handling and
+parsing of command line. We have tried to concentrate in this file
+all the system dependencies, so as to maximize portability.
+
+In the texts below we will
+sometimes use \.{CWEB} to refer to either of the two component
+programs, if no confusion can arise.
+
+The file begins with a few basic definitions.
+
+@c
+@<Include files@>@/
+@h
+@<Definitions that should agree with \.{CTANGLE} and \.{CWEAVE}@>@/
+@<Other definitions@>@/
+@<Predeclaration of procedures@>@/
+
+@ In certain cases \.{CTANGLE} and \.{CWEAVE} should do almost, but not
+quite, the same thing. In these cases we've written common code for
+both, differentiating between the two by means of the global variable
+|program|.
+
+@d ctangle 0
+@d cweave 1
+
+@<Definitions...@>=
+typedef short boolean;
+boolean program; /* \.{CWEAVE} or \.{CTANGLE}? */
+
+@ \.{CWEAVE} operates in three phases: First it inputs the source
+file and stores cross-reference data, then it inputs the source once again and
+produces the \TEX/ output file, and finally it sorts and outputs the index.
+Similarly, \.{CTANGLE} operates in two phases.
+The global variable |phase| tells which phase we are in.
+
+@<Other...@>= int phase; /* which phase are we in? */
+
+@ There's an initialization procedure that gets both \.{CTANGLE} and
+\.{CWEAVE} off to a good start. We will fill in the details of this
+procedure later.
+
+@c
+void
+common_init()
+{
+ @<Initialize pointers@>;
+ @<Set the default options common to \.{CTANGLE} and \.{CWEAVE}@>;
+ @<Scan arguments and open output files@>;
+}
+
+@* The character set.
+\.{CWEB} uses the conventions of \CEE/ programs found in the standard
+\.{ctype.h} header file.
+
+@<Include files@>=
+#include <ctype.h>
+
+@ A few character pairs are encoded internally as single characters,
+using the definitions below. These definitions are consistent with
+an extension of ASCII code originally developed at MIT and explained in
+Appendix~C of {\sl The \TEX/book\/}; thus, users who have such a
+character set can type things like \.{\char'32} and \.{\char'4} instead
+of \.{!=} and \.{\&\&}. (However, their files will not be too portable
+until more people adopt the extended code.)
+
+If the character set is not ASCII, the definitions given here may conflict
+with existing characters; in such cases, other arbitrary codes should be
+substituted. The indexes to \.{CTANGLE} and \.{CWEAVE} mention every
+case where similar codes may have to be changed in order to
+avoid character conflicts. Look for the entry ``ASCII code dependencies''
+in those indexes.
+
+@^ASCII code dependencies@>
+@^system dependencies@>
+
+@d and_and 04 /* `\.{\&\&}'\,; corresponds to MIT's {\tentex\char'4} */
+@d lt_lt 020 /* `\.{<<}'\,; corresponds to MIT's {\tentex\char'20} */
+@d gt_gt 021 /* `\.{>>}'\,; corresponds to MIT's {\tentex\char'21} */
+@d plus_plus 013 /* `\.{++}'\,; corresponds to MIT's {\tentex\char'13} */
+@d minus_minus 01 /* `\.{--}'\,; corresponds to MIT's {\tentex\char'1} */
+@d minus_gt 031 /* `\.{->}'\,; corresponds to MIT's {\tentex\char'31} */
+@d not_eq 032 /* `\.{!=}'\,; corresponds to MIT's {\tentex\char'32} */
+@d lt_eq 034 /* `\.{<=}'\,; corresponds to MIT's {\tentex\char'34} */
+@d gt_eq 035 /* `\.{>=}'\,; corresponds to MIT's {\tentex\char'35} */
+@d eq_eq 036 /* `\.{==}'\,; corresponds to MIT's {\tentex\char'36} */
+@d or_or 037 /* `\.{\v\v}'\,; corresponds to MIT's {\tentex\char'37} */
+@d dot_dot_dot 016 /* `\.{...}'\,; corresponds to MIT's {\tentex\char'16} */
+@d colon_colon 06 /* `\.{::}'\,; corresponds to MIT's {\tentex\char'6} */
+@d period_ast 026 /* `\.{.*}'\,; corresponds to MIT's {\tentex\char'26} */
+@d minus_gt_ast 027 /* `\.{->*}'\,; corresponds to MIT's {\tentex\char'27} */
+
+@** Input routines. The lowest level of input to the \.{CWEB} programs
+is performed by |input_ln|, which must be told which file to read from.
+The return value of |input_ln| is 1 if the read is successful and 0 if
+not (generally this means the file has ended). The conventions
+of \TEX/ are followed; i.e., the characters of the next line of the file
+are copied into the |buffer| array,
+and the global variable |limit| is set to the first unoccupied position.
+Trailing blanks are ignored. The value of |limit| must be strictly less
+than |buf_size|, so that |buffer[buf_size-1]| is never filled.
+
+Since |buf_size| is strictly less than |long_buf_size|,
+some of \.{CWEB}'s routines use the fact that it is safe to refer to
+|*(limit+2)| without overstepping the bounds of the array.
+
+@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */
+@d longest_name 10000
+@d long_buf_size (buf_size+longest_name) /* for \.{CWEAVE} */
+@d xisspace(c) (isspace(c)&&((unsigned char)c<0200))
+@d xisupper(c) (isupper(c)&&((unsigned char)c<0200))
+
+@<Definitions...@>=
+char buffer[long_buf_size]; /* where each line of input goes */
+char *buffer_end=buffer+buf_size-2; /* end of |buffer| */
+char *limit=buffer; /* points to the last character in the buffer */
+char *loc=buffer; /* points to the next character to be read from the buffer */
+
+@ @<Include files@>=
+#include <stdio.h>
+
+@ In the unlikely event that your standard I/O library does not
+support |feof|, |getc|, and |ungetc| you may have to change things here.
+@^system dependencies@>
+
+@c
+int input_ln(fp) /* copies a line into |buffer| or returns 0 */
+FILE *fp; /* what file to read from */
+{
+ register int c=EOF; /* character read; initialized so some compilers won't complain */
+ register char *k; /* where next character goes */
+ if (feof(fp)) return(0); /* we have hit end-of-file */
+ limit = k = buffer; /* beginning of buffer */
+ while (k<=buffer_end && (c=getc(fp)) != EOF && c!='\n')
+ if ((*(k++) = c) != ' ') limit = k;
+ if (k>buffer_end)
+ if ((c=getc(fp))!=EOF && c!='\n') {
+ ungetc(c,fp); loc=buffer; err_print("! Input line too long");
+@.Input line too long@>
+ }
+ if (c==EOF && limit==buffer) return(0); /* there was nothing after
+ the last newline */
+ return(1);
+}
+
+@ Now comes the problem of deciding which file to read from next.
+Recall that the actual text that \.{CWEB} should process comes from two
+streams: a |web_file|, which can contain possibly nested include
+commands \.{@@i}, and a |change_file|, which might also contain
+includes. The |web_file| together with the currently open include
+files form a stack |file|, whose names are stored in a parallel stack
+|file_name|. The boolean |changing| tells whether or not we're reading
+from the |change_file|.
+
+The line number of each open file is also kept for error reporting and
+for the benefit of \.{CTANGLE}.
+
+@f line x /* make |line| an unreserved word */
+@d max_include_depth 10 /* maximum number of source files open
+ simultaneously, not counting the change file */
+@d max_file_name_length 60
+@d cur_file file[include_depth] /* current file */
+@d cur_file_name file_name[include_depth] /* current file name */
+@d cur_line line[include_depth] /* number of current line in current file */
+@d web_file file[0] /* main source file */
+@d web_file_name file_name[0] /* main source file name */
+
+@<Definitions...@>=
+int include_depth; /* current level of nesting */
+FILE *file[max_include_depth]; /* stack of non-change files */
+FILE *change_file; /* change file */
+char file_name[max_include_depth][max_file_name_length];
+ /* stack of non-change file names */
+char change_file_name[max_file_name_length]; /* name of change file */
+char alt_web_file_name[max_file_name_length]; /* alternate name to try */
+int line[max_include_depth]; /* number of current line in the stacked files */
+int change_line; /* number of current line in change file */
+int change_depth; /* where \.{@@y} originated during a change */
+boolean input_has_ended; /* if there is no more input */
+boolean changing; /* if the current line is from |change_file| */
+boolean web_file_open=0; /* if the web file is being read */
+
+@ When |changing==0|, the next line of |change_file| is kept in
+|change_buffer|, for purposes of comparison with the next
+line of |cur_file|. After the change file has been completely input, we
+set |change_limit=change_buffer|,
+so that no further matches will be made.
+
+Here's a shorthand expression for inequality between the two lines:
+
+@d lines_dont_match (change_limit-change_buffer != limit-buffer ||
+ strncmp(buffer, change_buffer, limit-buffer))
+
+@<Other...@>=
+char change_buffer[buf_size]; /* next line of |change_file| */
+char *change_limit; /* points to the last character in |change_buffer| */
+
+@ Procedure |prime_the_change_buffer|
+sets |change_buffer| in preparation for the next matching operation.
+Since blank lines in the change file are not used for matching, we have
+|(change_limit==change_buffer && !changing)| if and only if
+the change file is exhausted. This procedure is called only when
+|changing| is 1; hence error messages will be reported correctly.
+
+@c
+void
+prime_the_change_buffer()
+{
+ change_limit=change_buffer; /* this value is used if the change file ends */
+ @<Skip over comment lines in the change file; |return| if end of file@>;
+ @<Skip to the next nonblank line; |return| if end of file@>;
+ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>;
+}
+
+@ While looking for a line that begins with \.{@@x} in the change file, we
+allow lines that begin with \.{@@}, as long as they don't begin with \.{@@y},
+\.{@@z}, or \.{@@i} (which would probably mean that the change file is fouled up).
+
+@<Skip over comment lines in the change file...@>=
+while(1) {
+ change_line++;
+ if (!input_ln(change_file)) return;
+ if (limit<buffer+2) continue;
+ if (buffer[0]!='@@') continue;
+ if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]);
+ if (buffer[1]=='x') break;
+ if (buffer[1]=='y' || buffer[1]=='z' || buffer[1]=='i') {
+ loc=buffer+2;
+ err_print("! Missing @@x in change file");
+@.Missing @@x...@>
+ }
+}
+
+@ Here we are looking at lines following the \.{@@x}.
+
+@<Skip to the next nonblank line...@>=
+do {
+ change_line++;
+ if (!input_ln(change_file)) {
+ err_print("! Change file ended after @@x");
+@.Change file ended...@>
+ return;
+ }
+} while (limit==buffer);
+
+@ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>=
+{
+ change_limit=change_buffer+(limit-buffer);
+ strncpy(change_buffer,buffer,limit-buffer+1);
+}
+
+@ The following procedure is used to see if the next change entry should
+go into effect; it is called only when |changing| is 0.
+The idea is to test whether or not the current
+contents of |buffer| matches the current contents of |change_buffer|.
+If not, there's nothing more to do; but if so, a change is called for:
+All of the text down to the \.{@@y} is supposed to match. An error
+message is issued if any discrepancy is found. Then the procedure
+prepares to read the next line from |change_file|.
+
+When a match is found, the current section is marked as changed unless
+the first line after the \.{@@x} and after the \.{@@y} both start with
+either |'@@*'| or |'@@ '| (possibly preceded by whitespace).
+
+This procedure is called only when |buffer<limit|, i.e., when the
+current line is nonempty.
+
+@d if_section_start_make_pending(b) {@+*limit='!';
+ for (loc=buffer;xisspace(*loc);loc++) ;
+ *limit=' ';
+ if (*loc=='@@' && (xisspace(*(loc+1)) || *(loc+1)=='*')) change_pending=b;
+}
+
+@c
+void
+check_change() /* switches to |change_file| if the buffers match */
+{
+ int n=0; /* the number of discrepancies found */
+ if (lines_dont_match) return;
+ change_pending=0;
+ if (!changed_section[section_count]) {
+ if_section_start_make_pending(1);
+ if (!change_pending) changed_section[section_count]=1;
+ }
+ while (1) {
+ changing=1; print_where=1; change_line++;
+ if (!input_ln(change_file)) {
+ err_print("! Change file ended before @@y");
+@.Change file ended...@>
+ change_limit=change_buffer; changing=0;
+ return;
+ }
+ if (limit>buffer+1 && buffer[0]=='@@') {
+ char xyz_code=xisupper(buffer[1])? tolower(buffer[1]): buffer[1];
+ @<If the current line starts with \.{@@y},
+ report any discrepancies and |return|@>;
+ }
+ @<Move |buffer| and |limit|...@>;
+ changing=0; cur_line++;
+ while (!input_ln(cur_file)) { /* pop the stack or quit */
+ if (include_depth==0) {
+ err_print("! CWEB file ended during a change");
+@.CWEB file ended...@>
+ input_has_ended=1; return;
+ }
+ include_depth--; cur_line++;
+ }
+ if (lines_dont_match) n++;
+ }
+}
+
+@ @<If the current line starts with \.{@@y}...@>=
+if (xyz_code=='x' || xyz_code=='z') {
+ loc=buffer+2; err_print("! Where is the matching @@y?");
+@.Where is the match...@>
+ }
+else if (xyz_code=='y') {
+ if (n>0) {
+ loc=buffer+2;
+ printf("\n! Hmm... %d ",n);
+ err_print("of the preceding lines failed to match");
+@.Hmm... n of the preceding...@>
+ }
+ change_depth=include_depth;
+ return;
+}
+
+@ The |reset_input| procedure, which gets \.{CWEB} ready to read the
+user's \.{CWEB} input, is used at the beginning of phase one of \.{CTANGLE},
+phases one and two of \.{CWEAVE}.
+
+@c
+void
+reset_input()
+{
+ limit=buffer; loc=buffer+1; buffer[0]=' ';
+ @<Open input files@>;
+ include_depth=0; cur_line=0; change_line=0;
+ change_depth=include_depth;
+ changing=1; prime_the_change_buffer(); changing=!changing;
+ limit=buffer; loc=buffer+1; buffer[0]=' '; input_has_ended=0;
+}
+
+@ The following code opens the input files.
+@^system dependencies@>
+
+@<Open input files@>=
+if ((web_file=fopen(web_file_name,"r"))==NULL) {
+ strcpy(web_file_name,alt_web_file_name);
+ if ((web_file=fopen(web_file_name,"r"))==NULL)
+ fatal("! Cannot open input file ", web_file_name);
+}
+@.Cannot open input file@>
+@.Cannot open change file@>
+web_file_open=1;
+if ((change_file=fopen(change_file_name,"r"))==NULL)
+ fatal("! Cannot open change file ", change_file_name);
+
+@ The |get_line| procedure is called when |loc>limit|; it puts the next
+line of merged input into the buffer and updates the other variables
+appropriately. A space is placed at the right end of the line.
+This procedure returns |!input_has_ended| because we often want to
+check the value of that variable after calling the procedure.
+
+If we've just changed from the |cur_file| to the |change_file|, or if
+the |cur_file| has changed, we tell \.{CTANGLE} to print this
+information in the \CEE/ file by means of the |print_where| flag.
+
+@d max_sections 2000 /* number of identifiers, strings, section names;
+ must be less than 10240 */
+
+@<Defin...@>=
+typedef unsigned short sixteen_bits;
+sixteen_bits section_count; /* the current section number */
+boolean changed_section[max_sections]; /* is the section changed? */
+boolean change_pending; /* if the current change is not yet recorded in
+ |changed_section[section_count]| */
+boolean print_where=0; /* should \.{CTANGLE} print line and file info? */
+
+@ @c
+int get_line() /* inputs the next line */
+{
+ restart:
+ if (changing && include_depth==change_depth)
+ @<Read from |change_file| and maybe turn off |changing|@>;
+ if (! changing || include_depth>change_depth) {
+ @<Read from |cur_file| and maybe turn on |changing|@>;
+ if (changing && include_depth==change_depth) goto restart;
+ }
+ if (input_has_ended) return 0;
+ loc=buffer; *limit=' ';
+ if (buffer[0]=='@@' && (buffer[1]=='i' || buffer[1]=='I')) {
+ loc=buffer+2; *limit='"';
+ while (*loc==' '||*loc=='\t') loc++;
+ if (loc>=limit) {
+ err_print("! Include file name not given");
+@.Include file name ...@>
+ goto restart;
+ }
+ if (include_depth>=max_include_depth-1) {
+ err_print("! Too many nested includes");
+@.Too many nested includes@>
+ goto restart;
+ }
+ include_depth++; /* push input stack */
+ @<Try to open include file, abort push if unsuccessful, go to |restart|@>;
+ }
+ return 1;
+}
+
+@ When an \.{@@i} line is found in the |cur_file|, we must temporarily
+stop reading it and start reading from the named include file. The
+\.{@@i} line should give a complete file name with or without
+double quotes.
+If the environment variable \.{CWEBINPUTS} is set, or if the compiler flag
+of the same name was defined at compile time,
+\.{CWEB} will look for include files in the directory thus named, if
+it cannot find them in the current directory.
+(Colon-separated paths are not supported.)
+The remainder of the \.{@@i} line after the file name is ignored.
+
+@d too_long() {include_depth--;
+ err_print("! Include file name too long"); goto restart;}
+
+@<Include...@>=
+#include <stdlib.h> /* declaration of |getenv| and |exit| */
+
+@ @<Try to open...@>= {
+ char temp_file_name[max_file_name_length];
+ char *cur_file_name_end=cur_file_name+max_file_name_length-1;
+ char *k=cur_file_name, *kk;
+ int l; /* length of file name */
+
+ if (*loc=='"') {
+ loc++;
+ while (*loc!='"' && k<=cur_file_name_end) *k++=*loc++;
+ if (loc==limit) k=cur_file_name_end+1; /* unmatched quote is `too long' */
+ } else
+ while (*loc!=' '&&*loc!='\t'&&*loc!='"'&&k<=cur_file_name_end) *k++=*loc++;
+ if (k>cur_file_name_end) too_long();
+@.Include file name ...@>
+ *k='\0';
+ if ((cur_file=fopen(cur_file_name,"r"))!=NULL) {
+ cur_line=0; print_where=1;
+ goto restart; /* success */
+ }
+ kk=getenv("CWEBINPUTS");
+ if (kk!=NULL) {
+ if ((l=strlen(kk))>max_file_name_length-2) too_long();
+ strcpy(temp_file_name,kk);
+ }
+ else {
+#ifdef CWEBINPUTS
+ if ((l=strlen(CWEBINPUTS))>max_file_name_length-2) too_long();
+ strcpy(temp_file_name,CWEBINPUTS);
+#else
+ l=0;
+#endif /* |CWEBINPUTS| */
+ }
+ if (l>0) {
+ if (k+l+2>=cur_file_name_end) too_long();
+@.Include file name ...@>
+ for (; k>= cur_file_name; k--) *(k+l+1)=*k;
+ strcpy(cur_file_name,temp_file_name);
+ cur_file_name[l]='/'; /* \UNIX/ pathname separator */
+ if ((cur_file=fopen(cur_file_name,"r"))!=NULL) {
+ cur_line=0; print_where=1;
+ goto restart; /* success */
+ }
+ }
+ include_depth--; err_print("! Cannot open include file"); goto restart;
+}
+
+@ @<Read from |cur_file|...@>= {
+ cur_line++;
+ while (!input_ln(cur_file)) { /* pop the stack or quit */
+ print_where=1;
+ if (include_depth==0) {input_has_ended=1; break;}
+ else {
+ fclose(cur_file); include_depth--;
+ if (changing && include_depth==change_depth) break;
+ cur_line++;
+ }
+ }
+ if (!changing && !input_has_ended)
+ if (limit-buffer==change_limit-change_buffer)
+ if (buffer[0]==change_buffer[0])
+ if (change_limit>change_buffer) check_change();
+}
+
+@ @<Read from |change_file|...@>= {
+ change_line++;
+ if (!input_ln(change_file)) {
+ err_print("! Change file ended without @@z");
+@.Change file ended...@>
+ buffer[0]='@@'; buffer[1]='z'; limit=buffer+2;
+ }
+ if (limit>buffer) { /* check if the change has ended */
+ if (change_pending) {
+ if_section_start_make_pending(0);
+ if (change_pending) {
+ changed_section[section_count]=1; change_pending=0;
+ }
+ }
+ *limit=' ';
+ if (buffer[0]=='@@') {
+ if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]);
+ if (buffer[1]=='x' || buffer[1]=='y') {
+ loc=buffer+2;
+ err_print("! Where is the matching @@z?");
+@.Where is the match...@>
+ }
+ else if (buffer[1]=='z') {
+ prime_the_change_buffer(); changing=!changing; print_where=1;
+ }
+ }
+ }
+}
+
+@ At the end of the program, we will tell the user if the change file
+had a line that didn't match any relevant line in |web_file|.
+
+@c
+void
+check_complete(){
+ if (change_limit!=change_buffer) { /* |changing| is 0 */
+ strncpy(buffer,change_buffer,change_limit-change_buffer+1);
+ limit=buffer+(int)(change_limit-change_buffer);
+ changing=1; change_depth=include_depth; loc=buffer;
+ err_print("! Change file entry did not match");
+@.Change file entry did not match@>
+ }
+}
+
+@** Storage of names and strings.
+Both \.{CWEAVE} and \.{CTANGLE} store identifiers, section names and
+other strings in a large array of |char|s, called |byte_mem|.
+Information about the names is kept in the array |name_dir|, whose
+elements are structures of type |name_info|, containing a pointer into
+the |byte_mem| array (the address where the name begins) and other data.
+A |name_pointer| variable is a pointer into |name_dir|.
+
+@d max_bytes 90000 /* the number of bytes in identifiers,
+ index entries, and section names; must be less than $2^{24}$ */
+@d max_names 4000 /* number of identifiers, strings, section names;
+ must be less than 10240 */
+
+@<Definitions that...@>=
+typedef struct name_info {
+ char *byte_start; /* beginning of the name in |byte_mem| */
+ @<More elements of |name_info| structure@>@;
+} name_info; /* contains information about an identifier or section name */
+typedef name_info *name_pointer; /* pointer into array of |name_info|s */
+char byte_mem[max_bytes]; /* characters of names */
+char *byte_mem_end = byte_mem+max_bytes-1; /* end of |byte_mem| */
+name_info name_dir[max_names]; /* information about names */
+name_pointer name_dir_end = name_dir+max_names-1; /* end of |name_dir| */
+
+@ The actual sequence of characters in the name pointed to by a |name_pointer
+p| appears in positions |p->byte_start| to |(p+1)->byte_start-1|, inclusive.
+The |print_id| macro prints this text on the user's terminal.
+
+@d length(c) (c+1)->byte_start-(c)->byte_start /* the length of a name */
+@d print_id(c) term_write((c)->byte_start,length((c))) /* print identifier */
+
+@ The first unused position in |byte_mem| and |name_dir| is
+kept in |byte_ptr| and |name_ptr|, respectively. Thus we
+usually have |name_ptr->byte_start==byte_ptr|, and certainly
+we want to keep |name_ptr<=name_dir_end| and |byte_ptr<=byte_mem_end|.
+
+@<Defini...@>=
+name_pointer name_ptr; /* first unused position in |name_dir| */
+char *byte_ptr; /* first unused position in |byte_mem| */
+
+@ @<Init...@>=
+name_dir->byte_start=byte_ptr=byte_mem; /* position zero in both arrays */
+name_ptr=name_dir+1; /* |name_dir[0]| will be used only for error recovery */
+name_ptr->byte_start=byte_mem; /* this makes name 0 of length zero */
+
+@ The names of identifiers are found by computing a hash address |h| and
+then looking at strings of bytes signified by the |name_pointer|s
+|hash[h]|, |hash[h]->link|, |hash[h]->link->link|, \dots,
+until either finding the desired name or encountering the null pointer.
+
+@<More elements of |name...@>=
+struct name_info *link;
+
+@ The hash table itself
+consists of |hash_size| entries of type |name_pointer|, and is
+updated by the |id_lookup| procedure, which finds a given identifier
+and returns the appropriate |name_pointer|. The matching is done by the
+function |names_match|, which is slightly different in
+\.{CWEAVE} and \.{CTANGLE}. If there is no match for the identifier,
+it is inserted into the table.
+
+@d hash_size 353 /* should be prime */
+
+@<Defini...@>=
+typedef name_pointer *hash_pointer;
+name_pointer hash[hash_size]; /* heads of hash lists */
+hash_pointer hash_end = hash+hash_size-1; /* end of |hash| */
+hash_pointer h; /* index into hash-head array */
+
+@ @<Predec...@>=
+extern int names_match();
+
+@ Initially all the hash lists are empty.
+
+@<Init...@>=
+for (h=hash; h<=hash_end; *h++=NULL) ;
+
+@ Here is the main procedure for finding identifiers:
+
+@c
+name_pointer
+id_lookup(first,last,t) /* looks up a string in the identifier table */
+char *first; /* first character of string */
+char *last; /* last character of string plus one */
+char t; /* the |ilk|; used by \.{CWEAVE} only */
+{
+ char *i=first; /* position in |buffer| */
+ int h; /* hash code */
+ int l; /* length of the given identifier */
+ name_pointer p; /* where the identifier is being sought */
+ if (last==NULL) for (last=first; *last!='\0'; last++);
+ l=last-first; /* compute the length */
+ @<Compute the hash code |h|@>;
+ @<Compute the name location |p|@>;
+ if (p==name_ptr) @<Enter a new name into the table at position |p|@>;
+ return(p);
+}
+
+@ A simple hash code is used: If the sequence of
+character codes is $c_1c_2\ldots c_n$, its hash value will be
+$$(2^{n-1}c_1+2^{n-2}c_2+\cdots+c_n)\,\bmod\,|hash_size|.$$
+
+@<Compute the hash...@>=
+h=(unsigned char)*i;
+while (++i<last) h=(h+h+(int)((unsigned char)*i)) % hash_size;
+@^high-bit character handling@>
+
+@ If the identifier is new, it will be placed in position |p=name_ptr|,
+otherwise |p| will point to its existing location.
+
+@<Compute the name location...@>=
+p=hash[h];
+while (p && !names_match(p,first,l,t)) p=p->link;
+if (p==NULL) {
+ p=name_ptr; /* the current identifier is new */
+ p->link=hash[h]; hash[h]=p; /* insert |p| at beginning of hash list */
+}
+
+@ The information associated with a new identifier must be initialized
+in a slightly different way in \.{CWEAVE} than in \.{CTANGLE}; hence the
+|init_p| procedure.
+
+@<Pred...@>=
+void init_p();
+
+@ @<Enter a new name...@>= {
+ if (byte_ptr+l>byte_mem_end) overflow("byte memory");
+ if (name_ptr>=name_dir_end) overflow("name");
+ strncpy(byte_ptr,first,l);
+ (++name_ptr)->byte_start=byte_ptr+=l;
+ if (program==cweave) init_p(p,t);
+}
+
+@ The names of sections are stored in |byte_mem| together
+with the identifier names, but a hash table is not used for them because
+\.{CTANGLE} needs to be able to recognize a section name when given a prefix of
+that name. A conventional binary search tree is used to retrieve section names,
+with fields called |llink| and |rlink| (where |llink| takes the place
+of |link|). The root of this tree is stored in |name_dir->rlink|;
+this will be the only information in |name_dir[0]|.
+
+Since the space used by |rlink| has a different function for
+identifiers than for section names, we declare it as a |union|.
+
+@d llink link /* left link in binary search tree for section names */
+@d rlink dummy.Rlink /* right link in binary search tree for section names */
+@d root name_dir->rlink /* the root of the binary search tree
+ for section names */
+
+@<More elements of |name...@>=
+union {
+ struct name_info *Rlink; /* right link in binary search tree for section
+ names */
+ char Ilk; /* used by identifiers in \.{CWEAVE} only */
+} dummy;
+
+@ @<Init...@>=
+root=NULL; /* the binary search tree starts out with nothing in it */
+
+@ If |p| is a |name_pointer| variable, as we have seen,
+|p->byte_start| is the beginning of the area where the name
+corresponding to |p| is stored. However, if |p| refers to a section
+name, the name may need to be stored in chunks, because it may
+``grow'': a prefix of the section name may be encountered before
+the full name. Furthermore we need to know the length of the shortest
+prefix of the name that was ever encountered.
+
+We solve this problem by inserting two extra bytes at |p->byte_start|,
+representing the length of the shortest prefix, when |p| is a
+section name. Furthermore, the last byte of the name will be a blank
+space if |p| is a prefix. In the latter case, the name pointer
+|p+1| will allow us to access additional chunks of the name:
+The second chunk will begin at the name pointer |(p+1)->link|,
+and if it too is a prefix (ending with blank) its |link| will point
+to additional chunks in the same way. Null links are represented by
+|name_dir|.
+
+@d first_chunk(p) ((p)->byte_start+2)
+@d prefix_length(p) (int)((unsigned char)*((p)->byte_start)*256 +
+ (unsigned char)*((p)->byte_start+1))
+@d set_prefix_length(p,m) (*((p)->byte_start)=(m)/256,
+ *((p)->byte_start+1)=(m)%256)
+
+@c
+void
+print_section_name(p)
+name_pointer p;
+{
+ char *ss, *s = first_chunk(p);
+ name_pointer q = p+1;
+ while (p!=name_dir) {
+ ss = (p+1)->byte_start-1;
+ if (*ss==' ' && ss>=s) {
+ term_write(s,ss-s); p=q->link; q=p;
+ } else {
+ term_write(s,ss+1-s); p=name_dir; q=NULL;
+ }
+ s = p->byte_start;
+ }
+ if (q) term_write("...",3); /* complete name not yet known */
+}
+
+@ @c
+void
+sprint_section_name(dest,p)
+ char*dest;
+ name_pointer p;
+{
+ char *ss, *s = first_chunk(p);
+ name_pointer q = p+1;
+ while (p!=name_dir) {
+ ss = (p+1)->byte_start-1;
+ if (*ss==' ' && ss>=s) {
+ p=q->link; q=p;
+ } else {
+ ss++; p=name_dir;
+ }
+ strncpy(dest,s,ss-s), dest+=ss-s;
+ s = p->byte_start;
+ }
+ *dest='\0';
+}
+
+@ @c
+void
+print_prefix_name(p)
+name_pointer p;
+{
+ char *s = first_chunk(p);
+ int l = prefix_length(p);
+ term_write(s,l);
+ if (s+l<(p+1)->byte_start) term_write("...",3);
+}
+
+@ When we compare two section names, we'll need a function analogous to
+|strcmp|. But we do not assume the strings
+are null-terminated, and we keep an eye open for prefixes and extensions.
+
+@d less 0 /* the first name is lexicographically less than the second */
+@d equal 1 /* the first name is equal to the second */
+@d greater 2 /* the first name is lexicographically greater than the second */
+@d prefix 3 /* the first name is a proper prefix of the second */
+@d extension 4 /* the first name is a proper extension of the second */
+
+@c
+int web_strcmp(j,j_len,k,k_len) /* fuller comparison than |strcmp| */
+ char *j, *k; /* beginning of first and second strings */
+ int j_len, k_len; /* length of strings */
+{
+ char *j1=j+j_len, *k1=k+k_len;
+ while (k<k1 && j<j1 && *j==*k) k++, j++;
+ if (k==k1) if (j==j1) return equal;
+ else return extension;
+ else if (j==j1) return prefix;
+ else if (*j<*k) return less;
+ else return greater;
+}
+
+@ Adding a section name to the tree is straightforward if we know its
+parent and whether it's the |rlink| or |llink| of the parent. As a
+special case, when the name is the first section being added, we set the
+``parent'' to |NULL|. When a section name is created, it has only one
+chunk, which however may be just a prefix; the full name will
+hopefully be unveiled later. Obviously, |prefix_length| starts
+out as the length of the first chunk, though it may decrease later.
+
+The information associated with a new node must be initialized
+differently in \.{CWEAVE} and \.{CTANGLE}; hence the
+|init_node| procedure, which is defined differently in \.{cweave.w}
+and \.{ctangle.w}.
+
+@<Prede...@>=
+extern void init_node();
+
+@ @c
+name_pointer
+add_section_name(par,c,first,last,ispref) /* install a new node in the tree */
+name_pointer par; /* parent of new node */
+int c; /* right or left? */
+char *first; /* first character of section name */
+char *last; /* last character of section name, plus one */
+int ispref; /* are we adding a prefix or a full name? */
+{
+ name_pointer p=name_ptr; /* new node */
+ char *s=first_chunk(p);
+ int name_len=last-first+ispref; /* length of section name */
+ if (s+name_len>byte_mem_end) overflow("byte memory");
+ if (name_ptr+1>=name_dir_end) overflow("name");
+ (++name_ptr)->byte_start=byte_ptr=s+name_len;
+ if (ispref) {
+ *(byte_ptr-1)=' ';
+ name_len--;
+ name_ptr->link=name_dir;
+ (++name_ptr)->byte_start=byte_ptr;
+ }
+ set_prefix_length(p,name_len);
+ strncpy(s,first,name_len);
+ p->llink=NULL;
+ p->rlink=NULL;
+ init_node(p);
+ return par==NULL ? (root=p) : c==less ? (par->llink=p) : (par->rlink=p);
+}
+
+@ @c
+void
+extend_section_name(p,first,last,ispref)
+name_pointer p; /* name to be extended */
+char *first; /* beginning of extension text */
+char *last; /* one beyond end of extension text */
+int ispref; /* are we adding a prefix or a full name? */
+{
+ char *s;
+ name_pointer q=p+1;
+ int name_len=last-first+ispref;
+ if (name_ptr>=name_dir_end) overflow("name");
+ while (q->link!=name_dir) q=q->link;
+ q->link=name_ptr;
+ s=name_ptr->byte_start;
+ name_ptr->link=name_dir;
+ if (s+name_len>byte_mem_end) overflow("byte memory");
+ (++name_ptr)->byte_start=byte_ptr=s+name_len;
+ strncpy(s,first,name_len);
+ if (ispref) *(byte_ptr-1)=' ';
+}
+
+@ The |section_lookup| procedure is supposed to find a
+section name that matches a new name, installing the new name if
+it doesn't match an existing one. The new name is the string
+between |first| and |last|; a ``match'' means that the new name
+exactly equals or is a prefix or extension of a name in the tree.
+
+@c
+name_pointer
+section_lookup(first,last,ispref) /* find or install section name in tree */
+char *first, *last; /* first and last characters of new name */
+int ispref; /* is the new name a prefix or a full name? */
+{
+ int c=0; /* comparison between two names; initialized so some compilers won't complain */
+ name_pointer p=root; /* current node of the search tree */
+ name_pointer q=NULL; /* another place to look in the tree */
+ name_pointer r=NULL; /* where a match has been found */
+ name_pointer par=NULL; /* parent of |p|, if |r| is |NULL|;
+ otherwise parent of |r| */
+ int name_len=last-first+1;
+ @<Look for matches for new name among shortest prefixes, complaining
+ if more than one is found@>;
+ @<If no match found, add new name to tree@>;
+ @<If one match found, check for compatibility and return match@>;
+}
+
+@ A legal new name matches an existing section name if and only if it
+matches the shortest prefix of that section name. Therefore we can
+limit our search for matches to shortest prefixes, which eliminates
+the need for chunk-chasing at this stage.
+
+@<Look for matches for new name among...@>=
+while (p) { /* compare shortest prefix of |p| with new name */
+ c=web_strcmp(first,name_len,first_chunk(p),prefix_length(p));
+ if (c==less || c==greater) { /* new name does not match |p| */
+ if (r==NULL) /* no previous matches have been found */
+ par=p;
+ p=(c==less?p->llink:p->rlink);
+ } else { /* new name matches |p| */
+ if (r!=NULL) { /* and also |r|: illegal */
+ printf("\n! Ambiguous prefix: matches <");
+@.Ambiguous prefix ... @>
+ print_prefix_name(p);
+ printf(">\n and <");
+ print_prefix_name(r);
+ err_print(">");
+ return name_dir; /* the unsection */
+ }
+ r=p; /* remember match */
+ p=p->llink; /* try another */
+ q=r->rlink; /* we'll get back here if the new |p| doesn't match */
+ }
+ if (p==NULL)
+ p=q, q=NULL; /* |q| held the other branch of |r| */
+}
+
+@ @<If no match ...@>=
+ if (r==NULL) /* no matches were found */
+ return add_section_name(par,c,first,last+1,ispref);
+
+@ Although error messages are given in anomalous cases, we do return the
+unique best match when a discrepancy is found, because users often
+change a title in one place while forgetting to change it elsewhere.
+
+@<If one match found, check for compatibility and return match@>=
+switch(section_name_cmp(&first,name_len,r)) {
+ /* compare all of |r| with new name */
+ case prefix:
+ if (!ispref) {
+ printf("\n! New name is a prefix of <");
+@.New name is a prefix...@>
+ print_section_name(r);
+ err_print(">");
+ }
+ else if (name_len<prefix_length(r)) set_prefix_length(r,name_len);
+ /* fall through */
+ case equal: return r;
+ case extension: if (!ispref || first<=last)
+ extend_section_name(r,first,last+1,ispref);
+ return r;
+ case bad_extension:
+ printf("\n! New name extends <");
+@.New name extends...@>
+ print_section_name(r);
+ err_print(">");
+ return r;
+ default: /* no match: illegal */
+ printf("\n! Section name incompatible with <");
+@.Section name incompatible...@>
+ print_prefix_name(r);
+ printf(">,\n which abbreviates <");
+ print_section_name(r);
+ err_print(">");
+ return r;
+}
+
+@ The return codes of |section_name_cmp|, which compares a string with
+the full name of a section, are those of |web_strcmp| plus
+|bad_extension|, used when the string is an extension of a
+supposedly already complete section name. This function has a side
+effect when the comparison string is an extension: It advances the
+address of the first character of the string by an amount equal to
+the length of the known part of the section name.
+
+The name \.{@@<foo...@@>} should be an acceptable ``abbreviation''
+for \.{@@<foo@@>}. If such an abbreviation comes after the complete
+name, there's no trouble recognizing it. If it comes before the
+complete name, we simply append a null chunk. This logic requires
+us to regard \.{@@<foo...@@>} as an ``extension'' of itself.
+
+@d bad_extension 5
+
+@<Predec...@>=
+int section_name_cmp();
+
+@ @c
+int section_name_cmp(pfirst,len,r)
+char **pfirst; /* pointer to beginning of comparison string */
+int len; /* length of string */
+name_pointer r; /* section name being compared */
+{
+ char *first=*pfirst; /* beginning of comparison string */
+ name_pointer q=r+1; /* access to subsequent chunks */
+ char *ss, *s=first_chunk(r);
+ int c; /* comparison */
+ int ispref; /* is chunk |r| a prefix? */
+ while (1) {
+ ss=(r+1)->byte_start-1;
+ if (*ss==' ' && ss>=r->byte_start) ispref=1,q=q->link;
+ else ispref=0,ss++,q=name_dir;
+ switch(c=web_strcmp(first,len,s,ss-s)) {
+ case equal: if (q==name_dir)
+ if (ispref) {
+ *pfirst=first+(ss-s);
+ return extension; /* null extension */
+ } else return equal;
+ else return (q->byte_start==(q+1)->byte_start)? equal: prefix;
+ case extension:
+ if (!ispref) return bad_extension;
+ first += ss-s;
+ if (q!=name_dir) {len -= ss-s; s=q->byte_start; r=q; continue;}
+ *pfirst=first; return extension;
+ default: return c;
+ }
+ }
+}
+
+@ The last component of |name_info| is different for \.{CTANGLE} and
+\.{CWEAVE}. In \.{CTANGLE}, if |p| is a pointer to a section name,
+|p->equiv| is a pointer to its replacement text, an element of the
+array |text_info|. In \.{CWEAVE}, on the other hand, if
+|p| points to an identifier, |p->xref| is a pointer to its
+list of cross-references, an element of the array |xmem|. The make-up
+of |text_info| and |xmem| is discussed in the \.{CTANGLE} and \.{CWEAVE}
+source files, respectively; here we just declare a common field
+|equiv_or_xref| as a pointer to a |char|.
+
+@<More elements of |name...@>=
+char *equiv_or_xref; /* info corresponding to names */
+
+@** Reporting errors to the user.
+A global variable called |history| will contain one of four values
+at the end of every run: |spotless| means that no unusual messages were
+printed; |harmless_message| means that a message of possible interest
+was printed but no serious errors were detected; |error_message| means that
+at least one error was found; |fatal_message| means that the program
+terminated abnormally. The value of |history| does not influence the
+behavior of the program; it is simply computed for the convenience
+of systems that might want to use such information.
+
+@d spotless 0 /* |history| value for normal jobs */
+@d harmless_message 1 /* |history| value when non-serious info was printed */
+@d error_message 2 /* |history| value when an error was noted */
+@d fatal_message 3 /* |history| value when we had to stop prematurely */
+@d mark_harmless {if (history==spotless) history=harmless_message;}
+@d mark_error history=error_message
+
+@<Definit...@>=
+int history=spotless; /* indicates how bad this run was */
+
+@ The command `|err_print("! Error message")|' will report a syntax error to
+the user, by printing the error message at the beginning of a new line and
+then giving an indication of where the error was spotted in the source file.
+Note that no period follows the error message, since the error routine
+will automatically supply a period. A newline is automatically supplied
+if the string begins with |"!"|.
+
+@<Predecl...@>=
+void err_print();
+
+@ @c
+void
+err_print(s) /* prints `\..' and location of error message */
+char *s;
+{
+ char *k,*l; /* pointers into |buffer| */
+ printf(*s=='!'? "\n%s" : "%s",s);
+ if(web_file_open) @<Print error location based on input buffer@>;
+ update_terminal; mark_error;
+}
+
+@ The error locations can be indicated by using the global variables
+|loc|, |cur_line|, |cur_file_name| and |changing|,
+which tell respectively the first
+unlooked-at position in |buffer|, the current line number, the current
+file, and whether the current line is from |change_file| or |cur_file|.
+This routine should be modified on systems whose standard text editor
+has special line-numbering conventions.
+@^system dependencies@>
+
+@<Print error location based on input buffer@>=
+{if (changing && include_depth==change_depth)
+ printf(". (l. %d of change file)\n", change_line);
+else if (include_depth==0) printf(". (l. %d)\n", cur_line);
+ else printf(". (l. %d of include file %s)\n", cur_line, cur_file_name);
+l= (loc>=limit? limit: loc);
+if (l>buffer) {
+ for (k=buffer; k<l; k++)
+ if (*k=='\t') putchar(' ');
+ else putchar(*k); /* print the characters already read */
+ putchar('\n');
+ for (k=buffer; k<l; k++) putchar(' '); /* space out the next line */
+}
+for (k=l; k<limit; k++) putchar(*k); /* print the part not yet read */
+if (*limit=='|') putchar('|'); /* end of \CEE/ text in section names */
+putchar(' '); /* to separate the message from future asterisks */
+}
+
+@ When no recovery from some error has been provided, we have to wrap
+up and quit as graciously as possible. This is done by calling the
+function |wrap_up| at the end of the code.
+
+\.{CTANGLE} and \.{CWEAVE} have their own notions about how to
+print the job statistics.
+
+@<Prede...@>=
+int wrap_up();
+extern void print_stats();
+
+@ Some implementations may wish to pass the |history| value to the
+operating system so that it can be used to govern whether or not other
+programs are started. Here, for instance, we pass the operating system
+a status of 0 if and only if only harmless messages were printed.
+@^system dependencies@>
+
+@c
+int wrap_up() {
+ putchar('\n');
+ if (show_stats)
+ print_stats(); /* print statistics about memory usage */
+ @<Print the job |history|@>;
+ if (history > harmless_message) return(1);
+ else return(0);
+}
+
+@ @<Print the job |history|@>=
+switch (history) {
+case spotless: if (show_happiness) printf("(No errors were found.)\n"); break;
+case harmless_message:
+ printf("(Did you see the warning message above?)\n"); break;
+case error_message:
+ printf("(Pardon me, but I think I spotted something wrong.)\n"); break;
+case fatal_message: printf("(That was a fatal error, my friend.)\n");
+} /* there are no other cases */
+
+@ When there is no way to recover from an error, the |fatal| subroutine is
+invoked. This happens most often when |overflow| occurs.
+
+@<Predec...@>=
+void fatal(), overflow();
+
+@ The two parameters to |fatal| are strings that are essentially
+concatenated to print the final error message.
+
+@c void
+fatal(s,t)
+ char *s,*t;
+{
+ if (*s) printf(s);
+ err_print(t);
+ history=fatal_message; exit(wrap_up());
+}
+
+@ An overflow stop occurs if \.{CWEB}'s tables aren't large enough.
+
+@c void
+overflow(t)
+ char *t;
+{
+ printf("\n! Sorry, %s capacity exceeded",t); fatal("","");
+}
+@.Sorry, capacity exceeded@>
+
+@ Sometimes the program's behavior is far different from what it should be,
+and \.{CWEB} prints an error message that is really for the \.{CWEB}
+maintenance person, not the user. In such cases the program says
+|confusion("indication of where we are")|.
+
+@d confusion(s) fatal("! This can't happen: ",s)
+@.This can't happen@>
+
+@** Command line arguments.
+The user calls \.{CWEAVE} and \.{CTANGLE} with arguments on the command line.
+These are either file names or flags to be turned off (beginning with |"-"|)
+or flags to be turned on (beginning with |"+"|).
+The following globals are for communicating the user's desires to the rest
+of the program. The various file name variables contain strings with
+the names of those files. Most of the 128 flags are undefined but available
+for future extensions.
+
+@d show_banner flags['b'] /* should the banner line be printed? */
+@d show_progress flags['p'] /* should progress reports be printed? */
+@d show_stats flags['s'] /* should statistics be printed at end of run? */
+@d show_happiness flags['h'] /* should lack of errors be announced? */
+
+@<Defin...@>=
+int argc; /* copy of |ac| parameter to |main| */
+char **argv; /* copy of |av| parameter to |main| */
+char C_file_name[max_file_name_length]; /* name of |C_file| */
+char tex_file_name[max_file_name_length]; /* name of |tex_file| */
+char idx_file_name[max_file_name_length]; /* name of |idx_file| */
+char scn_file_name[max_file_name_length]; /* name of |scn_file| */
+boolean flags[128]; /* an option for each 7-bit code */
+
+@ The |flags| will be initially zero. Some of them are set to~1 before
+scanning the arguments; if additional flags are 1 by default they
+should be set before calling |common_init|.
+
+@<Set the default options common to \.{CTANGLE} and \.{CWEAVE}@>=
+show_banner=show_happiness=show_progress=1;
+
+@ We now must look at the command line arguments and set the file names
+accordingly. At least one file name must be present: the \.{CWEB}
+file. It may have an extension, or it may omit the extension to get |".w"| or
+|".web"| added. The \TEX/ output file name is formed by replacing the \.{CWEB}
+file name extension by |".tex"|, and the \CEE/ file name by replacing
+the extension by |".c"|, after removing the directory name (if any).
+
+If there is a second file name present among the arguments, it is the
+change file, again either with an extension or without one to get |".ch"|.
+An omitted change file argument means that |"/dev/null"| should be used,
+when no changes are desired.
+@^system dependencies@>
+
+If there's a third file name, it will be the output file.
+
+@<Pred...@>=
+void scan_args();
+
+@ @c
+void
+scan_args()
+{
+ char *dot_pos; /* position of |'.'| in the argument */
+ char *name_pos; /* file name beginning, sans directory */
+ register char *s; /* register for scanning strings */
+ boolean found_web=0,found_change=0,found_out=0;
+ /* have these names been seen? */
+ boolean flag_change;
+
+ while (--argc > 0) {
+ if ((**(++argv)=='-'||**argv=='+')&&*(*argv+1)) @<Handle flag argument@>@;
+ else {
+ s=name_pos=*argv;@+dot_pos=NULL;
+ while (*s) {
+ if (*s=='.') dot_pos=s++;
+ else if (*s=='/') dot_pos=NULL,name_pos=++s;
+ else s++;
+ }
+ if (!found_web) @<Make
+ |web_file_name|, |tex_file_name|, and |C_file_name|@>@;
+ else if (!found_change) @<Make |change_file_name| from |fname|@>@;
+ else if (!found_out) @<Override |tex_file_name| and |C_file_name|@>@;
+ else @<Print usage error message and quit@>;
+ }
+ }
+ if (!found_web) @<Print usage error message and quit@>;
+ if (found_change<=0) strcpy(change_file_name,"/dev/null");
+}
+
+@ We use all of |*argv| for the |web_file_name| if there is a |'.'| in it,
+otherwise we add |".w"|. If this file can't be opened, we prepare an
+|alt_web_file_name| by adding |"web"| after the dot.
+The other file names come from adding other things
+after the dot. We must check that there is enough room in
+|web_file_name| and the other arrays for the argument.
+
+@<Make |web_file_name|...@>=
+{
+ if (s-*argv > max_file_name_length-5)
+ @<Complain about argument length@>;
+ if (dot_pos==NULL)
+ sprintf(web_file_name,"%s.w",*argv);
+ else {
+ strcpy(web_file_name,*argv);
+ *dot_pos=0; /* string now ends where the dot was */
+ }
+ sprintf(alt_web_file_name,"%s.web",*argv);
+ sprintf(tex_file_name,"%s.tex",name_pos); /* strip off directory name */
+ sprintf(idx_file_name,"%s.idx",name_pos);
+ sprintf(scn_file_name,"%s.scn",name_pos);
+ sprintf(C_file_name,"%s.c",name_pos);
+ found_web=1;
+}
+
+@ @<Make |change_file_name|...@>=
+{
+ if (strcmp(*argv,"-")==0) found_change=-1;
+ else {
+ if (s-*argv > max_file_name_length-4)
+ @<Complain about argument length@>;
+ if (dot_pos==NULL)
+ sprintf(change_file_name,"%s.ch",*argv);
+ else strcpy(change_file_name,*argv);
+ found_change=1;
+ }
+}
+
+@ @<Override...@>=
+{
+ if (s-*argv > max_file_name_length-5)
+ @<Complain about argument length@>;
+ if (dot_pos==NULL) {
+ sprintf(tex_file_name,"%s.tex",*argv);
+ sprintf(idx_file_name,"%s.idx",*argv);
+ sprintf(scn_file_name,"%s.scn",*argv);
+ sprintf(C_file_name,"%s.c",*argv);
+ } else {
+ strcpy(tex_file_name,*argv);
+ strcpy(C_file_name,*argv);
+ if (flags['x']) { /* indexes will be generated */
+ *dot_pos=0;
+ sprintf(idx_file_name,"%s.idx",*argv);
+ sprintf(scn_file_name,"%s.scn",*argv);
+ }
+ }
+ found_out=1;
+}
+
+@ @<Handle flag...@>=
+{
+ if (**argv=='-') flag_change=0;
+ else flag_change=1;
+ for(dot_pos=*argv+1;*dot_pos>'\0';dot_pos++)
+ flags[*dot_pos]=flag_change;
+}
+
+@ @<Print usage error message and quit@>=
+{
+if (program==ctangle)
+ fatal(
+"! Usage: ctangle [options] webfile[.w] [{changefile[.ch]|-} [outfile[.c]]]\n"
+ ,"");
+@.Usage:@>
+else fatal(
+"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n"
+ ,"");
+}
+
+@ @<Complain about arg...@>= fatal("! Filename too long\n", *argv);
+@.Filename too long@>
+
+@** Output. Here is the code that opens the output file:
+@^system dependencies@>
+
+@<Defin...@>=
+FILE *C_file; /* where output of \.{CTANGLE} goes */
+FILE *tex_file; /* where output of \.{CWEAVE} goes */
+FILE *idx_file; /* where index from \.{CWEAVE} goes */
+FILE *scn_file; /* where list of sections from \.{CWEAVE} goes */
+FILE *active_file; /* currently active file for \.{CWEAVE} output */
+
+@ @<Scan arguments and open output files@>=
+scan_args();
+if (program==ctangle) {
+ if ((C_file=fopen(C_file_name,"w"))==NULL)
+ fatal("! Cannot open output file ", C_file_name);
+@.Cannot open output file@>
+}
+else {
+ if ((tex_file=fopen(tex_file_name,"w"))==NULL)
+ fatal("! Cannot open output file ", tex_file_name);
+}
+
+@ The |update_terminal| procedure is called when we want
+to make sure that everything we have output to the terminal so far has
+actually left the computer's internal buffers and been sent.
+@^system dependencies@>
+
+@d update_terminal fflush(stdout) /* empty the terminal output buffer */
+
+@ Terminal output uses |putchar| and |putc| when we have to
+translate from \.{CWEB}'s code into the external character code,
+and |printf| when we just want to print strings.
+Several macros make other kinds of output convenient.
+@^system dependencies@>
+@d new_line putchar('\n') @d putxchar putchar
+@d term_write(a,b) fflush(stdout),fwrite(a,sizeof(char),b,stdout)
+@d C_printf(c,a) fprintf(C_file,c,a)
+@d C_putc(c) putc(c,C_file) /* isn't \CEE/ wonderfully consistent? */
+
+@ We predeclare several standard system functions here instead of including
+their system header files, because the names of the header files are not as
+standard as the names of the functions. (For example, some \CEE/ environments
+have \.{<string.h>} where others have \.{<strings.h>}.)
+
+@<Predecl...@>=
+extern int strlen(); /* length of string */
+extern int strcmp(); /* compare strings lexicographically */
+extern char* strcpy(); /* copy one string to another */
+extern int strncmp(); /* compare up to $n$ string characters */
+extern char* strncpy(); /* copy up to $n$ string characters */
+
+@** Index.
diff --git a/web/c_cpp/cweb/ctang-bs.ch b/web/c_cpp/cweb/ctang-bs.ch
new file mode 100644
index 0000000000..c4062c4064
--- /dev/null
+++ b/web/c_cpp/cweb/ctang-bs.ch
@@ -0,0 +1,202 @@
+Changes for CTANGLE for MSDOS and Borland C++ 3.1 using the following
+options (and perhaps others):
+
+ -mc -w-pro -Ff=5000 -Z- -O-p
+
+The options -Z- and -O-p explicitly turn off optimizations that break
+the code. (See makefile.bs.)
+
+The main purpose of these changes is to support MSDOS with full-size arrays
+by using "huge" pointers.
+
+(This file contributed by Barry Schwartz, trashman@crud.mn.org, 28 Jun 94;
+ revised 24 Jul 94.)
+
+
+@x Section 1.
+The ``banner line'' defined here should be changed whenever \.{CTANGLE}
+is modified.
+
+@d banner "This is CTANGLE (Version 3.64)\n"
+@y
+The ``banner line'' defined here should be changed whenever \.{CTANGLE}
+is modified.
+
+@d banner "This is CTANGLE (Version 3.64pc/big)\n"
+@z
+
+
+@x Section 4.
+@ The following parameters were sufficient in the original \.{TANGLE} to
+handle \TEX/,
+so they should be sufficient for most applications of \.{CTANGLE}.
+If you change |max_bytes|, |max_names| or |hash_size| you should also
+change them in the file |"common.w"|.
+
+@d max_bytes 90000 /* the number of bytes in identifiers,
+ index entries, and section names; used in |"common.w"| */
+@d max_toks 270000 /* number of bytes in compressed \CEE/ code */
+@d max_names 4000 /* number of identifiers, strings, section names;
+ must be less than 10240; used in |"common.w"| */
+@d max_texts 2500 /* number of replacement texts, must be less than 10240 */
+@d hash_size 353 /* should be prime; used in |"common.w"| */
+@d longest_name 10000 /* section names shouldn't be longer than this */
+@d stack_size 50 /* number of simultaneous levels of macro expansion */
+@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */
+@y
+@ The following parameters were sufficient in the original \.{TANGLE} to
+handle \TEX/,
+so they should be sufficient for most applications of \.{CTANGLE}.
+If you change |max_bytes|, |max_names| or |hash_size| you should also
+change them in the file |"common.w"|.
+
+(This is a modified version of \.{CTANGLE}, and in fact one of the parameters
+has been reduced in value. The parameter |max_toks|
+has been reduced from 270000 [which
+was sufficient to handle \TEX/] to
+170000, so that \.{CTANGLE}
+may be run on {\mc MSDOS}
+systems that are tight on memory. Consider, for
+instance, an 80286-based machine with several TSRs and drivers, trying
+to run \.{CTANGLE} from a makefile.)
+
+@d max_bytes 90000 /* the number of bytes in identifiers,
+ index entries, and section names; used in |"common.w"| */
+@d max_toks 170000 /* number of bytes in compressed \CEE/ code */
+@d max_names 4000 /* number of identifiers, strings, section names;
+ must be less than 10240; used in |"common.w"| */
+@d max_texts 2500 /* number of replacement texts, must be less than 10240 */
+@d hash_size 353 /* should be prime; used in |"common.w"| */
+@d longest_name 10000 /* section names shouldn't be longer than this */
+@d stack_size 50 /* number of simultaneous levels of macro expansion */
+@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */
+@z
+
+
+@x Section 9.
+@d chunk_marker 0
+
+@<Common code...@>=
+typedef struct name_info {
+ char *byte_start; /* beginning of the name in |byte_mem| */
+ struct name_info *link;
+ union {
+ struct name_info *Rlink; /* right link in binary search tree for section
+ names */
+ char Ilk; /* used by identifiers in \.{CWEAVE} only */
+ } dummy;
+ char *equiv_or_xref; /* info corresponding to names */
+} name_info; /* contains information about an identifier or section name */
+typedef name_info *name_pointer; /* pointer into array of \&{name\_info}s */
+typedef name_pointer *hash_pointer;
+extern char byte_mem[]; /* characters of names */
+extern char *byte_mem_end; /* end of |byte_mem| */
+extern name_info name_dir[]; /* information about names */
+extern name_pointer name_dir_end; /* end of |name_dir| */
+extern name_pointer name_ptr; /* first unused position in |name_dir| */
+extern char *byte_ptr; /* first unused position in |byte_mem| */
+extern name_pointer hash[]; /* heads of hash lists */
+extern hash_pointer hash_end; /* end of |hash| */
+extern hash_pointer h; /* index into hash-head array */
+extern name_pointer id_lookup(); /* looks up a string in the identifier table */
+extern name_pointer section_lookup(); /* finds section name */
+extern void print_section_name(), sprint_section_name();
+@y
+@d chunk_marker 0
+
+@f huge extern
+
+@<Common code...@>=
+typedef struct name_info {
+ char huge* byte_start; /* beginning of the name in |byte_mem| */
+ struct name_info *link;
+ union {
+ struct name_info *Rlink; /* right link in binary search tree for section
+ names */
+ char Ilk; /* used by identifiers in \.{CWEAVE} only */
+ } dummy;
+ union {
+ char *equiv_member;
+ char huge* xref_member;
+ } ptr_union; /* info corresponding to names */
+} name_info; /* contains information about an identifier or section name */
+typedef name_info *name_pointer; /* pointer into array of \&{name\_info}s */
+typedef name_pointer *hash_pointer;
+extern char huge byte_mem[]; /* characters of names */
+extern char huge* byte_mem_end; /* end of |byte_mem| */
+extern name_info name_dir[]; /* information about names */
+extern name_pointer name_dir_end; /* end of |name_dir| */
+extern name_pointer name_ptr; /* first unused position in |name_dir| */
+extern char huge* byte_ptr; /* first unused position in |byte_mem| */
+extern name_pointer hash[]; /* heads of hash lists */
+extern hash_pointer hash_end; /* end of |hash| */
+extern hash_pointer h; /* index into hash-head array */
+extern name_pointer id_lookup(); /* looks up a string in the identifier table */
+extern name_pointer section_lookup(); /* finds section name */
+extern void print_section_name(), sprint_section_name();
+@z
+
+
+@x Section 16.
+ eight_bits *tok_start; /* pointer into |tok_mem| */
+ sixteen_bits text_link; /* relates replacement texts */
+} text;
+typedef text *text_pointer;
+@y
+ eight_bits huge* tok_start; /* pointer into |tok_mem| */
+ sixteen_bits text_link; /* relates replacement texts */
+} text;
+typedef text *text_pointer;
+@z
+
+
+@x Section 17.
+eight_bits tok_mem[max_toks];
+eight_bits *tok_mem_end=tok_mem+max_toks-1;
+eight_bits *tok_ptr; /* first unused position in |tok_mem| */
+@y
+eight_bits huge tok_mem[max_toks];
+eight_bits huge* tok_mem_end;
+eight_bits huge* tok_ptr; /* first unused position in |tok_mem| */
+@z
+
+
+@x Section 18.
+text_info->tok_start=tok_ptr=tok_mem;
+text_ptr=text_info+1; text_ptr->tok_start=tok_mem;
+ /* this makes replacement text 0 of length zero */
+@y
+tok_mem_end=tok_mem+max_toks-1;
+text_info->tok_start=tok_ptr=tok_mem;
+text_ptr=text_info+1; text_ptr->tok_start=tok_mem;
+ /* this makes replacement text 0 of length zero */
+@z
+
+
+@x Section 19.
+@d equiv equiv_or_xref /* info corresponding to names */
+@y
+@d equiv ptr_union.equiv_member /* info corresponding to names */
+@z
+
+
+@x Section 27.
+ eight_bits *end_field; /* ending location of replacement text */
+ eight_bits *byte_field; /* present location within replacement text */
+@y
+ eight_bits huge* end_field; /* ending location of replacement text */
+ eight_bits huge* byte_field; /* present location within replacement text */
+@z
+
+
+@x Section 49.
+out_char(cur_char)
+eight_bits cur_char;
+{
+ char *j, *k; /* pointer into |byte_mem| */
+@y
+out_char(cur_char)
+eight_bits cur_char;
+{
+ char huge* j, huge* k; /* pointer into |byte_mem| */
+@z
diff --git a/web/c_cpp/cweb/ctang-man.ch b/web/c_cpp/cweb/ctang-man.ch
new file mode 100644
index 0000000000..12e9d3248e
--- /dev/null
+++ b/web/c_cpp/cweb/ctang-man.ch
@@ -0,0 +1,22 @@
+Change file to help make Appendix E of the full CWEB manual
+@x
+\def\botofcontents{\vfill
+\noindent
+Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth
+\bigskip\noindent
+Permission is granted to make and distribute verbatim copies of this
+document provided that the copyright notice and this permission notice
+are preserved on all copies.
+
+\smallskip\noindent
+Permission is granted to copy and distribute modified versions of this
+document under the conditions for verbatim copying, provided that the
+entire resulting derived work is given a different name and distributed
+under the terms of a permission notice identical to this one.
+}
+@y
+\def\botofcontents{\vfill\titlefalse}
+\def\contentspagenumber{63}
+\def\title{APPENDIX E: CTANGLE}
+\let\K=\leftarrow
+@z
diff --git a/web/c_cpp/cweb/ctang-pc.ch b/web/c_cpp/cweb/ctang-pc.ch
new file mode 100644
index 0000000000..67f32fae0c
--- /dev/null
+++ b/web/c_cpp/cweb/ctang-pc.ch
@@ -0,0 +1,24 @@
+This is the change file for CWEB's CTANGLE under DOS
+(Contributed by Lee Wittenberg, March 1993)
+
+Changes necessary for compiling with Borland C/C++
+Use compilation switches -mc -w-pro -Ff=5000
+
+Note: The changes to section 4 are not necessary if using a compiler
+that allows >64K arrays. If you need lots of bytes and toks, try the
+alternate change files with -bs suffix instead of -pc.
+
+@x section 1
+@d banner "This is CTANGLE (Version 3.64)\n"
+@y
+@d banner "This is CTANGLE (Version 3.64pc)\n"
+@z
+@x section 4
+@d max_bytes 90000 /* the number of bytes in identifiers,
+ index entries, and section names; used in |"common.w"| */
+@d max_toks 270000 /* number of bytes in compressed \CEE/ code */
+@y (note that CWEAVE itself needs only about 42K toks)
+@d max_bytes (unsigned)60000 /* the number of bytes in identifiers,
+ index entries, and section names; used in |"common.w"| */
+@d max_toks (unsigned)60000 /* number of bytes in compressed \CEE/ code */
+@z
diff --git a/web/c_cpp/cweb/ctang-ql.ch b/web/c_cpp/cweb/ctang-ql.ch
new file mode 100644
index 0000000000..a0920243a9
--- /dev/null
+++ b/web/c_cpp/cweb/ctang-ql.ch
@@ -0,0 +1,25 @@
+This is the change file for CWEB's CTANGLE under QDOS/SMSQ
+(Contributed by Robert H. Klein, September 1994)
+
+This change file is intended for use with C68 v4.13 (or later).
+compile with
+ex <dev_>cc;"-v -h -c -=500000 ctangle_c"
+
+
+@x
+\def\title{CTANGLE (Version 3.64)}
+@y
+\def\title{CTANGLE (QL Version 3.64)}
+@z
+
+@x section 1
+@d banner "This is CTANGLE (Version 3.64)\n"
+@y
+@d banner "This is CTANGLE (QL Version 3.64)\n"
+@z
+
+@x
+@i common.h
+@y
+@i common_h
+@z
diff --git a/web/c_cpp/cweb/ctang-vms.ch b/web/c_cpp/cweb/ctang-vms.ch
new file mode 100644
index 0000000000..7e538abc27
--- /dev/null
+++ b/web/c_cpp/cweb/ctang-vms.ch
@@ -0,0 +1,35 @@
+This is the change file for CWEB's CTANGLE for VAX/VMS.
+
+created:
+ 01-FEB-1992 ST (Stephan Trebels <trebels@ams02.dnet.gwdg.de>)
+ > include ctype,stdio from textlibrary SYS$SHARE:VAXCDEF.TLB
+ > change banner line to include (VAX/VMS)
+ ? will someone make a CLD interface? (should be easy)
+
+(also modified by Don Knuth to keep version numbers uptodate)
+(these changes not necessary for initial bootstrapping)
+
+@x section 1 (01-FEB-1992 ST)
+@d banner "This is CTANGLE (Version 3.64)\n"
+@y
+@d banner "This is CTANGLE (VAX/VMS Version 3.64)\n"
+@z
+
+@x section 6 (from common.h) (01-FEB-1992 ST)
+#include <stdio.h>
+@y
+#include stdio /* VMS searches Textlibraries faster */
+@z
+
+@x section 62 (01-FEB-1992 ST)
+#include <ctype.h> /* definition of |isalpha|, |isdigit| and so on */
+@y
+#include ctype /* definition of |isalpha|, |isdigit| and so on */
+ /* VMS searches text libraries faster */
+@z
+
+@x section 63 (01-FEB-1992 ST)
+@d isxalpha(c) ((c)=='_') /* non-alpha character allowed in identifier */
+@y
+@d isxalpha(c) ((c)=='_' || (c)=='$') /* non-alpha characters allowed in id */
+@z
diff --git a/web/c_cpp/cweb/ctang-w32.ch b/web/c_cpp/cweb/ctang-w32.ch
new file mode 100644
index 0000000000..523985ce3d
--- /dev/null
+++ b/web/c_cpp/cweb/ctang-w32.ch
@@ -0,0 +1,66 @@
+This is the change file for CWEB's CTANGLE under Win32
+(Contributed by Fabrice Popineau, February 2002)
+
+Changes necessary for compiling with Borland C/C++
+
+@x section 1
+@d banner "This is CTANGLE (Version 3.64)\n"
+@y
+@d banner "This is CTANGLE (Version 3.64win32)\n"
+@z
+
+@x
+@ We predeclare several standard system functions here instead of including
+their system header files, because the names of the header files are not as
+standard as the names of the functions. (For example, some \CEE/ environments
+have \.{<string.h>} where others have \.{<strings.h>}.)
+
+@<Predecl...@>=
+extern int strlen(); /* length of string */
+extern int strcmp(); /* compare strings lexicographically */
+extern char* strcpy(); /* copy one string to another */
+extern int strncmp(); /* compare up to $n$ string characters */
+extern char* strncpy(); /* copy up to $n$ string characters */
+@y
+@z
+
+@x
+int names_match(p,first,l)
+name_pointer p; /* points to the proposed match */
+char *first; /* position of first character of string */
+@y
+int __cdecl names_match(p,first,l)
+name_pointer p; /* points to the proposed match */
+char *first; /* position of first character of string */
+@z
+
+@x
+void
+init_node(node)
+name_pointer node;
+{
+ node->equiv=(char *)text_info;
+}
+void
+init_p() {}
+@y
+void
+init_node(node)
+name_pointer node;
+{
+ node->equiv=(char *)text_info;
+}
+void __cdecl
+init_p() {}
+@z
+
+@x
+@ @<Include...@>=
+#include <ctype.h> /* definition of |isalpha|, |isdigit| and so on */
+#include <stdlib.h> /* definition of |exit| */
+@y
+@ @<Include...@>=
+#include <ctype.h> /* definition of |isalpha|, |isdigit| and so on */
+#include <stdlib.h> /* definition of |exit| */
+#include <string.h>
+@z
diff --git a/web/c_cpp/cweb/ctangle.c b/web/c_cpp/cweb/ctangle.c
new file mode 100644
index 0000000000..b7a1b553ce
--- /dev/null
+++ b/web/c_cpp/cweb/ctangle.c
@@ -0,0 +1,1579 @@
+/*1:*/
+#line 64 "ctangle.w"
+
+/*6:*/
+#line 35 "common.h"
+
+#include <stdio.h>
+
+/*:6*//*62:*/
+#line 888 "ctangle.w"
+
+#include <ctype.h>
+#include <stdlib.h>
+
+/*:62*/
+#line 65 "ctangle.w"
+
+#define banner "This is CTANGLE (Version 3.64)\n" \
+
+#define max_bytes 90000 \
+
+#define max_toks 270000
+#define max_names 4000 \
+
+#define max_texts 2500
+#define hash_size 353
+#define longest_name 10000
+#define stack_size 50
+#define buf_size 100 \
+
+#define ctangle 0
+#define cweave 1 \
+
+#define and_and 04
+#define lt_lt 020
+#define gt_gt 021
+#define plus_plus 013
+#define minus_minus 01
+#define minus_gt 031
+#define not_eq 032
+#define lt_eq 034
+#define gt_eq 035
+#define eq_eq 036
+#define or_or 037
+#define dot_dot_dot 016
+#define colon_colon 06
+#define period_ast 026
+#define minus_gt_ast 027 \
+
+#define xisalpha(c) (isalpha(c) &&((eight_bits) c<0200) )
+#define xisdigit(c) (isdigit(c) &&((eight_bits) c<0200) )
+#define xisspace(c) (isspace(c) &&((eight_bits) c<0200) )
+#define xislower(c) (islower(c) &&((eight_bits) c<0200) )
+#define xisupper(c) (isupper(c) &&((eight_bits) c<0200) )
+#define xisxdigit(c) (isxdigit(c) &&((eight_bits) c<0200) ) \
+
+#define length(c) (c+1) ->byte_start-(c) ->byte_start
+#define print_id(c) term_write((c) ->byte_start,length((c) ) )
+#define llink link
+#define rlink dummy.Rlink
+#define root name_dir->rlink \
+
+#define chunk_marker 0 \
+
+#define spotless 0
+#define harmless_message 1
+#define error_message 2
+#define fatal_message 3
+#define mark_harmless {if(history==spotless) history= harmless_message;}
+#define mark_error history= error_message
+#define confusion(s) fatal("! This can't happen: ",s) \
+
+#define max_file_name_length 60
+#define cur_file file[include_depth]
+#define cur_file_name file_name[include_depth]
+#define web_file_name file_name[0]
+#define cur_line line[include_depth] \
+
+#define show_banner flags['b']
+#define show_progress flags['p']
+#define show_happiness flags['h'] \
+
+#define update_terminal fflush(stdout)
+#define new_line putchar('\n')
+#define putxchar putchar
+#define term_write(a,b) fflush(stdout) ,fwrite(a,sizeof(char) ,b,stdout)
+#define C_printf(c,a) fprintf(C_file,c,a)
+#define C_putc(c) putc(c,C_file) \
+
+#define equiv equiv_or_xref \
+
+#define section_flag max_texts \
+
+#define string 02
+#define join 0177
+#define output_defs_flag (2*024000-1) \
+
+#define cur_end cur_state.end_field
+#define cur_byte cur_state.byte_field
+#define cur_name cur_state.name_field
+#define cur_repl cur_state.repl_field
+#define cur_section cur_state.section_field \
+
+#define section_number 0201
+#define identifier 0202 \
+
+#define normal 0
+#define num_or_id 1
+#define post_slash 2
+#define unbreakable 3
+#define verbatim 4 \
+
+#define max_files 256
+#define translit_length 10 \
+
+#define ignore 0
+#define ord 0302
+#define control_text 0303
+#define translit_code 0304
+#define output_defs_code 0305
+#define format_code 0306
+#define definition 0307
+#define begin_C 0310
+#define section_name 0311
+#define new_section 0312 \
+
+#define constant 03 \
+
+#define isxalpha(c) ((c) =='_'||(c) =='$') \
+
+#define ishigh(c) ((unsigned char) (c) > 0177) \
+ \
+
+#define compress(c) if(loc++<=limit) return(c) \
+
+#define macro 0
+#define app_repl(c) {if(tok_ptr==tok_mem_end) overflow("token") ;*tok_ptr++= c;} \
+
+
+#line 66 "ctangle.w"
+
+/*5:*/
+#line 29 "common.h"
+
+typedef short boolean;
+typedef char unsigned eight_bits;
+extern boolean program;
+extern int phase;
+
+/*:5*//*7:*/
+#line 57 "common.h"
+
+char section_text[longest_name+1];
+char*section_text_end= section_text+longest_name;
+char*id_first;
+char*id_loc;
+
+/*:7*//*8:*/
+#line 72 "common.h"
+
+extern char buffer[];
+extern char*buffer_end;
+extern char*loc;
+extern char*limit;
+
+/*:8*//*9:*/
+#line 87 "common.h"
+
+typedef struct name_info{
+char*byte_start;
+struct name_info*link;
+union{
+struct name_info*Rlink;
+
+char Ilk;
+}dummy;
+char*equiv_or_xref;
+}name_info;
+typedef name_info*name_pointer;
+typedef name_pointer*hash_pointer;
+extern char byte_mem[];
+extern char*byte_mem_end;
+extern name_info name_dir[];
+extern name_pointer name_dir_end;
+extern name_pointer name_ptr;
+extern char*byte_ptr;
+extern name_pointer hash[];
+extern hash_pointer hash_end;
+extern hash_pointer h;
+extern name_pointer id_lookup();
+extern name_pointer section_lookup();
+extern void print_section_name(),sprint_section_name();
+
+/*:9*//*10:*/
+#line 122 "common.h"
+
+extern history;
+extern err_print();
+extern wrap_up();
+extern void fatal();
+extern void overflow();
+
+/*:10*//*11:*/
+#line 137 "common.h"
+
+extern include_depth;
+extern FILE*file[];
+extern FILE*change_file;
+extern char C_file_name[];
+extern char tex_file_name[];
+extern char idx_file_name[];
+extern char scn_file_name[];
+extern char file_name[][max_file_name_length];
+
+extern char change_file_name[];
+extern line[];
+extern change_line;
+extern change_depth;
+extern boolean input_has_ended;
+extern boolean changing;
+extern boolean web_file_open;
+extern reset_input();
+extern get_line();
+extern check_complete();
+
+/*:11*//*12:*/
+#line 159 "common.h"
+
+typedef unsigned short sixteen_bits;
+extern sixteen_bits section_count;
+extern boolean changed_section[];
+extern boolean change_pending;
+extern boolean print_where;
+
+/*:12*//*13:*/
+#line 171 "common.h"
+
+extern int argc;
+extern char**argv;
+extern boolean flags[];
+
+/*:13*//*14:*/
+#line 183 "common.h"
+
+extern FILE*C_file;
+extern FILE*tex_file;
+extern FILE*idx_file;
+extern FILE*scn_file;
+extern FILE*active_file;
+
+/*:14*//*15:*/
+#line 192 "common.h"
+
+extern void common_init();
+#line 128 "ctangle.w"
+
+/*:15*/
+#line 67 "ctangle.w"
+
+/*16:*/
+#line 152 "ctangle.w"
+
+typedef struct{
+eight_bits*tok_start;
+sixteen_bits text_link;
+}text;
+typedef text*text_pointer;
+
+/*:16*//*27:*/
+#line 296 "ctangle.w"
+
+typedef struct{
+eight_bits*end_field;
+eight_bits*byte_field;
+name_pointer name_field;
+text_pointer repl_field;
+sixteen_bits section_field;
+}output_state;
+typedef output_state*stack_pointer;
+
+/*:27*/
+#line 68 "ctangle.w"
+
+/*17:*/
+#line 159 "ctangle.w"
+
+text text_info[max_texts];
+text_pointer text_info_end= text_info+max_texts-1;
+text_pointer text_ptr;
+eight_bits tok_mem[max_toks];
+eight_bits*tok_mem_end= tok_mem+max_toks-1;
+eight_bits*tok_ptr;
+
+/*:17*//*23:*/
+#line 227 "ctangle.w"
+
+text_pointer last_unnamed;
+
+/*:23*//*28:*/
+#line 312 "ctangle.w"
+
+output_state cur_state;
+
+output_state stack[stack_size+1];
+stack_pointer stack_ptr;
+stack_pointer stack_end= stack+stack_size;
+
+/*:28*//*32:*/
+#line 384 "ctangle.w"
+
+int cur_val;
+
+/*:32*//*36:*/
+#line 473 "ctangle.w"
+
+eight_bits out_state;
+boolean protect;
+
+/*:36*//*38:*/
+#line 502 "ctangle.w"
+
+name_pointer output_files[max_files];
+name_pointer*cur_out_file,*end_output_files,*an_output_file;
+char cur_section_name_char;
+char output_file_name[longest_name];
+
+/*:38*//*45:*/
+#line 599 "ctangle.w"
+
+boolean output_defs_seen= 0;
+
+/*:45*//*51:*/
+#line 710 "ctangle.w"
+
+char translit[128][translit_length];
+
+/*:51*//*56:*/
+#line 789 "ctangle.w"
+
+eight_bits ccode[256];
+
+/*:56*//*59:*/
+#line 845 "ctangle.w"
+
+boolean comment_continues= 0;
+
+/*:59*//*61:*/
+#line 884 "ctangle.w"
+
+name_pointer cur_section_name;
+int no_where;
+
+/*:61*//*75:*/
+#line 1195 "ctangle.w"
+
+text_pointer cur_text;
+eight_bits next_control;
+
+/*:75*//*82:*/
+#line 1353 "ctangle.w"
+
+extern sixteen_bits section_count;
+
+/*:82*/
+#line 69 "ctangle.w"
+
+/*2:*/
+#line 77 "ctangle.w"
+
+extern int strlen();
+extern int strcmp();
+extern char*strcpy();
+extern int strncmp();
+extern char*strncpy();
+
+/*:2*//*41:*/
+#line 533 "ctangle.w"
+
+void phase_two();
+
+/*:41*//*46:*/
+#line 602 "ctangle.w"
+
+void output_defs();
+
+/*:46*//*48:*/
+#line 648 "ctangle.w"
+
+static void out_char();
+
+/*:48*//*90:*/
+#line 1460 "ctangle.w"
+
+void phase_one();
+
+/*:90*//*92:*/
+#line 1478 "ctangle.w"
+
+void skip_limbo();
+
+/*:92*/
+#line 70 "ctangle.w"
+
+
+/*:1*//*3:*/
+#line 91 "ctangle.w"
+
+int main(ac,av)
+int ac;
+char**av;
+{
+argc= ac;argv= av;
+program= ctangle;
+/*18:*/
+#line 167 "ctangle.w"
+
+text_info->tok_start= tok_ptr= tok_mem;
+text_ptr= text_info+1;text_ptr->tok_start= tok_mem;
+
+
+/*:18*//*20:*/
+#line 177 "ctangle.w"
+
+name_dir->equiv= (char*)text_info;
+
+/*:20*//*24:*/
+#line 230 "ctangle.w"
+last_unnamed= text_info;text_info->text_link= 0;
+
+/*:24*//*39:*/
+#line 512 "ctangle.w"
+
+cur_out_file= end_output_files= output_files+max_files;
+
+/*:39*//*52:*/
+#line 713 "ctangle.w"
+
+{
+int i;
+for(i= 0;i<128;i++)sprintf(translit[i],"X%02X",(unsigned)(128+i));
+}
+
+/*:52*//*57:*/
+#line 792 "ctangle.w"
+{
+int c;
+for(c= 0;c<256;c++)ccode[c]= ignore;
+ccode[' ']= ccode['\t']= ccode['\n']= ccode['\v']= ccode['\r']= ccode['\f']
+= ccode['*']= new_section;
+ccode['@']= '@';ccode['=']= string;
+ccode['d']= ccode['D']= definition;
+ccode['f']= ccode['F']= ccode['s']= ccode['S']= format_code;
+ccode['c']= ccode['C']= ccode['p']= ccode['P']= begin_C;
+ccode['^']= ccode[':']= ccode['.']= ccode['t']= ccode['T']=
+ccode['q']= ccode['Q']= control_text;
+ccode['h']= ccode['H']= output_defs_code;
+ccode['l']= ccode['L']= translit_code;
+ccode['&']= join;
+ccode['<']= ccode['(']= section_name;
+ccode['\'']= ord;
+}
+
+/*:57*//*71:*/
+#line 1116 "ctangle.w"
+section_text[0]= ' ';
+
+/*:71*/
+#line 98 "ctangle.w"
+;
+common_init();
+if(show_banner)printf(banner);
+phase_one();
+phase_two();
+return wrap_up();
+}
+
+/*:3*//*21:*/
+#line 183 "ctangle.w"
+
+int names_match(p,first,l)
+name_pointer p;
+char*first;
+int l;
+{
+if(length(p)!=l)return 0;
+return!strncmp(first,p->byte_start,l);
+}
+
+/*:21*//*22:*/
+#line 198 "ctangle.w"
+
+void
+init_node(node)
+name_pointer node;
+{
+node->equiv= (char*)text_info;
+}
+void
+init_p(){}
+
+/*:22*//*26:*/
+#line 260 "ctangle.w"
+
+void
+store_two_bytes(x)
+sixteen_bits x;
+{
+if(tok_ptr+2> tok_mem_end)overflow("token");
+*tok_ptr++= x>>8;
+*tok_ptr++= x&0377;
+}
+
+/*:26*//*30:*/
+#line 336 "ctangle.w"
+
+void
+push_level(p)
+name_pointer p;
+{
+if(stack_ptr==stack_end)overflow("stack");
+*stack_ptr= cur_state;
+stack_ptr++;
+if(p!=NULL){
+cur_name= p;cur_repl= (text_pointer)p->equiv;
+cur_byte= cur_repl->tok_start;cur_end= (cur_repl+1)->tok_start;
+cur_section= 0;
+}
+}
+
+/*:30*//*31:*/
+#line 355 "ctangle.w"
+
+void
+pop_level(flag)
+int flag;
+{
+if(flag&&cur_repl->text_link<section_flag){
+cur_repl= cur_repl->text_link+text_info;
+cur_byte= cur_repl->tok_start;cur_end= (cur_repl+1)->tok_start;
+return;
+}
+stack_ptr--;
+if(stack_ptr> stack)cur_state= *stack_ptr;
+}
+
+/*:31*//*33:*/
+#line 391 "ctangle.w"
+
+void
+get_output()
+{
+sixteen_bits a;
+restart:if(stack_ptr==stack)return;
+if(cur_byte==cur_end){
+cur_val= -((int)cur_section);
+pop_level(1);
+if(cur_val==0)goto restart;
+out_char(section_number);return;
+}
+a= *cur_byte++;
+if(out_state==verbatim&&a!=string&&a!=constant&&a!='\n')
+C_putc(a);
+else if(a<0200)out_char(a);
+else{
+a= (a-0200)*0400+*cur_byte++;
+switch(a/024000){
+case 0:cur_val= a;out_char(identifier);break;
+case 1:if(a==output_defs_flag)output_defs();
+else/*34:*/
+#line 423 "ctangle.w"
+
+{
+a-= 024000;
+if((a+name_dir)->equiv!=(char*)text_info)push_level(a+name_dir);
+else if(a!=0){
+printf("\n! Not present: <");
+print_section_name(a+name_dir);err_print(">");
+
+}
+goto restart;
+}
+
+/*:34*/
+#line 412 "ctangle.w"
+;
+break;
+default:cur_val= a-050000;if(cur_val> 0)cur_section= cur_val;
+out_char(section_number);
+}
+}
+}
+
+/*:33*//*37:*/
+#line 481 "ctangle.w"
+
+void
+flush_buffer()
+{
+C_putc('\n');
+if(cur_line%100==0&&show_progress){
+printf(".");
+if(cur_line%500==0)printf("%d",cur_line);
+update_terminal;
+}
+cur_line++;
+}
+
+/*:37*//*42:*/
+#line 536 "ctangle.w"
+
+void
+phase_two(){
+web_file_open= 0;
+cur_line= 1;
+/*29:*/
+#line 325 "ctangle.w"
+
+stack_ptr= stack+1;cur_name= name_dir;cur_repl= text_info->text_link+text_info;
+cur_byte= cur_repl->tok_start;cur_end= (cur_repl+1)->tok_start;cur_section= 0;
+
+/*:29*/
+#line 541 "ctangle.w"
+;
+/*44:*/
+#line 595 "ctangle.w"
+
+if(!output_defs_seen)
+output_defs();
+
+/*:44*/
+#line 542 "ctangle.w"
+;
+if(text_info->text_link==0&&cur_out_file==end_output_files){
+printf("\n! No program text was specified.");mark_harmless;
+
+}
+else{
+if(cur_out_file==end_output_files){
+if(show_progress)
+printf("\nWriting the output file (%s):",C_file_name);
+}
+else{
+if(show_progress){
+printf("\nWriting the output files:");
+
+printf(" (%s)",C_file_name);
+update_terminal;
+}
+if(text_info->text_link==0)goto writeloop;
+}
+while(stack_ptr> stack)get_output();
+flush_buffer();
+writeloop:/*43:*/
+#line 572 "ctangle.w"
+
+for(an_output_file= end_output_files;an_output_file> cur_out_file;){
+an_output_file--;
+sprint_section_name(output_file_name,*an_output_file);
+fclose(C_file);
+C_file= fopen(output_file_name,"w");
+if(C_file==0)fatal("! Cannot open output file:",output_file_name);
+
+printf("\n(%s)",output_file_name);update_terminal;
+cur_line= 1;
+stack_ptr= stack+1;
+cur_name= (*an_output_file);
+cur_repl= (text_pointer)cur_name->equiv;
+cur_byte= cur_repl->tok_start;
+cur_end= (cur_repl+1)->tok_start;
+while(stack_ptr> stack)get_output();
+flush_buffer();
+}
+
+/*:43*/
+#line 563 "ctangle.w"
+;
+if(show_happiness)printf("\nDone.");
+}
+}
+
+/*:42*//*47:*/
+#line 605 "ctangle.w"
+
+void
+output_defs()
+{
+sixteen_bits a;
+push_level(NULL);
+for(cur_text= text_info+1;cur_text<text_ptr;cur_text++)
+if(cur_text->text_link==0){
+cur_byte= cur_text->tok_start;
+cur_end= (cur_text+1)->tok_start;
+C_printf("%s","#define ");
+out_state= normal;
+protect= 1;
+while(cur_byte<cur_end){
+a= *cur_byte++;
+if(cur_byte==cur_end&&a=='\n')break;
+if(out_state==verbatim&&a!=string&&a!=constant&&a!='\n')
+C_putc(a);
+
+else if(a<0200)out_char(a);
+else{
+a= (a-0200)*0400+*cur_byte++;
+if(a<024000){
+cur_val= a;out_char(identifier);
+}
+else if(a<050000){confusion("macro defs have strange char");}
+else{
+cur_val= a-050000;cur_section= cur_val;out_char(section_number);
+}
+
+}
+}
+protect= 0;
+flush_buffer();
+}
+pop_level(0);
+}
+
+/*:47*//*49:*/
+#line 651 "ctangle.w"
+
+static void
+out_char(cur_char)
+eight_bits cur_char;
+{
+char*j,*k;
+restart:
+switch(cur_char){
+case'\n':if(protect&&out_state!=verbatim)C_putc(' ');
+if(protect||out_state==verbatim)C_putc('\\');
+flush_buffer();if(out_state!=verbatim)out_state= normal;break;
+/*53:*/
+#line 719 "ctangle.w"
+
+case identifier:
+if(out_state==num_or_id)C_putc(' ');
+j= (cur_val+name_dir)->byte_start;
+k= (cur_val+name_dir+1)->byte_start;
+while(j<k){
+if((unsigned char)(*j)<0200)C_putc(*j);
+
+else C_printf("%s",translit[(unsigned char)(*j)-0200]);
+j++;
+}
+out_state= num_or_id;break;
+
+/*:53*/
+#line 662 "ctangle.w"
+;
+/*54:*/
+#line 732 "ctangle.w"
+
+case section_number:
+if(cur_val> 0)C_printf("/*%d:*/",cur_val);
+else if(cur_val<0)C_printf("/*:%d*/",-cur_val);
+else if(protect){
+cur_byte+= 4;
+cur_char= '\n';
+goto restart;
+}else{
+sixteen_bits a;
+a= 0400**cur_byte++;
+a+= *cur_byte++;
+C_printf("\n#line %d \"",a);
+
+cur_val= *cur_byte++;
+cur_val= 0400*(cur_val-0200)+*cur_byte++;
+for(j= (cur_val+name_dir)->byte_start,k= (cur_val+name_dir+1)->byte_start;
+j<k;j++){
+if(*j=='\\'||*j=='"')C_putc('\\');
+C_putc(*j);
+}
+C_printf("%s","\"\n");
+}
+break;
+
+/*:54*/
+#line 663 "ctangle.w"
+;
+/*50:*/
+#line 681 "ctangle.w"
+
+case plus_plus:C_putc('+');C_putc('+');out_state= normal;break;
+case minus_minus:C_putc('-');C_putc('-');out_state= normal;break;
+case minus_gt:C_putc('-');C_putc('>');out_state= normal;break;
+case gt_gt:C_putc('>');C_putc('>');out_state= normal;break;
+case eq_eq:C_putc('=');C_putc('=');out_state= normal;break;
+case lt_lt:C_putc('<');C_putc('<');out_state= normal;break;
+case gt_eq:C_putc('>');C_putc('=');out_state= normal;break;
+case lt_eq:C_putc('<');C_putc('=');out_state= normal;break;
+case not_eq:C_putc('!');C_putc('=');out_state= normal;break;
+case and_and:C_putc('&');C_putc('&');out_state= normal;break;
+case or_or:C_putc('|');C_putc('|');out_state= normal;break;
+case dot_dot_dot:C_putc('.');C_putc('.');C_putc('.');out_state= normal;
+break;
+case colon_colon:C_putc(':');C_putc(':');out_state= normal;break;
+case period_ast:C_putc('.');C_putc('*');out_state= normal;break;
+case minus_gt_ast:C_putc('-');C_putc('>');C_putc('*');out_state= normal;
+break;
+
+/*:50*/
+#line 664 "ctangle.w"
+;
+case'=':case'>':C_putc(cur_char);C_putc(' ');
+out_state= normal;break;
+case join:out_state= unbreakable;break;
+case constant:if(out_state==verbatim){
+out_state= num_or_id;break;
+}
+if(out_state==num_or_id)C_putc(' ');out_state= verbatim;break;
+case string:if(out_state==verbatim)out_state= normal;
+else out_state= verbatim;break;
+case'/':C_putc('/');out_state= post_slash;break;
+case'*':if(out_state==post_slash)C_putc(' ');
+
+default:C_putc(cur_char);out_state= normal;break;
+}
+}
+
+/*:49*//*58:*/
+#line 813 "ctangle.w"
+
+eight_bits
+skip_ahead()
+{
+eight_bits c;
+while(1){
+if(loc> limit&&(get_line()==0))return(new_section);
+*(limit+1)= '@';
+while(*loc!='@')loc++;
+if(loc<=limit){
+loc++;c= ccode[(eight_bits)*loc];loc++;
+if(c!=ignore||*(loc-1)=='>')return(c);
+}
+}
+}
+
+/*:58*//*60:*/
+#line 848 "ctangle.w"
+
+int skip_comment(is_long_comment)
+boolean is_long_comment;
+{
+char c;
+while(1){
+if(loc> limit){
+if(is_long_comment){
+if(get_line())return(comment_continues= 1);
+else{
+err_print("! Input ended in mid-comment");
+
+return(comment_continues= 0);
+}
+}
+else return(comment_continues= 0);
+}
+c= *(loc++);
+if(is_long_comment&&c=='*'&&*loc=='/'){
+loc++;return(comment_continues= 0);
+}
+if(c=='@'){
+if(ccode[(eight_bits)*loc]==new_section){
+err_print("! Section name ended in mid-comment");loc--;
+
+return(comment_continues= 0);
+}
+else loc++;
+}
+}
+}
+
+/*:60*//*63:*/
+#line 900 "ctangle.w"
+
+eight_bits
+get_next()
+{
+static int preprocessing= 0;
+eight_bits c;
+while(1){
+if(loc> limit){
+if(preprocessing&&*(limit-1)!='\\')preprocessing= 0;
+if(get_line()==0)return(new_section);
+else if(print_where&&!no_where){
+print_where= 0;
+/*77:*/
+#line 1225 "ctangle.w"
+
+store_two_bytes(0150000);
+if(changing&&include_depth==change_depth){
+id_first= change_file_name;
+store_two_bytes((sixteen_bits)change_line);
+}else{
+id_first= cur_file_name;
+store_two_bytes((sixteen_bits)cur_line);
+}
+id_loc= id_first+strlen(id_first);
+{int a= id_lookup(id_first,id_loc,0)-name_dir;app_repl((a/0400)+0200);
+app_repl(a%0400);}
+
+/*:77*/
+#line 912 "ctangle.w"
+;
+}
+else return('\n');
+}
+c= *loc;
+if(comment_continues||(c=='/'&&(*(loc+1)=='*'||*(loc+1)=='/'))){
+skip_comment(comment_continues||*(loc+1)=='*');
+
+if(comment_continues)return('\n');
+else continue;
+}
+loc++;
+if(xisdigit(c)||c=='.')/*66:*/
+#line 978 "ctangle.w"
+{
+id_first= loc-1;
+if(*id_first=='.'&&!xisdigit(*loc))goto mistake;
+if(*id_first=='0'){
+if(*loc=='x'||*loc=='X'){
+loc++;while(xisxdigit(*loc))loc++;goto found;
+}
+}
+while(xisdigit(*loc))loc++;
+if(*loc=='.'){
+loc++;
+while(xisdigit(*loc))loc++;
+}
+if(*loc=='e'||*loc=='E'){
+if(*++loc=='+'||*loc=='-')loc++;
+while(xisdigit(*loc))loc++;
+}
+found:while(*loc=='u'||*loc=='U'||*loc=='l'||*loc=='L'
+||*loc=='f'||*loc=='F')loc++;
+id_loc= loc;
+return(constant);
+}
+
+/*:66*/
+#line 924 "ctangle.w"
+
+else if(c=='\''||c=='"'||(c=='L'&&(*loc=='\''||*loc=='"')))
+/*67:*/
+#line 1006 "ctangle.w"
+{
+char delim= c;
+id_first= section_text+1;
+id_loc= section_text;*++id_loc= delim;
+if(delim=='L'){
+delim= *loc++;*++id_loc= delim;
+}
+while(1){
+if(loc>=limit){
+if(*(limit-1)!='\\'){
+err_print("! String didn't end");loc= limit;break;
+
+}
+if(get_line()==0){
+err_print("! Input ended in middle of string");loc= buffer;break;
+
+}
+else if(++id_loc<=section_text_end)*id_loc= '\n';
+
+}
+if((c= *loc++)==delim){
+if(++id_loc<=section_text_end)*id_loc= c;
+break;
+}
+if(c=='\\'){
+if(loc>=limit)continue;
+if(++id_loc<=section_text_end)*id_loc= '\\';
+c= *loc++;
+}
+if(++id_loc<=section_text_end)*id_loc= c;
+}
+if(id_loc>=section_text_end){
+printf("\n! String too long: ");
+
+term_write(section_text+1,25);
+err_print("...");
+}
+id_loc++;
+return(string);
+}
+
+/*:67*/
+#line 926 "ctangle.w"
+
+else if(isalpha(c)||isxalpha(c)||ishigh(c))
+/*65:*/
+#line 972 "ctangle.w"
+{
+id_first= --loc;
+while(isalpha(*++loc)||isdigit(*loc)||isxalpha(*loc)||ishigh(*loc));
+id_loc= loc;return(identifier);
+}
+
+/*:65*/
+#line 928 "ctangle.w"
+
+else if(c=='@')/*68:*/
+#line 1050 "ctangle.w"
+{
+c= ccode[(eight_bits)*loc++];
+switch(c){
+case ignore:continue;
+case translit_code:err_print("! Use @l in limbo only");continue;
+
+case control_text:while((c= skip_ahead())=='@');
+
+if(*(loc-1)!='>')
+err_print("! Double @ should be used in control text");
+
+continue;
+case section_name:
+cur_section_name_char= *(loc-1);
+/*70:*/
+#line 1098 "ctangle.w"
+{
+char*k;
+/*72:*/
+#line 1118 "ctangle.w"
+
+k= section_text;
+while(1){
+if(loc> limit&&get_line()==0){
+err_print("! Input ended in section name");
+
+loc= buffer+1;break;
+}
+c= *loc;
+/*73:*/
+#line 1142 "ctangle.w"
+
+if(c=='@'){
+c= *(loc+1);
+if(c=='>'){
+loc+= 2;break;
+}
+if(ccode[(eight_bits)c]==new_section){
+err_print("! Section name didn't end");break;
+
+}
+if(ccode[(eight_bits)c]==section_name){
+err_print("! Nesting of section names not allowed");break;
+
+}
+*(++k)= '@';loc++;
+}
+
+/*:73*/
+#line 1127 "ctangle.w"
+;
+loc++;if(k<section_text_end)k++;
+if(xisspace(c)){
+c= ' ';if(*(k-1)==' ')k--;
+}
+*k= c;
+}
+if(k>=section_text_end){
+printf("\n! Section name too long: ");
+
+term_write(section_text+1,25);
+printf("...");mark_harmless;
+}
+if(*k==' '&&k> section_text)k--;
+
+/*:72*/
+#line 1100 "ctangle.w"
+;
+if(k-section_text> 3&&strncmp(k-2,"...",3)==0)
+cur_section_name= section_lookup(section_text+1,k-3,1);
+else cur_section_name= section_lookup(section_text+1,k,0);
+if(cur_section_name_char=='(')
+/*40:*/
+#line 516 "ctangle.w"
+
+{
+for(an_output_file= cur_out_file;
+an_output_file<end_output_files;an_output_file++)
+if(*an_output_file==cur_section_name)break;
+if(an_output_file==end_output_files){
+if(cur_out_file> output_files)
+*--cur_out_file= cur_section_name;
+else{
+overflow("output files");
+}
+}
+}
+
+/*:40*/
+#line 1106 "ctangle.w"
+;
+return(section_name);
+}
+
+/*:70*/
+#line 1064 "ctangle.w"
+;
+case string:/*74:*/
+#line 1164 "ctangle.w"
+{
+id_first= loc++;*(limit+1)= '@';*(limit+2)= '>';
+while(*loc!='@'||*(loc+1)!='>')loc++;
+if(loc>=limit)err_print("! Verbatim string didn't end");
+
+id_loc= loc;loc+= 2;
+return(string);
+}
+
+/*:74*/
+#line 1065 "ctangle.w"
+;
+case ord:/*69:*/
+#line 1077 "ctangle.w"
+
+id_first= loc;
+if(*loc=='\\'){
+if(*++loc=='\'')loc++;
+}
+while(*loc!='\''){
+if(*loc=='@'){
+if(*(loc+1)!='@')
+err_print("! Double @ should be used in ASCII constant");
+
+else loc++;
+}
+loc++;
+if(loc> limit){
+err_print("! String didn't end");loc= limit-1;break;
+
+}
+}
+loc++;
+return(ord);
+
+/*:69*/
+#line 1066 "ctangle.w"
+;
+default:return(c);
+}
+}
+
+/*:68*/
+#line 929 "ctangle.w"
+
+else if(xisspace(c)){
+if(!preprocessing||loc> limit)continue;
+
+else return(' ');
+}
+else if(c=='#'&&loc==buffer+1)preprocessing= 1;
+mistake:/*64:*/
+#line 950 "ctangle.w"
+
+switch(c){
+case'+':if(*loc=='+')compress(plus_plus);break;
+case'-':if(*loc=='-'){compress(minus_minus);}
+else if(*loc=='>')if(*(loc+1)=='*'){loc++;compress(minus_gt_ast);}
+else compress(minus_gt);break;
+case'.':if(*loc=='*'){compress(period_ast);}
+else if(*loc=='.'&&*(loc+1)=='.'){
+loc++;compress(dot_dot_dot);
+}
+break;
+case':':if(*loc==':')compress(colon_colon);break;
+case'=':if(*loc=='=')compress(eq_eq);break;
+case'>':if(*loc=='='){compress(gt_eq);}
+else if(*loc=='>')compress(gt_gt);break;
+case'<':if(*loc=='='){compress(lt_eq);}
+else if(*loc=='<')compress(lt_lt);break;
+case'&':if(*loc=='&')compress(and_and);break;
+case'|':if(*loc=='|')compress(or_or);break;
+case'!':if(*loc=='=')compress(not_eq);break;
+}
+
+/*:64*/
+#line 936 "ctangle.w"
+
+return(c);
+}
+}
+
+/*:63*//*76:*/
+#line 1199 "ctangle.w"
+
+void
+scan_repl(t)
+eight_bits t;
+{
+sixteen_bits a;
+if(t==section_name){/*77:*/
+#line 1225 "ctangle.w"
+
+store_two_bytes(0150000);
+if(changing&&include_depth==change_depth){
+id_first= change_file_name;
+store_two_bytes((sixteen_bits)change_line);
+}else{
+id_first= cur_file_name;
+store_two_bytes((sixteen_bits)cur_line);
+}
+id_loc= id_first+strlen(id_first);
+{int a= id_lookup(id_first,id_loc,0)-name_dir;app_repl((a/0400)+0200);
+app_repl(a%0400);}
+
+/*:77*/
+#line 1205 "ctangle.w"
+;}
+while(1)switch(a= get_next()){
+/*78:*/
+#line 1238 "ctangle.w"
+
+case identifier:a= id_lookup(id_first,id_loc,0)-name_dir;
+app_repl((a/0400)+0200);
+app_repl(a%0400);break;
+case section_name:if(t!=section_name)goto done;
+else{
+/*79:*/
+#line 1271 "ctangle.w"
+{
+char*try_loc= loc;
+while(*try_loc==' '&&try_loc<limit)try_loc++;
+if(*try_loc=='+'&&try_loc<limit)try_loc++;
+while(*try_loc==' '&&try_loc<limit)try_loc++;
+if(*try_loc=='=')err_print("! Missing `@ ' before a named section");
+
+
+
+}
+
+/*:79*/
+#line 1244 "ctangle.w"
+;
+a= cur_section_name-name_dir;
+app_repl((a/0400)+0250);
+app_repl(a%0400);
+/*77:*/
+#line 1225 "ctangle.w"
+
+store_two_bytes(0150000);
+if(changing&&include_depth==change_depth){
+id_first= change_file_name;
+store_two_bytes((sixteen_bits)change_line);
+}else{
+id_first= cur_file_name;
+store_two_bytes((sixteen_bits)cur_line);
+}
+id_loc= id_first+strlen(id_first);
+{int a= id_lookup(id_first,id_loc,0)-name_dir;app_repl((a/0400)+0200);
+app_repl(a%0400);}
+
+/*:77*/
+#line 1248 "ctangle.w"
+;break;
+}
+case output_defs_code:if(t!=section_name)err_print("! Misplaced @h");
+
+else{
+output_defs_seen= 1;
+a= output_defs_flag;
+app_repl((a/0400)+0200);
+app_repl(a%0400);
+/*77:*/
+#line 1225 "ctangle.w"
+
+store_two_bytes(0150000);
+if(changing&&include_depth==change_depth){
+id_first= change_file_name;
+store_two_bytes((sixteen_bits)change_line);
+}else{
+id_first= cur_file_name;
+store_two_bytes((sixteen_bits)cur_line);
+}
+id_loc= id_first+strlen(id_first);
+{int a= id_lookup(id_first,id_loc,0)-name_dir;app_repl((a/0400)+0200);
+app_repl(a%0400);}
+
+/*:77*/
+#line 1257 "ctangle.w"
+;
+}
+break;
+case constant:case string:
+/*80:*/
+#line 1282 "ctangle.w"
+
+app_repl(a);
+while(id_first<id_loc){
+if(*id_first=='@'){
+if(*(id_first+1)=='@')id_first++;
+else err_print("! Double @ should be used in string");
+
+}
+app_repl(*id_first++);
+}
+app_repl(a);break;
+
+/*:80*/
+#line 1261 "ctangle.w"
+;
+case ord:
+/*81:*/
+#line 1298 "ctangle.w"
+{
+int c= (eight_bits)*id_first;
+if(c=='\\'){
+c= *++id_first;
+if(c>='0'&&c<='7'){
+c-= '0';
+if(*(id_first+1)>='0'&&*(id_first+1)<='7'){
+c= 8*c+*(++id_first)-'0';
+if(*(id_first+1)>='0'&&*(id_first+1)<='7'&&c<32)
+c= 8*c+*(++id_first)-'0';
+}
+}
+else switch(c){
+case't':c= '\t';break;
+case'n':c= '\n';break;
+case'b':c= '\b';break;
+case'f':c= '\f';break;
+case'v':c= '\v';break;
+case'r':c= '\r';break;
+case'a':c= '\7';break;
+case'?':c= '?';break;
+case'x':
+if(xisdigit(*(id_first+1)))c= *(++id_first)-'0';
+else if(xisxdigit(*(id_first+1))){
+++id_first;
+c= toupper(*id_first)-'A'+10;
+}
+if(xisdigit(*(id_first+1)))c= 16*c+*(++id_first)-'0';
+else if(xisxdigit(*(id_first+1))){
+++id_first;
+c= 16*c+toupper(*id_first)-'A'+10;
+}
+break;
+case'\\':c= '\\';break;
+case'\'':c= '\'';break;
+case'\"':c= '\"';break;
+default:err_print("! Unrecognized escape sequence");
+
+}
+}
+
+app_repl(constant);
+if(c>=100)app_repl('0'+c/100);
+if(c>=10)app_repl('0'+(c/10)%10);
+app_repl('0'+c%10);
+app_repl(constant);
+}
+break;
+
+/*:81*/
+#line 1263 "ctangle.w"
+;
+case definition:case format_code:case begin_C:if(t!=section_name)goto done;
+else{
+err_print("! @d, @f and @c are ignored in C text");continue;
+
+}
+case new_section:goto done;
+
+/*:78*/
+#line 1210 "ctangle.w"
+
+case')':app_repl(a);
+if(t==macro)app_repl(' ');
+break;
+default:app_repl(a);
+}
+done:next_control= (eight_bits)a;
+if(text_ptr> text_info_end)overflow("text");
+cur_text= text_ptr;(++text_ptr)->tok_start= tok_ptr;
+}
+
+/*:76*//*83:*/
+#line 1360 "ctangle.w"
+
+void
+scan_section()
+{
+name_pointer p;
+text_pointer q;
+sixteen_bits a;
+section_count++;no_where= 1;
+if(*(loc-1)=='*'&&show_progress){
+printf("*%d",section_count);update_terminal;
+}
+next_control= 0;
+while(1){
+/*84:*/
+#line 1399 "ctangle.w"
+
+while(next_control<definition)
+
+if((next_control= skip_ahead())==section_name){
+loc-= 2;next_control= get_next();
+}
+
+/*:84*/
+#line 1374 "ctangle.w"
+;
+if(next_control==definition){
+/*85:*/
+#line 1406 "ctangle.w"
+{
+while((next_control= get_next())=='\n');
+if(next_control!=identifier){
+err_print("! Definition flushed, must start with identifier");
+
+continue;
+}
+app_repl(((a= id_lookup(id_first,id_loc,0)-name_dir)/0400)+0200);
+
+app_repl(a%0400);
+if(*loc!='('){
+app_repl(string);app_repl(' ');app_repl(string);
+}
+scan_repl(macro);
+cur_text->text_link= 0;
+}
+
+/*:85*/
+#line 1376 "ctangle.w"
+
+continue;
+}
+if(next_control==begin_C){
+p= name_dir;break;
+}
+if(next_control==section_name){
+p= cur_section_name;
+/*86:*/
+#line 1431 "ctangle.w"
+
+while((next_control= get_next())=='+');
+if(next_control!='='&&next_control!=eq_eq)
+continue;
+
+/*:86*/
+#line 1384 "ctangle.w"
+;
+break;
+}
+return;
+}
+no_where= print_where= 0;
+/*87:*/
+#line 1436 "ctangle.w"
+
+/*88:*/
+#line 1441 "ctangle.w"
+
+store_two_bytes((sixteen_bits)(0150000+section_count));
+
+
+/*:88*/
+#line 1437 "ctangle.w"
+;
+scan_repl(section_name);
+/*89:*/
+#line 1445 "ctangle.w"
+
+if(p==name_dir||p==0){
+(last_unnamed)->text_link= cur_text-text_info;last_unnamed= cur_text;
+}
+else if(p->equiv==(char*)text_info)p->equiv= (char*)cur_text;
+
+else{
+q= (text_pointer)p->equiv;
+while(q->text_link<section_flag)
+q= q->text_link+text_info;
+q->text_link= cur_text-text_info;
+}
+cur_text->text_link= section_flag;
+
+
+/*:89*/
+#line 1439 "ctangle.w"
+;
+
+/*:87*/
+#line 1390 "ctangle.w"
+;
+}
+
+/*:83*//*91:*/
+#line 1463 "ctangle.w"
+
+void
+phase_one(){
+phase= 1;
+section_count= 0;
+reset_input();
+skip_limbo();
+while(!input_has_ended)scan_section();
+check_complete();
+phase= 2;
+}
+
+/*:91*//*93:*/
+#line 1481 "ctangle.w"
+
+void
+skip_limbo()
+{
+char c;
+while(1){
+if(loc> limit&&get_line()==0)return;
+*(limit+1)= '@';
+while(*loc!='@')loc++;
+if(loc++<=limit){
+c= *loc++;
+if(ccode[(eight_bits)c]==new_section)break;
+switch(ccode[(eight_bits)c]){
+case translit_code:/*94:*/
+#line 1510 "ctangle.w"
+
+while(xisspace(*loc)&&loc<limit)loc++;
+loc+= 3;
+if(loc> limit||!xisxdigit(*(loc-3))||!xisxdigit(*(loc-2))
+||(*(loc-3)>='0'&&*(loc-3)<='7')||!xisspace(*(loc-1)))
+err_print("! Improper hex number following @l");
+
+else{
+unsigned i;
+char*beg;
+sscanf(loc-3,"%x",&i);
+while(xisspace(*loc)&&loc<limit)loc++;
+beg= loc;
+while(loc<limit&&(xisalpha(*loc)||xisdigit(*loc)||*loc=='_'))loc++;
+if(loc-beg>=translit_length)
+err_print("! Replacement string in @l too long");
+
+else{
+strncpy(translit[i-0200],beg,loc-beg);
+translit[i-0200][loc-beg]= '\0';
+}
+}
+
+/*:94*/
+#line 1494 "ctangle.w"
+;break;
+case format_code:case'@':break;
+case control_text:if(c=='q'||c=='Q'){
+while((c= skip_ahead())=='@');
+if(*(loc-1)!='>')
+err_print("! Double @ should be used in control text");
+
+break;
+}
+default:err_print("! Double @ should be used in limbo");
+
+}
+}
+}
+}
+
+/*:93*//*95:*/
+#line 1536 "ctangle.w"
+
+void
+print_stats(){
+printf("\nMemory usage statistics:\n");
+printf("%ld names (out of %ld)\n",
+(long)(name_ptr-name_dir),(long)max_names);
+printf("%ld replacement texts (out of %ld)\n",
+(long)(text_ptr-text_info),(long)max_texts);
+printf("%ld bytes (out of %ld)\n",
+(long)(byte_ptr-byte_mem),(long)max_bytes);
+printf("%ld tokens (out of %ld)\n",
+(long)(tok_ptr-tok_mem),(long)max_toks);
+}
+
+/*:95*/
diff --git a/web/c_cpp/cweb/ctangle.w b/web/c_cpp/cweb/ctangle.w
new file mode 100644
index 0000000000..130800210e
--- /dev/null
+++ b/web/c_cpp/cweb/ctangle.w
@@ -0,0 +1,1557 @@
+% This file is part of CWEB.
+% This program by Silvio Levy and Donald E. Knuth
+% is based on a program by Knuth.
+% It is distributed WITHOUT ANY WARRANTY, express or implied.
+% Version 3.64 --- February 2002
+% (same as Version 3.5 except for minor corrections)
+% (also quotes backslashes in file names of #line directives)
+
+% Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth
+
+% Permission is granted to make and distribute verbatim copies of this
+% document provided that the copyright notice and this permission notice
+% are preserved on all copies.
+
+% Permission is granted to copy and distribute modified versions of this
+% document under the conditions for verbatim copying, provided that the
+% entire resulting derived work is given a different name and distributed
+% under the terms of a permission notice identical to this one.
+
+% Here is TeX material that gets inserted after \input cwebmac
+\def\hang{\hangindent 3em\indent\ignorespaces}
+\def\pb{$\.|\ldots\.|$} % C brackets (|...|)
+\def\v{\char'174} % vertical (|) in typewriter font
+\mathchardef\RA="3221 % right arrow
+\mathchardef\BA="3224 % double arrow
+
+\def\title{CTANGLE (Version 3.64)}
+\def\topofcontents{\null\vfill
+ \centerline{\titlefont The {\ttitlefont CTANGLE} processor}
+ \vskip 15pt
+ \centerline{(Version 3.64)}
+ \vfill}
+\def\botofcontents{\vfill
+\noindent
+Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth
+\bigskip\noindent
+Permission is granted to make and distribute verbatim copies of this
+document provided that the copyright notice and this permission notice
+are preserved on all copies.
+
+\smallskip\noindent
+Permission is granted to copy and distribute modified versions of this
+document under the conditions for verbatim copying, provided that the
+entire resulting derived work is given a different name and distributed
+under the terms of a permission notice identical to this one.
+}
+\pageno=\contentspagenumber \advance\pageno by 1
+\let\maybe=\iftrue
+@s not_eq normal @q unreserve a C++ keyword @>
+
+@** Introduction.
+This is the \.{CTANGLE} program by Silvio Levy and Donald E. Knuth,
+based on \.{TANGLE} by Knuth.
+We are thankful to
+Nelson Beebe, Hans-Hermann Bode (to whom the \CPLUSPLUS/ adaptation is due),
+Klaus Guntermann, Norman Ramsey, Tomas Rokicki, Joachim Schnitter,
+Joachim Schrod, Lee Wittenberg, and others who have contributed improvements.
+
+The ``banner line'' defined here should be changed whenever \.{CTANGLE}
+is modified.
+
+@d banner "This is CTANGLE (Version 3.64)\n"
+
+@c
+@<Include files@>@/
+@h
+@<Common code for \.{CWEAVE} and \.{CTANGLE}@>@/
+@<Typedef declarations@>@/
+@<Global variables@>@/
+@<Predeclaration of procedures@>@/
+
+@ We predeclare several standard system functions here instead of including
+their system header files, because the names of the header files are not as
+standard as the names of the functions. (For example, some \CEE/ environments
+have \.{<string.h>} where others have \.{<strings.h>}.)
+
+@<Predecl...@>=
+extern int strlen(); /* length of string */
+extern int strcmp(); /* compare strings lexicographically */
+extern char* strcpy(); /* copy one string to another */
+extern int strncmp(); /* compare up to $n$ string characters */
+extern char* strncpy(); /* copy up to $n$ string characters */
+
+@ \.{CTANGLE} has a fairly straightforward outline. It operates in
+two phases: First it reads the source file, saving the \CEE/ code in
+compressed form; then it shuffles and outputs the code.
+
+Please read the documentation for \.{common}, the set of routines common
+to \.{CTANGLE} and \.{CWEAVE}, before proceeding further.
+
+@c
+int main (ac, av)
+int ac;
+char **av;
+{
+ argc=ac; argv=av;
+ program=ctangle;
+ @<Set initial values@>;
+ common_init();
+ if (show_banner) printf(banner); /* print a ``banner line'' */
+ phase_one(); /* read all the user's text and compress it into |tok_mem| */
+ phase_two(); /* output the contents of the compressed tables */
+ return wrap_up(); /* and exit gracefully */
+}
+
+@ The following parameters were sufficient in the original \.{TANGLE} to
+handle \TEX/,
+so they should be sufficient for most applications of \.{CTANGLE}.
+If you change |max_bytes|, |max_names|, or |hash_size| you should also
+change them in the file |"common.w"|.
+
+@d max_bytes 90000 /* the number of bytes in identifiers,
+ index entries, and section names; used in |"common.w"| */
+@d max_toks 270000 /* number of bytes in compressed \CEE/ code */
+@d max_names 4000 /* number of identifiers, strings, section names;
+ must be less than 10240; used in |"common.w"| */
+@d max_texts 2500 /* number of replacement texts, must be less than 10240 */
+@d hash_size 353 /* should be prime; used in |"common.w"| */
+@d longest_name 10000 /* section names and strings shouldn't be longer than this */
+@d stack_size 50 /* number of simultaneous levels of macro expansion */
+@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */
+
+@ The next few sections contain stuff from the file |"common.w"| that must
+be included in both |"ctangle.w"| and |"cweave.w"|. It appears in
+file |"common.h"|, which needs to be updated when |"common.w"| changes.
+
+@i common.h
+
+@* Data structures exclusive to {\tt CTANGLE}.
+We've already seen that the |byte_mem| array holds the names of identifiers,
+strings, and sections;
+the |tok_mem| array holds the replacement texts
+for sections. Allocation is sequential, since things are deleted only
+during Phase II, and only in a last-in-first-out manner.
+
+A \&{text} variable is a structure containing a pointer into
+|tok_mem|, which tells where the corresponding text starts, and an
+integer |text_link|, which, as we shall see later, is used to connect
+pieces of text that have the same name. All the \&{text}s are stored in
+the array |text_info|, and we use a |text_pointer| variable to refer
+to them.
+
+The first position of |tok_mem| that is unoccupied by
+replacement text is called |tok_ptr|, and the first unused location of
+|text_info| is called |text_ptr|. Thus we usually have the identity
+|text_ptr->tok_start==tok_ptr|.
+
+If your machine does not support |unsigned char| you should change
+the definition of \&{eight\_bits} to |unsigned short|.
+@^system dependencies@>
+
+@<Typed...@>=
+typedef struct {
+ eight_bits *tok_start; /* pointer into |tok_mem| */
+ sixteen_bits text_link; /* relates replacement texts */
+} text;
+typedef text *text_pointer;
+
+@ @<Glob...@>=
+text text_info[max_texts];
+text_pointer text_info_end=text_info+max_texts-1;
+text_pointer text_ptr; /* first unused position in |text_info| */
+eight_bits tok_mem[max_toks];
+eight_bits *tok_mem_end=tok_mem+max_toks-1;
+eight_bits *tok_ptr; /* first unused position in |tok_mem| */
+
+@ @<Set init...@>=
+text_info->tok_start=tok_ptr=tok_mem;
+text_ptr=text_info+1; text_ptr->tok_start=tok_mem;
+ /* this makes replacement text 0 of length zero */
+
+@ If |p| is a pointer to a section name, |p->equiv| is a pointer to its
+replacement text, an element of the array |text_info|.
+
+@d equiv equiv_or_xref /* info corresponding to names */
+
+@ @<Set init...@>=
+name_dir->equiv=(char *)text_info; /* the undefined section has no replacement text */
+
+@ Here's the procedure that decides whether a name of length |l|
+starting at position |first| equals the identifier pointed to by |p|:
+
+@c
+int names_match(p,first,l)
+name_pointer p; /* points to the proposed match */
+char *first; /* position of first character of string */
+int l; /* length of identifier */
+{
+ if (length(p)!=l) return 0;
+ return !strncmp(first,p->byte_start,l);
+}
+
+@ The common lookup routine refers to separate routines |init_node| and
+|init_p| when the data structure grows. Actually |init_p| is called only by
+\.{CWEAVE}, but we need to declare a dummy version so that
+the loader won't complain of its absence.
+
+@c
+void
+init_node(node)
+name_pointer node;
+{
+ node->equiv=(char *)text_info;
+}
+void
+init_p() {}
+
+@* Tokens.
+Replacement texts, which represent \CEE/ code in a compressed format,
+appear in |tok_mem| as mentioned above. The codes in
+these texts are called `tokens'; some tokens occupy two consecutive
+eight-bit byte positions, and the others take just one byte.
+
+If $p$ points to a replacement text, |p->tok_start| is the |tok_mem| position
+of the first eight-bit code of that text. If |p->text_link==0|,
+this is the replacement text for a macro, otherwise it is the replacement
+text for a section. In the latter case |p->text_link| is either equal to
+|section_flag|, which means that there is no further text for this section, or
+|p->text_link| points to a continuation of this replacement text; such
+links are created when several sections have \CEE/ texts with the same
+name, and they also tie together all the \CEE/ texts of unnamed sections.
+The replacement text pointer for the first unnamed section appears in
+|text_info->text_link|, and the most recent such pointer is |last_unnamed|.
+
+@d section_flag max_texts /* final |text_link| in section replacement texts */
+
+@<Glob...@>=
+text_pointer last_unnamed; /* most recent replacement text of unnamed section */
+
+@ @<Set init...@>= last_unnamed=text_info; text_info->text_link=0;
+
+@ If the first byte of a token is less than |0200|, the token occupies a
+single byte. Otherwise we make a sixteen-bit token by combining two consecutive
+bytes |a| and |b|. If |0200<=a<0250|, then |(a-0200)@t${}\times2^8$@>+b|
+points to an identifier; if |0250<=a<0320|, then
+|(a-0250)@t${}\times2^8$@>+b| points to a section name
+(or, if it has the special value |output_defs_flag|,
+to the area where the preprocessor definitions are stored); and if
+|0320<=a<0400|, then |(a-0320)@t${}\times2^8$@>+b| is the number of the section
+in which the current replacement text appears.
+
+Codes less than |0200| are 7-bit |char| codes that represent themselves.
+Some of the 7-bit codes will not be present, however, so we can
+use them for special purposes. The following symbolic names are used:
+
+\yskip \hang |join| denotes the concatenation of adjacent items with no
+space or line breaks allowed between them (the \.{@@\&} operation of \.{CWEB}).
+
+\hang |string| denotes the beginning or end of a string, verbatim
+construction or numerical constant.
+@^ASCII code dependencies@>
+
+@d string 02 /* takes the place of extended ASCII \.{\char2} */
+@d join 0177 /* takes the place of ASCII delete */
+@d output_defs_flag (2*024000-1)
+
+@ The following procedure is used to enter a two-byte value into
+|tok_mem| when a replacement text is being generated.
+
+@c
+void
+store_two_bytes(x)
+sixteen_bits x;
+{
+ if (tok_ptr+2>tok_mem_end) overflow("token");
+ *tok_ptr++=x>>8; /* store high byte */
+ *tok_ptr++=x&0377; /* store low byte */
+}
+
+@** Stacks for output. The output process uses a stack to keep track
+of what is going on at different ``levels'' as the sections are being
+written out. Entries on this stack have five parts:
+
+\yskip\hang |end_field| is the |tok_mem| location where the replacement
+text of a particular level will end;
+
+\hang |byte_field| is the |tok_mem| location from which the next token
+on a particular level will be read;
+
+\hang |name_field| points to the name corresponding to a particular level;
+
+\hang |repl_field| points to the replacement text currently being read
+at a particular level;
+
+\hang |section_field| is the section number, or zero if this is a macro.
+
+\yskip\noindent The current values of these five quantities are referred to
+quite frequently, so they are stored in a separate place instead of in
+the |stack| array. We call the current values |cur_end|, |cur_byte|,
+|cur_name|, |cur_repl|, and |cur_section|.
+
+The global variable |stack_ptr| tells how many levels of output are
+currently in progress. The end of all output occurs when the stack is
+empty, i.e., when |stack_ptr==stack|.
+
+@<Typed...@>=
+typedef struct {
+ eight_bits *end_field; /* ending location of replacement text */
+ eight_bits *byte_field; /* present location within replacement text */
+ name_pointer name_field; /* |byte_start| index for text being output */
+ text_pointer repl_field; /* |tok_start| index for text being output */
+ sixteen_bits section_field; /* section number or zero if not a section */
+} output_state;
+typedef output_state *stack_pointer;
+
+@ @d cur_end cur_state.end_field /* current ending location in |tok_mem| */
+@d cur_byte cur_state.byte_field /* location of next output byte in |tok_mem|*/
+@d cur_name cur_state.name_field /* pointer to current name being expanded */
+@d cur_repl cur_state.repl_field /* pointer to current replacement text */
+@d cur_section cur_state.section_field /* current section number being expanded */
+
+@<Global...@>=
+output_state cur_state; /* |cur_end|, |cur_byte|, |cur_name|, |cur_repl|,
+ and |cur_section| */
+output_state stack[stack_size+1]; /* info for non-current levels */
+stack_pointer stack_ptr; /* first unused location in the output state stack */
+stack_pointer stack_end=stack+stack_size; /* end of |stack| */
+
+@ To get the output process started, we will perform the following
+initialization steps. We may assume that |text_info->text_link| is nonzero,
+since it points to the \CEE/ text in the first unnamed section that generates
+code; if there are no such sections, there is nothing to output, and an
+error message will have been generated before we do any of the initialization.
+
+@<Initialize the output stacks@>=
+stack_ptr=stack+1; cur_name=name_dir; cur_repl=text_info->text_link+text_info;
+cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start; cur_section=0;
+
+@ When the replacement text for name |p| is to be inserted into the output,
+the following subroutine is called to save the old level of output and get
+the new one going.
+
+We assume that the \CEE/ compiler can copy structures.
+@^system dependencies@>
+
+@c
+void
+push_level(p) /* suspends the current level */
+name_pointer p;
+{
+ if (stack_ptr==stack_end) overflow("stack");
+ *stack_ptr=cur_state;
+ stack_ptr++;
+ if (p!=NULL) { /* |p==NULL| means we are in |output_defs| */
+ cur_name=p; cur_repl=(text_pointer)p->equiv;
+ cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start;
+ cur_section=0;
+ }
+}
+
+@ When we come to the end of a replacement text, the |pop_level| subroutine
+does the right thing: It either moves to the continuation of this replacement
+text or returns the state to the most recently stacked level.
+
+@c
+void
+pop_level(flag) /* do this when |cur_byte| reaches |cur_end| */
+int flag; /* |flag==0| means we are in |output_defs| */
+{
+ if (flag && cur_repl->text_link<section_flag) { /* link to a continuation */
+ cur_repl=cur_repl->text_link+text_info; /* stay on the same level */
+ cur_byte=cur_repl->tok_start; cur_end=(cur_repl+1)->tok_start;
+ return;
+ }
+ stack_ptr--; /* go down to the previous level */
+ if (stack_ptr>stack) cur_state=*stack_ptr;
+}
+
+@ The heart of the output procedure is the function |get_output|,
+which produces the next token of output and sends it on to the lower-level
+function |out_char|. The main purpose of |get_output| is to handle the
+necessary stacking and unstacking. It sends the value |section_number|
+if the next output begins or ends the replacement text of some section,
+in which case |cur_val| is that section's number (if beginning) or the
+negative of that value (if ending). (A section number of 0 indicates
+not the beginning or ending of a section, but a \&{\#line} command.)
+And it sends the value |identifier|
+if the next output is an identifier, in which case
+|cur_val| points to that identifier name.
+
+@d section_number 0201 /* code returned by |get_output| for section numbers */
+@d identifier 0202 /* code returned by |get_output| for identifiers */
+
+@<Global...@>=
+int cur_val; /* additional information corresponding to output token */
+
+@ If |get_output| finds that no more output remains, it returns with
+|stack_ptr==stack|.
+@^high-bit character handling@>
+
+@c
+void
+get_output() /* sends next token to |out_char| */
+{
+ sixteen_bits a; /* value of current byte */
+ restart: if (stack_ptr==stack) return;
+ if (cur_byte==cur_end) {
+ cur_val=-((int)cur_section); /* cast needed because of sign extension */
+ pop_level(1);
+ if (cur_val==0) goto restart;
+ out_char(section_number); return;
+ }
+ a=*cur_byte++;
+ if (out_state==verbatim && a!=string && a!=constant && a!='\n')
+ C_putc(a); /* a high-bit character can occur in a string */
+ else if (a<0200) out_char(a); /* one-byte token */
+ else {
+ a=(a-0200)*0400+*cur_byte++;
+ switch (a/024000) { /* |024000==(0250-0200)*0400| */
+ case 0: cur_val=a; out_char(identifier); break;
+ case 1: if (a==output_defs_flag) output_defs();
+ else @<Expand section |a-024000|, |goto restart|@>;
+ break;
+ default: cur_val=a-050000; if (cur_val>0) cur_section=cur_val;
+ out_char(section_number);
+ }
+ }
+}
+
+@ The user may have forgotten to give any \CEE/ text for a section name,
+or the \CEE/ text may have been associated with a different name by mistake.
+
+@<Expand section |a-...@>=
+{
+ a-=024000;
+ if ((a+name_dir)->equiv!=(char *)text_info) push_level(a+name_dir);
+ else if (a!=0) {
+ printf("\n! Not present: <");
+ print_section_name(a+name_dir); err_print(">");
+@.Not present: <section name>@>
+ }
+ goto restart;
+}
+
+@* Producing the output.
+The |get_output| routine above handles most of the complexity of output
+generation, but there are two further considerations that have a nontrivial
+effect on \.{CTANGLE}'s algorithms.
+
+@ First,
+we want to make sure that the output has spaces and line breaks in
+the right places (e.g., not in the middle of a string or a constant or an
+identifier, not at a `\.{@@\&}' position
+where quantities are being joined together, and certainly after an \.=
+because the \CEE/ compiler thinks \.{=-} is ambiguous).
+
+The output process can be in one of following states:
+
+\yskip\hang |num_or_id| means that the last item in the buffer is a number or
+identifier, hence a blank space or line break must be inserted if the next
+item is also a number or identifier.
+
+\yskip\hang |unbreakable| means that the last item in the buffer was followed
+by the \.{@@\&} operation that inhibits spaces between it and the next item.
+
+\yskip\hang |verbatim| means we're copying only character tokens, and
+that they are to be output exactly as stored. This is the case during
+strings, verbatim constructions and numerical constants.
+
+\yskip\hang |post_slash| means we've just output a slash.
+
+\yskip\hang |normal| means none of the above.
+
+\yskip\noindent Furthermore, if the variable |protect| is positive, newlines
+are preceded by a `\.\\'.
+
+@d normal 0 /* non-unusual state */
+@d num_or_id 1 /* state associated with numbers and identifiers */
+@d post_slash 2 /* state following a \./ */
+@d unbreakable 3 /* state associated with \.{@@\&} */
+@d verbatim 4 /* state in the middle of a string */
+
+@<Global...@>=
+eight_bits out_state; /* current status of partial output */
+boolean protect; /* should newline characters be quoted? */
+
+@ Here is a routine that is invoked when we want to output the current line.
+During the output process, |cur_line| equals the number of the next line
+to be output.
+
+@c
+void
+flush_buffer() /* writes one line to output file */
+{
+ C_putc('\n');
+ if (cur_line % 100 == 0 && show_progress) {
+ printf(".");
+ if (cur_line % 500 == 0) printf("%d",cur_line);
+ update_terminal; /* progress report */
+ }
+ cur_line++;
+}
+
+@ Second, we have modified the original \.{TANGLE} so that it will write output
+on multiple files.
+If a section name is introduced in at least one place by \.{@@(}
+instead of \.{@@<}, we treat it as the name of a file.
+All these special sections are saved on a stack, |output_files|.
+We write them out after we've done the unnamed section.
+
+@d max_files 256
+@<Glob...@>=
+name_pointer output_files[max_files];
+name_pointer *cur_out_file, *end_output_files, *an_output_file;
+char cur_section_name_char; /* is it |'<'| or |'('| */
+char output_file_name[longest_name]; /* name of the file */
+
+@ We make |end_output_files| point just beyond the end of
+|output_files|. The stack pointer
+|cur_out_file| starts out there. Every time we see a new file, we
+decrement |cur_out_file| and then write it in.
+@<Set initial...@>=
+cur_out_file=end_output_files=output_files+max_files;
+
+@ @<If it's not there, add |cur_section_name| to the output file stack, or
+complain we're out of room@>=
+{
+ for (an_output_file=cur_out_file;
+ an_output_file<end_output_files; an_output_file++)
+ if (*an_output_file==cur_section_name) break;
+ if (an_output_file==end_output_files) {
+ if (cur_out_file>output_files)
+ *--cur_out_file=cur_section_name;
+ else {
+ overflow("output files");
+ }
+ }
+}
+
+@* The big output switch. Here then is the routine that does the
+output.
+
+@<Predecl...@>=
+void phase_two();
+
+@ @c
+void
+phase_two () {
+ web_file_open=0;
+ cur_line=1;
+ @<Initialize the output stacks@>;
+ @<Output macro definitions if appropriate@>;
+ if (text_info->text_link==0 && cur_out_file==end_output_files) {
+ printf("\n! No program text was specified."); mark_harmless;
+@.No program text...@>
+ }
+ else {
+ if(cur_out_file==end_output_files) {
+ if(show_progress)
+ printf("\nWriting the output file (%s):",C_file_name);
+ }
+ else {
+ if (show_progress) {
+ printf("\nWriting the output files:");
+@.Writing the output...@>
+ printf(" (%s)",C_file_name);
+ update_terminal;
+ }
+ if (text_info->text_link==0) goto writeloop;
+ }
+ while (stack_ptr>stack) get_output();
+ flush_buffer();
+writeloop: @<Write all the named output files@>;
+ if(show_happiness) printf("\nDone.");
+ }
+}
+
+@ To write the named output files, we proceed as for the unnamed
+section.
+The only subtlety is that we have to open each one.
+
+@<Write all the named output files@>=
+for (an_output_file=end_output_files; an_output_file>cur_out_file;) {
+ an_output_file--;
+ sprint_section_name(output_file_name,*an_output_file);
+ fclose(C_file);
+ C_file=fopen(output_file_name,"w");
+ if (C_file ==0) fatal("! Cannot open output file:",output_file_name);
+@.Cannot open output file@>
+ printf("\n(%s)",output_file_name); update_terminal;
+ cur_line=1;
+ stack_ptr=stack+1;
+ cur_name= (*an_output_file);
+ cur_repl= (text_pointer)cur_name->equiv;
+ cur_byte=cur_repl->tok_start;
+ cur_end=(cur_repl+1)->tok_start;
+ while (stack_ptr > stack) get_output();
+ flush_buffer();
+}
+
+@ If a \.{@@h} was not encountered in the input,
+we go through the list of replacement texts and copy the ones
+that refer to macros, preceded by the \.{\#define} preprocessor command.
+
+@<Output macro definitions if appropriate@>=
+ if (!output_defs_seen)
+ output_defs();
+
+@ @<Glob...@>=
+boolean output_defs_seen=0;
+
+@ @<Predecl...@>=
+void output_defs();
+
+@ @c
+void
+output_defs()
+{
+ sixteen_bits a;
+ push_level(NULL);
+ for (cur_text=text_info+1; cur_text<text_ptr; cur_text++)
+ if (cur_text->text_link==0) { /* |cur_text| is the text for a macro */
+ cur_byte=cur_text->tok_start;
+ cur_end=(cur_text+1)->tok_start;
+ C_printf("%s","#define ");
+ out_state=normal;
+ protect=1; /* newlines should be preceded by |'\\'| */
+ while (cur_byte<cur_end) {
+ a=*cur_byte++;
+ if (cur_byte==cur_end && a=='\n') break; /* disregard a final newline */
+ if (out_state==verbatim && a!=string && a!=constant && a!='\n')
+ C_putc(a); /* a high-bit character can occur in a string */
+@^high-bit character handling@>
+ else if (a<0200) out_char(a); /* one-byte token */
+ else {
+ a=(a-0200)*0400+*cur_byte++;
+ if (a<024000) { /* |024000==(0250-0200)*0400| */
+ cur_val=a; out_char(identifier);
+ }
+ else if (a<050000) { confusion("macro defs have strange char");}
+ else {
+ cur_val=a-050000; cur_section=cur_val; out_char(section_number);
+ }
+ /* no other cases */
+ }
+ }
+ protect=0;
+ flush_buffer();
+ }
+ pop_level(0);
+}
+
+@ A many-way switch is used to send the output. Note that this function
+is not called if |out_state==verbatim|, except perhaps with arguments
+|'\n'| (protect the newline), |string| (end the string), or |constant|
+(end the constant).
+
+@<Predecl...@>=
+static void out_char();
+
+@ @c
+static void
+out_char(cur_char)
+eight_bits cur_char;
+{
+ char *j, *k; /* pointer into |byte_mem| */
+restart:
+ switch (cur_char) {
+ case '\n': if (protect && out_state!=verbatim) C_putc(' ');
+ if (protect || out_state==verbatim) C_putc('\\');
+ flush_buffer(); if (out_state!=verbatim) out_state=normal; break;
+ @/@t\4@>@<Case of an identifier@>;
+ @/@t\4@>@<Case of a section number@>;
+ @/@t\4@>@<Cases like \.{!=}@>;
+ case '=': case '>': C_putc(cur_char); C_putc(' ');
+ out_state=normal; break;
+ case join: out_state=unbreakable; break;
+ case constant: if (out_state==verbatim) {
+ out_state=num_or_id; break;
+ }
+ if(out_state==num_or_id) C_putc(' '); out_state=verbatim; break;
+ case string: if (out_state==verbatim) out_state=normal;
+ else out_state=verbatim; break;
+ case '/': C_putc('/'); out_state=post_slash; break;
+ case '*': if (out_state==post_slash) C_putc(' ');
+ /* fall through */
+ default: C_putc(cur_char); out_state=normal; break;
+ }
+}
+
+@ @<Cases like \.{!=}@>=
+case plus_plus: C_putc('+'); C_putc('+'); out_state=normal; break;
+case minus_minus: C_putc('-'); C_putc('-'); out_state=normal; break;
+case minus_gt: C_putc('-'); C_putc('>'); out_state=normal; break;
+case gt_gt: C_putc('>'); C_putc('>'); out_state=normal; break;
+case eq_eq: C_putc('='); C_putc('='); out_state=normal; break;
+case lt_lt: C_putc('<'); C_putc('<'); out_state=normal; break;
+case gt_eq: C_putc('>'); C_putc('='); out_state=normal; break;
+case lt_eq: C_putc('<'); C_putc('='); out_state=normal; break;
+case not_eq: C_putc('!'); C_putc('='); out_state=normal; break;
+case and_and: C_putc('&'); C_putc('&'); out_state=normal; break;
+case or_or: C_putc('|'); C_putc('|'); out_state=normal; break;
+case dot_dot_dot: C_putc('.'); C_putc('.'); C_putc('.'); out_state=normal;
+ break;
+case colon_colon: C_putc(':'); C_putc(':'); out_state=normal; break;
+case period_ast: C_putc('.'); C_putc('*'); out_state=normal; break;
+case minus_gt_ast: C_putc('-'); C_putc('>'); C_putc('*'); out_state=normal;
+ break;
+
+@ When an identifier is output to the \CEE/ file, characters in the
+range 128--255 must be changed into something else, so the \CEE/
+compiler won't complain. By default, \.{CTANGLE} converts the
+character with code $16 x+y$ to the three characters `\.X$xy$', but
+a different transliteration table can be specified. Thus a German
+might want {\it gr\"un\/} to appear as a still readable \.{gruen}.
+This makes debugging a lot less confusing.
+
+@d translit_length 10
+
+@<Glo...@>=
+char translit[128][translit_length];
+
+@ @<Set init...@>=
+{
+ int i;
+ for (i=0;i<128;i++) sprintf(translit[i],"X%02X",(unsigned)(128+i));
+}
+
+@ @<Case of an identifier@>=
+case identifier:
+ if (out_state==num_or_id) C_putc(' ');
+ j=(cur_val+name_dir)->byte_start;
+ k=(cur_val+name_dir+1)->byte_start;
+ while (j<k) {
+ if ((unsigned char)(*j)<0200) C_putc(*j);
+@^high-bit character handling@>
+ else C_printf("%s",translit[(unsigned char)(*j)-0200]);
+ j++;
+ }
+ out_state=num_or_id; break;
+
+@ @<Case of a sec...@>=
+case section_number:
+ if (cur_val>0) C_printf("/*%d:*/",cur_val);
+ else if(cur_val<0) C_printf("/*:%d*/",-cur_val);
+ else if (protect) {
+ cur_byte +=4; /* skip line number and file name */
+ cur_char = '\n';
+ goto restart;
+ } else {
+ sixteen_bits a;
+ a=0400* *cur_byte++;
+ a+=*cur_byte++; /* gets the line number */
+ C_printf("\n#line %d \"",a);
+@:line}{\.{\#line}@>
+ cur_val=*cur_byte++;
+ cur_val=0400*(cur_val-0200)+ *cur_byte++; /* points to the file name */
+ for (j=(cur_val+name_dir)->byte_start, k=(cur_val+name_dir+1)->byte_start;
+ j<k; j++) {
+ if (*j=='\\' || *j=='"') C_putc('\\');
+ C_putc(*j);
+ }
+ C_printf("%s","\"\n");
+ }
+ break;
+
+@** Introduction to the input phase.
+We have now seen that \.{CTANGLE} will be able to output the full
+\CEE/ program, if we can only get that program into the byte memory in
+the proper format. The input process is something like the output process
+in reverse, since we compress the text as we read it in and we expand it
+as we write it out.
+
+There are three main input routines. The most interesting is the one that gets
+the next token of a \CEE/ text; the other two are used to scan rapidly past
+\TEX/ text in the \.{CWEB} source code. One of the latter routines will jump to
+the next token that starts with `\.{@@}', and the other skips to the end
+of a \CEE/ comment.
+
+@ Control codes in \.{CWEB} begin with `\.{@@}', and the next character
+identifies the code. Some of these are of interest only to \.{CWEAVE},
+so \.{CTANGLE} ignores them; the others are converted by \.{CTANGLE} into
+internal code numbers by the |ccode| table below. The ordering
+of these internal code numbers has been chosen to simplify the program logic;
+larger numbers are given to the control codes that denote more significant
+milestones.
+
+@d ignore 0 /* control code of no interest to \.{CTANGLE} */
+@d ord 0302 /* control code for `\.{@@'}' */
+@d control_text 0303 /* control code for `\.{@@t}', `\.{@@\^}', etc. */
+@d translit_code 0304 /* control code for `\.{@@l}' */
+@d output_defs_code 0305 /* control code for `\.{@@h}' */
+@d format_code 0306 /* control code for `\.{@@f}' */
+@d definition 0307 /* control code for `\.{@@d}' */
+@d begin_C 0310 /* control code for `\.{@@c}' */
+@d section_name 0311 /* control code for `\.{@@<}' */
+@d new_section 0312 /* control code for `\.{@@\ }' and `\.{@@*}' */
+
+@<Global...@>=
+eight_bits ccode[256]; /* meaning of a char following \.{@@} */
+
+@ @<Set ini...@>= {
+ int c; /* must be |int| so the |for| loop will end */
+ for (c=0; c<256; c++) ccode[c]=ignore;
+ ccode[' ']=ccode['\t']=ccode['\n']=ccode['\v']=ccode['\r']=ccode['\f']
+ =ccode['*']=new_section;
+ ccode['@@']='@@'; ccode['=']=string;
+ ccode['d']=ccode['D']=definition;
+ ccode['f']=ccode['F']=ccode['s']=ccode['S']=format_code;
+ ccode['c']=ccode['C']=ccode['p']=ccode['P']=begin_C;
+ ccode['^']=ccode[':']=ccode['.']=ccode['t']=ccode['T']=
+ ccode['q']=ccode['Q']=control_text;
+ ccode['h']=ccode['H']=output_defs_code;
+ ccode['l']=ccode['L']=translit_code;
+ ccode['&']=join;
+ ccode['<']=ccode['(']=section_name;
+ ccode['\'']=ord;
+}
+
+@ The |skip_ahead| procedure reads through the input at fairly high speed
+until finding the next non-ignorable control code, which it returns.
+
+@c
+eight_bits
+skip_ahead() /* skip to next control code */
+{
+ eight_bits c; /* control code found */
+ while (1) {
+ if (loc>limit && (get_line()==0)) return(new_section);
+ *(limit+1)='@@';
+ while (*loc!='@@') loc++;
+ if (loc<=limit) {
+ loc++; c=ccode[(eight_bits)*loc]; loc++;
+ if (c!=ignore || *(loc-1)=='>') return(c);
+ }
+ }
+}
+
+@ The |skip_comment| procedure reads through the input at somewhat high
+speed in order to pass over comments, which \.{CTANGLE} does not transmit
+to the output. If the comment is introduced by \.{/*}, |skip_comment|
+proceeds until finding the end-comment token \.{*/} or a newline; in the
+latter case |skip_comment| will be called again by |get_next|, since the
+comment is not finished. This is done so that each newline in the
+\CEE/ part of a section is copied to the output; otherwise the \&{\#line}
+commands inserted into the \CEE/ file by the output routines become useless.
+On the other hand, if the comment is introduced by \.{//} (i.e., if it
+is a \CPLUSPLUS/ ``short comment''), it always is simply delimited by the next
+newline. The boolean argument |is_long_comment| distinguishes between
+the two types of comments.
+
+If |skip_comment| comes to the end of the section, it prints an error message.
+No comment, long or short, is allowed to contain `\.{@@\ }' or `\.{@@*}'.
+
+@<Global...@>=
+boolean comment_continues=0; /* are we scanning a comment? */
+
+@ @c
+int skip_comment(is_long_comment) /* skips over comments */
+boolean is_long_comment;
+{
+ char c; /* current character */
+ while (1) {
+ if (loc>limit) {
+ if (is_long_comment) {
+ if(get_line()) return(comment_continues=1);
+ else{
+ err_print("! Input ended in mid-comment");
+@.Input ended in mid-comment@>
+ return(comment_continues=0);
+ }
+ }
+ else return(comment_continues=0);
+ }
+ c=*(loc++);
+ if (is_long_comment && c=='*' && *loc=='/') {
+ loc++; return(comment_continues=0);
+ }
+ if (c=='@@') {
+ if (ccode[(eight_bits)*loc]==new_section) {
+ err_print("! Section name ended in mid-comment"); loc--;
+@.Section name ended in mid-comment@>
+ return(comment_continues=0);
+ }
+ else loc++;
+ }
+ }
+}
+
+@* Inputting the next token.
+
+@d constant 03
+
+@<Global...@>=
+name_pointer cur_section_name; /* name of section just scanned */
+int no_where; /* suppress |print_where|? */
+
+@ @<Include...@>=
+#include <ctype.h> /* definition of |isalpha|, |isdigit| and so on */
+#include <stdlib.h> /* definition of |exit| */
+
+@ As one might expect, |get_next| consists mostly of a big switch
+that branches to the various special cases that can arise.
+
+@d isxalpha(c) ((c)=='_' || (c)=='$')
+ /* non-alpha characters allowed in identifier */
+@d ishigh(c) ((unsigned char)(c)>0177)
+@^high-bit character handling@>
+
+@c
+eight_bits
+get_next() /* produces the next input token */
+{
+ static int preprocessing=0;
+ eight_bits c; /* the current character */
+ while (1) {
+ if (loc>limit) {
+ if (preprocessing && *(limit-1)!='\\') preprocessing=0;
+ if (get_line()==0) return(new_section);
+ else if (print_where && !no_where) {
+ print_where=0;
+ @<Insert the line number into |tok_mem|@>;
+ }
+ else return ('\n');
+ }
+ c=*loc;
+ if (comment_continues || (c=='/' && (*(loc+1)=='*' || *(loc+1)=='/'))) {
+ skip_comment(comment_continues||*(loc+1)=='*');
+ /* scan to end of comment or newline */
+ if (comment_continues) return('\n');
+ else continue;
+ }
+ loc++;
+ if (xisdigit(c) || c=='.') @<Get a constant@>@;
+ else if (c=='\'' || c=='"' || (c=='L'&&(*loc=='\'' || *loc=='"')))
+ @<Get a string@>@;
+ else if (isalpha(c) || isxalpha(c) || ishigh(c))
+ @<Get an identifier@>@;
+ else if (c=='@@') @<Get control code and possible section name@>@;
+ else if (xisspace(c)) {
+ if (!preprocessing || loc>limit) continue;
+ /* we don't want a blank after a final backslash */
+ else return(' '); /* ignore spaces and tabs, unless preprocessing */
+ }
+ else if (c=='#' && loc==buffer+1) preprocessing=1;
+ mistake: @<Compress two-symbol operator@>@;
+ return(c);
+ }
+}
+
+@ The following code assigns values to the combinations \.{++},
+\.{--}, \.{->}, \.{>=}, \.{<=}, \.{==}, \.{<<}, \.{>>}, \.{!=}, \.{||} and
+\.{\&\&}, and to the \CPLUSPLUS/
+combinations \.{...}, \.{::}, \.{.*} and \.{->*}.
+The compound assignment operators (e.g., \.{+=}) are
+treated as separate tokens.
+
+@d compress(c) if (loc++<=limit) return(c)
+
+@<Compress tw...@>=
+switch(c) {
+ case '+': if (*loc=='+') compress(plus_plus); break;
+ case '-': if (*loc=='-') {compress(minus_minus);}
+ else if (*loc=='>') if (*(loc+1)=='*') {loc++; compress(minus_gt_ast);}
+ else compress(minus_gt); break;
+ case '.': if (*loc=='*') {compress(period_ast);}
+ else if (*loc=='.' && *(loc+1)=='.') {
+ loc++; compress(dot_dot_dot);
+ }
+ break;
+ case ':': if (*loc==':') compress(colon_colon); break;
+ case '=': if (*loc=='=') compress(eq_eq); break;
+ case '>': if (*loc=='=') {compress(gt_eq);}
+ else if (*loc=='>') compress(gt_gt); break;
+ case '<': if (*loc=='=') {compress(lt_eq);}
+ else if (*loc=='<') compress(lt_lt); break;
+ case '&': if (*loc=='&') compress(and_and); break;
+ case '|': if (*loc=='|') compress(or_or); break;
+ case '!': if (*loc=='=') compress(not_eq); break;
+}
+
+@ @<Get an identifier@>= {
+ id_first=--loc;
+ while (isalpha(*++loc) || isdigit(*loc) || isxalpha(*loc) || ishigh(*loc));
+ id_loc=loc; return(identifier);
+}
+
+@ @<Get a constant@>= {
+ id_first=loc-1;
+ if (*id_first=='.' && !xisdigit(*loc)) goto mistake; /* not a constant */
+ if (*id_first=='0') {
+ if (*loc=='x' || *loc=='X') { /* hex constant */
+ loc++; while (xisxdigit(*loc)) loc++; goto found;
+ }
+ }
+ while (xisdigit(*loc)) loc++;
+ if (*loc=='.') {
+ loc++;
+ while (xisdigit(*loc)) loc++;
+ }
+ if (*loc=='e' || *loc=='E') { /* float constant */
+ if (*++loc=='+' || *loc=='-') loc++;
+ while (xisdigit(*loc)) loc++;
+ }
+ found: while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L'
+ || *loc=='f' || *loc=='F') loc++;
+ id_loc=loc;
+ return(constant);
+}
+
+@ \CEE/ strings and character constants, delimited by double and single
+quotes, respectively, can contain newlines or instances of their own
+delimiters if they are protected by a backslash. We follow this
+convention, but do not allow the string to be longer than |longest_name|.
+
+@<Get a string@>= {
+ char delim = c; /* what started the string */
+ id_first = section_text+1;
+ id_loc = section_text; *++id_loc=delim;
+ if (delim=='L') { /* wide character constant */
+ delim=*loc++; *++id_loc=delim;
+ }
+ while (1) {
+ if (loc>=limit) {
+ if(*(limit-1)!='\\') {
+ err_print("! String didn't end"); loc=limit; break;
+@.String didn't end@>
+ }
+ if(get_line()==0) {
+ err_print("! Input ended in middle of string"); loc=buffer; break;
+@.Input ended in middle of string@>
+ }
+ else if (++id_loc<=section_text_end) *id_loc='\n'; /* will print as
+ \.{"\\\\\\n"} */
+ }
+ if ((c=*loc++)==delim) {
+ if (++id_loc<=section_text_end) *id_loc=c;
+ break;
+ }
+ if (c=='\\') {
+ if (loc>=limit) continue;
+ if (++id_loc<=section_text_end) *id_loc = '\\';
+ c=*loc++;
+ }
+ if (++id_loc<=section_text_end) *id_loc=c;
+ }
+ if (id_loc>=section_text_end) {
+ printf("\n! String too long: ");
+@.String too long@>
+ term_write(section_text+1,25);
+ err_print("...");
+ }
+ id_loc++;
+ return(string);
+}
+
+@ After an \.{@@} sign has been scanned, the next character tells us
+whether there is more work to do.
+
+@<Get control code and possible section name@>= {
+ c=ccode[(eight_bits)*loc++];
+ switch(c) {
+ case ignore: continue;
+ case translit_code: err_print("! Use @@l in limbo only"); continue;
+@.Use @@l in limbo...@>
+ case control_text: while ((c=skip_ahead())=='@@');
+ /* only \.{@@@@} and \.{@@>} are expected */
+ if (*(loc-1)!='>')
+ err_print("! Double @@ should be used in control text");
+@.Double @@ should be used...@>
+ continue;
+ case section_name:
+ cur_section_name_char=*(loc-1);
+ @<Scan the section name and make |cur_section_name| point to it@>;
+ case string: @<Scan a verbatim string@>;
+ case ord: @<Scan an ASCII constant@>;
+ default: return(c);
+ }
+}
+
+@ After scanning a valid ASCII constant that follows
+\.{@@'}, this code plows ahead until it finds the next single quote.
+(Special care is taken if the quote is part of the constant.)
+Anything after a valid ASCII constant is ignored;
+thus, \.{@@'\\nopq'} gives the same result as \.{@@'\\n'}.
+
+@<Scan an ASCII constant@>=
+ id_first=loc;
+ if (*loc=='\\') {
+ if (*++loc=='\'') loc++;
+ }
+ while (*loc!='\'') {
+ if (*loc=='@@') {
+ if (*(loc+1)!='@@')
+ err_print("! Double @@ should be used in ASCII constant");
+@.Double @@ should be used...@>
+ else loc++;
+ }
+ loc++;
+ if (loc>limit) {
+ err_print("! String didn't end"); loc=limit-1; break;
+@.String didn't end@>
+ }
+ }
+ loc++;
+ return(ord);
+
+@ @<Scan the section name...@>= {
+ char *k; /* pointer into |section_text| */
+ @<Put section name into |section_text|@>;
+ if (k-section_text>3 && strncmp(k-2,"...",3)==0)
+ cur_section_name=section_lookup(section_text+1,k-3,1); /* 1 means is a prefix */
+ else cur_section_name=section_lookup(section_text+1,k,0);
+ if (cur_section_name_char=='(')
+ @<If it's not there, add |cur_section_name| to the output file stack, or
+ complain we're out of room@>;
+ return(section_name);
+}
+
+@ Section names are placed into the |section_text| array with consecutive spaces,
+tabs, and carriage-returns replaced by single spaces. There will be no
+spaces at the beginning or the end. (We set |section_text[0]=' '| to facilitate
+this, since the |section_lookup| routine uses |section_text[1]| as the first
+character of the name.)
+
+@<Set init...@>=section_text[0]=' ';
+
+@ @<Put section name...@>=
+k=section_text;
+while (1) {
+ if (loc>limit && get_line()==0) {
+ err_print("! Input ended in section name");
+@.Input ended in section name@>
+ loc=buffer+1; break;
+ }
+ c=*loc;
+ @<If end of name or erroneous nesting, |break|@>;
+ loc++; if (k<section_text_end) k++;
+ if (xisspace(c)) {
+ c=' '; if (*(k-1)==' ') k--;
+ }
+*k=c;
+}
+if (k>=section_text_end) {
+ printf("\n! Section name too long: ");
+@.Section name too long@>
+ term_write(section_text+1,25);
+ printf("..."); mark_harmless;
+}
+if (*k==' ' && k>section_text) k--;
+
+@ @<If end of name or erroneous nesting,...@>=
+if (c=='@@') {
+ c=*(loc+1);
+ if (c=='>') {
+ loc+=2; break;
+ }
+ if (ccode[(eight_bits)c]==new_section) {
+ err_print("! Section name didn't end"); break;
+@.Section name didn't end@>
+ }
+ if (ccode[(eight_bits)c]==section_name) {
+ err_print("! Nesting of section names not allowed"); break;
+@.Nesting of section names...@>
+ }
+ *(++k)='@@'; loc++; /* now |c==*loc| again */
+}
+
+@ At the present point in the program we
+have |*(loc-1)==string|; we set |id_first| to the beginning
+of the string itself, and |id_loc| to its ending-plus-one location in the
+buffer. We also set |loc| to the position just after the ending delimiter.
+
+@<Scan a verbatim string@>= {
+ id_first=loc++; *(limit+1)='@@'; *(limit+2)='>';
+ while (*loc!='@@' || *(loc+1)!='>') loc++;
+ if (loc>=limit) err_print("! Verbatim string didn't end");
+@.Verbatim string didn't end@>
+ id_loc=loc; loc+=2;
+ return(string);
+}
+
+@* Scanning a macro definition.
+The rules for generating the replacement texts corresponding to macros and
+\CEE/ texts of a section are almost identical; the only differences are that
+
+\yskip \item{a)}Section names are not allowed in macros;
+in fact, the appearance of a section name terminates such macros and denotes
+the name of the current section.
+
+\item{b)}The symbols \.{@@d} and \.{@@f} and \.{@@c} are not allowed after
+section names, while they terminate macro definitions.
+
+\item{c)}Spaces are inserted after right parentheses in macros, because the
+ANSI \CEE/ preprocessor sometimes requires it.
+
+\yskip Therefore there is a single procedure |scan_repl| whose parameter
+|t| specifies either |macro| or |section_name|. After |scan_repl| has
+acted, |cur_text| will point to the replacement text just generated, and
+|next_control| will contain the control code that terminated the activity.
+
+@d macro 0
+@d app_repl(c) {if (tok_ptr==tok_mem_end) overflow("token"); *tok_ptr++=c;}
+
+@<Global...@>=
+text_pointer cur_text; /* replacement text formed by |scan_repl| */
+eight_bits next_control;
+
+@ @c
+void
+scan_repl(t) /* creates a replacement text */
+eight_bits t;
+{
+ sixteen_bits a; /* the current token */
+ if (t==section_name) {@<Insert the line number into |tok_mem|@>;}
+ while (1) switch (a=get_next()) {
+ @<In cases that |a| is a non-|char| token (|identifier|,
+ |section_name|, etc.), either process it and change |a| to a byte
+ that should be stored, or |continue| if |a| should be ignored,
+ or |goto done| if |a| signals the end of this replacement text@>@;
+ case ')': app_repl(a);
+ if (t==macro) app_repl(' ');
+ break;
+ default: app_repl(a); /* store |a| in |tok_mem| */
+ }
+ done: next_control=(eight_bits) a;
+ if (text_ptr>text_info_end) overflow("text");
+ cur_text=text_ptr; (++text_ptr)->tok_start=tok_ptr;
+}
+
+@ Here is the code for the line number: first a |sixteen_bits| equal
+to |0150000|; then the numeric line number; then a pointer to the
+file name.
+
+@<Insert the line...@>=
+store_two_bytes(0150000);
+if (changing && include_depth==change_depth) { /* correction made Feb 2017 */
+ id_first=change_file_name;
+ store_two_bytes((sixteen_bits)change_line);
+}@+else {
+ id_first=cur_file_name;
+ store_two_bytes((sixteen_bits)cur_line);
+}
+id_loc=id_first+strlen(id_first);
+{int a=id_lookup(id_first,id_loc,0)-name_dir; app_repl((a / 0400)+0200);
+ app_repl(a % 0400);}
+
+@ @<In cases that |a| is...@>=
+case identifier: a=id_lookup(id_first,id_loc,0)-name_dir;
+ app_repl((a / 0400)+0200);
+ app_repl(a % 0400); break;
+case section_name: if (t!=section_name) goto done;
+ else {
+ @<Was an `@@' missed here?@>;
+ a=cur_section_name-name_dir;
+ app_repl((a / 0400)+0250);
+ app_repl(a % 0400);
+ @<Insert the line number into |tok_mem|@>; break;
+ }
+case output_defs_code: if (t!=section_name) err_print("! Misplaced @@h");
+@.Misplaced @@h@>
+ else {
+ output_defs_seen=1;
+ a=output_defs_flag;
+ app_repl((a / 0400)+0200);
+ app_repl(a % 0400);
+ @<Insert the line number into |tok_mem|@>;
+ }
+ break;
+case constant: case string:
+ @<Copy a string or verbatim construction or numerical constant@>;
+case ord:
+ @<Copy an ASCII constant@>;
+case definition: case format_code: case begin_C: if (t!=section_name) goto done;
+ else {
+ err_print("! @@d, @@f and @@c are ignored in C text"); continue;
+@.@@d, @@f and @@c are ignored in C text@>
+ }
+case new_section: goto done;
+
+@ @<Was an `@@'...@>= {
+ char *try_loc=loc;
+ while (*try_loc==' ' && try_loc<limit) try_loc++;
+ if (*try_loc=='+' && try_loc<limit) try_loc++;
+ while (*try_loc==' ' && try_loc<limit) try_loc++;
+ if (*try_loc=='=') err_print ("! Missing `@@ ' before a named section");
+@.Missing `@@ '...@>
+ /* user who isn't defining a section should put newline after the name,
+ as explained in the manual */
+}
+
+@ @<Copy a string...@>=
+ app_repl(a); /* |string| or |constant| */
+ while (id_first < id_loc) { /* simplify \.{@@@@} pairs */
+ if (*id_first=='@@') {
+ if (*(id_first+1)=='@@') id_first++;
+ else err_print("! Double @@ should be used in string");
+@.Double @@ should be used...@>
+ }
+ app_repl(*id_first++);
+ }
+ app_repl(a); break;
+
+@ This section should be rewritten on machines that don't use ASCII
+code internally.
+@^ASCII code dependencies@>
+
+@<Copy an ASCII constant@>= {
+ int c=(eight_bits) *id_first;
+ if (c=='\\') {
+ c=*++id_first;
+ if (c>='0' && c<='7') {
+ c-='0';
+ if (*(id_first+1)>='0' && *(id_first+1)<='7') {
+ c=8*c+*(++id_first) - '0';
+ if (*(id_first+1)>='0' && *(id_first+1)<='7' && c<32)
+ c=8*c+*(++id_first)- '0';
+ }
+ }
+ else switch (c) {
+ case 't':c='\t';@+break;
+ case 'n':c='\n';@+break;
+ case 'b':c='\b';@+break;
+ case 'f':c='\f';@+break;
+ case 'v':c='\v';@+break;
+ case 'r':c='\r';@+break;
+ case 'a':c='\7';@+break;
+ case '?':c='?';@+break;
+ case 'x':
+ if (xisdigit(*(id_first+1))) c=*(++id_first)-'0';
+ else if (xisxdigit(*(id_first+1))) {
+ ++id_first;
+ c=toupper(*id_first)-'A'+10;
+ }
+ if (xisdigit(*(id_first+1))) c=16*c+*(++id_first)-'0';
+ else if (xisxdigit(*(id_first+1))) {
+ ++id_first;
+ c=16*c+toupper(*id_first)-'A'+10;
+ }
+ break;
+ case '\\':c='\\';@+break;
+ case '\'':c='\'';@+break;
+ case '\"':c='\"';@+break;
+ default: err_print("! Unrecognized escape sequence");
+@.Unrecognized escape sequence@>
+ }
+ }@/
+ /* at this point |c| should have been converted to its ASCII code number */
+ app_repl(constant);
+ if (c>=100) app_repl('0'+c/100);
+ if (c>=10) app_repl('0'+(c/10)%10);
+ app_repl('0'+c%10);
+ app_repl(constant);
+}
+break;
+
+@* Scanning a section.
+The |scan_section| procedure starts when `\.{@@\ }' or `\.{@@*}' has been
+sensed in the input, and it proceeds until the end of that section. It
+uses |section_count| to keep track of the current section number; with luck,
+\.{CWEAVE} and \.{CTANGLE} will both assign the same numbers to sections.
+
+@<Global...@>=
+extern sixteen_bits section_count; /* the current section number */
+
+@ The body of |scan_section| is a loop where we look for control codes
+that are significant to \.{CTANGLE}: those
+that delimit a definition, the \CEE/ part of a module, or a new module.
+
+@c
+void
+scan_section()
+{
+ name_pointer p; /* section name for the current section */
+ text_pointer q; /* text for the current section */
+ sixteen_bits a; /* token for left-hand side of definition */
+ section_count++; @+ no_where=1;
+ if (*(loc-1)=='*' && show_progress) { /* starred section */
+ printf("*%d",section_count); update_terminal;
+ }
+ next_control=0;
+ while (1) {
+ @<Skip ahead until |next_control| corresponds to \.{@@d}, \.{@@<},
+ \.{@@\ } or the like@>;
+ if (next_control == definition) { /* \.{@@d} */
+ @<Scan a definition@>@;
+ continue;
+ }
+ if (next_control == begin_C) { /* \.{@@c} or \.{@@p} */
+ p=name_dir; break;
+ }
+ if (next_control == section_name) { /* \.{@@<} or \.{@@(} */
+ p=cur_section_name;
+ @<If section is not being defined, |continue| @>;
+ break;
+ }
+ return; /* \.{@@\ } or \.{@@*} */
+ }
+ no_where=print_where=0;
+ @<Scan the \CEE/ part of the current section@>;
+}
+
+@ At the top of this loop, if |next_control==section_name|, the
+section name has already been scanned (see |@<Get control code
+and...@>|). Thus, if we encounter |next_control==section_name| in the
+skip-ahead process, we should likewise scan the section name, so later
+processing will be the same in both cases.
+
+@<Skip ahead until |next_control| ...@>=
+while (next_control<definition)
+ /* |definition| is the lowest of the ``significant'' codes */
+ if((next_control=skip_ahead())==section_name){
+ loc-=2; next_control=get_next();
+ }
+
+@ @<Scan a definition@>= {
+ while ((next_control=get_next())=='\n'); /*allow newline before definition */
+ if (next_control!=identifier) {
+ err_print("! Definition flushed, must start with identifier");
+@.Definition flushed...@>
+ continue;
+ }
+ app_repl(((a=id_lookup(id_first,id_loc,0)-name_dir) / 0400)+0200);
+ /* append the lhs */
+ app_repl(a % 0400);
+ if (*loc!='(') { /* identifier must be separated from replacement text */
+ app_repl(string); app_repl(' '); app_repl(string);
+ }
+ scan_repl(macro);
+ cur_text->text_link=0; /* |text_link==0| characterizes a macro */
+}
+
+@ If the section name is not followed by \.{=} or \.{+=}, no \CEE/
+code is forthcoming: the section is being cited, not being
+defined. This use is illegal after the definition part of the
+current section has started, except inside a comment, but
+\.{CTANGLE} does not enforce this rule; it simply ignores the offending
+section name and everything following it, up to the next significant
+control code.
+
+@<If section is not being defined, |continue| @>=
+while ((next_control=get_next())=='+'); /* allow optional \.{+=} */
+if (next_control!='=' && next_control!=eq_eq)
+ continue;
+
+@ @<Scan the \CEE/...@>=
+@<Insert the section number into |tok_mem|@>;
+scan_repl(section_name); /* now |cur_text| points to the replacement text */
+@<Update the data structure so that the replacement text is accessible@>;
+
+@ @<Insert the section number...@>=
+store_two_bytes((sixteen_bits)(0150000+section_count));
+ /* |0150000==0320*0400| */
+
+@ @<Update the data...@>=
+if (p==name_dir||p==0) { /* unnamed section, or bad section name */
+ (last_unnamed)->text_link=cur_text-text_info; last_unnamed=cur_text;
+}
+else if (p->equiv==(char *)text_info) p->equiv=(char *)cur_text;
+ /* first section of this name */
+else {
+ q=(text_pointer)p->equiv;
+ while (q->text_link<section_flag)
+ q=q->text_link+text_info; /* find end of list */
+ q->text_link=cur_text-text_info;
+}
+cur_text->text_link=section_flag;
+ /* mark this replacement text as a nonmacro */
+
+@ @<Predec...@>=
+void phase_one();
+
+@ @c
+void
+phase_one() {
+ phase=1;
+ section_count=0;
+ reset_input();
+ skip_limbo();
+ while (!input_has_ended) scan_section();
+ check_complete();
+ phase=2;
+}
+
+@ Only a small subset of the control codes is legal in limbo, so limbo
+processing is straightforward.
+
+@<Predecl...@>=
+void skip_limbo();
+
+@ @c
+void
+skip_limbo()
+{
+ char c;
+ while (1) {
+ if (loc>limit && get_line()==0) return;
+ *(limit+1)='@@';
+ while (*loc!='@@') loc++;
+ if (loc++<=limit) {
+ c=*loc++;
+ if (ccode[(eight_bits)c]==new_section) break;
+ switch (ccode[(eight_bits)c]) {
+ case translit_code: @<Read in transliteration of a character@>; break;
+ case format_code: case '@@': break;
+ case control_text: if (c=='q' || c=='Q') {
+ while ((c=skip_ahead())=='@@');
+ if (*(loc-1)!='>')
+ err_print("! Double @@ should be used in control text");
+@.Double @@ should be used...@>
+ break;
+ } /* otherwise fall through */
+ default: err_print("! Double @@ should be used in limbo");
+@.Double @@ should be used...@>
+ }
+ }
+ }
+}
+
+@ @<Read in transliteration of a character@>=
+ while(xisspace(*loc)&&loc<limit) loc++;
+ loc+=3;
+ if (loc>limit || !xisxdigit(*(loc-3)) || !xisxdigit(*(loc-2)) @|
+ || (*(loc-3)>='0' && *(loc-3)<='7') || !xisspace(*(loc-1)))
+ err_print("! Improper hex number following @@l");
+@.Improper hex number...@>
+ else {
+ unsigned i;
+ char *beg;
+ sscanf(loc-3,"%x",&i);
+ while(xisspace(*loc)&&loc<limit) loc++;
+ beg=loc;
+ while(loc<limit&&(xisalpha(*loc)||xisdigit(*loc)||*loc=='_')) loc++;
+ if (loc-beg>=translit_length)
+ err_print("! Replacement string in @@l too long");
+@.Replacement string in @@l...@>
+ else{
+ strncpy(translit[i-0200],beg,loc-beg);
+ translit[i-0200][loc-beg]='\0';
+ }
+ }
+
+@ Because on some systems the difference between two pointers is a |long|
+but not an |int|, we use \.{\%ld} to print these quantities.
+
+@c
+void
+print_stats() {
+ printf("\nMemory usage statistics:\n");
+ printf("%ld names (out of %ld)\n",
+ (long)(name_ptr-name_dir),(long)max_names);
+ printf("%ld replacement texts (out of %ld)\n",
+ (long)(text_ptr-text_info),(long)max_texts);
+ printf("%ld bytes (out of %ld)\n",
+ (long)(byte_ptr-byte_mem),(long)max_bytes);
+ printf("%ld tokens (out of %ld)\n",
+ (long)(tok_ptr-tok_mem),(long)max_toks);
+}
+
+@** Index.
+Here is a cross-reference table for \.{CTANGLE}.
+All sections in which an identifier is
+used are listed with that identifier, except that reserved words are
+indexed only when they appear in format definitions, and the appearances
+of identifiers in section names are not indexed. Underlined entries
+correspond to where the identifier was declared. Error messages and
+a few other things like ``ASCII code dependencies'' are indexed here too.
diff --git a/web/c_cpp/cweb/cweav-bs.ch b/web/c_cpp/cweb/cweav-bs.ch
new file mode 100644
index 0000000000..8c4c1fe8ff
--- /dev/null
+++ b/web/c_cpp/cweb/cweav-bs.ch
@@ -0,0 +1,302 @@
+Changes for CWEAVE for MSDOS and Borland C++ 3.1 using the following
+options (and perhaps others):
+
+ -mc -w-pro -Ff=5000 -Z- -O-p
+
+The options -Z- and -O-p explicitly turn off optimizations that break
+the code. (See makefile.bs.)
+
+The main purpose of these changes is to support MSDOS with full-size arrays
+by using "huge" pointers.
+
+This file contributed by Barry Schwartz, trashman@crud.mn.org, 28 Jun 94.
+(Includes workaround for compiler bug [pointers wrapping around at
+ segment boundaries], November 1993, contributed by Jorge Fernandez Arnaiz
+ -- arnaiz@redvax1.dgsca.unam.mx)
+(Last revised 5 Dec 94 with help of bob@microprograms.com.)
+
+
+@x Section 1.
+The ``banner line'' defined here should be changed whenever \.{CWEAVE}
+is modified.
+
+@d banner "This is CWEAVE (Version 3.64)\n"
+@y
+The ``banner line'' defined here should be changed whenever \.{CWEAVE}
+is modified.
+
+@d banner "This is CWEAVE (Version 3.64pc/big)\n"
+@z
+
+
+@x Section 9.
+@d chunk_marker 0
+
+@<Common code...@>=
+typedef struct name_info {
+ char *byte_start; /* beginning of the name in |byte_mem| */
+ struct name_info *link;
+ union {
+ struct name_info *Rlink; /* right link in binary search tree for section
+ names */
+ char Ilk; /* used by identifiers in \.{CWEAVE} only */
+ } dummy;
+ char *equiv_or_xref; /* info corresponding to names */
+} name_info; /* contains information about an identifier or section name */
+typedef name_info *name_pointer; /* pointer into array of \&{name\_info}s */
+typedef name_pointer *hash_pointer;
+extern char byte_mem[]; /* characters of names */
+extern char *byte_mem_end; /* end of |byte_mem| */
+extern name_info name_dir[]; /* information about names */
+extern name_pointer name_dir_end; /* end of |name_dir| */
+extern name_pointer name_ptr; /* first unused position in |name_dir| */
+extern char *byte_ptr; /* first unused position in |byte_mem| */
+extern name_pointer hash[]; /* heads of hash lists */
+extern hash_pointer hash_end; /* end of |hash| */
+extern hash_pointer h; /* index into hash-head array */
+extern name_pointer id_lookup(); /* looks up a string in the identifier table */
+extern name_pointer section_lookup(); /* finds section name */
+extern void print_section_name(), sprint_section_name();
+@y
+@d chunk_marker 0
+
+@f huge extern
+
+@<Common code...@>=
+typedef struct name_info {
+ char huge* byte_start; /* beginning of the name in |byte_mem| */
+ struct name_info *link;
+ union {
+ struct name_info *Rlink; /* right link in binary search tree for section
+ names */
+ char Ilk; /* used by identifiers in \.{CWEAVE} only */
+ } dummy;
+ union {
+ char *equiv_member;
+ char huge* xref_member;
+ } ptr_union; /* info corresponding to names */
+} name_info; /* contains information about an identifier or section name */
+typedef name_info *name_pointer; /* pointer into array of \&{name\_info}s */
+typedef name_pointer *hash_pointer;
+extern char huge byte_mem[]; /* characters of names */
+extern char huge* byte_mem_end; /* end of |byte_mem| */
+extern name_info name_dir[]; /* information about names */
+extern name_pointer name_dir_end; /* end of |name_dir| */
+extern name_pointer name_ptr; /* first unused position in |name_dir| */
+extern char huge* byte_ptr; /* first unused position in |byte_mem| */
+extern name_pointer hash[]; /* heads of hash lists */
+extern hash_pointer hash_end; /* end of |hash| */
+extern hash_pointer h; /* index into hash-head array */
+extern name_pointer id_lookup(); /* looks up a string in the identifier table */
+extern name_pointer section_lookup(); /* finds section name */
+extern void print_section_name(), sprint_section_name();
+@z
+
+
+@x Section 18.
+typedef struct xref_info {
+ sixteen_bits num; /* section number plus zero or |def_flag| */
+ struct xref_info *xlink; /* pointer to the previous cross-reference */
+} xref_info;
+typedef xref_info *xref_pointer;
+@y
+typedef struct xref_info {
+ sixteen_bits num; /* section number plus zero or |def_flag| */
+ struct xref_info huge* xlink; /* pointer to the previous cross-reference */
+} xref_info;
+typedef xref_info huge* xref_pointer;
+@z
+
+
+@x Section 19.
+xref_info xmem[max_refs]; /* contains cross-reference information */
+xref_pointer xmem_end = xmem+max_refs-1;
+@y
+xref_info huge xmem[max_refs]; /* contains cross-reference information */
+xref_pointer xmem_end;
+@z
+
+
+@x Section 20.
+@d xref equiv_or_xref
+@y
+@d xref ptr_union.xref_member
+@z
+
+
+@x Section 20.
+xref_ptr=xmem; name_dir->xref=(char*)xmem; xref_switch=0; section_xref_switch=0;
+xmem->num=0; /* sentinel value */
+@y
+xmem_end = xmem + max_refs - 1;
+xref_ptr=xmem; name_dir->xref=(char*)xmem; xref_switch=0; section_xref_switch=0;
+xmem->num=0; /* sentinel value */
+@z
+
+
+@x Section 21.
+ append_xref(m); xref_ptr->xlink=q; p->xref=(char*)xref_ptr;
+@y
+ append_xref(m); xref_ptr->xlink=q; p->xref=(char huge*)xref_ptr;
+@z
+
+
+@x Section 22.
+ if (r==xmem) p->xref=(char*)xref_ptr;
+@y
+ if (r==xmem) p->xref=(char huge*)xref_ptr;
+@z
+
+
+@x Section 23.
+ q=(xref_pointer)p->xref;
+ if (q->num==file_flag) return;
+ append_xref(file_flag);
+ xref_ptr->xlink = q;
+ p->xref = (char *)xref_ptr;
+@y
+ q=(xref_pointer)p->xref;
+ if (q->num==file_flag) return;
+ append_xref(file_flag);
+ xref_ptr->xlink = q;
+ p->xref = (char huge*)xref_ptr;
+@z
+
+@x Section 25. (to please Borland's C++, version 4.02)
+token tok_mem[max_toks]; /* tokens */
+token_pointer tok_mem_end = tok_mem+max_toks-1; /* end of |tok_mem| */
+token_pointer tok_start[max_texts]; /* directory into |tok_mem| */
+token_pointer tok_ptr; /* first unused position in |tok_mem| */
+text_pointer text_ptr; /* first unused position in |tok_start| */
+text_pointer tok_start_end = tok_start+max_texts-1; /* end of |tok_start| */
+token_pointer max_tok_ptr; /* largest value of |tok_ptr| */
+@y
+token tok_mem[max_toks]; /* tokens */
+token_pointer tok_mem_end; /* end of |tok_mem| */
+token_pointer tok_start[max_texts]; /* directory into |tok_mem| */
+token_pointer tok_ptr; /* first unused position in |tok_mem| */
+text_pointer text_ptr; /* first unused position in |tok_start| */
+text_pointer tok_start_end; /* end of |tok_start| */
+token_pointer max_tok_ptr; /* largest value of |tok_ptr| */
+@z
+
+@x Section 26. (goes with the previous change)
+tok_start[1]=tok_mem+1;
+max_tok_ptr=tok_mem+1; max_text_ptr=tok_start+1;
+@y
+tok_start[1]=tok_mem+1;
+tok_mem_end=tok_mem+max_toks-1;
+tok_start_end=tok_start+max_texts-1;
+max_tok_ptr=tok_mem+1; max_text_ptr=tok_start+1;
+@z
+
+
+@x Section 27.
+ p->ilk=t; p->xref=(char*)xmem;
+@y
+ p->ilk=t; p->xref=(char huge*)xmem;
+@z
+
+
+@x Section 27.
+ p->xref=(char*)xmem;
+@y
+ p->xref=(char huge*)xmem;
+@z
+
+
+@x Section 70.
+ if (unindexed(lhs)) { /* retain only underlined entries */
+ xref_pointer q,r=NULL;
+ for (q=(xref_pointer)lhs->xref;q>xmem;q=q->xlink)
+ if (q->num<def_flag)
+ if (r) r->xlink=q->xlink;
+ else lhs->xref=(char*)q->xlink;
+ else r=q;
+ }
+@y
+ if (unindexed(lhs)) { /* retain only underlined entries */
+ xref_pointer q,r=NULL;
+ for (q=(xref_pointer)lhs->xref;q>xmem;q=q->xlink)
+ if (q->num<def_flag)
+ if (r) r->xlink=q->xlink;
+ else lhs->xref=(char huge*)q->xlink;
+ else r=q;
+ }
+@z
+
+
+@x Section 87.
+ char *k, *k_end=(p+1)->byte_start; /* pointers into |byte_mem| */
+ out('{');
+ for (k=p->byte_start; k<k_end; k++) {
+@y
+ char huge* k, huge* k_end=(p+1)->byte_start; /* pointers into |byte_mem| */
+ out('{');
+ for (k=p->byte_start; k<k_end; k++) {
+@z
+
+
+@x Section 116.
+ append_xref(0); /* this number doesn't matter */
+ xref_ptr->xlink=(xref_pointer)p->xref; r=xref_ptr;
+ p->xref=(char*)xref_ptr;
+ while (r->xlink!=q) {r->num=r->xlink->num; r=r->xlink;}
+ r->num=m; /* everything from |q| on is left undisturbed */
+@y
+ append_xref(0); /* this number doesn't matter */
+ xref_ptr->xlink=(xref_pointer)p->xref; r=xref_ptr;
+ p->xref=(char huge*)xref_ptr;
+ while (r->xlink!=q) {r->num=r->xlink->num; r=r->xlink;}
+ r->num=m; /* everything from |q| on is left undisturbed */
+@z
+
+
+@x Section 163.
+@ @<Change |pp| to $\max...@>=
+@y
+@ @<Change |pp| to $\max...@>=
+#ifdef __MSDOS__
+if (d<0 && pp+d>pp) pp=scrap_base; /* segmented architecture caused wrap */
+else
+#endif
+@z
+
+
+@x Section 194.
+ char *p; /* index into |byte_mem| */
+@y
+ char huge *p; /* index into |byte_mem| */
+@z
+
+
+@x Section 229.
+ if (cur_name->xref!=(char*)xmem) {
+@y
+ if (cur_name->xref!=(char huge*)xmem) {
+@z
+
+
+@x Section 232.
+char *cur_byte; /* index into |byte_mem| */
+@y
+char huge* cur_byte; /* index into |byte_mem| */
+@z
+
+
+@x Section 241.
+switch (cur_name->ilk) {
+ case normal: if (is_tiny(cur_name)) out_str("\\|");
+ else {char *j;
+@y
+switch (cur_name->ilk) {
+ case normal: if (is_tiny(cur_name)) out_str("\\|");
+ else {char huge* j;
+@z
+
+
+@x Section 241.
+ case custom: case quoted: {char *j; out_str("$\\");
+@y
+ case custom: case quoted: {char huge* j; out_str("$\\");
+@z
diff --git a/web/c_cpp/cweb/cweav-man.ch b/web/c_cpp/cweb/cweav-man.ch
new file mode 100644
index 0000000000..6cfcc8fe2d
--- /dev/null
+++ b/web/c_cpp/cweb/cweav-man.ch
@@ -0,0 +1,22 @@
+Change file to help make Appendix F of the full CWEB manual
+@x
+\def\botofcontents{\vfill
+\noindent
+Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth
+\bigskip\noindent
+Permission is granted to make and distribute verbatim copies of this
+document provided that the copyright notice and this permission notice
+are preserved on all copies.
+
+\smallskip\noindent
+Permission is granted to copy and distribute modified versions of this
+document under the conditions for verbatim copying, provided that the
+entire resulting derived work is given a different name and distributed
+under the terms of a permission notice identical to this one.
+}
+@y
+\def\botofcontents{\vfill\titlefalse}
+\def\contentspagenumber{109}
+\def\title{APPENDIX F: CWEAVE}
+\let\K=\leftarrow
+@z
diff --git a/web/c_cpp/cweb/cweav-pc.ch b/web/c_cpp/cweb/cweav-pc.ch
new file mode 100644
index 0000000000..28cd94f5a3
--- /dev/null
+++ b/web/c_cpp/cweb/cweav-pc.ch
@@ -0,0 +1,39 @@
+This is the change file for CWEB's CWEAVE under DOS
+(Contributed by Lee Wittenberg, March 1993)
+(Also includes workaround for compiler bug, November 1993,
+ contributed by Jorge Fernandez Arnaiz -- arnaiz@redvax1.dgsca.unam.mx)
+
+Changes necessary for compiling with Borland C/C++
+Use compilation switches -mc -w-pro -Ff=5000
+
+Note: The changes to section 4 are not necessary if using a compiler
+that allows >64K arrays. (If you need lots more bytes, try the alternate
+change files that have -bs in their name instead of -pc.)
+
+@x section 1
+@d banner "This is CWEAVE (Version 3.64)\n"
+@y
+@d banner "This is CWEAVE (Version 3.64pc)\n"
+@z
+
+@x section 4
+@d max_bytes 90000 /* the number of bytes in identifiers,
+@y
+@d max_bytes (unsigned)60000 /* the number of bytes in identifiers,
+@z
+@x
+@d max_refs 20000 /* number of cross-references; must be less than 65536 */
+@y
+@d max_refs 10000 /* number of cross-references; must be less than 65536 */
+@z
+
+@x section 163
+@ @<Change |pp| to $\max...@>=
+@y
+@ @<Change |pp| to $\max...@>=
+#ifdef __MSDOS__
+if (d<0 && pp+d>pp) pp=scrap_base; /* segmented architecture caused wrap */
+else
+#endif
+@z
+
diff --git a/web/c_cpp/cweb/cweav-ql.ch b/web/c_cpp/cweb/cweav-ql.ch
new file mode 100644
index 0000000000..3e37ba2352
--- /dev/null
+++ b/web/c_cpp/cweb/cweav-ql.ch
@@ -0,0 +1,32 @@
+This is the change file for CWEB's CWEAVE under QDOS/SMSQ
+(Contributed by Robert H. Klein, September 1994)
+
+This change file is intended for use with C68 v4.14 (or later).
+compile with
+ex <dev_>cc;"-v -h -c =500000 cweave_c"
+
+
+@x
+\def\title{CWEAVE (Version 3.64)}
+@y
+\def\title{CWEAVE (QL Version 3.64)}
+@z
+
+@x section 1
+@d banner "This is CWEAVE (Version 3.64)\n"
+@y
+@d banner "This is CWEAVE (QL Version 3.64)\n"
+@z
+
+@x
+@i common.h
+@y
+@i common_h
+@z
+
+
+@x
+@i prod.w
+@y
+@i prod_w
+@z
diff --git a/web/c_cpp/cweb/cweav-vms.ch b/web/c_cpp/cweb/cweav-vms.ch
new file mode 100644
index 0000000000..b6f46559cc
--- /dev/null
+++ b/web/c_cpp/cweb/cweav-vms.ch
@@ -0,0 +1,37 @@
+This is the change file for CWEB's CWEAVE for VAX/VMS.
+
+created:
+ 1991 JM (John Mulhollen, Science Applications International Corporation)
+
+modified:
+ 01-FEB-1992 ST (Stephan Trebels <trebels@ams02.dnet.gwdg.de>)
+ > include ctype,stdio from textlibrary SYS$SHARE:VAXCDEF.TLB
+ > change banner line to include (VAX/VMS)
+ > allow $ in identifiers (*necessary* for VAX/VMS)
+ ? will someone eventally make a CLD interface? (should be easy)
+
+(also modified by Don Knuth to keep version numbers uptodate)
+
+@x section 1 (01-FEB-1992 ST)
+@d banner "This is CWEAVE (Version 3.64)\n"
+@y
+@d banner "This is CWEAVE (VAX/VMS Version 3.64)\n"
+@z
+
+@x section 6 (from common.h) (01-FEB-1992 ST)
+#include <stdio.h>
+@y
+#include stdio /* VMS searches Textlibraries faster */
+@z
+
+@x section 38 (1991 JM) (01-FEB-1992 ST)
+#include <ctype.h> /* definition of |isalpha|, |isdigit| and so on */
+@y
+#include ctype /* VMS searches Textlibraries faster */
+@z
+
+@x section 39 (01-FEB-1992 ST)
+@d isxalpha(c) ((c)=='_') /* non-alpha character allowed in identifier */
+@y
+@d isxalpha(c) ((c)=='_' || (c)=='$') /* non-alpha characters allowed in id */
+@z
diff --git a/web/c_cpp/cweb/cweav-w32.ch b/web/c_cpp/cweb/cweav-w32.ch
new file mode 100644
index 0000000000..26825b0bfd
--- /dev/null
+++ b/web/c_cpp/cweb/cweav-w32.ch
@@ -0,0 +1,52 @@
+This is the change file for CWEB's CWEAVE under Win32
+(Contributed by Fabrice Popineau, February 2002)
+
+@x section 1
+@d banner "This is CWEAVE (Version 3.64)\n"
+@y
+@d banner "This is CWEAVE (Version 3.64win32)\n"
+@z
+
+@x
+@ We predeclare several standard system functions here instead of including
+their system header files, because the names of the header files are not as
+standard as the names of the functions. (For example, some \CEE/ environments
+have \.{<string.h>} where others have \.{<strings.h>}.)
+
+@<Predecl...@>=
+extern int strlen(); /* length of string */
+extern int strcmp(); /* compare strings lexicographically */
+extern char* strcpy(); /* copy one string to another */
+extern int strncmp(); /* compare up to $n$ string characters */
+extern char* strncpy(); /* copy up to $n$ string characters */
+@y
+@z
+
+@x
+int names_match(p,first,l,t)
+name_pointer p; /* points to the proposed match */
+@y
+int __cdecl names_match(p,first,l,t)
+name_pointer p; /* points to the proposed match */
+@z
+
+@x
+void
+init_p(p,t)
+name_pointer p;
+@y
+void __cdecl
+init_p(p,t)
+name_pointer p;
+@z
+
+@x
+@ @<Include...@>=
+#include <ctype.h> /* definition of |isalpha|, |isdigit| and so on */
+#include <stdlib.h> /* definition of |exit| */
+@y
+@ @<Include...@>=
+#include <ctype.h> /* definition of |isalpha|, |isdigit| and so on */
+#include <stdlib.h> /* definition of |exit| */
+#include <string.h> /* definition of |strncmp| and |strncpy| */
+@z
diff --git a/web/c_cpp/cweb/cweave.w b/web/c_cpp/cweb/cweave.w
new file mode 100644
index 0000000000..e06762b1fc
--- /dev/null
+++ b/web/c_cpp/cweb/cweave.w
@@ -0,0 +1,4652 @@
+% This file is part of CWEB.
+% This program by Silvio Levy and Donald E. Knuth
+% is based on a program by Knuth.
+% It is distributed WITHOUT ANY WARRANTY, express or implied.
+% Version 3.64 --- February 2002
+% (essentially the same as version 3.6, which added
+% recently introduced features of standard C++ to version 3.4)
+% (In November 2016 I made minor adjustments but changed no code -- DEK)
+
+% Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth
+
+% Permission is granted to make and distribute verbatim copies of this
+% document provided that the copyright notice and this permission notice
+% are preserved on all copies.
+
+% Permission is granted to copy and distribute modified versions of this
+% document under the conditions for verbatim copying, provided that the
+% entire resulting derived work is given a different name and distributed
+% under the terms of a permission notice identical to this one.
+
+% Here is TeX material that gets inserted after \input cwebmac
+\def\hang{\hangindent 3em\indent\ignorespaces}
+\def\pb{$\.|\ldots\.|$} % C brackets (|...|)
+\def\v{\char'174} % vertical (|) in typewriter font
+\def\dleft{[\![} \def\dright{]\!]} % double brackets
+\mathchardef\RA="3221 % right arrow
+\mathchardef\BA="3224 % double arrow
+\def\({} % ) kludge for alphabetizing certain section names
+\def\TeXxstring{\\{\TEX/\_string}}
+\def\skipxTeX{\\{skip\_\TEX/}}
+\def\copyxTeX{\\{copy\_\TEX/}}
+
+\def\title{CWEAVE (Version 3.64)}
+\def\topofcontents{\null\vfill
+ \centerline{\titlefont The {\ttitlefont CWEAVE} processor}
+ \vskip 15pt
+ \centerline{(Version 3.64)}
+ \vfill}
+\def\botofcontents{\vfill
+\noindent
+Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth
+\bigskip\noindent
+Permission is granted to make and distribute verbatim copies of this
+document provided that the copyright notice and this permission notice
+are preserved on all copies.
+
+\smallskip\noindent
+Permission is granted to copy and distribute modified versions of this
+document under the conditions for verbatim copying, provided that the
+entire resulting derived work is given a different name and distributed
+under the terms of a permission notice identical to this one.
+}
+\pageno=\contentspagenumber \advance\pageno by 1
+\let\maybe=\iftrue
+@s not_eq normal @q unreserve a C++ keyword @>
+
+@** Introduction.
+This is the \.{CWEAVE} program by Silvio Levy and Donald E. Knuth,
+based on \.{WEAVE} by Knuth.
+We are thankful to Steve Avery,
+Nelson Beebe, Hans-Hermann Bode (to whom the original \CPLUSPLUS/ adaptation
+is due), Klaus Guntermann, Norman Ramsey, Tomas Rokicki, Joachim Schnitter,
+Joachim Schrod, Lee Wittenberg, Saroj Mahapatra, Cesar Augusto Rorato
+Crusius, and others who have contributed improvements.
+
+The ``banner line'' defined here should be changed whenever \.{CWEAVE}
+is modified.
+
+@d banner "This is CWEAVE (Version 3.64)\n"
+
+@c @<Include files@>@/
+@h
+@<Common code for \.{CWEAVE} and \.{CTANGLE}@>@/
+@<Typedef declarations@>@/
+@<Global variables@>@/
+@<Predeclaration of procedures@>
+
+@ We predeclare several standard system functions here instead of including
+their system header files, because the names of the header files are not as
+standard as the names of the functions. (For example, some \CEE/ environments
+have \.{<string.h>} where others have \.{<strings.h>}.)
+
+@<Predecl...@>=
+extern int strlen(); /* length of string */
+extern int strcmp(); /* compare strings lexicographically */
+extern char* strcpy(); /* copy one string to another */
+extern int strncmp(); /* compare up to $n$ string characters */
+extern char* strncpy(); /* copy up to $n$ string characters */
+
+@ \.{CWEAVE} has a fairly straightforward outline. It operates in
+three phases: First it inputs the source file and stores cross-reference
+data, then it inputs the source once again and produces the \TEX/ output
+file, finally it sorts and outputs the index.
+
+Please read the documentation for \.{common}, the set of routines common
+to \.{CTANGLE} and \.{CWEAVE}, before proceeding further.
+
+@c
+int main (ac, av)
+int ac; /* argument count */
+char **av; /* argument values */
+{
+ argc=ac; argv=av;
+ program=cweave;
+ make_xrefs=force_lines=make_pb=1; /* controlled by command-line options */
+ common_init();
+ @<Set initial values@>;
+ if (show_banner) printf(banner); /* print a ``banner line'' */
+ @<Store all the reserved words@>;
+ phase_one(); /* read all the user's text and store the cross-references */
+ phase_two(); /* read all the text again and translate it to \TEX/ form */
+ phase_three(); /* output the cross-reference index */
+ return wrap_up(); /* and exit gracefully */
+}
+
+@ The following parameters were sufficient in the original \.{WEAVE} to
+handle \TEX/, so they should be sufficient for most applications of \.{CWEAVE}.
+If you change |max_bytes|, |max_names|, |hash_size|, or |buf_size|
+you have to change them also in the file |"common.w"|.
+
+@d max_bytes 90000 /* the number of bytes in identifiers,
+ index entries, and section names */
+@d max_names 4000 /* number of identifiers, strings, section names;
+ must be less than 10240; used in |"common.w"| */
+@d max_sections 2000 /* greater than the total number of sections */
+@d hash_size 353 /* should be prime */
+@d buf_size 100 /* maximum length of input line, plus one */
+@d longest_name 10000 /* section names and strings shouldn't be longer than this */
+@d long_buf_size (buf_size+longest_name)
+@d line_length 80 /* lines of \TEX/ output have at most this many characters;
+ should be less than 256 */
+@d max_refs 20000 /* number of cross-references; must be less than 65536 */
+@d max_toks 20000 /* number of symbols in \CEE/ texts being parsed;
+ must be less than 65536 */
+@d max_texts 4000 /* number of phrases in \CEE/ texts being parsed;
+ must be less than 10240 */
+@d max_scraps 2000 /* number of tokens in \CEE/ texts being parsed */
+@d stack_size 400 /* number of simultaneous output levels */
+
+@ The next few sections contain stuff from the file |"common.w"| that must
+be included in both |"ctangle.w"| and |"cweave.w"|. It appears in
+file |"common.h"|, which needs to be updated when |"common.w"| changes.
+
+@i common.h
+
+@* Data structures exclusive to {\tt CWEAVE}.
+As explained in \.{common.w}, the field of a |name_info| structure
+that contains the |rlink| of a section name is used for a completely
+different purpose in the case of identifiers. It is then called the
+|ilk| of the identifier, and it is used to
+distinguish between various types of identifiers, as follows:
+
+\yskip\hang |normal| and |func_template| identifiers are part of the
+\CEE/ program that will appear in italic type (or in typewriter type
+if all uppercase).
+
+\yskip\hang |custom| identifiers are part of the \CEE/ program that
+will be typeset in special ways.
+
+\yskip\hang |roman| identifiers are index entries that appear after
+\.{@@\^} in the \.{CWEB} file.
+
+\yskip\hang |wildcard| identifiers are index entries that appear after
+\.{@@:} in the \.{CWEB} file.
+
+\yskip\hang |typewriter| identifiers are index entries that appear after
+\.{@@.} in the \.{CWEB} file.
+
+\yskip\hang |alfop|, \dots, |template_like|
+identifiers are \CEE/ or \CPLUSPLUS/ reserved words whose |ilk|
+explains how they are to be treated when \CEE/ code is being
+formatted.
+
+@d ilk dummy.Ilk
+@d normal 0 /* ordinary identifiers have |normal| ilk */
+@d roman 1 /* normal index entries have |roman| ilk */
+@d wildcard 2 /* user-formatted index entries have |wildcard| ilk */
+@d typewriter 3 /* `typewriter type' entries have |typewriter| ilk */
+@d abnormal(a) (a->ilk>typewriter) /* tells if a name is special */
+@d func_template 4 /* identifiers that can be followed by optional template */
+@d custom 5 /* identifiers with user-given control sequence */
+@d alfop 22 /* alphabetic operators like \&{and} or \&{not\_eq} */
+@d else_like 26 /* \&{else} */
+@d public_like 40 /* \&{public}, \&{private}, \&{protected} */
+@d operator_like 41 /* \&{operator} */
+@d new_like 42 /* \&{new} */
+@d catch_like 43 /* \&{catch} */
+@d for_like 45 /* \&{for}, \&{switch}, \&{while} */
+@d do_like 46 /* \&{do} */
+@d if_like 47 /* \&{if}, \&{ifdef}, \&{endif}, \&{pragma}, \dots */
+@d delete_like 48 /* \&{delete} */
+@d raw_ubin 49 /* `\.\&' or `\.*' when looking for \&{const} following */
+@d const_like 50 /* \&{const}, \&{volatile} */
+@d raw_int 51 /* \&{int}, \&{char}, \dots; also structure and class names */
+@d int_like 52 /* same, when not followed by left parenthesis or \DC\ */
+@d case_like 53 /* \&{case}, \&{return}, \&{goto}, \&{break}, \&{continue} */
+@d sizeof_like 54 /* \&{sizeof} */
+@d struct_like 55 /* \&{struct}, \&{union}, \&{enum}, \&{class} */
+@d typedef_like 56 /* \&{typedef} */
+@d define_like 57 /* \&{define} */
+@d template_like 58 /* \&{template} */
+
+@ We keep track of the current section number in |section_count|, which
+is the total number of sections that have started. Sections which have
+been altered by a change file entry have their |changed_section| flag
+turned on during the first phase.
+
+@<Global...@>=
+boolean change_exists; /* has any section changed? */
+
+@ The other large memory area in \.{CWEAVE} keeps the cross-reference data.
+All uses of the name |p| are recorded in a linked list beginning at
+|p->xref|, which points into the |xmem| array. The elements of |xmem|
+are structures consisting of an integer, |num|, and a pointer |xlink|
+to another element of |xmem|. If |x=p->xref| is a pointer into |xmem|,
+the value of |x->num| is either a section number where |p| is used,
+or |cite_flag| plus a section number where |p| is mentioned,
+or |def_flag| plus a section number where |p| is defined;
+and |x->xlink| points to the next such cross-reference for |p|,
+if any. This list of cross-references is in decreasing order by
+section number. The next unused slot in |xmem| is |xref_ptr|.
+The linked list ends at |&xmem[0]|.
+
+The global variable |xref_switch| is set either to |def_flag| or to zero,
+depending on whether the next cross-reference to an identifier is to be
+underlined or not in the index. This switch is set to |def_flag| when
+\.{@@!} or \.{@@d} is scanned, and it is cleared to zero when
+the next identifier or index entry cross-reference has been made.
+Similarly, the global variable |section_xref_switch| is either
+|def_flag| or |cite_flag| or zero, depending
+on whether a section name is being defined, cited or used in \CEE/ text.
+
+@<Type...@>=
+typedef struct xref_info {
+ sixteen_bits num; /* section number plus zero or |def_flag| */
+ struct xref_info *xlink; /* pointer to the previous cross-reference */
+} xref_info;
+typedef xref_info *xref_pointer;
+
+@ @<Global...@>=
+xref_info xmem[max_refs]; /* contains cross-reference information */
+xref_pointer xmem_end = xmem+max_refs-1;
+xref_pointer xref_ptr; /* the largest occupied position in |xmem| */
+sixteen_bits xref_switch,section_xref_switch; /* either zero or |def_flag| */
+
+@ A section that is used for multi-file output (with the \.{@@(} feature)
+has a special first cross-reference whose |num| field is |file_flag|.
+
+@d file_flag (3*cite_flag)
+@d def_flag (2*cite_flag)
+@d cite_flag 10240 /* must be strictly larger than |max_sections| */
+@d xref equiv_or_xref
+
+@<Set init...@>=
+xref_ptr=xmem; name_dir->xref=(char*)xmem; xref_switch=0; section_xref_switch=0;
+xmem->num=0; /* sentinel value */
+
+@ A new cross-reference for an identifier is formed by calling |new_xref|,
+which discards duplicate entries and ignores non-underlined references
+to one-letter identifiers or \CEE/'s reserved words.
+
+If the user has sent the |no_xref| flag (the \.{-x} option of the command line),
+it is unnecessary to keep track of cross-references for identifiers.
+If one were careful, one could probably make more changes around section
+100 to avoid a lot of identifier looking up.
+
+@d append_xref(c) if (xref_ptr==xmem_end) overflow("cross-reference");
+ else (++xref_ptr)->num=c;
+@d no_xref (flags['x']==0)
+@d make_xrefs flags['x'] /* should cross references be output? */
+@d is_tiny(p) ((p+1)->byte_start==(p)->byte_start+1)
+@d unindexed(a) (a<res_wd_end && a->ilk>=custom)
+ /* tells if uses of a name are to be indexed */
+
+@c
+void
+new_xref(p)
+name_pointer p;
+{
+ xref_pointer q; /* pointer to previous cross-reference */
+ sixteen_bits m, n; /* new and previous cross-reference value */
+ if (no_xref) return;
+ if ((unindexed(p) || is_tiny(p)) && xref_switch==0) return;
+ m=section_count+xref_switch; xref_switch=0; q=(xref_pointer)p->xref;
+ if (q != xmem) {
+ n=q->num;
+ if (n==m || n==m+def_flag) return;
+ else if (m==n+def_flag) {
+ q->num=m; return;
+ }
+ }
+ append_xref(m); xref_ptr->xlink=q; p->xref=(char*)xref_ptr;
+}
+
+@ The cross-reference lists for section names are slightly different.
+Suppose that a section name is defined in sections $m_1$, \dots,
+$m_k$, cited in sections $n_1$, \dots, $n_l$, and used in sections
+$p_1$, \dots, $p_j$. Then its list will contain $m_1+|def_flag|$,
+\dots, $m_k+|def_flag|$, $n_1+|cite_flag|$, \dots,
+$n_l+|cite_flag|$, $p_1$, \dots, $p_j$, in this order.
+
+Although this method of storage takes quadratic time with respect to
+the length of the list, under foreseeable uses of \.{CWEAVE} this inefficiency
+is insignificant.
+
+@c
+void
+new_section_xref(p)
+name_pointer p;
+{
+ xref_pointer q,r; /* pointers to previous cross-references */
+ q=(xref_pointer)p->xref; r=xmem;
+ if (q>xmem)
+ while (q->num>section_xref_switch) {r=q; q=q->xlink;}
+ if (r->num==section_count+section_xref_switch)
+ return; /* don't duplicate entries */
+ append_xref(section_count+section_xref_switch);
+ xref_ptr->xlink=q; section_xref_switch=0;
+ if (r==xmem) p->xref=(char*)xref_ptr;
+ else r->xlink=xref_ptr;
+}
+
+@ The cross-reference list for a section name may also begin with
+|file_flag|. Here's how that flag gets put~in.
+
+@c
+void
+set_file_flag(p)
+name_pointer p;
+{
+ xref_pointer q;
+ q=(xref_pointer)p->xref;
+ if (q->num==file_flag) return;
+ append_xref(file_flag);
+ xref_ptr->xlink = q;
+ p->xref = (char *)xref_ptr;
+}
+
+@ A third large area of memory is used for sixteen-bit `tokens', which appear
+in short lists similar to the strings of characters in |byte_mem|. Token lists
+are used to contain the result of \CEE/ code translated into \TEX/ form;
+further details about them will be explained later. A |text_pointer| variable
+is an index into |tok_start|.
+
+@<Typed...@>=
+typedef sixteen_bits token;
+typedef token *token_pointer;
+typedef token_pointer *text_pointer;
+
+@ The first position of |tok_mem|
+that is unoccupied by replacement text is called |tok_ptr|, and the first
+unused location of |tok_start| is called |text_ptr|.
+Thus, we usually have |*text_ptr==tok_ptr|.
+
+@<Global...@>=
+token tok_mem[max_toks]; /* tokens */
+token_pointer tok_mem_end = tok_mem+max_toks-1; /* end of |tok_mem| */
+token_pointer tok_start[max_texts]; /* directory into |tok_mem| */
+token_pointer tok_ptr; /* first unused position in |tok_mem| */
+text_pointer text_ptr; /* first unused position in |tok_start| */
+text_pointer tok_start_end = tok_start+max_texts-1; /* end of |tok_start| */
+token_pointer max_tok_ptr; /* largest value of |tok_ptr| */
+text_pointer max_text_ptr; /* largest value of |text_ptr| */
+
+@ @<Set init...@>=
+tok_ptr=tok_mem+1; text_ptr=tok_start+1; tok_start[0]=tok_mem+1;
+tok_start[1]=tok_mem+1;
+max_tok_ptr=tok_mem+1; max_text_ptr=tok_start+1;
+
+@ Here are the three procedures needed to complete |id_lookup|:
+@c
+int names_match(p,first,l,t)
+name_pointer p; /* points to the proposed match */
+char *first; /* position of first character of string */
+int l; /* length of identifier */
+eight_bits t; /* desired ilk */
+{
+ if (length(p)!=l) return 0;
+ if (p->ilk!=t && !(t==normal && abnormal(p))) return 0;
+ return !strncmp(first,p->byte_start,l);
+}
+
+void
+init_p(p,t)
+name_pointer p;
+eight_bits t;
+{
+ p->ilk=t; p->xref=(char*)xmem;
+}
+
+void
+init_node(p)
+name_pointer p;
+{
+ p->xref=(char*)xmem;
+}
+
+@ We have to get \CEE/'s
+reserved words into the hash table, and the simplest way to do this is
+to insert them every time \.{CWEAVE} is run. Fortunately there are relatively
+few reserved words. (Some of these are not strictly ``reserved,'' but
+are defined in header files of the ISO Standard \CEE/ Library.)
+@^reserved words@>
+
+@<Store all the reserved words@>=
+id_lookup("and",NULL,alfop);
+id_lookup("and_eq",NULL,alfop);
+id_lookup("asm",NULL,sizeof_like);
+id_lookup("auto",NULL,int_like);
+id_lookup("bitand",NULL,alfop);
+id_lookup("bitor",NULL,alfop);
+id_lookup("bool",NULL,raw_int);
+id_lookup("break",NULL,case_like);
+id_lookup("case",NULL,case_like);
+id_lookup("catch",NULL,catch_like);
+id_lookup("char",NULL,raw_int);
+id_lookup("class",NULL,struct_like);
+id_lookup("clock_t",NULL,raw_int);
+id_lookup("compl",NULL,alfop);
+id_lookup("const",NULL,const_like);
+id_lookup("const_cast",NULL,raw_int);
+id_lookup("continue",NULL,case_like);
+id_lookup("default",NULL,case_like);
+id_lookup("define",NULL,define_like);
+id_lookup("defined",NULL,sizeof_like);
+id_lookup("delete",NULL,delete_like);
+id_lookup("div_t",NULL,raw_int);
+id_lookup("do",NULL,do_like);
+id_lookup("double",NULL,raw_int);
+id_lookup("dynamic_cast",NULL,raw_int);
+id_lookup("elif",NULL,if_like);
+id_lookup("else",NULL,else_like);
+id_lookup("endif",NULL,if_like);
+id_lookup("enum",NULL,struct_like);
+id_lookup("error",NULL,if_like);
+id_lookup("explicit",NULL,int_like);
+id_lookup("export",NULL,int_like);
+id_lookup("extern",NULL,int_like);
+id_lookup("FILE",NULL,raw_int);
+id_lookup("float",NULL,raw_int);
+id_lookup("for",NULL,for_like);
+id_lookup("fpos_t",NULL,raw_int);
+id_lookup("friend",NULL,int_like);
+id_lookup("goto",NULL,case_like);
+id_lookup("if",NULL,if_like);
+id_lookup("ifdef",NULL,if_like);
+id_lookup("ifndef",NULL,if_like);
+id_lookup("include",NULL,if_like);
+id_lookup("inline",NULL,int_like);
+id_lookup("int",NULL,raw_int);
+id_lookup("jmp_buf",NULL,raw_int);
+id_lookup("ldiv_t",NULL,raw_int);
+id_lookup("line",NULL,if_like);
+id_lookup("long",NULL,raw_int);
+id_lookup("mutable",NULL,int_like);
+id_lookup("namespace",NULL,struct_like);
+id_lookup("new",NULL,new_like);
+id_lookup("not",NULL,alfop);
+id_lookup("not_eq",NULL,alfop);
+id_lookup("NULL",NULL,custom);
+id_lookup("offsetof",NULL,raw_int);
+id_lookup("operator",NULL,operator_like);
+id_lookup("or",NULL,alfop);
+id_lookup("or_eq",NULL,alfop);
+id_lookup("pragma",NULL,if_like);
+id_lookup("private",NULL,public_like);
+id_lookup("protected",NULL,public_like);
+id_lookup("ptrdiff_t",NULL,raw_int);
+id_lookup("public",NULL,public_like);
+id_lookup("register",NULL,int_like);
+id_lookup("reinterpret_cast",NULL,raw_int);
+id_lookup("return",NULL,case_like);
+id_lookup("short",NULL,raw_int);
+id_lookup("sig_atomic_t",NULL,raw_int);
+id_lookup("signed",NULL,raw_int);
+id_lookup("size_t",NULL,raw_int);
+id_lookup("sizeof",NULL,sizeof_like);
+id_lookup("static",NULL,int_like);
+id_lookup("static_cast",NULL,raw_int);
+id_lookup("struct",NULL,struct_like);
+id_lookup("switch",NULL,for_like);
+id_lookup("template",NULL,template_like);
+id_lookup("this",NULL,custom);
+id_lookup("throw",NULL,case_like);
+id_lookup("time_t",NULL,raw_int);
+id_lookup("try",NULL,else_like);
+id_lookup("typedef",NULL,typedef_like);
+id_lookup("typeid",NULL,raw_int);
+id_lookup("typename",NULL,struct_like);
+id_lookup("undef",NULL,if_like);
+id_lookup("union",NULL,struct_like);
+id_lookup("unsigned",NULL,raw_int);
+id_lookup("using",NULL,int_like);
+id_lookup("va_dcl",NULL,decl); /* Berkeley's variable-arg-list convention */
+id_lookup("va_list",NULL,raw_int); /* ditto */
+id_lookup("virtual",NULL,int_like);
+id_lookup("void",NULL,raw_int);
+id_lookup("volatile",NULL,const_like);
+id_lookup("wchar_t",NULL,raw_int);
+id_lookup("while",NULL,for_like);
+id_lookup("xor",NULL,alfop);
+id_lookup("xor_eq",NULL,alfop);
+res_wd_end=name_ptr;
+id_lookup("TeX",NULL,custom);
+id_lookup("make_pair",NULL,func_template);
+
+@* Lexical scanning.
+Let us now consider the subroutines that read the \.{CWEB} source file
+and break it into meaningful units. There are four such procedures:
+One simply skips to the next `\.{@@\ }' or `\.{@@*}' that begins a
+section; another passes over the \TEX/ text at the beginning of a
+section; the third passes over the \TEX/ text in a \CEE/ comment;
+and the last, which is the most interesting, gets the next token of
+a \CEE/ text. They all use the pointers |limit| and |loc| into
+the line of input currently being studied.
+
+@ Control codes in \.{CWEB}, which begin with `\.{@@}', are converted
+into a numeric code designed to simplify \.{CWEAVE}'s logic; for example,
+larger numbers are given to the control codes that denote more significant
+milestones, and the code of |new_section| should be the largest of
+all. Some of these numeric control codes take the place of |char|
+control codes that will not otherwise appear in the output of the
+scanning routines.
+@^ASCII code dependencies@>
+
+@d ignore 00 /* control code of no interest to \.{CWEAVE} */
+@d verbatim 02 /* takes the place of extended ASCII \.{\char2} */
+@d begin_short_comment 03 /* \CPLUSPLUS/ short comment */
+@d begin_comment '\t' /* tab marks will not appear */
+@d underline '\n' /* this code will be intercepted without confusion */
+@d noop 0177 /* takes the place of ASCII delete */
+@d xref_roman 0203 /* control code for `\.{@@\^}' */
+@d xref_wildcard 0204 /* control code for `\.{@@:}' */
+@d xref_typewriter 0205 /* control code for `\.{@@.}' */
+@d TeX_string 0206 /* control code for `\.{@@t}' */
+@f TeX_string TeX
+@d ord 0207 /* control code for `\.{@@'}' */
+@d join 0210 /* control code for `\.{@@\&}' */
+@d thin_space 0211 /* control code for `\.{@@,}' */
+@d math_break 0212 /* control code for `\.{@@\v}' */
+@d line_break 0213 /* control code for `\.{@@/}' */
+@d big_line_break 0214 /* control code for `\.{@@\#}' */
+@d no_line_break 0215 /* control code for `\.{@@+}' */
+@d pseudo_semi 0216 /* control code for `\.{@@;}' */
+@d macro_arg_open 0220 /* control code for `\.{@@[}' */
+@d macro_arg_close 0221 /* control code for `\.{@@]}' */
+@d trace 0222 /* control code for `\.{@@0}', `\.{@@1}' and `\.{@@2}' */
+@d translit_code 0223 /* control code for `\.{@@l}' */
+@d output_defs_code 0224 /* control code for `\.{@@h}' */
+@d format_code 0225 /* control code for `\.{@@f}' and `\.{@@s}' */
+@d definition 0226 /* control code for `\.{@@d}' */
+@d begin_C 0227 /* control code for `\.{@@c}' */
+@d section_name 0230 /* control code for `\.{@@<}' */
+@d new_section 0231 /* control code for `\.{@@\ }' and `\.{@@*}' */
+
+@ Control codes are converted to \.{CWEAVE}'s internal
+representation by means of the table |ccode|.
+
+@<Global...@>=
+eight_bits ccode[256]; /* meaning of a char following \.{@@} */
+
+@ @<Set ini...@>=
+{int c; for (c=0; c<256; c++) ccode[c]=0;}
+ccode[' ']=ccode['\t']=ccode['\n']=ccode['\v']=ccode['\r']=ccode['\f']
+ =ccode['*']=new_section;
+ccode['@@']='@@'; /* `quoted' at sign */
+ccode['=']=verbatim;
+ccode['d']=ccode['D']=definition;
+ccode['f']=ccode['F']=ccode['s']=ccode['S']=format_code;
+ccode['c']=ccode['C']=ccode['p']=ccode['P']=begin_C;
+ccode['t']=ccode['T']=TeX_string;
+ccode['l']=ccode['L']=translit_code;
+ccode['q']=ccode['Q']=noop;
+ccode['h']=ccode['H']=output_defs_code;
+ccode['&']=join; ccode['<']=ccode['(']=section_name;
+ccode['!']=underline; ccode['^']=xref_roman;
+ccode[':']=xref_wildcard; ccode['.']=xref_typewriter; ccode[',']=thin_space;
+ccode['|']=math_break; ccode['/']=line_break; ccode['#']=big_line_break;
+ccode['+']=no_line_break; ccode[';']=pseudo_semi;
+ccode['[']=macro_arg_open; ccode[']']=macro_arg_close;
+ccode['\'']=ord;
+@<Special control codes for debugging@>@;
+
+@ Users can write
+\.{@@2}, \.{@@1}, and \.{@@0} to turn tracing fully on, partly on,
+and off, respectively.
+
+@<Special control codes...@>=
+ccode['0']=ccode['1']=ccode['2']=trace;
+
+@ The |skip_limbo| routine is used on the first pass to skip through
+portions of the input that are not in any sections, i.e., that precede
+the first section. After this procedure has been called, the value of
+|input_has_ended| will tell whether or not a section has actually been found.
+
+There's a complication that we will postpone until later: If the \.{@@s}
+operation appears in limbo, we want to use it to adjust the default
+interpretation of identifiers.
+
+@<Predec...@>=
+void skip_limbo();
+
+@ @c
+void
+skip_limbo() {
+ while(1) {
+ if (loc>limit && get_line()==0) return;
+ *(limit+1)='@@';
+ while (*loc!='@@') loc++; /* look for '@@', then skip two chars */
+ if (loc++ <=limit) { int c=ccode[(eight_bits)*loc++];
+ if (c==new_section) return;
+ if (c==noop) skip_restricted();
+ else if (c==format_code) @<Process simple format in limbo@>;
+ }
+ }
+}
+
+@ The |skip_TeX| routine is used on the first pass to skip through
+the \TEX/ code at the beginning of a section. It returns the next
+control code or `\.{\v}' found in the input. A |new_section| is
+assumed to exist at the very end of the file.
+
+@f skip_TeX TeX
+
+@c
+unsigned
+skip_TeX() /* skip past pure \TEX/ code */
+{
+ while (1) {
+ if (loc>limit && get_line()==0) return(new_section);
+ *(limit+1)='@@';
+ while (*loc!='@@' && *loc!='|') loc++;
+ if (*loc++ =='|') return('|');
+ if (loc<=limit) return(ccode[(eight_bits)*(loc++)]);
+ }
+}
+
+@*1 Inputting the next token.
+As stated above, \.{CWEAVE}'s most interesting lexical scanning routine is the
+|get_next| function that inputs the next token of \CEE/ input. However,
+|get_next| is not especially complicated.
+
+The result of |get_next| is either a |char| code for some special character,
+or it is a special code representing a pair of characters (e.g., `\.{!=}'),
+or it is the numeric value computed by the |ccode|
+table, or it is one of the following special codes:
+
+\yskip\hang |identifier|: In this case the global variables |id_first| and
+|id_loc| will have been set to the beginning and ending-plus-one locations
+in the buffer, as required by the |id_lookup| routine.
+
+\yskip\hang |string|: The string will have been copied into the array
+|section_text|; |id_first| and |id_loc| are set as above (now they are
+pointers into |section_text|).
+
+\yskip\hang |constant|: The constant is copied into |section_text|, with
+slight modifications; |id_first| and |id_loc| are set.
+
+\yskip\noindent Furthermore, some of the control codes cause
+|get_next| to take additional actions:
+
+\yskip\hang |xref_roman|, |xref_wildcard|, |xref_typewriter|, |TeX_string|,
+|verbatim|: The values of |id_first| and |id_loc| will have been set to
+the beginning and ending-plus-one locations in the buffer.
+
+\yskip\hang |section_name|: In this case the global variable |cur_section| will
+point to the |byte_start| entry for the section name that has just been scanned.
+The value of |cur_section_char| will be |'('| if the section name was
+preceded by \.{@@(} instead of \.{@@<}.
+
+\yskip\noindent If |get_next| sees `\.{@@!}'
+it sets |xref_switch| to |def_flag| and goes on to the next token.
+
+@d constant 0200 /* \CEE/ constant */
+@d string 0201 /* \CEE/ string */
+@d identifier 0202 /* \CEE/ identifier or reserved word */
+
+@<Global...@>=
+name_pointer cur_section; /* name of section just scanned */
+char cur_section_char; /* the character just before that name */
+
+@ @<Include...@>=
+#include <ctype.h> /* definition of |isalpha|, |isdigit| and so on */
+#include <stdlib.h> /* definition of |exit| */
+
+@ As one might expect, |get_next| consists mostly of a big switch
+that branches to the various special cases that can arise.
+\CEE/ allows underscores to appear in identifiers, and some \CEE/
+compilers even allow the dollar sign.
+
+@d isxalpha(c) ((c)=='_' || (c)=='$')
+ /* non-alpha characters allowed in identifier */
+@d ishigh(c) ((eight_bits)(c)>0177)
+@^high-bit character handling@>
+
+@<Predecl...@>=
+eight_bits get_next();
+
+@ @c
+eight_bits
+get_next() /* produces the next input token */
+{@+eight_bits c; /* the current character */
+ while (1) {
+ @<Check if we're at the end of a preprocessor command@>;
+ if (loc>limit && get_line()==0) return(new_section);
+ c=*(loc++);
+ if (xisdigit(c) || c=='.') @<Get a constant@>@;
+ else if (c=='\'' || c=='"' || (c=='L'&&(*loc=='\'' || *loc=='"'))@|
+ || (c=='<' && sharp_include_line==1))
+ @<Get a string@>@;
+ else if (xisalpha(c) || isxalpha(c) || ishigh(c))
+ @<Get an identifier@>@;
+ else if (c=='@@') @<Get control code and possible section name@>@;
+ else if (xisspace(c)) continue; /* ignore spaces and tabs */
+ if (c=='#' && loc==buffer+1) @<Raise preprocessor flag@>;
+ mistake: @<Compress two-symbol operator@>@;
+ return(c);
+ }
+}
+
+@ Because preprocessor commands do not fit in with the rest of the syntax
+of \CEE/,
+we have to deal with them separately. One solution is to enclose such
+commands between special markers. Thus, when a \.\# is seen as the
+first character of a line, |get_next| returns a special code
+|left_preproc| and raises a flag |preprocessing|.
+
+We can use the same internal code number for |left_preproc| as we do
+for |ord|, since |get_next| changes |ord| into a string.
+
+@d left_preproc ord /* begins a preprocessor command */
+@d right_preproc 0217 /* ends a preprocessor command */
+
+@<Glob...@>=
+boolean preprocessing=0; /* are we scanning a preprocessor command? */
+
+@ @<Raise prep...@>= {
+ preprocessing=1;
+ @<Check if next token is |include|@>;
+ return (left_preproc);
+}
+
+@ An additional complication is the freakish use of \.< and \.> to delimit
+a file name in lines that start with \.{\#include}. We must treat this file
+name as a string.
+
+@<Glob...@>=
+boolean sharp_include_line=0; /* are we scanning a |#include| line? */
+
+@ @<Check if next token is |include|@>=
+while (loc<=buffer_end-7 && xisspace(*loc)) loc++;
+if (loc<=buffer_end-6 && strncmp(loc,"include",7)==0) sharp_include_line=1;
+
+@ When we get to the end of a preprocessor line,
+we lower the flag and send a code |right_preproc|, unless
+the last character was a \.\\.
+
+@<Check if we're at...@>=
+ while (loc==limit-1 && preprocessing && *loc=='\\')
+ if (get_line()==0) return(new_section); /* still in preprocessor mode */
+ if (loc>=limit && preprocessing) {
+ preprocessing=sharp_include_line=0;
+ return(right_preproc);
+ }
+
+@ The following code assigns values to the combinations \.{++},
+\.{--}, \.{->}, \.{>=}, \.{<=}, \.{==}, \.{<<}, \.{>>}, \.{!=}, \.{\v\v}, and
+\.{\&\&}, and to the \CPLUSPLUS/
+combinations \.{...}, \.{::}, \.{.*} and \.{->*}.
+The compound assignment operators (e.g., \.{+=}) are
+treated as separate tokens.
+
+@d compress(c) if (loc++<=limit) return(c)
+
+@<Compress tw...@>=
+switch(c) {
+ case '/': if (*loc=='*') {compress(begin_comment);}
+ else if (*loc=='/') compress(begin_short_comment); break;
+ case '+': if (*loc=='+') compress(plus_plus); break;
+ case '-': if (*loc=='-') {compress(minus_minus);}
+ else if (*loc=='>') if (*(loc+1)=='*') {loc++; compress(minus_gt_ast);}
+ else compress(minus_gt); break;
+ case '.': if (*loc=='*') {compress(period_ast);}
+ else if (*loc=='.' && *(loc+1)=='.') {
+ loc++; compress(dot_dot_dot);
+ }
+ break;
+ case ':': if (*loc==':') compress(colon_colon); break;
+ case '=': if (*loc=='=') compress(eq_eq); break;
+ case '>': if (*loc=='=') {compress(gt_eq);}
+ else if (*loc=='>') compress(gt_gt); break;
+ case '<': if (*loc=='=') {compress(lt_eq);}
+ else if (*loc=='<') compress(lt_lt); break;
+ case '&': if (*loc=='&') compress(and_and); break;
+ case '|': if (*loc=='|') compress(or_or); break;
+ case '!': if (*loc=='=') compress(not_eq); break;
+}
+
+@ @<Get an identifier@>= {
+ id_first=--loc;
+ while (isalpha(*++loc) || isdigit(*loc) || isxalpha(*loc) || ishigh(*loc));
+ id_loc=loc; return(identifier);
+}
+
+@ Different conventions are followed by \TEX/ and \CEE/ to express octal
+and hexadecimal numbers; it is reasonable to stick to each convention
+within its realm. Thus the \CEE/ part of a \.{CWEB} file has octals
+introduced by \.0 and hexadecimals by \.{0x}, but \.{CWEAVE} will print
+with \TEX/ macros that the user can redefine to fit the context.
+In order to simplify such macros, we replace some of the characters.
+
+Notice that in this section and the next, |id_first| and |id_loc|
+are pointers into the array |section_text|, not into |buffer|.
+
+@<Get a constant@>= {
+ id_first=id_loc=section_text+1;
+ if (*(loc-1)=='0') {
+ if (*loc=='x' || *loc=='X') {*id_loc++='^'; loc++;
+ while (xisxdigit(*loc)) *id_loc++=*loc++;} /* hex constant */
+ else if (xisdigit(*loc)) {*id_loc++='~';
+ while (xisdigit(*loc)) *id_loc++=*loc++;} /* octal constant */
+ else goto dec; /* decimal constant */
+ }
+ else { /* decimal constant */
+ if (*(loc-1)=='.' && !xisdigit(*loc)) goto mistake; /* not a constant */
+ dec: *id_loc++=*(loc-1);
+ while (xisdigit(*loc) || *loc=='.') *id_loc++=*loc++;
+ if (*loc=='e' || *loc=='E') { /* float constant */
+ *id_loc++='_'; loc++;
+ if (*loc=='+' || *loc=='-') *id_loc++=*loc++;
+ while (xisdigit(*loc)) *id_loc++=*loc++;
+ }
+ }
+ while (*loc=='u' || *loc=='U' || *loc=='l' || *loc=='L'
+ || *loc=='f' || *loc=='F') {
+ *id_loc++='$'; *id_loc++=toupper(*loc); loc++;
+ }
+ return(constant);
+}
+
+@ \CEE/ strings and character constants, delimited by double and single
+quotes, respectively, can contain newlines or instances of their own
+delimiters if they are protected by a backslash. We follow this
+convention, but do not allow the string to be longer than |longest_name|.
+
+@<Get a string@>= {
+ char delim = c; /* what started the string */
+ id_first = section_text+1;
+ id_loc = section_text;
+ if (delim=='\'' && *(loc-2)=='@@') {*++id_loc='@@'; *++id_loc='@@';}
+ *++id_loc=delim;
+ if (delim=='L') { /* wide character constant */
+ delim=*loc++; *++id_loc=delim;
+ }
+ if (delim=='<') delim='>'; /* for file names in |#include| lines */
+ while (1) {
+ if (loc>=limit) {
+ if(*(limit-1)!='\\') {
+ err_print("! String didn't end"); loc=limit; break;
+@.String didn't end@>
+ }
+ if(get_line()==0) {
+ err_print("! Input ended in middle of string"); loc=buffer; break;
+@.Input ended in middle of string@>
+ }
+ }
+ if ((c=*loc++)==delim) {
+ if (++id_loc<=section_text_end) *id_loc=c;
+ break;
+ }
+ if (c=='\\') if (loc>=limit) continue;
+ else if (++id_loc<=section_text_end) {
+ *id_loc = '\\'; c=*loc++;
+ }
+ if (++id_loc<=section_text_end) *id_loc=c;
+ }
+ if (id_loc>=section_text_end) {
+ printf("\n! String too long: ");
+@.String too long@>
+ term_write(section_text+1,25);
+ printf("..."); mark_error;
+ }
+ id_loc++;
+ return(string);
+}
+
+@ After an \.{@@} sign has been scanned, the next character tells us
+whether there is more work to do.
+
+@<Get control code and possible section name@>= {
+ c=*loc++;
+ switch(ccode[(eight_bits)c]) {
+ case translit_code: err_print("! Use @@l in limbo only"); continue;
+@.Use @@l in limbo...@>
+ case underline: xref_switch=def_flag; continue;
+ case trace: tracing=c-'0'; continue;
+ case xref_roman: case xref_wildcard: case xref_typewriter:
+ case noop: case TeX_string: c=ccode[c]; skip_restricted(); return(c);
+ case section_name:
+ @<Scan the section name and make |cur_section| point to it@>;
+ case verbatim: @<Scan a verbatim string@>;
+ case ord: @<Get a string@>;
+ default: return(ccode[(eight_bits)c]);
+ }
+}
+
+@ The occurrence of a section name sets |xref_switch| to zero,
+because the section name might (for example) follow \&{int}.
+
+@<Scan the section name...@>= {
+ char *k; /* pointer into |section_text| */
+ cur_section_char=*(loc-1);
+ @<Put section name into |section_text|@>;
+ if (k-section_text>3 && strncmp(k-2,"...",3)==0)
+ cur_section=section_lookup(section_text+1,k-3,1); /* 1 indicates a prefix */
+ else cur_section=section_lookup(section_text+1,k,0);
+ xref_switch=0; return(section_name);
+}
+
+@ Section names are placed into the |section_text| array with consecutive spaces,
+tabs, and carriage-returns replaced by single spaces. There will be no
+spaces at the beginning or the end. (We set |section_text[0]=' '| to facilitate
+this, since the |section_lookup| routine uses |section_text[1]| as the first
+character of the name.)
+
+@<Set init...@>=section_text[0]=' ';
+
+@ @<Put section name...@>=
+k=section_text;
+while (1) {
+ if (loc>limit && get_line()==0) {
+ err_print("! Input ended in section name");
+@.Input ended in section name@>
+ loc=buffer+1; break;
+ }
+ c=*loc;
+ @<If end of name or erroneous control code, |break|@>;
+ loc++; if (k<section_text_end) k++;
+ if (xisspace(c)) {
+ c=' '; if (*(k-1)==' ') k--;
+ }
+*k=c;
+}
+if (k>=section_text_end) {
+ printf("\n! Section name too long: ");
+@.Section name too long@>
+ term_write(section_text+1,25);
+ printf("..."); mark_harmless;
+}
+if (*k==' ' && k>section_text) k--;
+
+@ @<If end of name...@>=
+if (c=='@@') {
+ c=*(loc+1);
+ if (c=='>') {
+ loc+=2; break;
+ }
+ if (ccode[(eight_bits)c]==new_section) {
+ err_print("! Section name didn't end"); break;
+@.Section name didn't end@>
+ }
+ if (c!='@@') {
+ err_print("! Control codes are forbidden in section name"); break;
+@.Control codes are forbidden...@>
+ }
+ *(++k)='@@'; loc++; /* now |c==*loc| again */
+}
+
+@ This function skips over a restricted context at relatively high speed.
+
+@<Predecl...@>=
+void skip_restricted();
+
+@ @c
+void
+skip_restricted()
+{
+ id_first=loc; *(limit+1)='@@';
+false_alarm:
+ while (*loc!='@@') loc++;
+ id_loc=loc;
+ if (loc++>limit) {
+ err_print("! Control text didn't end"); loc=limit;
+@.Control text didn't end@>
+ }
+ else {
+ if (*loc=='@@'&&loc<=limit) {loc++; goto false_alarm;}
+ if (*loc++!='>')
+ err_print("! Control codes are forbidden in control text");
+@.Control codes are forbidden...@>
+ }
+}
+
+@ At the present point in the program we
+have |*(loc-1)==verbatim|; we set |id_first| to the beginning
+of the string itself, and |id_loc| to its ending-plus-one location in the
+buffer. We also set |loc| to the position just after the ending delimiter.
+
+@<Scan a verbatim string@>= {
+ id_first=loc++; *(limit+1)='@@'; *(limit+2)='>';
+ while (*loc!='@@' || *(loc+1)!='>') loc++;
+ if (loc>=limit) err_print("! Verbatim string didn't end");
+@.Verbatim string didn't end@>
+ id_loc=loc; loc+=2;
+ return (verbatim);
+}
+
+@** Phase one processing.
+We now have accumulated enough subroutines to make it possible to carry out
+\.{CWEAVE}'s first pass over the source file. If everything works right,
+both phase one and phase two of \.{CWEAVE} will assign the same numbers to
+sections, and these numbers will agree with what \.{CTANGLE} does.
+
+The global variable |next_control| often contains the most recent output of
+|get_next|; in interesting cases, this will be the control code that
+ended a section or part of a section.
+
+@<Global...@>=
+eight_bits next_control; /* control code waiting to be acting upon */
+
+@ The overall processing strategy in phase one has the following
+straightforward outline.
+
+@<Predecl...@>=
+void phase_one();
+
+@ @c
+void
+phase_one() {
+ phase=1; reset_input(); section_count=0;
+ skip_limbo(); change_exists=0;
+ while (!input_has_ended)
+ @<Store cross-reference data for the current section@>;
+ changed_section[section_count]=change_exists;
+ /* the index changes if anything does */
+ phase=2; /* prepare for second phase */
+ @<Print error messages about unused or undefined section names@>;
+}
+
+@ @<Store cross-reference data...@>=
+{
+ if (++section_count==max_sections) overflow("section number");
+ changed_section[section_count]=changing;
+ /* it will become 1 if any line changes */
+ if (*(loc-1)=='*' && show_progress) {
+ printf("*%d",section_count);
+ update_terminal; /* print a progress report */
+ }
+ @<Store cross-references in the \TEX/ part of a section@>;
+ @<Store cross-references in the definition part of a section@>;
+ @<Store cross-references in the \CEE/ part of a section@>;
+ if (changed_section[section_count]) change_exists=1;
+}
+
+@ The |C_xref| subroutine stores references to identifiers in
+\CEE/ text material beginning with the current value of |next_control|
+and continuing until |next_control| is `\.\{' or `\.{\v}', or until the next
+``milestone'' is passed (i.e., |next_control>=format_code|). If
+|next_control>=format_code| when |C_xref| is called, nothing will happen;
+but if |next_control=='|'| upon entry, the procedure assumes that this is
+the `\.{\v}' preceding \CEE/ text that is to be processed.
+
+The parameter |spec_ctrl| is used to change this behavior. In most cases
+|C_xref| is called with |spec_ctrl==ignore|, which triggers the default
+processing described above. If |spec_ctrl==section_name|, section names will
+be gobbled. This is used when \CEE/ text in the \TEX/ part or inside comments
+is parsed: It allows for section names to appear in \pb, but these
+strings will not be entered into the cross reference lists since they are not
+definitions of section names.
+
+The program uses the fact that our internal code numbers satisfy
+the relations |xref_roman==identifier+roman| and |xref_wildcard==identifier
++wildcard| and |xref_typewriter==identifier+typewriter|,
+as well as |normal==0|.
+
+@<Predecl...@>=
+void C_xref();
+
+@ @c
+void
+C_xref( spec_ctrl ) /* makes cross-references for \CEE/ identifiers */
+ eight_bits spec_ctrl;
+{
+ name_pointer p; /* a referenced name */
+ while (next_control<format_code || next_control==spec_ctrl) {
+ if (next_control>=identifier && next_control<=xref_typewriter) {
+ if (next_control>identifier) @<Replace |"@@@@"| by |"@@"| @>@;
+ p=id_lookup(id_first, id_loc,next_control-identifier); new_xref(p);
+ }
+ if (next_control==section_name) {
+ section_xref_switch=cite_flag;
+ new_section_xref(cur_section);
+ }
+ next_control=get_next();
+ if (next_control=='|' || next_control==begin_comment ||
+ next_control==begin_short_comment) return;
+ }
+}
+
+@ The |outer_xref| subroutine is like |C_xref| except that it begins
+with |next_control!='|'| and ends with |next_control>=format_code|. Thus, it
+handles \CEE/ text with embedded comments.
+
+@<Predecl...@>=
+void outer_xref();
+
+@ @c
+void
+outer_xref() /* extension of |C_xref| */
+{
+ int bal; /* brace level in comment */
+ while (next_control<format_code)
+ if (next_control!=begin_comment && next_control!=begin_short_comment)
+ C_xref(ignore);
+ else {
+ boolean is_long_comment=(next_control==begin_comment);
+ bal=copy_comment(is_long_comment,1); next_control='|';
+ while (bal>0) {
+ C_xref(section_name); /* do not reference section names in comments */
+ if (next_control=='|') bal=copy_comment(is_long_comment,bal);
+ else bal=0; /* an error message will occur in phase two */
+ }
+ }
+}
+
+@ In the \TEX/ part of a section, cross-reference entries are made only for
+the identifiers in \CEE/ texts enclosed in \pb, or for control texts
+enclosed in \.{@@\^}$\,\ldots\,$\.{@@>} or \.{@@.}$\,\ldots\,$\.{@@>}
+or \.{@@:}$\,\ldots\,$\.{@@>}.
+
+@<Store cross-references in the \T...@>=
+while (1) {
+ switch (next_control=skip_TeX()) {
+ case translit_code: err_print("! Use @@l in limbo only"); continue;
+@.Use @@l in limbo...@>
+ case underline: xref_switch=def_flag; continue;
+ case trace: tracing=*(loc-1)-'0'; continue;
+ case '|': C_xref(section_name); break;
+ case xref_roman: case xref_wildcard: case xref_typewriter:
+ case noop: case section_name:
+ loc-=2; next_control=get_next(); /* scan to \.{@@>} */
+ if (next_control>=xref_roman && next_control<=xref_typewriter) {
+ @<Replace |"@@@@"| by |"@@"| @>@;
+ new_xref(id_lookup(id_first, id_loc,next_control-identifier));
+ }
+ break;
+ }
+ if (next_control>=format_code) break;
+}
+
+@ @<Replace |"@@@@"| by |"@@"| @>=
+{
+ char *src=id_first,*dst=id_first;
+ while(src<id_loc){
+ if(*src=='@@') src++;
+ *dst++=*src++;
+ }
+ id_loc=dst;
+ while (dst<src) *dst++=' '; /* clean up in case of error message display */
+}
+
+@ During the definition and \CEE/ parts of a section, cross-references
+are made for all identifiers except reserved words. However, the right
+identifier in a format definition is not referenced, and the left
+identifier is referenced only if it has been explicitly
+underlined (preceded by \.{@@!}).
+The \TEX/ code in comments is, of course, ignored, except for
+\CEE/ portions enclosed in \pb; the text of a section name is skipped
+entirely, even if it contains \pb\ constructions.
+
+The variables |lhs| and |rhs| point to the respective identifiers involved
+in a format definition.
+
+@<Global...@>=
+name_pointer lhs, rhs; /* pointers to |byte_start| for format identifiers */
+name_pointer res_wd_end; /* pointer to the first nonreserved identifier */
+
+@ When we get to the following code we have |next_control>=format_code|.
+
+@<Store cross-references in the d...@>=
+while (next_control<=definition) { /* |format_code| or |definition| */
+ if (next_control==definition) {
+ xref_switch=def_flag; /* implied \.{@@!} */
+ next_control=get_next();
+ } else @<Process a format definition@>;
+ outer_xref();
+}
+
+@ Error messages for improper format definitions will be issued in phase
+two. Our job in phase one is to define the |ilk| of a properly formatted
+identifier, and to remove cross-references to identifiers that we now
+discover should be unindexed.
+
+@<Process a form...@>= {
+ next_control=get_next();
+ if (next_control==identifier) {
+ lhs=id_lookup(id_first, id_loc,normal); lhs->ilk=normal;
+ if (xref_switch) new_xref(lhs);
+ next_control=get_next();
+ if (next_control==identifier) {
+ rhs=id_lookup(id_first, id_loc,normal);
+ lhs->ilk=rhs->ilk;
+ if (unindexed(lhs)) { /* retain only underlined entries */
+ xref_pointer q,r=NULL;
+ for (q=(xref_pointer)lhs->xref;q>xmem;q=q->xlink)
+ if (q->num<def_flag)
+ if (r) r->xlink=q->xlink;
+ else lhs->xref=(char*)q->xlink;
+ else r=q;
+ }
+ next_control=get_next();
+ }
+ }
+}
+
+@ A much simpler processing of format definitions occurs when the
+definition is found in limbo.
+
+@<Process simple format in limbo@>=
+{
+ if (get_next()!=identifier)
+ err_print("! Missing left identifier of @@s");
+@.Missing left identifier...@>
+ else {
+ lhs=id_lookup(id_first,id_loc,normal);
+ if (get_next()!=identifier)
+ err_print("! Missing right identifier of @@s");
+@.Missing right identifier...@>
+ else {
+ rhs=id_lookup(id_first,id_loc,normal);
+ lhs->ilk=rhs->ilk;
+ }
+ }
+}
+
+@ Finally, when the \TEX/ and definition parts have been treated, we have
+|next_control>=begin_C|.
+
+@<Store cross-references in the \CEE/...@>=
+if (next_control<=section_name) { /* |begin_C| or |section_name| */
+ if (next_control==begin_C) section_xref_switch=0;
+ else {
+ section_xref_switch=def_flag;
+ if(cur_section_char=='(' && cur_section!=name_dir)
+ set_file_flag(cur_section);
+ }
+ do {
+ if (next_control==section_name && cur_section!=name_dir)
+ new_section_xref(cur_section);
+ next_control=get_next(); outer_xref();
+ } while ( next_control<=section_name);
+}
+
+@ After phase one has looked at everything, we want to check that each
+section name was both defined and used. The variable |cur_xref| will point
+to cross-references for the current section name of interest.
+
+@<Global...@>=
+xref_pointer cur_xref; /* temporary cross-reference pointer */
+boolean an_output; /* did |file_flag| precede |cur_xref|? */
+
+@ The following recursive procedure
+walks through the tree of section names and prints out anomalies.
+@^recursion@>
+
+@<Predecl...@>=
+void section_check();
+
+@ @c
+void
+section_check(p)
+name_pointer p; /* print anomalies in subtree |p| */
+{
+ if (p) {
+ section_check(p->llink);
+ cur_xref=(xref_pointer)p->xref;
+ if (cur_xref->num==file_flag) {an_output=1; cur_xref=cur_xref->xlink;}
+ else an_output=0;
+ if (cur_xref->num <def_flag) {
+ printf("\n! Never defined: <"); print_section_name(p); putchar('>'); mark_harmless;
+@.Never defined: <section name>@>
+ }
+ while (cur_xref->num >=cite_flag) cur_xref=cur_xref->xlink;
+ if (cur_xref==xmem && !an_output) {
+ printf("\n! Never used: <"); print_section_name(p); putchar('>'); mark_harmless;
+@.Never used: <section name>@>
+ }
+ section_check(p->rlink);
+ }
+}
+
+@ @<Print error messages about un...@>=section_check(root)
+
+@* Low-level output routines.
+The \TEX/ output is supposed to appear in lines at most |line_length|
+characters long, so we place it into an output buffer. During the output
+process, |out_line| will hold the current line number of the line about to
+be output.
+
+@<Global...@>=
+char out_buf[line_length+1]; /* assembled characters */
+char *out_ptr; /* last character in |out_buf| */
+char *out_buf_end = out_buf+line_length; /* end of |out_buf| */
+int out_line; /* number of next line to be output */
+
+@ The |flush_buffer| routine empties the buffer up to a given breakpoint,
+and moves any remaining characters to the beginning of the next line.
+If the |per_cent| parameter is 1 a |'%'| is appended to the line
+that is being output; in this case the breakpoint |b| should be strictly
+less than |out_buf_end|. If the |per_cent| parameter is |0|,
+trailing blanks are suppressed.
+The characters emptied from the buffer form a new line of output;
+if the |carryover| parameter is true, a |"%"| in that line will be
+carried over to the next line (so that \TEX/ will ignore the completion
+of commented-out text).
+
+@d c_line_write(c) fflush(active_file),fwrite(out_buf+1,sizeof(char),c,active_file)
+@d tex_putc(c) putc(c,active_file)
+@d tex_new_line putc('\n',active_file)
+@d tex_printf(c) fprintf(active_file,c)
+
+@c
+void
+flush_buffer(b,per_cent,carryover)
+char *b; /* outputs from |out_buf+1| to |b|,where |b<=out_ptr| */
+boolean per_cent,carryover;
+{
+ char *j; j=b; /* pointer into |out_buf| */
+ if (! per_cent) /* remove trailing blanks */
+ while (j>out_buf && *j==' ') j--;
+ c_line_write(j-out_buf);
+ if (per_cent) tex_putc('%');
+ tex_new_line; out_line++;
+ if (carryover)
+ while (j>out_buf)
+ if (*j--=='%' && (j==out_buf || *j!='\\')) {
+ *b--='%'; break;
+ }
+ if (b<out_ptr) strncpy(out_buf+1,b+1,out_ptr-b);
+ out_ptr-=b-out_buf;
+}
+
+@ When we are copying \TEX/ source material, we retain line breaks
+that occur in the input, except that an empty line is not
+output when the \TEX/ source line was nonempty. For example, a line
+of the \TEX/ file that contains only an index cross-reference entry
+will not be copied. The |finish_line| routine is called just before
+|get_line| inputs a new line, and just after a line break token has
+been emitted during the output of translated \CEE/ text.
+
+@c
+void
+finish_line() /* do this at the end of a line */
+{
+ char *k; /* pointer into |buffer| */
+ if (out_ptr>out_buf) flush_buffer(out_ptr,0,0);
+ else {
+ for (k=buffer; k<=limit; k++)
+ if (!(xisspace(*k))) return;
+ flush_buffer(out_buf,0,0);
+ }
+}
+
+@ In particular, the |finish_line| procedure is called near the very
+beginning of phase two. We initialize the output variables in a slightly
+tricky way so that the first line of the output file will be
+`\.{\\input cwebmac}'.
+
+@<Set init...@>=
+out_ptr=out_buf+1; out_line=1; active_file=tex_file;
+*out_ptr='c'; tex_printf("\\input cwebma");
+
+@ When we wish to append one character |c| to the output buffer, we write
+`|out(c)|'; this will cause the buffer to be emptied if it was already
+full. If we want to append more than one character at once, we say
+|out_str(s)|, where |s| is a string containing the characters.
+
+A line break will occur at a space or after a single-nonletter
+\TEX/ control sequence.
+
+@d out(c) {if (out_ptr>=out_buf_end) break_out(); *(++out_ptr)=c;}
+
+@c
+void
+out_str(s) /* output characters from |s| to end of string */
+char *s;
+{
+ while (*s) out(*s++);
+}
+
+@ The |break_out| routine is called just before the output buffer is about
+to overflow. To make this routine a little faster, we initialize position
+0 of the output buffer to `\.\\'; this character isn't really output.
+
+@<Set init...@>=
+out_buf[0]='\\';
+
+@ A long line is broken at a blank space or just before a backslash that isn't
+preceded by another backslash. In the latter case, a |'%'| is output at
+the break.
+
+@<Predecl...@>=
+void break_out();
+
+@ @c
+void
+break_out() /* finds a way to break the output line */
+{
+ char *k=out_ptr; /* pointer into |out_buf| */
+ while (1) {
+ if (k==out_buf) @<Print warning message, break the line, |return|@>;
+ if (*k==' ') {
+ flush_buffer(k,0,1); return;
+ }
+ if (*(k--)=='\\' && *k!='\\') { /* we've decreased |k| */
+ flush_buffer(k,1,1); return;
+ }
+ }
+}
+
+@ We get to this section only in the unusual case that the entire output line
+consists of a string of backslashes followed by a string of nonblank
+non-backslashes. In such cases it is almost always safe to break the
+line by putting a |'%'| just before the last character.
+
+@<Print warning message...@>=
+{
+ printf("\n! Line had to be broken (output l. %d):\n",out_line);
+@.Line had to be broken@>
+ term_write(out_buf+1, out_ptr-out_buf-1);
+ new_line; mark_harmless;
+ flush_buffer(out_ptr-1,1,1); return;
+}
+
+@ Here is a macro that outputs a section number in decimal notation.
+The number to be converted by |out_section| is known to be less than
+|def_flag|, so it cannot have more than five decimal digits. If
+the section is changed, we output `\.{\\*}' just after the number.
+
+@c
+void
+out_section(n)
+sixteen_bits n;
+{
+ char s[6];
+ sprintf(s,"%d",n); out_str(s);
+ if(changed_section[n]) out_str ("\\*");
+@.\\*@>
+}
+
+@ The |out_name| procedure is used to output an identifier or index
+entry, enclosing it in braces.
+
+@c
+void
+out_name(p,quote_xalpha)
+name_pointer p;
+boolean quote_xalpha;
+{
+ char *k, *k_end=(p+1)->byte_start; /* pointers into |byte_mem| */
+ out('{');
+ for (k=p->byte_start; k<k_end; k++) {
+ if (isxalpha(*k) && quote_xalpha) out('\\');
+@.\\\$@>
+@.\\\_@>
+ out(*k);
+ }
+ out('}');
+}
+
+@* Routines that copy \TEX/ material.
+During phase two, we use subroutines |copy_limbo|, |copy_TeX|, and
+|copy_comment| in place of the analogous |skip_limbo|, |skip_TeX|, and
+|skip_comment| that were used in phase one. (Well, |copy_comment|
+was actually written in such a way that it functions as |skip_comment|
+in phase one.)
+
+The |copy_limbo| routine, for example, takes \TEX/ material that is not
+part of any section and transcribes it almost verbatim to the output file.
+The use of `\.{@@}' signs is severely restricted in such material:
+`\.{@@@@}' pairs are replaced by singletons; `\.{@@l}' and `\.{@@q}' and
+`\.{@@s}' are interpreted.
+
+@c
+void
+copy_limbo()
+{
+ char c;
+ while (1) {
+ if (loc>limit && (finish_line(), get_line()==0)) return;
+ *(limit+1)='@@';
+ while (*loc!='@@') out(*(loc++));
+ if (loc++<=limit) {
+ c=*loc++;
+ if (ccode[(eight_bits)c]==new_section) break;
+ switch (ccode[(eight_bits)c]) {
+ case translit_code: out_str("\\ATL"); break;
+@.\\ATL@>
+ case '@@': out('@@'); break;
+ case noop: skip_restricted(); break;
+ case format_code: if (get_next()==identifier) get_next();
+ if (loc>=limit) get_line(); /* avoid blank lines in output */
+ break; /* the operands of \.{@@s} are ignored on this pass */
+ default: err_print("! Double @@ should be used in limbo");
+@.Double @@ should be used...@>
+ out('@@');
+ }
+ }
+ }
+}
+
+@ The |copy_TeX| routine processes the \TEX/ code at the beginning of a
+section; for example, the words you are now reading were copied in this
+way. It returns the next control code or `\.{\v}' found in the input.
+We don't copy spaces or tab marks into the beginning of a line. This
+makes the test for empty lines in |finish_line| work.
+
+@ @f copy_TeX TeX
+@c
+eight_bits
+copy_TeX()
+{
+ char c; /* current character being copied */
+ while (1) {
+ if (loc>limit && (finish_line(), get_line()==0)) return(new_section);
+ *(limit+1)='@@';
+ while ((c=*(loc++))!='|' && c!='@@') {
+ out(c);
+ if (out_ptr==out_buf+1 && (xisspace(c))) out_ptr--;
+ }
+ if (c=='|') return('|');
+ if (loc<=limit) return(ccode[(eight_bits)*(loc++)]);
+ }
+}
+
+@ The |copy_comment| function issues a warning if more braces are opened than
+closed, and in the case of a more serious error it supplies enough
+braces to keep \TEX/ from complaining about unbalanced braces.
+Instead of copying the \TEX/ material
+into the output buffer, this function copies it into the token memory
+(in phase two only).
+The abbreviation |app_tok(t)| is used to append token |t| to the current
+token list, and it also makes sure that it is possible to append at least
+one further token without overflow.
+
+@d app_tok(c) {if (tok_ptr+2>tok_mem_end) overflow("token"); *(tok_ptr++)=c;}
+
+@<Predec...@>=
+int copy_comment();
+
+@ @c
+int copy_comment(is_long_comment,bal) /* copies \TEX/ code in comments */
+boolean is_long_comment; /* is this a traditional \CEE/ comment? */
+int bal; /* brace balance */
+{
+ char c; /* current character being copied */
+ while (1) {
+ if (loc>limit) {
+ if (is_long_comment) {
+ if (get_line()==0) {
+ err_print("! Input ended in mid-comment");
+@.Input ended in mid-comment@>
+ loc=buffer+1; goto done;
+ }
+ }
+ else {
+ if (bal>1) err_print("! Missing } in comment");
+@.Missing \} in comment@>
+ goto done;
+ }
+ }
+ c=*(loc++);
+ if (c=='|') return(bal);
+ if (is_long_comment) @<Check for end of comment@>;
+ if (phase==2) {
+ if (ishigh(c)) app_tok(quoted_char);
+ app_tok(c);
+ }
+ @<Copy special things when |c=='@@', '\\'|@>;
+ if (c=='{') bal++;
+ else if (c=='}') {
+ if(bal>1) bal--;
+ else {err_print("! Extra } in comment");
+@.Extra \} in comment@>
+ if (phase==2) tok_ptr--;
+ }
+ }
+ }
+done:@<Clear |bal| and |return|@>;
+}
+
+@ @<Check for end of comment@>=
+if (c=='*' && *loc=='/') {
+ loc++;
+ if (bal>1) err_print("! Missing } in comment");
+@.Missing \} in comment@>
+ goto done;
+}
+
+@ @<Copy special things when |c=='@@'...@>=
+if (c=='@@') {
+ if (*(loc++)!='@@') {
+ err_print("! Illegal use of @@ in comment");
+@.Illegal use of @@...@>
+ loc-=2; if (phase==2) *(tok_ptr-1)=' '; goto done;
+ }
+}
+else if (c=='\\' && *loc!='@@')
+ if (phase==2) app_tok(*(loc++))@; else loc++;
+
+@ We output
+enough right braces to keep \TEX/ happy.
+
+@<Clear |bal|...@>=
+if (phase==2) while (bal-- >0) app_tok('}');
+return(0);
+
+@** Parsing.
+The most intricate part of \.{CWEAVE} is its mechanism for converting
+\CEE/-like code into \TEX/ code, and we might as well plunge into this
+aspect of the program now. A ``bottom up'' approach is used to parse the
+\CEE/-like material, since \.{CWEAVE} must deal with fragmentary
+constructions whose overall ``part of speech'' is not known.
+
+At the lowest level, the input is represented as a sequence of entities
+that we shall call {\it scraps}, where each scrap of information consists
+of two parts, its {\it category} and its {\it translation}. The category
+is essentially a syntactic class, and the translation is a token list that
+represents \TEX/ code. Rules of syntax and semantics tell us how to
+combine adjacent scraps into larger ones, and if we are lucky an entire
+\CEE/ text that starts out as hundreds of small scraps will join
+together into one gigantic scrap whose translation is the desired \TEX/
+code. If we are unlucky, we will be left with several scraps that don't
+combine; their translations will simply be output, one by one.
+
+The combination rules are given as context-sensitive productions that are
+applied from left to right. Suppose that we are currently working on the
+sequence of scraps $s_1\,s_2\ldots s_n$. We try first to find the longest
+production that applies to an initial substring $s_1\,s_2\ldots\,$; but if
+no such productions exist, we try to find the longest production
+applicable to the next substring $s_2\,s_3\ldots\,$; and if that fails, we
+try to match $s_3\,s_4\ldots\,$, etc.
+
+A production applies if the category codes have a given pattern. For
+example, one of the productions (see rule~3) is
+$$\hbox{|exp| }\left\{\matrix{\hbox{|binop|}\cr\hbox{|ubinop|}}\right\}
+\hbox{ |exp| }\RA\hbox{ |exp|}$$
+and it means that three consecutive scraps whose respective categories are
+|exp|, |binop| (or |ubinop|),
+and |exp| are converted to one scrap whose category
+is |exp|. The translations of the original
+scraps are simply concatenated. The case of
+$$\hbox{|exp| |comma| |exp| $\RA$ |exp|} \hskip4emE_1C\,\\{opt}9\,E_2$$
+(rule 4) is only slightly more complicated:
+Here the resulting |exp| translation
+consists not only of the three original translations, but also of the
+tokens |opt| and 9 between the translations of the
+|comma| and the following |exp|.
+In the \TEX/ file, this will specify an optional line break after the
+comma, with penalty 90.
+
+At each opportunity the longest possible production is applied. For
+example, if the current sequence of scraps is |int_like| |cast|
+|lbrace|, rule 31 is applied; but if the sequence is |int_like| |cast|
+followed by anything other than |lbrace|, rule 32 takes effect.
+
+Translation rules such as `$E_1C\,\\{opt}9\,E_2$' above use subscripts
+to distinguish between translations of scraps whose categories have the
+same initial letter; these subscripts are assigned from left to right.
+
+@ Here is a list of the category codes that scraps can have.
+(A few others, like |int_like|, have already been defined; the
+|cat_name| array contains a complete list.)
+
+@d exp 1 /* denotes an expression, including perhaps a single identifier */
+@d unop 2 /* denotes a unary operator */
+@d binop 3 /* denotes a binary operator */
+@d ubinop 4
+ /* denotes an operator that can be unary or binary, depending on context */
+@d cast 5 /* denotes a cast */
+@d question 6 /* denotes a question mark and possibly the expressions flanking it */
+@d lbrace 7 /* denotes a left brace */
+@d rbrace 8 /* denotes a right brace */
+@d decl_head 9 /* denotes an incomplete declaration */
+@d comma 10 /* denotes a comma */
+@d lpar 11 /* denotes a left parenthesis or left bracket */
+@d rpar 12 /* denotes a right parenthesis or right bracket */
+@d prelangle 13 /* denotes `$<$' before we know what it is */
+@d prerangle 14 /* denotes `$>$' before we know what it is */
+@d langle 15 /* denotes `$<$' when it's used as angle bracket in a template */
+@d colcol 18 /* denotes `::' */
+@d base 19 /* denotes a colon that introduces a base specifier */
+@d decl 20 /* denotes a complete declaration */
+@d struct_head 21 /* denotes the beginning of a structure specifier */
+@d stmt 23 /* denotes a complete statement */
+@d function 24 /* denotes a complete function */
+@d fn_decl 25 /* denotes a function declarator */
+@d semi 27 /* denotes a semicolon */
+@d colon 28 /* denotes a colon */
+@d tag 29 /* denotes a statement label */
+@d if_head 30 /* denotes the beginning of a compound conditional */
+@d else_head 31 /* denotes a prefix for a compound statement */
+@d if_clause 32 /* pending \.{if} together with a condition */
+@d lproc 35 /* begins a preprocessor command */
+@d rproc 36 /* ends a preprocessor command */
+@d insert 37 /* a scrap that gets combined with its neighbor */
+@d section_scrap 38 /* section name */
+@d dead 39 /* scrap that won't combine */
+@d ftemplate 59 /* \\{make\_pair} */
+@d new_exp 60 /* \&{new} and a following type identifier */
+@d begin_arg 61 /* \.{@@[} */
+@d end_arg 62 /* \.{@@]} */
+
+@<Glo...@>=
+char cat_name[256][12];
+eight_bits cat_index;
+
+@ @<Set in...@>=
+ for (cat_index=0;cat_index<255;cat_index++)
+ strcpy(cat_name[cat_index],"UNKNOWN");
+@.UNKNOWN@>
+ strcpy(cat_name[exp],"exp");
+ strcpy(cat_name[unop],"unop");
+ strcpy(cat_name[binop],"binop");
+ strcpy(cat_name[ubinop],"ubinop");
+ strcpy(cat_name[cast],"cast");
+ strcpy(cat_name[question],"?");
+ strcpy(cat_name[lbrace],"{"@q}@>);
+ strcpy(cat_name[rbrace],@q{@>"}");
+ strcpy(cat_name[decl_head],"decl_head");
+ strcpy(cat_name[comma],",");
+ strcpy(cat_name[lpar],"(");
+ strcpy(cat_name[rpar],")");
+ strcpy(cat_name[prelangle],"<");
+ strcpy(cat_name[prerangle],">");
+ strcpy(cat_name[langle],"\\<");
+ strcpy(cat_name[colcol],"::");
+ strcpy(cat_name[base],"\\:");
+ strcpy(cat_name[decl],"decl");
+ strcpy(cat_name[struct_head],"struct_head");
+ strcpy(cat_name[alfop],"alfop");
+ strcpy(cat_name[stmt],"stmt");
+ strcpy(cat_name[function],"function");
+ strcpy(cat_name[fn_decl],"fn_decl");
+ strcpy(cat_name[else_like],"else_like");
+ strcpy(cat_name[semi],";");
+ strcpy(cat_name[colon],":");
+ strcpy(cat_name[tag],"tag");
+ strcpy(cat_name[if_head],"if_head");
+ strcpy(cat_name[else_head],"else_head");
+ strcpy(cat_name[if_clause],"if()");
+ strcpy(cat_name[lproc],"#{"@q}@>);
+ strcpy(cat_name[rproc],@q{@>"#}");
+ strcpy(cat_name[insert],"insert");
+ strcpy(cat_name[section_scrap],"section");
+ strcpy(cat_name[dead],"@@d");
+ strcpy(cat_name[public_like],"public");
+ strcpy(cat_name[operator_like],"operator");
+ strcpy(cat_name[new_like],"new");
+ strcpy(cat_name[catch_like],"catch");
+ strcpy(cat_name[for_like],"for");
+ strcpy(cat_name[do_like],"do");
+ strcpy(cat_name[if_like],"if");
+ strcpy(cat_name[delete_like],"delete");
+ strcpy(cat_name[raw_ubin],"ubinop?");
+ strcpy(cat_name[const_like],"const");
+ strcpy(cat_name[raw_int],"raw");
+ strcpy(cat_name[int_like],"int");
+ strcpy(cat_name[case_like],"case");
+ strcpy(cat_name[sizeof_like],"sizeof");
+ strcpy(cat_name[struct_like],"struct");
+ strcpy(cat_name[typedef_like],"typedef");
+ strcpy(cat_name[define_like],"define");
+ strcpy(cat_name[template_like],"template");
+ strcpy(cat_name[ftemplate],"ftemplate");
+ strcpy(cat_name[new_exp],"new_exp");
+ strcpy(cat_name[begin_arg],"@@["@q]@>);
+ strcpy(cat_name[end_arg],@q[@>"@@]");
+ strcpy(cat_name[0],"zero");
+
+@ This code allows \.{CWEAVE} to display its parsing steps.
+
+@c
+void
+print_cat(c) /* symbolic printout of a category */
+eight_bits c;
+{
+ printf(cat_name[c]);
+}
+
+@ The token lists for translated \TEX/ output contain some special control
+symbols as well as ordinary characters. These control symbols are
+interpreted by \.{CWEAVE} before they are written to the output file.
+
+\yskip\hang |break_space| denotes an optional line break or an en space;
+
+\yskip\hang |force| denotes a line break;
+
+\yskip\hang |big_force| denotes a line break with additional vertical space;
+
+\yskip\hang |preproc_line| denotes that the line will be printed flush left;
+
+\yskip\hang |opt| denotes an optional line break (with the continuation
+line indented two ems with respect to the normal starting position)---this
+code is followed by an integer |n|, and the break will occur with penalty
+$10n$;
+
+\yskip\hang |backup| denotes a backspace of one em;
+
+\yskip\hang |cancel| obliterates any |break_space|, |opt|, |force|, or
+|big_force| tokens that immediately precede or follow it and also cancels any
+|backup| tokens that follow it;
+
+\yskip\hang |indent| causes future lines to be indented one more em;
+
+\yskip\hang |outdent| causes future lines to be indented one less em.
+
+\yskip\noindent All of these tokens are removed from the \TEX/ output that
+comes from \CEE/ text between \pb\ signs; |break_space| and |force| and
+|big_force| become single spaces in this mode. The translation of other
+\CEE/ texts results in \TEX/ control sequences \.{\\1}, \.{\\2},
+\.{\\3}, \.{\\4}, \.{\\5}, \.{\\6}, \.{\\7}, \.{\\8}
+corresponding respectively to
+|indent|, |outdent|, |opt|, |backup|, |break_space|, |force|,
+|big_force| and |preproc_line|.
+However, a sequence of consecutive `\.\ ', |break_space|,
+|force|, and/or |big_force| tokens is first replaced by a single token
+(the maximum of the given ones).
+
+The token |math_rel| will be translated into
+\.{\\MRL\{}, and it will get a matching \.\} later.
+Other control sequences in the \TEX/ output will be
+`\.{\\\\\{}$\,\ldots\,$\.\}'
+surrounding identifiers, `\.{\\\&\{}$\,\ldots\,$\.\}' surrounding
+reserved words, `\.{\\.\{}$\,\ldots\,$\.\}' surrounding strings,
+`\.{\\C\{}$\,\ldots\,$\.\}$\,$|force|' surrounding comments, and
+`\.{\\X$n$:}$\,\ldots\,$\.{\\X}' surrounding section names, where
+|n| is the section number.
+
+@d math_rel 0206
+@d big_cancel 0210 /* like |cancel|, also overrides spaces */
+@d cancel 0211 /* overrides |backup|, |break_space|, |force|, |big_force| */
+@d indent 0212 /* one more tab (\.{\\1}) */
+@d outdent 0213 /* one less tab (\.{\\2}) */
+@d opt 0214 /* optional break in mid-statement (\.{\\3}) */
+@d backup 0215 /* stick out one unit to the left (\.{\\4}) */
+@d break_space 0216 /* optional break between statements (\.{\\5}) */
+@d force 0217 /* forced break between statements (\.{\\6}) */
+@d big_force 0220 /* forced break with additional space (\.{\\7}) */
+@d preproc_line 0221 /* begin line without indentation (\.{\\8}) */
+@^high-bit character handling@>
+@d quoted_char 0222
+ /* introduces a character token in the range |0200|--|0377| */
+@d end_translation 0223 /* special sentinel token at end of list */
+@d inserted 0224 /* sentinel to mark translations of inserts */
+@d qualifier 0225 /* introduces an explicit namespace qualifier */
+
+@ The raw input is converted into scraps according to the following table,
+which gives category codes followed by the translations.
+\def\stars {\.{**}}%
+The symbol `\stars' stands for `\.{\\\&\{{\rm identifier}\}}',
+i.e., the identifier itself treated as a reserved word.
+The right-hand column is the so-called |mathness|, which is explained
+further below.
+
+An identifier |c| of length 1 is translated as \.{\\\v c} instead of
+as \.{\\\\\{c\}}. An identifier \.{CAPS} in all caps is translated as
+\.{\\.\{CAPS\}} instead of as \.{\\\\\{CAPS\}}. An identifier that has
+become a reserved word via |typedef| is translated with \.{\\\&} replacing
+\.{\\\\} and |raw_int| replacing |exp|.
+
+A string of length greater than 20 is broken into pieces of size at most~20
+with discretionary breaks in between.
+
+\yskip\halign{\quad#\hfil&\quad#\hfil&\quad\hfil#\hfil\cr
+\.{!=}&|binop|: \.{\\I}&yes\cr
+\.{<=}&|binop|: \.{\\Z}&yes\cr
+\.{>=}&|binop|: \.{\\G}&yes\cr
+\.{==}&|binop|: \.{\\E}&yes\cr
+\.{\&\&}&|binop|: \.{\\W}&yes\cr
+\.{\v\v}&|binop|: \.{\\V}&yes\cr
+\.{++}&|unop|: \.{\\PP}&yes\cr
+\.{--}&|unop|: \.{\\MM}&yes\cr
+\.{->}&|binop|: \.{\\MG}&yes\cr
+\.{>>}&|binop|: \.{\\GG}&yes\cr
+\.{<<}&|binop|: \.{\\LL}&yes\cr
+\.{::}&|colcol|: \.{\\DC}&maybe\cr
+\.{.*}&|binop|: \.{\\PA}&yes\cr
+\.{->*}&|binop|: \.{\\MGA}&yes\cr
+\.{...}&|raw_int|: \.{\\,\\ldots\\,}&yes\cr
+\."string\."&|exp|: \.{\\.\{}string with special characters quoted\.\}&maybe\cr
+\.{@@=}string\.{@@>}&|exp|: \.{\\vb\{}string with special characters
+ quoted\.\}&maybe\cr
+\.{@@'7'}&|exp|: \.{\\.\{@@'7'\}}&maybe\cr
+\.{077} or \.{\\77}&|exp|: \.{\\T\{\\\~77\}}&maybe\cr
+\.{0x7f}&|exp|: \.{\\T\{\\\^7f\}}&maybe\cr
+\.{77}&|exp|: \.{\\T\{77\}}&maybe\cr
+\.{77L}&|exp|: \.{\\T\{77\\\$L\}}&maybe\cr
+\.{0.1E5}&|exp|: \.{\\T\{0.1\\\_5\}}&maybe\cr
+\.+&|ubinop|: \.+&yes\cr
+\.-&|ubinop|: \.-&yes\cr
+\.*&|raw_ubin|: \.*&yes\cr
+\./&|binop|: \./&yes\cr
+\.<&|prelangle|: \.{\\langle}&yes\cr
+\.=&|binop|: \.{\\K}&yes\cr
+\.>&|prerangle|: \.{\\rangle}&yes\cr
+\..&|binop|: \..&yes\cr
+\.{\v}&|binop|: \.{\\OR}&yes\cr
+\.\^&|binop|: \.{\\XOR}&yes\cr
+\.\%&|binop|: \.{\\MOD}&yes\cr
+\.?&|question|: \.{\\?}&yes\cr
+\.!&|unop|: \.{\\R}&yes\cr
+\.\~&|unop|: \.{\\CM}&yes\cr
+\.\&&|raw_ubin|: \.{\\AND}&yes\cr
+\.(&|lpar|: \.(&maybe\cr
+\.[&|lpar|: \.[&maybe\cr
+\.)&|rpar|: \.)&maybe\cr
+\.]&|rpar|: \.]&maybe\cr
+\.\{&|lbrace|: \.\{&yes\cr
+\.\}&|lbrace|: \.\}&yes\cr
+\.,&|comma|: \.,&yes\cr
+\.;&|semi|: \.;&maybe\cr
+\.:&|colon|: \.:&no\cr
+\.\# (within line)&|ubinop|: \.{\\\#}&yes\cr
+\.\# (at beginning)&|lproc|: |force| |preproc_line| \.{\\\#}&no\cr
+end of \.\# line&|rproc|: |force|&no\cr
+identifier&|exp|: \.{\\\\\{}identifier with underlines and
+ dollar signs quoted\.\}&maybe\cr
+\.{and}&|alfop|: \stars&yes\cr
+\.{and\_eq}&|alfop|: \stars&yes\cr
+\.{asm}&|sizeof_like|: \stars&maybe\cr
+\.{auto}&|int_like|: \stars&maybe\cr
+\.{bitand}&|alfop|: \stars&yes\cr
+\.{bitor}&|alfop|: \stars&yes\cr
+\.{bool}&|raw_int|: \stars&maybe\cr
+\.{break}&|case_like|: \stars&maybe\cr
+\.{case}&|case_like|: \stars&maybe\cr
+\.{catch}&|catch_like|: \stars&maybe\cr
+\.{char}&|raw_int|: \stars&maybe\cr
+\.{class}&|struct_like|: \stars&maybe\cr
+\.{clock\_t}&|raw_int|: \stars&maybe\cr
+\.{compl}&|alfop|: \stars&yes\cr
+\.{const}&|const_like|: \stars&maybe\cr
+\.{const\_cast}&|raw_int|: \stars&maybe\cr
+\.{continue}&|case_like|: \stars&maybe\cr
+\.{default}&|case_like|: \stars&maybe\cr
+\.{define}&|define_like|: \stars&maybe\cr
+\.{defined}&|sizeof_like|: \stars&maybe\cr
+\.{delete}&|delete_like|: \stars&maybe\cr
+\.{div\_t}&|raw_int|: \stars&maybe\cr
+\.{do}&|do_like|: \stars&maybe\cr
+\.{double}&|raw_int|: \stars&maybe\cr
+\.{dynamic\_cast}&|raw_int|: \stars&maybe\cr
+\.{elif}&|if_like|: \stars&maybe\cr
+\.{else}&|else_like|: \stars&maybe\cr
+\.{endif}&|if_like|: \stars&maybe\cr
+\.{enum}&|struct_like|: \stars&maybe\cr
+\.{error}&|if_like|: \stars&maybe\cr
+\.{explicit}&|int_like|: \stars&maybe\cr
+\.{export}&|int_like|: \stars&maybe\cr
+\.{extern}&|int_like|: \stars&maybe\cr
+\.{FILE}&|raw_int|: \stars&maybe\cr
+\.{float}&|raw_int|: \stars&maybe\cr
+\.{for}&|for_like|: \stars&maybe\cr
+\.{fpos\_t}&|raw_int|: \stars&maybe\cr
+\.{friend}&|int_like|: \stars&maybe\cr
+\.{goto}&|case_like|: \stars&maybe\cr
+\.{if}&|if_like|: \stars&maybe\cr
+\.{ifdef}&|if_like|: \stars&maybe\cr
+\.{ifndef}&|if_like|: \stars&maybe\cr
+\.{include}&|if_like|: \stars&maybe\cr
+\.{inline}&|int_like|: \stars&maybe\cr
+\.{int}&|raw_int|: \stars&maybe\cr
+\.{jmp\_buf}&|raw_int|: \stars&maybe\cr
+\.{ldiv\_t}&|raw_int|: \stars&maybe\cr
+\.{line}&|if_like|: \stars&maybe\cr
+\.{long}&|raw_int|: \stars&maybe\cr
+\.{make\_pair}&|ftemplate|: \.{\\\\\{make\\\_pair\}}&maybe\cr
+\.{mutable}&|int_like|: \stars&maybe\cr
+\.{namespace}&|struct_like|: \stars&maybe\cr
+\.{new}&|new_like|: \stars&maybe\cr
+\.{not}&|alfop|: \stars&yes\cr
+\.{not\_eq}&|alfop|: \stars&yes\cr
+\.{NULL}&|exp|: \.{\\NULL}&yes\cr
+\.{offsetof}&|raw_int|: \stars&maybe\cr
+\.{operator}&|operator_like|: \stars&maybe\cr
+\.{or}&|alfop|: \stars&yes\cr
+\.{or\_eq}&|alfop|: \stars&yes\cr
+\.{pragma}&|if_like|: \stars&maybe\cr
+\.{private}&|public_like|: \stars&maybe\cr
+\.{protected}&|public_like|: \stars&maybe\cr
+\.{ptrdiff\_t}&|raw_int|: \stars&maybe\cr
+\.{public}&|public_like|: \stars&maybe\cr
+\.{register}&|int_like|: \stars&maybe\cr
+\.{reinterpret\_cast}&|raw_int|: \stars&maybe\cr
+\.{return}&|case_like|: \stars&maybe\cr
+\.{short}&|raw_int|: \stars&maybe\cr
+\.{sig\_atomic\_t}&|raw_int|: \stars&maybe\cr
+\.{signed}&|raw_int|: \stars&maybe\cr
+\.{size\_t}&|raw_int|: \stars&maybe\cr
+\.{sizeof}&|sizeof_like|: \stars&maybe\cr
+\.{static}&|int_like|: \stars&maybe\cr
+\.{static\_cast}&|raw_int|: \stars&maybe\cr
+\.{struct}&|struct_like|: \stars&maybe\cr
+\.{switch}&|for_like|: \stars&maybe\cr
+\.{template}&|template_like|: \stars&maybe\cr
+\.{TeX}&|exp|: \.{\\TeX}&yes\cr
+\.{this}&|exp|: \.{\\this}&yes\cr
+\.{throw}&|case_like|: \stars&maybe\cr
+\.{time\_t}&|raw_int|: \stars&maybe\cr
+\.{try}&|else_like|: \stars&maybe\cr
+\.{typedef}&|typedef_like|: \stars&maybe\cr
+\.{typeid}&|raw_int|: \stars&maybe\cr
+\.{typename}&|struct_like|: \stars&maybe\cr
+\.{undef}&|if_like|: \stars&maybe\cr
+\.{union}&|struct_like|: \stars&maybe\cr
+\.{unsigned}&|raw_int|: \stars&maybe\cr
+\.{using}&|int_like|: \stars&maybe\cr
+\.{va\_dcl}&|decl|: \stars&maybe\cr
+\.{va\_list}&|raw_int|: \stars&maybe\cr
+\.{virtual}&|int_like|: \stars&maybe\cr
+\.{void}&|raw_int|: \stars&maybe\cr
+\.{volatile}&|const_like|: \stars&maybe\cr
+\.{wchar\_t}&|raw_int|: \stars&maybe\cr
+\.{while}&|for_like|: \stars&maybe\cr
+\.{xor}&|alfop|: \stars&yes\cr
+\.{xor\_eq}&|alfop|: \stars&yes\cr
+\.{@@,}&|insert|: \.{\\,}&maybe\cr
+\.{@@\v}&|insert|: |opt| \.0&maybe\cr
+\.{@@/}&|insert|: |force|&no\cr
+\.{@@\#}&|insert|: |big_force|&no\cr
+\.{@@+}&|insert|: |big_cancel| \.{\{\}} |break_space|
+ \.{\{\}} |big_cancel|&no\cr
+\.{@@;}&|semi|: &maybe\cr
+\.{@@[@q]@>}&|begin_arg|: &maybe\cr
+\.{@q[@>@@]}&|end_arg|: &maybe\cr
+\.{@@\&}&|insert|: \.{\\J}&maybe\cr
+\.{@@h}&|insert|: |force| \.{\\ATH} |force|&no\cr
+\.{@@<}\thinspace section name\thinspace\.{@@>}&|section_scrap|:
+ \.{\\X}$n$\.:translated section name\.{\\X}&maybe\cr
+\.{@@(@q)@>}\thinspace section name\thinspace\.{@@>}&|section_scrap|:
+ \.{\\X}$n$\.{:\\.\{}section name with special characters
+ quoted\.{\ \}\\X}&maybe\cr
+\.{/*}comment\.{*/}&|insert|: |cancel|
+ \.{\\C\{}translated comment\.\} |force|&no\cr
+\.{//}comment&|insert|: |cancel|
+ \.{\\SHC\{}translated comment\.\} |force|&no\cr
+}
+
+\smallskip
+The construction \.{@@t}\thinspace stuff\/\thinspace\.{@@>} contributes
+\.{\\hbox\{}\thinspace stuff\/\thinspace\.\} to the following scrap.
+
+@i prod.w
+
+@* Implementing the productions.
+More specifically, a scrap is a structure consisting of a category
+|cat| and a |text_pointer| |trans|, which points to the translation in
+|tok_start|. When \CEE/ text is to be processed with the grammar above,
+we form an array |scrap_info| containing the initial scraps.
+Our production rules have the nice property that the right-hand side is never
+longer than the left-hand side. Therefore it is convenient to use sequential
+allocation for the current sequence of scraps. Five pointers are used to
+manage the parsing:
+
+\yskip\hang |pp| is a pointer into |scrap_info|. We will try to match
+the category codes |pp->cat,@,@,(pp+1)->cat|$,\,\,\ldots\,$
+to the left-hand sides of productions.
+
+\yskip\hang |scrap_base|, |lo_ptr|, |hi_ptr|, and |scrap_ptr| are such that
+the current sequence of scraps appears in positions |scrap_base| through
+|lo_ptr| and |hi_ptr| through |scrap_ptr|, inclusive, in the |cat| and
+|trans| arrays. Scraps located between |scrap_base| and |lo_ptr| have
+been examined, while those in positions |>=hi_ptr| have not yet been
+looked at by the parsing process.
+
+\yskip\noindent Initially |scrap_ptr| is set to the position of the final
+scrap to be parsed, and it doesn't change its value. The parsing process
+makes sure that |lo_ptr>=pp+3|, since productions have as many as four terms,
+by moving scraps from |hi_ptr| to |lo_ptr|. If there are
+fewer than |pp+3| scraps left, the positions up to |pp+3| are filled with
+blanks that will not match in any productions. Parsing stops when
+|pp==lo_ptr+1| and |hi_ptr==scrap_ptr+1|.
+
+Since the |scrap| structure will later be used for other purposes, we
+declare its second element as a union.
+
+@<Type...@>=
+typedef struct {
+ eight_bits cat;
+ eight_bits mathness;
+ union {
+ text_pointer Trans;
+ @<Rest of |trans_plus| union@>@;
+ } trans_plus;
+} scrap;
+typedef scrap *scrap_pointer;
+
+@ @d trans trans_plus.Trans /* translation texts of scraps */
+
+@<Global...@>=
+scrap scrap_info[max_scraps]; /* memory array for scraps */
+scrap_pointer scrap_info_end=scrap_info+max_scraps -1; /* end of |scrap_info| */
+scrap_pointer pp; /* current position for reducing productions */
+scrap_pointer scrap_base; /* beginning of the current scrap sequence */
+scrap_pointer scrap_ptr; /* ending of the current scrap sequence */
+scrap_pointer lo_ptr; /* last scrap that has been examined */
+scrap_pointer hi_ptr; /* first scrap that has not been examined */
+scrap_pointer max_scr_ptr; /* largest value assumed by |scrap_ptr| */
+
+@ @<Set init...@>=
+scrap_base=scrap_info+1;
+max_scr_ptr=scrap_ptr=scrap_info;
+
+@ Token lists in |@!tok_mem| are composed of the following kinds of
+items for \TEX/ output.
+
+\yskip\item{$\bullet$}Character codes and special codes like |force| and
+|math_rel| represent themselves;
+
+\item{$\bullet$}|id_flag+p| represents \.{\\\\\{{\rm identifier $p$}\}};
+
+\item{$\bullet$}|res_flag+p| represents \.{\\\&\{{\rm identifier $p$}\}};
+
+\item{$\bullet$}|section_flag+p| represents section name |p|;
+
+\item{$\bullet$}|tok_flag+p| represents token list number |p|;
+
+\item{$\bullet$}|inner_tok_flag+p| represents token list number |p|, to be
+translated without line-break controls.
+
+@d id_flag 10240 /* signifies an identifier */
+@d res_flag 2*id_flag /* signifies a reserved word */
+@d section_flag 3*id_flag /* signifies a section name */
+@d tok_flag 4*id_flag /* signifies a token list */
+@d inner_tok_flag 5*id_flag /* signifies a token list in `\pb' */
+
+@c
+void
+print_text(p) /* prints a token list for debugging; not used in |main| */
+text_pointer p;
+{
+ token_pointer j; /* index into |tok_mem| */
+ sixteen_bits r; /* remainder of token after the flag has been stripped off */
+ if (p>=text_ptr) printf("BAD");
+ else for (j=*p; j<*(p+1); j++) {
+ r=*j%id_flag;
+ switch (*j/id_flag) {
+ case 1: printf("\\\\{"@q}@>); print_id((name_dir+r)); printf(@q{@>"}");
+ break; /* |id_flag| */
+ case 2: printf("\\&{"@q}@>); print_id((name_dir+r)); printf(@q{@>"}");
+ break; /* |res_flag| */
+ case 3: printf("<"); print_section_name((name_dir+r)); printf(">");
+ break; /* |section_flag| */
+ case 4: printf("[[%d]]",r); break; /* |tok_flag| */
+ case 5: printf("|[[%d]]|",r); break; /* |inner_tok_flag| */
+ default: @<Print token |r| in symbolic form@>;
+ }
+ }
+ fflush(stdout);
+}
+
+@ @<Print token |r|...@>=
+switch (r) {
+ case math_rel: printf("\\mathrel{"@q}@>); break;
+ case big_cancel: printf("[ccancel]"); break;
+ case cancel: printf("[cancel]"); break;
+ case indent: printf("[indent]"); break;
+ case outdent: printf("[outdent]"); break;
+ case backup: printf("[backup]"); break;
+ case opt: printf("[opt]"); break;
+ case break_space: printf("[break]"); break;
+ case force: printf("[force]"); break;
+ case big_force: printf("[fforce]"); break;
+ case preproc_line: printf("[preproc]"); break;
+ case quoted_char: j++; printf("[%o]",(unsigned)*j); break;
+ case end_translation: printf("[quit]"); break;
+ case inserted: printf("[inserted]"); break;
+ default: putxchar(r);
+}
+
+@ The production rules listed above are embedded directly into \.{CWEAVE},
+since it is easier to do this than to write an interpretive system
+that would handle production systems in general. Several macros are defined
+here so that the program for each production is fairly short.
+
+All of our productions conform to the general notion that some |k|
+consecutive scraps starting at some position |j| are to be replaced by a
+single scrap of some category |c| whose translation is composed from the
+translations of the disappearing scraps. After this production has been
+applied, the production pointer |pp| should change by an amount |d|. Such
+a production can be represented by the quadruple |(j,k,c,d)|. For example,
+the production `|exp@,comma@,exp| $\RA$ |exp|' would be represented by
+`|(pp,3,exp,-2)|'; in this case the pointer |pp| should decrease by 2
+after the production has been applied, because some productions with
+|exp| in their second or third positions might now match,
+but no productions have
+|exp| in the fourth position of their left-hand sides. Note that
+the value of |d| is determined by the whole collection of productions, not
+by an individual one.
+The determination of |d| has been
+done by hand in each case, based on the full set of productions but not on
+the grammar of \CEE/ or on the rules for constructing the initial
+scraps.
+
+We also attach a serial number to each production, so that additional
+information is available when debugging. For example, the program below
+contains the statement `|reduce(pp,3,exp,-2,4)|' when it implements
+the production just mentioned.
+
+Before calling |reduce|, the program should have appended the tokens of
+the new translation to the |tok_mem| array. We commonly want to append
+copies of several existing translations, and macros are defined to
+simplify these common cases. For example, \\{app2}|(pp)| will append the
+translations of two consecutive scraps, |pp->trans| and |(pp+1)->trans|, to
+the current token list. If the entire new translation is formed in this
+way, we write `|squash(j,k,c,d,n)|' instead of `|reduce(j,k,c,d,n)|'. For
+example, `|squash(pp,3,exp,-2,3)|' is an abbreviation for `\\{app3}|(pp);
+reduce(pp,3,exp,-2,3)|'.
+
+A couple more words of explanation:
+Both |big_app| and |app| append a token (while |big_app1| to |big_app4|
+append the specified number of scrap translations) to the current token list.
+The difference between |big_app| and |app| is simply that |big_app|
+checks whether there can be a conflict between math and non-math
+tokens, and intercalates a `\.{\$}' token if necessary. When in
+doubt what to use, use |big_app|.
+
+The |mathness| is an attribute of scraps that says whether they are
+to be printed in a math mode context or not. It is separate from the
+``part of speech'' (the |cat|) because to make each |cat| have
+a fixed |mathness| (as in the original \.{WEAVE}) would multiply the
+number of necessary production rules.
+
+The low two bits (i.e. |mathness % 4|) control the left boundary.
+(We need two bits because we allow cases |yes_math|, |no_math| and
+|maybe_math|, which can go either way.)
+The next two bits (i.e. |mathness / 4|) control the right boundary.
+If we combine two scraps and the right boundary of the first has
+a different mathness from the left boundary of the second, we
+insert a \.{\$} in between. Similarly, if at printing time some
+irreducible scrap has a |yes_math| boundary the scrap gets preceded
+or followed by a \.{\$}. The left boundary is |maybe_math| if and
+only if the right boundary is.
+
+The code below is an exact translation of the production rules into
+\CEE/, using such macros, and the reader should have no difficulty
+understanding the format by comparing the code with the symbolic
+productions as they were listed earlier.
+
+@d no_math 2 /* should be in horizontal mode */
+@d yes_math 1 /* should be in math mode */
+@d maybe_math 0 /* works in either horizontal or math mode */
+@d big_app2(a) big_app1(a);big_app1(a+1)
+@d big_app3(a) big_app2(a);big_app1(a+2)
+@d big_app4(a) big_app3(a);big_app1(a+3)
+@d app(a) *(tok_ptr++)=a
+@d app1(a) *(tok_ptr++)=tok_flag+(int)((a)->trans-tok_start)
+
+@<Global...@>=
+int cur_mathness, init_mathness;
+
+@ @c
+void
+app_str(s)
+char *s;
+{
+ while (*s) app_tok(*(s++));
+}
+
+void
+big_app(a)
+token a;
+{
+ if (a==' ' || (a>=big_cancel && a<=big_force)) /* non-math token */ {
+ if (cur_mathness==maybe_math) init_mathness=no_math;
+ else if (cur_mathness==yes_math) app_str("{}$");
+ cur_mathness=no_math;
+ }
+ else {
+ if (cur_mathness==maybe_math) init_mathness=yes_math;
+ else if (cur_mathness==no_math) app_str("${}");
+ cur_mathness=yes_math;
+ }
+ app(a);
+}
+
+void
+big_app1(a)
+scrap_pointer a;
+{
+ switch (a->mathness % 4) { /* left boundary */
+ case (no_math):
+ if (cur_mathness==maybe_math) init_mathness=no_math;
+ else if (cur_mathness==yes_math) app_str("{}$");
+ cur_mathness=a->mathness / 4; /* right boundary */
+ break;
+ case (yes_math):
+ if (cur_mathness==maybe_math) init_mathness=yes_math;
+ else if (cur_mathness==no_math) app_str("${}");
+ cur_mathness=a->mathness / 4; /* right boundary */
+ break;
+ case (maybe_math): /* no changes */ break;
+ }
+ app(tok_flag+(int)((a)->trans-tok_start));
+}
+
+@ Let us consider the big switch for productions now, before looking
+at its context. We want to design the program so that this switch
+works, so we might as well not keep ourselves in suspense about exactly what
+code needs to be provided with a proper environment.
+
+@d cat1 (pp+1)->cat
+@d cat2 (pp+2)->cat
+@d cat3 (pp+3)->cat
+@d lhs_not_simple (pp->cat!=public_like
+ && pp->cat!=semi
+ && pp->cat!=prelangle
+ && pp->cat!=prerangle
+ && pp->cat!=template_like
+ && pp->cat!=new_like
+ && pp->cat!=new_exp
+ && pp->cat!=ftemplate
+ && pp->cat!=raw_ubin
+ && pp->cat!=const_like
+ && pp->cat!=raw_int
+ && pp->cat!=operator_like)
+ /* not a production with left side length 1 */
+
+@<Match a production at |pp|, or increase |pp| if there is no match@>= {
+ if (cat1==end_arg && lhs_not_simple)
+ if (pp->cat==begin_arg) squash(pp,2,exp,-2,124);
+ else squash(pp,2,end_arg,-1,125);
+ else if (cat1==insert) squash(pp,2,pp->cat,-2,0);
+ else if (cat2==insert) squash(pp+1,2,(pp+1)->cat,-1,0);
+ else if (cat3==insert) squash(pp+2,2,(pp+2)->cat,0,0);
+ else
+ switch (pp->cat) {
+ case exp: @<Cases for |exp|@>; @+break;
+ case lpar: @<Cases for |lpar|@>; @+break;
+ case unop: @<Cases for |unop|@>; @+break;
+ case ubinop: @<Cases for |ubinop|@>; @+break;
+ case binop: @<Cases for |binop|@>; @+break;
+ case cast: @<Cases for |cast|@>; @+break;
+ case sizeof_like: @<Cases for |sizeof_like|@>; @+break;
+ case int_like: @<Cases for |int_like|@>; @+break;
+ case public_like: @<Cases for |public_like|@>; @+break;
+ case colcol: @<Cases for |colcol|@>; @+break;
+ case decl_head: @<Cases for |decl_head|@>; @+break;
+ case decl: @<Cases for |decl|@>; @+break;
+ case base: @<Cases for |base|@>; @+break;
+ case struct_like: @<Cases for |struct_like|@>; @+break;
+ case struct_head: @<Cases for |struct_head|@>; @+break;
+ case fn_decl: @<Cases for |fn_decl|@>; @+break;
+ case function: @<Cases for |function|@>; @+break;
+ case lbrace: @<Cases for |lbrace|@>; @+break;
+ case if_like: @<Cases for |if_like|@>; @+break;
+ case else_like: @<Cases for |else_like|@>; @+break;
+ case else_head: @<Cases for |else_head|@>; @+break;
+ case if_clause: @<Cases for |if_clause|@>; @+break;
+ case if_head: @<Cases for |if_head|@>; @+break;
+ case do_like: @<Cases for |do_like|@>; @+break;
+ case case_like: @<Cases for |case_like|@>; @+break;
+ case catch_like: @<Cases for |catch_like|@>; @+break;
+ case tag: @<Cases for |tag|@>; @+break;
+ case stmt: @<Cases for |stmt|@>; @+break;
+ case semi: @<Cases for |semi|@>; @+break;
+ case lproc: @<Cases for |lproc|@>; @+break;
+ case section_scrap: @<Cases for |section_scrap|@>; @+break;
+ case insert: @<Cases for |insert|@>; @+break;
+ case prelangle: @<Cases for |prelangle|@>; @+break;
+ case prerangle: @<Cases for |prerangle|@>; @+break;
+ case langle: @<Cases for |langle|@>; @+break;
+ case template_like: @<Cases for |template_like|@>; @+break;
+ case new_like: @<Cases for |new_like|@>; @+break;
+ case new_exp: @<Cases for |new_exp|@>; @+break;
+ case ftemplate: @<Cases for |ftemplate|@>; @+break;
+ case for_like: @<Cases for |for_like|@>; @+break;
+ case raw_ubin: @<Cases for |raw_ubin|@>; @+break;
+ case const_like: @<Cases for |const_like|@>; @+break;
+ case raw_int: @<Cases for |raw_int|@>; @+break;
+ case operator_like: @<Cases for |operator_like|@>; @+break;
+ case typedef_like: @<Cases for |typedef_like|@>; @+break;
+ case delete_like: @<Cases for |delete_like|@>; @+break;
+ case question: @<Cases for |question|@>; @+break;
+ }
+ pp++; /* if no match was found, we move to the right */
+}
+
+@ In \CEE/, new specifier names can be defined via |typedef|, and we want
+to make the parser recognize future occurrences of the identifier thus
+defined as specifiers. This is done by the procedure |make_reserved|,
+which changes the |ilk| of the relevant identifier.
+
+We first need a procedure to recursively seek the first
+identifier in a token list, because the identifier might
+be enclosed in parentheses, as when one defines a function
+returning a pointer.
+
+If the first identifier found is a keyword like `\&{case}', we
+return the special value |case_found|; this prevents underlining
+of identifiers in case labels.
+
+If the first identifier is the keyword `\&{operator}', we give up;
+users who want to index definitions of overloaded \CPLUSPLUS/ operators
+should say, for example, `\.{@@!@@\^\\\&\{operator\} \$+\{=\}\$@@>}' (or,
+more properly alphebetized,
+`\.{@@!@@:operator+=\}\{\\\&\{operator\} \$+\{=\}\$@@>}').
+
+@d no_ident_found (token_pointer)0 /* distinct from any identifier token */
+@d case_found (token_pointer)1 /* likewise */
+@d operator_found (token_pointer)2 /* likewise */
+
+@c
+token_pointer
+find_first_ident(p)
+text_pointer p;
+{
+ token_pointer q; /* token to be returned */
+ token_pointer j; /* token being looked at */
+ sixteen_bits r; /* remainder of token after the flag has been stripped off */
+ if (p>=text_ptr) confusion("find_first_ident");
+ for (j=*p; j<*(p+1); j++) {
+ r=*j%id_flag;
+ switch (*j/id_flag) {
+ case 2: /* |res_flag| */
+ if (name_dir[r].ilk==case_like) return case_found;
+ if (name_dir[r].ilk==operator_like) return operator_found;
+ if (name_dir[r].ilk!=raw_int) break;
+ case 1: return j;
+ case 4: case 5: /* |tok_flag| or |inner_tok_flag| */
+ if ((q=find_first_ident(tok_start+r))!=no_ident_found)
+ return q;
+ default: ; /* char, |section_flag|, fall thru: move on to next token */
+ if (*j==inserted) return no_ident_found; /* ignore inserts */
+ else if (*j==qualifier) j++; /* bypass namespace qualifier */
+ }
+ }
+ return no_ident_found;
+}
+
+@ The scraps currently being parsed must be inspected for any
+occurrence of the identifier that we're making reserved; hence
+the |for| loop below.
+
+@c
+void
+make_reserved(p) /* make the first identifier in |p->trans| like |int| */
+scrap_pointer p;
+{
+ sixteen_bits tok_value; /* the name of this identifier, plus its flag*/
+ token_pointer tok_loc; /* pointer to |tok_value| */
+ if ((tok_loc=find_first_ident(p->trans))<=operator_found)
+ return; /* this should not happen */
+ tok_value=*tok_loc;
+ for (;p<=scrap_ptr; p==lo_ptr? p=hi_ptr: p++) {
+ if (p->cat==exp) {
+ if (**(p->trans)==tok_value) {
+ p->cat=raw_int;
+ **(p->trans)=tok_value%id_flag+res_flag;
+ }
+ }
+ }
+ (name_dir+(sixteen_bits)(tok_value%id_flag))->ilk=raw_int;
+ *tok_loc=tok_value%id_flag+res_flag;
+}
+
+@ In the following situations we want to mark the occurrence of
+an identifier as a definition: when |make_reserved| is just about to be
+used; after a specifier, as in |char **argv|;
+before a colon, as in \\{found}:; and in the declaration of a function,
+as in \\{main}()$\{\ldots;\}$. This is accomplished by the invocation
+of |make_underlined| at appropriate times. Notice that, in the declaration
+of a function, we find out that the identifier is being defined only after
+it has been swallowed up by an |exp|.
+
+@c
+void
+make_underlined(p)
+/* underline the entry for the first identifier in |p->trans| */
+scrap_pointer p;
+{
+ token_pointer tok_loc; /* where the first identifier appears */
+ if ((tok_loc=find_first_ident(p->trans))<=operator_found)
+ return; /* this happens, for example, in |case found:| */
+ xref_switch=def_flag;
+ underline_xref(*tok_loc%id_flag+name_dir);
+}
+
+@ We cannot use |new_xref| to underline a cross-reference at this point
+because this would just make a new cross-reference at the end of the list.
+We actually have to search through the list for the existing
+cross-reference.
+
+@<Predecl...@>=
+void underline_xref();
+
+@ @c
+void
+underline_xref(p)
+name_pointer p;
+{
+ xref_pointer q=(xref_pointer)p->xref; /* pointer to cross-reference being examined */
+ xref_pointer r; /* temporary pointer for permuting cross-references */
+ sixteen_bits m; /* cross-reference value to be installed */
+ sixteen_bits n; /* cross-reference value being examined */
+ if (no_xref) return;
+ m=section_count+xref_switch;
+ while (q != xmem) {
+ n=q->num;
+ if (n==m) return;
+ else if (m==n+def_flag) {
+ q->num=m; return;
+ }
+ else if (n>=def_flag && n<m) break;
+ q=q->xlink;
+ }
+ @<Insert new cross-reference at |q|, not at beginning of list@>;
+}
+
+@ We get to this section only when the identifier is one letter long,
+so it didn't get a non-underlined entry during phase one. But it may
+have got some explicitly underlined entries in later sections, so in order
+to preserve the numerical order of the entries in the index, we have
+to insert the new cross-reference not at the beginning of the list
+(namely, at |p->xref|), but rather right before |q|.
+
+@<Insert new cross-reference at |q|...@>=
+ append_xref(0); /* this number doesn't matter */
+ xref_ptr->xlink=(xref_pointer)p->xref; r=xref_ptr;
+ p->xref=(char*)xref_ptr;
+ while (r->xlink!=q) {r->num=r->xlink->num; r=r->xlink;}
+ r->num=m; /* everything from |q| on is left undisturbed */
+
+@ Now comes the code that tries to match each production starting
+with a particular type of scrap. Whenever a match is discovered,
+the |squash| or |reduce| macro will cause the appropriate action
+to be performed, followed by |goto found|.
+
+@<Cases for |exp|@>=
+if (cat1==lbrace || cat1==int_like || cat1==decl) {
+ make_underlined(pp); big_app1(pp); big_app(indent); app(indent);
+ reduce(pp,1,fn_decl,0,1);
+}
+else if (cat1==unop) squash(pp,2,exp,-2,2);
+else if ((cat1==binop || cat1==ubinop) && cat2==exp)
+ squash(pp,3,exp,-2,3);
+else if (cat1==comma && cat2==exp) {
+ big_app2(pp);
+ app(opt); app('9'); big_app1(pp+2); reduce(pp,3,exp,-2,4);
+}
+else if (cat1==lpar && cat2==rpar && cat3==colon) squash(pp+3,1,base,0,5);
+else if (cat1==cast && cat2==colon) squash(pp+2,1,base,0,5);
+else if (cat1==semi) squash(pp,2,stmt,-1,6);
+else if (cat1==colon) {
+ make_underlined (pp); squash(pp,2,tag,-1,7);
+}
+else if (cat1==rbrace) squash(pp,1,stmt,-1,8);
+else if (cat1==lpar && cat2==rpar && (cat3==const_like || cat3==case_like)) {
+ big_app1(pp+2); big_app(' '); big_app1(pp+3); reduce(pp+2,2,rpar,0,9);
+}
+else if (cat1==cast && (cat2==const_like || cat2==case_like)) {
+ big_app1(pp+1); big_app(' '); big_app1(pp+2); reduce(pp+1,2,cast,0,9);
+}
+else if (cat1==exp || cat1==cast) squash(pp,2,exp,-2,10);
+
+@ @<Cases for |lpar|@>=
+if ((cat1==exp||cat1==ubinop) && cat2==rpar) squash(pp,3,exp,-2,11);
+else if (cat1==rpar) {
+ big_app1(pp); app('\\'); app(','); big_app1(pp+1);
+@.\\,@>
+ reduce(pp,2,exp,-2,12);
+}
+else if ((cat1==decl_head || cat1==int_like || cat1==cast) && cat2==rpar)
+ squash(pp,3,cast,-2,13);
+else if ((cat1==decl_head || cat1==int_like || cat1==exp) && cat2==comma) {
+ big_app3(pp); app(opt); app('9'); reduce(pp,3,lpar,-1,14);
+}
+else if (cat1==stmt || cat1==decl) {
+ big_app2(pp); big_app(' '); reduce(pp,2,lpar,-1,15);
+}
+
+@ @<Cases for |unop|@>=
+if (cat1==exp || cat1==int_like) squash(pp,2,exp,-2,16);
+
+@ @<Cases for |ubinop|@>=
+if (cat1==cast && cat2==rpar) {
+ big_app('{'); big_app1(pp); big_app('}'); big_app1(pp+1);
+ reduce(pp,2,cast,-2,17);
+}
+else if (cat1==exp || cat1==int_like) {
+ big_app('{'); big_app1(pp); big_app('}'); big_app1(pp+1);
+ reduce(pp,2,cat1,-2,18);
+}
+else if (cat1==binop) {
+ big_app(math_rel); big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
+ big_app('}'); reduce(pp,2,binop,-1,19);
+}
+
+@ @<Cases for |binop|@>=
+if (cat1==binop) {
+ big_app(math_rel); big_app('{'); big_app1(pp); big_app('}');
+ big_app('{'); big_app1(pp+1); big_app('}');
+ big_app('}'); reduce(pp,2,binop,-1,20);
+}
+
+@ @<Cases for |cast|@>=
+if (cat1==lpar) squash(pp,2,lpar,-1,21);
+else if (cat1==exp) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,21);
+}
+else if (cat1==semi) squash(pp,1,exp,-2,22);
+
+@ @<Cases for |sizeof_like|@>=
+if (cat1==cast) squash(pp,2,exp,-2,23);
+else if (cat1==exp) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,24);
+}
+
+@ @<Cases for |int_like|@>=
+if (cat1==int_like|| cat1==struct_like) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,cat1,-2,25);
+}
+else if (cat1==exp && (cat2==raw_int||cat2==struct_like))
+ squash(pp,2,int_like,-2,26);
+else if (cat1==exp || cat1==ubinop || cat1==colon) {
+ big_app1(pp); big_app(' '); reduce(pp,1,decl_head,-1,27);
+}
+else if (cat1==semi || cat1==binop) squash(pp,1,decl_head,0,28);
+
+@ @<Cases for |public_like|@>=
+if (cat1==colon) squash(pp,2,tag,-1,29);
+else squash(pp,1,int_like,-2,30);
+
+@ @<Cases for |colcol|@>=
+if (cat1==exp||cat1==int_like) {
+ app(qualifier); squash(pp,2,cat1,-2,31);
+}@+else if (cat1==colcol) squash(pp,2,colcol,-1,32);
+
+@ @<Cases for |decl_head|@>=
+if (cat1==comma) {
+ big_app2(pp); big_app(' '); reduce(pp,2,decl_head,-1,33);
+}
+else if (cat1==ubinop) {
+ big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
+ reduce(pp,2,decl_head,-1,34);
+}
+else if (cat1==exp && cat2!=lpar && cat2!=exp && cat2!=cast) {
+ make_underlined(pp+1); squash(pp,2,decl_head,-1,35);
+}
+else if ((cat1==binop||cat1==colon) && cat2==exp && (cat3==comma ||
+ cat3==semi || cat3==rpar))
+ squash(pp,3,decl_head,-1,36);
+else if (cat1==cast) squash(pp,2,decl_head,-1,37);
+else if (cat1==lbrace || cat1==int_like || cat1==decl) {
+ big_app1(pp); big_app(indent); app(indent); reduce(pp,1,fn_decl,0,38);
+}
+else if (cat1==semi) squash(pp,2,decl,-1,39);
+
+@ @<Cases for |decl|@>=
+if (cat1==decl) {
+ big_app1(pp); big_app(force); big_app1(pp+1);
+ reduce(pp,2,decl,-1,40);
+}
+else if (cat1==stmt || cat1==function) {
+ big_app1(pp); big_app(big_force);
+ big_app1(pp+1); reduce(pp,2,cat1,-1,41);
+}
+
+@ @<Cases for |base|@>=
+if (cat1==int_like || cat1==exp) {
+ if (cat2==comma) {
+ big_app1(pp); big_app(' '); big_app2(pp+1);
+ app(opt); app('9'); reduce(pp,3,base,0,42);
+ }
+ else if (cat2==lbrace) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); big_app(' '); big_app1(pp+2);
+ reduce(pp,3,lbrace,-2,43);
+ }
+}
+
+@ @<Cases for |struct_like|@>=
+if (cat1==lbrace) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,struct_head,0,44);
+}
+else if (cat1==exp||cat1==int_like) {
+ if (cat2==lbrace || cat2==semi) {
+ make_underlined(pp+1); make_reserved(pp+1);
+ big_app1(pp); big_app(' '); big_app1(pp+1);
+ if (cat2==semi) reduce(pp,2,decl_head,0,45);
+ else {
+ big_app(' '); big_app1(pp+2);reduce(pp,3,struct_head,0,46);
+ }
+ }
+ else if (cat2==colon) squash(pp+2,1,base,2,47);
+ else if (cat2!=base) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,int_like,-2,48);
+ }
+}
+
+@ @<Cases for |struct_head|@>=
+if ((cat1==decl || cat1==stmt || cat1==function) && cat2==rbrace) {
+ big_app1(pp); big_app(indent); big_app(force); big_app1(pp+1);
+ big_app(outdent); big_app(force); big_app1(pp+2);
+ reduce(pp,3,int_like,-2,49);
+}
+else if (cat1==rbrace) {
+ big_app1(pp); app_str("\\,"); big_app1(pp+1);
+@.\\,@>
+ reduce(pp,2,int_like,-2,50);
+}
+
+@ @<Cases for |fn_decl|@>=
+if (cat1==decl) {
+ big_app1(pp); big_app(force); big_app1(pp+1); reduce(pp,2,fn_decl,0,51);
+}
+else if (cat1==stmt) {
+ big_app1(pp); app(outdent); app(outdent); big_app(force);
+ big_app1(pp+1); reduce(pp,2,function,-1,52);
+}
+
+@ @<Cases for |function|@>=
+if (cat1==function || cat1==decl || cat1==stmt) {
+ big_app1(pp); big_app(big_force); big_app1(pp+1); reduce(pp,2,cat1,-1,53);
+}
+
+@ @<Cases for |lbrace|@>=
+if (cat1==rbrace) {
+ big_app1(pp); app('\\'); app(','); big_app1(pp+1);
+@.\\,@>
+ reduce(pp,2,stmt,-1,54);
+}
+else if ((cat1==stmt||cat1==decl||cat1==function) && cat2==rbrace) {
+ big_app(force); big_app1(pp); big_app(indent); big_app(force);
+ big_app1(pp+1); big_app(force); big_app(backup); big_app1(pp+2);
+ big_app(outdent); big_app(force); reduce(pp,3,stmt,-1,55);
+}
+else if (cat1==exp) {
+ if (cat2==rbrace) squash(pp,3,exp,-2,56);
+ else if (cat2==comma && cat3==rbrace) squash(pp,4,exp,-2,56);
+}
+
+@ @<Cases for |if_like|@>=
+if (cat1==exp) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,if_clause,0,57);
+}
+
+@ @<Cases for |else_like|@>=
+if (cat1==colon) squash(pp+1,1,base,1,58);
+else if (cat1==lbrace) squash(pp,1,else_head,0,59);
+else if (cat1==stmt) {
+ big_app(force); big_app1(pp); big_app(indent); big_app(break_space);
+ big_app1(pp+1); big_app(outdent); big_app(force);
+ reduce(pp,2,stmt,-1,60);
+}
+
+@ @<Cases for |else_head|@>=
+if (cat1==stmt || cat1==exp) {
+ big_app(force); big_app1(pp); big_app(break_space); app(noop);
+ big_app(cancel); big_app1(pp+1); big_app(force);
+ reduce(pp,2,stmt,-1,61);
+}
+
+@ @<Cases for |if_clause|@>=
+if (cat1==lbrace) squash(pp,1,if_head,0,62);
+else if (cat1==stmt) {
+ if (cat2==else_like) {
+ big_app(force); big_app1(pp); big_app(indent); big_app(break_space);
+ big_app1(pp+1); big_app(outdent); big_app(force); big_app1(pp+2);
+ if (cat3==if_like) {
+ big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,63);
+ }@+else reduce(pp,3,else_like,0,64);
+ }
+ else squash(pp,1,else_like,0,65);
+}
+
+@ @<Cases for |if_head|@>=
+if (cat1==stmt || cat1==exp) {
+ if (cat2==else_like) {
+ big_app(force); big_app1(pp); big_app(break_space); app(noop);
+ big_app(cancel); big_app1(pp+1); big_app(force); big_app1(pp+2);
+ if (cat3==if_like) {
+ big_app(' '); big_app1(pp+3); reduce(pp,4,if_like,0,66);
+ }@+else reduce(pp,3,else_like,0,67);
+ }
+ else squash(pp,1,else_head,0,68);
+}
+
+@ @<Cases for |do_like|@>=
+if (cat1==stmt && cat2==else_like && cat3==semi) {
+ big_app1(pp); big_app(break_space); app(noop); big_app(cancel);
+ big_app1(pp+1); big_app(cancel); app(noop); big_app(break_space);
+ big_app2(pp+2); reduce(pp,4,stmt,-1,69);
+}
+
+@ @<Cases for |case_like|@>=
+if (cat1==semi) squash(pp,2,stmt,-1,70);
+else if (cat1==colon) squash(pp,2,tag,-1,71);
+else if (cat1==exp) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,72);
+}
+
+@ @<Cases for |catch_like|@>=
+if (cat1==cast || cat1==exp) {
+ big_app2(pp); big_app(indent); big_app(indent); reduce(pp,2,fn_decl,0,73);
+}
+
+@ @<Cases for |tag|@>=
+if (cat1==tag) {
+ big_app1(pp); big_app(break_space); big_app1(pp+1); reduce(pp,2,tag,-1,74);
+}
+else if (cat1==stmt||cat1==decl||cat1==function) {
+ big_app(force); big_app(backup); big_app1(pp); big_app(break_space);
+ big_app1(pp+1); reduce(pp,2,cat1,-1,75);
+}
+
+@ The user can decide at run-time whether short statements should be
+grouped together on the same line.
+
+@d force_lines flags['f'] /* should each statement be on its own line? */
+@<Cases for |stmt|@>=
+if (cat1==stmt||cat1==decl||cat1==function) {
+ big_app1(pp);
+ if (cat1==function) big_app(big_force);
+ else if (cat1==decl) big_app(big_force);
+ else if (force_lines) big_app(force);
+ else big_app(break_space);
+ big_app1(pp+1); reduce(pp,2,cat1,-1,76);
+}
+
+@ @<Cases for |semi|@>=
+big_app(' '); big_app1(pp); reduce(pp,1,stmt,-1,77);
+
+@ @<Cases for |lproc|@>=
+if (cat1==define_like) make_underlined(pp+2);
+if (cat1==else_like || cat1==if_like ||cat1==define_like)
+ squash(pp,2,lproc,0,78);
+else if (cat1==rproc) {
+ app(inserted); big_app2(pp); reduce(pp,2,insert,-1,79);
+} else if (cat1==exp || cat1==function) {
+ if (cat2==rproc) {
+ app(inserted); big_app1(pp); big_app(' '); big_app2(pp+1);
+ reduce(pp,3,insert,-1,80);
+ }
+ else if (cat2==exp && cat3==rproc && cat1==exp) {
+ app(inserted); big_app1(pp); big_app(' '); big_app1(pp+1); app_str(" \\5");
+@.\\5@>
+ big_app2(pp+2); reduce(pp,4,insert,-1,80);
+ }
+}
+
+@ @<Cases for |section_scrap|@>=
+if (cat1==semi) {
+ big_app2(pp); big_app(force); reduce(pp,2,stmt,-2,81);
+}
+else squash(pp,1,exp,-2,82);
+
+@ @<Cases for |insert|@>=
+if (cat1)
+ squash(pp,2,cat1,0,83);
+
+@ @<Cases for |prelangle|@>=
+init_mathness=cur_mathness=yes_math;
+app('<'); reduce(pp,1,binop,-2,84);
+
+@ @<Cases for |prerangle|@>=
+init_mathness=cur_mathness=yes_math;
+app('>'); reduce(pp,1,binop,-2,85);
+
+@ @<Cases for |langle|@>=
+if (cat1==prerangle) {
+ big_app1(pp); app('\\'); app(','); big_app1(pp+1);
+@.\\,@>
+ reduce(pp,2,cast,-1,86);
+}
+else if (cat1==decl_head || cat1==int_like || cat1==exp) {
+ if (cat2==prerangle) squash(pp,3,cast,-1,87);
+ else if (cat2==comma) {
+ big_app3(pp); app(opt); app('9'); reduce(pp,3,langle,0,88);
+ }
+}
+
+@ @<Cases for |template_like|@>=
+if (cat1==exp && cat2==prelangle) squash(pp+2,1,langle,2,89);
+else if (cat1==exp || cat1==raw_int) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,cat1,-2,90);
+}@+ else squash(pp,1,raw_int,0,91);
+
+@ @<Cases for |new_like|@>=
+if (cat1==lpar && cat2==exp && cat3==rpar) squash(pp,4,new_like,0,92);
+else if (cat1==cast) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,93);
+}
+else if (cat1!=lpar) squash(pp,1,new_exp,0,94);
+
+@ @<Cases for |new_exp|@>=
+if (cat1==int_like || cat1==const_like) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,new_exp,0,95);
+}
+else if (cat1==struct_like && (cat2==exp || cat2==int_like)) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); big_app(' ');
+ big_app1(pp+2); reduce(pp,3,new_exp,0,96);
+}
+else if (cat1==raw_ubin) {
+ big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
+ reduce(pp,2,new_exp,0,97);
+}
+else if (cat1==lpar) squash(pp,1,exp,-2,98);
+else if (cat1==exp) {
+ big_app1(pp); big_app(' '); reduce(pp,1,exp,-2,98);
+}
+else if (cat1!=raw_int && cat1!=struct_like && cat1!=colcol)
+ squash(pp,1,exp,-2,99);
+
+@ @<Cases for |ftemplate|@>=
+if (cat1==prelangle) squash(pp+1,1,langle,1,100);
+else squash(pp,1,exp,-2,101);
+
+@ @<Cases for |for_like|@>=
+if (cat1==exp) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,else_like,-2,102);
+}
+
+@ @<Cases for |raw_ubin|@>=
+if (cat1==const_like) {
+ big_app2(pp); app_str("\\ "); reduce(pp,2,raw_ubin,0,103);
+@.\\\ @>
+} else squash(pp,1,ubinop,-2,104);
+
+@ @<Cases for |const_like|@>=
+squash(pp,1,int_like,-2,105);
+
+@ @<Cases for |raw_int|@>=
+if (cat1==prelangle) squash(pp+1,1,langle,1,106);
+else if (cat1==colcol) squash(pp,2,colcol,-1,107);
+else if (cat1==cast) squash(pp,2,raw_int,0,108);
+else if (cat1==lpar) squash(pp,1,exp,-2,109);
+else if (cat1!=langle) squash(pp,1,int_like,-3,110);
+
+@ @<Cases for |operator_like|@>=
+if (cat1==binop || cat1==unop || cat1==ubinop) {
+ if (cat2==binop) break;
+ big_app1(pp); big_app('{'); big_app1(pp+1); big_app('}');
+ reduce(pp,2,exp,-2,111);
+}
+else if (cat1==new_like || cat1==delete_like) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,112);
+}
+else if (cat1==comma) squash(pp,2,exp,-2,113);
+else if (cat1!=raw_ubin) squash(pp,1,new_exp,0,114);
+
+@ @<Cases for |typedef_like|@>=
+if ((cat1==int_like || cat1==cast) && (cat2==comma || cat2==semi))
+ squash(pp+1,1,exp,-1,115);
+else if (cat1==int_like) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,typedef_like,0,116);
+}
+else if (cat1==exp && cat2!=lpar && cat2!=exp && cat2!=cast) {
+ make_underlined(pp+1); make_reserved(pp+1);
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,typedef_like,0,117);
+}
+else if (cat1==comma) {
+ big_app2(pp); big_app(' '); reduce(pp,2,typedef_like,0,118);
+}
+else if (cat1==semi) squash(pp,2,decl,-1,119);
+else if (cat1==ubinop && (cat2==ubinop || cat2==cast)) {
+ big_app('{'); big_app1(pp+1); big_app('}'); big_app1(pp+2);
+ reduce(pp+1,2,cat2,0,120);
+}
+
+@ @<Cases for |delete_like|@>=
+if (cat1==lpar && cat2==rpar) {
+ big_app2(pp); app('\\'); app(','); big_app1(pp+2);
+@.\\,@>
+ reduce(pp,3,delete_like,0,121);
+}
+else if (cat1==exp) {
+ big_app1(pp); big_app(' '); big_app1(pp+1); reduce(pp,2,exp,-2,122);
+}
+
+@ @<Cases for |question|@>=
+if (cat1==exp && (cat2==colon || cat2==base)) {
+ (pp+2)->mathness=5*yes_math; /* this colon should be in math mode */
+ squash(pp,3,binop,-2,123);
+}
+
+@ Now here's the |reduce| procedure used in our code for productions.
+
+The `|freeze_text|' macro is used to give official status to a token list.
+Before saying |freeze_text|, items are appended to the current token list,
+and we know that the eventual number of this token list will be the current
+value of |text_ptr|. But no list of that number really exists as yet,
+because no ending point for the current list has been
+stored in the |tok_start| array. After saying |freeze_text|, the
+old current token list becomes legitimate, and its number is the current
+value of |text_ptr-1| since |text_ptr| has been increased. The new
+current token list is empty and ready to be appended to.
+Note that |freeze_text| does not check to see that |text_ptr| hasn't gotten
+too large, since it is assumed that this test was done beforehand.
+
+@d freeze_text *(++text_ptr)=tok_ptr
+
+@c
+void
+reduce(j,k,c,d,n)
+scrap_pointer j;
+eight_bits c;
+short k, d, n;
+{
+ scrap_pointer i, i1; /* pointers into scrap memory */
+ j->cat=c; j->trans=text_ptr;
+ j->mathness=4*cur_mathness+init_mathness;
+ freeze_text;
+ if (k>1) {
+ for (i=j+k, i1=j+1; i<=lo_ptr; i++, i1++) {
+ i1->cat=i->cat; i1->trans=i->trans;
+ i1->mathness=i->mathness;
+ }
+ lo_ptr=lo_ptr-k+1;
+ }
+ pp=(pp+d<scrap_base? scrap_base: pp+d);
+ @<Print a snapshot of the scrap list if debugging @>;
+ pp--; /* we next say |pp++| */
+}
+
+@ Here's the |squash| procedure, which
+takes advantage of the simplification that occurs when |k==1|.
+
+@c
+void
+squash(j,k,c,d,n)
+scrap_pointer j;
+eight_bits c;
+short k, d, n;
+{
+ scrap_pointer i; /* pointers into scrap memory */
+ if (k==1) {
+ j->cat=c; pp=(pp+d<scrap_base? scrap_base: pp+d);
+ @<Print a snapshot...@>;
+ pp--; /* we next say |pp++| */
+ return;
+ }
+ for (i=j; i<j+k; i++) big_app1(i);
+ reduce(j,k,c,d,n);
+}
+
+@ And here now is the code that applies productions as long as possible.
+Before applying the production mechanism, we must make sure
+it has good input (at least four scraps, the length of the lhs of the
+longest rules), and that there is enough room in the memory arrays
+to hold the appended tokens and texts. Here we use a very
+conservative test; it's more important to make sure the program
+will still work if we change the production rules (within reason)
+than to squeeze the last bit of space from the memory arrays.
+
+@d safe_tok_incr 20
+@d safe_text_incr 10
+@d safe_scrap_incr 10
+
+@<Reduce the scraps using the productions until no more rules apply@>=
+while (1) {
+ @<Make sure the entries |pp| through |pp+3| of |cat| are defined@>;
+ if (tok_ptr+safe_tok_incr>tok_mem_end) {
+ if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
+ overflow("token");
+ }
+ if (text_ptr+safe_text_incr>tok_start_end) {
+ if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
+ overflow("text");
+ }
+ if (pp>lo_ptr) break;
+ init_mathness=cur_mathness=maybe_math;
+ @<Match a production...@>;
+}
+
+@ If we get to the end of the scrap list, category codes equal to zero are
+stored, since zero does not match anything in a production.
+
+@<Make sure the entries...@>=
+if (lo_ptr<pp+3) {
+ while (hi_ptr<=scrap_ptr && lo_ptr!=pp+3) {
+ (++lo_ptr)->cat=hi_ptr->cat; lo_ptr->mathness=(hi_ptr)->mathness;
+ lo_ptr->trans=(hi_ptr++)->trans;
+ }
+ for (i=lo_ptr+1;i<=pp+3;i++) i->cat=0;
+}
+
+@ If \.{CWEAVE} is being run in debugging mode, the production numbers and
+current stack categories will be printed out when |tracing| is set to 2;
+a sequence of two or more irreducible scraps will be printed out when
+|tracing| is set to 1.
+
+@<Global...@>=
+int tracing; /* can be used to show parsing details */
+
+@ @<Print a snapsh...@>=
+{ scrap_pointer k; /* pointer into |scrap_info| */
+ if (tracing==2) {
+ printf("\n%d:",n);
+ for (k=scrap_base; k<=lo_ptr; k++) {
+ if (k==pp) putxchar('*'); else putxchar(' ');
+ if (k->mathness %4 == yes_math) putchar('+');
+ else if (k->mathness %4 == no_math) putchar('-');
+ print_cat(k->cat);
+ if (k->mathness /4 == yes_math) putchar('+');
+ else if (k->mathness /4 == no_math) putchar('-');
+ }
+ if (hi_ptr<=scrap_ptr) printf("..."); /* indicate that more is coming */
+ }
+}
+
+@ The |translate| function assumes that scraps have been stored in
+positions |scrap_base| through |scrap_ptr| of |cat| and |trans|. It
+applies productions as much as
+possible. The result is a token list containing the translation of
+the given sequence of scraps.
+
+After calling |translate|, we will have |text_ptr+3<=max_texts| and
+|tok_ptr+6<=max_toks|, so it will be possible to create up to three token
+lists with up to six tokens without checking for overflow. Before calling
+|translate|, we should have |text_ptr<max_texts| and |scrap_ptr<max_scraps|,
+since |translate| might add a new text and a new scrap before it checks
+for overflow.
+
+@c
+text_pointer
+translate() /* converts a sequence of scraps */
+{
+ scrap_pointer i, /* index into |cat| */
+ j; /* runs through final scraps */
+ pp=scrap_base; lo_ptr=pp-1; hi_ptr=pp;
+ @<If tracing, print an indication of where we are@>;
+ @<Reduce the scraps...@>;
+ @<Combine the irreducible scraps that remain@>;
+}
+
+@ If the initial sequence of scraps does not reduce to a single scrap,
+we concatenate the translations of all remaining scraps, separated by
+blank spaces, with dollar signs surrounding the translations of scraps
+where appropriate.
+
+@<Combine the irreducible...@>= {
+ @<If semi-tracing, show the irreducible scraps@>;
+ for (j=scrap_base; j<=lo_ptr; j++) {
+ if (j!=scrap_base) app(' ');
+ if (j->mathness % 4 == yes_math) app('$');
+ app1(j);
+ if (j->mathness / 4 == yes_math) app('$');
+ if (tok_ptr+6>tok_mem_end) overflow("token");
+ }
+ freeze_text; return(text_ptr-1);
+}
+
+@ @<If semi-tracing, show the irreducible scraps@>=
+if (lo_ptr>scrap_base && tracing==1) {
+ printf("\nIrreducible scrap sequence in section %d:",section_count);
+@.Irreducible scrap sequence...@>
+ mark_harmless;
+ for (j=scrap_base; j<=lo_ptr; j++) {
+ printf(" "); print_cat(j->cat);
+ }
+}
+
+@ @<If tracing,...@>=
+if (tracing==2) {
+ printf("\nTracing after l. %d:\n",cur_line); mark_harmless;
+@.Tracing after...@>
+ if (loc>buffer+50) {
+ printf("...");
+ term_write(loc-51,51);
+ }
+ else term_write(buffer,loc-buffer);
+}
+
+@* Initializing the scraps.
+If we are going to use the powerful production mechanism just developed, we
+must get the scraps set up in the first place, given a \CEE/ text. A table
+of the initial scraps corresponding to \CEE/ tokens appeared above in the
+section on parsing; our goal now is to implement that table. We shall do this
+by implementing a subroutine called |C_parse| that is analogous to the
+|C_xref| routine used during phase one.
+
+Like |C_xref|, the |C_parse| procedure starts with the current
+value of |next_control| and it uses the operation |next_control=get_next()|
+repeatedly to read \CEE/ text until encountering the next `\.{\v}' or
+`\.{/*}', or until |next_control>=format_code|. The scraps corresponding to
+what it reads are appended into the |cat| and |trans| arrays, and |scrap_ptr|
+is advanced.
+
+@c
+void
+C_parse(spec_ctrl) /* creates scraps from \CEE/ tokens */
+ eight_bits spec_ctrl;
+{
+ int count; /* characters remaining before string break */
+ while (next_control<format_code || next_control==spec_ctrl) {
+ @<Append the scrap appropriate to |next_control|@>;
+ next_control=get_next();
+ if (next_control=='|' || next_control==begin_comment ||
+ next_control==begin_short_comment) return;
+ }
+}
+
+@ The following macro is used to append a scrap whose tokens have just
+been appended:
+
+@d app_scrap(c,b) {
+ (++scrap_ptr)->cat=(c); scrap_ptr->trans=text_ptr;
+ scrap_ptr->mathness=5*(b); /* no no, yes yes, or maybe maybe */
+ freeze_text;
+}
+
+@ @<Append the scr...@>=
+@<Make sure that there is room for the new scraps, tokens, and texts@>;
+switch (next_control) {
+ case section_name:
+ app(section_flag+(int)(cur_section-name_dir));
+ app_scrap(section_scrap,maybe_math);
+ app_scrap(exp,yes_math);@+break;
+ case string: case constant: case verbatim: @<Append a string or constant@>;
+ @+break;
+ case identifier: app_cur_id(1);@+break;
+ case TeX_string: @<Append a \TEX/ string, without forming a scrap@>;@+break;
+ case '/': case '.':
+ app(next_control); app_scrap(binop,yes_math);@+break;
+ case '<': app_str("\\langle");@+app_scrap(prelangle,yes_math);@+break;
+@.\\langle@>
+ case '>': app_str("\\rangle");@+app_scrap(prerangle,yes_math);@+break;
+@.\\rangle@>
+ case '=': app_str("\\K"); app_scrap(binop,yes_math);@+break;
+@.\\K@>
+ case '|': app_str("\\OR"); app_scrap(binop,yes_math);@+break;
+@.\\OR@>
+ case '^': app_str("\\XOR"); app_scrap(binop,yes_math);@+break;
+@.\\XOR@>
+ case '%': app_str("\\MOD"); app_scrap(binop,yes_math);@+break;
+@.\\MOD@>
+ case '!': app_str("\\R"); app_scrap(unop,yes_math);@+break;
+@.\\R@>
+ case '~': app_str("\\CM"); app_scrap(unop,yes_math);@+break;
+@.\\CM@>
+ case '+': case '-': app(next_control); app_scrap(ubinop,yes_math);@+break;
+ case '*': app(next_control); app_scrap(raw_ubin,yes_math);@+break;
+ case '&': app_str("\\AND"); app_scrap(raw_ubin,yes_math);@+break;
+@.\\AND@>
+ case '?': app_str("\\?"); app_scrap(question,yes_math);@+break;
+@.\\?@>
+ case '#': app_str("\\#"); app_scrap(ubinop,yes_math);@+break;
+@.\\\#@>
+ case ignore: case xref_roman: case xref_wildcard:
+ case xref_typewriter: case noop:@+break;
+ case '(': case '[': app(next_control); app_scrap(lpar,maybe_math);@+break;
+ case ')': case ']': app(next_control); app_scrap(rpar,maybe_math);@+break;
+ case '{': app_str("\\{"@q}@>); app_scrap(lbrace,yes_math);@+break;
+@.\\\{@>@q}@>
+ case '}': app_str(@q{@>"\\}"); app_scrap(rbrace,yes_math);@+break;
+@q{@>@.\\\}@>
+ case ',': app(','); app_scrap(comma,yes_math);@+break;
+ case ';': app(';'); app_scrap(semi,maybe_math);@+break;
+ case ':': app(':'); app_scrap(colon,no_math);@+break;@/
+ @t\4@> @<Cases involving nonstandard characters@>@;
+ case thin_space: app_str("\\,"); app_scrap(insert,maybe_math);@+break;
+@.\\,@>
+ case math_break: app(opt); app_str("0");
+ app_scrap(insert,maybe_math);@+break;
+ case line_break: app(force); app_scrap(insert,no_math);@+break;
+ case left_preproc: app(force); app(preproc_line);
+ app_str("\\#"); app_scrap(lproc,no_math);@+break;
+@.\\\#@>
+ case right_preproc: app(force); app_scrap(rproc,no_math);@+break;
+ case big_line_break: app(big_force); app_scrap(insert,no_math);@+break;
+ case no_line_break: app(big_cancel); app(noop); app(break_space);
+ app(noop); app(big_cancel);
+ app_scrap(insert,no_math);@+break;
+ case pseudo_semi: app_scrap(semi,maybe_math);@+break;
+ case macro_arg_open: app_scrap(begin_arg,maybe_math);@+break;
+ case macro_arg_close: app_scrap(end_arg,maybe_math);@+break;
+ case join: app_str("\\J"); app_scrap(insert,no_math);@+break;
+@.\\J@>
+ case output_defs_code: app(force); app_str("\\ATH"); app(force);
+ app_scrap(insert,no_math);@+break;
+@.\\ATH@>
+ default: app(inserted); app(next_control);
+ app_scrap(insert,maybe_math);@+break;
+}
+
+@ @<Make sure that there is room for the new...@>=
+if (scrap_ptr+safe_scrap_incr>scrap_info_end ||
+ tok_ptr+safe_tok_incr>tok_mem_end @| ||
+ text_ptr+safe_text_incr>tok_start_end) {
+ if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
+ if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
+ if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
+ overflow("scrap/token/text");
+}
+
+@ Some nonstandard characters may have entered \.{CWEAVE} by means of
+standard ones. They are converted to \TEX/ control sequences so that it is
+possible to keep \.{CWEAVE} from outputting unusual |char| codes.
+
+@<Cases involving nonstandard...@>=
+case not_eq: app_str("\\I");@+app_scrap(binop,yes_math);@+break;
+@.\\I@>
+case lt_eq: app_str("\\Z");@+app_scrap(binop,yes_math);@+break;
+@.\\Z@>
+case gt_eq: app_str("\\G");@+app_scrap(binop,yes_math);@+break;
+@.\\G@>
+case eq_eq: app_str("\\E");@+app_scrap(binop,yes_math);@+break;
+@.\\E@>
+case and_and: app_str("\\W");@+app_scrap(binop,yes_math);@+break;
+@.\\W@>
+case or_or: app_str("\\V");@+app_scrap(binop,yes_math);@+break;
+@.\\V@>
+case plus_plus: app_str("\\PP");@+app_scrap(unop,yes_math);@+break;
+@.\\PP@>
+case minus_minus: app_str("\\MM");@+app_scrap(unop,yes_math);@+break;
+@.\\MM@>
+case minus_gt: app_str("\\MG");@+app_scrap(binop,yes_math);@+break;
+@.\\MG@>
+case gt_gt: app_str("\\GG");@+app_scrap(binop,yes_math);@+break;
+@.\\GG@>
+case lt_lt: app_str("\\LL");@+app_scrap(binop,yes_math);@+break;
+@.\\LL@>
+case dot_dot_dot: app_str("\\,\\ldots\\,");@+app_scrap(raw_int,yes_math);
+ @+break;
+@.\\,@>
+@.\\ldots@>
+case colon_colon: app_str("\\DC");@+app_scrap(colcol,maybe_math);@+break;
+@.\\DC@>
+case period_ast: app_str("\\PA");@+app_scrap(binop,yes_math);@+break;
+@.\\PA@>
+case minus_gt_ast: app_str("\\MGA");@+app_scrap(binop,yes_math);@+break;
+@.\\MGA@>
+
+@ The following code must use |app_tok| instead of |app| in order to
+protect against overflow. Note that |tok_ptr+1<=max_toks| after |app_tok|
+has been used, so another |app| is legitimate before testing again.
+
+Many of the special characters in a string must be prefixed by `\.\\' so that
+\TEX/ will print them properly.
+@^special string characters@>
+
+@<Append a string or...@>=
+count= -1;
+if (next_control==constant) app_str("\\T{"@q}@>);
+@.\\T@>
+else if (next_control==string) {
+ count=20; app_str("\\.{"@q}@>);
+}
+@.\\.@>
+else app_str("\\vb{"@q}@>);
+@.\\vb@>
+while (id_first<id_loc) {
+ if (count==0) { /* insert a discretionary break in a long string */
+ app_str(@q(@>@q{@>"}\\)\\.{"@q}@>); count=20;
+@q(@>@.\\)@>
+ }
+@^high-bit character handling@>
+ if((eight_bits)(*id_first)>0177) {
+ app_tok(quoted_char);
+ app_tok((eight_bits)(*id_first++));
+ }
+ else {
+ switch (*id_first) {
+ case ' ':case '\\':case '#':case '%':case '$':case '^':
+ case '{': case '}': case '~': case '&': case '_': app('\\'); break;
+@.\\\ @>
+@.\\\\@>
+@.\\\#@>
+@.\\\%@>
+@.\\\$@>
+@.\\\^@>
+@.\\\{@>@q}@>
+@q{@>@.\\\}@>
+@.\\\~@>
+@.\\\&@>
+@.\\\_@>
+ case '@@': if (*(id_first+1)=='@@') id_first++;
+ else err_print("! Double @@ should be used in strings");
+@.Double @@ should be used...@>
+ }
+ app_tok(*id_first++);
+ }
+ count--;
+}
+app(@q{@>'}');
+app_scrap(exp,maybe_math);
+
+@ We do not make the \TEX/ string into a scrap, because there is no
+telling what the user will be putting into it; instead we leave it
+open, to be picked up by the next scrap. If it comes at the end of a
+section, it will be made into a scrap when |finish_C| is called.
+
+There's a known bug here, in cases where an adjacent scrap is
+|prelangle| or |prerangle|. Then the \TEX/ string can disappear
+when the \.{\\langle} or \.{\\rangle} becomes \.{<} or \.{>}.
+For example, if the user writes \.{\v x<@@ty@@>\v}, the \TEX/ string
+\.{\\hbox\{y\}} eventually becomes part of an |insert| scrap, which is combined
+with a |prelangle| scrap and eventually lost. The best way to work around
+this bug is probably to enclose the \.{@@t...@@>} in \.{@@[...@@]} so that
+the \TEX/ string is treated as an expression.
+@^bug, known@>
+
+@<Append a \TEX/ string, without forming a scrap@>=
+app_str("\\hbox{"@q}@>);
+@^high-bit character handling@>
+while (id_first<id_loc)
+ if((eight_bits)(*id_first)>0177) {
+ app_tok(quoted_char);
+ app_tok((eight_bits)(*id_first++));
+ }
+ else {
+ if (*id_first=='@@') id_first++;
+ app_tok(*id_first++);
+ }
+app(@q{@>'}');
+
+@ The function |app_cur_id| appends the current identifier to the
+token list; it also builds a new scrap if |scrapping==1|.
+
+@<Predec...@>=
+void app_cur_id();
+
+@ @c
+void
+app_cur_id(scrapping)
+boolean scrapping; /* are we making this into a scrap? */
+{
+ name_pointer p=id_lookup(id_first,id_loc,normal);
+ if (p->ilk<=custom) { /* not a reserved word */
+ app(id_flag+(int)(p-name_dir));
+ if (scrapping) app_scrap(p->ilk==func_template? ftemplate: exp,
+ p->ilk==custom? yes_math: maybe_math);
+@.\\NULL@>
+ } else {
+ app(res_flag+(int)(p-name_dir));
+ if (scrapping) {
+ if (p->ilk==alfop) app_scrap(ubinop,yes_math)@;
+ else app_scrap(p->ilk,maybe_math);
+ }
+ }
+}
+
+@ When the `\.{\v}' that introduces \CEE/ text is sensed, a call on
+|C_translate| will return a pointer to the \TEX/ translation of
+that text. If scraps exist in |scrap_info|, they are
+unaffected by this translation process.
+
+@c
+text_pointer
+C_translate()
+{
+ text_pointer p; /* points to the translation */
+ scrap_pointer save_base; /* holds original value of |scrap_base| */
+ save_base=scrap_base; scrap_base=scrap_ptr+1;
+ C_parse(section_name); /* get the scraps together */
+ if (next_control!='|') err_print("! Missing '|' after C text");
+@.Missing '|'...@>
+ app_tok(cancel); app_scrap(insert,maybe_math);
+ /* place a |cancel| token as a final ``comment'' */
+ p=translate(); /* make the translation */
+ if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
+ scrap_ptr=scrap_base-1; scrap_base=save_base; /* scrap the scraps */
+ return(p);
+}
+
+@ The |outer_parse| routine is to |C_parse| as |outer_xref|
+is to |C_xref|: It constructs a sequence of scraps for \CEE/ text
+until |next_control>=format_code|. Thus, it takes care of embedded comments.
+
+The token list created from within `\pb' brackets is output as an argument
+to \.{\\PB}, if the user has invoked \.{CWEAVE} with the \.{+e} flag.
+Although \.{cwebmac} ignores \.{\\PB}, other macro packages
+might use it to localize the special meaning of the macros that mark up
+program text.
+
+@d make_pb flags['e']
+
+@c
+void
+outer_parse() /* makes scraps from \CEE/ tokens and comments */
+{
+ int bal; /* brace level in comment */
+ text_pointer p, q; /* partial comments */
+ while (next_control<format_code)
+ if (next_control!=begin_comment && next_control!=begin_short_comment)
+ C_parse(ignore);
+ else {
+ boolean is_long_comment=(next_control==begin_comment);
+ @<Make sure that there is room for the new...@>;
+ app(cancel); app(inserted);
+ if (is_long_comment) app_str("\\C{"@q}@>);
+@.\\C@>
+ else app_str("\\SHC{"@q}@>);
+@.\\SHC@>
+ bal=copy_comment(is_long_comment,1); next_control=ignore;
+ while (bal>0) {
+ p=text_ptr; freeze_text; q=C_translate();
+ /* at this point we have |tok_ptr+6<=max_toks| */
+ app(tok_flag+(int)(p-tok_start));
+ if (make_pb) app_str("\\PB{");
+@.\\PB@>
+ app(inner_tok_flag+(int)(q-tok_start));
+ if (make_pb) app_tok('}');
+ if (next_control=='|') {
+ bal=copy_comment(is_long_comment,bal);
+ next_control=ignore;
+ }
+ else bal=0; /* an error has been reported */
+ }
+ app(force); app_scrap(insert,no_math);
+ /* the full comment becomes a scrap */
+ }
+}
+
+@* Output of tokens.
+So far our programs have only built up multi-layered token lists in
+\.{CWEAVE}'s internal memory; we have to figure out how to get them into
+the desired final form. The job of converting token lists to characters in
+the \TEX/ output file is not difficult, although it is an implicitly
+recursive process. Four main considerations had to be kept in mind when
+this part of \.{CWEAVE} was designed. (a) There are two modes of output:
+|outer| mode, which translates tokens like |force| into line-breaking
+control sequences, and |inner| mode, which ignores them except that blank
+spaces take the place of line breaks. (b) The |cancel| instruction applies
+to adjacent token or tokens that are output, and this cuts across levels
+of recursion since `|cancel|' occurs at the beginning or end of a token
+list on one level. (c) The \TEX/ output file will be semi-readable if line
+breaks are inserted after the result of tokens like |break_space| and
+|force|. (d) The final line break should be suppressed, and there should
+be no |force| token output immediately after `\.{\\Y\\B}'.
+
+@ The output process uses a stack to keep track of what is going on at
+different ``levels'' as the token lists are being written out. Entries on
+this stack have three parts:
+
+\yskip\hang |end_field| is the |tok_mem| location where the token list of a
+particular level will end;
+
+\yskip\hang |tok_field| is the |tok_mem| location from which the next token
+on a particular level will be read;
+
+\yskip\hang |mode_field| is the current mode, either |inner| or |outer|.
+
+\yskip\noindent The current values of these quantities are referred to
+quite frequently, so they are stored in a separate place instead of in the
+|stack| array. We call the current values |cur_end|, |cur_tok|, and
+|cur_mode|.
+
+The global variable |stack_ptr| tells how many levels of output are
+currently in progress. The end of output occurs when an |end_translation|
+token is found, so the stack is never empty except when we first begin the
+output process.
+
+@d inner 0 /* value of |mode| for \CEE/ texts within \TEX/ texts */
+@d outer 1 /* value of |mode| for \CEE/ texts in sections */
+
+@<Typed...@>= typedef int mode;
+typedef struct {
+ token_pointer end_field; /* ending location of token list */
+ token_pointer tok_field; /* present location within token list */
+ boolean mode_field; /* interpretation of control tokens */
+} output_state;
+typedef output_state *stack_pointer;
+
+@ @d cur_end cur_state.end_field /* current ending location in |tok_mem| */
+@d cur_tok cur_state.tok_field /* location of next output token in |tok_mem| */
+@d cur_mode cur_state.mode_field /* current mode of interpretation */
+@d init_stack stack_ptr=stack;cur_mode=outer /* initialize the stack */
+
+@<Global...@>=
+output_state cur_state; /* |cur_end|, |cur_tok|, |cur_mode| */
+output_state stack[stack_size]; /* info for non-current levels */
+stack_pointer stack_ptr; /* first unused location in the output state stack */
+stack_pointer stack_end=stack+stack_size-1; /* end of |stack| */
+stack_pointer max_stack_ptr; /* largest value assumed by |stack_ptr| */
+
+@ @<Set init...@>=
+max_stack_ptr=stack;
+
+@ To insert token-list |p| into the output, the |push_level| subroutine
+is called; it saves the old level of output and gets a new one going.
+The value of |cur_mode| is not changed.
+
+@c
+void
+push_level(p) /* suspends the current level */
+text_pointer p;
+{
+ if (stack_ptr==stack_end) overflow("stack");
+ if (stack_ptr>stack) { /* save current state */
+ stack_ptr->end_field=cur_end;
+ stack_ptr->tok_field=cur_tok;
+ stack_ptr->mode_field=cur_mode;
+ }
+ stack_ptr++;
+ if (stack_ptr>max_stack_ptr) max_stack_ptr=stack_ptr;
+ cur_tok=*p; cur_end=*(p+1);
+}
+
+@ Conversely, the |pop_level| routine restores the conditions that were in
+force when the current level was begun. This subroutine will never be
+called when |stack_ptr==1|.
+
+@c
+void
+pop_level()
+{
+ cur_end=(--stack_ptr)->end_field;
+ cur_tok=stack_ptr->tok_field; cur_mode=stack_ptr->mode_field;
+}
+
+@ The |get_output| function returns the next byte of output that is not a
+reference to a token list. It returns the values |identifier| or |res_word|
+or |section_code| if the next token is to be an identifier (typeset in
+italics), a reserved word (typeset in boldface), or a section name (typeset
+by a complex routine that might generate additional levels of output).
+In these cases |cur_name| points to the identifier or section name in
+question.
+
+@<Global...@>=
+name_pointer cur_name;
+
+@ @d res_word 0201 /* returned by |get_output| for reserved words */
+@d section_code 0200 /* returned by |get_output| for section names */
+
+@c
+eight_bits
+get_output() /* returns the next token of output */
+{
+ sixteen_bits a; /* current item read from |tok_mem| */
+ restart: while (cur_tok==cur_end) pop_level();
+ a=*(cur_tok++);
+ if (a>=0400) {
+ cur_name=a % id_flag + name_dir;
+ switch (a / id_flag) {
+ case 2: return(res_word); /* |a==res_flag+cur_name| */
+ case 3: return(section_code); /* |a==section_flag+cur_name| */
+ case 4: push_level(a % id_flag + tok_start); goto restart;
+ /* |a==tok_flag+cur_name| */
+ case 5: push_level(a % id_flag + tok_start); cur_mode=inner; goto restart;
+ /* |a==inner_tok_flag+cur_name| */
+ default: return(identifier); /* |a==id_flag+cur_name| */
+ }
+ }
+ return(a);
+}
+
+@ The real work associated with token output is done by |make_output|.
+This procedure appends an |end_translation| token to the current token list,
+and then it repeatedly calls |get_output| and feeds characters to the output
+buffer until reaching the |end_translation| sentinel. It is possible for
+|make_output| to be called recursively, since a section name may include
+embedded \CEE/ text; however, the depth of recursion never exceeds one
+level, since section names cannot be inside of section names.
+
+A procedure called |output_C| does the scanning, translation, and
+output of \CEE/ text within `\pb' brackets, and this procedure uses
+|make_output| to output the current token list. Thus, the recursive call
+of |make_output| actually occurs when |make_output| calls |output_C|
+while outputting the name of a section.
+@^recursion@>
+
+@c
+void
+output_C() /* outputs the current token list */
+{
+ token_pointer save_tok_ptr;
+ text_pointer save_text_ptr;
+ sixteen_bits save_next_control; /* values to be restored */
+ text_pointer p; /* translation of the \CEE/ text */
+ save_tok_ptr=tok_ptr; save_text_ptr=text_ptr;
+ save_next_control=next_control; next_control=ignore; p=C_translate();
+ app(inner_tok_flag+(int)(p-tok_start));
+ if (make_pb) {
+ out_str("\\PB{"); make_output(); out('}');
+@.\\PB@>
+ }@+else make_output(); /* output the list */
+ if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
+ if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
+ text_ptr=save_text_ptr; tok_ptr=save_tok_ptr; /* forget the tokens */
+ next_control=save_next_control; /* restore |next_control| to original state */
+}
+
+@ Here is \.{CWEAVE}'s major output handler.
+
+@<Predecl...@>=
+void make_output();
+
+@ @c
+void
+make_output() /* outputs the equivalents of tokens */
+{
+ eight_bits a, /* current output byte */
+ b; /* next output byte */
+ int c; /* count of |indent| and |outdent| tokens */
+ char scratch[longest_name]; /* scratch area for section names */
+ char *k, *k_limit; /* indices into |scratch| */
+ char *j; /* index into |buffer| */
+ char *p; /* index into |byte_mem| */
+ char delim; /* first and last character of string being copied */
+ char *save_loc, *save_limit; /* |loc| and |limit| to be restored */
+ name_pointer cur_section_name; /* name of section being output */
+ boolean save_mode; /* value of |cur_mode| before a sequence of breaks */
+ app(end_translation); /* append a sentinel */
+ freeze_text; push_level(text_ptr-1);
+ while (1) {
+ a=get_output();
+ reswitch: switch(a) {
+ case end_translation: return;
+ case identifier: case res_word: @<Output an identifier@>; break;
+ case section_code: @<Output a section name@>; break;
+ case math_rel: out_str("\\MRL{"@q}@>);
+@.\\MRL@>
+ case noop: case inserted: break;
+ case cancel: case big_cancel: c=0; b=a;
+ while (1) {
+ a=get_output();
+ if (a==inserted) continue;
+ if ((a<indent && !(b==big_cancel&&a==' ')) || a>big_force) break;
+ if (a==indent) c++; else if (a==outdent) c--;
+ else if (a==opt) a=get_output();
+ }
+ @<Output saved |indent| or |outdent| tokens@>;
+ goto reswitch;
+ case indent: case outdent: case opt: case backup: case break_space:
+ case force: case big_force: case preproc_line: @<Output a control,
+ look ahead in case of line breaks, possibly |goto reswitch|@>; break;
+ case quoted_char: out(*(cur_tok++));
+ case qualifier: break;
+ default: out(a); /* otherwise |a| is an ordinary character */
+ }
+ }
+}
+
+@ An identifier of length one does not have to be enclosed in braces, and it
+looks slightly better if set in a math-italic font instead of a (slightly
+narrower) text-italic font. Thus we output `\.{\\\v}\.{a}' but
+`\.{\\\\\{aa\}}'.
+
+@<Output an identifier@>=
+out('\\');
+if (a==identifier) {
+ if (cur_name->ilk==custom && !doing_format) {
+ custom_out:
+ for (p=cur_name->byte_start;p<(cur_name+1)->byte_start;p++)
+ out(*p=='_'? 'x': *p=='$'? 'X': *p);
+ break;
+ } else if (is_tiny(cur_name)) out('|')@;
+@.\\|@>
+ else { delim='.';
+ for (p=cur_name->byte_start;p<(cur_name+1)->byte_start;p++)
+ if (xislower(*p)) { /* not entirely uppercase */
+ delim='\\'; break;
+ }
+ out(delim);
+ }
+@.\\\\@>
+@.\\.@>
+}@+else if (cur_name->ilk==alfop) {
+ out('X');
+ goto custom_out;
+}@+else out('&'); /* |a==res_word| */
+@.\\\&@>
+if (is_tiny(cur_name)) {
+ if (isxalpha((cur_name->byte_start)[0]))
+ out('\\');
+ out((cur_name->byte_start)[0]);
+}
+else out_name(cur_name,1);
+
+@ The current mode does not affect the behavior of \.{CWEAVE}'s output routine
+except when we are outputting control tokens.
+
+@<Output a control...@>=
+if (a<break_space || a==preproc_line) {
+ if (cur_mode==outer) {
+ out('\\'); out(a-cancel+'0');
+@.\\1@>
+@.\\2@>
+@.\\3@>
+@.\\4@>
+@.\\8@>
+ if (a==opt) {
+ b=get_output(); /* |opt| is followed by a digit */
+ if (b!='0' || force_lines==0) out(b)@;
+ else out_str("{-1}"); /* |force_lines| encourages more \.{@@\v} breaks */
+ }
+ } else if (a==opt) b=get_output(); /* ignore digit following |opt| */
+ }
+else @<Look ahead for strongest line break, |goto reswitch|@>
+
+@ If several of the tokens |break_space|, |force|, |big_force| occur in a
+row, possibly mixed with blank spaces (which are ignored),
+the largest one is used. A line break also occurs in the output file,
+except at the very end of the translation. The very first line break
+is suppressed (i.e., a line break that follows `\.{\\Y\\B}').
+
+@<Look ahead for st...@>= {
+ b=a; save_mode=cur_mode; c=0;
+ while (1) {
+ a=get_output();
+ if (a==inserted) continue;
+ if (a==cancel || a==big_cancel) {
+ @<Output saved |indent| or |outdent| tokens@>;
+ goto reswitch; /* |cancel| overrides everything */
+ }
+ if ((a!=' ' && a<indent) || a==backup || a>big_force) {
+ if (save_mode==outer) {
+ if (out_ptr>out_buf+3 && strncmp(out_ptr-3,"\\Y\\B",4)==0)
+ goto reswitch;
+ @<Output saved |indent| or |outdent| tokens@>;
+ out('\\'); out(b-cancel+'0');
+@.\\5@>
+@.\\6@>
+@.\\7@>
+ if (a!=end_translation) finish_line();
+ }
+ else if (a!=end_translation && cur_mode==inner) out(' ');
+ goto reswitch;
+ }
+ if (a==indent) c++;
+ else if (a==outdent) c--;
+ else if (a==opt) a=get_output();
+ else if (a>b) b=a; /* if |a==' '| we have |a<b| */
+ }
+}
+
+@ @<Output saved...@>=
+ for (;c>0;c--) out_str("\\1");
+@.\\1@>
+ for (;c<0;c++) out_str("\\2");
+@.\\2@>
+
+@ The remaining part of |make_output| is somewhat more complicated. When we
+output a section name, we may need to enter the parsing and translation
+routines, since the name may contain \CEE/ code embedded in
+\pb\ constructions. This \CEE/ code is placed at the end of the active
+input buffer and the translation process uses the end of the active
+|tok_mem| area.
+
+@<Output a section name@>= {
+ out_str("\\X");
+@.\\X@>
+ cur_xref=(xref_pointer)cur_name->xref;
+ if (cur_xref->num==file_flag) {an_output=1; cur_xref=cur_xref->xlink;}
+ else an_output=0;
+ if (cur_xref->num>=def_flag) {
+ out_section(cur_xref->num-def_flag);
+ if (phase==3) {
+ cur_xref=cur_xref->xlink;
+ while (cur_xref->num>=def_flag) {
+ out_str(", ");
+ out_section(cur_xref->num-def_flag);
+ cur_xref=cur_xref->xlink;
+ }
+ }
+ }
+ else out('0'); /* output the section number, or zero if it was undefined */
+ out(':');
+ if (an_output) out_str("\\.{"@q}@>);
+@.\\.@>
+ @<Output the text of the section name@>;
+ if (an_output) out_str(@q{@>" }");
+ out_str("\\X");
+}
+
+@ @<Output the text...@>=
+sprint_section_name(scratch,cur_name);
+k=scratch;
+k_limit=scratch+strlen(scratch);
+cur_section_name=cur_name;
+while (k<k_limit) {
+ b=*(k++);
+ if (b=='@@') @<Skip next character, give error if not `\.{@@}'@>;
+ if (an_output)
+ switch (b) {
+ case ' ':case '\\':case '#':case '%':case '$':case '^':
+ case '{': case '}': case '~': case '&': case '_':
+ out('\\'); /* falls through */
+@.\\\ @>
+@.\\\\@>
+@.\\\#@>
+@.\\\%@>
+@.\\\$@>
+@.\\\^@>
+@.\\\{@>@q}@>
+@q{@>@.\\\}@>
+@.\\\~@>
+@.\\\&@>
+@.\\\_@>
+ default: out(b);
+ }
+ else if (b!='|') out(b)@;
+ else {
+ @<Copy the \CEE/ text into the |buffer| array@>;
+ save_loc=loc; save_limit=limit; loc=limit+2; limit=j+1;
+ *limit='|'; output_C();
+ loc=save_loc; limit=save_limit;
+ }
+}
+
+@ @<Skip next char...@>=
+if (*k++!='@@') {
+ printf("\n! Illegal control code in section name: <");
+@.Illegal control code...@>
+ print_section_name(cur_section_name); printf("> "); mark_error;
+}
+
+@ The \CEE/ text enclosed in \pb\ should not contain `\.{\v}' characters,
+except within strings. We put a `\.{\v}' at the front of the buffer, so that an
+error message that displays the whole buffer will look a little bit sensible.
+The variable |delim| is zero outside of strings, otherwise it
+equals the delimiter that began the string being copied.
+
+@<Copy the \CEE/ text into...@>=
+j=limit+1; *j='|'; delim=0;
+while (1) {
+ if (k>=k_limit) {
+ printf("\n! C text in section name didn't end: <");
+@.C text...didn't end@>
+ print_section_name(cur_section_name); printf("> "); mark_error; break;
+ }
+ b=*(k++);
+ if (b=='@@' || (b=='\\' && delim!=0))
+ @<Copy a quoted character into the buffer@>@;
+ else {
+ if (b=='\'' || b=='"')
+ if (delim==0) delim=b;
+ else if (delim==b) delim=0;
+ if (b!='|' || delim!=0) {
+ if (j>buffer+long_buf_size-3) overflow("buffer");
+ *(++j)=b;
+ }
+ else break;
+ }
+}
+
+@ @<Copy a quoted char...@>= {
+ if (j>buffer+long_buf_size-4) overflow("buffer");
+ *(++j)=b; *(++j)=*(k++);
+}
+
+@** Phase two processing.
+We have assembled enough pieces of the puzzle in order to be ready to specify
+the processing in \.{CWEAVE}'s main pass over the source file. Phase two
+is analogous to phase one, except that more work is involved because we must
+actually output the \TEX/ material instead of merely looking at the
+\.{CWEB} specifications.
+
+@<Predecl...@>=
+void phase_two();
+
+@ @c
+void
+phase_two() {
+reset_input(); if (show_progress) printf("\nWriting the output file...");
+@.Writing the output file...@>
+section_count=0; format_visible=1; copy_limbo();
+finish_line(); flush_buffer(out_buf,0,0); /* insert a blank line, it looks nice */
+while (!input_has_ended) @<Translate the current section@>;
+}
+
+@ The output file will contain the control sequence \.{\\Y} between non-null
+sections of a section, e.g., between the \TEX/ and definition parts if both
+are nonempty. This puts a little white space between the parts when they are
+printed. However, we don't want \.{\\Y} to occur between two definitions
+within a single section. The variables |out_line| or |out_ptr| will
+change if a section is non-null, so the following macros `|save_position|'
+and `|emit_space_if_needed|' are able to handle the situation:
+
+@d save_position save_line=out_line; save_place=out_ptr
+@d emit_space_if_needed if (save_line!=out_line || save_place!=out_ptr)
+ out_str("\\Y");
+ space_checked=1
+@.\\Y@>
+
+@<Global...@>=
+int save_line; /* former value of |out_line| */
+char *save_place; /* former value of |out_ptr| */
+int sec_depth; /* the integer, if any, following \.{@@*} */
+boolean space_checked; /* have we done |emit_space_if_needed|? */
+boolean format_visible; /* should the next format declaration be output? */
+boolean doing_format=0; /* are we outputting a format declaration? */
+boolean group_found=0; /* has a starred section occurred? */
+
+@ @<Translate the current section@>= {
+ section_count++;
+ @<Output the code for the beginning of a new section@>;
+ save_position;
+ @<Translate the \TEX/ part of the current section@>;
+ @<Translate the definition part of the current section@>;
+ @<Translate the \CEE/ part of the current section@>;
+ @<Show cross-references to this section@>;
+ @<Output the code for the end of a section@>;
+}
+
+@ Sections beginning with the \.{CWEB} control sequence `\.{@@\ }' start in the
+output with the \TEX/ control sequence `\.{\\M}', followed by the section
+number. Similarly, `\.{@@*}' sections lead to the control sequence `\.{\\N}'.
+In this case there's an additional parameter, representing one plus the
+specified depth, immediately after the \.{\\N}.
+If the section has changed, we put \.{\\*} just after the section number.
+
+@<Output the code for the beginning...@>=
+if (*(loc-1)!='*') out_str("\\M");
+@.\\M@>
+else {
+ while (*loc == ' ') loc++;
+ if (*loc=='*') { /* ``top'' level */
+ sec_depth = -1;
+ loc++;
+ }
+ else {
+ for (sec_depth=0; xisdigit(*loc);loc++)
+ sec_depth = sec_depth*10 + (*loc) -'0';
+ }
+ while (*loc == ' ') loc++; /* remove spaces before group title */
+ group_found=1;
+ out_str("\\N");
+@.\\N@>
+ {@+ char s[32];@+sprintf(s,"{%d}",sec_depth+1);@+out_str(s);@+}
+ if (show_progress)
+ printf("*%d",section_count); update_terminal; /* print a progress report */
+}
+out_str("{");out_section(section_count); out_str("}");
+
+@ In the \TEX/ part of a section, we simply copy the source text, except that
+index entries are not copied and \CEE/ text within \pb\ is translated.
+
+@<Translate the \T...@>= do {
+ next_control=copy_TeX();
+ switch (next_control) {
+ case '|': init_stack; output_C(); break;
+ case '@@': out('@@'); break;
+ case TeX_string: case noop:
+ case xref_roman: case xref_wildcard: case xref_typewriter:
+ case section_name: loc-=2; next_control=get_next(); /* skip to \.{@@>} */
+ if (next_control==TeX_string)
+ err_print("! TeX string should be in C text only"); break;
+@.TeX string should be...@>
+ case thin_space: case math_break: case ord:
+ case line_break: case big_line_break: case no_line_break: case join:
+ case pseudo_semi: case macro_arg_open: case macro_arg_close:
+ case output_defs_code:
+ err_print("! You can't do that in TeX text"); break;
+@.You can't do that...@>
+ }
+} while (next_control<format_code);
+
+@ When we get to the following code we have |next_control>=format_code|, and
+the token memory is in its initial empty state.
+
+@<Translate the d...@>=
+space_checked=0;
+while (next_control<=definition) { /* |format_code| or |definition| */
+ init_stack;
+ if (next_control==definition) @<Start a macro definition@>@;
+ else @<Start a format definition@>;
+ outer_parse(); finish_C(format_visible); format_visible=1;
+ doing_format=0;
+}
+
+@ The |finish_C| procedure outputs the translation of the current
+scraps, preceded by the control sequence `\.{\\B}' and followed by the
+control sequence `\.{\\par}'. It also restores the token and scrap
+memories to their initial empty state.
+
+A |force| token is appended to the current scraps before translation
+takes place, so that the translation will normally end with \.{\\6} or
+\.{\\7} (the \TEX/ macros for |force| and |big_force|). This \.{\\6} or
+\.{\\7} is replaced by the concluding \.{\\par} or by \.{\\Y\\par}.
+
+@<Predecl...@>=
+void finish_C();
+
+@ @c
+void
+finish_C(visible) /* finishes a definition or a \CEE/ part */
+ boolean visible; /* nonzero if we should produce \TEX/ output */
+{
+ text_pointer p; /* translation of the scraps */
+ if (visible) {
+ out_str("\\B"); app_tok(force); app_scrap(insert,no_math);
+ p=translate();
+@.\\B@>
+ app(tok_flag+(int)(p-tok_start)); make_output(); /* output the list */
+ if (out_ptr>out_buf+1)
+ if (*(out_ptr-1)=='\\')
+@.\\6@>
+@.\\7@>
+@.\\Y@>
+ if (*out_ptr=='6') out_ptr-=2;
+ else if (*out_ptr=='7') *out_ptr='Y';
+ out_str("\\par"); finish_line();
+ }
+ if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
+ if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
+ if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
+ tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrap_ptr=scrap_info;
+ /* forget the tokens and the scraps */
+}
+
+@ Keeping in line with the conventions of the \CEE/ preprocessor (and
+otherwise contrary to the rules of \.{CWEB}) we distinguish here
+between the case that `\.(' immediately follows an identifier and the
+case that the two are separated by a space. In the latter case, and
+if the identifier is not followed by `\.(' at all, the replacement
+text starts immediately after the identifier. In the former case,
+it starts after we scan the matching `\.)'.
+
+@<Start a macro...@>= {
+ if (save_line!=out_line || save_place!=out_ptr || space_checked) app(backup);
+ if(!space_checked){emit_space_if_needed;save_position;}
+ app_str("\\D"); /* this will produce `\&{define }' */
+@.\\D@>
+ if ((next_control=get_next())!=identifier)
+ err_print("! Improper macro definition");
+@.Improper macro definition@>
+ else {
+ app('$'); app_cur_id(0);
+ if (*loc=='(')
+ reswitch: switch (next_control=get_next()) {
+ case '(': case ',': app(next_control); goto reswitch;
+ case identifier: app_cur_id(0); goto reswitch;
+ case ')': app(next_control); next_control=get_next(); break;
+ default: err_print("! Improper macro definition"); break;
+ }
+ else next_control=get_next();
+ app_str("$ "); app(break_space);
+ app_scrap(dead,no_math); /* scrap won't take part in the parsing */
+ }
+}
+
+@ @<Start a format...@>= {
+ doing_format=1;
+ if(*(loc-1)=='s' || *(loc-1)=='S') format_visible=0;
+ if(!space_checked){emit_space_if_needed;save_position;}
+ app_str("\\F"); /* this will produce `\&{format }' */
+@.\\F@>
+ next_control=get_next();
+ if (next_control==identifier) {
+ app(id_flag+(int)(id_lookup(id_first, id_loc,normal)-name_dir));
+ app(' ');
+ app(break_space); /* this is syntactically separate from what follows */
+ next_control=get_next();
+ if (next_control==identifier) {
+ app(id_flag+(int)(id_lookup(id_first, id_loc,normal)-name_dir));
+ app_scrap(exp,maybe_math); app_scrap(semi,maybe_math);
+ next_control=get_next();
+ }
+ }
+ if (scrap_ptr!=scrap_info+2) err_print("! Improper format definition");
+@.Improper format definition@>
+}
+
+@ Finally, when the \TEX/ and definition parts have been treated, we have
+|next_control>=begin_C|. We will make the global variable |this_section|
+point to the current section name, if it has a name.
+
+@<Global...@>=
+name_pointer this_section; /* the current section name, or zero */
+
+@ @<Translate the \CEE/...@>=
+this_section=name_dir;
+if (next_control<=section_name) {
+ emit_space_if_needed; init_stack;
+ if (next_control==begin_C) next_control=get_next();
+ else {
+ this_section=cur_section;
+ @<Check that '=' or '==' follows this section name, and
+ emit the scraps to start the section definition@>;
+ }
+ while (next_control<=section_name) {
+ outer_parse();
+ @<Emit the scrap for a section name if present@>;
+ }
+ finish_C(1);
+}
+
+@ The title of the section and an $\E$ or $\mathrel+\E$ are made
+into a scrap that should not take part in the parsing.
+
+@<Check that '='...@>=
+do next_control=get_next();
+ while (next_control=='+'); /* allow optional `\.{+=}' */
+if (next_control!='=' && next_control!=eq_eq)
+ err_print("! You need an = sign after the section name");
+@.You need an = sign...@>
+ else next_control=get_next();
+if (out_ptr>out_buf+1 && *out_ptr=='Y' && *(out_ptr-1)=='\\') app(backup);
+ /* the section name will be flush left */
+@.\\Y@>
+app(section_flag+(int)(this_section-name_dir));
+cur_xref=(xref_pointer)this_section->xref;
+if(cur_xref->num==file_flag) cur_xref=cur_xref->xlink;
+app_str("${}");
+if (cur_xref->num!=section_count+def_flag) {
+ app_str("\\mathrel+"); /*section name is multiply defined*/
+ this_section=name_dir; /*so we won't give cross-reference info here*/
+}
+app_str("\\E"); /* output an equivalence sign */
+@.\\E@>
+app_str("{}$");
+app(force); app_scrap(dead,no_math);
+ /* this forces a line break unless `\.{@@+}' follows */
+
+@ @<Emit the scrap...@>=
+if (next_control<section_name) {
+ err_print("! You can't do that in C text");
+@.You can't do that...@>
+ next_control=get_next();
+}
+else if (next_control==section_name) {
+ app(section_flag+(int)(cur_section-name_dir));
+ app_scrap(section_scrap,maybe_math);
+ next_control=get_next();
+}
+
+@ Cross references relating to a named section are given
+after the section ends.
+
+@<Show cross...@>=
+if (this_section>name_dir) {
+ cur_xref=(xref_pointer)this_section->xref;
+ if (cur_xref->num==file_flag){an_output=1;cur_xref=cur_xref->xlink;}
+ else an_output=0;
+ if (cur_xref->num>def_flag)
+ cur_xref=cur_xref->xlink; /* bypass current section number */
+ footnote(def_flag); footnote(cite_flag); footnote(0);
+}
+
+@ The |footnote| procedure gives cross-reference information about
+multiply defined section names (if the |flag| parameter is
+|def_flag|), or about references to a section name
+(if |flag==cite_flag|), or to its uses (if |flag==0|). It assumes that
+|cur_xref| points to the first cross-reference entry of interest, and it
+leaves |cur_xref| pointing to the first element not printed. Typical outputs:
+`\.{\\A101.}'; `\.{\\Us 370\\ET1009.}';
+`\.{\\As 8, 27\\*\\ETs64.}'.
+
+Note that the output of \.{CWEAVE} is not English-specific; users may
+supply new definitions for the macros \.{\\A}, \.{\\As}, etc.
+
+@<Predecl...@>=
+void footnote();
+
+@ @c
+void
+footnote(flag) /* outputs section cross-references */
+sixteen_bits flag;
+{
+ xref_pointer q; /* cross-reference pointer variable */
+ if (cur_xref->num<=flag) return;
+ finish_line(); out('\\');
+@.\\A@>
+@.\\Q@>
+@.\\U@>
+ out(flag==0? 'U': flag==cite_flag? 'Q': 'A');
+ @<Output all the section numbers on the reference list |cur_xref|@>;
+ out('.');
+}
+
+@ The following code distinguishes three cases, according as the number
+of cross-references is one, two, or more than two. Variable |q| points
+to the first cross-reference, and the last link is a zero.
+
+@<Output all the section numbers...@>=
+q=cur_xref; if (q->xlink->num>flag) out('s'); /* plural */
+while (1) {
+ out_section(cur_xref->num-flag);
+ cur_xref=cur_xref->xlink; /* point to the next cross-reference to output */
+ if (cur_xref->num<=flag) break;
+ if (cur_xref->xlink->num>flag) out_str(", "); /* not the last */
+ else {out_str("\\ET"); /* the last */
+@.\\ET@>
+ if (cur_xref != q->xlink) out('s'); /* the last of more than two */
+ }
+}
+
+@ @<Output the code for the end of a section@>=
+out_str("\\fi"); finish_line();
+@.\\fi@>
+flush_buffer(out_buf,0,0); /* insert a blank line, it looks nice */
+
+@** Phase three processing.
+We are nearly finished! \.{CWEAVE}'s only remaining task is to write out the
+index, after sorting the identifiers and index entries.
+
+If the user has set the |no_xref| flag (the \.{-x} option on the command line),
+just finish off the page, omitting the index, section name list, and table of
+contents.
+
+@<Predecl...@>=
+void phase_three();
+
+@ @c
+void
+phase_three() {
+if (no_xref) {
+ finish_line();
+ out_str("\\end");
+@.\\end@>
+ finish_line();
+}
+else {
+ phase=3; if (show_progress) printf("\nWriting the index...");
+@.Writing the index...@>
+ finish_line();
+ if ((idx_file=fopen(idx_file_name,"w"))==NULL)
+ fatal("! Cannot open index file ",idx_file_name);
+@.Cannot open index file@>
+ if (change_exists) {
+ @<Tell about changed sections@>; finish_line(); finish_line();
+ }
+ out_str("\\inx"); finish_line();
+@.\\inx@>
+ active_file=idx_file; /* change active file to the index file */
+ @<Do the first pass of sorting@>;
+ @<Sort and output the index@>;
+ finish_line(); fclose(active_file); /* finished with |idx_file| */
+ active_file=tex_file; /* switch back to |tex_file| for a tic */
+ out_str("\\fin"); finish_line();
+@.\\fin@>
+ if ((scn_file=fopen(scn_file_name,"w"))==NULL)
+ fatal("! Cannot open section file ",scn_file_name);
+@.Cannot open section file@>
+ active_file=scn_file; /* change active file to section listing file */
+ @<Output all the section names@>;
+ finish_line(); fclose(active_file); /* finished with |scn_file| */
+ active_file=tex_file;
+ if (group_found) out_str("\\con");@+else out_str("\\end");
+@.\\con@>
+@.\\end@>
+ finish_line();
+ fclose(active_file);
+}
+if (show_happiness) printf("\nDone.");
+check_complete(); /* was all of the change file used? */
+}
+
+@ Just before the index comes a list of all the changed sections, including
+the index section itself.
+
+@<Global...@>=
+sixteen_bits k_section; /* runs through the sections */
+
+@ @<Tell about changed sections@>= {
+ /* remember that the index is already marked as changed */
+ k_section=0;
+ while (!changed_section[++k_section]);
+ out_str("\\ch ");
+@.\\ch@>
+ out_section(k_section);
+ while (k_section<section_count) {
+ while (!changed_section[++k_section]);
+ out_str(", "); out_section(k_section);
+ }
+ out('.');
+}
+
+@ A left-to-right radix sorting method is used, since this makes it easy to
+adjust the collating sequence and since the running time will be at worst
+proportional to the total length of all entries in the index. We put the
+identifiers into 102 different lists based on their first characters.
+(Uppercase letters are put into the same list as the corresponding lowercase
+letters, since we want to have `$t<\\{TeX}<\&{to}$'.) The
+list for character |c| begins at location |bucket[c]| and continues through
+the |blink| array.
+
+@<Global...@>=
+name_pointer bucket[256];
+name_pointer next_name; /* successor of |cur_name| when sorting */
+name_pointer blink[max_names]; /* links in the buckets */
+
+@ To begin the sorting, we go through all the hash lists and put each entry
+having a nonempty cross-reference list into the proper bucket.
+
+@<Do the first pass...@>= {
+int c;
+for (c=0; c<=255; c++) bucket[c]=NULL;
+for (h=hash; h<=hash_end; h++) {
+ next_name=*h;
+ while (next_name) {
+ cur_name=next_name; next_name=cur_name->link;
+ if (cur_name->xref!=(char*)xmem) {
+ c=(eight_bits)((cur_name->byte_start)[0]);
+ if (xisupper(c)) c=tolower(c);
+ blink[cur_name-name_dir]=bucket[c]; bucket[c]=cur_name;
+ }
+ }
+}
+}
+
+@ During the sorting phase we shall use the |cat| and |trans| arrays from
+\.{CWEAVE}'s parsing algorithm and rename them |depth| and |head|. They now
+represent a stack of identifier lists for all the index entries that have
+not yet been output. The variable |sort_ptr| tells how many such lists are
+present; the lists are output in reverse order (first |sort_ptr|, then
+|sort_ptr-1|, etc.). The |j|th list starts at |head[j]|, and if the first
+|k| characters of all entries on this list are known to be equal we have
+|depth[j]==k|.
+
+@ @<Rest of |trans_plus| union@>=
+name_pointer Head;
+
+@ @d depth cat /* reclaims memory that is no longer needed for parsing */
+@d head trans_plus.Head /* ditto */
+@f sort_pointer int
+@d sort_pointer scrap_pointer /* ditto */
+@d sort_ptr scrap_ptr /* ditto */
+@d max_sorts max_scraps /* ditto */
+
+@<Global...@>=
+eight_bits cur_depth; /* depth of current buckets */
+char *cur_byte; /* index into |byte_mem| */
+sixteen_bits cur_val; /* current cross-reference number */
+sort_pointer max_sort_ptr; /* largest value of |sort_ptr| */
+
+@ @<Set init...@>=
+max_sort_ptr=scrap_info;
+
+@ The desired alphabetic order is specified by the |collate| array; namely,
+$|collate|[0]<|collate|[1]<\cdots<|collate|[100]$.
+
+@<Global...@>=
+eight_bits collate[102+128]; /* collation order */
+@^high-bit character handling@>
+
+@ We use the order $\hbox{null}<\.\ <\hbox{other characters}<{}$\.\_${}<
+\.A=\.a<\cdots<\.Z=\.z<\.0<\cdots<\.9.$ Warning: The collation mapping
+needs to be changed if ASCII code is not being used.
+@^ASCII code dependencies@>
+@^high-bit character handling@>
+
+We initialize |collate| by copying a few characters at a time, because
+some \CEE/ compilers choke on long strings.
+
+@<Set init...@>=
+collate[0]=0;
+strcpy(collate+1," \1\2\3\4\5\6\7\10\11\12\13\14\15\16\17");
+/* 16 characters + 1 = 17 */
+strcpy(collate+17,"\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37");
+/* 16 characters + 17 = 33 */
+strcpy(collate+33,"!\42#$%&'()*+,-./:;<=>?@@[\\]^`{|}~_");
+/* 32 characters + 33 = 65 */
+strcpy(collate+65,"abcdefghijklmnopqrstuvwxyz0123456789");
+/* (26 + 10) characters + 65 = 101 */
+strcpy(collate+101,"\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217");
+/* 16 characters + 101 = 117 */
+strcpy(collate+117,"\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237");
+/* 16 characters + 117 = 133 */
+strcpy(collate+133,"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257");
+/* 16 characters + 133 = 149 */
+strcpy(collate+149,"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277");
+/* 16 characters + 149 = 165 */
+strcpy(collate+165,"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317");
+/* 16 characters + 165 = 181 */
+strcpy(collate+181,"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337");
+/* 16 characters + 181 = 197 */
+strcpy(collate+197,"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357");
+/* 16 characters + 197 = 213 */
+strcpy(collate+213,"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377");
+/* 16 characters + 213 = 229 */
+
+@ Procedure |unbucket| goes through the buckets and adds nonempty lists
+to the stack, using the collating sequence specified in the |collate| array.
+The parameter to |unbucket| tells the current depth in the buckets.
+Any two sequences that agree in their first 255 character positions are
+regarded as identical.
+
+@d infinity 255 /* $\infty$ (approximately) */
+
+@<Predecl...@>=
+void unbucket();
+
+@ @c
+void
+unbucket(d) /* empties buckets having depth |d| */
+eight_bits d;
+{
+ int c; /* index into |bucket|; cannot be a simple |char| because of sign
+ comparison below*/
+ for (c=100+128; c>= 0; c--) if (bucket[collate[c]]) {
+@^high-bit character handling@>
+ if (sort_ptr>=scrap_info_end) overflow("sorting");
+ sort_ptr++;
+ if (sort_ptr>max_sort_ptr) max_sort_ptr=sort_ptr;
+ if (c==0) sort_ptr->depth=infinity;
+ else sort_ptr->depth=d;
+ sort_ptr->head=bucket[collate[c]]; bucket[collate[c]]=NULL;
+ }
+}
+
+@ @<Sort and output...@>=
+sort_ptr=scrap_info; unbucket(1);
+while (sort_ptr>scrap_info) {
+ cur_depth=sort_ptr->depth;
+ if (blink[sort_ptr->head-name_dir]==0 || cur_depth==infinity)
+ @<Output index entries for the list at |sort_ptr|@>@;
+ else @<Split the list at |sort_ptr| into further lists@>;
+}
+
+@ @<Split the list...@>= {
+ eight_bits c;
+ next_name=sort_ptr->head;
+ do {
+ cur_name=next_name; next_name=blink[cur_name-name_dir];
+ cur_byte=cur_name->byte_start+cur_depth;
+ if (cur_byte==(cur_name+1)->byte_start) c=0; /* hit end of the name */
+ else {
+ c=(eight_bits) *cur_byte;
+ if (xisupper(c)) c=tolower(c);
+ }
+ blink[cur_name-name_dir]=bucket[c]; bucket[c]=cur_name;
+ } while (next_name);
+ --sort_ptr; unbucket(cur_depth+1);
+}
+
+@ @<Output index...@>= {
+ cur_name=sort_ptr->head;
+ do {
+ out_str("\\I");
+@.\\I@>
+ @<Output the name at |cur_name|@>;
+ @<Output the cross-references at |cur_name|@>;
+ cur_name=blink[cur_name-name_dir];
+ } while (cur_name);
+ --sort_ptr;
+}
+
+@ @<Output the name...@>=
+switch (cur_name->ilk) {
+ case normal: case func_template: if (is_tiny(cur_name)) out_str("\\|");
+ else {char *j;
+ for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++)
+ if (xislower(*j)) goto lowcase;
+ out_str("\\."); break;
+lowcase: out_str("\\\\");
+ }
+ break;
+@.\\|@>
+@.\\.@>
+@.\\\\@>
+ case wildcard: out_str("\\9");@+ goto not_an_identifier;
+@.\\9@>
+ case typewriter: out_str("\\.");
+@.\\.@>
+ case roman: not_an_identifier: out_name(cur_name,0); goto name_done;
+ case custom: {char *j; out_str("$\\");
+ for (j=cur_name->byte_start;j<(cur_name+1)->byte_start;j++)
+ out(*j=='_'? 'x': *j=='$'? 'X': *j);
+ out('$');
+ goto name_done;
+ }
+ default: out_str("\\&");
+@.\\\&@>
+}
+out_name(cur_name,1);
+name_done:@;
+
+@ Section numbers that are to be underlined are enclosed in
+`\.{\\[}$\,\ldots\,$\.]'.
+
+@<Output the cross-references...@>=
+@<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>;
+do {
+ out_str(", "); cur_val=cur_xref->num;
+ if (cur_val<def_flag) out_section(cur_val);
+ else {out_str("\\["); out_section(cur_val-def_flag); out(']');}
+@.\\[@>
+ cur_xref=cur_xref->xlink;
+} while (cur_xref!=xmem);
+out('.'); finish_line();
+
+@ List inversion is best thought of as popping elements off one stack and
+pushing them onto another. In this case |cur_xref| will be the head of
+the stack that we push things onto.
+@<Global...@>=
+xref_pointer next_xref, this_xref;
+ /* pointer variables for rearranging a list */
+
+@ @<Invert the cross-reference list at |cur_name|, making |cur_xref| the head@>=
+this_xref=(xref_pointer)cur_name->xref; cur_xref=xmem;
+do {
+ next_xref=this_xref->xlink; this_xref->xlink=cur_xref;
+ cur_xref=this_xref; this_xref=next_xref;
+} while (this_xref!=xmem);
+
+@ The following recursive procedure walks through the tree of section names and
+prints them.
+@^recursion@>
+
+@<Predecl...@>=
+void section_print();
+
+@ @c
+void
+section_print(p) /* print all section names in subtree |p| */
+name_pointer p;
+{
+ if (p) {
+ section_print(p->llink); out_str("\\I");
+@.\\I@>
+ tok_ptr=tok_mem+1; text_ptr=tok_start+1; scrap_ptr=scrap_info; init_stack;
+ app(p-name_dir+section_flag); make_output();
+ footnote(cite_flag);
+ footnote(0); /* |cur_xref| was set by |make_output| */
+ finish_line();@/
+ section_print(p->rlink);
+ }
+}
+
+@ @<Output all the section names@>=section_print(root)
+
+@ Because on some systems the difference between two pointers is a |long|
+rather than an |int|, we use \.{\%ld} to print these quantities.
+
+@c
+void
+print_stats() {
+ printf("\nMemory usage statistics:\n");
+@.Memory usage statistics:@>
+ printf("%ld names (out of %ld)\n",
+ (long)(name_ptr-name_dir),(long)max_names);
+ printf("%ld cross-references (out of %ld)\n",
+ (long)(xref_ptr-xmem),(long)max_refs);
+ printf("%ld bytes (out of %ld)\n",
+ (long)(byte_ptr-byte_mem),(long)max_bytes);
+ printf("Parsing:\n");
+ printf("%ld scraps (out of %ld)\n",
+ (long)(max_scr_ptr-scrap_info),(long)max_scraps);
+ printf("%ld texts (out of %ld)\n",
+ (long)(max_text_ptr-tok_start),(long)max_texts);
+ printf("%ld tokens (out of %ld)\n",
+ (long)(max_tok_ptr-tok_mem),(long)max_toks);
+ printf("%ld levels (out of %ld)\n",
+ (long)(max_stack_ptr-stack),(long)stack_size);
+ printf("Sorting:\n");
+ printf("%ld levels (out of %ld)\n",
+ (long)(max_sort_ptr-scrap_info),(long)max_scraps);
+}
+
+@** Index.
+If you have read and understood the code for Phase III above, you know what
+is in this index and how it got here. All sections in which an identifier is
+used are listed with that identifier, except that reserved words are
+indexed only when they appear in format definitions, and the appearances
+of identifiers in section names are not indexed. Underlined entries
+correspond to where the identifier was declared. Error messages, control
+sequences put into the output, and a few
+other things like ``recursion'' are indexed here too.
diff --git a/web/c_cpp/cweb/cweb.1 b/web/c_cpp/cweb/cweb.1
new file mode 100644
index 0000000000..ad41c427ea
--- /dev/null
+++ b/web/c_cpp/cweb/cweb.1
@@ -0,0 +1,138 @@
+.TH CWEB 1L 2002-Apr-13
+.
+.SH NAME
+ctangle, cweave \- translate CWEB to C and/or TeX
+.
+.SH SYNOPSIS
+.na
+.B ctangle
+[
+.B \-bhp
+] [
+.B +s
+] webfile[.w] [changefile[.ch]] [outputfile[.c]]
+.br
+.B cweave
+[
+.B \-befhpx
+] [
+.B +s
+] webfile[.w] [changefile[.ch]] [outputfile[.tex]]
+.ad
+.
+.SH DESCRIPTION
+The
+.I ctangle
+program converts a CWEB
+source document into a C\ program that may be compiled in the usual way.
+The output file includes #line specifications so that debugging can be
+done in terms of the CWEB source file.
+.PP
+The
+.I cweave
+program converts the same CWEB file into a TeX file that may be
+formatted and printed in the usual way.
+It takes appropriate care of typographic details like page
+layout and the use of indentation, italics, boldface, etc., and it supplies
+extensive cross-index information that it gathers automatically.
+.PP
+CWEB allows you to prepare a single
+document containing all the information that is needed both to produce
+a compilable C\ program and to produce a well-formatted document
+describing the program in as much detail as the writer may desire.
+The user of CWEB ought to be familiar with TeX as well as\ C.
+.PP
+The command line should have one, two, or three names on it.
+The first is taken as the CWEB file (and .w is added if there is no
+extension).
+If that file cannot be opened, the extension .web is tried instead.
+(But .w is recommended, since .web usually implies Pascal.)
+If there is a second name, it is a change file (and .ch is added if there is
+no extension).
+The change file overrides parts of the WEB file,
+as described in the documentation.
+If there is a third name, it overrides
+the default name of the output file, which is ordinarily the same as
+the name of the input file (but on the current directory) with the
+extension .c or .tex.
+.PP
+Options in the command line may be either turned off with\ \-
+(if they are on by default) or turned on with\ + (if they are off by
+default).
+In fact, the options are processed from left to right,
+so a sequence like -f\ +f corresponds to +f (which is the default).
+.PP
+The
+.B \-b
+option suppresses the banner line that normally appears on your terminal
+when ctangle or cweave begins.
+The
+.B \-h
+option suppresses the happy message that normally appears if the processing
+was successful.
+The
+.B \-p
+option suppresses progress reports (starred module numbers) as the processing
+takes place.
+If you say -bhp, you get nothing but error messages.
+.PP
+The
+.B +s
+option prints statistics about memory usage at the end of a run
+(assuming that the programs have been compiled with the -DSTAT switch).
+.PP
+There are three other options applicable to
+.I cweave
+only:
+.B \-f
+means do not force a newline after every statement in the formatted output.
+.B \-e
+inhibits the enclosure of C\ material formatted by
+.I cweave
+in brackets
+\ePB{...}.
+Such brackets are normally inserted so that special hooks
+can be used by
+.I cweb-latex
+and similar programs.
+.B \-x
+means omit the index and table of contents.
+.
+.SH FILES
+.TP
+/usr/local/lib/tex/inputs/cwebmac.tex
+TeX macros used by cweave output.
+.TP
+/usr/local/src/cweb/cwebman.tex
+The user manual.
+.TP
+/usr/local/src/cweb/examples/wc.w
+An introductory example.
+.TP
+/usr/local/src/cweb/examples/wmerge.w
+Patch program based on CWEB-style change files.
+.TP
+/usr/local/lib/cweb
+Directory for cweb "include" files.
+.
+.SH "SEE ALSO"
+.TP
+.I Literate Programming
+by D. E. Knuth
+.TP
+.I Weaving a Program
+by Wayne Sewell
+.TP
+.I The CWEB System of Structured Documentation
+by Donald E. Knuth and Silvio Levy (hardcopy version of cwebman.tex
+and the source code listings)
+.TP
+tex(1), cc(1)
+.
+.SH AUTHORS
+Don Knuth wrote WEB for TeX and Pascal.
+Silvio Levy designed and developed CWEB
+by adapting the WEB conventions to\ C and by recoding everything in CWEB.
+Knuth began using CWEB and made further refinements.
+Many other helpers are acknowledged in the CWEB manual.
+
diff --git a/web/c_cpp/cweb/cweb.el b/web/c_cpp/cweb/cweb.el
new file mode 100644
index 0000000000..c243f35b2e
--- /dev/null
+++ b/web/c_cpp/cweb/cweb.el
@@ -0,0 +1,218 @@
+;; This file contains extensions to GNU-Emacs, to wit:
+; (1) some WEB-oriented functions that are also of general use
+; (2) changes to the GNU-distributed TeX mode
+; (3) definitions of simple WEB and CWEB modes
+
+; To use: Put this in your EMACS-lisp library and say (load-library "cweb")
+; in your .emacs init file.
+
+; Contributed by Don Knuth, July 1990
+
+;; OK, here's part (1): some WEB-oriented functions whose main purpose is
+; to maintain a stack of module names that are "pending" as you are writing
+; a program. When you first think of a module that needs to be written later,
+; put it into the pending list (by typing CTL-Z instead of @> after the
+; name). Later you can say CTL-\ to retrieve a pending name (and if
+; you want to cycle through the pending names, ESC-y after CTL-\ will
+; do it, just as ESC-y works after a yank).
+; After you've said CTL-\, the current region is the name just removed from
+; the pending list. If you change your mind, you can put it back again by
+; saying ESC-\. If you had put it into the pending list by mistake, you
+; can get rid of it by using the normal CTL-W operation (kill-region).
+; The following code binds the new commands to CTL-Z, CTL-\, and ESC-\
+; in all modes. You may prefer other bindings, of course.
+; CTL-Z is normally "suspend emacs", but it is best not used when emacs
+; has its own window as it usually does nowadays; if you need the
+; old CTL-Z, you might rather bind it to CTL-X CTL-Z.
+; CTL-\ is normally undefined.
+; ESC-\ is normally "delete space", but ESC-space DEL does that easily too.
+
+(defvar pending-list nil
+ "List of strings (usually WEB module names) still pending.")
+
+(defun into-pending-list (beg end)
+ "Copy region into pending-list."
+ (interactive "r")
+ (indicate-region)
+ (setq pending-list (cons (buffer-substring beg end) pending-list)))
+
+(defun new-module-name-pending ()
+ "Insert @> to complete a module name, then put it into pending-list."
+ (interactive)
+ (insert "@>")
+ (push-mark)
+ (if (search-backward "@<" nil t)
+ (progn
+ (exchange-point-and-mark)
+ (into-pending-list (point) (mark))
+ )
+ (message "There's no @< to begin the module name!")))
+(global-set-key "\C-z" 'new-module-name-pending)
+
+(defun pop-pending-list (arg)
+ "Remove first element of pending-list and insert it as current region.
+With argument, put point at left; otherwise point will follow the insertion.
+Say \\[new-yank-pop] to replace this by another element of the list.
+Say \\[into-pending-list] to put it back in the list."
+ (interactive "*P")
+ (if (consp pending-list)
+ (progn
+ (push-mark (point))
+ (insert (car pending-list))
+ (setq pending-list (cdr pending-list))
+ (if arg
+ (exchange-point-and-mark)))
+ (message "Nothing is pending.")
+ (setq this-command nil)))
+(global-set-key "\C-\\" 'pop-pending-list)
+(global-set-key "\M-\\" 'into-pending-list)
+
+(defun new-yank-pop (arg)
+ "If previous command was \\[pop-pending-list], pop a different string;
+otherwise do an ordinary Meta-y."
+ (interactive "*p")
+ (if (eq last-command 'pop-pending-list)
+ (let (xch)
+ (setq xch (< (point) (mark)))
+ (setq pending-list (append pending-list
+ (list (buffer-substring (point) (mark)))))
+ (delete-region (point) (mark))
+ (setq this-command 'pop-pending-list)
+ (pop-pending-list xch))
+ (yank-pop arg)))
+(global-set-key "\M-y" 'new-yank-pop)
+
+(defun indicate-region ()
+ "Bounce cursor to mark and back again"
+ (let ((point-save (point)))
+ (unwind-protect
+ (progn (goto-char (mark))
+ (sit-for 0 300)) ;; wait 300 milliseconds
+ (goto-char point-save))))
+
+; I prefer to change the standard copy-region command to the following,
+; which gives me visual feedback about what I've copied to the kill ring:
+(defun indicate-and-copy-region (beg end)
+ "Indicate current region, then copy it to the kill ring."
+ (interactive "r")(indicate-region)(copy-region-as-kill beg end))
+(global-set-key "\M-w" 'indicate-and-copy-region)
+
+; Here's another convenient command, bound to the usually unused ESC-".
+(defun ditto (arg)
+ "Copy ARG characters from the line above."
+ (interactive "*p")
+ (let (ch)
+ (while (> arg 0)
+ (setq temporary-goal-column (current-column))
+ (save-excursion
+ (previous-line 1)
+ (setq ch (following-char)))
+ (insert ch)
+ (setq arg (1- arg)))))
+(global-set-key "\M-\"" 'ditto)
+; If "ditto" suddenly fails to work, you have probably set goal-column
+; inadvertently. To unset it, say C-u C-x C-n.
+
+;; OK, here's part (2): Changes to TeX mode.
+; The WEB modes below are very much like TeX mode, but some improvements were
+; desirable in TeX mode:
+; I made newline act as it does in indented-text mode, since this
+; works nicely for both TeX and WEB (Pascal or C code).
+; I made RET check for unmatched delimiters if it ends a paragraph.
+; Otherwise TeX mode remains as it was before.
+
+(setq TeX-mode-map (make-sparse-keymap))
+(define-key TeX-mode-map "\C-c\C-k" 'TeX-kill-job)
+(define-key TeX-mode-map "\C-c\C-l" 'TeX-recenter-output-buffer)
+(define-key TeX-mode-map "\C-c\C-q" 'TeX-show-print-queue)
+(define-key TeX-mode-map "\C-c\C-p" 'TeX-print)
+(define-key TeX-mode-map "\"" 'TeX-insert-quote)
+(define-key TeX-mode-map "\e}" 'up-list)
+(define-key TeX-mode-map "\e{" 'TeX-insert-braces)
+(define-key TeX-mode-map "\C-c\C-r" 'TeX-region)
+(define-key TeX-mode-map "\C-c\C-b" 'TeX-buffer)
+(define-key TeX-mode-map "\C-c\C-f" 'TeX-close-LaTeX-block)
+(define-key TeX-mode-map "\r" 'TeX-newline)
+(define-key TeX-mode-map "\t" 'indent-relative)
+(setq TeX-mode-hook '(lambda ()
+ (make-local-variable 'indent-line-function)
+ (setq indent-line-function 'indent-relative-maybe)))
+
+(defun TeX-newline (arg)
+"If previous character is newline and no ARG, check for unbalanced braces
+and/or dollar signs in previous paragraph. If ARG is \\[universal-argument],
+do a single newline; otherwise do ordinary newline."
+ (interactive "*P")
+ (if (and (eq (preceding-char) ?\n) (not arg))
+ (TeX-check-paragraph)
+ (if (listp arg)
+ (newline)
+ (newline arg))))
+
+(defun TeX-check-paragraph ()
+"Insert a newline following a newline, breaking a paragraph for TeX.
+Check for mismatched delimiters in paragraph being terminated."
+ (interactive)
+ (if (TeX-validate-paragraph
+ (save-excursion
+ (search-backward "\n\n" nil 'move)
+ (point))
+ (point))
+ (insert ?\n)
+ (insert ?\n)
+ (error "Mismatched delimiters in that paragraph?")))
+
+;; and now, part (3): WEB and CWEB modes.
+; These are like plain TeX mode except that the automatic conversion of
+; " to `` or '' is disabled. (Personally I never liked that feature anyway,
+; since it's easy to get used to typing `` and ''. In WEB modes, the
+; feature soon becomes intolerable, unless you never use string constants!)
+; Another thing distinguishing WEB mode from TeX is ESC-p and ESC-n, to
+; move to previous or next module. These keys are usually unbound, except
+; when processing email.
+
+(defun forward-module (arg)
+"Advance past next WEB module beginning; with ARG, repeat ARG times."
+ (interactive "p")
+ (move-to-module arg))
+(defun backward-module (arg)
+"Advance to previous WEB module beginning; with ARG, repeat ARG times."
+ (interactive "p")
+ (move-to-module (- arg)))
+(defun move-to-module (arg)
+ (while (> arg 0)
+ (re-search-forward "@ \\|@\\*\\|@\n")
+ (setq arg (1- arg)))
+ (while (< arg 0)
+ (re-search-backward "@ \\|@\\*\\|@\n")
+ (setq arg (1+ arg))))
+
+(defun web-mode ()
+ "Major mode like TeX mode plus \\[forward-module] and \\[backward-module]
+for relative module movement. The automatic \" feature is disabled."
+ (interactive)
+ (plain-tex-mode)
+ (local-set-key "\M-n" 'forward-module)
+ (local-set-key "\M-p" 'backward-module)
+ (local-set-key "\"" 'self-insert-command)
+ (setq mode-name "WEB")
+ (setq major-mode 'web-mode)
+ (run-hooks 'web-mode-hook))
+(setq auto-mode-alist (cons '("\\.web$" . web-mode) auto-mode-alist))
+
+(defun cweb-mode ()
+ "Major mode like TeX mode plus \\[forward-module] and \\[backward-module]
+for relative module movement. The automatic \" feature is disabled."
+ (interactive)
+ (plain-tex-mode)
+ (local-set-key "\M-n" 'forward-module)
+ (local-set-key "\M-p" 'backward-module)
+ (local-set-key "\"" 'self-insert-command)
+ (setq comment-start nil)
+ (modify-syntax-entry ?% "@")
+ (setq mode-name "CWEB")
+ (setq major-mode 'cweb-mode)
+ (setq tex-fontify-script nil) ;; needed in GNU Emacs version 22?
+ (run-hooks 'cweb-mode-hook))
+(setq auto-mode-alist (cons '("\\.w$" . cweb-mode) auto-mode-alist))
+(setq auto-mode-alist (cons '("\\.ch$" . cweb-mode) auto-mode-alist))
diff --git a/web/c_cpp/cweb/cwebmac.tex b/web/c_cpp/cweb/cwebmac.tex
new file mode 100644
index 0000000000..60f86ce5a9
--- /dev/null
+++ b/web/c_cpp/cweb/cwebmac.tex
@@ -0,0 +1,553 @@
+% standard macros for CWEB listings (in addition to plain.tex)
+% Version 3.70 --- July 2017
+\ifx\renewenvironment\undefined\else\endinput\fi % LaTeX will use other macros
+\xdef\fmtversion{\fmtversion+CWEB3.70}
+\chardef\cwebversion=3 \chardef\cwebrevision=70
+\newif\ifpdf
+\ifx\pdf+\pdftrue\fi
+% Uncomment the following line if you want PDF goodies to be the default
+%\ifx\pdf-\else\pdftrue\fi
+\def\pdflinkcolor{0 0 1} % the RGB values for hyperlink color
+\newif\ifpdftex
+\ifx\pdfoutput\undefined \pdftexfalse \else\ifnum\pdfoutput=0 \pdftexfalse
+%\else \pdftextrue \pdfoutput=1 \input pdfcolor \let\setcolor\pdfsetcolor \fi\fi
+\else \pdftextrue \pdfoutput=1 % changed in 3.69
+ \def\Black{\pdfliteral{0 g 0 G}} % use rgb colors for direct PDF output too
+ \def\Blue{\pdfliteral{0 0 1 rg 0 0 1 RG}}
+\fi\fi
+\newif\ifacro \ifpdf\acrotrue\fi \ifpdftex\acrotrue\fi
+
+\let\:=\. % preserve a way to get the dot accent
+ % (all other accents will still work as usual)
+
+\parskip 0pt % no stretch between paragraphs
+\parindent 1em % for paragraphs and for the first line of C text
+
+\font\ninerm=cmr9
+\let\mc=\ninerm % medium caps
+\def\CEE/{{\mc C\spacefactor1000}}
+\def\UNIX/{{\mc U\kern-.05emNIX\spacefactor1000}}
+\def\TEX/{\TeX}
+\def\CPLUSPLUS/{{\mc C\PP\spacefactor1000}}
+\def\Cee{\CEE/} % for backward compatibility
+\def\9#1{}
+ % with this definition of \9 you can say @:sort key}{TeX code@>
+ % to alphabetize an index entry by the sort key but format with the TeX code
+\font\eightrm=cmr8
+\let\sc=\eightrm % for smallish caps (NOT a caps-and-small-caps font)
+\let\mainfont=\tenrm
+\let\cmntfont\tenrm
+%\font\tenss=cmss10 \let\cmntfont\tenss % alternative comment font
+\font\titlefont=cmr7 scaled\magstep4 % title on the contents page
+\font\ttitlefont=cmtt10 scaled\magstep2 % typewriter type in title
+\font\tentex=cmtex10 % TeX extended character set (used in strings)
+\fontdimen7\tentex=0pt % no double space after sentences
+
+\def\\#1{\leavevmode\hbox{\it#1\/\kern.05em}} % italic type for identifiers
+\def\|#1{\leavevmode\hbox{$#1$}} % one-letter identifiers look better this way
+\def\&#1{\leavevmode\hbox{\bf
+ \def\_{\kern.04em\vbox{\hrule width.3em height .6pt}\kern.08em}%
+ #1\/\kern.05em}} % boldface type for reserved words
+\def\.#1{\leavevmode\hbox{\tentex % typewriter type for strings
+ \let\\=\BS % backslash in a string
+ \let\{=\LB % left brace in a string
+ \let\}=\RB % right brace in a string
+ \let\~=\TL % tilde in a string
+ \let\ =\SP % space in a string
+ \let\_=\UL % underline in a string
+ \let\&=\AM % ampersand in a string
+ \let\^=\CF % circumflex in a string
+ #1\kern.05em}}
+\def\){{\tentex\kern-.05em}\discretionary{\hbox{\tentex\BS}}{}{}}
+\def\AT{@} % at sign for control text (not needed in versions >= 2.9)
+\def\ATL{\par\noindent\bgroup\catcode`\_=12 \postATL} % print @l in limbo
+\def\postATL#1 #2 {\bf letter \\{\uppercase{\char"#1}}
+ tangles as \tentex "#2"\egroup\par}
+\def\noATL#1 #2 {}
+\def\noatl{\let\ATL=\noATL} % suppress output from @l
+\def\ATH{{\acrofalse\X\kern-.5em:Preprocessor definitions\X}}
+\let\PB=\relax % hook for program brackets |...| in TeX part or section name
+
+\chardef\AM=`\& % ampersand character in a string
+\chardef\BS=`\\ % backslash in a string
+\chardef\LB=`\{ % left brace in a string
+\chardef\RB=`\} % right brace in a string
+\def\SP{{\tt\char`\ }} % (visible) space in a string
+\chardef\TL=`\~ % tilde in a string
+\chardef\UL=`\_ % underline character in a string
+\chardef\CF=`\^ % circumflex character in a string
+
+\newbox\PPbox % symbol for ++
+\setbox\PPbox=\hbox{\kern.5pt\raise1pt\hbox{\sevenrm+\kern-1pt+}\kern.5pt}
+\def\PP{\copy\PPbox}
+\newbox\MMbox \setbox\MMbox=\hbox{\kern.5pt\raise1pt\hbox{\sevensy\char0
+ \kern-1pt\char0}\kern.5pt}
+\def\MM{\copy\MMbox}
+\newbox\MGbox % symbol for ->
+\setbox\MGbox=\hbox{\kern-2pt\lower3pt\hbox{\teni\char'176}\kern1pt}
+\def\MG{\copy\MGbox}
+\def\MRL#1{\mathrel{\let\K==#1}}
+%\def\MRL#1{\KK#1}\def\KK#1#2{\buildrel\;#1\over{#2}}
+\let\GG=\gg
+\let\LL=\ll
+\let\NULL=\Lambda
+\mathchardef\AND="2026 % bitwise and; also \& (unary operator)
+\let\OR=\mid % bitwise or
+\let\XOR=\oplus % bitwise exclusive or
+\def\CM{{\sim}} % bitwise complement
+\newbox\MODbox \setbox\MODbox=\hbox{\eightrm\%}
+\def\MOD{\mathbin{\copy\MODbox}}
+\def\DC{\kern.1em{::}\kern.1em} % symbol for ::
+\def\PA{\mathbin{.*}} % symbol for .*
+\def\MGA{\mathbin{\MG*}} % symbol for ->*
+\def\this{\&{this}}
+
+\newbox\bak \setbox\bak=\hbox to -1em{} % backspace one em
+\newbox\bakk\setbox\bakk=\hbox to -2em{} % backspace two ems
+
+\newcount\ind % current indentation in ems
+\def\1{\global\advance\ind by1\hangindent\ind em} % indent one more notch
+\def\2{\global\advance\ind by-1} % indent one less notch
+\def\3#1{\hfil\penalty#10\hfilneg} % optional break within a statement
+\def\4{\copy\bak} % backspace one notch
+\def\5{\hfil\penalty-1\hfilneg\kern2.5em\copy\bakk\ignorespaces}% optional break
+\def\6{\ifmmode\else\par % forced break
+ \hangindent\ind em\noindent\kern\ind em\copy\bakk\ignorespaces\fi}
+\def\7{\Y\6} % forced break and a little extra space
+\def\8{\hskip-\ind em\hskip 2em} % no indentation
+
+\newcount\gdepth % depth of current major group, plus one
+\newcount\secpagedepth
+\secpagedepth=3 % page breaks will occur for depths -1, 0, and 1
+\newtoks\gtitle % title of current major group
+\newskip\intersecskip \intersecskip=12pt minus 3pt % space between sections
+\let\yskip=\smallskip
+\def\?{\mathrel?}
+\def\note#1#2.{\Y\noindent{\hangindent2em%
+ \baselineskip10pt\eightrm#1~\ifacro{\pdfnote#2.}\else#2\fi.\par}}
+
+\newtoks\toksA \newtoks\toksB \newtoks\toksC \newtoks\toksD
+\newtoks\toksE \newtoks\toksF \newtoks\usersanitizer
+\newcount\countA \countA=0 \newcount\countB \countB=0
+\newcount\countC \countC=0
+\newif\iftokprocessed \newif\ifTnum \newif\ifinstr
+{\def\\{\global\let\spacechar= }\\ }
+
+\ifacro % The following are pdf macros
+\def\thewidth{\the\wd0 \space}
+\def\theheight{\the\ht\strutbox\space}
+\def\thedepth{\the\dp\strutbox\space}
+\ifpdftex
+ \ifx\pdfannotlink\undefined\let\pdfannotlink\pdfstartlink\fi% for pdfTeX 0.14
+ \def\pdflink#1#2{\hbox{\pdfannotlink height\ht\strutbox depth\dp\strutbox
+ attr{/Border [0 0 0]} goto num #1 \Blue #1\Black\pdfendlink}} % changed 3.69
+\else\def\pdflink#1#2{\setbox0=\hbox{\special{pdf: bc [ \pdflinkcolor ]}{#1}%
+ \special{pdf: ec}}\special{pdf: ann width \thewidth height \theheight
+ depth \thedepth << /Type /Annot /Subtype /Link
+ /Border [0 0 0] /A << /S /GoTo /D (#2) >> >>}\box0\relax}\fi
+\def\pdfnote#1.{\setbox0=\hbox{\toksA={#1.}\toksB={}\maketoks}\the\toksA}
+\def\firstsecno#1.{\setbox0=\hbox{\toksA={#1.}\toksB={}%
+ \def\makenote{\addtokens\toksB{\the\toksC}\def\makenote{\toksD={}
+ \toksC={}\let\space\empty}\makenote}\maketoks}}
+\def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks}
+\def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}%
+ \ifcat\noexpand\first0\countB=`#1\else\countB=0\fi\toksA={#2}}
+\def\maketoks{\expandafter\poptoks\the\toksA|ENDTOKS|%
+ \ifnum\countB>`9 \countB=0 \fi
+ \ifnum\countB<`0
+ \ifnum0=\countC\else\makenote\fi
+ \ifx\first.\let\next=\maketoksdone\else
+ \let\next=\maketoks
+ \addtokens\toksB{\the\toksD}
+ \ifx\first,\addtokens\toksB{\space}\fi
+ \fi
+ \else \addtokens\toksC{\the\toksD}\global\countC=1\let\next=\maketoks
+ \fi
+ \next
+}
+\def\makenote{\addtokens\toksB
+ {\noexpand\pdflink{\the\toksC}{\romannumeral\the\toksC}}\toksC={}\global\countC=0}
+\def\maketoksdone{\edef\st{\global\noexpand\toksA={\the\toksB}}\st}
+\def\pdfURL#1#2{\ifpdftex\pdfannotlink height\ht\strutbox depth\dp\strutbox
+ attr {/Border [0 0 0]} user { /Type /Action /Subtype /Link /A
+ << /S /URI /URI (#2) >>}\Blue #1\Black \pdfendlink % changed in 3.69
+ \else \ifpdf{\setbox0=\hbox{\special{pdf: bc [ \pdflinkcolor ]}{#1}%
+ \special{pdf: ec}}\special{pdf: ann width \thewidth\space height \theheight
+ \space depth \thedepth\space << /Border [0 0 0]
+ /Type /Action /Subtype /Link /A << /S /URI /URI (#2) >> >>}\box0\relax}%
+ \else #1 ({\tt#2})\fi\fi}
+{\catcode`\~=12 \gdef\TILDE/{~}} % ~ in a URL
+{\catcode`\_=12 \gdef\UNDER/{_}} % _ in a URL
+\def\sanitizecommand#1#2{\addtokens\usersanitizer
+ {\noexpand\dosanitizecommand\noexpand#1{#2}}}
+\def\dosanitizecommand#1#2{\ifx\nxt#1\addF{#2}\fi}
+
+\catcode`\[=1 \catcode`\]=2 \catcode`\{=12 \catcode`\}=12
+ \def\lbchar[{] \def\rbchar[}]
+\catcode`\[=12 \catcode`\]=12 \catcode`\{=1 \catcode`\}=2
+\catcode`\~=12 \def\tildechar{~} \catcode`\~=13
+\catcode`\|=0 |catcode`|\=12 |def|bschar{\} |catcode`|\=0 \catcode`\|=12
+\def\makeoutlinetoks{\Tnumfalse\afterassignment\makeolproctok\let\nxt= }
+\def\makeolnexttok{\afterassignment\makeolproctok\let\nxt= }
+\def\makeolgobbletok{\afterassignment\makeolnexttok\let\nxt= }
+\def\addF#1{\addtokens\toksF{#1}\tokprocessedtrue}
+% now comes a routine to "sanitize" section names, for pdf outlines
+\def\makeolproctok{\tokprocessedfalse
+ \let\next\makeolnexttok % default
+ \ifx\nxt\outlinedone\let\next\outlinedone
+ \else\ifx{\nxt \else\ifx}\nxt \Tnumfalse \instrfalse % skip braces
+ \else\ifx$\nxt % or a $ sign
+ \else\ifx^\nxt \addF^\else\ifx_\nxt \addF_% sanitize ^ and _
+ \else\ifx\nxt\spacechar \addF\space
+ \else\if\noexpand\nxt\relax % we have a control sequence; is it one we know?
+ \ifx\nxt~\addF\space
+ \else\ifx\nxt\onespace\addF\space
+ \else\the\usersanitizer
+ \iftokprocessed\else\makeolproctokctli
+ \iftokprocessed\else\makeolproctokctlii
+ \iftokprocessed\else\makeolproctokctliii % if not recognised, skip it
+ \fi\fi\fi\fi\fi
+ \else % we don't have a control sequence, it's an ordinary char
+ \ifx/\nxt \addF{\string\/}% quote chars special to PDF with backslash
+ \else\ifx(\nxt \addF{\string\(}\else\ifx)\nxt \addF{\string\)}%
+ \else\ifx[\nxt \addF{\string\[}\else\ifx]\nxt \addF{\string\]}%
+ \else\expandafter\makeolproctokchar\meaning\nxt
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+ \next
+}
+\def\makeolproctokchar#1 #2 #3{\addF{#3}}
+\def\makeolproctokctli{%
+ \ifx\nxt\CEE\addF{C}\let\next\makeolgobbletok % \CEE/
+ \else\ifx\nxt\UNIX\addF{UNIX}\let\next\makeolgobbletok % \UNIX/
+ \else\ifx\nxt\TEX\addF{TeX}\let\next\makeolgobbletok % \TEX/
+ \else\ifx\nxt\TeX\addF{TeX}\else\ifx\nxt\LaTeX\addF{LaTeX}%
+ \else\ifx\nxt\CPLUSPLUS\addF{C++}\let\next\makeolgobbletok % \CPLUSPLUS/
+ \else\ifx\nxt\Cee\addF{C}%
+ \else\ifx\nxt\PB \let\next\makeolgobbletok \tokprocessedtrue % \PB{...}
+ \else\ifx\nxt\.\tokprocessedtrue\instrtrue % \.{...}
+ % skip \|
+ \else\ifx\nxt\\\ifinstr\addF{\bschar\bschar}\else\tokprocessedtrue\fi
+ \else\ifx\nxt\&\ifinstr\addF&\else\tokprocessedtrue\fi
+ \else\ifx\nxt\~\ifTnum\addF{0}\else\addF\tildechar\fi % 077->\T{\~77}
+ \else\ifx\nxt\_\ifTnum\addF{E}\else\addF_\fi % 0.1E5->\T{0.1\_5}
+ \else\ifx\nxt\^\ifTnum\addF{0x}\else\addF^\fi % 0x77 -> \T{\^77}
+ \else\ifx\nxt\$\ifTnum\tokprocessedtrue\else\addF$\fi % \T{77\$L}
+ \else\ifx\nxt\{\addF\lbchar \else\ifx\nxt\}\addF\rbchar
+ \else\ifx\nxt\ \addF\space \else\ifx\nxt\#\addF{\string\#}%
+ \else\ifx\nxt\PP\addF{++}\else\ifx\nxt\MM\addF{--}%
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+}
+\def\makeolproctokctlii{%
+ \ifx\nxt\MG\addF{->}\else\ifx\nxt\GG\addF{>>}%
+ \else\ifx\nxt\LL\addF{<<}\else\ifx\nxt\NULL\addF{NULL}%
+ \else\ifx\nxt\AND\addF&\else\ifx\nxt\OR\addF|%
+ \else\ifx\nxt\XOR\addF^\else\ifx\nxt\CM\addF\tildechar
+ \else\ifx\nxt\MOD\addF{\string\%}\else\ifx\nxt\DC\addF{::}%
+ \else\ifx\nxt\PA\addF{.*}\else\ifx\nxt\MGA\addF{->*}%
+ \else\ifx\nxt\this\addF{this}\else\ifx\nxt\?\addF?%
+ \else\ifx\nxt\E\addF{==}\else\ifx\nxt\G\addF{>=}%
+ \else\ifx\nxt\I\addF{!=}\else\ifx\nxt\K\addF{=}%
+ \else\ifx\nxt\l\addF{l}\else\ifx\nxt\L\addF{L}%
+ \else\ifx\nxt\o\addF{o}\else\ifx\nxt\O\addF{O}%
+ \else\ifx\nxt\R\addF!%
+ \else\ifx\nxt\T \Tnumtrue \let\next\makeolgobbletok
+ \tokprocessedtrue % \T{number}
+ \else\ifx\nxt\AM\addF&\else\ifx\nxt\%\addF{\string\%}%
+ \fi\fi\fi\fi\fi \fi\fi\fi\fi\fi
+ \fi\fi\fi\fi\fi \fi\fi\fi\fi\fi
+ \fi\fi\fi\fi\fi\fi
+}
+\def\makeolproctokctliii{%
+ \ifx\nxt\V\addF{||}\else\ifx\nxt\W\addF{&&}\else\ifx\nxt\Z\addF{<=}%
+ \else\ifx\nxt\*\addF*\else\ifx\nxt\Xand\addF{\space and\space}%
+ \else\ifx\nxt\Xandxeq\addF{\space and_eq\space}%
+ \else\ifx\nxt\Xbitand\addF{\space bitand\space}%
+ \else\ifx\nxt\Xbitor\addF{\space bitor\space}%
+ \else\ifx\nxt\Xcompl\addF{\space compl\space}%
+ \else\ifx\nxt\Xnot\addF{\space not\space}%
+ \else\ifx\nxt\Xnotxeq\addF{\space not_eq\space}%
+ \else\ifx\nxt\Xor\addF{\space or\space}%
+ \else\ifx\nxt\Xorxeq\addF{\space or_eq\space}%
+ \else\ifx\nxt\Xxor\addF{\space xor\space}%
+ \else\ifx\nxt\Xxorxeq\addF{\space xor_eq\space}%
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+ \fi\fi\fi\fi\fi
+}
+\def\outlinedone{\edef\outlinest{\global\noexpand\toksE={\the\toksF}}%
+ \outlinest\let\outlinedone=\relax}
+\fi % End of pdf macros
+
+\def\lapstar{\rlap{*}}
+\def\stsec{\rightskip=0pt % get out of C mode (cf. \B)
+ \sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50
+ \noindent{\let\*=\lapstar\bf\secstar.\quad}%
+ \ifpdftex\smash{\raise\baselineskip\hbox to0pt{%
+% \let\*=\empty\pdfdest num \secstar fith}} % bad space in versions < 3.68
+ \let\*=\empty\pdfdest num \secstar fith}}% changed in version 3.68
+ \else\ifpdf\smash{\raise\baselineskip\hbox to0pt{%
+ \let\*=\empty\special{%
+ pdf: dest (\romannumeral\secstar) [ @thispage /FitH @ypos ]}}}\fi\fi}
+\let\startsection=\stsec
+\def\defin#1{\global\advance\ind by 2 \1\&{#1 } } % begin `define' or `format'
+\def\A{\note{See also section}} % xref for doubly defined section name
+\def\As{\note{See also sections}} % xref for multiply defined section name
+\def\B{\rightskip=0pt plus 100pt minus 10pt % go into C mode
+ \sfcode`;=3000
+ \pretolerance 10000
+ \hyphenpenalty 1000 % so strings can be broken (discretionary \ is inserted)
+ \exhyphenpenalty 10000
+ \global\ind=2 \1\ \unskip}
+\def\C#1{\5\5\quad$/\ast\,${\cmntfont #1}$\,\ast/$}
+\let\SHC\C % "// short comments" treated like "/* ordinary comments */"
+%\def\C#1{\5\5\quad$\triangleright\,${\cmntfont#1}$\,\triangleleft$}
+%\def\SHC#1{\5\5\quad$\diamond\,${\cmntfont#1}}
+\def\D{\defin{\#define}} % macro definition
+\let\E=\equiv % equivalence sign
+\def\ET{ and~} % conjunction between two section numbers
+\def\ETs{, and~} % conjunction between the last two of several section numbers
+\def\F{\defin{format}} % format definition
+\let\G=\ge % greater than or equal sign
+% \H is long Hungarian umlaut accent
+\let\I=\ne % unequal sign
+\def\J{\.{@\&}} % TANGLE's join operation
+\let\K== % assignment operator
+%\let\K=\leftarrow % "honest" alternative to standard assignment operator
+% \L is Polish letter suppressed-L
+\outer\def\M#1{\MN{#1}\ifon\vfil\penalty-100\vfilneg % beginning of section
+ \vskip\intersecskip\startsection\ignorespaces}
+\outer\def\N#1#2#3.{% beginning of starred section
+ \ifacro{\toksF={}\makeoutlinetoks#3\outlinedone\outlinedone}\fi
+ \gdepth=#1\gtitle={#3}\MN{#2}%
+ \ifon\ifnum#1<\secpagedepth \vfil\eject % force page break if depth is small
+ \else\vfil\penalty-100\vfilneg\vskip\intersecskip\fi\fi
+ \message{*\secno} % progress report
+ \def\stripprefix##1>{}\def\gtitletoks{#3}%
+ \edef\gtitletoks{\expandafter\stripprefix\meaning\gtitletoks}%
+ \edef\next{\write\cont{\ZZ{\gtitletoks}{#1}{\secno}% write to contents file
+ {\noexpand\the\pageno}{\the\toksE}}}\next % \ZZ{title}{depth}{sec}{page}{ss}
+ \ifpdftex\expandafter\xdef\csname curr#1\endcsname{\secno}
+ \ifnum#1>0\countB=#1 \advance\countB by-1
+ \advancenumber{chunk\the\countB.\expnumber{curr\the\countB}}\fi\fi
+ \ifpdf\special{pdf: outline #1 << /Title (\the\toksE) /Dest
+ [ @thispage /FitH @ypos ] >>}\fi
+ \ifon\startsection{\bf#3.\quad}\ignorespaces}
+\def\MN#1{\par % common code for \M, \N
+ {\xdef\secstar{#1}\let\*=\empty\xdef\secno{#1}}% remove \* from section name
+ \ifx\secno\secstar \onmaybe \else\ontrue \fi
+ \mark{{{\tensy x}\secno}{\the\gdepth}{\the\gtitle}}}
+% each \mark is {section reference or null}{depth plus 1}{group title}
+% \O is Scandinavian letter O-with-slash
+% \P is paragraph sign
+\def\Q{\note{This code is cited in section}} % xref for mention of a section
+\def\Qs{\note{This code is cited in sections}} % xref for mentions of a section
+\let\R=\lnot % logical not
+% \S is section sign
+\def\T#1{\leavevmode % octal, hex or decimal constant
+ \hbox{$\def\?{\kern.2em}%
+% \def\$##1{\egroup_{\,\rm##1}\bgroup}% suffix to constant % versions < 3.67
+ \def\$##1{\egroup_{\rm##1}\bgroup}% suffix to constant % in version 3.67
+ \def\_{\cdot 10^{\aftergroup}}% power of ten (via dirty trick)
+ \let\~=\oct \let\^=\hex {#1}$}}
+\def\U{\note{This code is used in section}} % xref for use of a section
+\def\Us{\note{This code is used in sections}} % xref for uses of a section
+\let\V=\lor % logical or
+\let\W=\land % logical and
+\def\X#1:#2\X{\ifmmode\gdef\XX{\null$\null}\else\gdef\XX{}\fi %$% section name
+ \XX$\langle\,${\let\I=\ne#2\eightrm\kern.5em
+ \ifacro{\pdfnote#1.}\else#1\fi}$\,\rangle$\XX}
+\def\Y{\par\yskip}
+\let\Z=\le
+\let\ZZ=\let % now you can \write the control sequence \ZZ
+\let\*=*
+
+\def\Xand{\W} \def\Xandxeq{\MRL{{\AND}{\K}}} \def\Xbitand{\AND}
+\def\Xbitor{\OR} \def\Xcompl{\CM} \def\Xnot{\R} \def\Xnotxeq{\I} \def\Xor{\V}
+\def\Xorxeq{\MRL{{\OR}{\K}}} \def\Xxor{\XOR} \def\Xxorxeq{\MRL{{\XOR}{\K}}}
+
+%\def\oct{\hbox{\rm\char'23\kern-.2em\it\aftergroup\?\aftergroup}} % WEB style
+%\def\hex{\hbox{\rm\char"7D\tt\aftergroup}} % WEB style
+\def\oct{\hbox{$^\circ$\kern-.1em\it\aftergroup\?\aftergroup}}% CWEB style
+\def\hex{\hbox{$^{\scriptscriptstyle\#}$\tt\aftergroup}} % CWEB style
+\def\vb#1{\leavevmode\hbox{\kern2pt\vrule\vtop{\vbox{\hrule
+ \hbox{\strut\kern2pt\.{#1}\kern2pt}}
+ \hrule}\vrule\kern2pt}} % verbatim string
+
+\def\onmaybe{\let\ifon=\maybe} \let\maybe=\iftrue
+\newif\ifon \newif\iftitle \newif\ifpagesaved
+
+\newif\ifheader
+\def\lheader{\headertrue\mainfont\the\pageno\eightrm\qquad\grouptitle
+ \hfill\title\qquad\mainfont\topsecno} % top line on left-hand pages
+\def\rheader{\headertrue\mainfont\topsecno\eightrm\qquad\title\hfill
+ \grouptitle\qquad\mainfont\the\pageno} % top line on right-hand pages
+\def\grouptitle{\let\i=I\let\j=J\uppercase\expandafter{\expandafter
+ \takethree\topmark}}
+\def\topsecno{\expandafter\takeone\topmark}
+\def\takeone#1#2#3{#1}
+\def\taketwo#1#2#3{#2}
+\def\takethree#1#2#3{#3}
+\def\nullsec{\eightrm\kern-2em} % the \kern-2em cancels \qquad in headers
+
+\let\page=\pagebody \raggedbottom
+% \def\page{\box255 }\normalbottom % faster, but loses plain TeX footnotes
+\def\normaloutput#1#2#3{\ifodd\pageno\hoffset=\pageshift\fi
+ \shipout\vbox{
+ \vbox to\fullpageheight{
+ \iftitle\global\titlefalse
+ \else\hbox to\pagewidth{\vbox to10pt{}\ifodd\pageno #3\else#2\fi}\fi
+ \vfill#1}} % parameter #1 is the page itself
+ \global\advance\pageno by1}
+
+\gtitle={\.{CWEB} output} % this running head is reset by starred sections
+\mark{\noexpand\nullsec0{\the\gtitle}}
+\def\title{\expandafter\uppercase\expandafter{\jobname}}
+\def\topofcontents{\centerline{\titlefont\title}\vskip.7in
+ \vfill} % this material will start the table of contents page
+\def\startpdf{\ifpdftex\pdfcatalog{/PageMode /UseOutlines}\else
+ \ifpdf{\special{pdf: docview << /PageMode /UseOutlines >>}}\fi\fi}
+\def\botofcontents{\vfill
+ \centerline{\covernote}} % this material will end the table of contents page
+\def\covernote{}
+\def\contentspagenumber{0} % default page number for table of contents
+\newdimen\pagewidth \pagewidth=6.5in % the width of each page
+\newdimen\pageheight \pageheight=8.7in % the height of each page
+\newdimen\fullpageheight \fullpageheight=9in % page height including headlines
+\newdimen\pageshift \pageshift=\hoffset
+ % shift righthand pages wrt lefthand ones (changed in version 3.70)
+\def\magnify#1{\mag=#1\pagewidth=6.5truein\pageheight=8.7truein
+ \fullpageheight=9truein\setpage}
+\def\setpage{\hsize\pagewidth\vsize\pageheight} % use after changing page size
+\def\contentsfile{\jobname.toc} % file that gets table of contents info
+\def\readcontents{\input \contentsfile}
+\def\readindex{\input \jobname.idx}
+\def\readsections{\input \jobname.scn}
+
+\newwrite\cont
+\output{\setbox0=\page % the first page is garbage
+ \openout\cont=\contentsfile
+ \write\cont{\catcode `\noexpand\@=11\relax} % \makeatletter
+ \global\output{\normaloutput\page\lheader\rheader}}
+\setpage
+\vbox to \vsize{} % the first \topmark won't be null
+
+\def\ch{\note{The following sections were changed by the change file:}
+ \let\*=\relax}
+\newbox\sbox % saved box preceding the index
+\newbox\lbox % lefthand column in the index
+\def\inx{\par\vskip6pt plus 1fil % we are beginning the index
+ \def\page{\box255 } \normalbottom
+ \write\cont{} % ensure that the contents file isn't empty
+ \write\cont{\catcode `\noexpand\@=12\relax} % \makeatother
+ \closeout\cont % the contents information has been fully gathered
+ \output{\ifpagesaved\normaloutput{\box\sbox}\lheader\rheader\fi
+ \global\setbox\sbox=\page \global\pagesavedtrue}
+ \pagesavedfalse \eject % eject the page-so-far and predecessors
+ \setbox\sbox\vbox{\unvbox\sbox} % take it out of its box
+ \vsize=\pageheight \advance\vsize by -\ht\sbox % the remaining height
+ \hsize=.5\pagewidth \advance\hsize by -10pt
+ % column width for the index (20pt between cols)
+ \parfillskip 0pt plus .6\hsize % try to avoid almost empty lines
+ \def\lr{L} % this tells whether the left or right column is next
+ \output{\if L\lr\global\setbox\lbox=\page \gdef\lr{R}
+ \else\normaloutput{\vbox to\pageheight{\box\sbox\vss
+ \hbox to\pagewidth{\box\lbox\hfil\page}}}\lheader\rheader
+ \global\vsize\pageheight\gdef\lr{L}\global\pagesavedfalse\fi}
+ \message{Index:}
+ \parskip 0pt plus .5pt
+ \outer\def\I##1, ##2.{\par\hangindent2em\noindent##1:\kern1em
+ \ifacro\pdfnote##2.\else##2\fi.} % index entry
+ \def\[##1]{$\underline{##1}$} % underlined index item
+ \rm \rightskip0pt plus 2.5em \tolerance 10000 \let\*=\lapstar
+ \hyphenpenalty 10000 \parindent0pt
+ \readindex}
+\def\fin{\par\vfill\eject % this is done when we are ending the index
+ \ifpagesaved\null\vfill\eject\fi % output a null index column
+ \if L\lr\else\null\vfill\eject\fi % finish the current page
+ \ifpdftex \makebookmarks \fi % added in Version 3.68
+ \parfillskip 0pt plus 1fil
+ \def\grouptitle{NAMES OF THE SECTIONS}
+ \let\topsecno=\nullsec
+ \message{Section names:}
+ \output={\normaloutput\page\lheader\rheader}
+ \setpage
+ \def\note##1##2.{\quad{\eightrm##1~\ifacro{\pdfnote##2.}\else{##2}\fi.}}
+ \def\Q{\note{Cited in section}} % crossref for mention of a section
+ \def\Qs{\note{Cited in sections}} % crossref for mentions of a section
+ \def\U{\note{Used in section}} % crossref for use of a section
+ \def\Us{\note{Used in sections}} % crossref for uses of a section
+ \def\I{\par\hangindent 2em}\let\*=*
+ \ifacro \def\outsecname{Names of the sections} \let\Xpdf\X
+% \ifpdftex \makebookmarks \pdfdest name {NOS} fitb % in versions < 3.68
+ \ifpdftex \pdfdest name {NOS} fith % changed in version 3.69
+ \pdfoutline goto name {NOS} count -\secno {\outsecname}
+ \def\X##1:##2\X{\Xpdf##1:##2\X \firstsecno##1.%
+ {\toksF={}\makeoutlinetoks##2\outlinedone\outlinedone}%
+ \pdfoutline goto num \the\toksA \expandafter{\the\toksE}}
+ \else\ifpdf
+ \special{pdf: outline -1 << /Title (\outsecname)
+ /Dest [ @thispage /FitH @ypos ] >>}
+ \def\X##1:##2\X{\Xpdf##1:##2\X \firstsecno##1.%
+ {\toksF={}\makeoutlinetoks##2\outlinedone\outlinedone}%
+ \special{pdf: outline 0 << /Title (\the\toksE)
+ /A << /S /GoTo /D (\romannumeral\the\toksA) >> >>}}
+ \fi\fi\fi
+ \readsections}
+\def\makebookmarks{\let\ZZ=\writebookmarkline \readcontents\relax}
+\def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0%
+ \else \csname#1\endcsname \fi} % Petr Olsak's macros from texinfo.tex
+\def\advancenumber#1{\countA=\expnumber{#1}\relax \advance\countA by1
+ \expandafter\xdef\csname#1\endcsname{\the\countA}}
+\def\writebookmarkline#1#2#3#4#5{{%
+ \let\(=\let \let\)=\let \let\[=\let \let\]=\let \let\/=\let
+ \pdfoutline goto num #3 count -\expnumber{chunk#2.#3} {#5}}}
+\def\con{\par\vfill\eject % finish the section names
+% \ifodd\pageno\else\titletrue\null\vfill\eject\fi % for duplex printers
+ \rightskip 0pt \hyphenpenalty 50 \tolerance 200
+ \setpage \output={\normaloutput\page\lheader\rheader}
+ \titletrue % prepare to output the table of contents
+ \pageno=\contentspagenumber
+ \def\grouptitle{TABLE OF CONTENTS}
+ \message{Table of contents:}
+ \topofcontents \startpdf
+ \line{\hfil Section\hbox to3em{\hss Page}}
+ \let\ZZ=\contentsline
+ \readcontents\relax % read the contents info
+ \botofcontents \end} % print the contents page(s) and terminate
+\def\contentsline#1#2#3#4#5{\ifnum#2=0 \smallbreak\fi
+ \line{\consetup{#2}#1
+ \rm\leaders\hbox to .5em{.\hfil}\hfil
+ \ \ifacro\pdflink{#3}{\romannumeral#3}\else#3\fi\hbox to3em{\hss#4}}}
+\def\consetup#1{\ifcase#1 \bf % depth -1 (@**)
+ \or % depth 0 (@*)
+ \or \hskip2em % depth 1 (@*1)
+ \or \hskip4em \or \hskip6em \or \hskip8em \or \hskip10em % depth 2,3,4,5
+ \else \hskip12em \fi} % depth 6 or more
+\def\noinx{\let\inx=\end} % no indexes or table of contents
+\def\nosecs{\let\FIN=\fin \def\fin{\let\parfillskip=\end \FIN}}
+ % no index of section names or table of contents
+\def\nocon{\let\con=\end} % no table of contents
+\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}
+\newcount\twodigits
+\def\hours{\twodigits=\time \divide\twodigits by 60 \printtwodigits
+ \multiply\twodigits by-60 \advance\twodigits by\time :\printtwodigits}
+\def\gobbleone1{}
+\def\printtwodigits{\advance\twodigits100
+ \expandafter\gobbleone\number\twodigits
+ \advance\twodigits-100 }
+\def\TeX{{\ifmmode\it\fi
+ \leavevmode\hbox{T\kern-.1667em\lower.424ex\hbox{E}\hskip-.125em X}}}
+\def\,{\relax\ifmmode\mskip\thinmuskip\else\thinspace\fi}
+\def\datethis{\def\startsection{\leftline{\sc\today\ at \hours}\bigskip
+ \let\startsection=\stsec\stsec}}
+ % say `\datethis' in limbo, to get your listing timestamped before section 1
+%\def\datecontentspage{% versions up to 3.65
+% \def\topofcontents{\leftline{\sc\today\ at \hours}\bigskip
+% \centerline{\titlefont\title}\vfill}} % timestamps the contents page
+\def\datecontentspage{% changed in version 3.66
+ \def\botofcontents{\vfill
+ \centerline{\covernote}
+ \bigskip
+ \leftline{\sc\today\ at \hours}}} % timestamps the contents page
diff --git a/web/c_cpp/cweb/cwebman.tex b/web/c_cpp/cweb/cwebman.tex
new file mode 100644
index 0000000000..2e4ec65ea5
--- /dev/null
+++ b/web/c_cpp/cweb/cwebman.tex
@@ -0,0 +1,1763 @@
+% This file generates the user manual; TeX it, don't read it!
+% update 14 Nov 2016 by DEK: corrected obsolete remarks re debugging info
+
+\def\tangref{3} % where the main explanation of CTANGLing is given
+\input cwebmac
+\acrofalse\pdffalse\pdftexfalse
+\def\page{\box255 } \normalbottom
+\parskip 0pt plus 1pt
+\def\RA{\char'31 } % right arrow
+\def\hang{\hangindent 4em\ignorespaces}
+\font\eightrm=cmr8
+\font\ninerm=cmr9
+\font\ninett=cmtt9
+\font\eighttt=cmtt8
+\font\twelvett=cmtt12
+\font\quoterm=cmssq8
+\font\quoteit=cmssqi8
+\font\authorfont=cmr12
+\font\sectionfont=cmbx12
+
+\def\pb{\.{|...|}}
+\def\v{\.{\char'174}} % vertical (|) in typewriter font
+\def\lpile{\def\cr{\hfill\endline}\matrix} % I only use \lpile by itself
+\abovedisplayskip=.5\abovedisplayskip
+\belowdisplayskip=.5\belowdisplayskip
+\abovedisplayshortskip=.5\abovedisplayshortskip
+\belowdisplayshortskip=.5\belowdisplayshortskip
+\advance\baselineskip by -.5pt
+\advance\pageheight by \baselineskip % the manual just got a bit longer
+\advance\fullpageheight by \baselineskip
+\setpage
+
+\outer\def\section #1.{\penalty-500\bigskip
+ \centerline{\sectionfont\def\.##1{{\twelvett##1}} #1}\nobreak\vskip 6pt
+ \everypar{\hskip-\parindent\everypar{}}}
+
+\def\lheader{\mainfont\the\pageno\hfill\sc\runninghead\hfill}
+\def\rheader{\hfill\sc\runninghead\hfill\mainfont\the\pageno}
+\def\runninghead{{\tentt CWEB} USER MANUAL (VERSION 3.64)}
+
+% This verbatim mode assumes that ! marks are !! in the text being copied.
+\def\verbatim{\begingroup
+ \def\do##1{\catcode`##1=12 } \dospecials
+ \parskip 0pt \parindent 0pt \let\!=!
+ \catcode`\ =13 \catcode`\^^M=13
+ \tt \catcode`\!=0 \verbatimdefs \verbatimgobble}
+{\catcode`\^^M=13{\catcode`\ =13\gdef\verbatimdefs{\def^^M{\ \par}\let =\ }} %
+ \gdef\verbatimgobble#1^^M{}}
+
+\null\vfill
+\centerline{\titlefont The {\ttitlefont CWEB} System of
+ Structured Documentation}
+\vskip 18pt\centerline{(Version 3.64 --- February 2002)}
+\vskip 24pt
+\centerline{\authorfont Donald E. Knuth and Silvio Levy}
+\vfill
+
+\noindent
+\TeX\ is a trademark of the American Mathematical Society.
+
+\noindent
+Acrobat Reader is a trademark of Adobe Systems Incorporated.
+
+\bigskip\noindent
+The printed form of this manual is copyright \copyright\ 1994
+ by Addison-Wesley Publishing Company, Inc. All rights reserved.
+\smallskip\noindent
+The electronic form is copyright \copyright\ 1987, 1990, 1993, 2000
+ by Silvio Levy and Donald E. Knuth.
+
+\bigskip\noindent
+Permission is granted to make and distribute verbatim copies of the
+electronic form of this document provided that the electronic copyright
+notice and this permission notice are preserved on all copies.
+
+\smallskip\noindent
+Permission is granted to copy and distribute modified versions of the
+electronic form of this document 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.
+
+\smallskip\noindent
+Individuals may make copies of the documentation from the electronic files
+for their own personal use.
+
+\smallskip\noindent
+Internet page \.{http://www-cs-faculty.stanford.edu/\char`\~knuth/cweb.html}
+contains current info about \.{CWEB} and related topics.
+
+\pageno=0 \titletrue\eject
+
+\titletrue
+\centerline{\titlefont The {\ttitlefont CWEB} System of
+ Structured Documentation}
+
+\vskip 15pt plus 3pt minus 3pt
+\centerline{\authorfont Donald E. Knuth and Silvio Levy}
+
+\vskip 24pt plus 3pt minus 3pt
+\noindent
+This document describes a version of Don Knuth's \.{WEB} system,
+adapted to \CEE/ by Silvio Levy. Since its creation in 1987, \.{CWEB}
+has been revised and enhanced in various ways, by both Knuth and Levy.
+We now believe that its evolution is near an end; however, bug
+reports, suggestions and comments are still welcome, and
+should be sent to Levy (\.{levy@math.berkeley.edu}).
+
+Readers who are familiar with Knuth's memo ``The \.{WEB} System of Structured
+Documentation'' will be able
+to skim this material rapidly, because \.{CWEB} and \.{WEB} share
+the same philosophy and (essentially) the same syntax. In some respects
+\.{CWEB} is a simplification
+of \.{WEB}: for example, \.{CWEB} does not need \.{WEB}'s features
+for macro definition and string handling, because \CEE/ and its
+preprocessor already take care of macros and strings. Similarly, the \.{WEB}
+conventions of denoting octal and hexadecimal constants by \.{@'77}
+and \.{@"3f} are replaced by \CEE/'s conventions \.{077} and
+\.{0x3f}. All other features of \.{WEB} have been
+retained, and new features have been added.
+
+We thank all who contributed suggestions and criticism to
+the development of \.{CWEB}. We are especially grateful to Steve
+Avery, Nelson Beebe, Hans-Hermann Bode, Klaus Guntermann, Norman Ramsey,
+Joachim Schnitter, and Saroj Mahapatra,
+who contributed code, and to Cameron Smith, who
+made many suggestions improving the manual. Ramsey has made
+literate programming accessible to users of yet other languages by means of
+his \.{SPIDER} system [see {\sl Communications of the ACM\/ \bf32} (1989),
+1051--1055]. The book {\sl Literate Programming\/} by Knuth (1992) contains
+a comprehensive bibliography of related early work.
+Bode, Schnitter, and Mahapatra adapted \.{CWEB} so that it works
+for \CPLUSPLUS/ as well; therefore in the text below you can read \CPLUSPLUS/
+for \CEE/ if you so desire.
+
+\section Introduction.
+The philosophy behind \.{CWEB} is
+that programmers who want to provide the best
+possible documentation for their programs need two things
+simultaneously: a language like \TEX/ for formatting, and a language like
+\CEE/ for programming. Neither type of language can provide the
+best documentation by itself. But when both are appropriately combined, we
+obtain a system that is much more useful than either language separately.
+
+The structure of a software program may be thought of as a ``web'' that is
+made up of many interconnected pieces. To document such a program, we want
+to explain each individual part of the web and how it relates to its
+neighbors. The typographic tools provided by \TEX/ give us an opportunity
+to explain the local structure of each part by making that structure
+visible, and the programming tools provided by \CEE/ make it possible
+for us to specify the algorithms formally and unambiguously. By combining
+the two, we can develop a style of programming that maximizes our ability
+to perceive the structure of a complex piece of software, and at the same
+time the documented programs can be mechanically translated into a working
+software system that matches the documentation.
+
+The \.{CWEB} system consists of two programs named \.{CWEAVE} and \.{CTANGLE}.
+When writing a \.{CWEB} program the user keeps the
+\CEE/ code and the documentation in the same file, called the \.{CWEB}
+file and generally named \.{something.w}. The command
+`\.{cweave} \.{something}' creates an output file \.{something.tex}, which
+can then be fed to \TEX/, yielding a ``pretty printed'' version of
+\.{something.w} that correctly handles
+typographic details like page layout and the use of indentation,
+italics, boldface, and mathematical symbols. The typeset output also
+includes extensive cross-index
+information that is gathered automatically. Similarly, if you run the
+command `\.{ctangle} \.{something}' you will get a \CEE/ file \.{something.c},
+which can then be compiled to yield executable code.
+
+Besides providing a documentation tool, \.{CWEB} enhances the \CEE/
+language by providing the
+ability to permute pieces of the program text, so that a large system can
+be understood entirely in terms of small sections and their local
+interrelationships. The \.{CTANGLE} program is so named because it takes a
+given web and moves the sections from their web structure into the order
+required by \CEE/; the advantage of programming in \.{CWEB} is that the
+algorithms can be expressed in ``untangled'' form, with each section
+explained separately. The \.{CWEAVE} program is so named because it takes
+a given web and intertwines the \TEX/ and \CEE/ portions contained in
+each section, then it knits the whole fabric into a structured document.
+(Get it? Wow.) Perhaps there is some deep connection here with the fact
+that the German word for ``weave'' is ``{\it webe\/}'', and the
+corresponding Latin imperative is ``{\it texe\/}''!
+
+A user of \.{CWEB} should be fairly familiar with the \CEE/
+programming language. A minimal amount of acquaintance with \TEX/ is also
+desirable, but in fact it can be acquired as one uses \.{CWEB}, since
+straight text can be typeset in \TEX/ with virtually no knowledge of
+that language. To someone familiar with both \CEE/ and \TEX/ the amount of
+effort necessary to learn the commands of \.{CWEB} is small.
+
+\section Overview.
+Two kinds of material go into \.{CWEB} files: \TEX/ text and \CEE/ text.
+A programmer writing in \.{CWEB} should be thinking both of the
+documentation and of the \CEE/ program being created;
+i.e., the programmer should be instinctively aware of the different
+actions that \.{CWEAVE} and \.{CTANGLE} will perform on the \.{CWEB} file.
+\TEX/ text is essentially copied without change by \.{CWEAVE}, and it is
+entirely deleted by \.{CTANGLE}; the \TEX/ text is ``pure
+documentation.'' \CEE/ text, on the other hand, is formatted by
+\.{CWEAVE} and it is shuffled around by \.{CTANGLE}, according to rules that
+will become clear later. For now the important point to keep in mind is
+that there are two kinds of text. Writing \.{CWEB} programs is something
+like writing \TEX/ documents, but with an additional ``\CEE/ mode''
+that is added to \TEX/'s horizontal mode, vertical mode, and math mode.
+
+A \.{CWEB} file is built up from units called {\sl sections\/} that are more
+or less self-contained. Each section has three parts:
+
+\yskip\item{$\bullet$} A \TEX/ part, containing explanatory material about what
+is going on in the section.
+
+\item{$\bullet$} A middle part, containing macro definitions that serve as
+abbreviations for \CEE/ constructions that would be less comprehensible
+if written out in full each time. They are turned by \.{CTANGLE} into
+preprocessor macro definitions.
+
+\item{$\bullet$} A \CEE/ part, containing a piece of the program that
+\.{CTANGLE} will produce. This \CEE/ code should ideally be about a
+dozen lines long, so that it is easily comprehensible as a unit and so
+that its structure is readily perceived.
+
+\yskip\noindent The three parts of each section must appear in this order;
+i.e., the \TEX/ commentary must come first, then the middle part, and
+finally the \CEE/ code. Any of the parts may be empty.
+
+A section begins with either of the symbols `\.{@\ }' or `\.{@*}', where
+`\.{\ }' denotes a blank space. A section ends
+at the beginning of the next section (i.e., at the next
+`\.{@\ }' or `\.{@*}'), or at the end of the file, whichever comes first.
+The \.{CWEB} file may also contain material that is not part of any section
+at all, namely the text (if any) that occurs before the first section.
+Such text is said to be ``in limbo''; it is ignored by \.{CTANGLE}
+and copied essentially verbatim by \.{CWEAVE}, so its function is to
+provide any additional formatting instructions that may be desired in the
+\TEX/ output. Indeed, it is customary to begin a \.{CWEB} file with
+\TEX/ code in limbo that loads special fonts, defines special macros,
+changes the page sizes, and/or produces a title page.
+
+Sections are numbered consecutively, starting with 1. These numbers appear
+at the beginning of each section of the \TEX/ documentation output by
+\.{CWEAVE}, and they appear
+as bracketed comments at the beginning and end of the code generated by that
+section in the \CEE/ program output by \.{CTANGLE}.
+
+\section Section Names.
+Fortunately, you never mention these numbers yourself when you are writing
+in \.{CWEB}. You just say `\.{@\ }' or `\.{@*}' at the beginning of each
+new section, and the numbers are supplied automatically by \.{CWEAVE} and
+\.{CTANGLE}. As far as you are concerned, a section has a
+{\sl name\/} instead of a number; its name is specified by writing
+`\.{@<}' followed by \TEX/ text followed by `\.{@>}'. When \.{CWEAVE}
+outputs a section name, it replaces the `\.{@<}' and `\.{@>}' by
+angle brackets and inserts the section number in small type. Thus, when you
+read the output of \.{CWEAVE} it is easy to locate any section that is
+referred to in another section.
+
+For expository purposes, a section name should be a good description of the
+contents of that section; i.e., it should stand for the abstraction
+represented by the section. Then the section can be ``plugged into'' one or
+more other sections in such a way
+that unimportant details of its inner workings
+are suppressed. A section name therefore ought to be long enough to convey
+the necessary meaning.
+
+Unfortunately, it is laborious to type
+such long names over and over again, and it is also difficult to specify a
+long name twice in exactly the same way so that \.{CWEAVE} and \.{CTANGLE}
+will be able to match the names to the sections. To ameliorate this situation,
+\.{CWEAVE} and \.{CTANGLE} let you abbreviate a section name, so long as
+the full name appears somewhere in the \.{CWEB} file; you can type simply
+`\.{@<$\alpha$...@>}', where $\alpha$ is any string that is a prefix of
+exactly one section name appearing in the file. For example, `\.{@<Clear
+the arrays@>}' can be abbreviated to `\.{@<Clear...@>}' if no other section
+name begins with the five letters `\.{Clear}'. Elsewhere
+you might use the abbreviation `\.{@<Clear t...@>}', and so on.
+
+Section names must otherwise match character for character, except
+that consecutive characters of white space (spaces, tab marks, newlines, and/or
+form feeds) are treated as equivalent to a single space, and such spaces are
+deleted at the beginning and end of the name. Thus, `\.{@< Clear { }the
+arrays @>}' will also match the name in the previous example.
+Spaces following the ellipsis in abbreviations are ignored as well, but
+not those before, so that `\.{@<Clear t ...@>}' would not match
+`\.{@<Clear the arrays@>}'.
+
+\section What \.{CTANGLE} Does.
+We have said that a section begins with `\.{@\ }' or `\.{@*}', but we
+didn't say how it gets divided up into a \TEX/ part, a middle part,
+and a \CEE/ part. The middle part begins with the first appearance of
+`\.{@d}' or `\.{@f}' in the section, and the \CEE/ part begins with
+the first appearance of `\.{@c}' or `\.{@<section name@>=}'. In the
+latter case you are saying, in effect, that the section name stands
+for the \CEE/ text that follows. Alternatively, if the \CEE/ part
+begins with `\.{@c}' instead of a section name, the current section is
+said to be {\sl unnamed}.
+
+The construct `\.{@<section name@>}' can appear
+any number of times in the \CEE/ part of a section:
+Subsequent appearances indicate that a named section is being
+``used'' rather than ``defined.'' In other words, the
+\CEE/ code for the named section, presumably defined elsewhere, should be
+spliced in at this point in the \CEE/ program. Indeed,
+the main idea of \.{CTANGLE} is to make a \CEE/ program out of
+individual sections, named and unnamed. The exact way in which this is done
+is this: First all the macro definitions
+indicated by `\.{@d}' are turned into \CEE/ preprocessor macro definitions
+and copied at the beginning.
+Then the \CEE/ parts of unnamed sections are copied down,
+in order; this constitutes the first-order
+approximation to the text of the program. (There should be at least
+one unnamed section, otherwise there will be no program.) Then all section
+names that appear in the first-order approximation are replaced by the \CEE/
+parts of the corresponding sections, and this substitution process
+continues until no section names remain. All comments are removed, because
+the \CEE/ program is intended only for the eyes of the \CEE/ compiler.
+
+If the same name has been given to more than one section, the \CEE/ text
+for that name is obtained by putting together all of the \CEE/ parts in
+the corresponding sections. This feature is useful, for example, in a
+section named `Global variables', since one can then
+declare global variables in whatever sections those variables are
+introduced. When several sections have the same name, \.{CWEAVE} assigns the
+first section number as the number corresponding to that name, and it
+inserts a note at the bottom of that section telling the reader to `See
+also sections so-and-so'; this footnote gives the numbers of all the other
+sections having the same name as the present one. The \CEE/ text
+corresponding to a section is usually formatted by \.{CWEAVE} so that the
+output has an equivalence sign in place of the equals sign in the \.{CWEB}
+file; i.e., the output says `$\langle\,$section
+name$\,\rangle\equiv\null$\CEE/ text'. However, in the case of the second
+and subsequent appearances of a section with the same name, this `$\equiv$'
+sign is replaced by `$\mathrel+\equiv$', as an indication that the
+following \CEE/ text is being appended to the \CEE/ text of another section.
+
+As \.{CTANGLE} enters and leaves sections, it inserts preprocessor
+\.{\#line} commands into the \CEE/ output file. This means that
+when the compiler gives you error messages, or when you debug your program,
+the messages refer to line numbers in the \.{CWEB} file, and not in the
+\CEE/ file. In most cases you can therefore
+forget about the \CEE/ file altogether.
+
+\section What \.{CWEAVE} Does.
+The general idea of \.{CWEAVE} is to make a \.{.tex} file from the \.{CWEB}
+file in the following way: The first line of the \.{.tex} file
+tells \TEX/ to input a file with macros that
+define \.{CWEB}'s documentation conventions. The next lines of the file
+will be copied from whatever \TEX/ text is in limbo before the first
+section. Then comes the output for each section in turn, possibly
+interspersed with end-of-page marks. Finally, \.{CWEAVE} will generate a
+cross-reference index that lists each section number in which each \CEE/
+identifier appears, and it will also generate an alphabetized list
+of the section names, as well as a table of contents that
+shows the page and section numbers for each ``starred'' section.
+
+What is a ``starred'' section, you ask? A section that begins with `\.{@*}'
+instead of `\.{@\ }' is slightly special in that it denotes a new major
+group of sections. The `\.{@*}' should be followed by the title of this
+group, followed by a period. Such sections will always start on a new page
+in the \TEX/ output, and the group title will appear as a running headline
+on all subsequent pages until the next starred section. The title will also
+appear in the table of contents, and in boldface type at the beginning of
+its section. Caution: Do not use \TEX/ control sequences in such titles,
+unless you know that the \.{cwebmac} macros will do the right thing with
+them. The reason is that these titles are converted to uppercase when
+they appear as running heads, and they are converted to boldface when they
+appear at the beginning of their sections, and they are also written out to
+a table-of-contents file used for temporary storage while \TEX/ is
+working; whatever control sequences you use must be meaningful in all
+three of these modes.
+
+The \TEX/ output produced by \.{CWEAVE} for each section consists of
+the following: First comes the section number (e.g., `\.{\\M123.}'
+at the beginning of section 123, except that `\.{\\N}' appears in place of
+`\.{\\M}' at the beginning of a starred section). Then comes the
+\TEX/ part of the section, copied almost verbatim except as noted
+below. Then comes the middle part and the \CEE/ part, formatted
+so that there will be a little extra space between them if both are
+nonempty. The middle and \CEE/ parts are obtained by inserting
+a bunch of funny-looking \TEX/ macros into the \CEE/ program; these
+macros handle typographic details about fonts and proper math spacing,
+as well as line breaks and indentation.
+
+\section C Code in \TEX/ Text and Vice Versa.
+When you are typing \TEX/ text, you will probably want to make frequent
+reference to variables and other quantities in your \CEE/ code, and you
+will want those variables to have the same typographic treatment
+when they appear in your text as when they appear in your
+program. Therefore the \.{CWEB} language allows you to get the effect of
+\CEE/ editing within \TEX/ text, if you place `\.|' marks before and
+after the \CEE/ material. For example, suppose you want to say something
+like this:
+$$\hbox{ If \\{pa} is declared as `\&{int} ${}{*}\\{pa}$',
+the assignment $\\{pa}\K{\AND}\|a[\T{0}]$ makes \\{pa}
+point to the zeroth element of \|a.}$$
+The \TEX/ text would look like this in your \.{CWEB} file:
+$$\lpile{\.{If |pa| is declared as `|int *pa|', the}\cr
+\.{assignment |pa=\&a[0]| makes |pa| point
+to the zeroth element of |a|.}\cr}$$
+And \.{CWEAVE} translates this into something you are glad you didn't have
+to type:
+$$\lpile{\.{If \\\\\{pa\} is declared as
+ `\\\&\{int\} \$\{\}\{*\}\\\\\{pa\}\$',}\cr
+\.{the assignment \$\\\\\{pa\}\\K\{\\AND\}\\|a[\\T\{0\}]\$}\cr
+\.{makes \\\\\{pa\} point to the zeroth element of \\|a.}\cr}$$
+Incidentally, the cross-reference index that \.{CWEAVE} would make, in
+the presence of a comment like this, would include
+the current section number as one of the index entries for \\{pa},
+even though \\{pa} might not appear in the \CEE/ part of
+this section. Thus, the index covers references to identifiers in
+the explanatory comments as well as in the program itself; you will
+soon learn to appreciate this feature. However, the identifiers
+\&{int} and \|a\ would not be indexed,
+because \.{CWEAVE} does not make index entries for reserved words or
+single-letter identifiers. Such identifiers are felt to be so ubiquitous
+that it would be pointless to mention every place where they occur.
+
+Although a section begins with \TEX/ text and ends with \CEE/ text, we
+have noted that the dividing line isn't sharp, since \CEE/ text can be
+included in \TEX/ text if it is enclosed in `\pb'. Conversely, \TEX/ text
+appears frequently within \CEE/ text, because everything in
+comments (i.e., between \.{/*} and \.{*/}, or following \.{//})
+is treated as \TEX/ text.
+Likewise, the text of a section name consists of \TEX/ text, but
+the construct \.{@<section name@>} as a whole is expected to be found
+in \CEE/ text; thus, one typically goes back and forth
+between the \CEE/ and \TEX/ environments in a natural way, as in these
+examples:
+$$
+\displaylines{
+\hbox{\.{if} \.{(x==0)} \.{@<Empty} \.{the} \.{|buffer|} \.{array@>}} \cr
+\hbox{\.{...} \.{using} \.{the} \.{algorithm}
+\.{in} \.{|@<Empty} \.{the} \.{|buffer|} \.{array@>|.}} }
+$$
+The first of these excerpts
+would be found in the \CEE/ part of a section, into which the code
+from the section
+named ``Empty the \\{buffer} array'' is being spliced. The second excerpt
+would be found in the \TEX/ part of the section, and the named section
+is being ``cited'', rather than defined or used.
+(Note the `\pb' surrounding the section name in this case.)
+
+\section Macros.
+The control code \.{@d} followed by
+$$\\{identifier}\.{ }\hbox{\CEE/ text}\qquad\hbox{or by}\qquad
+\\{identifier}\.(\\{par}_1,\ldots,\\{par}_n\.{) }\hbox{\CEE/ text}$$
+(where there is no blank between the
+\\{identifier} and the parentheses in the second case) is
+transformed by \.{CTANGLE} into a preprocessor command, starting with
+\.{\#define}, which is printed at the top of the \CEE/ output file
+as explained earlier.
+
+A `\.{@d}' macro definition can go on for several lines, and the
+newlines don't have to be protected by backslashes, since \.{CTANGLE}
+itself inserts the backslashes. If
+for any reason you need a \.{\#define} command at a specific spot in
+your \CEE/ file, you can treat it as \CEE/ code, instead of as a
+\.{CWEB} macro; but then you do have to protect newlines yourself.
+
+\section Strings and constants.
+If you want a string to appear in the \CEE/ file, delimited by pairs of
+\.' or \." marks as usual, you can type it exactly so in the \.{CWEB} file,
+except that the character `\.@' should be typed `\.{@@}' (it becomes a
+control code, the only one that can appear in strings; see below).
+Strings should end on the same line as they begin, unless there's a
+backslash at the end of lines within them.
+
+\TEX/ and \CEE/ have different ways to refer to octal and hex constants,
+because \TEX/ is oriented to technical writing while \CEE/ is oriented to
+computer processing. In \TEX/ you
+make a constant octal or hexadecimal by prepending \.' or \.",
+respectively, to it; in \CEE/ the constant should be preceded by \.0
+or \.{0x}. In \.{CWEB} it seems reasonable to let each convention hold
+in its respective realm; so in \CEE/ text you get $40_8$ by typing
+`\.{040}', which \.{CTANGLE} faithfully copies into the \CEE/ file (for
+the compiler's benefit) and which \.{CWEAVE} prints as $\T{\~40}$.
+Similarly, \.{CWEAVE} prints the hexadecimal \CEE/ constant `\.{0x20}'
+as \T{\^20}. The use of italic font for octal digits and typewriter font
+for hexadecimal digits makes the meaning of such constants clearer in
+a document. For consistency, then, you
+should type `\.{|040|}' or `\.{|0x20|}'
+in the \TEX/ part of the section.
+
+\section Control codes.
+A \.{CWEB} {\sl control code\/}
+is a two-character combination of which the first is `\.@'.
+We've already seen the meaning of several control codes; it's time to
+list them more methodically.
+
+In the following list,
+the letters in brackets after a control code indicate in what contexts that
+code is allowed. $L$ indicates that the code is allowed in limbo; $T$
+(for \TEX/), $M$ (for middle), and $C$ (for \CEE/) mean that the code is
+allowed in each of the three parts of a section, at top level---that
+is, outside such constructs as `\pb' and section names. An arrow $\to$
+means that the control code terminates the present part of the \.{CWEB}
+file, and inaugurates the part indicated by the letter following the
+arrow. Thus $[LTMC\to T]$ next to \.{@\ } indicates that this control
+code can occur in limbo, or in any of the three parts of a section, and
+that it starts the (possibly empty) \TEX/ part of the following section.
+
+Two other abbreviations can occur in these brackets: The letter $r$ stands for
+{\it restricted context}, that is, material inside \CEE/ comments, section
+names, \CEE/ strings and control texts (defined below); the letter
+$c$ stands for {\it inner \CEE/ context}, that is, \CEE/ material
+inside `\pb' (including `\pb's inside comments, but not those
+occurring in other restricted contexts). An asterisk $*$ following
+the brackets means
+that the context from this control code to the matching \.{@>} is
+restricted.
+
+Control codes involving letters are case-insensitive; thus \.{@d} and
+\.{@D} are equivalent. Only the lowercase versions are mentioned
+specifically below.
+
+\gdef\@#1[#2] {\penalty-50\yskip\hangindent 2em\noindent\.{@#1\unskip
+ \spacefactor1000{ }}$[#2]$\quad}
+\def\more{\hangindent 2em \hangafter0}
+\def\subsec{\penalty-300\medskip\noindent}
+
+\@@ [LTMCrc] A double \.@ denotes the single character `\.@'. This is
+the only control code that is legal everywhere.
+Note that you must use this convention if you are giving an internet
+email address in a \.{CWEB} file (e.g., \.{levy@@math.berkeley.edu}).
+
+\subsec
+Here are the codes that introduce the \TEX/ part of a section.
+
+\@\ [LTMC\to T] This denotes the beginning of a new (unstarred)
+section. A tab mark or form feed or
+end-of-line character is equivalent to a space when it follows an \.@
+sign (and in most other cases).
+
+\@* [LTMC\to T] This denotes the beginning of a new starred
+section, i.e., a section that begins a new major group. The title of the new
+group should appear after the \.{@*}, followed by a period. As explained
+above, \TEX/ control sequences should be avoided in such titles unless
+they are quite simple. When \.{CWEAVE} and \.{CTANGLE} read a \.{@*}, they
+print an asterisk on the terminal
+followed by the current section number, so that the user
+can see some indication of progress. The very first section should be starred.
+
+\more You can specify the ``depth'' of a starred section by typing \.* or a
+decimal number after the \.{@*}; this indicates the relative ranking
+of the current group of sections in the program hierarchy. Top-level
+portions of the program, introduced by \.{@**}, get their names typeset
+in boldface type in the table of contents; they are said to have
+depth~$-1$. Otherwise the depth is a nonnegative number, which governs
+the amount of indentation on the contents page. Such indentation helps
+clarify the structure of a long program. The depth is assumed to be 0
+if it is not specified explicitly; when your program is short, you
+might as well leave all depths zero. A starred section always begins
+a new page in the output, unless the depth is greater than~1.
+
+\subsec
+The middle part of each section consists of any number of
+macro definitions (beginning with \.{@d}) and format definitions (beginning
+with \.{@f} or \.{@s}), intermixed in any order.
+
+\@d [TM\to M] Macro definitions begin with \.{@d}, followed by
+an identifier and optional parameters and \CEE/ text as explained earlier.
+
+\@f [TM\to M] Format definitions begin with \.{@f}; they cause
+\.{CWEAVE} to treat identifiers in a special way when they appear in
+\CEE/ text. The general form of a format definition is `\.{@f} \|l
+\|r', followed by an optional comment enclosed between
+\.{/*} and \.{*/}, where \|l and \|r
+are identifiers; \.{CWEAVE} will subsequently treat identifier \|l as it
+currently treats \|r. This feature allows a \.{CWEB} programmer to invent
+new reserved words and/or to unreserve some of \CEE/'s reserved
+identifiers. For example, the common words `error' and `line'
+have been given a special meaning in the \CEE/ preprocessor,
+so \.{CWEAVE} is set up to format them specially; if you want a variable
+named \\{error} or \\{line}, you should say
+$$\.{@f error normal}\qquad\qquad\.{@f line normal}$$
+somewhere in your program.
+
+\more If \|r is the special identifier `\\{TeX}', identifier \|l
+will be formatted as a \TEX/ control sequence; for example,
+`\.{@f foo TeX}' in the \.{CWEB} file will cause identifier \\{foo} to
+be output as \.{\\foo} by \.{CWEAVE}. The programmer should define
+\.{\\foo} to have whatever custom format is desired, assuming \TEX/
+math mode. (Each underline
+character is converted to \.{x} when making the \TEX/ control sequence,
+and each dollar sign is converted to~\.X;
+thus \\{foo\_bar} becomes \.{\\fooxbar}. Other characters, including digits,
+are left untranslated, so \TEX/ will consider them as macro parameters,
+not as part of the control sequence itself. For example,
+$$\.{\\def\\x\#1\{x\_\{\#1\}\} @f x1 TeX @f x2 TeX}$$
+will format \.{x1} and \.{x2} not as \\{x1} and \\{x2} but as $x_1$ and $x_2$.)
+
+\more If \|r is the special identifier `\\{make\_pair}', identifier \|l will
+be treated as a \CPLUSPLUS/ function template. For example, after
+\.{@f}~\.{convert}~\.{make\_pair} one can say `\.{convert<int>(2.5)}' without
+having \.< and \.> misunderstood as less-than and greater-than signs.
+
+\more \.{CWEAVE} knows that identifiers being
+defined with a \&{typedef} should become reserved words; thus you
+don't need format definitions very often.
+
+\@s [TM\to M;\;L] Same as \.{@f}, but \.{CWEAVE} does not show the format
+definition in the output, and the optional \CEE/ comment is not
+allowed. This is used mostly in \.{@i} files.
+
+\subsec
+Next come the codes that govern the \CEE/ part of a section.
+
+\@{c @p} [TM\to C] The \CEE/ part of an unnamed section begins with \.{@c}
+(or with \.{@p} for ``program''; both control codes do the same thing).
+This causes \.{CTANGLE} to append the following \CEE/ code
+to the first-order program text, as explained on page~\tangref.
+Note that \.{CWEAVE} does not print a `\.{@c}' in the \TEX/
+output, so if you are creating a \.{CWEB} file based on a \TEX/-printed
+\.{CWEB} documentation you have to remember to insert \.{@c} in the
+appropriate places of the unnamed sections.
+
+\@< [TM\to C;\; C;\; c] $*$ This control code introduces a
+section name (or unambiguous prefix, as discussed above), which
+consists of \TEX/ text and extends to the matching \.{@>}.
+The whole construct \.{@<...@>} is conceptually a \CEE/ element.
+The behavior is different depending on the context:
+
+\more A \.{@<} appearing in contexts $T$ and $M$ attaches the
+following section name to the current section, and inaugurates the
+\CEE/ part of the section. The closing \.{@>} should be followed by
+\.{=} or \.{+=}.
+
+\more
+In context $C$, \.{@<} indicates that the named
+section is being used---its \CEE/ definition is spliced in by
+\.{CTANGLE}, as explained on page~\tangref.
+As an error-detection measure,
+\.{CTANGLE} and \.{CWEAVE} complain if such a section name is followed
+by \.=, because most likely this is meant as the definition of a new
+section, and so should be preceded by \.{@\ }. If you really want to
+say $\langle\,$foo$\,\rangle=\\{bar}$, where $\langle\,$foo$\,\rangle$
+is being used and not defined, put a newline before the \.=.
+
+\more
+Finally, in inner \CEE/ context (that is, within `\pb' in the \TEX/ part
+of a section or in a comment), \.{@<...@>}
+means that the named section is being
+cited. Such an occurrence is ignored by \.{CTANGLE}. Note that
+even here we think of the section name as being a \CEE/ element, hence the \pb.
+
+\@( [TM\to C;\;C;\;c] $*$ A section name can begin with \.{@(}.
+Everything works just as for \.{@<}, except that the \CEE/ code
+of the section named \.{@(foo@>} is written by \.{CTANGLE}
+to file \.{foo}. In this way you can get multiple-file output from
+a single \.{CWEB} file. (The \.{@d} definitions are not output
+to such files, only to the master \.{.c} file.) One use of this feature
+is to produce header files for other program modules that will be loaded
+with the present one. Another use is to produce a test routine that
+goes with your program. By keeping the sources for a program and its
+header and test routine together, you are more likely to keep
+all three consistent with each other. Notice that the output of a named
+section can be incorporated in several different output files, because
+you can mention \.{@<foo@>} in both \.{@(bar1@>} and \.{@(bar2@>}.
+
+\@h [Cc] Causes \.{CTANGLE}
+to insert at the current spot the \.{\#define} statements
+from the middle parts of all sections,
+and {\it not\/} to write them at the beginning of the \CEE/ file.
+Useful when you want the macro definitions to come after the include files,
+say. (Ignored by \.{CTANGLE} inside `\pb'.)
+
+\subsec
+The next several control codes introduce ``control
+texts,'' which end with the next `\.{@>}'. The closing `\.{@>}' must be on
+the same line of the \.{CWEB} file as the line where the control text began.
+The context from each of these control codes to the matching \.{@>} is
+restricted.
+
+\@\^ [TMCc] $*$ The control text that follows, up to the next
+`\.{@>}', will be entered into the index together with the identifiers of
+the \CEE/ program; this text will appear in roman type. For example, to
+put the phrase ``system dependencies'' into the index that is output by
+\.{CWEAVE}, type
+`\.{@\^system dependencies@>}' in each section
+that you want to index as system dependent.
+
+\@. [TMCc] $*$ The control text that follows will be entered into the index
+in \.{typewriter} \.{type}.
+
+\@: [TMCc] $*$ The control text that follows will be entered into the index
+in a format controlled by the \TEX/ macro `\.{\\9}', which you
+should define as desired.
+
+\@t [MCc] $*$ The control text that follows will
+be put into a \TEX/ \.{\\hbox} and formatted along with the neighboring
+\CEE/ program. This text is ignored by \.{CTANGLE}, but it can be used
+for various purposes within \.{CWEAVE}. For example, you can make comments
+that mix \CEE/ and classical mathematics, as in `$\\{size}<2^{15}$', by
+typing `\.{|size < 2@t\$\^\{15\}\$@>|}'.
+
+\@= [MCc] $*$ The control text that follows will
+be passed verbatim to the \CEE/ program.
+
+\@q [LTMCc] $*$ The control text that follows will
+be totally ignored---it's a comment for readers of the \.{CWEB} file only.
+A file intended to be included in
+limbo, with \.{@i}, can identify itself with \.{@q} comments.
+Another use is to balance unbalanced parentheses in \CEE/ strings,
+so that your text editor's parenthesis matcher doesn't go into a tailspin.
+
+\@! [TMCc] $*$
+The section number in an index entry will be underlined if `\.{@!}'
+immediately precedes the identifier or control text being indexed. This
+convention is used to distinguish the sections where an identifier is
+defined, or where it is explained in some special way, from the sections
+where it is used. A~reserved word or an identifier of length one will not
+be indexed except for underlined entries. An `\.{@!}' is implicitly inserted
+by \.{CWEAVE} when an identifier is being defined or declared in \CEE/
+code; for example, the definition
+$$\hbox{\&{int} \\{array}[\\{max\_dim}], \\{count}${}=\\{old\_count};$}$$
+makes the names \\{array} and \\{count} get an underlined entry in the
+index. Statement labels, function definitions like
+\\{main}(\&{int}~\\{argc},\,\&{char}~$*$\\{argv}[\,]),
+and \&{typedef} definitions also
+imply underlining. An old-style
+function definition (without prototyping) doesn't define its arguments;
+the arguments will, however, be considered to be defined
+(i.e., their index entries will be underlined) if their types are
+declared before the body of the function in the usual way
+(e.g., `\&{int}~\\{argc}; \&{char}~${*}\\{argv}[\,]$; $\{\,\ldots\,\}$').
+Thus \.{@!} is not needed very often, except in unusual constructions
+or in cases like
+$$\.{enum boolean \{@!false, @!true\};}$$
+here \.{@!} gives the best results because individual constants enumerated
+by \.{enum} are not automatically underlined in the index at their
+point of definition.
+
+\subsec
+We now turn to control codes that affect only the operation of
+\.{CTANGLE}.
+
+\@' [MCc] This control code is dangerous because it has quite different
+meanings in \.{CWEB} and the original \.{WEB}. In \.{CWEB} it produces the
+decimal constant corresponding to the ASCII code for a string of length~1
+(e.g., \.{@'a'} is \.{CTANGLE}d into \.{97} and \.{@'\\t'} into
+\.9). You might want to use this if you need to work in ASCII on a
+non-ASCII machine; but in most cases the \CEE/ conventions of
+\.{<ctype.h>} are adequate for character-set-independent programming.
+
+\@\& [MCc] The \.{@\&} operation causes whatever is on its left to be
+adjacent to whatever is on its right, in the \CEE/ output. No spaces or
+line breaks will separate these two items.
+
+\@l [L] \.{CWEB} programmers have the option of using any 8-bit character
+code from the often-forbidden range 128--255 within \TEX/ text; such
+characters are also permitted in strings and even in identifiers of the
+\CEE/ program.
+Under various extensions of the basic
+ASCII standard, the higher 8-bit codes correspond
+to accented letters, letters from non-Latin alphabets,
+and so on. When such characters occur in identifiers, \.{CTANGLE} must replace
+them by standard ASCII alphanumeric characters or
+\.{\_}, in order to generate legal \CEE/ code. It does this by means
+of a transliteration table, which by default associates the string
+\.{Xab} to the character with ASCII code \T{\^}$ab$ (where $a$ and $b$ are
+hexadecimal digits, and $a\ge8$). By placing the
+construction \.{@l\ ab\ newstring} in limbo, you are telling
+\.{CTANGLE} to replace this character by \.{newstring} instead.
+For example, the ISO Latin-1 code for the letter `\"u' is \T{\^FC}
+(or \.{'\char`\\374'}),
+and \.{CTANGLE} will normally change this code to the
+three-character sequence \.{XFC} if it
+appears in an identifier. If you say \.{@l} \.{fc} \.{ue}, the code will
+be transliterated into \.{ue} instead.
+
+\more
+\.{CWEAVE} passes 8-bit characters straight through to \TEX/ without
+transliteration; therefore \TEX/ must be prepared to receive them.
+If you are formatting all your nonstandard identifiers as ``custom''
+control sequences, you should
+make \TEX/ treat all their characters as letters. Otherwise you should either
+make your 8-bit codes ``active'' in \TEX/, or load fonts that
+contain the special characters you need in the correct positions.
+(The font selected by \TEX/ control sequence \.{\\it} is used for
+identifiers.)
+Look for special macro packages designed for \.{CWEB} users in your language;
+or, if you are brave, write one yourself.
+
+\subsec
+The next eight control codes (namely `\.{@,}', `\.{@/}', `\.{@|}', `\.{@\#}',
+`\.{@+}', `\.{@;}', `\.{@[}', and `\.{@]}') have no effect on the \CEE/
+program output by \.{CTANGLE}; they merely help to improve the readability
+of the \TEX/-formatted \CEE/ that is output by \.{CWEAVE}, in unusual
+circumstances. \.{CWEAVE}'s built-in formatting method is fairly good
+when dealing with syntactically correct \CEE/ text, but
+it is incapable of handling all possible cases, because it must deal with
+fragments of text involving macros and section names; these fragments do
+not necessarily obey \CEE/'s syntax. Although \.{CWEB} allows you to
+override the automatic formatting, your best strategy is not to worry
+about such things until you have seen what \.{CWEAVE} produces automatically,
+since you will probably need to make only a few corrections when you are
+touching up your documentation.
+
+\@, [MCc] This control code inserts a thin space in \.{CWEAVE}'s output.
+Sometimes you need this extra space if you are using
+macros in an unusual way, e.g., if two identifiers are adjacent.
+
+\@/ [MC] This control code causes a line break to occur within a \CEE/
+program formatted by \.{CWEAVE}. Line breaks
+are chosen automatically by \TEX/ according to a scheme that works 99\%\
+of the time, but sometimes you will prefer to force a line break so that
+the program is segmented according to logical rather than visual
+criteria. If a comment follows, say `\.{@/@,}' to break the line
+before the comment.
+
+\@| [MC] This control code specifies an optional line break in the midst of
+an expression. For example, if you have
+a long expression on the right-hand side of an assignment
+statement, you can use `\.{@|}' to specify breakpoints more logical than
+the ones that \TEX/ might choose on visual grounds.
+
+\@\# [MC] This control code forces a line break, like \.{@/} does,
+and it also causes a little extra white space to appear between the lines at
+this break. You might use it, for example,
+between groups of macro definitions that are logically separate but within
+the same section. \.{CWEB} automatically inserts this extra space
+between functions, between external declarations and functions, and
+between declarations and statements within a function.
+
+\@+ [MC] This control code cancels a line break that might otherwise be
+inserted by \.{CWEAVE}, e.g., before the word `\&{else}', if you want to
+put a short if--else construction on a single line.
+If you say `\.{\{@+}' at the beginning of a compound statement
+that is the body of a function, the first declaration or
+statement of the function will appear on the same line as the
+left brace, and it will be indented by the same amount as the
+second declaration or statement on the next line.
+
+\@; [MC] This control code is treated like a semicolon, for formatting
+purposes, except that it is invisible. You can use it, for example, after
+a section name or macro when the \CEE/ text represented by that section or macro
+is a compound statement or ends
+with a semicolon. Consider constructions like
+$$\lpile{\.{if (condition) macro @;}\cr
+\.{else break;}\cr}$$
+where \\{macro} is defined to be a compound statement (enclosed in braces).
+This is a well-known infelicity of \CEE/ syntax.
+
+\@{[} [MC] See \.{@]}.
+
+\@] [MC] Place \.{@[...@]} brackets around program text that \.{CWEAVE} is
+supposed to format as an expression, if it doesn't already do so. (This
+occasionally applies to unusual macro arguments.) Also
+insert `\.{@[@]}' between a simple type name and a left parenthesis
+when declaring a pointer to a function, as in
+$$\.{int @[@] (*f)();}$$
+otherwise \.{CWEAVE} will confuse the first part of that declaration with
+the \CPLUSPLUS/ expression `\&{int}($*f$)'. Another example, for people
+who want to use low-level \.{\#define} commands in the midst of \CEE/ code
+and the definition begins with a cast:
+$$\.{\#define foo @[(int)(bar)@]}$$
+
+\subsec
+The remaining control codes govern the input that \.{CWEB} sees.
+
+\@{x @y @z}[\\{change\_file}]
+\.{CWEAVE} and \.{CTANGLE} are designed to work with two input files,
+called \\{web\_file} and \\{change\_file}, where \\{change\_file} contains
+data that overrides selected portions of \\{web\_file}. The resulting merged
+text is actually what has been called the \.{CWEB} file elsewhere in this
+report.
+
+\more Here's how it works: The change file consists of zero or more ``changes,''
+where a change has the form `\.{@x}$\langle$old lines$\rangle$\.{@y}$\langle$%
+new lines$\rangle$\.{@z}'. The special control codes \.{@x}, \.{@y}, \.{@z},
+which are allowed only in change files, must appear at the beginning of a line;
+the remainder of such a line is ignored.
+The $\langle$old lines$\rangle$ represent material that exactly matches
+consecutive lines of the \\{web\_file}; the $\langle$new lines$\rangle$
+represent zero or more lines that are supposed to replace the old. Whenever
+the first ``old line'' of a change is found to match a line in the
+\\{web\_file}, all the other lines in that change must match too.
+
+\more Between changes, before the first change, and after the last change,
+the change file can have any number of lines that do not begin with
+`\.{@x}', `\.{@y}', or~`\.{@z}'. Such lines are bypassed and not used for
+matching purposes.
+
+\more This dual-input feature is useful when working with a master \.{CWEB}
+file that has been received from elsewhere (e.g., \.{tangle.w} or
+\.{weave.w} or \.{tex.web}), when changes are desirable to customize the
+program for your local computer system. You will be able to debug your
+system-dependent changes without clobbering the master web file; and once
+your changes are working, you will be able to incorporate them readily
+into new releases of the master web file that you might receive from time
+to time.
+
+\@i [\\{web\_file}]
+Furthermore the \\{web\_file} itself can be a combination of
+several files. When either \.{CWEAVE} or \.{CTANGLE} is reading a file and
+encounters the control code \.{@i} at the beginning of a line, it
+interrupts normal reading and starts looking at the file named after the
+\.{@i}, much as the \CEE/ preprocessor does when it encounters an \.{\#include}
+line. After the included file has been entirely read, the program
+goes back to the next line
+of the original file. The file name following \.{@i} can be
+surrounded by \." characters, but such delimiters are
+optional. Include files can nest.
+
+\more
+Change files can have lines starting with \.{@i}. In this way
+you can replace one included file with another. Conceptually, the
+replacement mechanism described above does its work first, and
+its output is then checked for \.{@i} lines. If \.{@i} \.{foo}
+occurs between \.{@y} and \.{@z} in a change file, individual lines
+of file \.{foo} and files it includes are not changeable; but changes
+can be made to lines from files that were included by unchanged input.
+
+\more On \UNIX/ systems (and others that support environment variables),
+if the environment variable \.{CWEBINPUTS} is set, or if the compiler flag
+of the same name was defined at compile time,
+\.{CWEB} will look for include files in the directory thus named, if
+it cannot find them in the current directory.
+
+\section Additional features and caveats.
+
+1. In certain installations of \.{CWEB} that
+{\def\\#1#2{`{\tentex\char'#1#2}'}%
+have an extended character set, the characters
+\\13, \\01, \\31, \\32, \\34, \\35,
+\\36, \\37, \\04, \\20, and \\21}
+can be typed as abbreviations for `\.{++}', `\.{--}', `\.{->}',
+`\.{!=}', `\.{<=}', `\.{>=}', `\.{==}', `\.{\v\v}', `\.{\&\&}',
+`\.{<<}', and `\.{>>}',
+respectively.
+
+2. If you have an extended character set, you can use it with only minimal
+restrictions, as discussed under the rules for \.{@l} above. But you should
+stick to standard ASCII characters if you want to write programs that will
+be useful to all the poor souls out there who don't have extended
+character sets.
+
+3. The \TEX/ file output by \.{CWEAVE} is broken into lines having at most
+80 characters each. When
+\TEX/ text is being copied, the existing line breaks are copied as well.
+If you aren't doing anything too tricky, \.{CWEAVE} will recognize when
+a \TEX/ comment is being split across two or more lines, and it will
+append `\.\%' to the beginning of such continued comments.
+
+4. \CEE/ text is translated by a ``bottom up'' procedure that
+identifies each token as a ``part of speech'' and combines parts of speech
+into larger and larger phrases as much as possible according to a special
+grammar that is explained in the documentation of \.{CWEAVE}. It is easy to
+learn the translation scheme for simple constructions like single
+identifiers and short expressions, just by looking at a few examples of
+what \.{CWEAVE} does, but the general mechanism is somewhat complex because
+it must handle much more than \CEE/ itself. Furthermore the output
+contains embedded codes that cause \TEX/ to indent and break lines as
+necessary, depending on the fonts used and the desired page width. For
+best results it is wise to avoid enclosing long \CEE/ texts in \pb, since the
+indentation and line breaking codes are omitted when the \pb\ text is
+translated from \CEE/ to \TEX/. Stick to simple expressions or
+statements. If a \CEE/ preprocessor command is enclosed in \pb,
+the \.\# that introduces it must be at the beginning of a line,
+or \.{CWEAVE} won't print it correctly.
+
+5. Comments are not permitted in \pb\ text. After a `\.|'
+signals the change from \TEX/ text to \CEE/ text, the next `\.|' that is
+not part of a string or control text or section name ends the \CEE/ text.
+
+6. A comment must have properly nested occurrences of left and right
+braces, otherwise \.{CWEAVE} will complain. But it
+does try to balance the braces, so that \TEX/ won't foul up too much.
+
+7. When you're debugging a program and decide to omit some of your
+\CEE/ code, do NOT simply ``comment it out.'' Such comments are not
+in the spirit of \.{CWEB} documentation; they will appear to readers
+as if they were explanations of the uncommented-out instructions.
+Furthermore, comments of a program must be valid \TEX/ text; hence
+\.{CWEAVE} will get confused if you enclose \CEE/ statements in
+\.{/*...*/} instead of in \.{/*|...|*/}. If you must comment out
+\CEE/ code, you can surround it with preprocessor commands
+like \.{\#if 0==1} and \.{\#endif}.
+
+8. The \.{@f} feature allows you to define one identifier to act like
+another, and these format definitions are carried out sequentially.
+In general, a given identifier has only one printed format
+throughout the entire document, and this format is used even before
+the \.{@f} that defines it. The reason is that \.{CWEAVE} operates in two
+passes; it processes \.{@f}'s and cross-references on the first pass and
+it does the output on the second. (However, identifiers that
+implicitly get a boldface format, thanks to a \.{typedef} declaration,
+don't obey this rule; they are printed differently before and after
+the relevant \.{typedef}. This is unfortunate, but hard to fix. You can
+get around the restriction by saying, say, `\.{@s} \.{foo} \.{int}',
+before or after the \.{typedef}.)
+
+9. Sometimes it is desirable to insert spacing into formatted \CEE/ code that
+is more general than the thin space provided by `\.{@,}'. The \.{@t} feature
+can be used for this purpose; e.g., `\.{@t\\hskip 1in@>}' will
+leave one inch of blank space. Furthermore, `\.{@t\\4@>}' can be
+used to backspace by one unit of indentation, since the control sequence
+\.{\\4} is defined in \.{cwebmac} to be such a backspace. (This
+control sequence is used, for example, at the beginning of lines that
+contain labeled statements, so that the label will stick out a little at
+the left.) You can also use `\.{@t\}\\3\{-5@>}' to force a break
+in the middle of an expression.
+
+10. Each identifier in \.{CWEB} has a single formatting convention. Therefore
+you shouldn't use the same identifier to denote, say, both a type name and
+part of a \.{struct}, even though \CEE/ does allow this.
+
+\section Running the programs.
+The \UNIX/ command line for \.{CTANGLE} is
+$$\.{ctangle [options] web\_file[.w] [\{change\_file[.ch]|-\} [out\_file]]}$$
+and the same conventions apply to \.{CWEAVE}. If `\.-' or no change file is
+specified, the change file is null. The extensions \.{.w} and \.{.ch}
+are appended only if the given file names contain no dot. If the
+web file defined in this way cannot be found, the extension \.{.web}
+will be tried. For example, `\.{cweave} \.{cob}' will try to read
+\.{cob.w}; failing that, it will try \.{cob.web} before giving up.
+If no output file name is specified, the name of the \CEE/ file output by
+\.{CTANGLE} is obtained by appending the extension \.{.c};
+the name of the \TEX/ file output by \.{CWEAVE} gets the extension \.{.tex}.
+Index files output by \.{CWEAVE} replace \.{.tex} by \.{.idx} and \.{.scn}.
+
+Programmers who like terseness might choose to set up their
+ operating shell so that `\.{wv}' expands to
+`\.{cweave -bhp}'; this will suppress most terminal output from \.{CWEAVE}
+except for error messages.
+
+Options are introduced either by a \.- sign, to turn an option off,
+or by a \.+ sign to turn one on. For example, `\.{-fb}' turns off
+options \.f and \.b; `\.{+s}' turns on option \.s. Options can be
+specified before the file names, after the file names, or both. The following
+options are currently implemented:
+
+\yskip
+\def\option#1 {\textindent{\.#1}\hangindent2\parindent}
+
+\option b Print a banner line at the beginning of execution. (On
+by default.)
+
+\option e Enclose \CEE/ material formatted by \.{CWEAVE} in
+brackets \.{\\PB\{...\}}, so that special hooks can be used.
+(Off by default; has no effect on \.{CTANGLE}.)
+
+\option f Force line breaks after each \CEE/ statement formatted
+by \.{CWEAVE}. (On by default; \.{-f} saves paper but looks less \CEE/-like
+to some people.) (Has no effect on \.{CTANGLE}.)
+
+\option h Print a happy message at the conclusion of a successful
+run. (On by default.)
+
+\option p Give progress reports as the program runs. (On by default.)
+
+\option s Show statistics about memory usage after the program
+runs to completion. (Off by default.)
+If you
+have large \.{CWEB} files or sections, you may need to see
+how close you come to exceeding the capacity of \.{CTANGLE} and/or \.{CWEAVE}.
+
+\option x Include indexes and a table of contents in the \TEX/ file
+output by \.{CWEAVE}. (On by default.) (Has no effect on \.{CTANGLE}.)
+
+\section Further details about formatting.
+You may not like the way \.{CWEAVE} handles certain
+situations. If you're desperate, you can customize \.{CWEAVE}
+by changing its grammar. This means changing the source code,
+a task that you might find amusing. A table of grammar rules
+appears in the \.{CWEAVE} source listing, and you can make a separate
+copy of that table by copying the file \.{prod.w} found in the \.{CWEB}
+sources and saying `\.{cweave}~\.{-x}~\.{prod}', followed by
+`\.{tex}~\.{prod}'.
+
+You can see exactly
+how \.{CWEAVE} is parsing your \CEE/ code by preceding
+it with the line `\.{@ @c @2}'. (The control code `\.{@2}'
+turns on a ``peeping'' mode, and `\.{@0}' turns it off.)
+For example, if you run \.{CWEAVE} on the file
+\medskip
+\begingroup
+\verbatim
+@ @c @2
+main (argc,argv)
+char **argv;
+{ for (;argc>0;argc--) printf("%s\n",argv[argc-1]); }
+!endgroup
+\endgroup
+\medskip\noindent
+you get the following gibberish on your screen:
+\medskip
+\begingroup
+\verbatim
+[...]
+14:*exp +(+ exp...
+11:*exp +exp+ raw...
+10:*+exp+ raw +ubinop?+...
+[...]
+60: +fn_decl+*+{+ -stmt- +}-
+55:*+fn_decl+ -stmt-
+52:*+function-
+[...]
+!endgroup
+\endgroup
+\medskip
+The first line says that grammar rule 14 has just been applied, and \.{CWEAVE}
+currently has in its memory a sequence of chunks of \TEX/ code (called
+``scraps'') that are respectively
+of type \\{exp} (for expression), open-parenthesis,
+\\{exp} again, close-parenthesis, and further scraps that haven't yet
+been considered by the parser. (The \.+ and \.- signs stipulate that
+\TEX/ should be in or out of math mode at the scrap boundaries. The \.* shows
+the parser's current position.)
+Then rule 11 is applied, and
+the sequence $(\,exp\,)$ becomes an \\{exp} and so on. In the
+end the whole \CEE/ text has become one big scrap of type \\{function}.
+
+Sometimes things don't work as smoothly, and you get a bunch of
+lines lumped together. This means that \.{CWEAVE} could not
+digest something in your \CEE/ code. For instance, suppose
+`\.{@<Argument definitions@>}' had appeared instead of
+`\.{char **argv;}' in the program above. Then \.{CWEAVE} would have
+been somewhat mystified, since it thinks that section names
+are just \\{exp}s. Thus it would tell \TEX/ to format
+`\X2:Argument declarations\X' on the same line as
+`$\\{main}(\\{argc},\39\\{argv}{}$)'.
+In this case you should help \.{CWEAVE} by putting `\.{@/}' after
+`\.{main(argc,argv)}'.
+
+\.{CWEAVE} automatically inserts a bit of extra space between declarations
+and the first apparent statement of a block. One way to defeat this
+spacing locally is
+$$\vbox{\halign{#\hfil\cr
+\.{int x;@+@t\}\\6\{@>}\cr
+\.{@<Other locals@>@;@\#}\cr}}$$
+the `\.{@\#}' will put extra space after `$\langle\,$Other locals$\,\rangle$'.
+
+\section Hypertext and hyperdocumentation.
+
+Many people have of course noticed analogies between \.{CWEB} and the
+World Wide Web. The \.{CWEB} macros are in fact set up so that the output of
+\.{CWEAVE} can be converted easily into Portable Document Format,
+with clickable hyperlinks that can be read with Adobe's Acrobat Reader,
+using a widely available open-source program called \.{dvipdfm} developed
+by Mark~A. Wicks. After using \.{CWEAVE} to convert \.{cob.w} into
+\.{cob.tex}, you can prepare and view a hypertext version of the program
+by giving the commands
+$$\vbox{\halign{\.{#}\hfil\cr
+tex "\\let\\pdf+ \\input cob"\cr
+dvipdfm cob\cr
+acroread cob.pdf\cr}}$$
+instead of invoking \TeX\ in the normal way. (Thanks to Hans Hagen,
+C\'esar Augusto Rorato Crusius, and Julian Gilbey
+for the macros that make this work.)
+Alternatively, thanks to H\`an Th\^e\kern-.3em\raise.3ex\hbox{\'{}} Th\`anh
+and Andreas Scherer, you can generate \.{cob.pdf} in one step by simply
+saying `\.{pdftex}~\.{cob}'.
+
+A more elaborate system called \.{CTWILL}, which extends the usual cross
+references of \.{CWEAVE} by preparing links from the uses of identifiers
+to their definitions, is also available---provided that you are willing
+to work a bit harder in cases where an identifier is multiply defined.
+\.{CTWILL} is intended primarily for hardcopy output, but its principles
+could be used for hypertext as well.
+See Chapter 11 of {\sl Digital Typography\/} by D.~E. Knuth (1999), and
+the program sources at \.{ftp://ftp.cs.stanford.edu/pub/ctwill}.
+
+\section Appendices.
+
+As an example of a real program written in \.{CWEB}, Appendix~A
+contains an excerpt from the \.{CWEB} program itself. The reader who
+examines the listings in this appendix carefully will get a good
+feeling for the basic ideas of \.{CWEB}.
+
+Appendix B is the file that sets \TEX/ up to accept
+the output of \.{CWEAVE}, and Appendix~C discusses how to use some of those
+macros to vary the output formats.
+
+A ``long'' version of this manual, which can be produced from the \.{CWEB}
+sources via the \UNIX/ command \.{make} \.{fullmanual}, also contains
+appendices D, E, and~F, which exhibit the complete source code for
+\.{CTANGLE} and \.{CWEAVE}.
+
+\vfil\eject\titletrue
+
+\def\runninghead{APPENDIX A --- {\tentt CWEB} FILE FORMAT}
+\section Appendix A: Excerpts from a \.{CWEB} Program.
+
+This appendix consists
+of four listings. The first shows the \.{CWEB} input that
+generated sections 12--15 of the file \.{common.w}, which contains
+routines common to \.{CWEAVE} and \.{CTANGLE}.
+Note that some of the lines are indented to show the program structure;
+the indentation is ignored by \.{CWEAVE} and \.{CTANGLE}, but users find
+that \.{CWEB} files are quite readable if they have some such indentation.
+
+The second and third listings
+show corresponding parts
+of the \CEE/ code output by \.{CTANGLE} and of
+the corresponding \TEX/ code output by \.{CWEAVE}, when run on \.{common.w}.
+The fourth listing shows how that output looks when printed out.
+
+\vskip 6pt
+\begingroup \def\tt{\eighttt} \baselineskip9pt
+\verbatim
+@ Procedure |prime_the_change_buffer|
+sets |change_buffer| in preparation for the next matching operation.
+Since blank lines in the change file are not used for matching, we have
+|(change_limit==change_buffer && !!changing)| if and only if
+the change file is exhausted. This procedure is called only when
+|changing| is 1; hence error messages will be reported correctly.
+
+@c
+void
+prime_the_change_buffer()
+{
+ change_limit=change_buffer; /* this value is used if the change file ends */
+ @<Skip over comment lines in the change file; |return| if end of file@>;
+ @<Skip to the next nonblank line; |return| if end of file@>;
+ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>;
+}
+
+@ While looking for a line that begins with \.{@@x} in the change file, we
+allow lines that begin with \.{@@}, as long as they don't begin with \.{@@y},
+\.{@@z}, or \.{@@i} (which would probably mean that the change file is fouled up).
+
+@<Skip over comment lines in the change file...@>=
+while(1) {
+ change_line++;
+ if (!!input_ln(change_file)) return;
+ if (limit<buffer+2) continue;
+ if (buffer[0]!!='@@') continue;
+ if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]);
+ if (buffer[1]=='x') break;
+ if (buffer[1]=='y' || buffer[1]=='z' || buffer[1]=='i') {
+ loc=buffer+2;
+ err_print("!! Missing @@x in change file");
+@.Missing @@x...@>
+ }
+}
+
+@ Here we are looking at lines following the \.{@@x}.
+
+@<Skip to the next nonblank line...@>=
+do {
+ change_line++;
+ if (!!input_ln(change_file)) {
+ err_print("!! Change file ended after @@x");
+@.Change file ended...@>
+ return;
+ }
+} while (limit==buffer);
+
+@ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>=
+{
+ change_limit=change_buffer-buffer+limit;
+ strncpy(change_buffer,buffer,limit-buffer+1);
+}
+
+!endgroup
+\endgroup
+\vfill\eject
+
+\def\runninghead{APPENDIX A --- TRANSLATION BY {\tentt CTANGLE}}
+
+Here's the portion of the \CEE/ code generated by \.{CTANGLE} that corresponds
+to the source on the preceding page. Notice that sections~13, 14 and~15
+have been tangled into section~12.
+
+\vskip6pt
+\begingroup \def\tt{\eighttt} \baselineskip9pt
+\verbatim
+/*:9*//*12:*/
+#line 247 "common.w"
+
+void
+prime_the_change_buffer()
+{
+change_limit= change_buffer;
+/*13:*/
+#line 261 "common.w"
+
+while(1){
+change_line++;
+if(!!input_ln(change_file))return;
+if(limit<buffer+2)continue;
+if(buffer[0]!!='@')continue;
+if(xisupper(buffer[1]))buffer[1]= tolower(buffer[1]);
+if(buffer[1]=='x')break;
+if(buffer[1]=='y'||buffer[1]=='z'||buffer[1]=='i'){
+loc= buffer+2;
+err_print("!! Missing @x in change file");
+
+}
+}
+
+/*:13*/
+#line 252 "common.w"
+;
+/*14:*/
+#line 278 "common.w"
+
+do{
+change_line++;
+if(!!input_ln(change_file)){
+err_print("!! Change file ended after @x");
+
+return;
+}
+}while(limit==buffer);
+
+/*:14*/
+#line 253 "common.w"
+;
+/*15:*/
+#line 288 "common.w"
+
+{
+change_limit= change_buffer-buffer+limit;
+strncpy(change_buffer,buffer,limit-buffer+1);
+}
+
+/*:15*/
+#line 254 "common.w"
+;
+}
+
+/*:12*//*16:*/
+!endgroup
+\endgroup
+\vfill\eject
+
+\def\runninghead{APPENDIX A --- TRANSLATION BY {\tentt CWEAVE}}
+
+Here is the corresponding excerpt from \.{common.tex}.
+
+\vskip6pt
+\begingroup \def\tt{\eighttt} \baselineskip9pt
+\verbatim
+\M{12}Procedure \PB{\\{prime\_the\_change\_buffer}}
+sets \PB{\\{change\_buffer}} in preparation for the next matching operation.
+Since blank lines in the change file are not used for matching, we have
+\PB{$(\\{change\_limit}\E\\{change\_buffer}\W\R\\{changing})$} if and only if
+the change file is exhausted. This procedure is called only when
+\PB{\\{changing}} is 1; hence error messages will be reported correctly.
+!vskip-.5!baselineskip
+\Y\B\&{void} \\{prime\_the\_change\_buffer}(\,)\1\1\2\2\6
+${}\{{}$\1\6
+${}\\{change\_limit}\K\\{change\_buffer}{}$;\C{ this value is used if the
+change file ends }\6
+\X13:Skip over comment lines in the change file; \PB{\&{return}} if end of file%
+\X;\6
+\X14:Skip to the next nonblank line; \PB{\&{return}} if end of file\X;\6
+\X15:Move \PB{\\{buffer}} and \PB{\\{limit}} to \PB{\\{change\_buffer}} and %
+\PB{\\{change\_limit}}\X;\6
+\4${}\}{}$\2\par
+\fi
+!vskip-.5!baselineskip
+\M{13}While looking for a line that begins with \.{@x} in the change file, we
+allow lines that begin with \.{@}, as long as they don't begin with \.{@y},
+\.{@z}, or \.{@i} (which would probably mean that the change file is fouled
+up).
+!vskip-.5!baselineskip
+\Y\B\4\X13:Skip over comment lines in the change file; \PB{\&{return}} if end
+of file\X${}\E{}$\6
+\&{while} (\T{1})\5
+${}\{{}$\1\6
+${}\\{change\_line}\PP;{}$\6
+\&{if} ${}(\R\\{input\_ln}(\\{change\_file})){}$\1\5
+\&{return};\2\6
+\&{if} ${}(\\{limit}<\\{buffer}+\T{2}){}$\1\5
+\&{continue};\2\6
+\&{if} ${}(\\{buffer}[\T{0}]\I\.{'@'}){}$\1\5
+\&{continue};\2\6
+\&{if} (\\{xisupper}(\\{buffer}[\T{1}]))\1\5
+${}\\{buffer}[\T{1}]\K\\{tolower}(\\{buffer}[\T{1}]);{}$\2\6
+\&{if} ${}(\\{buffer}[\T{1}]\E\.{'x'}){}$\1\5
+\&{break};\2\6
+\&{if} ${}(\\{buffer}[\T{1}]\E\.{'y'}\V\\{buffer}[\T{1}]\E\.{'z'}\V\\{buffer}[%
+\T{1}]\E\.{'i'}){}$\5
+${}\{{}$\1\6
+${}\\{loc}\K\\{buffer}+\T{2};{}$\6
+\\{err\_print}(\.{"!!\ Missing\ @x\ in\ cha}\)\.{nge\ file"});\6
+\4${}\}{}$\2\6
+\4${}\}{}$\2\par
+\U12.\fi
+!vskip-.5!baselineskip
+\M{14}Here we are looking at lines following the \.{@x}.
+!vskip-.5!baselineskip
+\Y\B\4\X14:Skip to the next nonblank line; \PB{\&{return}} if end of file\X${}%
+\E{}$\6
+\&{do}\5
+${}\{{}$\1\6
+${}\\{change\_line}\PP;{}$\6
+\&{if} ${}(\R\\{input\_ln}(\\{change\_file})){}$\5
+${}\{{}$\1\6
+\\{err\_print}(\.{"!!\ Change\ file\ ended}\)\.{\ after\ @x"});\6
+\&{return};\6
+\4${}\}{}$\2\6
+\4${}\}{}$\2\5
+\&{while} ${}(\\{limit}\E\\{buffer}){}$;\par
+\U12.\fi
+!vskip-.5!baselineskip
+\M{15}\B\X15:Move \PB{\\{buffer}} and \PB{\\{limit}} to \PB{\\{change\_buffer}}
+and \PB{\\{change\_limit}}\X${}\E{}$\6
+${}\{{}$\1\6
+${}\\{change\_limit}\K\\{change\_buffer}-\\{buffer}+\\{limit};{}$\6
+${}\\{strncpy}(\\{change\_buffer},\39\\{buffer},\39\\{limit}-\\{buffer}+%
+\T{1});{}$\6
+\4${}\}{}$\2\par
+\Us12\ET16.\fi
+!endgroup
+\endgroup
+\vfil\eject
+
+\def\runninghead{APPENDIX A --- FINAL DOCUMENT}
+
+And here's what the same excerpt looks like when typeset.
+
+\M{12}Procedure \PB{\\{prime\_the\_change\_buffer}}
+sets \PB{\\{change\_buffer}} in preparation for the next matching operation.
+Since blank lines in the change file are not used for matching, we have
+\PB{$(\\{change\_limit}\E\\{change\_buffer}\W\R\\{changing})$} if and only if
+the change file is exhausted. This procedure is called only when
+\PB{\\{changing}} is 1; hence error messages will be reported correctly.
+
+\Y\B\&{void} \\{prime\_the\_change\_buffer}(\,)\1\1\2\2\6
+${}\{{}$\1\6
+${}\\{change\_limit}\K\\{change\_buffer}{}$;\C{ this value is used if the
+change file ends }\6
+\X13:Skip over comment lines in the change file; \PB{\&{return}} if end of file%
+\X;\6
+\X14:Skip to the next nonblank line; \PB{\&{return}} if end of file\X;\6
+\X15:Move \PB{\\{buffer}} and \PB{\\{limit}} to \PB{\\{change\_buffer}} and %
+\PB{\\{change\_limit}}\X;\6
+\4${}\}{}$\2\par
+\fi
+
+\M{13}While looking for a line that begins with \.{@x} in the change file, we
+allow lines that begin with \.{@}, as long as they don't begin with \.{@y},
+\.{@z}, or \.{@i} (which would probably mean that the change file is fouled up).
+
+\Y\B\4\X13:Skip over comment lines in the change file; \PB{\&{return}} if end
+of file\X${}\E{}$\6
+\&{while} (\T{1})\5
+${}\{{}$\1\6
+${}\\{change\_line}\PP;{}$\6
+\&{if} ${}(\R\\{input\_ln}(\\{change\_file})){}$\1\5
+\&{return};\2\6
+\&{if} ${}(\\{limit}<\\{buffer}+\T{2}){}$\1\5
+\&{continue};\2\6
+\&{if} ${}(\\{buffer}[\T{0}]\I\.{'@'}){}$\1\5
+\&{continue};\2\6
+\&{if} (\\{xisupper}(\\{buffer}[\T{1}]))\1\5
+${}\\{buffer}[\T{1}]\K\\{tolower}(\\{buffer}[\T{1}]);{}$\2\6
+\&{if} ${}(\\{buffer}[\T{1}]\E\.{'x'}){}$\1\5
+\&{break};\2\6
+\&{if} ${}(\\{buffer}[\T{1}]\E\.{'y'}\V\\{buffer}[\T{1}]\E\.{'z'}\V\\{buffer}[%
+\T{1}]\E\.{'i'}){}$\5
+${}\{{}$\1\6
+${}\\{loc}\K\\{buffer}+\T{2};{}$\6
+\\{err\_print}(\.{"!\ Missing\ @x\ in\ cha}\)\.{nge\ file"});\6
+\4${}\}{}$\2\6
+\4${}\}{}$\2\par
+\U12.\fi
+
+\M{14}Here we are looking at lines following the \.{@x}.
+
+\Y\B\4\X14:Skip to the next nonblank line; \PB{\&{return}} if end of file\X${}%
+\E{}$\6
+\&{do}\5
+${}\{{}$\1\6
+${}\\{change\_line}\PP;{}$\6
+\&{if} ${}(\R\\{input\_ln}(\\{change\_file})){}$\5
+${}\{{}$\1\6
+\\{err\_print}(\.{"!\ Change\ file\ ended}\)\.{\ after\ @x"});\6
+\&{return};\6
+\4${}\}{}$\2\6
+\4${}\}{}$\2\5
+\&{while} ${}(\\{limit}\E\\{buffer}){}$;\par
+\U12.\fi
+
+\M{15}\B\X15:Move \PB{\\{buffer}} and \PB{\\{limit}} to \PB{\\{change\_buffer}}
+and \PB{\\{change\_limit}}\X${}\E{}$\6
+${}\{{}$\1\6
+${}\\{change\_limit}\K\\{change\_buffer}-\\{buffer}+\\{limit};{}$\6
+${}\\{strncpy}(\\{change\_buffer},\39\\{buffer},\39\\{limit}-\\{buffer}+%
+\T{1});{}$\6
+\4${}\}{}$\2\par
+\Us12\ET16.\fi
+
+\vfil\eject\titletrue
+\rightskip=0pt % get out of C mode (cf. \B)
+\sfcode`;=1500 \pretolerance 200 \hyphenpenalty 50 \exhyphenpenalty 50
+
+\def\runninghead{APPENDIX B --- MACROS FOR FORMATTING}
+\section Appendix B: The \.{cwebmac.tex} file.
+This is the file that extends ``plain \TEX/'' format in order to support the
+features needed by the output of \.{CWEAVE}.
+
+\vskip6pt
+\begingroup \def\tt{\eighttt} \baselineskip9pt
+\def\printmacs{\begingroup
+ \def\do##1{\catcode`##1=12 } \dospecials
+ \parskip 0pt \parindent 0pt
+ \catcode`\ =13 \catcode`\^^M=13
+ \tt \verbatimdefs \input cwebmac \endgroup}
+\printmacs
+\endgroup
+\vfill\eject
+
+\def\runninghead{APPENDIX C --- NOTES ON FORMATTING}
+\section Appendix C: How to use \.{CWEB} macros.
+The macros in \.{cwebmac} make it possible to produce a variety of formats
+without editing the output of \.{CWEAVE}, and the purpose of this appendix
+is to explain some of the possibilities.
+
+\def\point#1.{\yskip\indent#1.\quad\ignorespaces}
+
+\point 1. Four fonts have been declared in addition to the standard fonts of
+\.{PLAIN} format: You can say `\.{\{\\mc UNIX\}}' to get {\mc UNIX} in
+medium-size caps; you can say `\.{\{\\sc STUFF\}}' to get {\sc STUFF}
+in small caps; and you can select the largish fonts \.{\\titlefont}
+and \.{\\ttitlefont} in the title of your document, where \.{\\ttitlefont}
+is a typewriter style of type. There are macros \.{\\UNIX/} and \.{\\CEE/}
+to refer to \UNIX/ and \CEE/ with medium-size caps.
+
+\point 2. When you mention an identifier in \TEX/ text, you normally call
+it `\.{|identifier|}'. But you can also say `\.{\\\\\{identifier\}}'. The
+output will look the same in both cases, but the second alternative
+doesn't put \\{identifier} into the index, since
+it bypasses \.{CWEAVE}'s translation from \CEE/ mode. In the second
+case you must put a backslash before each underline character
+in the identifier.
+
+\point 3. To get typewriter-like type, as when referring to `\.{CWEB}', you
+can use the `\.{\\.}' macro (e.g., `\.{\\.\{CWEB\}}'). In the argument to
+this macro you should insert an additional backslash before the symbols
+listed as `special string characters' in the index to \.{CWEAVE}, i.e.,
+before backslashes and dollar signs and the like.
+A `\.{\\\ }' here will result in the visible space symbol; to get an
+invisible space following a control sequence you can say `\.{\{\ \}}'.
+If the string is long, you can break it up into substrings that
+are separated by `\.{\\)}'\,; the latter gives a discretionary backslash
+if \TEX/ has to break a line here.
+
+\point 4. The three control sequences \.{\\pagewidth}, \.{\\pageheight},
+and \.{\\fullpageheight} can be redefined in the limbo section at the
+beginning of your \.{CWEB} file, to change the dimensions of each page.
+The default settings
+$$\lpile{\.{\\pagewidth=6.5in}\cr
+ \.{\\pageheight=8.7in}\cr
+ \.{\\fullpageheight=9in}\cr}$$
+were used to prepare this manual; \.{\\fullpageheight} is
+\.{\\pageheight} plus room for the additional heading and page numbers at
+the top of each page. If you change any of these quantities, you should
+call the macro \.{\\setpage} immediately after making the change.
+
+\point 5. The \.{\\pageshift} macro defines an amount by which right-hand
+pages (i.e., odd-numbered pages) are shifted right with respect to
+left-hand (even-numbered) ones. By adjusting this amount you may be
+able to get two-sided output in which the page numbers line up on
+opposite sides of each sheet.
+
+\point 6. The \.{\\title} macro will appear at the top of each page
+in small caps; it is the job name unless redefined.
+
+\point 7. The first page usually is assigned page
+number 1. To start on page 16, with contents
+on page 15, say this: `\.{\\def\\contentspagenumber\{15\}}
+\.{\\pageno=\\contentspagenumber} \.{\\advance\\pageno by 1}'.
+
+\point 8. The macro \.{\\iftitle} will suppress the header line if it is
+defined by `\.{\\titletrue}'. The normal value is \.{\\titlefalse}
+except for the table of contents; thus, the contents
+page is usually unnumbered.
+
+Two macros are provided to give flexibility to the table of
+contents: \.{\\topofcontents} is invoked just before the contents
+info is read, and \.{\\botofcontents} is invoked just after.
+Here's a typical definition:
+$$\lpile{\.{\\def\\topofcontents\{\\null\\vfill}\cr
+ \.{ { }\\titlefalse \% include headline on the contents page}\cr
+ \.{ { }\\def\\rheader\{\\mainfont The \{\\tt CWEAVE\}{ }processor\\hfil\}}\cr
+ \.{ { }\\centerline\{\\titlefont The \{\\ttitlefont CWEAVE\}{ }processor\}}\cr
+ \.{ { }\\vskip 15pt \\centerline\{(Version 3.64)\}{ }\\vfill\}}\cr}$$
+Redefining \.{\\rheader}, which is the headline for right-hand pages,
+suffices in this case to put the desired information at the top of the
+contents page.
+
+\point 9. Data for the table of contents is written to a file that
+is read after the indexes have been \TEX/ed; there's one line of data
+for every starred section. The file \.{common.toc} might look like this:
+$$\lpile{\.{\\ZZ \{Introduction\}\{0\}\{1\}\{28\}\{\}}\cr
+ \.{\\ZZ \{The character set\}\{2\}\{5\}\{29\}\{\}}\cr}$$
+and so on. The \.{\\topofcontents} macro could
+redefine \.{\\ZZ} so that the information appears in any desired format.
+(See also point~19 below.)
+
+\point 10. Sometimes it is necessary or desirable to divide the output of
+\.{CWEAVE} into subfiles that can be processed separately. For example,
+the listing of \TEX/ runs to more than 500 pages, and that is enough to
+exceed the capacity of many printing devices and/or their software.
+When an extremely large job isn't cut into smaller pieces, the entire
+process might be spoiled by a single error of some sort, making it
+necessary to start everything over.
+
+Here's a safe way to break a woven file into three parts:
+Say the pieces are $\alpha$,
+$\beta$, and $\gamma$, where each piece begins with a starred section.
+All macros should be defined in the opening limbo section of $\alpha$,
+and copies of this \TEX/ code should be placed at the
+beginning of $\beta$ and of $\gamma$. In order to process the parts
+separately, we need to take care of two things: The starting page
+numbers of $\beta$ and $\gamma$ need to be set up properly, and
+the table of contents data from all three runs needs to be
+accumulated.
+
+The \.{cwebmac} macros include two control sequences \.{\\contentsfile} and
+\.{\\readcontents} that facilitate the necessary processing. We include
+`\.{\\def\\contentsfile\{cont1\}}' in the limbo section of $\alpha$, and
+we include `\.{\\def\\contentsfile\{cont2\}}' in the limbo section of
+$\beta$; this causes \TEX/ to write the contents data for $\alpha$ and $\beta$
+into \.{cont1.tex} and \.{cont2.tex}. Now in $\gamma$ we say
+$$\.{\\def\\readcontents\{\\input cont1 \\input cont2
+ \\input \\contentsfile\}}\,;$$
+this brings in the data from all three pieces, in the proper order.
+
+However, we still need to solve the page-numbering problem. One way to
+do it is to include the following in the limbo material for $\beta$:
+$$\lpile{\.{\\message\{Please type the last page number of part 1: \}}\cr
+ \.{\\read -1 to \\temp \\pageno=\\temp \\advance\\pageno by 1}\cr}$$
+Then you simply provide the necessary data when \TEX/ requests
+it; a similar construction is used at the beginning of $\gamma$.
+
+This method can, of course, be used to divide a woven file into
+any number of pieces.
+
+\point 11. Sometimes it is nice to include things in the index that are
+typeset in a special way. For example, we might want to have an
+index entry for `\TeX'. \.{CWEAVE} provides two simple ways to
+typeset an index entry (unless the entry is an identifier or a reserved word):
+`\.{@\^}' gives roman type, and `\.{@.}' gives typewriter type.
+But if we try to typeset `\TeX' in roman type by saying, e.g.,
+`\.{@\^\\TeX@>}', the backslash character gets in the way,
+and this entry wouldn't appear in the index with the T's.
+
+The solution is to use the `\.{@:}' feature, declaring a macro that
+simply removes a sort key as follows:
+$$\.{\\def\\9\#1\{\}}$$
+Now you can say, e.g., `\.{@:TeX\}\{\\TeX@>}' in your \.{CWEB} file; \.{CWEAVE}
+puts it into the index alphabetically, based on the sort key, and
+produces the macro call `\.{\\9\{TeX\}\{\\TeX\}}' which will ensure that
+the sort key isn't printed.
+
+A similar idea can be used to insert hidden material into section
+names so that they are alphabetized in whatever way you might wish.
+Some people call these tricks ``special refinements''; others call
+them ``kludges.''
+
+\point 12. The control sequence \.{\\secno} is set to the number of the
+section being typeset.
+
+\point 13. If you want to list only the sections that have changed,
+together with the index, put the command `\.{\\let\\maybe=\\iffalse}' in
+the limbo section before the first section of your \.{CWEB} file. It's
+customary to make this the first change in your change file.
+
+This feature has a \TeX nical limitation, however: You cannot use it
+together with control sequences like \.{\\proclaim} or \.{\\+} or
+\.{\\newcount} that plain \TeX\ has declared to be `\.{\\outer}',
+because \TeX\ refuses to skip silently over such control sequences.
+One way to work around this limitation is to say
+$$\.{\\fi \\let\\proclaim\\relax \\def\\proclaim\{...\} \\ifon}$$
+where \.{\\proclaim} is redefined to be the same as usual but without
+an \.{\\outer} qualification. (The \.{\\fi} here stops the conditional
+skipping, and the \.{\\ifon} turns it back on again.) Similarly,
+$$\.{\\fi \\newcount\\n \\ifon}$$
+is a safe way to use \.{\\newcount}. Plain \TeX\ already provides a
+non-outer macro \.{\\tabalign} that does the work of \.{\\+}; you can say
+$$\postdisplaypenalty=10000
+\.{\\fi \\let\\+\\tabalign \\ifon}$$
+if you prefer the shorter notation \.{\\+}.
+
+\point 14. To get output in languages other than English, redefine the
+macros \.{\\A}, \.{\\As}, \.{\\ATH},
+\.{\\ET}, \.{\\ETs}, \.{\\Q}, \.{\\Qs}, \.{\\U},
+\.{\\Us}, \.{\\ch}, \.{\\fin}, \.{\\con}, \.{\\today}, \.{\\datethis}, and
+\.{\\datecontentspage}. \.{CWEAVE} itself need not be changed.
+
+\point 15. Some output can be selectively suppressed with the macros
+\.{\\noatl}, \.{\\noinx}, \.{\\nosecs}, \.{\\nocon}.
+
+\point 16. All accents and special text symbols of plain \TEX/ format
+will work in \.{CWEB} documents just as they are described in
+Chapter~9 of {\sl The \TEX/book}, with one exception.
+The dot accent (normally \.{\\.}) must be typed \.{\\:} instead.
+
+\point 17. Several commented-out lines in \.{cwebmac.tex} are suggestions
+that users may wish to adopt. For example, one such line inserts a blank page
+if you have a duplex printer. Appendices D, E, and F of the complete
+version of this manual are printed using a commented-out option that
+substitutes `$\gets$' for `$=$' in the program listings. Looking at those
+appendices might help you decide which format you like better.
+
+\point 18. Andreas Scherer has contributed a macro called \.{\\pdfURL}
+with which one can say things like the following, anywhere in the \TeX\ parts
+or the \CEE/ comments of a \.{CWEB} file:
+$$\vbox{\halign{\.{#}\hfil\cr
+You can send email to
+ \\pdfURL\{the author\}\{mailto:andreas.scherer@@pobox.com\}\cr
+or visit \\pdfURL\{his home page\}\{http://www.pobox.com/%
+ \\TILDE/scherer\}.\cr}}$$
+In a {\mc PDF} document, the first argument will appear in blue as
+clickable text; the Acrobat reader, if correctly configured, will then
+redirect those links to the user's browser and open either the
+email client or the HTML viewer. In a hardcopy document, both arguments
+will be printed ({\tt the second in parentheses and typewriter type}).
+Certain special characters in an Internet address need to be handled
+in a somewhat awkward way, so that \.{CWEAVE} and/or \TeX\
+will not confuse them with formatting controls: Use \.{@@} for \.@
+and \.{\\TILDE/} for \.\~ and \.{\\UNDER/} for \.\_.
+
+\point 19. {\mc PDF} documents contain bookmarks that list all the major group
+titles in the table of contents, some of which will be subsidiary to
+others if the depth feature of \.{@*} has been used.
+Such bookmark entries are also known as ``outlines.''
+Moreover, the final group title, `Names of the sections',
+can be opened up to list every section name; Acrobat users can therefore
+navigate easily to any desired section.
+
+The macros of \.{cwebmac.tex} are careful to ``sanitize'' all the names
+that appear as bookmarks, by removing special characters and
+formatting codes that are inappropriate for the limited typographic
+capabilities of {\mc PDF} outlines. For example, one section of \.{CWEAVE}
+is named `Cases for \\{case\_like}', which is represented by the \TeX\ code
+`\.{Cases} \.{for} \.{\\PB\{\\\\\{case\\\_like\}\}}' in \.{cweave.tex}; its
+sanitized name is simply `\.{Cases} \.{for} \.{case\_like}'.
+(When \.{.pdf} files are produced, the fifth parameter of every \.{\\ZZ} in
+the \.{.toc} file is set to the sanitized form of the first parameter;
+see point~9 above and point~20 below.)
+
+In general, sanitization removes \TeX\ control sequences and braces,
+except for control sequences defined by \.{CWEB} itself. Such a translation
+works most of the time, but you can override the defaults and obtain any
+translation that you want by using \TeX nical tricks. For example, after
+$$\.{\\sanitizecommand\\foo\{bar\}}$$
+the control sequence \.{\\foo} will sanitize to `\.{bar}'. And after
+$$\.{\\def\\kluj\#1\\\\\{foo\}}$$
+the \TeX\ code `\.{\\kluj bar\\\\}' will print as `foo' but sanitize
+to `\.{bar}', because the control sequences \.{\\kluj} and
+\.{\\\\} are removed by sanitization.
+
+\point 20. Furthermore, group titles can be converted to an arbitrary
+sanitized text while also changing their form in running headlines, by
+using \.{\\ifheader}. Consider, for example, a \.{CWEB} source file that
+begins with the two lines
+$$\lpile{\.{\\def\\klujj\#1\\\\\{\\ifheader FOO\\else foo\\fi\}}\cr
+\.{@*Chinese \\klujj bar\\.}\cr}$$
+This coding introduces a major group entitled `{\bf Chinese foo}', with
+running headline `{\eightrm CHINESE FOO}' and table-of-contents entry
+`Chinese foo'. The corresponding bookmark is, however, `\.{Chinese} \.{bar}'.
+And the corresponding \.{.toc} file entry is
+`\.{\\ZZ \{Chinese \\klujj bar\\\\\}\{1\}\{1\}\{1\}\{Chinese bar\}}'.
+
+\vfill\end
+
diff --git a/web/c_cpp/cweb/makefile.bs b/web/c_cpp/cweb/makefile.bs
new file mode 100644
index 0000000000..5e97012804
--- /dev/null
+++ b/web/c_cpp/cweb/makefile.bs
@@ -0,0 +1,60 @@
+# Makefile for CTANGLE and CWEAVE, pc/big versions, using
+# Borland C++ 3.1 and Borland Make.
+#
+# (This file contributed by Barry Schwartz, trashman@crud.mn.org,
+# 24 Jul 94.)
+
+
+
+CC = bcc
+
+# Redundant Load Suppression (-Z) is turned off, because it seems to
+# break the code. Likewise for Copy Propagation (-Op). (These
+# optimizations don't seem to cause any problems in common.w, but
+# better safe than sorry--compile everything with them turned off.)
+OPT = -O2-p -Z-
+
+# Compile with symbols. That way you'll be able to use the debugger if
+# you run into trouble. You can always use tdstrip later, to remove the
+# symbols.
+DEBUG = -v
+
+LCFLAGS = -mc -Ff=5000 -d -w-pro $(DEBUG)
+CFLAGS = $(LCFLAGS) $(OPT)
+COMPILE = $(CC) $(CFLAGS)
+
+LINK = $(CC) $(LCFLAGS) -e
+
+
+
+# Where to find an "old" version of ctangle, for bootstrapping. The first
+# time you make ctangle, you may have to edit the distributed ctangle.c
+# and/or common.c by hand to reduce the size of one or more arrays.
+# This will give you a functional ctangle.exe, which you can use to bootstrap
+# the "real" ctangle.exe.
+CTANGLE = ctangle
+
+
+
+
+all default: ctangle.exe cweave.exe
+
+
+ctangle.exe: ctangle.obj common.obj
+ $(LINK)$* $**
+
+cweave.exe: cweave.obj common.obj
+ $(LINK)$* $**
+
+
+common.obj: common.w comm-bs.ch
+ $(CTANGLE) common.w comm-bs.ch
+ $(COMPILE) -c common.c
+
+ctangle.obj: ctangle.w common.h ctang-bs.ch
+ $(CTANGLE) ctangle.w ctang-bs.ch
+ $(COMPILE) -c ctangle.c
+
+cweave.obj: cweave.w common.h cweav-bs.ch
+ $(CTANGLE) cweave.w cweav-bs.ch
+ $(COMPILE) -c cweave.c
diff --git a/web/c_cpp/cweb/prod.w b/web/c_cpp/cweb/prod.w
new file mode 100644
index 0000000000..5f76a19379
--- /dev/null
+++ b/web/c_cpp/cweb/prod.w
@@ -0,0 +1,307 @@
+% This file is part of CWEB.
+% This program by Silvio Levy and Donald E. Knuth
+% is based on a program by Knuth.
+% It is distributed WITHOUT ANY WARRANTY, express or implied.
+% Version 3.6 --- May 2000
+%
+@ Here is a table of all the productions. Each production that
+combines two or more consecutive scraps implicitly inserts a {\tt \$}
+where necessary, that is, between scraps whose abutting boundaries
+have different |mathness|. In this way we never get double {\tt\$\$}.
+
+% The following kludge is needed because \newcount, \newdimen, and \+
+% are "\outer" control sequences that cannot be used in skipped text!
+\fi \newcount\prodno \newdimen\midcol \let\+\relax \ifon
+
+\def\v{\char'174}
+\mathchardef\RA="3221 % right arrow
+\mathchardef\BA="3224 % double arrow
+
+A translation is provided when the resulting scrap is not merely a
+juxtaposition of the scraps it comes from. An asterisk$^*$ next to a scrap
+means that its first identifier gets an underlined entry in the index,
+via the function |make_underlined|. Two asterisks$^{**}$ means that both
+|make_underlined| and |make_reserved| are called; that is, the
+identifier's ilk becomes |raw_int|. A dagger \dag\ before the
+production number refers to the notes at the end of this section,
+which deal with various exceptional cases.
+
+We use \\{in}, \\{out}, \\{back} and
+\\{bsp} as shorthands for |indent|, |outdent|, |backup| and
+|break_space|, respectively.
+
+\begingroup \lineskip=4pt
+\def\alt #1 #2
+{$\displaystyle\Bigl\{\!\matrix{\strut\hbox{#1}\cr
+ \strut\hbox{#2}\cr}\!\Bigr\}$ }
+\def\altt #1 #2 #3
+{$\displaystyle\Biggl\{\!\matrix{\strut\hbox{#1}\cr\hbox{#2}\cr
+ \strut\hbox{#3}\cr}\!\Biggr\}$ }
+\def\malt #1 #2
+{$\displaystyle\matrix{\strut\hbox{#1}\hfill\cr\strut\hbox{#2}\hfill\cr}$}
+\def\maltt #1 #2 #3
+{$\displaystyle\matrix{\strut\hbox{#1}\hfill\cr\hbox{#2}\hfill\cr
+ \strut\hbox{#3}\hfill\cr}$}
+\yskip
+\prodno=0 \midcol=2.5in
+\def\theprodno{\number\prodno \global\advance\prodno by1\enspace}
+\def\dagit{\dag\theprodno}
+\def\+#1&#2&#3&#4\cr{\def\next{#1}%
+ \line{\hbox to 2em{\hss
+ \ifx\next\empty\theprodno\else\next\fi}\strut
+ \ignorespaces#2\hfil\hbox to\midcol{$\RA$
+ \ignorespaces#3\hfil}\quad \hbox to1.45in{\ignorespaces#4\hfil}}}
+\+\relax & LHS & RHS \hfill Translation & Example\cr
+\yskip
+\+& \altt\\{any} {\\{any} \\{any}} {\\{any} \\{any} \\{any}}
+|insert| & \altt\\{any} {\\{any} \\{any}} {\\{any} \\{any} \\{any}}
+& stmt; \ /$\ast\,$comment$\,*$/\cr
+\+& |exp| \altt|lbrace| |int_like| |decl|
+ & |fn_decl| \altt|lbrace| |int_like| |decl|
+ \hfill $F=E^*\,|in|\,|in|$ & \malt {\\{main}()$\{$}
+ {\\{main}$(\\{ac},\\{av})$ \&{int} \\{ac};} \cr
+\+& |exp| |unop| & |exp| & |x++|\cr
+\+& |exp| \alt |binop| |ubinop| |exp| & |exp| & \malt {|x/y|} {|x+y|} \cr
+\+& |exp| |comma| |exp| & |exp| \hfill $EC\,|opt|9\,E$& |f(x,y)|\cr
+\+& |exp| \alt {|lpar| |rpar|} |cast| |colon| &
+ |exp| \alt {|lpar| |rpar|} |cast| |base| &
+ \malt \&C|()|: {\&C|int i)|:} \cr
+\+& |exp| |semi| & |stmt| & |x=0;|\cr
+\+& |exp| |colon| & |tag| \hfill $E^*C$ & |found:|\cr
+\+& |exp| |rbrace| & |stmt| |rbrace| & end of \&{enum} list\cr
+\+& |exp| \alt {|lpar| |rpar|} |cast| \alt|const_like| |case_like| &
+ |exp| \alt {|lpar| |rpar|} |cast| \hfill
+ \alt $R=R\.\ C$ $C_1=C_1\.\ C_2$ &
+ \malt {|f() const|} {|f(int) throw|} \cr
+\+& |exp| \alt |exp| |cast| & |exp| & |time()|\cr
+\+& |lpar| \alt |exp| |ubinop| |rpar| & |exp| & \malt{|(x)|} {|(*)|} \cr
+\+& |lpar| |rpar| & |exp| \hfill $L\.{\\,}R$ & functions, declarations\cr
+\+& |lpar| \altt |decl_head| |int_like| |cast| |rpar| & |cast| & |(char*)|\cr
+\+& |lpar| \altt |decl_head| |int_like| |exp| |comma| & |lpar| \hfill
+ $L$\,\altt $D$ $I$ $E$ $C$\,|opt|9 & |(int,|\cr
+\+& |lpar| \alt |stmt| |decl| & |lpar| \hfill \alt {$LS\.\ $} {$LD\.\ $} &
+ \malt {|(k=5;|} {|(int k=5;|} \cr
+\+& |unop| \alt |exp| |int_like| & |exp| &
+ \malt |!x| |~|\&C \cr
+\+& |ubinop| |cast| |rpar| & |cast| |rpar| \hfill
+ $C=\.\{U\.\}C$ & |*|\&{CPtr}) \cr
+\+& |ubinop| \alt|exp| |int_like| & \alt|exp| |int_like| \hfill
+ \.\{$U$\.\}\alt$E$ $I$ & \malt |*x| |*|\&{CPtr} \cr
+\+& |ubinop| |binop| & |binop| \hfill $|math_rel|\,U\.\{B\.\}\.\}$ & |*=|\cr
+\+& |binop| |binop| & |binop| \hfill
+ $|math_rel|\,\.\{B_1\.\}\.\{B_2\.\}\.\}$ & |>>=|\cr
+\+& |cast| \alt |lpar| |exp| & \alt |lpar| |exp| \hfill
+ \alt $CL$ $C\.\ E$ & \malt |(double)(x+2)| |(double)x| \cr
+\+& |cast| |semi| & |exp| |semi| & |(int);|\cr
+\+& |sizeof_like| |cast| & |exp| & |sizeof (double)|\cr
+\+& |sizeof_like| |exp| & |exp| \hfill $S\.\ E$ & |sizeof x|\cr
+\+& |int_like| \alt|int_like| |struct_like| &
+ \alt|int_like| |struct_like| \hfill $I\.\ $\alt $I$ $S$
+ \unskip& |extern char|\cr
+\+& |int_like| |exp| \alt|raw_int| |struct_like| &
+ |int_like| \alt|raw_int| |struct_like| & |extern "Ada" int|\cr
+\+& |int_like| \altt|exp| |ubinop| |colon| &
+ |decl_head| \altt|exp| |ubinop| |colon| \hfill
+ $D=I$\.\ & \maltt|int x| |int*x| |unsigned:| \cr
+\+& |int_like| \alt |semi| |binop| & |decl_head| \alt |semi| |binop| &
+ \malt |int x;| {\&{int} $f(\&{int}=4)$} \cr
+\+& |public_like| |colon| & |tag| & \&{private}:\cr
+\+& |public_like| & |int_like| & \&{private}\cr
+\+& |colcol| \alt|exp| |int_like| & \alt|exp| |int_like| \hfill
+ |qualifier| $C$ \alt$E$ $I$ & \&C\DC$x$\cr
+\+& |colcol| |colcol| & |colcol| & \&C\DC\&B\DC\cr
+\+& |decl_head| |comma| & |decl_head| \hfill $DC\.\ $ & |int x,|\cr
+\+& |decl_head| |ubinop| & |decl_head| \hfill $D\.\{U\.\}$ & |int *|\cr
+\+\dagit& |decl_head| |exp| & |decl_head| \hfill $DE^*$ & |int x|\cr
+\+& |decl_head| \alt|binop| |colon| |exp| \altt|comma| |semi| |rpar| &
+ |decl_head| \altt|comma| |semi| |rpar| \hfill
+ $D=D$\alt $B$ $C$ \unskip$E$ & \malt {\&{int} $f(\&{int}\ x=2)$} |int b:1| \cr
+\+& |decl_head| |cast| & |decl_head| & |int f(int)|\cr
+\+& |decl_head| \altt|int_like| |lbrace| |decl| & |fn_decl|
+ \altt|int_like| |lbrace| |decl| \hfill $F=D\,|in|\,|in|$
+ & |long time () {|\cr
+\+& |decl_head| |semi| & |decl| & |int n;|\cr
+\+& |decl| |decl| & |decl| \hfill $D_1\,|force|\,D_2$ & |int n;double x;|\cr
+\+& |decl| \alt|stmt| |function| & \alt|stmt| |function|
+ \hfill $D\,|big_force|\,$\alt $S$ $F$ \unskip& \&{extern} $n$;
+ \\{main} ()|{}|\cr
+\+& |base| \alt |int_like| |exp| |comma| & |base| \hfill
+ $B$\.\ \alt $I$ $E$ \unskip$C$\,|opt|9
+ & \malt {: \&{public} \&A,} {: $i(5)$,} \cr
+\+& |base| \alt |int_like| |exp| |lbrace| & |lbrace| \hfill
+ $B$\.\ \alt $I$ $E$ \unskip\.\ $L$ & \&D : \&{public} \&A $\{$\cr
+\+& |struct_like| |lbrace| & |struct_head| \hfill $S\.\ L$ & |struct {|\cr
+\+& |struct_like| \alt|exp| |int_like| |semi| & |decl_head| |semi|
+ \hfill $S\.\ $\alt $E^{**}$ $I^{**}$ & \&{struct} \&{forward};\cr
+\+& |struct_like| \alt|exp| |int_like| |lbrace| & |struct_head| \hfill
+ $S\.\ $\alt $E^{**}$ $I^{**}$ \unskip $\.\ L$ &
+ \&{struct} \&{name\_info} $\{$\cr
+\+& |struct_like| \alt|exp| |int_like| |colon| &
+ |struct_like| \alt|exp| |int_like| |base| & |class| \&C :\cr
+\+\dagit& |struct_like| \alt|exp| |int_like| & |int_like|
+ \hfill $S\.\ $\alt$E$ $I$ & \&{struct} \&{name\_info} $z$;\cr
+\+& |struct_head| \altt|decl| |stmt| |function| |rbrace| & |int_like|\hfill
+ $S\,\\{in}\,|force|$\altt$D$ $S$ $F$ $\\{out}\,|force|\,R$ &
+ |struct {| declaration |}|\cr
+\+& |struct_head| |rbrace| & |int_like|\hfill $S\.{\\,}R$ & |class C{}|\cr
+\+& |fn_decl| |decl| & |fn_decl| \hfill $F\,|force|\,D$
+ & $f(z)$ \&{double} $z$; \cr
+\+& |fn_decl| |stmt| & |function| \hfill $F\,|out|\,|out|\,|force|\,S$
+ & \\{main}() {\dots}\cr
+\+& |function| \altt|stmt| |decl| |function| & \altt |stmt| |decl| |function|
+ \hfill $F\,|big_force|\,$\altt $S$ $D$ $F$ & outer block\cr
+\+& |lbrace| |rbrace| & |stmt| \hfill $L\.{\\,}R$ & empty statement\cr
+\advance\midcol35pt
+\+& |lbrace| \altt|stmt| |decl| |function| |rbrace| & |stmt| \hfill
+ $|force|\,L\,\\{in}\,|force|\,S\,
+ |force|\,\\{back}\,R\,\\{out}\,|force|$ & compound statement\cr
+\advance\midcol-20pt
+\+& |lbrace| |exp| [|comma|] |rbrace| & |exp| & initializer\cr
+\+& |if_like| |exp| & |if_clause| \hfill $I\.{\ }E$ & |if (z)|\cr
+\+& |else_like| |colon| & |else_like| |base| & \&{try} :\cr
+\+& |else_like| |lbrace| & |else_head| |lbrace| & \&{else} $\{$\cr
+\+& |else_like| |stmt| & |stmt| \hfill
+ $|force|\,E\,\\{in}\,\\{bsp}\,S\,\\{out}\,|force|$ & |else x=0;|\cr
+\+& |else_head| \alt|stmt| |exp| & |stmt| \hfill
+ $|force|\,E\,\\{bsp}\,|noop|\,|cancel|\,S\,\\{bsp}$ & |else{x=0;}|\cr
+\+& |if_clause| |lbrace| & |if_head| |lbrace| & |if (x) {|\cr
+\+& |if_clause| |stmt| |else_like| |if_like| & |if_like| \hfill
+ $|force|\,I\,\\{in}\,\\{bsp}\,S\,\\{out}\,|force|\,E\,\.\ I$ &
+ |if (x) y; else if|\cr
+\+& |if_clause| |stmt| |else_like| & |else_like| \hfill
+ $|force|\,I\,\\{in}\,\\{bsp}\,S\,\\{out}\,|force|\,E$ &
+ |if (x) y; else|\cr
+\+& |if_clause| |stmt| & |else_like| |stmt| & |if (x)|\cr
+\+& |if_head| \alt|stmt| |exp| |else_like| |if_like| & |if_like| \hfill
+ $|force|\,I\,\\{bsp}\,|noop|\,|cancel|\,S\,|force|\,E\,\.\ I$ &
+ |if (x){y;}else if|\cr
+\+& |if_head| \alt|stmt| |exp| |else_like| & |else_like| \hfill
+ $|force|\,I\,\\{bsp}\,|noop|\,|cancel|\,S\,|force|\,E$ &
+ |if (x){y;}else|\cr
+\+& |if_head| \alt|stmt| |exp| & |else_head| \alt|stmt| |exp| & |if (x){y;}|\cr
+\advance\midcol20pt
+\+& |do_like| |stmt| |else_like| |semi| & |stmt| \hfill
+ $D\,\\{bsp}\,|noop|\,|cancel|\,S\,|cancel|\,|noop|\,\\{bsp}\,ES$%
+ & |do f(x); while (g(x));|\cr
+\advance\midcol-20pt
+\+& |case_like| |semi| & |stmt| & |return;|\cr
+\+& |case_like| |colon| & |tag| & |default:|\cr
+\+& |case_like| |exp| & |exp| \hfill $C\.\ E$ & |return 0|\cr
+\+& |catch_like| \alt|cast| |exp| & |fn_decl| \hfill
+ $C$\alt $C$ $E$ \\{in}\,\\{in} & |catch (...)|\cr
+\+& |tag| |tag| & |tag| \hfill $T_1\,\\{bsp}\,T_2$ & |case 0: case 1:|\cr
+\+& |tag| \altt|stmt| |decl| |function| & \altt|stmt| |decl| |function|
+ \hfill $|force|\,\\{back}\,T\,\\{bsp}\,S$ & |case 0: z=0;|\cr
+\+\dagit& |stmt| \altt|stmt| |decl| |function| &
+ \altt|stmt| |decl| |function|
+ \hfill $S\,$\altt$|force|\,S$ $|big_force|\,D$ $|big_force|\,F$ &
+ |x=1;y=2;|\cr
+\+& |semi| & |stmt| \hfill \.\ $S$& empty statement\cr
+\+\dagit& |lproc| \altt |if_like| |else_like| |define_like| & |lproc| &
+ \maltt {{\bf \#include}} {\bf\#else} {\bf\#define} \cr
+\+& |lproc| |rproc| & |insert| & {\bf\#endif} \cr
+\+& |lproc| \alt {|exp| [|exp|]} |function| |rproc| & |insert| \hfill
+ $I$\.\ \alt {$E{[\.{\ \\5}E]}$} {$F$} &
+ \malt{{\bf\#define} $a$\enspace 1} {{\bf\#define} $a$\enspace$\{\,b;\,\}$} \cr
+\+& |section_scrap| |semi| & |stmt|\hfill $MS$ |force|
+ &$\langle\,$section name$\,\rangle$;\cr
+\+& |section_scrap| & |exp| &$\langle\,$section name$\,\rangle$\cr
+\+& |insert| |any| & |any| & \.{\v\#include\v}\cr
+\+& |prelangle| & |binop| \hfill \.< & $<$ not in template\cr
+\+& |prerangle| & |binop| \hfill \.> & $>$ not in template\cr
+\+& |langle| |prerangle| & |cast| \hfill $L\.{\\,}P$ & $\langle\,\rangle$\cr
+\+& |langle| \altt|decl_head| |int_like| |exp| |prerangle| & |cast| &
+ $\langle\&{class}\,\&C\rangle$\cr
+\+& |langle| \altt|decl_head| |int_like| |exp| |comma| & |langle| \hfill
+ $L$\,\altt $D$ $I$ $E$ $C$\,|opt|9 & $\langle\&{class}\,\&C,$\cr
+\+& |template_like| |exp| |prelangle| & |template_like| |exp| |langle| &
+ \&{template} $a\langle100\rangle$\cr
+\+& |template_like| \alt|exp| |raw_int| & \alt|exp| |raw_int| \hfill
+ $T$\.\ \alt$E$ $R$ & \&C\DC\&{template} |a()|\cr
+\+& |template_like| & |raw_int| & \&{template}$\langle\&{class}\,\&T\rangle$\cr
+\+& |new_like| |lpar| |exp| |rpar| & |new_like| & \&{new}(\\{nothrow})\cr
+\+& |new_like| |cast| & |exp| \hfill $N\.\ C$ & |new(int*)|\cr
+\+\dagit& |new_like| & |new_exp| & \&{new} \&C|()|\cr
+\+& |new_exp| \alt|int_like| |const_like| & |new_exp| \hfill
+ $N$\.\ \alt $I$ $C$ & |new const int|\cr
+\+& |new_exp| |struct_like| \alt |exp| |int_like| & |new_exp| \hfill
+ $N\.\ S$\.\ \alt $E$ $I$ & \&{new} \&{struct} \&S\cr
+\+& |new_exp| |raw_ubin| & |new_exp| \hfill $N\.\{R\.\}$ & |new int*[2]|\cr
+\+& |new_exp| \alt |lpar| |exp| & |exp| \alt |lpar| |exp| \hfill
+ $E=N$\,\alt {} {\.\ } & \malt |operator[](int)| {|new int(2)|} \cr
+\+\dagit& |new_exp| & |exp| & |new int;|\cr
+\+& |ftemplate| |prelangle| & |ftemplate| |langle| & |make_pair<int,int>|\cr
+\+& |ftemplate| & |exp| & |make_pair(1,2)|\cr
+\+& |for_like| |exp| & |else_like| \hfill $F\.\ E$ & |while (1)|\cr
+\+& |raw_ubin| |const_like| & |raw_ubin| \hfill $RC$\.{\\\ }
+ & $*$\&{const} |x|\cr
+\+& |raw_ubin| & |ubinop| & $*$ |x|\cr
+\+& |const_like| & |int_like| & \&{const} |x|\cr
+\+& |raw_int| |prelangle| & |raw_int| |langle| & \&C$\langle$\cr
+\+& |raw_int| |colcol| & |colcol| & \&C\DC\cr
+\+& |raw_int| |cast| & |raw_int| & \&C$\langle\&{class}\ \&T\rangle$\cr
+\+& |raw_int| |lpar| & |exp| |lpar| & \&{complex}$(x,y)$\cr
+\+\dagit& |raw_int| & |int_like| & \&{complex} |z|\cr
+\+\dagit& |operator_like| \altt|binop| |unop| |ubinop| & |exp|
+ \hfill $O$\.\{\altt $B$ $U$ $U$ \unskip\.\} & |operator+|\cr
+\+& |operator_like| \alt|new_like| |delete_like| & |exp| \hfill
+ $O$\.\ \alt $N$ $S$ & |operator delete|\cr
+\+& |operator_like| |comma| & |exp| & \&{operator},\cr
+\+\dagit& |operator_like| & |new_exp| & |operator char*|\cr
+\advance\midcol-8pt
+\+& |typedef_like| \alt|int_like| |cast| \alt|comma| |semi| &
+ |typedef_like| |exp| \alt|comma| |semi| & \&{typedef} \&{int} \&I,\cr
+\advance\midcol+8pt
+\+& |typedef_like| |int_like| & |typedef_like| \hfill $T\.\ I$ &
+ \&{typedef} \&{char}\cr
+\+\dagit& |typedef_like| |exp| & |typedef_like| \hfill $T\.\ E^{**}$ &
+ \&{typedef} \&I \.{@@[@@]} (|*|\&P)\cr
+\+& |typedef_like| |comma| & |typedef_like| \hfill $TC\.\ $ &
+ \&{typedef} \&{int} \&x,\cr
+\+& |typedef_like| |semi| & |decl| & \&{typedef} \&{int} $\&x,\&y$;\cr
+\+& |typedef_like| |ubinop| \alt |cast| |ubinop| &
+ |typedef_like| \alt |cast| |ubinop| \hfill
+ \alt $C=\.\{U\.\}C$ $U_2=\.\{U_1\.\}U_2$ \unskip &
+ \&{typedef} |*|{}|*|(\&{CPtr})\cr
+\+& |delete_like| |lpar| |rpar| & |delete_like|\hfill $DL\.{\\,}R$ &
+ \&{delete}|[]| \cr
+\+& |delete_like| |exp| & |exp| \hfill $D\.\ E$ & |delete p| \cr
+\+\dagit& |question| |exp| \alt |colon| |base| & |binop| &
+ \malt |?x:| |?f():| \cr
+\+& |begin_arg| |end_arg| & |exp| & \.{@@[}\&{char}$*$\.{@@]}\cr
+\+& |any_other| |end_arg| & |end_arg| & \&{char}$*$\.{@@]}\cr
+\yskip
+\yskip
+\yskip
+\parindent=0pt
+\dag{\bf Notes}
+\yskip
+Rule 35: The |exp| must not be immediately followed by |lpar|, |exp|,
+ or~|cast|.
+
+Rule 48: The |exp| or |int_like| must not be immediately followed by |base|.
+
+Rule 76: The |force| in the |stmt| line becomes \\{bsp} if \.{CWEAVE} has
+been invoked with the \.{-f} option.
+
+Rule 78: The |define_like| case calls |make_underlined| on the following scrap.
+
+Rule 94: The |new_like| must not be immediately followed by |lpar|.
+
+Rule 99: The |new_exp| must not be immediately followed by |raw_int|,
+|struct_like|, or |colcol|.
+
+Rule 110: The |raw_int| must not be immediately followed by |langle|.
+
+Rule 111: The operator after |operator_like|
+must not be immediately followed by a |binop|.
+
+Rule 114: The |operator_like| must not be immediately followed by
+|raw_ubin|.
+
+Rule 117: The |exp| must not be immediately followed by |lpar|, |exp|,
+or |cast|.
+
+Rule 123: The mathness of the |colon| or |base| changes to `yes'.
+
+\endgroup
diff --git a/web/c_cpp/cweb/readme.ql b/web/c_cpp/cweb/readme.ql
new file mode 100644
index 0000000000..907d4c3192
--- /dev/null
+++ b/web/c_cpp/cweb/readme.ql
@@ -0,0 +1,84 @@
+This is the readme file for CWEB for QDOS/SMSQ systems
+
+(These instructions are for systems with Toolkit II,
+ please report any problems to me, the address is at the
+ end of the file)
+
+If you want to compile CWEB for your QL system, you must first
+convert the ASCII code to the QL's character set. Therefore you
+can use the little BASIC program appended at the end of the file.
+
+For a first version you have to alter the supplied ctangle_c file.
+Set your DATA_USE to the directory you have the CWEB sources in, and
+the PROG_USE to C68's directory.
+compile it with:
+ex cc;'common_c ctangle_c -bufp500K -octangle'
+
+then ctangle the source files with:
+ex datad$&'ctangle';'common_w comm-ql_ch'
+ex datad$&'ctangle';'ctangle_w ctang-ql_ch'
+ex datad$&'ctangle';'cweave_w cweav-ql_ch'
+
+Compile the following way (C68v4.14 +):
+
+ex cc;'-c common_c'
+ex cc;'-c ctangle_c'
+ex cc;'-c cweave_c'
+ex ld;'-bufp500K common_o ctangle_o -octangle'
+ex ld;'-bufp500K common_o cweave_o -ocweave'
+
+After that copy the ctangle and cweave executables into your
+programs directory (if you want them there).
+
+The DATA default may be used as usual. E.g. if you have
+a file win2_data_test_w and the DATA default set to
+win2_data_ you may call ctangle with
+ ex ctangle;'test'
+assuming that ctangle is in your PROG default.
+
+Please report any problems with the QL version to:
+Robert Klein
+Bluecherstrasse 24
+D-56349 Kaub
+Germany
+
+
+**************** ASCII Conversion program ***************
+With this program you can convert DOS and Unix 7-Bit ASCII
+files to the QL's character set. You'll need Toolkit II.
+The program will take all the files in the source directory
+and put them converted into the destination&source directory,
+e.g. you have as drive1$='win2_', drive2$='win3_',
+path1$='cweb_' and path2$='ql_'. Then the routine will take
+all files in win2_cweb_ (wthout subdirectories!) convert them
+and write them to 'win3_ql_cweb_'. It's only a lousy hack,
+but it'll do it's job.
+
+1000 DEFine PROCedure dos2ql (drive1$,path1$,drive2$,path2$)
+1002 LOCal zx$,zx%,ishl,ashl
+1005 DELETE drive2$&path2$&'dirlist'
+1010 OPEN_NEW#5,drive2$&path2$&'dirlist'
+1020 DIR#5,drive1$&path1$
+1030 CLOSE#5
+1040 OPEN_IN#5,drive2$&path2$&'dirlist'
+1050 INPUT#5,zx$:INPUT#5,zx$:REMark devicename and sectors
+1060 REPeat ashl
+1070 IF EOF(#5)THEN EXIT ashl
+1080 INPUT#5,zx$
+1085 IF '->' INSTR zx$ THEN NEXT ashl
+1090 OPEN_IN#3,drive1$&zx$
+1100 OPEN_NEW#4,drive2$&path2$&zx$
+1110 REPeat ishl
+1120 IF EOF(#3)THEN EXIT ishl
+1130 BGET#3,zx%
+1140 SELect ON zx%
+1150 = 13:REMark do nothing (DOS LineFeed)
+1155 = 26:REMark do nothing (DOS EOF sign)
+1160 = 96: BPUT#4,159:REMark Unix/DOS beginning quote sign
+1170 = REMAINDER : BPUT#4,zx%
+1180 END SELect
+1190 END REPeat ishl
+1195 CLOSE#3:CLOSE#4
+1200 END REPeat ashl
+1205 CLOSE#5
+1210 END DEFine dos2ql
diff --git a/web/c_cpp/cwebbin/README-2019.txt b/web/c_cpp/cwebbin/README-2019.txt
new file mode 100644
index 0000000000..b09a017c18
--- /dev/null
+++ b/web/c_cpp/cwebbin/README-2019.txt
@@ -0,0 +1,478 @@
+ -*-Text-*-
+%%% LEGALESE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% This file is part of CWEBbin (Version 3.64c [2019]).
+% (Set TAB to 8 spaces to get the spacing right.)
+% The CWEB programs by Silvio Levy are based on programs by D. E. Knuth.
+% They are distributed WITHOUT ANY WARRANTY, express or implied.
+
+% This README file was last updated January 1, 2019 by Andreas Scherer.
+
+% The following copyright notices extend to the respective parts of the
+% changed or added source code introduced in this patch only, not to the
+% original CWEB distribution, which is copyright (C) 1987,1990,1993,1998
+% by Silvio Levy and Donald E. Knuth.
+%
+% Copyright (C) 1991-1993 Hans-Hermann Bode
+% Copyright (C) 1992 Klaus Guntermann
+% Copyright (C) 1991,1993 Carsten Steger
+% Copyright (C) 1993-2000,2005,2011,2018,2019 Andreas Scherer
+
+% Permission is granted to make and distribute verbatim copies of this
+% document provided that the copyright notice and this permission notice
+% are preserved on all copies.
+
+% Permission is granted to copy and distribute modified versions of this
+% document under the conditions for verbatim copying, provided that the
+% entire resulting derived work is given a different name and distributed
+% under the terms of a permission notice identical to this one.
+
+% Please send comments, suggestions, etc., concerning the original CWEB
+% implementation to tex-k@tug.org.
+
+% Please send comments, suggestions, etc., related to changes specific
+% for this modified distribution CWEBbin, especially language catalog
+% translations to https://ascherer.github.io, or write an issue or pull
+% request in https://github.com/ascherer/cwebbin.
+
+%%% WHAT IS THIS STUFF? %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+CWEBbin is the ANSI-C/C++ implementation of Silvio Levy's and Donald Ervin
+Knuth's CWEB system, compiled and provided with changefiles for ANSI-C and
+makefiles for Borland C/C++ 3.1 (no longer actively supported), MS/VC++ 4.1
+and 6.0 (both no longer actively supported), SAS/C++ 6.57 (no longer actively
+supported), and most of all UNIX-cc/g++. Additional features differing from
+the original distribution are described further below. General information is
+provided in the original README file shipped with the CWEB distribution.
+
+CWEBbin started from the Amiga port of CWEB 2.8 by Carsten Steger. Then it
+was merged with the CWEB-PC 3.0 distribution by Hans-Hermann Bode and Klaus
+Guntermann, and the Amiga port of CWEB 3.1 by Tomas Charles Willis. Of
+course, it includes all features of the original UNIX implementation and all
+enhancements of these Amiga and MS/DOS/Windows ports.
+
+The distribution of CWEBbin consists of the additional files for this patch
+only. The complete contents of the original distribution is a prerequisite.
+CWEB can be retrieved via anonymous ftp from
+
+ FTP: ftp://ftp.cs.stanford.edu/pub/cweb
+ CTAN: https://ctan.org/pkg/cweb
+
+To apply this patched version of CWEB, extract the patch archive (yielding a
+new subdirectory) and add the original distribution. Care has been taken to
+avoid collisions with any files from the original distribution and the
+Makefiles provide a target to cleanly remove the patch leaving only the files
+of the original distribution (and vice versa).
+
+Intermediate files with extensions .tex and .cxx are reproducable from the
+general sources by means of an executable ctangle, cweave, and an ANSI-C/C++
+compiler. In addition you need Klaus Guntermann's TIE processor, which is
+available at
+
+ CTAN: https://ctan.org/pkg/tie
+
+TIE should be available on all systems with a recent TeX installation.
+Alternatively, you can also try to use Julian Gilbey's CTIE processor, but
+intermediate results are different.
+
+%%% TABLE OF CONTENTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+The following files were added to this distribution by various contributors:
+
+GENERAL CONTRIBUTION:
+.
+├── 0001-Make-clean-twinx.patch Patch for twinx.w
+├── 0002-Make-clean-refsort.patch Patch for refsort.w
+├── arexx [AMIGA]
+│   ├── catalogs
+│   │   ├── cweb_arexx.cd [AMIGA] catalog description for German defaults
+│   │   ├── cweb_arexx.e.ct [AMIGA] catalog translation for English users
+│   │   ├── cweb_arexx.f.ct [AMIGA] catalog translation for French users
+│   │   ├── cweb_arexx.i.ct [AMIGA] catalog translation for Italian users
+│   │   ├── english
+│   │   │   └── cweb_arexx.catalog [AMIGA] message catalog for English users
+│   │   ├── francais
+│   │   │   └── cweb_arexx.catalog [AMIGA] message catalog for French users
+│   │   └── italiano
+│   │   └── cweb_arexx.catalog [AMIGA] message catalog for Italian users
+│   ├── compile.ced [AMIGA] ARexx script to start SAS/C 6.x from CED (V3.5+)
+│   └── start_web.ced [AMIGA] ARexx script to start cweave/ctangle from CED
+├── catalogs
+│   ├── cweb.cd [AMIGA] catalog description for English defaults
+│   ├── cweb.d.ct [AMIGA] catalog translation for German users
+│   ├── cweb.i.ct [AMIGA] catalog translation for Italian users
+│   ├── dcweb.h [AMIGA,BCC] header file with the German strings
+│   ├── ecweb.h [AMIGA,BCC] header file with the English default strings
+│   └── icweb.h [AMIGA,BCC] header file with the Italian strings
+├── comm-ansi.ch change file for common.w
+├── comm-ansi.hch change file for common.h
+├── comm-arexx.ch [AMIGA] change file for common.w
+├── comm-arexx.hch [AMIGA] change file for common.h
+├── comm-borlandc.ch [BCC] change file for common.w
+├── comm-borlandc.hch [BCC] change file for common.h
+├── comm-extensions.ch change file for common.w
+├── comm-extensions.hch change file for common.h
+├── comm-i18n.ch change file for common.w
+├── comm-i18n.hch change file for common.h
+├── comm-memory.ch [AMIGA,BCC] change file for common.w
+├── comm-memory.hch [AMIGA,BCC] change file for common.h
+├── comm-newpage.ch change file for common.w
+├── common.cxx product of common.w and comm-foo.ch
+├── comm-output.ch change file for common.w
+├── comm-output.hch change file for common.h
+├── comm-patch.ch change file for common.w
+├── comm-texlive.ch change file for common.w
+├── comm-texlive.hch change file for common.h
+├── comm-translation.ch [AMIGA,BCC] change file for common.w
+├── comm-translation.hch [AMIGA,BCC] change file for common.h
+├── ctang-ansi.ch change file for ctangle.w
+├── ctang-borlandc.ch [BCC] change file for ctangle.w
+├── ctang-extensions.ch change file for ctangle.w
+├── ctang-i18n.ch change file for ctangle.w
+├── ctangle.1 clone of cweb.1
+├── ctangle.cxx product of ctangle.w and ctang-foo.ch
+├── ctangle.dsp [MSVC] Developer Studio Project for CTANGLE
+├── ctang-memory.ch [AMIGA,BCC] change file for ctangle.w
+├── ctang-newpage.ch change file for ctangle.w
+├── ctang-output.ch change file for ctangle.w
+├── ctang-patch.ch change file for ctangle.w
+├── ctang-texlive.ch change file for ctangle.w
+├── ctang-translation.ch [AMIGA,BCC] change file for ctangle.w
+├── ctwill.bux auxiliary file for CTWILL
+├── ctwill.md manpage for CTWILL in markdown
+├── ctwill-mini.ch auxiliary file for CTWILL
+├── ctwill-refsort.1 manpage link to ctwill.1
+├── ctwill-texlive.ch change file for cweave.w/ctwill.w
+├── ctwill-twinx.1 manpage link to ctwill.1
+├── cweav-ansi.ch change file for cweave.w
+├── cweav-borlandc.ch [BCC] change file for cweave.w
+├── cweave.1 clone of cweb.1
+├── cweave.dsp [MSVC] Developer Studio Project for CWEAVE
+├── cweav-extensions.ch change file for cweave.w
+├── cweav-i18n.ch change file for cweave.w
+├── cweav-memory.ch [AMIGA,BCC] change file for cweave.w
+├── cweav-newpage.ch change file for cweave.w
+├── cweav-output.ch change file for cweave.w
+├── cweav-patch.ch change file for cweave.w
+├── cweav-texlive.ch change file for cweave.w
+├── cweav-translation.ch [AMIGA,BCC] change file for cweave.w
+├── cweav-twill.ch change file for cweave.w
+├── cwebbin.dsw [MSVC] Developer Studio Workspace for all three
+├── cwebbin.spec extended build recipe for debbuild
+├── cwebinputs
+│   ├── amiga_types.w keywords by Commodore and SAS
+│   ├── c++1xlib.w Keywords for modern C++ standards
+│   ├── cweb_ecma94.w Transliteration table for Latin-1
+│   ├── cweb_hp8.w Transliteration table for HP Roman 8
+│   ├── cweb_mac8.w Transliteration table for Mac 8-bit
+│   └── cweb_pc850.w Transliteration table for Codepage 850
+│   ├── iso_types.w Keywords for ISO C/C++ standards
+├── cwebman.ch change file for cwebman.tex
+├── examples
+│   ├── cct.w program to translate between character tables
+│   ├── commonwords.w program to count word frequencies in text files
+│   ├── extex-ansi.ch change file for extex.w
+│   ├── Makefile.sas [AMIGA] makefile for SAS/C compiler 6.0 and up
+│   ├── matrix.w C++ program to invert complex 4x4 matrices
+│   ├── primes.ch changes for the first 1000000 prime numbers
+│   ├── primes.w program to print the first 1000 prime numbers
+│   ├── README.p11 extended description for the added examples
+│   ├── sample.w program to produce random numbers
+│   ├── treeprint-ansi.ch change file for treeprint.w
+│   ├── wc-ansi.ch change file for wc.w
+│   ├── wmerg-ansi.ch change file for wmerge.w
+│   ├── wmerg-borlandc.ch [BCC] change file for wmerge.w
+│   ├── wmerge.dsp [MSVC] Developer Studio Project for WMERGE
+│   ├── wmerg-extensions.ch change file for wmerge.w
+│   ├── wmerg-memory.ch [AMIGA,BCC] change file for wmerge.w
+│   ├── wmerg-output.ch change file for wmerge.w
+│   ├── wmerg-patch.ch change file for wmerge.w
+│   └── wordtest-ansi.ch change file for wordtest.w
+├── LICENSE MIT license
+├── Makefile.bcc [BCC] makefile for Borland C/C++
+├── Makefile.sas [AMIGA] makefile for SAS/C compiler 6.0 and up
+├── Makefile.unix makefile for cc, c89, gcc, ... on several machines
+├── po
+│   ├── cweb.pot Portable Object Template for i18n
+│   ├── cweb-tl.pot Portable Object Template for i18n
+│   ├── de
+│   │   ├── cweb.po Portable Object for German t10n
+│   │   ├── cweb-tl.po Portable Object for German t10n
+│   │   └── web2c-help.po Portable Object for German t10n
+│   ├── it
+│   │   └── cweb.po Portable Object for Italian t10n
+│   └── web2c-help.pot Portable Object Template for i18n
+├── prod-twill.ch change file for prod.w/CTWILL
+├── README.md Github project description
+├── README.txt the current file
+├── system.bux auxiliary file for CTWILL
+├── texinputs
+│   ├── cweb_ecma94.sty Umlauts and special characters for Latin-1
+│   ├── cweb_hp8.sty Umlauts and special characters for HP Roman 8
+│   ├── cweb_mac8.sty Umlauts and special characters for Macintosh
+│   ├── cweb_pc850.sty Umlauts and special characters for IBM 850
+│   ├── dctwimac.tex German captions in addition to ctwimac.tex
+│   ├── dcwebmac.tex German captions in addition to cwebmac.tex
+│   ├── dcwebstrings.tex Common German captions
+│   ├── dproofmac.tex German captions in addition to proofmac.tex
+│   ├── fcwebmac.tex French captions in addition to cwebmac.tex
+│   ├── icwebmac.tex Italian captions in addition to cwebmac.tex
+│   └── Xcwebmac.tex beautifications for cwebmac.tex
+└── texlive.w introduction to *-w2c.ch change files
+
+%%% HOW TO CREATE THE BINARIES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+[UNIX/Linux, GCC] The current setup of CWEBbin has been created on a Linux PC
+ running GNU/Linux including the gcc/g++ compiler and the TeXLive system.
+ Any similar setup should also work. All set?
+ -- Then proceed as follows:
+
+ 1. Check the entries in Makefile.unix for local conditions like a
+ different compiler name or additional compiler options you want to
+ use. Check also the other lines in Makefile.unix so that all
+ directory definitions are set properly for your local system
+ configuration.
+
+ 2. If you want to create the ctangle and cweave binaries for a
+ different language than English, set a link from one of the
+ `[dei]cweb.h' header files to `cweb.h' in the ./catalogs directory.
+
+ 3. Touch common.cxx and ctangle.cxx to make them up-to-date. Then say
+ `make -f Makefile.unix boot'; this will create a local ctangle binary
+ simply by compiling the distributed .cxx files.
+
+ 4. To make ctangle, cweave, and the wmerge processor say `make -f
+ Makefile.unix [all]'. To get some reassurance that things are OK, you
+ can say `make cautiously', which ensures that ctangle will reproduce
+ itself. (Otherwise the source files common.w and ctangle.w won't
+ actually have been used.)
+
+ 5. After all is set, you should become `superuser' and run `make -f
+ Makefile.unix install'; this will install the binaries, the TeX macros
+ and CWEB @include files, and some documentation in places specified in
+ Makefile.unix.
+
+ 6. If you want a full documentation of the tangle and weave programs,
+ type `make -f Makefile.unix docs' or preferably `make -f Makefile.unix
+ fullmanual'. The documentation created will include all changes
+ introduced by the .ch files.
+
+ 7. To delete all intermediate files created in the make processes say
+ `make -f Makefile.unix clean'.
+
+ 8. To remove the complete patch from the installed CWEB system, say
+ `make -f Makefile.unix remove'. You will be left with the original
+ CWEB system.
+
+ 9. To remove the complete base system leaving only the patch behind,
+ you can say `make -f Makefile.unix remove-orig'.
+
+ 10. The other labels have not been tested seriously. :-)
+
+[AMIGA, SAS/C++ 6] I can no longer support this compiler and computer system
+ and most likely it's impossible to install CWEBbin with SAS/C++. The
+ source files common.cxx, common.h, and ctangle.cxx can definitely NOT
+ be used with SAS/C++ anymore. They were created on a Linux PC leaving
+ the Amiga stuff out. You will have to use an older ctangle binary to
+ create the TIE processor and then create the complete set of change
+ files according to Makefile.sas. Good luck!
+
+[MS/DOS, BORLAND C++ 3.1] I can no longer support this compiler and most
+ likely it's impossible to install CWEBbin with BC. The source files
+ common.cxx, common.h, and ctangle.cxx can definitely NOT be used with
+ BC anymore. They were created on a Linux PC leaving the
+ `*-borlandc.*' change files out. You will have to use an older
+ ctangle.exe binary to create the TIE processor and then create the
+ complete set of change files according to Makefile.bcc. Good luck!
+
+[MS/WINDOWS, MS/VC++ 4.1 and 6.0] I can no longer support this compiler and
+ most likely it is impossible to install CWEBbin with this version of
+ the Microsoft compiler. The current version of MS/VC++ is supported
+ through binary versions of CTANGLE and CWEAVE at
+ http://www.literateprogramming.com.
+
+%%% LIST OF FEATURES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+After the announcement of CWEB 3.3 [p11a] on news:comp.programming.literate
+and news:comp.text.tex there have been questions: ``What's different in your
+CWEB system in respect to the original system? Why should programmers use
+your's instead of the Levy/Knuth distribution?''
+
+So here are some words about the `special features':
+
+ - [GENERAL] The complete source code can (or at least at some point of time
+ could) be recompiled with SAS/C for AmigaOS, with Borland C/C++ 3.1 for
+ MS/DOS, with MS/VC++ 4.1 and 6.0 for MS/Windows, and with CC, C89, and
+ GCC for UNIX without the need for further changes. Well, to be honest,
+ the complete source code was only compiled using GCC.
+
+ - [GENERAL] The `+l' (or `-l') option with its argument `X' causes CWEAVE
+ to prepend `X' to `cwebmac.tex' in the first line of the output file.
+ `X' may be any string of characters (case dependent and possibly empty),
+ e.g., if you called CWEAVE with the option `+ldansk', the danish macro
+ file `danskcwebmac.tex' (if there's such a thing) would be included
+ instead of `cwebmac.tex'. The macro file `Xcwebmac.tex' itself contains
+ some modifications to the original `cwebmac.tex' file as described in the
+ documentation. At the time of writing there are macro packages
+ `dcwebmac.tex' by Andreas Scherer for German users, `icwebmac.tex' by
+ Giuseppe Ghibò for Italian users, and `fcwebmac.tex' by Denis B. Roegel
+ for French users. These macro files translate all captions used by the
+ CWEAVE processor into the respective languages and also include support
+ for special characters like umlauts (diacritics) and some other
+ frequently used specials according to ISO Latin-1, IBM PC International
+ Codepage 850, Macintosh 8-bit font table and HP Roman 8. Similar
+ packages for other languages can easily be added to this scheme. To date
+ there are no conflicting languages, so single-character strings are used.
+ However, there is no support for UTF-8 at this time.
+
+ - [GENERAL] <Obsolete> As of March 1997 five new macros with the prefix
+ `pdf' are available. Together with the "tex2pdf/pdftex" system they
+ enable the presenation of CWEB source code in "Hyper CWEB" form, i.e.,
+ all section references and the table of contents are hyperlinked and can
+ be used in PDF readers. Call "cweave -lpdf" (or "cweave -lpdfd", etc.)
+ to include the respective macro file in the TeX output, before running
+ "pdftex". </Obsolete> As of July 2000 these macros are united with the
+ generic macros, i.e., `cwebmac.tex' can be used with "plain TeX," "plain
+ TeX + dvipdfm," and "pdftex."
+
+ - [GENERAL] There are transliteration tables `cweb_ecma94.w', `cweb_hp8.w',
+ `cweb_mac8.w', and `cweb_pc850.w' for @inclusion in limbo. These files
+ \input the associated TeX macro files `cweb_ecma94.sty', `cweb_hp8.sty',
+ `cweb_mac8.sty', and `cweb_pc850.sty' with i18n support of extended code
+ tables. These macros can, of course, also be used independently of
+ the CWEB files and have been set up to work as `packages' for LaTeX
+ as well. The option `+a' of former versions of the AMIGA installation
+ is now replaced by the file `amiga_types.w' that can be `@i'ncluded in
+ the source files where needed.
+
+ - [GENERAL] Both CTANGLE and CWEAVE are fully localized for other natural
+ languages than the English default. See the 'po/' directory for the
+ files used with the "GNU gettext utilities".
+ <Obsolete>#include files with the English, German, and Italian strings
+ are provided in the ./catalogs directory for non-localized operating
+ systems. On AmigaOS 2.1/3.0 localization is done with the help of
+ language catalogs and the system `locale.library'. Default is (of
+ course) English; catalogs descriptions for German and Italian are
+ provided and other language catalogs can easily be added.</Obsolete>
+
+ - [GENERAL] An algorithm for recursive `@i'nclude file search was adapted
+ from the Web2c implementation of TeX and METAFONT. The weave and tangle
+ processors as well as wmerge now recognize the environment variable
+ CWEBINPUTS. When an include file name (argument to the @i command) can
+ not be found in the current directory or in the absolute path, a
+ multi-path search is performed. CWEBINPUTS---if not empty---may contain
+ a list of search path names, delimited by PATH_SEPARATORs, e.g., colons.
+ The current directory is represented by an empty path entry, but it is
+ searched first anyway. In the respective makefiles for AMIGA, UNIX and
+ MS/DOS some decent defaults are set in the compile time constant
+ CWEBINPUTS, which always is appended to any environment variable, so you
+ don't have to repeat the defaults.
+
+ - [GENERAL] The `-o' option was added in connection with Carsten Steger's
+ `-i' option. Both affect typographic niceties in the woven output.
+
+ - [GENERAL] The output files of CTANGLE and CWEAVE are only written when
+ there are significant changes to their contents, i.e., when a CWEB source
+ creates multiple output files, only those modules effected by changes
+ will be recompiled in the `make' process. This mechanism was taken from
+ Preston Briggs's NUWEB program, to whom credit is due.
+
+ - [GENERAL] Five additional CWEB example programs are included as examples
+ for the portability between PASCAL-WEB and C-CWEB and for the usage of
+ the C++ features of version 3.1. The fifth example program is a simple
+ text converter for files with extended character codes of ISO-Latin-1,
+ PC-850, MAC 8-bit font, and HP 8-bit font.
+
+ - [GENERAL] The latest release of CWEBbin is fully compatible with the
+ "TeX Live" system. 'cwebbin.spec' and 'Makefile.unix' are prepared to
+ work with the '--with texlive' option. This appends and merges the
+ *-texlive.* change files and creates a set of *-w2c.ch change files and
+ an extended comm-foo.h @include file. These files are drop-in
+ replacements for the hand-coded files used in the TL ecosystem.
+
+ - [GENERAL] The latest latest release of CWEBbin includes CWEAVE's
+ 'evil twin' CTWILL, together with its utility programs 'refsort' and
+ 'twinx', and the associated TeX macros.
+
+ - [AMIGA] Two AREXX scripts for use with the CygnusEd Professional Editor
+ were added to this package, one for CTANGLE and CWEAVE, localized with
+ the help of language catalogs under AmigaOS version 2.1 or 3.0, the other
+ for use with the SAS/C 6.x compiler in connection with CED V3.5.
+
+ - [AMIGA] All three system programs support the `version' information
+ command of the Amiga operating system.
+
+ - [AMIGA] All three system programs are compiled in the NEAR data segment
+ and can be made `resident'.
+
+ - [AMIGA] The `+m' option enables ARexx communication between CWEB and the
+ SAS/C message browser SCMSG. Any warnings or error messages are
+ transferred to its list window. The behaviour of this feature can be
+ controlled via the external environment variable SCMSGOPT, which may be
+ set to any legal option string as described in the documentation of the
+ SAS/C development system by SAS Institute.
+
+%%% A BIT OF HISTORY %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Patch level [p9b] of this implementation introduced localization to other
+languages than English. All output strings of ctangle and cweave were
+replaced by variable references to an array AppStrings in cweb.h (also new),
+set to the English defaults at startup time. This works for all systems and
+compilers in a compatible way. However, version 2.1 of the AMIGA operating
+system introduced the use of language catalogs, thus enabling programs and
+applications to be inherently multilingual without recompilation. To
+activate this feature, you only have to install AmigaOS 2.1/3.0. Catalogs
+for various natural languages are already present at the correct place
+(./catalogs/), so ctangle and cweave will greet you in any of these
+languages, if you start them from their home directory ./bin and if your
+system default language is supported. If you want to use CTANGLE, CWEAVE,
+and WMERGE as resident programs, you have to move the language catalogs to
+the appropriate directories of the LOCALE: drawer. Catalog translations for
+other languages can easily be installed. The author of this distribution
+would be grateful to receive catalog translations for other languages for
+inclusion in future versions.
+
+Patch level [p9d] of this implementation introduced dynamic memory allocation
+for all internal arrays except for `flags[256]'. By this method both ctangle
+and cweave can be compiled in the `NEAR' data segment, so on the AMIGA they
+can be made `resident', i.e., they can reside in RAM and don't have to be
+loaded from disk after the first time. Patch level [p9d] also introduced an
+ARexx communication facility between CWEB (i.e., ctangle and cweave) and the
+`Message Browser' SCMSG, included in the SAS/C 6.X development system. If
+you run CWEB with the `+m' option, any error messages will be displayed in
+the window of SCMSG. The default setting is `off'. You can control the
+behaviour of this feature by setting the environment variable SCMSGOPT to
+a string with any legal command line options for SCMSG as described in the
+documentation provided with the compiler package by SAS Institute. If the
+environment variable is not set, the default behaviour of SCMSG will be used.
+Patch level [p9d] was evaluated on July 1, 1994, by Andreas Scherer and
+Burkhard Schmitt of Bayreuth University with CC and GCC on a HP Apollo
+workstation and a Sun 4 workstation and a SGI workstation, and on July 2,
+with Borland C/C++ version 3.1 on a MS/DOS machine without any problems.
+
+Patch level [p10] was released to the AmiNet and the Comprehensive TeX
+Archive Network (CTAN) in August 1994. At least one user had problems
+installing the MS/DOS version.
+
+Patch level [p11] was released to the AmiNet and the Comprehensive TeX
+Archive Network (CTAN) in December 1994. Only two days later another
+update of CWEB 3.3 was released in Stanford, so a new patch level [p11a]
+had to be created and released in mid-December 1994. In January 1995 the
+successful installation on at least two more systems has been notified.
+The first is MS/DOS with GCC, the second OS/2 in genuine mode, both working
+with Makefile.unix (and the obvious modifications).
+
+%%% CREDIT WHERE CREDIT IS DUE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+I want to express my deep gratitude to Silvio Levy and Donald Knuth for the
+marvelous tool they provided us with. Also I am indepted to my various pre-
+and co-workers on whose initial ideas and contributions this package is based.
+
+
+Happy CWEBbin'!
+
+January 1, 2019.
+
+Andreas Scherer
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/web/c_cpp/cwebbin/README.md b/web/c_cpp/cwebbin/README.md
new file mode 100644
index 0000000000..245a1a232c
--- /dev/null
+++ b/web/c_cpp/cwebbin/README.md
@@ -0,0 +1,58 @@
+# literate programming in ansi-c/c++
+
+*cwebbin* is the ansi-c/c++ implementation of silvio levy's and donald e.
+knuth's [cweb system](http://www-cs-faculty.stanford.edu/~uno/cweb.html) and
+donald e. knuth's [ctwill program](ftp://ftp.cs.stanford.edu/pub/ctwill). it
+requires the contents of [the original source
+drop](http://mirrors.ctan.org/web/c_cpp/cweb/cweb.tar.gz) and [the secondary
+source drop](ftp://ftp.cs.stanford.edu/pub/ctwill/ctwill.tar.gz), to which it
+applies a set of change files to fix warnings issued by modern c/c++ compilers
+and to introduce advanced features. see the extensive [readme](README.txt) for
+the full story.
+
+extract *cwebbin-2019.tar.gz* and add the contents of *cweb-3.64c.tar.gz* and
+*ctwill.tar.gz* for the full set of source files. unix/linux users should work
+with [make -f Makefile.unix](Makefile.unix) exclusively (targets ‘boot,’
+‘cautiously,’ and ‘all’).
+
+## advanced packaging
+
+alternatively, you may want to use *rpmbuild* or *debbuild* for compiling the
+sources and for creating installable packages in *rpm* and *deb* format. clone
+[cweb](https://github.com/ascherer/cweb) and
+[cwebbin](https://github.com/ascherer/cwebbin), create the source drops with
+```
+git archive -o cweb-3.64c.tar.gz cweb-3.64c
+git archive -o cwebbin-2019.tar.gz cwebbin-2019
+```
+respectively, put these two tarballs and the original *ctwill.tar.gz* in the
+*SOURCES* directory and *cwebbin.spec* in the *SPECS* directory of your build
+arena, and run
+```
+rpmbuild -ba SPECS/cwebbin.spec
+debbuild -ba SPECS/cwebbin.spec
+```
+depending on your preferences.
+
+## plain vanilla cweb
+
+if all you want is the original cweb without any add-ons but minus heaps of
+compiler warnings, use the special option `--with ansi_only` to include only
+the minimal changes required for a clean compilation.
+```
+rpmbuild -ba SPECS/cwebbin.spec --with ansi_only
+debbuild -ba SPECS/cwebbin.spec --with ansi_only
+```
+
+## cweb for texlive
+
+the extended sources and the build system were modified to smoothly integrate
+with the [texlive build system](https://github.com/TeX-Live/texlive-source). by invoking
+```
+debbuild -bi SPECS/cwebbin.spec --with texlive
+```
+you receive a small tarball `cweb-texlive.tar.gz`, which should be extracted in
+texlive's source directory `texk/web2c/cwebdir`. this tarball contains
+`*-w2c.ch` files that modify the original cweb sources for the texlive
+ecosystem. additionally, it contains language catalogs, tex macros, and cweb
+include files.
diff --git a/web/c_cpp/cwebx/Makefile b/web/c_cpp/cwebx/Makefile
new file mode 100644
index 0000000000..a61bd6280a
--- /dev/null
+++ b/web/c_cpp/cwebx/Makefile
@@ -0,0 +1,122 @@
+# This file is part of CWEB, version x3.0.
+
+#
+# Read the README file, then edit this file to reflect local conditions
+#
+
+# The C compiler should be ANSI compatible
+
+CC = gcc
+
+# We let CWEAVE report syntax errors by setting +d.
+# The flag +m makes the TeX output slightly more compact.
+# We use the +e flag since our printer is two-sided.
+
+CWFLAGS = +mde
+CTFLAGS =
+
+# We keep debugging info around to enable the `+d' option of cweave
+CFLAGS = -DDEBUG -DSTAT -g
+
+# RM and CP are used below in case rm and cp are aliased
+
+RM= /bin/rm
+CP= /bin/cp
+RENAME= /bin/mv
+
+
+# Set CCHANGES to common-foo.ch if you need changes to common.w in another
+# file than common.ch
+
+CCHANGES=
+
+# Set TCHANGES to ctangle-foo.ch if you need changes to ctangle.w in another
+# file than ctangle.ch
+
+TCHANGES=
+
+# Set WCHANGES to cweave-foo.ch if you need changes to cweave.w in another
+# file than cweave.ch
+
+WCHANGES=
+
+########## You shouldn't have to change anything after this point #######
+
+CWEAVE = ./cweave $(CWFLAGS)
+CTANGLE = ./ctangle $(CTFLAGS)
+
+.SUFFIXES: .tex .dvi .w
+
+.w.tex:
+ $(CWEAVE) $*
+
+.tex.dvi:
+ tex $*.tex
+
+.w.c:
+ $(CTANGLE) $*
+
+.w.dvi:
+ make $*.tex
+ make $*.dvi
+
+.w.o:
+ make $*.c
+ make $*.o
+
+all: cweb doc listings
+cweb: ctangle cweave
+manual doc: manual.dvi
+listings: common.dvi ctangle.dvi cweave.dvi
+
+cautiously:
+ make common.c ctangle.c cweave.c
+ $(RENAME) ctangle SAVEctangle # save version in case things mess up
+ make ctangle
+ $(RENAME) common.c SAVEcommon.c
+ ./ctangle common $(CCHANGES)
+ diff common.c SAVEcommon.c
+ $(RENAME) SAVEcommon.c common.c # restore date
+ $(RENAME) ctangle.c SAVEctangle.c
+ ./ctangle ctangle $(TCHANGES)
+ diff ctangle.c SAVEctangle.c
+ $(RENAME) SAVEctangle.c ctangle.c # restore date
+ $(RENAME) cweave.c SAVEcweave.c
+ ./ctangle cweave $(WCHANGES)
+ diff cweave.c SAVEcweave.c
+ $(RENAME) SAVEcweave.c cweave.c # restore date
+ $(RM) SAVEctangle # succeeded, use new binary from now on
+
+SAVEctangle.c:
+ $(CP) ctangle.c SAVEctangle.c
+
+SAVEcommon.c:
+ $(CP) common.c SAVEcommon.c
+
+common.c: common.w $(CCHANGES) common.inc
+ $(CTANGLE) common $(CCHANGES)
+common.h: common.w $(CCHANGES)
+ $(CTANGLE) common $(CCHANGES)
+
+common.tex: common.w common.inc
+ $(CWEAVE) common $(CCHANGES)
+
+ctangle: ctangle.o common.o
+ $(CC) $(CFLAGS) -o ctangle ctangle.o common.o
+
+ctangle.c: ctangle.w $(TCHANGES) common.inc common.h
+ $(CTANGLE) ctangle $(TCHANGES)
+
+ctangle.tex: ctangle.w $(TCHANGES) common.inc intro.inc
+ $(CWEAVE) ctangle $(TCHANGES)
+
+cweave: cweave.o common.o
+ $(CC) $(CFLAGS) -o cweave cweave.o common.o
+
+cweave.c: cweave.w $(WCHANGES) common.inc common.h parser.w rules.w
+ $(CTANGLE) cweave $(WCHANGES)
+
+cweave.tex: cweave.w $(WCHANGES) parser.w rules.w common.inc intro.inc
+ $(CWEAVE) cweave $(WCHANGES)
+
+manual.dvi: compare.tex
diff --git a/web/c_cpp/cwebx/README b/web/c_cpp/cwebx/README
new file mode 100644
index 0000000000..66fd57e171
--- /dev/null
+++ b/web/c_cpp/cwebx/README
@@ -0,0 +1,111 @@
+This file is part of CWEB version x3.04, and explains briefly what CWEB is,
+and how to set it up, and what the various files are for. Here is a listing
+of the other files constituting the release with a brief indication of their
+purpose.
+
+
+common.w % CWEB source for routines common to CTANGLE and CWEAVE
+ctangle.w % CWEB source for CTANGLE
+cweave.w % CWEB source for bulk of CWEAVE
+parser.w % CWEB source for parser of CWEAVE
+rules.w % CWEB source for grammar rules of CWEAVE
+common.inc % CWEB source included by common.w, ctangle.w, and cweave.w
+intro.inc % CWEB source included by ctangle.w and cweave.w
+
+common.c % C file produced (by CTANGLE) from common.w; for bootstrap
+common.h % C file produced (by CTANGLE) from common.w; for bootstrap
+ctangle.c % C file produced (by CTANGLE) from ctangle.w; for bootstrap
+
+cwebxmac.tex % TeX macro file needed to process files produced by CWEAVE
+cwebcmac.tex % TeX macro file needed in addition for compatibility mode
+
+cwebhmac.tex % optional TeX macro file creating hyperlinks for xhdvi (e.g.)
+
+manual.tex % master file for the CWEB manual
+compare.tex % file \input by manual.tex (present to facilitate bootstrap)
+
+Makefile % control file for UNIX make facility to build CWEB
+
+man1 % directory with UNIX manpage
+man1/cweb.1 % UNIX manpage for CTANGLE and CWEAVE
+
+examples % directory with sample CWEB programs
+examples/compare.w % Compare files; source for compare.tex above
+examples/treeprint.w % Convert sorted file listings to a tree diagram
+examples/wc.w % Count characters, words and lines in text files
+examples/wmerge.w % Perform preprocessing of change files as filter
+examples/Makefile
+
+cweb.el % EMACS file that might facilitate editing CWEB files
+
+
+The CWEB system allows you to write C programs and their documentation at
+the same time, in a way that optimises human readability. This version
+fully supports ANSI/ISO C, and indeed requires such a compiler for its own
+compilation. Like other WEB systems, CWEB allows you to decompose your
+programs into small, logically related portions, to add any desired amount
+of documentation to each of them, and to present them in any order that help
+understanding. As TeX is used to obtain the printed source document, a high
+typographic quality can be obtained while allowing for formatting of
+complicated formulae and tables; formatting of C program fragments is simple
+however, since it is done fully automatically. When used properly, CWEB can
+be used to produce documents that combine the qualities of a scientific
+publication about algorithms and of a well documented source listing for an
+implementation of those algorithms.
+
+The CWEB system consists of two programs, CTANGLE and CWEAVE, that are to be
+used in combination with a C compiler and TeX; both transform text files,
+while they share the same input language. CWEB source files, that typically
+have suffix `.w', can be converted by CTANGLE to C files (suffix `.c') that
+can be compiled, and alternatively can be converted by CWEAVE to TeX files
+(suffix `.tex') from which the typeset source listing can be produced by
+TeX. More details can be found in the manual, which you obtain by running
+TeX on the file manual.tex. Here the main interest is that since CWEB is
+written using CWEB you need a bootstrap procedure to get things going. For
+this purpose the derived files common.c, common.h and ctangle.c are supplied.
+If you have the UNIX make facility, all you have to do is check that these
+files are newer than the sources common.w and ctangle.w (they should be when
+the archive is unpacked, but you can use "touch" to make them newer in case
+this should be necessary), and that the Makefile macro CC refers to an ANSI
+compiler (it is set to "cc"; you may need to select "gcc" instead or to
+supply additional flags in CFLAGS) and then invoke "make all". Otherwise
+here is the required sequence of commands.
+
+$ cc -c ctangle.c # compile main part of CTANGLE
+$ cc -c common.c # compile common code
+$ cc -o ctangle ctangle.o common.o # link CTANGLE together
+$ ./ctangle cweave # create cweave.c from cweave.w
+$ cc -DDEBUG -DSTAT -g -c cweave.c # compile main part of CWEAVE
+$ cc -DDEBUG -DSTAT -g -o cweave cweave.o common.o # link CWEAVE together
+$ tex manual.tex # typeset the manual
+
+$ # the rest is only needed to obtain source listings for the CWEB system
+$ ./cweave common # produce common.tex
+$ tex common # typeset listing of common code
+$ ./cweave ctangle # produce ctangle.tex
+$ tex ctangle # typeset listing of CTANGLE
+$ ./cweave cweave # produce cweave.tex
+$ tex cweave # typeset listing of CWEAVE
+
+By the time you have done all this successfully, you have already tested
+CTANGLE and CWEAVE on a substantial amount of input, and you may be
+confident that the system is working properly.
+
+Should you on the other hand encounter problems during bootstrapping, then
+things are of course less pleasant, especially because you cannot print the
+source listings yet. Few problems are expected though, since there are no
+known system dependencies, and identical source code compiles on several
+dissimilar systems, one of which is quite non-UNIX. It is expected though that
+the compiler can handle large arrays (certainly larger than 64 Kb) and
+programs that used command line arguments; if your compiler does not, you will
+either have to replace it by a better one or do some tailoring of the
+programs. If you encounter any other difficulties, please report them to me at
+<maavl@zenon.univ-poitiers.fr>. If you do need to make changes to common.c,
+common.h, or ctangle.c, don't forget to write them down, since they will have
+to be applied at the proper places in common.w, ctangle.w, or common.inc in
+order to persist after bootstrapping. Such patches are best incorporated into
+a change file (e.g., ctangle.ch) as explained in the manual.
+
+Marc van Leeuwen
+Universit\'e de Poitiers
+http://wallis.univ-poitiers.fr/~maavl/
diff --git a/web/c_cpp/cwebx/common.c b/web/c_cpp/cwebx/common.c
new file mode 100644
index 0000000000..bbd7c75d0a
--- /dev/null
+++ b/web/c_cpp/cwebx/common.c
@@ -0,0 +1,885 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include "common.h"
+#define max_bytes 50000L
+#define max_modules 1000
+#define max_idents 5000
+#define max_sections 4000
+#define hash_size 353
+#define buf_size 100
+#define longest_name 1000
+#define long_buf_size (buf_size+longest_name)
+#define local static
+#define array_size(a)((int)(sizeof(a)/sizeof(a[0])))
+#define false (boolean)0
+#define true (boolean)1
+#define ctangle 0
+#define cweave 1
+#define and_and 04
+#define lt_lt 020
+#define gt_gt 021
+#define plus_plus 013
+#define minus_minus 01
+#define minus_gt 031
+#define not_eq 032
+#define lt_eq 034
+#define gt_eq 035
+#define eq_eq 036
+#define or_or 037
+#define find_char()(loc<=limit||get_line())
+#define id_index(p)((sixteen_bits)((p)-id_table))
+#define id_at(i)(&id_table[i])
+#define mod_index(p)((sixteen_bits)((p)-mod_table))
+#define mod_at(i)(&mod_table[i])
+#define name_begin(p)((p)->byte_start)
+#define length(p)((int)(strlen(name_begin(p))))
+#define name_end(p)(name_begin(p)+length(p))
+#define complete_name(p)((p)->byte_start[-1]=='\0')
+#define print_mod(p) \
+printf(": <%s%s>",name_begin(p),complete_name(p)?"":"...")
+#define spotless 0
+#define harmless_message 1
+#define error_message 2
+#define fatal_message 3
+#define mark_harmless() \
+if(history==spotless)history=harmless_message;else
+#define mark_error()(history=error_message)
+#define overflow(t)fatal("\n! Sorry, %s capacity exceeded",t)
+#define confusion(s)fatal("\n! This can't happen: %s",s)
+#define show_banner flags['b']
+#define show_happiness flags['h']
+#define show_progress flags['p']
+#define show_stats flags['s']
+#define C_plus_plus flags['+']
+#define compatibility_mode flags['c']
+#define update_terminal()fflush(stdout)
+#define new_line()putchar('\n')
+#define term_write(string,leng)printf("%.*s",(int)(leng),string)
+#define buffer_end (&buffer[buf_size-2])
+#define max_include_depth 10
+#define max_include_paths 8
+#define max_path_length 80
+#define lines_match() \
+(change_limit-change_buffer==limit-buffer \
+&&strncmp(buffer,change_buffer,limit-buffer)==0)
+#define byte_mem_end (&byte_mem[max_bytes])
+#define id_table_end (&id_table[max_idents])
+#define mod_table_end (&mod_table[max_modules])
+#define copy_char(c)if(id_loc<mod_text_end)*id_loc++=c;else(void)(c)
+/*13:*//*8:*/
+#line 122 "common.inc"
+boolean names_match(id_pointer,char*,int,int);
+void init_id_name(id_pointer,int);
+void init_module_name(mod_pointer);/*:8*//*17:*/
+#line 106 "common.w"
+int program,phase;/*:17*//*21:*/
+#line 145 "common.w"
+char buffer[long_buf_size];
+char*loc=buffer;
+
+char*limit=buffer;/*:21*//*24:*/
+#line 230 "common.w"
+struct f file[max_include_depth];
+struct f change;
+local char web_file_name[max_file_name_length]
+,change_file_name[max_file_name_length]
+,alt_web_file_name[max_file_name_length];
+int include_depth;
+boolean input_has_ended;
+boolean changing;
+boolean web_file_open=false;
+boolean print_where=false;
+local struct{char*name;int length;}
+at_h_path[max_include_paths],at_i_path;
+
+boolean including_header_file=false;/*:24*//*29:*/
+#line 382 "common.w"
+local boolean saved_changing;
+local char*saved_change_limit;
+local int saved_include_depth=0;/*:29*//*32:*/
+#line 452 "common.w"
+local char change_buffer[buf_size];
+local char*change_limit;/*:32*//*44:*/
+#line 632 "common.w"
+sixteen_bits section_count;
+eight_bits changed_section[(max_sections+7)/8];/*:44*//*53:*/
+#line 811 "common.w"
+char byte_mem[max_bytes];
+char*byte_ptr= &byte_mem[0];
+id_info id_table[max_idents];
+id_pointer id_ptr= &id_table[0];
+mod_info mod_table[max_modules];
+mod_pointer mod_ptr= &mod_table[0];/*:53*//*59:*/
+#line 893 "common.w"
+id_pointer hash[hash_size];/*:59*//*68:*/
+#line 1009 "common.w"
+mod_pointer root=NULL;/*:68*//*81:*/
+#line 1276 "common.w"
+char mod_text[longest_name+1];
+char*id_first;
+char*id_loc;/*:81*//*89:*/
+#line 1439 "common.w"
+int history=spotless;/*:89*//*96:*/
+#line 1535 "common.w"
+boolean flags[UCHAR_MAX+1];
+char C_file_name[max_file_name_length];
+local char tex_file_name[max_file_name_length];
+char idx_file_name[max_file_name_length];
+char scn_file_name[max_file_name_length];
+local boolean change_file_explicit=false;/*:96*//*107:*/
+#line 1704 "common.w"
+FILE*C_file;
+FILE*tex_file;/*:107*//*110:*/
+#line 1730 "common.w"
+local boolean term_line_empty=true;/*:110*//*69:*/
+#line 1021 "common.w"
+enum mod_comparison
+{less,
+
+equal,
+greater,
+
+prefix,
+extension
+};/*:69*//*97:*/
+#line 1547 "common.w"
+local void scan_args(int argc,char* *argv);/*:97*//*:13*//*19:*/
+#line 116 "common.w"
+void common_init(int argc,char* *argv)
+{/*28:*/
+#line 352 "common.w"
+{char*cwebinputs=getenv("CWEBINPUTS");
+at_h_path[0].name=at_i_path.name=NULL;
+#ifdef CWEBHEADERS
+at_h_path[0].name=CWEBHEADERS;
+at_h_path[0].length=(int)strlen(CWEBHEADERS);
+#endif
+if(cwebinputs!=NULL)
+{at_i_path.length=(int)strlen(cwebinputs);
+at_i_path.name=strcpy(byte_ptr,cwebinputs);
+byte_ptr+=at_i_path.length+1;
+}
+else
+{
+#ifdef CWEBINPUTS
+at_i_path.name=CWEBINPUTS;at_i_path.length=(int)strlen(CWEBINPUTS);
+#endif
+}
+}/*:28*//*60:*/
+#line 901 "common.w"
+{int i=hash_size;do hash[--i]=NULL;while(i>0);}/*:60*//*66:*/
+#line 1000 "common.w"
+*byte_ptr++='\0';/*:66*//*83:*/
+#line 1307 "common.w"
+mod_text[0]=' ';/*:83*//*102:*/
+#line 1649 "common.w"
+show_banner=show_happiness=show_progress=true;/*:102*/
+#line 119 "common.w"
+scan_args(argc,argv);
+}/*:19*//*22:*/
+#line 162 "common.w"
+local boolean input_ln(FILE*f)
+
+{register int c;
+register char*k=limit=buffer;
+while((c=getc(f))!='\n'&&c!=EOF)
+if(k<=buffer_end){*k++=c;if(!isspace(c))limit=k;}
+if(k>buffer_end)
+{loc= &buffer[0];
+err_print("! Input line too long");
+if(limit>buffer_end)limit=buffer_end;
+}
+if(buffer[0]=='@'&&limit> &buffer[1]&&strchr("IXYZ",buffer[1])!=NULL)
+buffer[1]=tolower(buffer[1]);
+return c!=EOF||limit>buffer;
+}/*:22*//*25:*/
+#line 261 "common.w"
+boolean push_input_file(boolean header,boolean suspend)
+{boolean success=false;
+char delim=' ';
+while(loc<limit&&(isspace((eight_bits)*loc)))++loc;
+if(*loc=='"')delim= *loc++;
+else if(*loc=='<')delim='>',++loc;
+if(loc>=limit)err_print("! Include file name not given");
+
+else if(++include_depth>=max_include_depth)
+{--include_depth;
+err_print("! Too many nested includes");
+}
+else
+{/*26:*/
+#line 298 "common.w"
+{char*k=cur_file_name;
+while(loc<limit
+&&(delim==' '?!isspace((eight_bits)*loc):*loc!=delim))
+if(k== &cur_file_name[max_file_name_length-1])
+{err_print("! Include file name truncated");break;}
+
+else*k++= *loc++;
+*k='\0';
+}/*:26*/
+#line 275 "common.w"
+if(delim!='>'&&(cur_file=fopen(cur_file_name,"r"))!=NULL)
+success=true;
+else/*27:*/
+#line 320 "common.w"
+{char name_buf[max_path_length+max_file_name_length];int i;
+if(header)
+for(i=0;i<max_include_paths;++i)
+if(at_h_path[i].name==NULL)break;
+else
+{strcpy(name_buf,at_h_path[i].name);
+strcpy(&name_buf[at_h_path[i].length],cur_file_name);
+if((cur_file=fopen(name_buf,"r"))!=NULL){success=true;break;}
+}
+else if(at_i_path.name!=NULL)
+{strcpy(name_buf,at_i_path.name);
+strcpy(&name_buf[at_i_path.length],cur_file_name);
+success=(cur_file=fopen(name_buf,"r"))!=NULL;
+}
+}/*:27*/
+#line 278 "common.w"
+if(success)
+{cur_line=0;print_where=true;/*30:*/
+#line 392 "common.w"
+if(suspend)
+{saved_changing=changing;changing=false;
+saved_change_limit=change_limit;change_limit=change_buffer;
+saved_include_depth=include_depth;
+}/*:30*/
+#line 281 "common.w"
+}
+else
+{--include_depth;
+if(delim!='>')
+err_print("! Cannot open include file");
+
+}
+}
+loc= &limit[1];
+return success;
+}/*:25*//*31:*/
+#line 418 "common.w"
+local boolean get_web_line(void)
+{do
+if(++cur_line,input_ln(cur_file))
+if(!compatibility_mode
+&&limit> &buffer[1]&&buffer[0]=='@'&&buffer[1]=='i')
+{loc= &buffer[2];print_where=true;push_input_file(false,false);}
+
+else return true;
+else if(include_depth==0)
+{input_has_ended=true;web_file_open=false;return false;}
+else
+{fclose(cur_file);print_where=true;
+if(include_depth-- ==saved_include_depth)
+{changing=saved_changing;change_limit=saved_change_limit;
+saved_include_depth=0;including_header_file=false;
+if(changing)return false;
+}
+}
+while(true);
+}/*:31*//*33:*/
+#line 464 "common.w"
+local void prime_the_change_buffer(void)
+{change_limit=change_buffer;/*34:*/
+#line 477 "common.w"
+do
+{if(++change_line,!input_ln(change_file))return;
+if(limit> &buffer[1]&&buffer[0]=='@')
+if(buffer[1]=='x')break;
+else if(buffer[1]=='y'||buffer[1]=='z')
+{loc= &buffer[2];
+err_print("! Where is the matching @x?");
+}
+else/*35:*/
+#line 497 "common.w"
+{if(buffer[1]=='i'&&!compatibility_mode)
+{loc= &buffer[2];err_print("! No includes allowed in change file");}
+}/*:35*/
+#line 486 "common.w"
+}while(true);/*:34*//*36:*/
+#line 506 "common.w"
+do
+if(++change_line,!input_ln(change_file))
+{loc= &buffer[0];err_print("! Change file ended after @x");return;}
+while(limit==buffer);/*:36*//*37:*/
+#line 512 "common.w"
+{int n=(int)(limit-buffer);change_limit=change_buffer+n;
+strncpy(change_buffer,buffer,n);
+}/*:37*/
+#line 470 "common.w"
+}/*:33*//*38:*/
+#line 529 "common.w"
+local void check_change(void)
+
+{int n=0;
+if(!lines_match())return;
+print_where=true;
+do
+{changing=true;/*39:*/
+#line 560 "common.w"
+{if(++change_line,!input_ln(change_file))
+{loc= &buffer[0];err_print("! Change file ended before @y");
+
+change_limit=change_buffer;changing=false;return;
+}
+if(limit> &buffer[1]&&buffer[0]=='@')
+if(buffer[1]=='y')break;
+else if(buffer[1]=='x'||buffer[1]=='z')
+{loc= &buffer[2];err_print("! Where is the matching @y?");}
+
+else/*35:*/
+#line 497 "common.w"
+{if(buffer[1]=='i'&&!compatibility_mode)
+{loc= &buffer[2];err_print("! No includes allowed in change file");}
+}/*:35*//*37:*/
+#line 512 "common.w"
+{int n=(int)(limit-buffer);change_limit=change_buffer+n;
+strncpy(change_buffer,buffer,n);
+}/*:37*/
+#line 572 "common.w"
+}/*:39*/
+#line 538 "common.w"
+changing=false;
+if(!get_web_line())
+{loc= &buffer[0];
+err_print("! CWEB file ended during a change");return;
+
+}
+if(!lines_match())++n;
+}while(true);
+if(n>0)
+{loc= &buffer[2];
+print("\n! Hmm... %d of the preceding lines failed to match",n);
+
+err_print("");
+}
+}/*:38*//*41:*/
+#line 585 "common.w"
+void reset_input(void)
+{boolean use_change_file=change_file_name[0]!='\0';/*42:*/
+#line 601 "common.w"
+{if((web_file=fopen(web_file_name,"r"))!=NULL)
+strcpy(file[0].name,web_file_name);
+else if((web_file=fopen(alt_web_file_name,"r"))!=NULL)
+strcpy(file[0].name,alt_web_file_name);
+else fatal("! Cannot open \"%s\" as input file",web_file_name);
+
+web_file_open=true;
+if(use_change_file)
+if((change_file=fopen(change_file_name,"r"))!=NULL)
+strcpy(change.name,change_file_name);
+else if(!change_file_explicit)
+use_change_file=false;
+else fatal("! Cannot open \"%s\" as change file",change_file_name);
+
+}/*:42*/
+#line 588 "common.w"
+cur_line=0;change_line=0;include_depth=0;
+if(use_change_file){changing=true;prime_the_change_buffer();}
+
+else change_limit=change_buffer;
+
+limit=buffer;loc= &buffer[1];
+changing=false;input_has_ended=false;
+}/*:41*//*45:*/
+#line 660 "common.w"
+boolean get_line(void)
+{
+restart:
+if(changing)mark_section_as_changed(section_count);
+else/*47:*/
+#line 715 "common.w"
+{if(get_web_line()
+&&change_limit>change_buffer
+&&limit-buffer==change_limit-change_buffer
+&&buffer[0]==change_buffer[0]
+)check_change();
+}/*:47*/
+#line 665 "common.w"
+if(changing)
+{/*48:*/
+#line 728 "common.w"
+{if(++change_line,!input_ln(change_file))
+{err_print("! Change file ended without @z");
+buffer[0]='@';buffer[1]='z';limit= &buffer[2];
+}
+if(limit> &buffer[1]&&buffer[0]=='@')
+if(buffer[1]=='z')
+{prime_the_change_buffer();changing=false;print_where=true;}
+else if(buffer[1]=='x'||buffer[1]=='y')
+{loc= &buffer[2];err_print("! Where is the matching @z?");}
+
+else/*35:*/
+#line 497 "common.w"
+{if(buffer[1]=='i'&&!compatibility_mode)
+{loc= &buffer[2];err_print("! No includes allowed in change file");}
+}/*:35*/
+#line 739 "common.w"
+}/*:48*/
+#line 667 "common.w"
+if(!changing)
+{mark_section_as_changed(section_count);goto restart;}
+}
+loc= &buffer[0];*limit=' ';
+if(compatibility_mode&&buffer[0]=='@'&&buffer[1]=='i')
+{loc+=2;print_where=true;push_input_file(false,changing);
+goto restart;
+}
+if(limit-buffer>5
+&&strncmp(buffer,"#line",5)==0&&isspace((eight_bits)buffer[5]))/*46:*/
+#line 686 "common.w"
+{sixteen_bits line=0;
+print_where=true;
+loc= &buffer[6];while(loc<limit&&isspace((eight_bits)*loc))++loc;
+if(isdigit((eight_bits)*loc))
+{do line=10*line+ *loc++ -'0';while(isdigit((eight_bits)*loc));
+while(loc<limit&&isspace((eight_bits)*loc))++loc;
+if(*loc++ =='"')
+{int i=0;while(&loc[i]<limit&&loc[i]!='"')++i;
+if(loc[i]=='"'&&i<max_file_name_length)
+{struct f*cur_f=changing? &change:&file[include_depth];
+cur_f->line=line-1;
+strncpy(cur_f->name,loc,i);cur_f->name[i]='\0';
+goto restart;
+}
+}
+}
+err_print("! Improper #line directive");goto restart;
+
+}/*:46*/
+#line 679 "common.w"
+return!input_has_ended;
+}/*:45*//*50:*/
+#line 755 "common.w"
+void check_complete(void)
+{if(change_limit!=change_buffer)
+{int l=(int)(change_limit-change_buffer);
+strncpy(buffer,change_buffer,l);limit= &buffer[l];
+changing=true;loc=buffer;web_file_open=true;
+
+err_print("! Change file entry did not match");
+
+}
+}/*:50*//*54:*/
+#line 823 "common.w"
+char*store_string(char*s,int l)
+{char*dest=byte_ptr;
+if(byte_mem_end-byte_ptr<=l)overflow("byte memory");
+byte_ptr+=l;*byte_ptr++='\0';return strncpy(dest,s,l);
+}/*:54*//*61:*/
+#line 914 "common.w"
+id_pointer id_lookup(char*first,char*last,int ilk)
+
+{int l,h;
+if(last==NULL)last=first+(l=(int)strlen(first));
+else l=(int)(last-first);/*62:*/
+#line 932 "common.w"
+{char*p=first;
+h= *p;while(++p<last)h=((h<<1)+ *p)%hash_size;
+}/*:62*//*63:*/
+#line 942 "common.w"
+{id_pointer p=hash[h];
+while(p!=NULL&&!names_match(p,first,l,ilk))p=p->hash_link;
+if(p==NULL)/*64:*/
+#line 955 "common.w"
+{p=id_ptr;
+if(id_ptr++ >=id_table_end)overflow("identifier");
+name_begin(p)=store_string(first,l);
+if(program==cweave)init_id_name(p,ilk);
+p->hash_link=hash[h];hash[h]=p;
+}/*:64*/
+#line 947 "common.w"
+return p;
+}/*:63*/
+#line 922 "common.w"
+}/*:61*//*70:*/
+#line 1036 "common.w"
+local enum mod_comparison mod_name_cmp
+(char*p,int l1,char*q,int l2)
+{int l=l1<l2?l1:l2;
+while(--l>=0)if(*p++ != *q++)return* --p< * --q?less:greater;
+return l1<l2?prefix:l1>l2?extension:equal;
+}/*:70*//*71:*/
+#line 1051 "common.w"
+local mod_pointer make_mod_node(char*name)
+{mod_pointer node=mod_ptr;
+if(mod_ptr++ >=mod_table_end)overflow("module name");
+name_begin(node)=name;
+node->llink=NULL;node->rlink=NULL;
+init_module_name(node);
+return node;
+}/*:71*//*72:*/
+#line 1067 "common.w"
+local mod_pointer mod_name_lookup(char*name,int l)
+
+{mod_pointer p;
+mod_pointer*loc= &root;
+while((p= *loc)!=NULL)
+{int l0=p->key_length;char*key=name_begin(p);
+switch(mod_name_cmp(name,l,key,l0))
+{case less:loc= &p->llink;break;
+case greater:loc= &p->rlink;break;
+case equal:case extension:/*74:*/
+#line 1109 "common.w"
+{enum mod_comparison cmp=
+mod_name_cmp(name+l0,l-l0,key+l0,(int)strlen(key+l0));
+switch(cmp)
+{case less:case greater:
+err_print("! Incompatible module name");
+print("\nName inconsistently extends <%.*s...>.\n",l0,key);
+
+return NULL;
+case extension:case equal:
+if(complete_name(p))
+if(cmp==equal)return p;
+else
+{err_print("! Incompatible module name");
+print("\nPrefix exists: <%s>.\n",key);return NULL;
+
+}
+name_begin(p)=store_string(name,l);/*77:*/
+#line 1200 "common.w"
+free(key-1);/*:77*/
+#line 1128 "common.w"
+return p;
+}
+}/*:74*/
+#line 1081 "common.w"
+case prefix:
+err_print("! Incompatible module name");
+print("\nName is a prefix of <%s%s>.\n"
+,key,complete_name(p)?"":"...");
+return NULL;
+}
+}/*73:*/
+#line 1098 "common.w"
+{(p=make_mod_node(store_string(name,l)))->key_length=l;
+return*loc=p;
+}/*:73*/
+#line 1090 "common.w"
+}/*:72*//*75:*/
+#line 1152 "common.w"
+local mod_pointer prefix_lookup(char*name,int l)
+
+{mod_pointer p=root,*loc= &root;
+mod_pointer match=NULL;
+mod_pointer saved=NULL;
+while(p!=NULL)
+{int l0=p->key_length;char*key=name_begin(p);
+switch(mod_name_cmp(name,l,key,l0))
+{case less:p= *(loc= &p->llink);break;
+case greater:p= *(loc= &p->rlink);break;
+case equal:return p;
+case extension:/*78:*/
+#line 1209 "common.w"
+{enum mod_comparison cmp=
+mod_name_cmp(name+l0,l-l0,key+l0,(int)strlen(key+l0));
+switch(cmp)
+{case less:case greater:
+err_print("! Incompatible module name");
+print("\nName inconsistently extends <%.*s...>.\n",l0,key);
+
+return NULL;
+case prefix:case equal:return p;
+case extension:
+if(complete_name(p))
+{err_print("! Incompatible module name");
+print("\nPrefix exists: <%s>.\n",key);return NULL;
+}/*79:*/
+#line 1236 "common.w"
+{/*77:*/
+#line 1200 "common.w"
+free(key-1);/*:77*/
+#line 1237 "common.w"
+if((key=(char*)malloc(l+2))==NULL)fatal("Out of dynamic memory!");
+*key++='\1';
+strncpy(key,name,l);key[l]='\0';
+name_begin(p)=key;
+}/*:79*/
+#line 1224 "common.w"
+return p;
+}
+}/*:78*/
+#line 1167 "common.w"
+case prefix:
+if(match!=NULL)
+{err_print("! Ambiguous prefix");return NULL;}
+
+match=p;saved=p->rlink;p=p->llink;
+}
+if(p==NULL&&match!=NULL)
+p=saved,saved=NULL;
+}
+if(match==NULL)/*76:*/
+#line 1190 "common.w"
+{char*key=(char*)malloc(l+2);
+if(key==NULL)fatal("Out of dynamic memory!");
+*key++='\1';
+strncpy(key,name,l);key[l]='\0';
+(p=make_mod_node(key))->key_length=l;
+return*loc=p;
+}/*:76*/
+#line 1179 "common.w"
+match->key_length=l;
+return match;
+}/*:75*//*82:*/
+#line 1291 "common.w"
+mod_pointer get_module_name(void)
+{/*84:*/
+#line 1315 "common.w"
+{eight_bits c;char*k=mod_text;
+do
+{if(!find_char())
+{err_print("! Input ended in module name");break;}
+
+c= *loc++;/*85:*/
+#line 1342 "common.w"
+if(c=='@')
+{if((c= *loc++)=='>')break;
+if(isspace(c)||c=='*'||c=='~')
+{err_print("! Module name didn't end");loc-=2;break;}
+
+if(k<mod_text_end-1)* ++k='@';
+
+}/*:85*/
+#line 1322 "common.w"
+if(isspace(c))c=' ';
+if(k<mod_text_end-1&&!(c==' '&& *k==' '))* ++k=c;
+}while(true);
+id_first= &mod_text[1];
+if(k>=mod_text_end-1)
+{print("\n! Module name too long: ");
+term_write(id_first,25);err_print("..");
+}
+id_loc= *k==' '&&k>mod_text?k:k+1;
+
+}/*:84*/
+#line 1294 "common.w"
+{int l=(int)(id_loc-id_first);
+return l>=3&&strncmp(id_loc-3,"...",3)==0
+?prefix_lookup(id_first,l-3):mod_name_lookup(id_first,l);
+}
+}/*:82*//*86:*/
+#line 1360 "common.w"
+boolean get_control_text(void)
+{char c,*k=id_first= &mod_text[1];
+do
+if((*k++= *loc++)=='@')
+if((c= *loc++)!='@')
+{if(c!='>')
+err_print("! Control codes are forbidden in control text");
+
+return(id_loc=k-1)==id_first;
+}
+while(loc<=limit);
+err_print("! Control text didn't end");
+return(id_loc=k)==id_first;
+}/*:86*//*87:*/
+#line 1386 "common.w"
+void get_string(void)
+{char c,delim=loc[-1];
+id_loc=id_first= &mod_text[1];copy_char(delim);
+if(delim=='L')
+*id_loc++=delim= *loc++;
+else if(delim=='<')delim='>';
+do
+{if(loc>=limit)
+{err_print("! String didn't end");loc=limit;break;}
+
+copy_char(c= *loc++);
+if(c=='\\')
+if(loc<limit)copy_char(*loc++);
+
+else if(get_line())
+if(program==cweave)--id_loc;
+else copy_char('\n');
+else
+{loc=buffer;
+err_print("! Input ended in middle of string");
+
+break;
+}
+else if(!including_header_file&&c=='@')
+if(*loc=='@')++loc;
+else err_print("! Double @ required in strings");
+
+}
+while(c!=delim);
+if(id_loc>=mod_text_end)
+{print("\n! String too long: ");
+term_write(mod_text+1,25);err_print("..");
+}
+}/*:87*//*90:*/
+#line 1449 "common.w"
+void err_print(char*s)
+{print(*s=='!'?"\n%s.":"%s.",s);
+if(web_file_open)/*91:*/
+#line 1462 "common.w"
+{char*k,*l=(loc<limit)?loc:limit;
+if(changing)printf(" (l. %d of change file)\n",change_line);
+else if(include_depth==0)printf(" (l. %d)\n",cur_line);
+else printf(" (l. %d of include file %s)\n",cur_line,cur_file_name);
+if(l>buffer)
+{for(k=buffer;k<l;k++)putchar(*k=='\t'?' ':*k);
+new_line();
+for(k=buffer;k<l;k++)putchar(' ');
+}
+for(k=l;k<limit;k++)putchar(*k);
+}/*:91*/
+#line 1452 "common.w"
+update_terminal();mark_error();
+}/*:90*//*92:*/
+#line 1483 "common.w"
+void wrap_up(void)
+{
+#ifdef STAT
+if(show_stats)print_stats();
+#endif/*93:*/
+#line 1496 "common.w"
+{static char*mess[]=
+{"No errors were found.",
+"Did you see the warning message above?",
+"Pardon me, but I think I spotted something wrong",
+"That was a fatal error, my friend."
+};
+if(show_happiness||history>0)print("\n(%s)\n",mess[history]);
+}/*:93*/
+#line 1489 "common.w"
+exit(history>harmless_message);
+}/*:92*//*94:*/
+#line 1510 "common.w"
+void fatal(char*s,...)
+{va_list p;va_start(p,s);
+vprintf(s,p);va_end(p);err_print("");
+
+history=fatal_message;wrap_up();
+}/*:94*//*98:*/
+#line 1563 "common.w"
+local void scan_args(int argc,char* *argv)
+{char*dot_pos;
+int files_found=0,paths_found=at_h_path[0].name==NULL?0:1;
+while(--argc>0)
+if(((* ++argv)[0]=='+'||(*argv)[0]=='-')&&(*argv)[1]!='\0')/*103:*/
+#line 1656 "common.w"
+{boolean flag_change=(* *argv=='+');
+char*p= &(*argv)[1];unsigned char c;
+while((c= *p++)!='\0')
+if((c=tolower(c))!='i')flags[c]=flag_change;
+else/*104:*/
+#line 1668 "common.w"
+{size_t l=strlen(p);
+if(l==0)err_print("! Empty include path");
+
+else if(l>max_path_length)err_print("! Include path too long");
+
+else if(paths_found>=max_include_paths)
+err_print("! Too many include paths");
+
+else
+{at_h_path[paths_found].length=(int)l;
+at_h_path[paths_found++].name=strcpy(byte_ptr,p);
+byte_ptr+=l+1;
+}
+break;
+}/*:104*/
+#line 1661 "common.w"
+}/*:103*/
+#line 1569 "common.w"
+else
+{if(strlen(*argv)+5>max_file_name_length)
+
+fatal("! Filename too long:\n%s",*argv);
+dot_pos=strrchr(*argv,'.');
+switch(++files_found)
+{case 1:/*99:*/
+#line 1597 "common.w"
+#ifndef CPPEXT
+#define CPPEXT "C"
+
+#endif
+{if(dot_pos==NULL)sprintf(web_file_name,"%s.w",*argv);
+else
+{sprintf(web_file_name,"%s",*argv);
+*dot_pos='\0';
+}
+sprintf(alt_web_file_name,"%s.web",*argv);
+sprintf(change_file_name,"%s.ch",*argv);
+if(program==ctangle)
+sprintf(C_file_name,"%s.%s",*argv,C_plus_plus?CPPEXT:"c");
+else
+{sprintf(tex_file_name,"%s.tex",*argv);
+sprintf(idx_file_name,"%s.idx",*argv);
+sprintf(scn_file_name,"%s.scn",*argv);
+}
+}/*:99*/
+#line 1577 "common.w"
+
+break;case 2:/*100:*/
+#line 1624 "common.w"
+if((*argv)[0]=='-')change_file_name[0]='\0';
+else if((*argv)[0]!='+')
+{change_file_explicit=true;
+sprintf(change_file_name,dot_pos==NULL?"%s.ch":"%s",*argv);
+}/*:100*/
+#line 1578 "common.w"
+
+break;case 3:/*101:*/
+#line 1634 "common.w"
+if(program==ctangle)
+if(dot_pos!=NULL)sprintf(C_file_name,"%s",*argv);
+else sprintf(C_file_name,"%s.%s",*argv,C_plus_plus?CPPEXT:"c");
+else
+{if(dot_pos!=NULL)
+{sprintf(tex_file_name,"%s",*argv);*dot_pos='\0';}
+else sprintf(tex_file_name,"%s.tex",*argv);
+sprintf(idx_file_name,"%s.idx",*argv);
+sprintf(scn_file_name,"%s.scn",*argv);
+}/*:101*/
+#line 1579 "common.w"
+
+break;default:/*105:*/
+#line 1688 "common.w"
+fatal("! Usage:\n"
+"c%se [(+|-)options] cwebfile[.w] [(changefile[.ch]|+|-) [outputfile[.%s]]]"
+,program==ctangle?"tangl":"weav"
+,program==ctangle?"c":"tex");/*:105*/
+#line 1581 "common.w"
+}
+}
+if(files_found==0)/*105:*/
+#line 1688 "common.w"
+fatal("! Usage:\n"
+"c%se [(+|-)options] cwebfile[.w] [(changefile[.ch]|+|-) [outputfile[.%s]]]"
+,program==ctangle?"tangl":"weav"
+,program==ctangle?"c":"tex");/*:105*/
+#line 1584 "common.w"
+if(paths_found<max_include_paths)
+at_h_path[paths_found].name=NULL;
+}/*:98*//*108:*/
+#line 1708 "common.w"
+void open_output_file(void)
+{char*name;FILE* *file;
+if(program==ctangle){name=C_file_name;file= &C_file;}
+else{name=tex_file_name;file= &tex_file;}
+if((*file=fopen(name,"w"))==NULL)
+fatal("! Cannot open \"%s\" as output file",name);
+
+}/*:108*//*111:*/
+#line 1744 "common.w"
+void print(char*s,...)
+{va_list p;va_start(p,s);
+if(term_line_empty&& *s=='\n')++s;
+vprintf(s,p);va_end(p);
+term_line_empty=s[strlen(s)-1]=='\n';update_terminal();
+}
+
+void print_progress(char*s){if(show_progress)print(s);}
+
+void print_section_progress(void)
+{if(show_progress)print("*%u",section_count);}/*:111*/
diff --git a/web/c_cpp/cwebx/common.h b/web/c_cpp/cwebx/common.h
new file mode 100644
index 0000000000..6981a0bbcc
--- /dev/null
+++ b/web/c_cpp/cwebx/common.h
@@ -0,0 +1,90 @@
+/*14:*//*15:*/
+#line 90 "common.w"
+typedef char boolean;
+typedef unsigned char eight_bits;
+typedef unsigned short sixteen_bits;/*:15*//*51:*/
+#line 778 "common.w"
+typedef struct id_info
+{char*byte_start;/*55:*/
+#line 860 "common.w"
+struct variant*equiv_or_xref;/*:55*//*57:*/
+#line 871 "common.w"
+struct id_info*hash_link;
+int ilk;/*:57*/
+#line 780 "common.w"
+
+}id_info,*id_pointer;
+
+typedef struct mod_info
+{char*byte_start;/*56:*/
+#line 863 "common.w"
+struct variant*equiv_or_xref;/*:56*//*65:*/
+#line 979 "common.w"
+struct mod_info*llink,*rlink;
+
+int key_length;/*:65*/
+#line 785 "common.w"
+
+}mod_info,*mod_pointer;/*:51*//*16:*/
+#line 103 "common.w"
+extern int program,phase;/*:16*//*18:*/
+#line 112 "common.w"
+void common_init(int argc,char* *argv);/*:18*//*20:*/
+#line 133 "common.w"
+extern char buffer[],*loc,*limit;/*:20*//*23:*/
+#line 201 "common.w"
+#define max_file_name_length 60
+extern struct f
+{FILE*file;char name[max_file_name_length];sixteen_bits line;}
+file[],change;
+extern int include_depth;
+extern boolean input_has_ended,changing,web_file_open,print_where
+,including_header_file;
+
+boolean push_input_file(boolean,boolean);
+boolean get_line(void);
+
+#define cur_file file[include_depth].file
+#define cur_file_name file[include_depth].name
+#define cur_line file[include_depth].line
+
+#define web_file file[0].file
+#define change_file change.file
+#define change_line change.line/*:23*//*40:*/
+#line 579 "common.w"
+void reset_input(void);/*:40*//*43:*/
+#line 625 "common.w"
+extern sixteen_bits section_count;
+extern eight_bits changed_section[];
+#define mark_section_as_changed(n) (changed_section[(n)>>3]|=1<<((n)&7))
+#define section_changed(n) ((changed_section[(n)>>3]&(1<<((n)&7)))!=0)/*:43*//*49:*/
+#line 745 "common.w"
+extern void check_complete(void);/*:49*//*52:*/
+#line 796 "common.w"
+extern char byte_mem[],*byte_ptr;
+extern id_info id_table[],*id_ptr;
+extern mod_info mod_table[],*mod_ptr;/*:52*//*58:*/
+#line 886 "common.w"
+extern id_pointer hash[];
+#define hash_end (&hash[hash_size])
+id_pointer id_lookup(char*,char*,int);/*:58*//*67:*/
+#line 1005 "common.w"
+extern mod_pointer root;/*:67*//*80:*/
+#line 1266 "common.w"
+extern char mod_text[],*id_first,*id_loc;
+#define mod_text_end (&mod_text[longest_name+1])
+mod_pointer get_module_name(void);
+boolean get_control_text(void);
+void get_string(void);/*:80*//*88:*/
+#line 1433 "common.w"
+extern history;
+extern void err_print(char*),wrap_up(void),print_stats(void),
+fatal(char*,...);/*:88*//*95:*/
+#line 1531 "common.w"
+extern boolean flags[];
+extern char C_file_name[],idx_file_name[],scn_file_name[];/*:95*//*106:*/
+#line 1697 "common.w"
+extern FILE*C_file,*tex_file;
+void open_output_file(void);/*:106*//*109:*/
+#line 1723 "common.w"
+void print(char*,...),print_progress(char*),print_section_progress(void);/*:109*//*:14*/
diff --git a/web/c_cpp/cwebx/common.inc b/web/c_cpp/cwebx/common.inc
new file mode 100644
index 0000000000..db117631a6
--- /dev/null
+++ b/web/c_cpp/cwebx/common.inc
@@ -0,0 +1,184 @@
+@ This is is the beginning of material included (by means of `\.{@@i}') from
+the file \.{common.inc}, so that it appears in an identical way in the
+programs for \.{CTANGLE}, \.{CWEAVE}, and in the code shared between them
+(from the file \.{common.w}). There will therefore not be any code producing
+material, just like in a header file. However, the major part of the
+declarative information that is shared between all the compilation units is
+contained in an actual header file \.{common.h}, which is written as an
+auxiliary output file when \.{CTANGLE} processes \.{common.w}; in particular
+that file contains all the typedefs, |extern| variable declarations and
+function prototype declarations relating to code shared by \.{CTANGLE} and
+\.{CWEAVE}. Therefore this file is almost exclusively devoted to some macro
+definitions of general utility and a few function prototype declarations for
+functions that are {\it used\/} by the shared code but defined separately in
+\.{CTANGLE} and \.{CWEAVE}.
+
+@h <stdlib.h>
+@h <stdio.h>
+@h <string.h>
+@h <ctype.h>
+@h <limits.h>
+@h "common.h"
+
+@ We start with some dimensioning parameters that are used both in
+\.{CTANGLE} and \.{CWEAVE}. Some of them have been decreased with respect to
+their earlier values which were sufficient in the original \.{WEB} to handle
+\TeX. Nevertheless they should be sufficient for most applications of
+\.{CWEB}, since in \Cee\ there is no need to generate large programs
+entirely as a single file (and \TeX\ is not written in \.{CWEB}!). The
+smaller values allow \.{CWEB} to run on rather moderate size computers.
+
+@d max_bytes 50000L
+ /* the number of bytes in identifier and module names */
+@d max_modules 1000 /* maximal number of module names */
+@d max_idents 5000 /* maximal number of identifiers */
+@d max_sections 4000
+ /* greater than the total number of sections, and less than $10240$ */
+@d hash_size 353 /* hash modulus, preferably odd */
+@d buf_size 100 /* maximum length of input line, plus two */
+@d longest_name 1000
+ /* module names and strings shouldn't be longer than this */
+@d long_buf_size (buf_size+longest_name) /* for \.{CWEAVE} */
+
+@ Here are some macros of general utility. We use |local| in place of
+|static| for functions and variables when we want to stress the property
+of file-scope rather than static initialisation and permanence of value.
+The macro |array_size| can be used to compute the number of elements in a
+statically initialised array. For truth values we use the type |boolean|
+and the values |true| and |false|. We also make the general convention that
+whenever we mention a pointer to the ``end'' of a subsequence of a linear
+array, we mean the address of first entry beyond the subsequence itself.
+This is in keeping with general practice in~\Cee, and the language definition
+in fact guarantees the existence of the address even if the subsequence
+should contain the last entry of the array; this convention avoids repeated
+use of turgid phrases such as ``pointing one place beyond the last entry
+of~\dots''.
+
+@d local static
+@f local static
+@d array_size(a) ((int)(sizeof(a)/sizeof(a[0])))
+@d false (boolean) 0
+@d true (boolean) 1
+@d ctangle 0
+@d cweave 1
+
+@ Although \.{CWEB} uses the conventions of \Cee\ programs found in
+the standard \.{<ctype.h>} header file, it does assume that the character set
+is the \caps{ASCII} code. This dependency is mild however, and limited to
+the assumption that certain character codes below |040| are not occupied by
+ordinary characters. To be able to use such vacant spots in a character
+code independent way is possible (as is done in \TeX) by mapping all
+characters on input to their \caps{ASCII} positions (thereby ensuring that
+certain positions remain unused) and unmapping them on output; such an
+approach was deemed too tedious for the \.{CWEB} system however. Rather,
+the few places that have to be modified for non-\caps{ASCII} codes can be
+located by looking up the entry named ``\caps{ASCII} code dependencies''
+in the index of each of the programs.
+
+@ A few character pairs are encoded internally as single characters, using
+the definitions below. These definitions are consistent with an extension of
+\caps{ASCII} code originally developed at \caps{MIT} and explained in
+Appendix~C of {\sl The \TeX book\/}. Thus, users who have such a character
+set can type things like `\.{\char'32}' and `\.{\char'4}' instead of
+`\.{!=}' and `\.{\&\&}'; however, their files will not be too portable until
+more people adopt the extended code. To be precise, when moved to other
+installations their files can still be processed by \.{CTANGLE} and
+\.{CWEAVE}, producing the required output, but users will have problems
+reading the source files. Therefore it is advised to use the two-character
+form in the \.{CWEB} files, which will be converted to single characters on
+input.
+
+@^ASCII code dependencies@> @^system dependencies@>
+
+@d and_and 04 /* `\.{\&\&}'; this corresponds to \caps{MIT}'s \.{\char'4} */
+@d lt_lt 020 /* `\.{<<}'; this corresponds to \caps{MIT}'s \.{\char'20} */
+@d gt_gt 021 /* `\.{>>}'; this corresponds to \caps{MIT}'s \.{\char'21} */
+@d plus_plus 013 /* `\.{++}'; this corresponds to \caps{MIT}'s \.{\char'13} */
+@d minus_minus 01 /* `\.{--}'; this corresponds to \caps{MIT}'s \.{\char'1} */
+@d minus_gt 031 /* `\.{->}'; this corresponds to \caps{MIT}'s \.{\char'31} */
+@d not_eq 032 /* `\.{!=}'; this corresponds to \caps{MIT}'s \.{\char'32} */
+@d lt_eq 034 /* `\.{<=}'; this corresponds to \caps{MIT}'s \.{\char'34} */
+@d gt_eq 035 /* `\.{>=}'; this corresponds to \caps{MIT}'s \.{\char'35} */
+@d eq_eq 036 /* `\.{==}'; this corresponds to \caps{MIT}'s \.{\char'36} */
+@d or_or 037 /* `\.{\v\v}'; this corresponds to \caps{MIT}'s \.{\char'37} */
+
+@ Invoking the macro |find_char| will fetch a new line if the current one
+has been completely read, and it will either return |false| to indicate that
+there is no input left, or otherwise ensure that it is safe to inspect
+|*loc| (although it might be the line-ending space).
+
+@d find_char() (loc<=limit || get_line())
+
+@ The following declarations give the interface to the searching algorithms.
+They are defined separately in \.{CTANGLE} and \.{CWEAVE} and used by the
+common code, rather than the other way around. The small number of such
+functions does not seem to justify creating a separate header file for them,
+and moreover, it would be difficult to decide whether such a header file
+should be produced by the source file for \.{CTANGLE} or by the source file
+for \.{CWEAVE}.
+
+@< Function prototypes used but not defined in the shared code @>=
+
+boolean names_match (id_pointer,char*,int,int);
+void init_id_name (id_pointer,int);
+void init_module_name (mod_pointer);
+
+@ Here are some macros associated with the storage of names. The first four
+of them convert pointers to structures representing identifiers or module
+names to smaller |sixteen_bits| indices into the arrays they are stored in,
+and back again. The macros |name_begin|, |name_end| and |length| provide
+the basic attributes of the actual string referred to by a name pointer.
+The macro |complete_name| tells whether the complete name for a module has
+been encountered so far, and |print_mod| prints a module name on the user's
+terminal for error reporting, providing a colon, angle brackets and an
+ellipsis if necessary.
+
+@d id_index(p) ((sixteen_bits)((p)-id_table))
+@d id_at(i) (&id_table[i])
+@d mod_index(p) ((sixteen_bits)((p)-mod_table))
+@d mod_at(i) (&mod_table[i])
+@d name_begin(p) ((p)->byte_start)
+@d length(p) ((int)(strlen(name_begin(p))))
+@d name_end(p) (name_begin(p)+length(p))
+@d complete_name(p) ((p)->byte_start[-1]=='\0')
+@d print_mod(p)
+ printf(": <%s%s>",name_begin(p), complete_name(p) ? "" : "..." )
+
+@ Three levels of error severity are distinguished: informative, serious and
+fatal. An overflow stop occurs if \.{CWEB}'s tables aren't large enough.
+Sometimes the program will detect a violation of one of its supposed
+invariants (at least this could happen if the program still contains some
+errors), and \.{CWEB} then prints an error message that is really for the
+\.{CWEB} maintenance person, not the user. In such cases the program says
+|confusion("indication of where we are")|.
+
+@d spotless 0 /* |history| value for normal jobs */
+@d harmless_message 1 /* |history| value when non-serious info was printed */
+@d error_message 2 /* |history| value when an error was noted */
+@d fatal_message 3 /* |history| value when we had to stop prematurely */
+@d mark_harmless()
+ @+ if (history==spotless) history=harmless_message; @+ else @;
+@d mark_error() (history=error_message)
+@d overflow(t) fatal("\n! Sorry, %s capacity exceeded",t)
+ @.Sorry,... capacity exceeded@>
+@d confusion(s) fatal("\n! This can't happen: %s",s) @.This can't happen@>
+
+@ Command line flag settings are stored in an array |flags|. For some of
+them we use symbolic names.
+
+@d show_banner flags['b'] /* should the banner line be printed? */
+@d show_happiness flags['h'] /* should lack of errors be announced? */
+@d show_progress flags['p'] /* should progress reports be printed? */
+@d show_stats flags['s'] /* should statistics be printed at end of run? */
+@d C_plus_plus flags['+'] /* is the language `\Cpp' rather than `\Cee'? */
+@d compatibility_mode flags['c'] /* emulate \LKC.? */
+
+@ Here are some macros for terminal output. The macro |update_terminal| is
+invoked when we want to make sure that everything we have output to the
+terminal so far has actually left the computer's internal buffers and been
+sent. Note that the cast on the |leng| parameter of |term_write| is
+necessary because a pointer difference need not be of type |int|.
+
+@d update_terminal() fflush(stdout) /* empty the terminal output buffer */
+@d new_line() putchar('\n')
+@d term_write(string,leng) printf("%.*s",(int)(leng),string) /* write on the standard output */
diff --git a/web/c_cpp/cwebx/common.w b/web/c_cpp/cwebx/common.w
new file mode 100644
index 0000000000..9d5176f559
--- /dev/null
+++ b/web/c_cpp/cwebx/common.w
@@ -0,0 +1,1757 @@
+% This file is part of CWEBx.
+% This program by Marc van Leeuwen based on earlier versions by
+% D. E. Knuth., Silvio Levy and Frank Jensen.
+% It is distributed WITHOUT ANY WARRANTY, express or implied.
+% CWEB (Revision: 2.0) % Don Knuth, July 1990
+% Version 3.x, Marc van Leeuwen, December 1993
+% CWEBx 2+1.0, Marc van Leeuwen, August 1994
+% CWEBx 3.0, Marc van Leeuwen, Januari 1995
+% CWEBx 3.02, Marc van Leeuwen, April 1996
+
+% Copyright (C) 1987,1990 Silvio Levy and Donald E. Knuth
+% Copyright 1994 Marc A. A. van Leeuwen
+
+% Permission is granted to make and distribute verbatim copies of this
+% document provided that the copyright notice and this permission notice
+% are preserved on all copies.
+
+% Permission is granted to copy and distribute modified versions of this
+% document 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.
+
+\def\pb{$\.|\ldots\.|$} % C brackets (|...|)
+\def\LKC.{Levy/Knuth \.{CWEB}}
+\def\:#1{`\.{@@#1}'}
+
+\def\title{Common code for CTANGLE and CWEAVE (Version x3.0)}
+\def\topofcontents
+{\topglue 0pt plus .5 fill
+ \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and
+ {\ttitlefont CWEAVE}}
+ \vskip 15pt
+ \centerline{(\.{CWEB} version x3.0)}
+}
+\def\botofcontents
+{\vfill\noindent
+ Copyright \copyright\ 1987,\thinspace1990 Silvio Levy and Donald E. Knuth
+ \par\noindent
+ Copyright 1994 Marc A. A. van Leeuwen
+ \bigskip\noindent
+ Permission is granted to make and distribute verbatim copies of this
+ document provided that the copyright notice and this permission notice
+ are preserved on all copies.
+
+ \smallskip\noindent
+ Permission is granted to copy and distribute modified versions of this
+ document 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.
+}
+
+@* Introduction. This file contains code common to both \.{CTANGLE}
+and \.{CWEAVE}, that roughly concerns the following problems: input
+routines, name table handling, error handling and handling of the command
+line.
+
+@h <stdarg.h>
+
+@i common.inc
+
+
+@* Generalities.
+That completes the contents of \.{common.inc}.
+In the texts below we will sometimes use \.{CWEB} to refer to either
+of the two component programs, if no confusion can arise.
+
+Here is the overall appearance of this file, except for the function
+definitions for (local and public) functions, which will follow in the
+remaining unnamed sections.
+
+@c
+@< Function prototypes used but not defined in the shared code @>@;
+@< Definitions of variables common to \.{CTANGLE} and \.{CWEAVE} @>@;
+@< Prototypes of local functions @>@;
+
+@ For all functions and variables defined here that are accessible to
+\.{CTANGLE} and \.{CWEAVE}, prototype respectively |extern| declarations are
+placed on the file \.{common.h} that is included by all three source files.
+Typedef declarations that are publicly visible also appear in this file.
+
+@( common.h @>=
+@< Public typedef declarations @>@;
+@< Declarations of public variables and function prototypes @>@;
+
+@ Since a number of large arrays are used to store various kinds of data, we
+wish to have some control over the number of bytes occupied by the basic
+items. In such cases we use one of the following types rather than |int|.
+
+@< Public typedef declarations @>=
+typedef char boolean;
+typedef unsigned char eight_bits;
+typedef unsigned short sixteen_bits;
+
+@ In certain cases \.{CTANGLE} and \.{CWEAVE} should do almost, but not
+quite, the same thing. In these cases we've written common code for both,
+differentiating between the two by means of the global variable |program|.
+Furthermore, |CTANGLE| operates in two phases (input and output), and
+similarly |CWEAVE| operates in three phases (cross-reference collection,
+translation of the source, and output of the index); the global variable
+|phase| tells which phase we are in.
+
+@< Declarations... @>=
+extern int program, phase;
+
+@~@< Definitions... @>=
+int program, phase;
+
+@ There's an initialisation function that gets both \.{CTANGLE} and
+\.{CWEAVE} off to a good start.
+
+@< Declarations...@>=
+void common_init (int argc,char** argv);
+
+@~We will fill in the details of this function later.
+@c
+void common_init (int argc,char** argv)
+{ @< Initialise variables @>
+ @< Set the default options common to \.{CTANGLE} and \.{CWEAVE} @>
+ scan_args(argc,argv);
+}
+
+
+@* Input routines.
+The lowest level of input to the \.{CWEB} programs is performed by
+|input_ln|, which must be told which file to read from. The return value
+of |input_ln| is |true| if the read is successful and |false| if not
+(i.e., if file has ended). The conventions of \TeX\ are followed; i.e.,
+the characters of the next line of the file are copied into the |buffer|
+array, and the global variable |limit| will point to the first unoccupied
+position; trailing white space is ignored.
+
+@< Declarations... @>=
+extern char buffer[], *loc, *limit;
+
+@~The value of |limit| must be less than or equal to |buffer_end|, so that
+|*buffer_end| is never filled by |input_ln|. The characters |*limit| and
+|limit[1]| are reserved for placing a sentinel at the end of the line. For
+the convenience of |CWEAVE|, the buffer is extended by |longest_name|
+characters, so that there is enough space to place any module name after
+the input.
+
+@d buffer_end (&buffer[buf_size-2]) /* practical end of |buffer| */
+
+@< Definitions... @>=
+char buffer[long_buf_size]; /* where each line of input goes */
+char *loc=buffer;
+ /* points to the next character to be read from the buffer */
+char *limit=buffer; /* points to the end of the input line */
+
+@ If a non-empty line follows the last newline in a file, we return it with
+a success status when |EOF| is read; in this case the next call will read
+|EOF| once again, and that time return failure. We are careful in case
+|isspace| is a macro using its argument more than once. As a service to the
+include and change file handling functions, |get_line| replaces any initial
+\:I, \:X, \:Y, or \:Z by its lower-case counterpart. The value of |loc| is
+usually irrelevant during the lower level input functions, and will later be
+set properly by |get_line|; however, when error messages are given, the
+value of |loc| will determine the way that the current line of input is
+displayed, so we give it an appropriate value in those cases.
+
+@c
+local boolean input_ln (FILE *f)
+ /* copies a line into |buffer| or returns |false| */
+{ register int c; /* the character read */
+ register char* k=limit=buffer; /* where next character goes */
+ while ((c=getc(f))!='\n' && c!=EOF)
+ if (k<=buffer_end) {@; *k++=c; @+ if (!isspace(c)) limit=k; }
+ if (k>buffer_end)
+ { loc=&buffer[0]; /* now |err_print| will display unbroken input line */
+ err_print ("! Input line too long"); @.Input line too long@>
+ if (limit>buffer_end) limit=buffer_end; /* truncate line */
+ }
+ if (buffer[0]=='@@' && limit>&buffer[1] && strchr("IXYZ",buffer[1])!=NULL)
+ buffer[1]=tolower(buffer[1]);
+ return c!=EOF || limit>buffer; /* whether anything new has been found */
+}
+
+@ Now comes the problem of deciding which file to read from next. Recall
+that the actual text that \.{CWEB} should process comes from two streams: a
+|web_file|, which can contain possibly nested include commands \:i,
+and a |change_file|.
+For each file we store its name and line number for error reporting and for
+the production of \&{\#line} directives by |CTANGLE|. Information for the
+|web_file| together with the currently open include files is kept on a stack
+|file| with stack pointer |include_depth|, while the change file has its own
+record. The boolean |changing| tells whether or not we're reading from the
+|change_file|. Whenever we switch from the |cur_file| to the |change_file|
+or vice versa, or if the |cur_file| has changed, we tell |CTANGLE| to print
+this information by means of a \&{\#line} directive in the \Cee\ file, by
+raising the |print_where| flag. This flag is handled like an interrupt
+request, i.e., it remains raised until it is serviced at an appropriate time
+(when a complete token has been scanned), whereupon it is cleared by the
+service routine. In Phase~I of \.{CWEAVE} header files following \:h
+are swiftly scanned for typedef declarations, which creates one or more
+extra levels of input, for which we use the same stack as for~\:i.
+Certain functions operate differently at such times, so we must be able
+to distinguish these inclusions; this is achieved by maintaining a boolean
+variable |including_header_file|.
+
+@< Declarations...@>=
+#define max_file_name_length 60
+extern struct f
+{ FILE *file; char name[max_file_name_length]; sixteen_bits line; }
+file[], change;
+extern int include_depth;
+extern boolean input_has_ended, changing, web_file_open, print_where
+ , including_header_file;
+@)
+boolean push_input_file(boolean,boolean); /* start a new level of input */
+boolean get_line (void); /* get the next line of merged input */
+
+#define cur_file file[include_depth].file /* current file */
+#define cur_file_name file[include_depth].name /* current file name */
+#define cur_line file[include_depth].line
+ /* number of current line in current file */
+#define web_file file[0].file
+#define change_file change.file
+#define change_line change.line
+
+@~We also keep an array |at_h_path| of alternative search paths for locating
+\:h files, and a path |at_i_path| for locating \:i files.
+
+@d max_include_depth 10
+ /* maximum nesting depth of source files, not counting the change file */
+@d max_include_paths 8
+ /* maximum number of additional search paths for \:h files */
+@d max_path_length 80 /* maximal length of a search path */
+
+@<Definitions...@>=
+struct f file[max_include_depth]; /* stack of non-change files */
+struct f change; /* change file */
+local char web_file_name[max_file_name_length]
+ , change_file_name[max_file_name_length]
+ , alt_web_file_name[max_file_name_length];
+int include_depth; /* current level of nesting */
+boolean input_has_ended; /* whether there is no more input */
+boolean changing; /* whether the current line is from |change_file| */
+boolean web_file_open=false; /* whether the web file is being read */
+boolean print_where=false; /* should |CTANGLE| print line and file info? */
+local struct { char* name; int length; }
+ at_h_path[max_include_paths],at_i_path;
+ /* alternative search paths for \:h and \:i */
+boolean including_header_file=false; /* are we processing \:h? */
+
+@ Before we consider merging the main input with the change file, we first
+handle pushing and popping files in the main stream. The function
+|push_input_file| opens a new level of input, e.g., when a \:i line is
+found. It is used both from within the common code, namely to open files
+included by~\:i, and by a direct call from |CWEAVE|, to open files included
+by~\:h (and nested include files) during its first phase. When it is
+called, the file name is supposed to start at the first non-blank character
+from |loc|; it is delimited by either blank space, double quotes or angle
+brackets. Once the file name is located and the file is opened, any further
+input from the current line will be discarded. This function has two boolean
+parameters, the first telling whether the file to be included is a header
+file (rather than a \:i file), the second telling whether changes should be
+suspended during the file inclusion; the boolean result tells whether a
+file was actually opened.
+
+@c
+boolean push_input_file(boolean header,boolean suspend)
+{ boolean success=false; /* whether a file as been opened */
+ char delim=' '; /* the character being used to delimit the file name */
+ while (loc<limit && (isspace((eight_bits)*loc))) ++loc;
+ if (*loc=='"') delim=*loc++; /* file name in quotes */
+ else if (*loc=='<') delim='>',++loc; /* file name in angle brackets */
+ if (loc>=limit) err_print("! Include file name not given");
+ @.Include file name not given@>
+ else if (++include_depth>=max_include_depth)
+ @/{@; --include_depth;
+ err_print("! Too many nested includes"); @.Too many nested includes@>
+ }
+ else
+ { @< Read file name into |cur_file_name| @>
+ if (delim!='>' && (cur_file=fopen(cur_file_name,"r"))!=NULL)
+ success=true;
+ else @< Try to open file in alternative directory, and set |success| @>
+ if (success)
+ {@; cur_line=0; print_where=true;
+ @< If necessary deactivate the change file @>
+ }
+ else
+ { --include_depth;
+ if (delim!='>') /* don't complain about system header files */
+ err_print("! Cannot open include file");
+ @.Cannot open include file@>
+ }
+ }
+ loc=&limit[1]; /* force |input_ln| before next character is read */
+ return success;
+}
+
+@ When the include file name is delimited by spaces, any white-space
+character will end the name; in any case we accept the end of the line as
+end of the file name.
+
+@< Read file name into |cur_file_name| @>=
+{ char* k=cur_file_name;
+ while (loc<limit
+ &&(delim==' ' ? !isspace((eight_bits)*loc) : *loc!=delim))
+ if (k==&cur_file_name[max_file_name_length-1])
+ @/{@; err_print("! Include file name truncated"); break; }
+ @.Include file name truncated@>
+ else *k++=*loc++;
+ *k='\0';
+}
+
+@ At initialisation time, paths may have been stored in |at_i_path| and
+|at_h_path|, that will be prefixed to given file name in an attempt to find
+include files. For a file opened in this manner |cur_file_name| will not
+contain the full path name but just the final component; this affects error
+messages and \&{\#line} directives produced while reading the file. The only
+problem that this might cause is that a debugger could be unable to locate
+a source file for code included from a \:i file; however, it is not likely
+that such a file outside the current directory will contain any code
+producing material, and good debuggers have their own means to specify a
+search path for source files.
+
+@< Try to open file in alternative directory... @>=
+{ char name_buf[max_path_length+max_file_name_length]; int i;
+ if (header)
+ for (i=0; i<max_include_paths; ++i)
+ if (at_h_path[i].name==NULL) break;
+ else
+ { strcpy(name_buf,at_h_path[i].name);
+ strcpy(&name_buf[at_h_path[i].length],cur_file_name);
+ if ((cur_file=fopen(name_buf,"r"))!=NULL) {@; success=true; break; }
+ }
+ else if (at_i_path.name!=NULL) /* \:i include file */
+ { strcpy(name_buf,at_i_path.name);
+ strcpy(&name_buf[at_i_path.length],cur_file_name);
+ success= (cur_file=fopen(name_buf,"r"))!=NULL;
+ }
+}
+
+@ We allow values for |at_h_path[0]| and |at_i_path| to be built into the
+program by defining the preprocessor symbols |CWEBHEADERS| respectively
+|CWEBINPUTS| to be the appropriate strings; these should be complete
+prefixes that can be attached to file names, so they probably have to end
+with a pathname separator. For |CWEBHEADERS| one could take the system
+include file area, although this should usually not be necessary since the
+typedefs contained in system header files are already built into |CWEAVE|.
+Defining |CWEBINPUTS| only makes sense if \.{CWEB} is compiled specifically
+for one particular project, as long as there are no general purpose
+\:i~files. Following \LKC. we also allow |CWEBINPUTS|
+to be overridden by an environment variable. For specifying further values of
+|at_h_path| we use the more practical method of command line arguments (just
+like most \Cee~compilers use for specifying alternative include
+directories), which are handled by |scan_args|.
+
+@< Init... @>=
+{ char* cwebinputs=getenv("CWEBINPUTS");
+ at_h_path[0].name=at_i_path.name=NULL; /* defaults */
+#ifdef CWEBHEADERS
+ at_h_path[0].name=CWEBHEADERS;
+ at_h_path[0].length=(int)strlen(CWEBHEADERS);
+#endif
+ if (cwebinputs!=NULL)
+ { at_i_path.length=(int)strlen(cwebinputs);
+ at_i_path.name=strcpy(byte_ptr,cwebinputs);
+ byte_ptr+=at_i_path.length+1;
+ }
+ else
+ {
+#ifdef CWEBINPUTS
+ at_i_path.name=CWEBINPUTS; at_i_path.length=(int)strlen(CWEBINPUTS);
+#endif
+ }
+}
+
+@ In some cases we wish to suspend changes during the inclusion of a file,
+and any nested inclusions. This happens when during the first pass of
+\.{CWEAVE} a header file specified after \:h is being read in, or when
+in compatibility mode a \:i inclusion is issued under control of the
+change file. In such cases we suspend the change file by setting
+|changing=false| and |change_limit=change_buffer| as if the change file had
+ended, after having saved the old values of |changing| and |change_limit|.
+The change file will be reactivated when the included file ends, which
+requires saving |include_depth| as well.
+
+@<Definitions...@>=
+local boolean saved_changing; /* were we changing before it was suspended? */
+local char* saved_change_limit; /* end of suspended change line */
+local int saved_include_depth=0; /* depth after opening \:h file */
+
+@~Although this could be easily changed, the current code relies on the fact
+that suspension cannot be nested (as would be the case if \:h were
+activated in a file included under control of the change file), since
+compatibility mode does not support \:h file inclusion.
+
+@< If necessary deactivate the change file @>=
+if (suspend)
+{ saved_changing=changing; changing=false;
+@/saved_change_limit=change_limit; change_limit=change_buffer;
+@/saved_include_depth=include_depth;
+}
+
+@ The function |get_web_line| fetches the next line from the main input
+stream, taking care of the interpretation on \:i and of restoring input to
+the parent file when an include file has ended. Like |input_ln| it returns a
+boolean value telling whether a line could be found. When this is not the
+case, it means that either the main input stream has dried up, or we have
+come to the end of a header file included by an \:h code issued from the
+change file, in which case |changing==true| afterwards, and we should not
+read from the main input stream after all.
+
+In compatibility mode |get_web_line| operates differently, since in
+\LKC. include files are expanded after matching against the change file
+rather than before, although an expanded include file will be reconsidered
+for matching against (the same line of) the change file, unless it was
+included under control of the change file itself. This means that in
+compatibility mode no include file should be opened while preparing the
+main input stream for a match. On the other hand, if an include file ends,
+there is no other sensible action but to close the file and read on at the
+previous level.
+
+@c
+local boolean get_web_line(void)
+{ do
+ if (++cur_line,input_ln(cur_file)) /* then a line has been found */
+ if (!compatibility_mode
+ && limit>&buffer[1] && buffer[0]=='@@' && buffer[1]=='i')
+ @/{@;loc=&buffer[2]; print_where=true; push_input_file(false,false); }
+ /* expand \:i */
+ else return true; /* return the line without further action */
+ else if (include_depth==0) /* then end of input has been reached */
+ @/{@; input_has_ended=true; web_file_open=false; return false; }
+ else
+ { fclose(cur_file); print_where=true;
+ if (include_depth--==saved_include_depth) /* then restore |changing| */
+ { changing=saved_changing; change_limit=saved_change_limit;
+ saved_include_depth=0; including_header_file=false;
+ if (changing) return false; /* fall back into change file */
+ }
+ }
+ while (true);
+}
+
+@ Now we come to merging the main input stream with the change file.
+When |changing| is false, the first non-empty line of |change_file| after
+the next \:x to be matched is kept in |change_buffer|, for purposes of
+comparison with the next line of |cur_file|. The test |lines_match| is
+used for equality between the two lines; it will never return |true| when
+|change_limit==change_buffer| because it will not be invoked when
+|limit==buffer|.
+
+@d lines_match()
+ (change_limit-change_buffer==limit-buffer
+ && strncmp(buffer, change_buffer, limit-buffer)==0)
+
+@<Definitions...@>=
+local char change_buffer[buf_size]; /* next line of |change_file| */
+local char *change_limit; /* points to the effective end of |change_buffer| */
+
+@ The function |prime_the_change_buffer| sets |change_buffer| in preparation
+for the next matching operation. After the change file has been completely
+input, we set |change_limit=change_buffer|, so that no further matches will
+be made; since blank lines in the change file are not used for matching, we
+have |(change_limit==change_buffer && !changing)| if and only if the change
+file is exhausted (or suspended). This function is called only when
+|changing| is true; hence error messages will be reported correctly.
+
+@c
+local void prime_the_change_buffer (void)
+{ change_limit=change_buffer;
+ /* this value is used if the change file ends */
+ @<Skip over comment lines in the change file; |return| if end of file@>
+ @<Skip to the next non-blank line; |return| if end of file@>
+ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>
+}
+
+@ While looking for a line that begins with \:x in the change file, we allow
+lines that begin with `\.{@@}', as long as they don't begin with \:y or \:z
+(which would probably indicate that the change file is fouled up).
+
+@<Skip over comment lines in the change file...@>=
+do
+{ if (++change_line,!input_ln(change_file)) return;
+ if (limit>&buffer[1] && buffer[0]=='@@')
+ if (buffer[1]=='x') break;
+ else if (buffer[1]=='y' || buffer[1]=='z')
+ { loc=&buffer[2]; /* point out error after \:y or \:z */
+ err_print ("! Where is the matching @@x?"); @.Where is the match...@>
+ }
+ else @< Check for erroneous \:i @>
+} while (true);
+
+@ When not in compatibility mode, \:i lines are expanded by |get_web_line|,
+so it makes no sense to place such a code between \:x and~\:y or between \:y
+and~\:z; to allow them outside of the changes they would only cause
+confusion by suggesting the inclusion of a subsidiary change file. Therefore
+we normally do not allow \:i at the beginning of any line of the change file;
+in compatibility mode however, \:i can be used in both sides of a change,
+and outside of the changes the code is allowed but ignored.
+
+@< Check for erron... @>=
+{ if (buffer[1]=='i' && !compatibility_mode)
+ @/{@; loc=&buffer[2]; err_print ("! No includes allowed in change file"); }
+} @.No includes allowed...@>
+
+@ After a \:x has been found, we ignore the rest of the line, as well
+as any blank lines that follow it; since |input_ln| removes trailing blanks,
+we can simply test for empty lines.
+
+@< Skip to the next non-blank line... @>=
+do
+ if (++change_line,!input_ln(change_file))
+ @/{@; loc=&buffer[0]; err_print("! Change file ended after @@x"); return; }
+while (limit==buffer); @.Change file ended...@>
+
+@ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>=
+{@; int n=(int)(limit-buffer); change_limit=change_buffer+n;
+ strncpy(change_buffer,buffer,n);
+}
+
+@ The function |check_change| is used to see if the next change entry should
+go into effect; it is called only when |changing| is false. The idea is to
+test whether or not the current contents of |buffer| matches the current
+contents of |change_buffer|. If not, there's nothing more to do, but if so,
+a change is called for. When this happens, all of the text down to the \:y
+is supposed to match, and an error message is issued if any discrepancy is
+found; after finding \:y we have |changing==true|, so that subsequent lines
+will be read from the change file. Since |check_change| is called only when
+|change_limit>change_buffer|, i.e., when the change file is active, we don't
+have to consider the case here that |get_web_line| returns |false| after
+reactivating the suspended change file.
+
+@c
+local void check_change (void)
+ /* switches to |change_file| if the buffers match */
+{ int n=0; /* the number of discrepancies found */
+ if (!lines_match()) return;
+ print_where=true; /* indicate interrupted line sequencing */
+ do
+ { changing=true;
+ @< Read a line from the change file into the change buffer;
+ if \:y is found, |break|; if the change file ends, |return| @>
+ changing=false;
+ if (!get_web_line())
+ @/{@; loc=&buffer[0];
+ err_print("! CWEB file ended during a change"); return;
+ @.CWEB file ended...@>
+ }
+ if (!lines_match()) ++n;
+ } while (true);
+ if (n>0)
+ { loc=&buffer[2];
+ print("\n! Hmm... %d of the preceding lines failed to match",n);
+ @.Hmm... $n$ of the preceding...@>
+ err_print("");
+ }
+}
+
+@ Since we read a line from the change file before reading the line from the
+main input stream that should match it, we can use |input_ln| to read the
+line into |buffer| first, and move it to |change_buffer| afterwards.
+When expecting \:y, we signal and ignore any \:x or \:z.
+
+@< Read a line from the change file into the change buffer... @>=
+{ if (++change_line,!input_ln(change_file))
+ { loc=&buffer[0]; err_print("! Change file ended before @@y");
+ @.Change file ended...@>
+ change_limit=change_buffer; changing=false; return;
+ }
+ if (limit>&buffer[1] && buffer[0]=='@@')
+ if (buffer[1]=='y') break;
+ else if (buffer[1]=='x' || buffer[1]=='z')
+ @/{@; loc=&buffer[2]; err_print("! Where is the matching @@y?"); }
+ @.Where is the match...@>
+ else @< Check for erron... @>
+ @< Move |buffer| and |limit|... @>
+}
+
+@ The function |reset_input|, which gets \.{CWEB} ready to read the \.{CWEB}
+source file(s), is used at the beginning of Phase~I of |CTANGLE|, and
+of Phases I~and~II of |CWEAVE|.
+
+@< Declarations... @>=
+void reset_input (void);
+
+@~Although |reset_input| will not read anything from |web_file| after
+opening it, it will move up to the first change line in |change_file|.
+
+@c
+void reset_input (void) /* initialise to read the web file and change file */
+{ boolean use_change_file= change_file_name[0]!='\0';
+ @<Open input files@>
+ cur_line=0; change_line=0; include_depth=0;
+ if (use_change_file) {@; changing=true; prime_the_change_buffer(); }
+ /* prepare change file */
+ else change_limit=change_buffer;
+ /* emulate that change file that has ended */
+ limit=buffer; loc=&buffer[1]; /* now |find_char()| will read a line */
+ changing=false; input_has_ended=false;
+}
+
+@ The following code opens the input files. We complain about a missing
+change file only if it was explicitly mentioned as a command line argument.
+
+@<Open input files@>=
+{ if ((web_file=fopen(web_file_name,"r"))!=NULL)
+ strcpy(file[0].name,web_file_name);
+ else if ((web_file=fopen(alt_web_file_name,"r"))!=NULL)
+ strcpy(file[0].name,alt_web_file_name);
+ else fatal("! Cannot open \"%s\" as input file", web_file_name);
+ @.Cannot open input file@>
+ web_file_open=true;
+ if (use_change_file)
+ if ((change_file=fopen(change_file_name,"r"))!=NULL)
+ strcpy(change.name,change_file_name);
+ else if (!change_file_explicit)
+ use_change_file=false; /* forget about the change file */
+ else fatal("! Cannot open \"%s\" as change file", change_file_name);
+ @.Cannot open change file@>
+}
+
+@ Here are some more variables relevant to the reading of input files.
+Every time an input line is read coming from the change file, and on
+returning to reading from |cur_file| (possibly after one or more lines of
+the main input stream have been removed by the change file), we mark the
+current section as having changed by setting a bit in the bitmap
+|changed_section|.
+
+@< Declarations... @>=
+extern sixteen_bits section_count;
+extern eight_bits changed_section[];
+#define mark_section_as_changed(n) (changed_section[(n)>>3]|=1<<((n)&7))
+#define section_changed(n) ((changed_section[(n)>>3]&(1<<((n)&7)))!=0)
+
+@~
+@<Defin...@>=
+sixteen_bits section_count; /* the current section number */
+eight_bits changed_section[(max_sections+7)/8]; /* is the section changed? */
+
+@ The function |get_line| puts the next line of merged input into the
+buffer and updates the variables appropriately. A space is placed at the
+right end of the line (i.e., at |*limit|), serving many purposes, like
+ensuring that a final `\.@@' on a line will be interpreted as \:\ ,
+and at other times allowing us to test for interesting characters without
+first testing for line end. The function returns |!input_has_ended| because
+we often want to check the value of that variable after calling the
+function. Usually |get_line| is called after the space at |*limit| has been
+processed; therefore a call often takes the form of the macro |find_char|,
+which calls |get_line| if necessary, and returns whether it has succeeded
+in making |loc| point to a valid character (possibly a line-ending space).
+
+The logic of marking sections as changed, which is implemented below, is a
+bit subtle. The status of |changing| is noted for every line read, but since
+the test is made at the start of |get_line|, it actually happens just before
+the next line is read in. This means that if the first replacement line of a
+change involves the start of a new section, then the new section is marked
+as changed rather than the one before it, which is the right choice,
+assuming that sections are started at the beginning of a line. It is
+possible that |changing| is switched on and then right back off again (if
+the line after \:y starts with \:z); in that case we mark the
+current section as changed and restart |get_line|, since we still have found
+no actual line.
+
+@c
+boolean get_line (void) /* inputs the next line */
+{
+restart:
+ if (changing) mark_section_as_changed(section_count);
+ else @<Read from |cur_file| and maybe turn on |changing|@>
+ if (changing)
+ { @<Read from |change_file| and maybe turn off |changing|@>
+ if (!changing)
+ {@; mark_section_as_changed(section_count); goto restart; }
+ }
+ loc=&buffer[0]; *limit= ' '; /* place sentinel space */
+ if (compatibility_mode && buffer[0]=='@@' && buffer[1]=='i')
+ @/{@; loc+=2; print_where=true; push_input_file(false,changing);
+ goto restart;
+ }
+ if (limit-buffer>5
+ && strncmp(buffer,"#line",5)==0 && isspace((eight_bits)buffer[5]))
+ @< Set file name and line number according to \&{\#line}
+ directive and |goto restart| @>
+ return !input_has_ended;
+}
+
+@ A \&{\#line} directive should have the form `\.{\#line 85 "common.w"}'.
+The line number and file name simply override |cur_line| and |cur_file_name|.
+
+@< Set file name and line number... @>=
+{ sixteen_bits line=0;
+ print_where=true; /* output a \&{\#line} directive soon */
+ loc=&buffer[6]; @+ while (loc<limit && isspace((eight_bits)*loc)) ++loc;
+ if (isdigit((eight_bits)*loc))
+ { do line=10*line + *loc++ -'0'; while (isdigit((eight_bits)*loc));
+ while (loc<limit && isspace((eight_bits)*loc)) ++loc;
+ if (*loc++=='"')
+ { int i=0; @+ while (&loc[i]<limit && loc[i]!='"') ++i;
+ if (loc[i]=='"' && i<max_file_name_length)
+ { struct f* cur_f= changing ? &change : &file[include_depth];
+ cur_f->line=line-1; /* directive applies to next line, not this one */
+ strncpy(cur_f->name,loc,i); cur_f->name[i]='\0';
+ goto restart;
+ }
+ }
+ }
+ err_print("! Improper #line directive"); goto restart;
+ @.Improper \#line directive@>
+}
+
+@ After checking that a line could be obtained from the main input stream,
+some quick tests are made that will avoid calling |check_change| in most
+cases. The switch to |changing| mentioned in the module name is
+usually brought about by |check_change|, but may also happen when the
+suspension of the change file during inclusion of a header file is ended by
+|get_web_line|. In either case further input lines should be taken from
+the change file.
+
+@< Read from |cur_file|... @>=
+{ if (get_web_line()
+ && change_limit>change_buffer
+ && limit-buffer==change_limit-change_buffer
+ && buffer[0]==change_buffer[0]
+ ) check_change();
+}
+
+@ Here we get a line of input from the change file, unless it starts
+with~\:z. The statements `|loc=buffer; *limit=' ';|' were performed in
+|get_web_line| for lines from the main input stream, but must be issued
+explicitly for lines from the change file.
+
+@< Read from |change_file|... @>=
+{ if (++change_line,!input_ln (change_file))
+ { err_print("! Change file ended without @@z"); @.Change file ended...@>
+ @/buffer[0]='@@'; buffer[1]='z'; limit=&buffer[2];
+ }
+ if (limit>&buffer[1] && buffer[0]=='@@') /* check if the change has ended */
+ if (buffer[1]=='z')
+ @/{@; prime_the_change_buffer(); changing=false; print_where=true; }
+ else if (buffer[1]=='x' || buffer[1]=='y')
+ @/{@; loc=&buffer[2]; err_print("! Where is the matching @@z?"); }
+ @.Where is the match...@>
+ else @< Check for erron... @>
+}
+
+@ The function |check_complete| will be called at the end of \.{CTANGLE}
+and \.{CWEAVE} to check for an unfinished state of the change file.
+
+@< Declarations...@>=
+extern void check_complete (void);
+
+@~When |check_complete| is called we have |input_has_ended|, which implies
+|!changing|. The only thing to test for is that there is no change line still
+waiting for a match. In order to get a decent display of the non-matching
+line, we copy it from the |change_buffer| to the |buffer|, and set some other
+variable appropriately. There is no need to restore any variables, since
+|check_complete| is called at the very end of the run.
+
+@c
+void check_complete (void) /* checks that all changes were picked up */
+{ if (change_limit!=change_buffer)
+ { int l=(int)(change_limit-change_buffer);
+ strncpy(buffer,change_buffer,l); limit=&buffer[l];
+ changing=true; loc=buffer; web_file_open=true;
+ /* prepare unmatched line for display */
+ err_print("! Change file entry did not match");
+ @.Change file entry did not match@>
+ }
+}
+
+
+@* Storage of names and strings.
+Both \.{CTANGLE} and \.{CWEAVE} store the strings representing identifiers,
+module names and (in case of \.{CWEAVE}) index entries in a large array of
+characters, called |byte_mem|. These strings are not accessed directly,
+but via structures that collect further information about these objects.
+These structures come in two kinds, depending on whether they correspond
+to identifiers (or index entries) or to module names; these structures are
+called |id_info| and |mod_info| respectively.
+
+@< Public typedef...@>=
+
+typedef struct id_info
+{ char *byte_start; /* beginning of the name in |byte_mem| */
+ @<More fields of |struct id_info|@>@;
+} id_info, *id_pointer;
+@)
+typedef struct mod_info
+{ char *byte_start; /* beginning of the name in |byte_mem| */
+ @<More fields of |struct mod_info|@>@;
+} mod_info, *mod_pointer;
+
+@ All |id_info| and |mod_info| structures are stored in one of two arrays,
+called |id_table| and |mod_table| respectively, and hence all |id_pointer|
+and |mod_pointer| values point into these arrays. Therefore we can freely
+convert between such a pointer and an index into the appropriate array;
+the macros |id_index|, |id_at|, |mod_index| and |mod_at| defined above
+perform these conversions.
+
+@< Declarations... @>=
+extern char byte_mem[], *byte_ptr;
+extern id_info id_table[], *id_ptr;
+extern mod_info mod_table[], *mod_ptr;
+
+@~The first unused position in |byte_mem| is kept in |byte_ptr|, and the
+first unused positions in |id_table| and |mod_table| are similarly kept in
+|id_ptr| and |mod_ptr|, respectively. We want to keep
+|byte_ptr<=byte_mem_end|, |id_ptr<=id_table_end| and
+|mod_ptr<=mod_table_end|.
+
+@d byte_mem_end (&byte_mem[max_bytes]) /* end of |byte_mem| */
+@d id_table_end (&id_table[max_idents]) /* end of |id_table| */
+@d mod_table_end (&mod_table[max_modules]) /* end of |mod_table| */
+
+@<Definitions...@>=
+char byte_mem[max_bytes]; /* characters of names */
+char *byte_ptr=&byte_mem[0]; /* first unused position in |byte_mem| */
+id_info id_table[max_idents]; /* information about identifiers */
+id_pointer id_ptr=&id_table[0]; /* first unused position in |id_table| */
+mod_info mod_table[max_modules]; /* information about module names */
+mod_pointer mod_ptr=&mod_table[0]; /* first unused position in |mod_table| */
+
+@ Here is a simple function that copies a (not necessarily null-terminated)
+string~|s| of length~|l| into |byte_mem| and returns a pointer to the copied
+string.
+
+@c
+char* store_string(char* s, int l)
+{ char* dest=byte_ptr;
+ if (byte_mem_end-byte_ptr<=l) overflow ("byte memory");
+ byte_ptr+=l; *byte_ptr++='\0'; return strncpy(dest,s,l);
+}
+
+@ A component is present in both |id_info| and |mod_info| structures,
+whose function is different for \.{CTANGLE} and \.{CWEAVE}. In |CTANGLE|,
+it is used only in |mod_info| structures, and is a pointer to a replacement
+text for the module name. In |CWEAVE| it is a pointer to a list of
+cross-references for the identifier or module name. The precise nature of
+these pointers is of no interest to the common code, and at this point we do
+not have the types available to express this field as a |union|. However,
+since in both cases it will be a pointer to a structure, we can use a little
+trick by declaring it as a pointer to a |struct variant| where |variant| is
+not further specified here. Then in \.{CTANGLE} and \.{CWEAVE} we define
+|variant| as a macro for the appropriate |struct| specifier, while in the
+common code we leave it undefined (the \:d defining |variant| is given
+very early, so that it will precede the `\.{@@h "common.h"}' that will read
+in the definition of |struct id_info| and |struct mod_info|).
+
+It is not quite proper that in the common code these structures contain a
+pointer to a named but undefined structure, while in the other compilation
+unit of \.{CTANGLE} and \.{CWEAVE} respectively, they contain a pointer to
+a known structure with a {\it different\/} specifier (due to the macro
+definition); in \Cee\ structures with different specifiers can never be the
+same type. However, since the linker does not type-check, and the compiled
+code is not likely to depend on the name of a structure specifier, this
+should cause no problems, except possibly some mild confusion to a debugger.
+An alternative solution of defining a structure of the same name to denote
+entirely different types in \.{CTANGLE} and \.{CWEAVE} would be clearer to
+the computer, but more confusing to humans. Of course we could also have
+used a |(void*)| field instead of a pointer to a structure, but this would
+require a lot of explicit or implicit casts, allowing possible type errors
+to go undetected by the compiler.
+
+@< More fields of |struct id_info| @>=
+struct variant* equiv_or_xref; /* extra information about this identifier */
+@~
+@< More fields of |struct mod_info| @>=
+struct variant* equiv_or_xref; /* extra information about this module */
+
+@ The |id_info| structures are linked together into (hopefully) short lists
+sharing the same hash key by means of the |hash_link| field. In |CWEAVE|,
+an additional field is used to store information about the syntactic r\^ole
+of the identifier, its so-called |ilk|.
+
+@< More fields of |struct id_info| @>=
+struct id_info *hash_link; /* links identifiers with same hash code */
+int ilk; /* syntactic information, used in |CWEAVE| only */
+
+@ The pointers to the heads of the hash lists are stored in the
+array~|hash|. Identifiers can be found by computing a hash code~|h| and then
+looking at the identifiers represented by the |id_pointer|s |hash[h]|,
+|hash[h]->hash_link|, |hash[h]->hash_link->hash_link|,~\dots, until either
+finding the desired name or encountering the null pointer. Thus the hash
+table consists of entries of type |id_pointer|; it is maintained by the
+function |id_lookup|, which finds a given identifier and returns the
+appropriate |id_pointer|. The basic matching is done by the function
+|names_match|, which is slightly different in \.{CTANGLE} and \.{CWEAVE}. If
+there is no match for the identifier, it is inserted into the table.
+
+@< Declarations... @>=
+extern id_pointer hash[];
+#define hash_end (&hash[hash_size]) /* end of |hash| */
+id_pointer id_lookup(char*,char*,int);
+
+@~The |hash| table has size~|hash_size|.
+
+@<Definitions...@>=
+id_pointer hash[hash_size]; /* heads of hash lists */
+
+@ Initially all the hash lists are empty. Although strictly speaking the
+array |hash| should be initialised to null pointers by the compiler,
+we don't count too much on this in case such pointers are not represented
+by null bit patterns.
+
+@<Init...@>=
+{@; int i=hash_size; do hash[--i]=NULL; while(i>0); }
+
+@ Here is the main function for finding identifiers (and index entries).
+The parameters |first| and |last| point to the beginning and end of the
+string. The parameter |ilk| is used by |CWEAVE| only in the course of the
+matching process; within |id_lookup| it is just passed on to the functions
+|names_match| and~|init_id_name|, which are defined in \.{CTANGLE} and
+\.{CWEAVE} separately. We facilitate the initialisation of the reserved
+words in |CWEAVE| by allowing the use of null-terminated strings rather
+than using a pointer to the end of the string: in this case |first| should
+point to such a string, and |last==NULL|.
+
+@c
+id_pointer id_lookup (char* first,char* last,int ilk)
+ /* look up an identifier */
+{ int l,h; /* length and hash code of the given identifier */
+ if (last==NULL) last=first+(l=(int)strlen(first)); /* null-terminated string */
+ else l=(int)(last-first); /* compute the length */
+ @<Compute the hash code |h| of the string from |first| to |last| @>
+ @<Compute and |return| the name location,
+ possibly by entering a new identifier into the tables@>
+}
+
+@ A simple hash code is used: If the sequence of character codes is
+$c_1c_2\ldots c_n$, its hash value will be
+$$ (2^{n-1}c_1+2^{n-2}c_2+\cdots+c_n)\bmod\hbox{|hash_size|}. $$
+The purist might worry about the empty string, which, although of course
+impossible as identifier, might be flagged as an index entry; such an index
+entry is however explicitly ruled out in |CWEAVE|.
+
+@<Compute the hash...@>=
+{ char* p=first;
+ h=*p; while (++p<last) h=((h<<1)+*p)%hash_size;
+}
+
+@ Here we either find an existing node for the identifier, or create one,
+inserting it into the name table and the hash list. The maximal average
+length |max_idents/hash_prime| of hash lists should be sufficiently small
+that linearly searching them is quite fast.
+
+@<Compute and |return|...@>=
+{ id_pointer p=hash[h]; /* the head of the hash list */
+ while (p!=NULL && !names_match(p,first,l,ilk)) p=p->hash_link;
+ if (p==NULL) /* we haven't seen this identifier before */
+ @< Make |p| point to a fresh |id_node| that refers to a string copied from
+ |first|, and prepend the node to hash list |h| @>
+ return p;
+}
+
+@ The information associated with a new identifier must be initialised
+in |CWEAVE| in a way that does not apply to~\.{CTANGLE}; hence the
+function |init_id_name|.
+
+@< Make |p| point to a fresh |id_node|... @>=
+{ p=id_ptr; /* this is where the new name entry will be created */
+ if (id_ptr++>=id_table_end) overflow ("identifier");
+ name_begin(p)=store_string(first,l);
+ if (program==cweave) init_id_name(p,ilk);
+ p->hash_link=hash[h]; hash[h]=p; /* insert |p| at beginning of hash list */
+}
+
+@ The names of modules are stored in |byte_mem| together with the identifier
+names, but a hash table is not used for them because \.{CWEB} needs to be
+able to recognise a module name when given a prefix of that name. To this
+end the |mod_info| structures are linked into a binary search tree. The only
+unconventional thing about this search tree is that the search key is not
+necessarily equal to the full string stored but that a prefix is decisive
+for matching purposes: once that prefix matches, not matching the remainder
+of the string is considered to be an error. The reason for this is that the
+module name may have been specified first by a short prefix and is later
+extended; we need to be aware of the ambiguity when a second incompatible
+extension of the original prefix is attempted. Therefore a field
+|key_length| is included in |struct mod_info| that indicates the length of
+the prefix that should determine a unique match; its value is the length of
+the shortest partial specification of this module name that has been
+encountered so far.
+
+@< More fields of |struct mod_info| @>=
+struct mod_info *llink,*rlink;
+ /* left and right links in binary search tree */
+int key_length; /* number of characters decisive for match */
+
+@ There is one more attribute that must be recorded for a module name,
+namely whether the string accessed by the |byte_start| field is the full
+module name, or just the longest prefix specified so far (i.e., all
+occurrences so far ended with `\.{...}'). Rather than extending |struct
+mod_info| with another (boolean) field or encoding this information in one
+of the other fields we use a small trick to record this information. All
+full module names will be stored in |byte_mem|, and since that is filled
+with null-terminated strings, we will have for any |mod_pointer p@;|
+representing a complete module name that |p->byte_start[-1]=='\0'|. The
+macro |complete_name| defined above tests this condition, and we shall
+store incomplete module names in such a way that the condition fails for
+them. This method costs just one byte of temporary storage for each module
+name that is incompletely specified on its first occurrence, except that a
+one-time sacrifice of another byte is needed to guarantee that even the
+first name is preceded by a null byte.
+
+@< Initialise... @>=
+*byte_ptr++='\0'; /* prefix a null byte to the first string */
+
+@~Like most trees, the search tree for module names starts at its |root|.
+
+@< Declarations... @>=
+extern mod_pointer root;
+
+@~The search tree starts out empty.
+@< Definitions... @>=
+mod_pointer root=NULL;
+ /* the root of the binary search tree for module names */
+
+@ The set of all possible strings can be conceptually arranged in an
+infinite tree with the empty string at its root, where the direct descendents
+of a string are those strings obtained by appending a single letter to it,
+listed in alphabetical order. The position of one string relative to another
+in this tree is one of five possibilities: to the left of, to the right of,
+ancestor of, descendent of, or equal to. The type |enum mod_comparison|
+encodes these five possibilities.
+
+@< Prototypes of local functions @>=
+enum mod_comparison @/
+{ less, /* the first name is lexicographically less than,
+ but no prefix of the second */
+ equal, /* the first name is equal to the second */
+ greater, /* the first name is lexicographically greater than,
+ but no extension of the second */
+ prefix, /* the first name is a proper prefix of the second */
+ extension /* the first name is a proper extension of the second */
+};
+
+@~The function |mod_name_cmp| will determine which one of the relations
+described above holds for a given pair of strings, each represented by a
+pointer to its beginning and its length.
+
+@c
+local enum mod_comparison mod_name_cmp
+ (char* p, int l1, char* q, int l2)
+{ int l= l1<l2 ? l1 : l2;
+ while (--l>=0) if (*p++!=*q++) return *--p<*--q ? less : greater;
+ return l1<l2 ? prefix : l1>l2 ? extension : equal;
+}
+
+@ When a new module name is found and approved, we first store the string
+representing it in an appropriate place, and then call |new_mod_node| to
+install a node for the name in the |mod_table| array and prepare it for
+inclusion in the search tree. The information associated with the new node
+must be initialised in a slightly different way in |CWEAVE| than in
+|CTANGLE|; hence the call of |init_module_name|.
+
+@c
+local mod_pointer make_mod_node (char* name)
+{ mod_pointer node=mod_ptr; /* allocate new node */
+ if (mod_ptr++>=mod_table_end) overflow ("module name");
+ name_begin(node)=name;
+ node->llink=NULL; node->rlink=NULL;
+ init_module_name(node); /* initialise new node */
+ return node;
+}
+
+@ The function |mod_name_lookup| is used to look up a complete module name
+in the search tree, inserting it if necessary, and returns a pointer to
+where it was found. Its parameters give the beginning and length of the
+module name. The name might be illegal, for instance if it is a prefix of an
+existing name, in which case |NULL| is returned rather than a pointer into
+|mod_table|, after printing an error message.
+@c
+local mod_pointer mod_name_lookup (char* name, int l)
+ /* finds complete module name */
+{ mod_pointer p; /* current node of the search tree */
+ mod_pointer* loc=&root; /* |p| will come from this location */
+ while ((p=*loc)!=NULL)
+ { int l0=p->key_length; char* key=name_begin(p);
+ switch (mod_name_cmp(name,l,key,l0))
+ { case less: loc=&p->llink; break;
+ case greater: loc=&p->rlink; break;
+ case equal: case extension:
+ @< Check that |name| matches the remainder of |key|;
+ if so, complete |p| if necessary and |return p|,
+ if |name| is a prefix of~|key| fall through,
+ and otherwise report an error and |return NULL| @>
+ case prefix:
+ err_print("! Incompatible module name"); @.Incompatible module name@>
+ print("\nName is a prefix of <%s%s>.\n" @.Name is a prefix of <...>@>
+ ,key, complete_name(p) ? "" : "...");
+ return NULL; /* dummy module name */
+ }
+ }
+ @< Copy |name| into |byte_mem|, install a new node in the tree at |*loc|,
+ and |return| it @>
+}
+
+@ When the name is not found in the tree, a new module has been specified
+whose name is complete from the start, and can therefore be installed in
+|byte_mem|. Its |key_length| field is set to the length~|l| of the name as
+specified here, but it might be decreased later.
+
+@< Copy |name| into |byte_mem|... @>=
+{ (p=make_mod_node(store_string(name,l)))->key_length=l; /* prepare new node */
+ return *loc=p; /* install new node into tree */
+}
+
+@ When the module name |name| being looked up matches the string |key| in a
+node~|p| of the search tree for the first |p->key_length| characters, then
+this is guaranteed to be the only such match in the tree. It is required
+that the rest of |key| matches the remainder of~|name| as well, and if
+|complete_name(p)| holds then the match must exhaust~|name|.
+
+@< Check that |name| matches the remainder of |key|... @>=
+{ enum mod_comparison cmp=
+ mod_name_cmp(name+l0,l-l0,key+l0,(int)strlen(key+l0));
+ switch(cmp)
+ { case less: case greater:
+ err_print("! Incompatible module name"); @.Incompatible module name@>
+ print("\nName inconsistently extends <%.*s...>.\n",l0,key);
+ @.Name inconsistently extends <...>@>
+ return NULL;
+ case extension: case equal:
+ if (complete_name(p))
+ if (cmp==equal) return p;
+ else
+ { err_print("! Incompatible module name"); @.Incompatible module name@>
+ print("\nPrefix exists: <%s>.\n",key); return NULL;
+ @.Prefix exists@>
+ }
+ name_begin(p)=store_string(name,l);
+ /* install |name| in place of |key| */
+ @< Deallocate memory for |key| @>
+ return p;
+ }
+}
+
+@ The function |prefix_lookup| is similar to |mod_name_lookup|, but it is
+called when the specification of a module name ends with `\.{...}'. Here,
+unlike in |mod_name_lookup|, there is the possibility that there is more
+than one match. The function decides whether there are $0$,~$1$, or~$>1$
+matches present in the tree, but in the final case it need not find all
+matches. There is a match of |name| with node~|p| if the first
+|p->key_length| characters at |name_begin(p)| are equal, an extension or a
+prefix of~|name| (in the last case we should not have |completed(p)|). It is
+clear that if there is a match with two distinct nodes, then there is also a
+match with their closest common ancestor in the search tree, and since we do
+not allow inclusions among the significant parts of the keys in the tree,
+this situation can only occur if |name| is a proper prefix for all its
+matches. Hence, once a first match is found, any further match must be
+among its descendents in the tree.
+
+The value of |loc| is maintained as in |mod_name_lookup| to allow insertion
+of a new node if no match is found; however, once we have |match!=NULL|, the
+value of~|loc| becomes irrelevant.
+
+@c
+local mod_pointer prefix_lookup (char* name,int l)
+ /* finds module name given a prefix */
+{ mod_pointer p=root,* loc=&root; /* current node and where it comes from */
+ mod_pointer match=NULL; /* the first matching node, if any */
+ mod_pointer saved=NULL; /* another subtree that might have matches */
+ while (p!=NULL)
+ { int l0=p->key_length; char* key=name_begin(p);
+ switch (mod_name_cmp(name,l,key,l0))
+ { case less: p=*(loc=&p->llink); break;
+ case greater: p=*(loc=&p->rlink); break;
+ case equal: return p; /* a match, and no other matches are possible */
+ case extension:
+ @< Check that |name| matches the remainder of~|key|;
+ if so, extend its string if necessary and |return p|,
+ otherwise report an error and |return NULL| @>
+ case prefix:
+ if (match!=NULL)
+ {@; err_print("! Ambiguous prefix"); return NULL; }
+ @.Ambiguous prefix@>
+ match=p; saved=p->rlink; p=p->llink; /* |loc| is irrelevant now */
+ }
+ if (p==NULL && match!=NULL)
+ p=saved, saved=NULL; /* search other subtree */
+ }
+ if (match==NULL)
+ @< Copy the incomplete |name| in a temporary place, install a new node
+ in the tree at |*loc|, and |return| it @>
+ match->key_length=l; /* |name| is a shorter prefix than used before */
+ return match;
+}
+
+@ Incomplete nodes are not stored in |byte_mem|, but temporarily set aside
+in dynamic memory, which will be freed when the name is completed. A
+non-zero byte is installed at the beginning to make the |complete_name|
+macro function properly. Like for complete names, the initial |key_length|
+is the full length of the string specified.
+
+@< Copy the incomplete |name|... @>=
+{ char* key=(char*)malloc(l+2);
+ if (key==NULL) fatal("Out of dynamic memory!");
+ *key++='\1'; /* ensure that |complete_name(p)| is false afterwards */
+ strncpy(key,name,l); key[l]='\0'; /* store the incomplete name */
+ (p=make_mod_node(key))->key_length=l; /* prepare new node */
+ return *loc=p; /* install new node into tree */
+}
+
+@~When freeing the dynamic memory, we mustn't forget to subtract~1.
+
+@< Deallocate memory for |key| @>= @+ free(key-1);
+
+@ When we come here, we have found that |name| extends the first
+|p->key_length| characters of the name stored in~|p|, and therefore cannot
+similarly match any other nodes.
+
+@< Check that |name| matches the remainder of~|key|;
+ if so, extend its string if necessary and |return p|,
+ otherwise report an error and |return NULL| @>=
+{ enum mod_comparison cmp=
+ mod_name_cmp(name+l0,l-l0,key+l0,(int)strlen(key+l0));
+ switch(cmp)
+ { case less: case greater:
+ err_print("! Incompatible module name"); @.Incompatible module name@>
+ print("\nName inconsistently extends <%.*s...>.\n",l0,key);
+ @.Name inconsistently extends <...>@>
+ return NULL;
+ case prefix: case equal: return p;
+ case extension:
+ if (complete_name(p))
+ { err_print("! Incompatible module name"); @.Incompatible module name@>
+ print("\nPrefix exists: <%s>.\n",key); return NULL; @.Prefix exists@>
+ }
+ @< Replace name stored in |p| by the larger prefix |name| @>
+ return p;
+ }
+}
+
+@ We come here in the rather unusual case that a second larger prefix of the
+same module name is given before the full name is specified. We discard the
+old memory for |key| and replace it by a fresh copy of |name|, which is
+easier and probably more efficient than to try to reuse the old |key| by
+using |realloc|. As for the initial dynamic allocation, we must not forget
+the byte at~|key[-1]| here.
+
+@< Replace name stored in |p| by the larger prefix |name| @>=
+{ @< Deallocate memory for |key| @>
+ if ((key=(char*)malloc(l+2))==NULL) fatal("Out of dynamic memory!");
+ *key++='\1'; /* ensure that |complete_name(p)| is false afterwards */
+ strncpy(key,name,l); key[l]='\0'; /* store the incomplete name */
+ name_begin(p)=key; /* install new name in node |p| */
+}
+
+@* Lexical routines.
+Much of the code of \.{CWEB} deals with lexical matters such as recognising
+tokens, control texts, etc. This inevitably involves some complications
+since the relevant set of lexical rules varies from place to place in the
+source file, being sometimes that of \TeX, sometimes of \Cee, and sometimes
+rules defined by \.{CWEB} itself. Furthermore the source file is read in on
+three different occasions: once by \.{CTANGLE} and twice by \.{CWEAVE}; the
+level of detail in which the source is inspected differs between these
+passes. We can alleviate the task of lexical recognition by collecting in
+the common code a few functions that will scan specific lexical items; we do
+this for various classes of ``large'' lexical items: module names, control
+texts and strings.
+
+In all cases we copy the characters of the lexical item to a separate place,
+making minor modifications as necessary (for instance replacing \:@@
+by~`\.@@'). To this end there is a buffer |mod_text| used to copy the
+characters into; its name is derived from its most important purpose of
+storing module names, for which a separate buffer is definitely needed since
+these names can be spread over several lines of input. There are also two
+pointers |id_first| and~|id_loc| that are used to point to the beginning
+and end of lexical entities.
+
+@< Declarations... @>=
+extern char mod_text[], *id_first, *id_loc;
+#define mod_text_end (&mod_text[longest_name+1]) /* end of |mod_text| */
+mod_pointer get_module_name (void);
+boolean get_control_text(void);
+void get_string(void);
+
+@~The character |mod_text[0]| will not be used to store any actual
+characters, whence we make |mod_text| one slot longer than |longest_name|.
+
+@<Definitions...@>=
+char mod_text[longest_name+1]; /* name being sought for */
+char *id_first; /* where the current identifier begins in the buffer */
+char *id_loc; /* just after the current identifier in the buffer */
+
+@ The function for scanning and looking up module names is
+|get_module_name|; it will read the module name from the input, and decide
+how to search depending on the presence or absence of an ellipsis. This
+function is called when \:< has just been scanned; it will scan the
+module name and look it up by |mod_name_lookup| or |prefix_lookup| as
+appropriate; it returns a |mod_pointer| to the name found, or |NULL| if the
+name was found to be erroneous. Consequent to the limit, \.{CWEB} will treat
+`\.{@@<...@@>}' as a valid module name if and only if if there exactly one
+module name in the entire program.
+
+@c
+mod_pointer get_module_name (void)
+{ @< Put module name into |mod_text|,
+ set |id_first| and |id_loc| appropriately @>
+ { int l=(int)(id_loc-id_first);
+ return l>=3 && strncmp(id_loc-3,"...",3)==0
+ @/ ? prefix_lookup(id_first,l-3) : mod_name_lookup(id_first,l);
+ }
+}
+
+@ Module names are placed into the |mod_text| array with consecutive spaces,
+tabs, and carriage-returns replaced by single spaces. There will be no
+spaces at the beginning or the end. We set |mod_text[0]=' '| to facilitate
+this, and put |id_first=&mod_text[1]| for the calls to the lexical routines
+that use |mod_text|.
+
+@<Init...@>=
+mod_text[0]=' ';
+
+@~A module name of exactly |longest_name| characters will cause an error
+message, even though all its characters are stored; this is because we
+don't take the effort to distinguish a `full' state of the buffer from an
+`overflowed' one.
+
+@< Put module name... @>=
+{ eight_bits c; char* k=mod_text; /* points to last recorded character */
+ do
+ { if (!find_char())
+ {@; err_print("! Input ended in module name"); break; }
+ @.Input ended in module name@>
+ c=*loc++;
+ @<Handle |c=='@@'|; if end of name, |break|@>
+ if (isspace(c)) c=' '; /* convert tabs, newlines etc. */
+ if (k<mod_text_end-1 && !(c==' ' && *k==' ') ) *++k=c;
+ } while(true);
+ id_first=&mod_text[1];
+ if (k>=mod_text_end-1)
+@/{@; print("\n! Module name too long: "); @.Module name too long@>
+ term_write(id_first,25); err_print("..");
+ }
+ id_loc= *k==' ' && k>mod_text ? k : k+1;
+ /* point after last non-space character */
+}
+
+@ Except for the beginning of new sections we are not fussy about unexpected
+control sequences within module names, since we might be within `\pb';
+any problems will be eventually be detected during the output of module
+names by |CWEAVE|. So we are only looking for \:> (incidentally this
+means that control texts like those introduced by \:t are forbidden
+in module names).
+
+@< Handle |c=='@@'|... @>=
+if (c=='@@')
+{ if ((c=*loc++)=='>') break;
+ if (isspace(c) || c=='*' || c=='~')
+ @/{@; err_print("! Module name didn't end"); loc-=2; break; }
+ @.Module name didn't end@>
+ if (k<mod_text_end-1) *++k='@@';
+ /* record the `\.{@@}', now |c==loc[-1]| again */
+}
+
+@ The function |get_control_text| handles control texts. Like
+|get_module_name| it copies text until \:> into the |mod_text| array,
+and sets |id_first| and |id_loc| appropriately. The function returns a
+boolean value telling whether the control text was in fact empty, since that
+case sometimes needs special treatment. Always using |get_control_text|
+guarantees uniformity in the recognition of various types of control texts
+(not counting module names).
+
+@c
+boolean get_control_text(void)
+{ char c,* k=id_first=&mod_text[1]; /* points after last recorded character */
+ do
+ if ((*k++=*loc++)=='@@')
+ if ((c=*loc++)!='@@')
+ { if (c!='>')
+ err_print("! Control codes are forbidden in control text");
+ @.Control codes are forbidden...@>
+ return (id_loc=k-1)==id_first;
+ }
+ while(loc<=limit);
+ err_print("! Control text didn't end"); @.Control text didn't end@>
+ return (id_loc=k)==id_first;
+}
+
+@ And here is a similar function |get_string| that is used to scan strings
+and character constants. These can contain newlines or instances of their own
+delimiters if they are protected by a backslash. We follow this convention,
+but do not allow the string to be longer than |longest_name|. The macro
+|copy_char| copies a character to |mod_text| without risking overflow; the
+|else| branch of its definition serves only to ensure that any side effect
+of its argument is always performed.
+
+@d copy_char(c) @+ if (id_loc<mod_text_end) *id_loc++=c; @+ else (void)(c) @;
+
+@c
+void get_string(void)
+{ char c, delim = loc[-1]; /* what started the string */
+ id_loc=id_first = &mod_text[1]; copy_char(delim);
+ if (delim=='L')
+ *id_loc++=delim=*loc++; /* after `\.L' comes the real delimiter */
+ else if (delim=='<') delim='>'; /* for file names in \&{\#include} lines */
+ do
+ { if (loc>=limit)
+ {@; err_print("! String didn't end"); loc=limit; break; }
+ @.String didn't end@>
+ copy_char(c=*loc++);
+ if (c=='\\')
+ if (loc<limit) copy_char(*loc++);
+ /* record `\.\\|c|' with |c!='\n'| literally */
+ else if (get_line())
+ if (program==cweave) --id_loc; /* |CWEAVE| erases backslash */
+ else copy_char('\n'); /* but |CTANGLE| copies escaped newline */
+ else
+ {@; loc=buffer;
+ err_print("! Input ended in middle of string");
+ @.Input ended in middle of string@>
+ break;
+ }
+ else if (!including_header_file && c=='@@')
+ if (*loc=='@@') ++loc; /* undouble \:@@ */
+ else err_print("! Double @@ required in strings");
+ @.Double @@ required...@>
+ }
+ while (c!=delim);
+ if (id_loc>=mod_text_end)
+ @/{@; print("\n! String too long: "); @.String too long@>
+ term_write(mod_text+1,25); err_print("..");
+ }
+}
+
+
+@* Reporting errors to the user.
+A global variable called |history| will contain one of four values at the
+end of every run: |spotless| means that no unusual messages were printed;
+|harmless_message| means that a message of possible interest was printed
+but no serious errors were detected; |error_message| means that at least
+one error was found; |fatal_message| means that the program terminated
+abnormally. The value of |history| does not influence the behaviour of the
+program; it is simply computed for the convenience of systems that might
+want to use such information.
+
+@< Declarations... @>=
+extern history; /* indicates how bad this run was */
+extern void err_print (char*), wrap_up (void), print_stats (void),
+ fatal (char*,...);
+
+@~Despite the name |history|, each run starts in an unblemished state.
+@< Definitions... @>=
+int history=spotless; /* indicates how bad this run was */
+
+@ The call |err_print("! Error message")| will report an error to the user,
+printing the error message at the beginning of a new line and then giving an
+indication of where the error was spotted in the source file. Note that the
+string passed to |err_print| does not end with a period, since one will be
+automatically supplied, as will an initial newline if the string begins
+with~|"!"|.
+
+@c
+void err_print (char *s) /* prints `\..' and location of error message */
+{ print(*s=='!' ? "\n%s." : "%s.",s);
+ if (web_file_open) @<Print error location based on input buffer@>
+ update_terminal(); mark_error();
+}
+
+@ The error locations can be indicated by using the global variables
+|loc|, |cur_line|, |cur_file_name| and |changing|, which tell
+respectively the first unlooked-at position in |buffer|, the current
+line number, the current file, and whether the current line is from
+|change_file| or |cur_file|.
+
+@< Print error location based on input buffer @>=
+{ char *k, *l=(loc<limit) ? loc : limit; /* pointers into |buffer| */
+ if (changing) printf(" (l. %d of change file)\n", change_line);
+ else if (include_depth==0) printf(" (l. %d)\n", cur_line);
+ else printf(" (l. %d of include file %s)\n", cur_line, cur_file_name);
+ if (l>buffer)
+ { for (k=buffer; k<l; k++) putchar(*k=='\t' ? ' ': *k);
+ new_line();
+ for (k=buffer; k<l; k++) putchar(' '); /* space out the next line */
+ }
+ for (k=l; k<limit; k++) putchar(*k); /* print the part not yet read */
+}
+
+@ When a fatal error is encountered, or when the program comes to its normal
+termination, the function |wrap_up| is called, which will not return to the
+caller. Some implementations may wish to pass the |history| value to the
+operating system so that it can be used to govern whether or not other
+programs are started. Here, for instance, we pass the operating system
+a status of~0 if and only if at worst only harmless messages were printed.
+@^system dependencies@>
+
+@c
+void wrap_up (void)
+{
+#ifdef STAT
+ if (show_stats) print_stats(); /* print statistics about memory usage */
+#endif
+ @< Print the job |history| @>
+ exit(history>harmless_message);
+}
+
+@ A spotless status is reported if |show_happiness| is true, any other
+exit status is always reported.
+
+@< Print the job |history| @>=
+{ static char* mess[]=
+ { "No errors were found.",
+ "Did you see the warning message above?",
+ "Pardon me, but I think I spotted something wrong",
+ "That was a fatal error, my friend."
+ };
+ if (show_happiness || history>0) print("\n(%s)\n",mess[history]);
+}
+
+@ When an error or overflow condition is detected for which no recovery is
+possible, we call |fatal|, which aborts the program after pointing out the
+source of trouble and wrapping up as graciously as possible.
+
+@c
+void fatal(char* s,...)
+{ va_list p; va_start(p,s);
+ vprintf(s,p); va_end(p); err_print("");
+ /* print reason and location of fatal stop */
+ history=fatal_message; wrap_up();
+}
+
+
+@* Command line arguments.
+The user calls \.{CWEAVE} and \.{CTANGLE} with one or more arguments on the
+command line. These are either file names or sets of flags to be turned on
+(beginning with |"+"|) or off (beginning with |"-"|); in case the special
+flag |'i'| occurs, the remainder of that argument is interpreted as a string
+rather than as a set of flags.
+
+The following globals are for communicating the user's desires to the rest
+of the program. The various file name variables contain strings with the
+names of those files. Most of the flags are undefined but available for
+future extensions.
+
+@< Declarations... @>=
+extern boolean flags[];
+extern char C_file_name[],idx_file_name[],scn_file_name[];
+
+@~@< Definitions... @>=
+boolean flags[UCHAR_MAX+1]; /* an option for each character code */
+char C_file_name[max_file_name_length]; /* name of |C_file| */
+local char tex_file_name[max_file_name_length]; /* name of |tex_file| */
+char idx_file_name[max_file_name_length]; /* name of index file */
+char scn_file_name[max_file_name_length]; /* name of module names file */
+local boolean change_file_explicit=false;
+ /* was a change file argument specified? */
+
+@ We now must look at the command line arguments and set the file names
+accordingly.
+
+@< Prototypes of local functions @>=
+local void scan_args (int argc,char** argv);
+
+@~At least one file name must be present: the \.{CWEB} file. It may have an
+extension, or it may omit the extension to get |".w"| or |".web"| added.
+The \TeX\ output file name is formed by replacing the \.{CWEB} file name
+extension by |".tex"|, and the \Cee\ file name by replacing the extension
+by~|".c"|.
+
+If a second file name is given, it is the change file, again either with an
+extension or without one to get |".ch"|. An omitted change file argument
+means that the change file name is that of the \.{CWEB} file with the
+extension replaced by |".ch"| if that file exists, or none at all otherwise.
+If present, a third file name replaces the default output file name,
+possibly including the extension.
+
+@c
+local void scan_args (int argc,char** argv)
+{ char *dot_pos; /* position of rightmost |'.'| in the argument */
+ int files_found=0, paths_found= at_h_path[0].name==NULL ? 0 : 1;
+ while (--argc>0) /* first ``argument'' (program name) is irrelevant */
+ if (((*++argv)[0]=='+' || (*argv)[0]=='-') && (*argv)[1]!='\0')
+ @<Handle flag argument@>
+ else
+ { if (strlen(*argv)+5>max_file_name_length)
+ /* we need room to add things like `\.{.web}' */
+ fatal("! Filename too long:\n%s", *argv);
+ dot_pos=strrchr(*argv,'.');
+ switch (++files_found)
+ { case 1:
+ @< Make |web_file_name|, and defaults for other file names,
+ from~|*argv| @> @+
+ break; case 2: @< Make |change_file_name| from |*argv| @> @+
+ break; case 3: @< Make output file names from |*argv| @> @+
+ break; default: @< Print usage error message and quit @>
+ }
+ }
+ if (files_found==0) @< Print usage error message and quit @>
+ if (paths_found<max_include_paths)
+ at_h_path[paths_found].name=NULL; /* mark end of list */
+}
+
+@ We use |*argv| for the |web_file_name| if there is a |'.'| in it,
+otherwise we add |".w"|. We prepare an alternative name |alt_web_file_name|
+by adding |"web"| after the dot. The other file names come from adding other
+things after the dot. Since there is no general agreement about the proper
+extension for \Cpp\ file names, we use a macro |CPPEXT| for it, which
+defaults to |"C"| but can be overridden by predefining this preprocessor
+symbol when \.{common.c} is compiled.
+
+@< Make |web_file_name|... @>=
+#ifndef CPPEXT
+#define CPPEXT "C"
+ /* extension for \Cpp\ file names; should not exceed 3 characters */
+#endif
+{ if (dot_pos==NULL) sprintf(web_file_name,"%s.w",*argv);
+ else
+ { sprintf(web_file_name,"%s",*argv); /* use file name and extension */
+ *dot_pos='\0'; /* truncate the name before the dot */
+ }
+ sprintf(alt_web_file_name,"%s.web",*argv);
+ sprintf(change_file_name,"%s.ch",*argv);
+ if (program==ctangle)
+ sprintf(C_file_name,"%s.%s",*argv, C_plus_plus ? CPPEXT : "c");
+ else
+ { sprintf(tex_file_name,"%s.tex",*argv);
+ sprintf(idx_file_name,"%s.idx",*argv);
+ sprintf(scn_file_name,"%s.scn",*argv);
+ }
+}
+
+@ If in place of the change file name a `\.-' is specified, we clear the
+|change_file_name|, and if a `\.+' is specified we retain the default
+(but |files_found| is increased so that the next file name will be the
+output file); otherwise, |change_file_explicit| is raised and the default
+change file name is replaced by the given one.
+
+@< Make |change_file_name|... @>=
+if ((*argv)[0]=='-') change_file_name[0]='\0';
+else if ((*argv)[0]!='+')
+@/{@; change_file_explicit=true;
+ sprintf(change_file_name,dot_pos==NULL ? "%s.ch" : "%s", *argv);
+}
+
+@ If an output file name is given when calling \.{CWEAVE}, its base name is
+also used for |idx_file_name| and |scn_file_name|.
+
+@< Make output file names... @>=
+if (program==ctangle)
+ if (dot_pos!=NULL) sprintf(C_file_name, "%s", *argv);
+ else sprintf(C_file_name,"%s.%s", *argv, C_plus_plus ? CPPEXT : "c");
+else
+{ if (dot_pos!=NULL)
+ {@; sprintf(tex_file_name, "%s", *argv); *dot_pos='\0'; }
+ else sprintf(tex_file_name,"%s.tex", *argv);
+ sprintf(idx_file_name,"%s.idx",*argv);
+ sprintf(scn_file_name,"%s.scn",*argv);
+}
+
+@ The |flags| are turned off initially; any flags that are on by default are
+set before calling |common_init|.
+
+@< Set the default options common to \.{CTANGLE} and \.{CWEAVE} @>=
+show_banner=show_happiness=show_progress=true;
+
+@~Flags are made case-insensitive, since some operating systems do not
+allow passing of both lower and upper case arguments. The |'i'| flag gets
+a special treatment.
+
+@< Handle flag... @>=
+{ boolean flag_change=(**argv == '+');
+ char* p=&(*argv)[1]; unsigned char c;
+ while ((c=*p++)!='\0')
+ if ((c=tolower(c))!='i') flags[c]=flag_change;
+ else @< Store string |p| as new include path and |break| @>
+}
+
+@ We copy include paths into |byte_mem|; since we are at the very beginning
+of the run, there is no chance that we overflow |byte_mem| already, so that
+we need not include a fourth error message below.
+
+@< Store string |p| as new include path and |break| @>=
+{ size_t l=strlen(p);
+ if (l==0) err_print("! Empty include path");
+ @.Empty include path@>
+ else if (l>max_path_length) err_print("! Include path too long");
+ @.Include path too long@>
+ else if (paths_found>=max_include_paths)
+ err_print("! Too many include paths");
+ @.Too many include paths@>
+ else
+ { at_h_path[paths_found].length=(int)l;
+ at_h_path[paths_found++].name=strcpy(byte_ptr,p);
+ byte_ptr+=l+1;
+ }
+ break;
+}
+
+@ The usage message gives only a sketch of the proper way to call the
+\.{CWEB}. programs; more details can be found in the manual.
+
+@< Print usage error message and quit @>=
+fatal("! Usage:\n" @+
+"c%se [(+|-)options] cwebfile[.w] [(changefile[.ch]|+|-) [outputfile[.%s]]]"
+ , program==ctangle ? "tangl" : "weav"
+ , program==ctangle ? "c" : "tex");
+
+@* Output. The only thing done in the common code for the output files is
+declaring the variables through which they are accessed, and opening them.
+
+@< Declarations... @>=
+extern FILE *C_file, *tex_file;
+void open_output_file(void);
+
+@~Having separate variables for the output files of \.{CTANGLE} and
+\.{CWEAVE} only serves to give them more meaningful names.
+
+@<Definitions...@>=
+FILE *C_file; /* where output of \.{CTANGLE} goes */
+FILE *tex_file; /* where output of \.{CWEAVE} goes */
+
+@~@c
+void open_output_file(void)
+{ char* name; FILE** file;
+ if (program==ctangle) {@; name=C_file_name; file=&C_file; }
+ else {@; name=tex_file_name; file=&tex_file; }
+ if ((*file=fopen(name,"w"))==NULL)
+ fatal("! Cannot open \"%s\" as output file",name);
+ @.Cannot open output file@>
+}
+
+@ All regular terminal output passes through the function |print|, which
+takes the place of |printf|; it suppresses initial newlines if the line is
+already empty. The function |print_progress| and |print_section_progress|
+are used to display progress reports on the screen.
+
+@< Declarations...@>=
+void print(char*,...), print_progress(char*), print_section_progress(void);
+
+@~A variable |term_line_empty| keeps track of whether we are at the
+beginning of an output line, so that we can force certain terminal output
+to start on a new line without producing empty lines.
+
+@<Definitions...@>=
+local boolean term_line_empty=true;
+ /* has anything been written to the current line? */
+
+@~Any initial or final newline produced by~|print| is caused by the format
+string, not by any of the arguments following it; this makes it easy to
+maintain |term_line_empty|.
+
+If a function produces terminal output otherwise than through one of the
+three functions below, it should take care of |term_line_empty| itself;
+for instance |err_print| produces the error context using |printf| and
+|putchar|, knowing that |term_line_empty==false| at that time, which is
+also the correct value afterwards.
+
+@c
+void print(char* s,...)
+{ va_list p; va_start(p,s);
+ if (term_line_empty && *s=='\n') ++s; /* avoid printing empty line */
+ vprintf(s,p); va_end(p); /* print formatted value */
+ term_line_empty= s[strlen(s)-1]=='\n'; update_terminal();
+}
+
+void print_progress (char* s) @+{@; if (show_progress) print(s); }
+
+void print_section_progress (void)
+@+{@; if (show_progress) print("*%u",section_count); }
+
+
+@* Index. % CWEAVE will add the index to this section.
diff --git a/web/c_cpp/cwebx/compare.tex b/web/c_cpp/cwebx/compare.tex
new file mode 100644
index 0000000000..8d8c03f490
--- /dev/null
+++ b/web/c_cpp/cwebx/compare.tex
@@ -0,0 +1,202 @@
+\input cwebxmac
+
+\N0 1. Comparing text files.
+This is an entirely trivial program, that tests whether two text files are
+equal, and if not so, points out the first point of difference.
+
+\Y\B\h$\.{<stdio.h>}$\par
+\B\h$\.{<stdlib.h>}$\par
+\Y\B$\&{typedef}~\&{char}~\&{bool};$\par
+\fi
+
+\M2. The outline of the program is simple. We read characters from both input
+files into $ c_1$ and~$ c_2$ until the comparison is complete. Line and column
+counts are maintained in $\\{line}$ and~$\\{col}$.
+
+\Y\B\D$\\{left\_margin}$\5
+$\T{1}$\C{ leftmost column number; change to 0 if you prefer }\par
+\Y\B$\X5:Functions\X$\7
+\&{int} $\\{main}$\5
+$(\1\1\1\&{int}~ n,\31~\&{char}~\m*\m*\\{arg}\2\2\2)$\6
+$\a\{\1\&{FILE}~\m* f_1,\31~\m* f_2;$\C{ the two input files }\6
+$\&{int}~ c_1,\31~ c_2,\31~\\{col}\K\\{left\_margin};$\6
+$\&{long}~\\{line}\K\T{1};$\7
+$\X6:Open the files $ f_1$ and~$ f_2$, taking their names from the command line
+or from the terminal; in case of an error for which no recovery is possible,
+call $\\{exit}(\T{1})$\X$\6
+$\X3:Search for first difference, leaving $ c_1\I c_2$ if and only if a
+difference was found\X$\6
+$\X4:Report the outcome of the comparison\X$\6
+$\&{return}~\T{0};$\C{ successful completion }\2\6
+$\}$\par
+\fi
+
+\M3. The heart of the program is this simple loop. When we reach the end of
+one of the files, the files match if and only if the other file has also
+reached its end. For this reason the test $ c_1\E c_2$, which requires
+characters to be read from both files, must precede the test for file end;
+when only one file ends, it is the former test which breaks the loop.
+
+\Y\B\4$\X3:Search for first difference, leaving $ c_1\I c_2$ if and only if a
+difference was found\X\EQ{}$\6
+\&{while}~$(( c_1\K\\{getc}( f_1))\E( c_2\K\\{getc}( f_2))\W c_1\I\.{EOF})\1$\6
+\&{if}~$( c_1\E\.{'\\n'})\1$\5
+$\{\1$\5
+$\PP\\{line};$\5
+$\\{col}\K\\{left\_margin};\2$\5
+$\}$\5
+\2\&{else}\1\5
+$\PP\\{col};\2$\2\par
+\U 2.\fi
+
+\M4. When the first difference occurs at the end of one of the files, or at the
+end of a line, we give a message indicating this fact.
+
+\Y\B\4$\X4:Report the outcome of the comparison\X\EQ{}$\6
+\&{if}~$( c_1\E c_2)\1$\5
+$\\{printf}(\.{"Files\ match.\\n"});\2$\6
+\&{else}\6
+$\a\{\1\\{printf}(\.{"Files\ differ.\\n"});$\6
+\&{if}~$( c_1\E\.{EOF}\V c_2\E\.{EOF})$\1\6
+$\{\1$\5
+$\\{the\_file}( c_1\E\.{EOF});$\5
+$\\{printf}(\.{"is\ contained\ in\ the\)\ other\ as\ initial\ seg\)ment.\\n"});%
+\2$\5
+$\}\2$\6
+\&{else}~\&{if}~$( c_1\E\.{'\\n'}\V c_2\E\.{'\\n'})$\1\6
+$\{\1$\5
+$\\{the\_file}( c_1\E\.{'\\n'});$\5
+$\\{printf}(\.{"has\ a\ shorter\ line\ \)number\ \%ld\ than\ the\ o\)ther.%
+\\n"},\31\\{line});\2$\5
+$\}\2$\6
+\&{else}\1\5
+$\\{printf}(\.{"First\ difference\ at\)\ line\ \%ld,\ column\ \%d.\)\\n"},\31%
+\\{line},\31\\{col});\2$\2\6
+$\}$\par
+\U 2.\fi
+
+\M5. The function $\\{the\_file}$ starts a sentence about the first or second
+file,
+depending on its boolean argument.
+
+\Y\B\4$\X5:Functions\X\EQ{}$\6
+\&{void} $\\{the\_file}$\5
+$(\1\1\1\&{bool}~\\{is\_first}\2\2\2)$\5
+$\{\1$\5
+$\\{printf}(\.{"The\ \%s\ file\ "},\31\\{is\_first}\?\.{"first"}:\.{"second"});%
+\2$\5
+$\}$\par
+\A 7.
+\U 2.\fi
+
+\M6. There can be be zero, one or two command line arguments. If there are
+none,
+the user is prompted to supply them, and if there are two these are taken as
+the file names, prompting the user only in case a file could not be opened.
+In case just one argument is present, the first file is assumed to be the
+standard input, which does not have to be opened; in this case however we
+will not read a file name from terminal in case the second file cannot be
+opened.
+
+\Y\B\D$\\{read\_mode}$\5
+$\.{"r"}$\par
+\Y\B\4$\X6:Open the files $ f_1$ and~$ f_2$, taking their names from the
+command line or from the terminal; in case of an error for which no recovery is
+possible, call $\\{exit}(\T{1})$\X\EQ{}$\6
+$\MM n;$\5
+$\PP\\{arg};$\C{ ignore ``argument'' 0, which is the program name }\6
+\&{if}~$( n\E\T{0})$\1\6
+$\{\1$\5
+$\\{open\_file}(\m\AND f_1,\31\.{"First\ file\ to\ compa\)re"},\31\NULL);$\5
+$\\{open\_file}(\m\AND f_2,\31\.{"Second\ file\ to\ comp\)are"},\31\NULL);\2$\5
+$\}\2$\6
+\&{else}~\&{if}~$( n\E\T{1})$\6
+$\a\{\1 f_1\K\\{stdin};$\6
+\&{if}~$(( f_2\K\\{fopen}(\m*\\{arg},\31\\{read\_mode}))\E\NULL)\1$\5
+$\{\1$\5
+$\\{printf}(\.{"Could\ not\ open\ file\)\ \%s.\\n"},\31\m*\\{arg});$\5
+$\\{exit}(\T{1});\2$\5
+$\}\2$\2\6
+$\}$\6
+\&{else}~\&{if}~$( n\E\T{2})$\6
+$\a\{\1\\{open\_file}(\m\AND f_1,\31\.{"Give\ another\ first\ \)file"},\31\m*%
+\\{arg}\PP);$\5
+$\\{open\_file}(\m\AND f_2,\31\.{"Give\ another\ second\)\ file"},\31\m*%
+\\{arg});\2$\6
+$\}$\6
+\&{else}\1\5
+$\{\1$\5
+$\\{printf}(\.{"No\ more\ than\ two\ co\)mmand\ line\ arguments\ \)are\
+allowed.\\n"});$\5
+$\\{exit}(\T{1});\2$\5
+$\}\2$\par
+\U 2.\fi
+
+\M7. The function $\\{open\_file}$ will try to open the file $\\{name}$ for
+reading, and
+if this fails it will prompt for another file name until it has success. If
+called with $\\{name}\E\NULL$, the function starts with prompting right away.
+
+\Y\B\4$\X5:Functions\X\PE{}$\6
+\&{void} $\\{open\_file}$\5
+$(\1\1\1\&{FILE}~\m*\m* f,\31~\&{char}~\m*\\{prompt},\31~\&{char}~\m*\\{name}\2%
+\2\2)$\6
+$\a\{\1\&{char}~\\{buf}[\T{80}];$\7
+\&{if}~$(\\{name}\E\NULL\V(\m* f\K\\{fopen}(\\{name},\31\\{read\_mode}))\E%
+\NULL)\1$\6
+\&{do}\1\5
+$\{\1$\5
+$\\{printf}(\.{"\%s:\ "},\31\\{prompt});$\5
+$\\{fflush}(\\{stdout});$\5
+$\\{scanf}(\.{"\%79s"},\31\\{buf});\2$\5
+$\}$\2\6
+\&{while}~$((\m* f\K\\{fopen}(\\{buf},\31\\{read\_mode}))\E\NULL);$\2\2\6
+$\}$\par
+\fi
+
+\N0 8. Index.
+\fi
+
+
+\inx
+\@m\\{arg}, \[2], 6.
+\@h\&{bool}, \[1], 5.
+\@m\\{buf}, \[7].
+\@m\\{col}, \[2], 3, 4.
+\@m c_1, \[2], 3, 4.
+\@m c_2, \[2], 3, 4.
+\@m\.{EOF}, 3, 4.
+\@m\\{exit}, 6.
+\@m f, \[7].
+\@m\\{fflush}, 7.
+\@m\\{fopen}, 6, 7.
+\@m f_1, \[2], 3, 6.
+\@m f_2, \[2], 3, 6.
+\@m\\{getc}, 3.
+\@m\\{is\_first}, \[5].
+\@m\\{left\_margin}, \[2], 3.
+\@m\\{line}, \[2], 3, 4.
+\@m\\{main}, \[2].
+\@m n, \[2].
+\@m\\{name}, \[7].
+\@m\\{open\_file}, 6, \[7].
+\@m\\{printf}, 4, 5, 6, 7.
+\@m\\{prompt}, \[7].
+\@m\\{read\_mode}, \[6], 7.
+\@m\\{scanf}, 7.
+\@m\\{stdin}, 6.
+\@m\\{stdout}, 7.
+\@m\\{the\_file}, 4, \[5].
+\fin
+\@$\X5, 7:Functions\X$
+\U 2.
+\@$\X6:Open the files $ f_1$ and~$ f_2$, taking their names from the command
+line or from the terminal; in case of an error for which no recovery is
+possible, call $\\{exit}(\T{1})$\X$
+\U 2.
+\@$\X4:Report the outcome of the comparison\X$
+\U 2.
+\@$\X3:Search for first difference, leaving $ c_1\I c_2$ if and only if a
+difference was found\X$
+\U 2.
+\con
diff --git a/web/c_cpp/cwebx/ctangle.c b/web/c_cpp/cwebx/ctangle.c
new file mode 100644
index 0000000000..2ce302a9ef
--- /dev/null
+++ b/web/c_cpp/cwebx/ctangle.c
@@ -0,0 +1,996 @@
+#define version_string "3.04"
+#define banner "This is CTANGLE (Version x" version_string ")\n"
+#define max_toks 150000L
+#define max_texts 2500
+#define max_files 50
+#define stack_size_max 50
+#define max_indent 1000
+#define variant text
+#define line_output flags['l']
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include "common.h"
+#define max_bytes 50000L
+#define max_modules 1000
+#define max_idents 5000
+#define max_sections 4000
+#define hash_size 353
+#define buf_size 100
+#define longest_name 1000
+#define long_buf_size (buf_size+longest_name)
+#define local static
+#define array_size(a)((int)(sizeof(a)/sizeof(a[0])))
+#define false (boolean)0
+#define true (boolean)1
+#define ctangle 0
+#define cweave 1
+#define and_and 04
+#define lt_lt 020
+#define gt_gt 021
+#define plus_plus 013
+#define minus_minus 01
+#define minus_gt 031
+#define not_eq 032
+#define lt_eq 034
+#define gt_eq 035
+#define eq_eq 036
+#define or_or 037
+#define find_char()(loc<=limit||get_line())
+#define id_index(p)((sixteen_bits)((p)-id_table))
+#define id_at(i)(&id_table[i])
+#define mod_index(p)((sixteen_bits)((p)-mod_table))
+#define mod_at(i)(&mod_table[i])
+#define name_begin(p)((p)->byte_start)
+#define length(p)((int)(strlen(name_begin(p))))
+#define name_end(p)(name_begin(p)+length(p))
+#define complete_name(p)((p)->byte_start[-1]=='\0')
+#define print_mod(p) \
+printf(": <%s%s>",name_begin(p),complete_name(p)?"":"...")
+#define spotless 0
+#define harmless_message 1
+#define error_message 2
+#define fatal_message 3
+#define mark_harmless() \
+if(history==spotless)history=harmless_message;else
+#define mark_error()(history=error_message)
+#define overflow(t)fatal("\n! Sorry, %s capacity exceeded",t)
+#define confusion(s)fatal("\n! This can't happen: %s",s)
+#define show_banner flags['b']
+#define show_happiness flags['h']
+#define show_progress flags['p']
+#define show_stats flags['s']
+#define C_plus_plus flags['+']
+#define compatibility_mode flags['c']
+#define update_terminal()fflush(stdout)
+#define new_line()putchar('\n')
+#define term_write(string,leng)printf("%.*s",(int)(leng),string)
+#define tok_begin(p)(p)->tok_start
+#define tok_end(p)((p)+1)->tok_start
+#define text_table_end (&text_table[max_texts])
+#define tok_mem_end (&tok_mem[max_toks])
+#define store_byte(c) \
+if(tok_ptr==tok_mem_end)overflow("token");else*tok_ptr++=c
+#define macro_flag (text_table_end-1)
+#define header_flag text_table_end
+#define next_sec(m)((m)->text_link)
+#define equiv equiv_or_xref
+#define verb_quote 0x2
+#define join 0x3
+#define cur_repl cur_state.repl_field
+#define cur_byte cur_state.byte_field
+#define cur_end cur_state.end_field
+#define cur_sec cur_state.sec_nr_field
+#define cur_ind cur_state.indent_field
+#define cur_state stack[0]
+#define stack_end (&stack[stack_size_max])
+#define stack_empty()(stack_ptr== &stack[0])
+#define C_printf(format,x)fprintf(C_file,format,x)
+#define C_putc(c)putc(c,C_file)
+#define put_indent() \
+(indent_buffer[ind_i=cur_ind]='\0',C_printf("%s",indent_buffer))
+#define append_white(c) \
+if(ind_i>=max_indent)overflow("indent buffer"); \
+else indent_buffer[ind_i++]=isspace(c)?c:' '
+#define trans_limit 9
+#define trans_of(c)c_trans[(unsigned char)(c)-0x80]
+#define translation_exists(c)(trans_of(c)[0]!='\0')
+#define comp_op(op) \
+(C_printf(out_state==operator&&line_output?" %s":"%s",op) \
+,out_state=operator)
+#define code_of(c)ccode[(unsigned char)(c)]
+#define compress(char2,code) \
+if(*loc==char2)return++loc,code
+#define preproc_directive 0
+#define section_body 1
+#define report(k,c,m) \
+printf("%lu %ss (out of %lu)\n",(unsigned long)(c),k,(unsigned long)(m))
+/*3:*//*10:*/
+#line 122 "common.inc"
+boolean names_match(id_pointer,char*,int,int);
+void init_id_name(id_pointer,int);
+void init_module_name(mod_pointer);/*:10*//*15:*/
+#line 116 "ctangle.w"
+typedef struct text
+{eight_bits*tok_start;
+struct text*text_link;
+}text,*text_pointer;/*:15*//*30:*/
+#line 442 "ctangle.w"
+typedef struct
+{text_pointer repl_field;
+eight_bits*byte_field;
+eight_bits*end_field;
+sixteen_bits sec_nr_field;
+sixteen_bits indent_field;
+}output_state,*stack_pointer;/*:30*//*36:*/
+#line 561 "ctangle.w"
+enum{identifier=0x80,section_start,section_end,line_mark};/*:36*//*44:*/
+#line 747 "ctangle.w"
+enum{no_space,num_or_id,operator,literal};/*:44*//*54:*/
+#line 936 "ctangle.w"
+enum
+{ignore=0x80,
+id_code,constant,
+verbatim,
+at_sign_image,
+join_code,
+ord,
+control_text,
+include_preproc,
+char_trans,
+format,
+definition,
+header,
+begin_C,
+module_name,
+new_section
+};/*:54*//*24:*/
+#line 301 "ctangle.w"
+void phase_two(void);
+void output(text_pointer);
+void output_preproc_directives(void);
+void C_newline(void);
+void out_char(eight_bits);/*:24*//*80:*/
+#line 1604 "ctangle.w"
+boolean mark_line(void);/*:80*//*89:*/
+#line 1770 "ctangle.w"
+void phase_one(void);/*:89*//*16:*/
+#line 136 "ctangle.w"
+text text_table[max_texts];
+text_pointer text_ptr= &text_table[0];
+eight_bits tok_mem[max_toks];
+eight_bits*tok_ptr= &tok_mem[0];/*:16*//*20:*/
+#line 197 "ctangle.w"
+text_pointer text_root=NULL;
+text_pointer*last_unnamed= &text_root;/*:20*//*23:*/
+#line 291 "ctangle.w"
+boolean atp_seen=false;/*:23*//*26:*/
+#line 343 "ctangle.w"
+mod_pointer output_file[max_files];
+int output_file_count=0;/*:26*//*31:*/
+#line 466 "ctangle.w"
+output_state stack[stack_size_max];
+stack_pointer stack_ptr;/*:31*//*32:*/
+#line 486 "ctangle.w"
+char indent_buffer[max_indent];
+
+sixteen_bits ind_i;/*:32*//*35:*/
+#line 543 "ctangle.w"
+int cur_val;/*:35*//*43:*/
+#line 723 "ctangle.w"
+eight_bits out_state;
+boolean protect;/*:43*//*47:*/
+#line 819 "ctangle.w"
+char c_trans[UCHAR_MAX+1-0x80][trans_limit+1];/*:47*//*55:*/
+#line 962 "ctangle.w"
+eight_bits ccode[UCHAR_MAX+1];/*:55*//*60:*/
+#line 1100 "ctangle.w"
+id_pointer cur_id;
+mod_pointer cur_mod;/*:60*//*70:*/
+#line 1342 "ctangle.w"
+text_pointer cur_text;
+eight_bits next_control;/*:70*/
+#line 79 "ctangle.w"
+
+
+int main(int argc,char* *argv)
+{program=ctangle;
+line_output=true;
+common_init(argc,argv);/*17:*/
+#line 144 "ctangle.w"
+tok_begin(text_ptr)=tok_ptr;/*:17*//*48:*/
+#line 827 "ctangle.w"
+if(compatibility_mode)
+{unsigned char c=UCHAR_MAX;
+do sprintf(trans_of(c),"X%X",c);while(--c>=0x80);
+}/*:48*//*56:*/
+#line 970 "ctangle.w"
+{unsigned char c=0;
+do ccode[c]=isspace(c)?new_section:ignore;while(c++ !=UCHAR_MAX);
+ccode['v']=ccode['V']='|';
+ccode['=']=verbatim;
+ccode['@']=at_sign_image;
+ccode['&']=join_code;
+ccode['\'']=ord;
+ccode['^']=ccode['?']=ccode['.']=ccode[':']=ccode['#']=
+ccode['t']=ccode['T']=ccode['q']=ccode['Q']=control_text;
+ccode['p']=ccode['P']=include_preproc;
+ccode['l']=ccode['L']=char_trans;
+ccode['f']=ccode['F']=ccode['s']=ccode['S']=format;
+ccode['d']=ccode['D']=definition;
+ccode['h']=ccode['H']=header;
+ccode['c']=ccode['C']=begin_C;
+ccode['<']=ccode['(']=module_name;
+ccode['~']=ccode['*']=new_section;
+if(compatibility_mode)/*57:*/
+#line 1000 "ctangle.w"
+{ccode['h']=ccode['H']=include_preproc;
+ccode['p']=ccode['P']=begin_C;
+ccode['#']=ignore;
+}/*:57*/
+#line 989 "ctangle.w"
+}/*:56*/
+#line 86 "ctangle.w"
+if(show_banner)print(banner);
+phase_one();
+phase_two();
+wrap_up();
+return 0;
+}/*:3*//*18:*/
+#line 153 "ctangle.w"
+void store_two_bytes(sixteen_bits x)
+{if(tok_ptr+2>tok_mem_end)overflow("token");
+*tok_ptr++=x>>8;
+*tok_ptr++=x&0xFF;
+}/*:18*//*21:*/
+#line 211 "ctangle.w"
+boolean names_match(id_pointer x,char*q,int l,int dummy)
+{char*p=name_begin(x);while(--l>=0)if(*p++ != *q++)return false;
+return*p=='\0';
+}
+
+void init_module_name(mod_pointer node)
+{node->equiv=NULL;}
+
+void init_id_name(id_pointer dummy,int ilk){}/*:21*//*25:*/
+#line 314 "ctangle.w"
+void phase_two(void)
+{phase=2;
+if(text_root==NULL&&output_file_count==0)
+{print("\n! No program text was specified.");mark_harmless();}
+
+else
+{if(show_progress)
+{print("\nWriting the output file%s"
+,(text_root!=NULL)+output_file_count>1?"s":"");
+if(text_root!=NULL)printf(" (%s):",C_file_name);
+update_terminal();
+}
+if(text_root==NULL)C_file=NULL;
+else
+{open_output_file();cur_line=1;
+if(!atp_seen)output_preproc_directives();
+output(text_root);
+}/*27:*/
+#line 355 "ctangle.w"
+{int i;
+char output_file_name[longest_name+1];
+for(i=0;i<output_file_count;i++)
+{mod_pointer output_module=output_file[i];/*28:*/
+#line 384 "ctangle.w"
+{char*p=output_file_name,*q=name_begin(output_module);
+while(*q!='\0')
+if((*p++= *q++)=='@')
+if(*q++ !='@')
+{print("\n! Illegal control code in file name");
+
+print_mod(output_module);err_print("");
+}
+*p='\0';
+}/*:28*/
+#line 360 "ctangle.w"
+if(C_file!=NULL)fclose(C_file);
+if(output_module->equiv==NULL)
+{print("\n! Module not present");
+
+print_mod(output_module);err_print("");
+}
+else if((C_file=fopen(output_file_name,"w"))==NULL)
+{print("\n! Cannot open \"%s\" as output file",output_file_name);
+
+err_print("");
+}
+else
+{if(show_progress)print("\n(%s):",output_file_name);
+cur_line=1;
+output(output_module->equiv);
+}
+}
+}/*:27*/
+#line 333 "ctangle.w"
+print_progress("\nDone.\n");
+}
+}/*:25*//*33:*/
+#line 499 "ctangle.w"
+void push_level(mod_pointer p)
+{if(stack_ptr==stack_end)overflow("output stack");
+*stack_ptr++=cur_state;
+cur_repl=p->equiv;
+cur_byte=tok_begin(cur_repl);cur_end=tok_end(cur_repl);
+cur_ind=ind_i;
+}/*:33*//*34:*/
+#line 516 "ctangle.w"
+void continue_or_pop_level(void)
+{if(cur_repl->text_link!=NULL)
+
+{cur_repl=next_sec(cur_repl);
+cur_byte=tok_begin(cur_repl);cur_end=tok_end(cur_repl);
+}
+else if(--stack_ptr> &stack[0])cur_state= *stack_ptr;
+
+ind_i=cur_ind;
+}/*:34*//*37:*/
+#line 576 "ctangle.w"
+void output(text_pointer repl)
+{stack_ptr= &stack[1];
+cur_repl=repl;cur_byte=tok_begin(cur_repl);cur_end=tok_end(cur_repl);
+cur_ind=ind_i=0;
+do
+if(cur_byte==cur_end)
+{cur_val=cur_sec;
+continue_or_pop_level();
+out_char(section_end);
+}
+else/*38:*/
+#line 601 "ctangle.w"
+{int a= *cur_byte++;
+if(a<0x80)out_char(a);
+else if(a>=0xF8)
+if(a<0xFA)out_char(a==0xF8? *cur_byte++:line_mark);
+else{C_newline();output_preproc_directives();}
+else
+{cur_val=(((a-=0x80)%0x28)<<8)+ *cur_byte++;
+switch(a/0x28)
+{case 0:out_char(identifier);break;
+case 1:/*39:*/
+#line 623 "ctangle.w"
+{mod_pointer mod_name=mod_at(cur_val);
+if(mod_name->equiv!=NULL)push_level(mod_name);
+else
+{print("\n! Module not present");print_mod(mod_name);err_print("");
+
+}
+}/*:39*/
+#line 610 "ctangle.w"
+break;
+case 2:cur_sec=cur_val;out_char(section_start);
+
+}
+}
+}/*:38*/
+#line 589 "ctangle.w"
+while(!stack_empty());
+C_newline();
+}/*:37*//*40:*/
+#line 644 "ctangle.w"
+void output_preproc_directives(void)
+{text_pointer repl,l;
+eight_bits*p,*end;
+protect=true;
+for(repl= &text_table[0];repl<text_ptr;repl++)
+if((l=repl->text_link)==macro_flag||l==header_flag)
+{p=tok_begin(repl);end=tok_end(repl);
+C_printf("#%se ",l==macro_flag?"defin":"includ");
+out_state=no_space;
+while(p<end)/*41:*/
+#line 670 "ctangle.w"
+{int a= *p++;
+if(a<0x80)out_char(a);
+else if(a>=0xF8)
+if(a==0xF8)out_char(*p++);
+else confusion("`@p' within macro");
+else
+{cur_val=(((a-=0x80)%0x28)<<8)+ *p++;
+if(a<0x28)out_char(identifier);
+else confusion("module within macro");
+}
+}/*:41*/
+#line 656 "ctangle.w"
+C_newline();
+}
+protect=false;
+}/*:40*//*42:*/
+#line 692 "ctangle.w"
+void C_newline(void)
+{C_putc('\n');
+if(!line_output)put_indent();
+if(cur_line%100==0&&show_progress)
+{if(cur_line%500!=0)print(".");
+else print(cur_line%2500==0?"%u\n":"%u",cur_line);
+update_terminal();
+}
+++cur_line;
+}/*:42*//*45:*/
+#line 764 "ctangle.w"
+void out_char(eight_bits c)
+{if(out_state==literal)
+if(c==verb_quote)out_state=num_or_id;
+else C_putc(c);
+else if(isalnum(c)&&c<0x80||c=='_')
+
+{if(out_state==num_or_id&&line_output)C_putc(' ');
+C_putc(c);out_state=num_or_id;
+if(!line_output)append_white(c);
+}
+else switch(c)
+{case verb_quote:
+if(out_state==num_or_id&&line_output)C_putc(' ');
+out_state=literal;break;
+case join:out_state=no_space;break;
+case '\n':/*46:*/
+#line 803 "ctangle.w"
+{if(protect){C_putc(' ');C_putc('\\');}
+C_newline();
+if(out_state!=literal)out_state=no_space;
+}/*:46*/
+#line 779 "ctangle.w"
+break;
+case identifier:/*49:*/
+#line 838 "ctangle.w"
+{char*p=name_begin(id_at(cur_val));int l=0;
+if(out_state==num_or_id&&line_output)C_putc(' ');
+do
+if((unsigned char)(*p)<0x80){C_putc(*p);++l;}
+else
+{char*q=trans_of(*p);do{C_putc(*q);++l;}while(* ++q!='\0');}
+while(* ++p!='\0');
+out_state=num_or_id;
+if(!line_output)do append_white(' ');while(--l>0);
+}/*:49*/
+#line 780 "ctangle.w"
+break;
+case section_start:
+if(line_output)C_printf("/*%d:*/",cur_val);else C_newline();
+out_state=no_space;break;
+case section_end:
+if(line_output)C_printf("/*:%d*/",cur_val);else C_newline();
+out_state=no_space;break;
+case line_mark:/*50:*/
+#line 854 "ctangle.w"
+{sixteen_bits a;
+a=(*cur_byte++)<<8;a+= *cur_byte++;
+C_newline();C_printf("#line %u \"",a);
+a=(*cur_byte++)<<8;a+= *cur_byte++;
+C_printf("%s\"",name_begin(id_at(a)));
+C_newline();out_state=no_space;
+}/*:50*/
+#line 787 "ctangle.w"
+break;/*51:*/
+#line 877 "ctangle.w"
+case '+':case '-':case '*':case '/':case '%':case '?':
+case '<':case '>':case '&':case '|':
+if(out_state==operator&&line_output)C_putc(' ');
+case '=':C_putc(c);out_state=operator;break;/*:51*//*52:*/
+#line 892 "ctangle.w"
+case plus_plus:comp_op("++");break;
+case minus_minus:comp_op("--");break;
+case minus_gt:comp_op("->");break;
+case gt_gt:comp_op(">>");break;
+case eq_eq:comp_op("==");break;
+case lt_lt:comp_op("<<");break;
+case gt_eq:comp_op(">=");break;
+case lt_eq:comp_op("<=");break;
+case not_eq:comp_op("!=");break;
+case and_and:comp_op("&&");break;
+case or_or:comp_op("||");break;/*:52*/
+#line 790 "ctangle.w"
+default:C_putc(c);out_state=no_space;
+if(!line_output)append_white(c);
+}
+}/*:45*//*58:*/
+#line 1012 "ctangle.w"
+eight_bits skip_ahead(void)
+{eight_bits c;
+while(find_char())
+{limit[1]='@';
+while(*loc++ !='@'){}
+if(loc<=limit&&(c=code_of(*loc++))!=ignore)return c;
+}
+return new_section;
+}/*:58*//*59:*/
+#line 1051 "ctangle.w"
+boolean skip_comment(boolean one_liner)
+{char c;
+do
+{if(loc>=limit)
+if(one_liner)return false;
+else if(get_line())return true;
+else
+{err_print("! Input ended in mid-comment");return false;}
+
+if((c= *loc++)=='/'&& *loc=='*')
+err_print("! `/*' inside comment, did you forget `*/' before? ");
+
+if(c=='@')
+{eight_bits cc=code_of(*loc++);
+if(cc==new_section)
+{err_print("! Section ended in mid-comment");loc-=2;return false;}
+
+if(cc==module_name){/*68:*/
+#line 1291 "ctangle.w"
+{boolean file_module=loc[-1]=='(';
+
+cur_mod=get_module_name();
+if(file_module&&cur_mod!=NULL)/*29:*/
+#line 398 "ctangle.w"
+{int i=0;
+while(i<output_file_count)
+if(output_file[i]==cur_mod)break;else++i;
+if(i==output_file_count)
+if(output_file_count==max_files)overflow("output files");
+else output_file[output_file_count++]=cur_mod;
+}/*:29*/
+#line 1296 "ctangle.w"
+}/*:68*/
+#line 1068 "ctangle.w"
+continue;}
+}
+if(!line_output)
+{store_byte(c);
+if(c=='@'&&(c=loc[-1])!='@')store_byte(c);
+}
+}while(c!='*'|| *loc!='/'||one_liner);
+++loc;if(!line_output)store_byte('/');
+return false;
+}/*:59*//*61:*/
+#line 1115 "ctangle.w"
+eight_bits get_next(void)
+{static boolean preprocessing=false;
+static boolean comment_continues=false;
+eight_bits c;
+restart:/*62:*/
+#line 1152 "ctangle.w"
+{if(loc>=limit)
+{if(preprocessing&&limit>buffer&&limit[-1]!='\\')
+preprocessing=false;
+return get_line()?'\n':new_section;
+}
+if(comment_continues
+||(c= *loc++)=='/'&&(*loc=='*'||C_plus_plus&& *loc=='/'))/*63:*/
+#line 1184 "ctangle.w"
+{boolean one_liner=false;
+if(!comment_continues)
+{if(!line_output){store_byte('/');store_byte(*loc);}
+one_liner= *loc++ =='/';
+
+}
+else if(preprocessing)
+{print("\nWarning: Multi-line comment in preprocessor line");
+
+preprocessing=false;mark_harmless();
+}
+if(comment_continues=skip_comment(one_liner))
+
+return '\n';
+else goto restart;
+}/*:63*/
+#line 1162 "ctangle.w"
+if(isspace(c))
+if(line_output)
+if(preprocessing)return ' ';else goto restart;
+
+else return c;
+
+if(c=='#'&&loc==buffer+1)preprocessing=true;
+}/*:62*/
+#line 1123 "ctangle.w"
+if(c=='L'&&(*loc=='\''|| *loc=='\"'))
+{get_string();return constant;}
+if(c<0x80?isalpha(c)||c=='_':translation_exists(c))
+{/*65:*/
+#line 1233 "ctangle.w"
+{id_first= --loc;
+do c= * ++loc;
+while(c<0x80?isalnum(c)||c=='_':translation_exists(c));
+cur_id=
+loc==id_first+1&&(eight_bits)(*id_first)<0x80
+?NULL:id_lookup(id_first,loc,0);
+}/*:65*/
+#line 1126 "ctangle.w"
+return id_code;}
+if(c>=0x80){err_print("! Illegal 8-bit character");goto restart;}
+
+if(isdigit(c)||c=='.'&&isdigit((eight_bits)*loc))
+{/*66:*/
+#line 1250 "ctangle.w"
+{if(*(id_first=loc-1)=='0'&&tolower((eight_bits)*loc)=='x')
+
+do c= * ++loc;while(isxdigit(c));
+else
+{while(isdigit(c))c= *loc++;
+if(c=='.')do c= *loc++;while(isdigit(c));
+if(tolower(c)=='e')
+{if((c= *loc)=='+'||c=='-')c= * ++loc;
+while(isdigit(c))c= * ++loc;
+}
+else--loc;
+}
+while(isalpha(c))c= * ++loc;
+
+id_loc=loc;
+}/*:66*/
+#line 1130 "ctangle.w"
+return constant;}
+switch(c)
+{case '\'':case '"':get_string();return constant;
+case '@':/*67:*/
+#line 1275 "ctangle.w"
+{eight_bits cc=code_of(*loc++);
+switch(cc)
+{case ignore:goto restart;
+case control_text:get_control_text();goto restart;
+case verbatim:if(get_control_text())goto restart;else break;
+case ord:/*69:*/
+#line 1302 "ctangle.w"
+id_first=loc;
+while(*loc!='\'')
+{if(*loc++ =='\\')loc++;
+if(loc>=limit){err_print("! ASCII constant didn't end");break;}
+
+}
+id_loc=loc++;/*:69*/
+#line 1280 "ctangle.w"
+break;
+case module_name:/*68:*/
+#line 1291 "ctangle.w"
+{boolean file_module=loc[-1]=='(';
+
+cur_mod=get_module_name();
+if(file_module&&cur_mod!=NULL)/*29:*/
+#line 398 "ctangle.w"
+{int i=0;
+while(i<output_file_count)
+if(output_file[i]==cur_mod)break;else++i;
+if(i==output_file_count)
+if(output_file_count==max_files)overflow("output files");
+else output_file[output_file_count++]=cur_mod;
+}/*:29*/
+#line 1296 "ctangle.w"
+}/*:68*/
+#line 1283 "ctangle.w"
+}
+return cc;
+}/*:67*//*64:*/
+#line 1217 "ctangle.w"
+case '+':compress('+',plus_plus);break;
+case '-':compress('-',minus_minus);compress('>',minus_gt);break;
+case '=':compress('=',eq_eq);break;
+case '>':compress('=',gt_eq);compress('>',gt_gt);break;
+case '<':compress('=',lt_eq);compress('<',lt_lt);break;
+case '&':compress('&',and_and);break;
+case '|':compress('|',or_or);break;
+case '!':compress('=',not_eq);break;/*:64*/
+#line 1137 "ctangle.w"
+}
+return c;
+}/*:61*//*71:*/
+#line 1367 "ctangle.w"
+void scan_repl(eight_bits context)
+{eight_bits a;
+eight_bits*keep=tok_ptr;
+int brace_level=0,par_level=0;
+if(context==section_body)/*81:*/
+#line 1612 "ctangle.w"
+{if(mark_line()){a=new_section;goto done;}}/*:81*/
+#line 1373 "ctangle.w"
+do/*72:*/
+#line 1388 "ctangle.w"
+{switch(a=get_next())
+{/*75:*/
+#line 1459 "ctangle.w"
+case id_code:/*76:*/
+#line 1496 "ctangle.w"
+if(cur_id==NULL)store_byte(*id_first);
+else store_two_bytes(0x8000+id_index(cur_id));/*:76*/
+#line 1460 "ctangle.w"
+keep=tok_ptr;continue;
+case module_name:if(context==preproc_directive)goto done;
+if(cur_mod!=NULL)
+{sixteen_bits n=mod_index(cur_mod);/*77:*/
+#line 1508 "ctangle.w"
+{char*p=loc;
+while(*p==' '&&p<limit)++p;
+if(*p=='+')++p;
+if(*p=='=')
+err_print
+("! Illegal defining occurrence of module name; did you forget `@ '?");
+
+}/*:77*/
+#line 1465 "ctangle.w"
+if(line_output)tok_ptr=keep;
+store_two_bytes(0xA800+n);keep=tok_ptr;/*81:*/
+#line 1612 "ctangle.w"
+{if(mark_line()){a=new_section;goto done;}}/*:81*/
+#line 1469 "ctangle.w"
+
+}
+continue;
+case constant:case verbatim:/*78:*/
+#line 1530 "ctangle.w"
+if(id_loc==id_first+1)store_byte(*id_first);
+else
+{store_byte(verb_quote);
+do
+if(*id_first==verb_quote)
+{++id_first;store_byte('\\');store_byte('0'+(verb_quote>>6));
+store_byte('0'+((verb_quote>>3)&7));store_byte('0'+(verb_quote&7));
+}
+else
+{if((eight_bits)(*id_first)>=0x80)store_byte(0xF8);
+
+store_byte(*id_first++);
+}
+while(id_first<id_loc);
+store_byte(verb_quote);
+if(context==section_body&&print_where)/*81:*/
+#line 1612 "ctangle.w"
+{if(mark_line()){a=new_section;goto done;}}/*:81*/
+#line 1547 "ctangle.w"
+}/*:78*/
+#line 1473 "ctangle.w"
+keep=tok_ptr;
+continue;
+case ord:/*79:*/
+#line 1559 "ctangle.w"
+{int c= *id_first++;
+if(c=='@'&& *id_first++ !='@')
+{err_print("! Double `@' should be used in ASCII constant");
+
+--id_first;
+}
+if(c=='\\')
+{c= *id_first++;
+switch(c)
+{case 't':c='\011';break;
+case 'n':c='\012';break;
+case 'b':c='\010';break;
+case 'f':c='\014';break;
+case 'v':c='\013';break;
+case 'r':c='\015';break;
+case '0':c='\0';break;
+case '\\':c='\134';break;
+case '\'':c='\047';break;
+case '\"':c='\042';break;
+default:err_print("! Unrecognised escape sequence");
+
+}
+}
+else
+{
+}
+if(id_first!=id_loc)
+if(id_loc>id_first)
+err_print("! ASCII constant should be single character");
+
+else{err_print("! Empty ASCII constant");c=0;}
+
+store_byte(verb_quote);
+if(c>=100)store_byte('0'+c/100);if(c>=10)store_byte('0'+(c/10)%10);
+store_byte('0'+c%10);
+store_byte(verb_quote);
+}/*:79*/
+#line 1476 "ctangle.w"
+keep=tok_ptr;continue;
+case include_preproc:
+if(context==preproc_directive)
+err_print("! `@p' is forbidden in preprocessor directive");
+
+else
+{if(line_output)tok_ptr=keep;
+store_byte(0xFA);atp_seen=true;keep=tok_ptr;/*81:*/
+#line 1612 "ctangle.w"
+{if(mark_line()){a=new_section;goto done;}}/*:81*/
+#line 1485 "ctangle.w"
+}
+continue;
+case char_trans:
+err_print("! `@l' is only allowed in limbo");
+
+continue;/*:75*/
+#line 1394 "ctangle.w"
+case format:case definition:case header:case begin_C:
+if(context==preproc_directive)goto done;
+err_print
+("! `@f', `@d', `@h', and `@c' are ignored in section body");
+
+continue;
+case new_section:goto done;/*73:*/
+#line 1420 "ctangle.w"
+case '(':++par_level;break;
+case ')':
+if(par_level<=0)
+{err_print("! Unmatched closing parenthesis");continue;}
+
+--par_level;break;
+case '{':++brace_level;break;
+case '}':
+if(brace_level<=0)
+{err_print("! Unmatched closing brace");continue;}
+--brace_level;break;/*:73*/
+#line 1402 "ctangle.w"
+case '\n':store_byte('\n');
+if(context==section_body&&print_where)
+{tok_ptr=keep;/*81:*/
+#line 1612 "ctangle.w"
+{if(mark_line()){a=new_section;goto done;}}/*:81*/
+#line 1406 "ctangle.w"
+}
+continue;
+case join_code:a=join;
+}
+store_byte(a);keep=tok_ptr;
+}/*:72*/
+#line 1375 "ctangle.w"
+while(true);
+done:tok_ptr=keep;
+next_control=a;
+if(par_level>0||brace_level>0)/*74:*/
+#line 1439 "ctangle.w"
+{char*p,*s;int l;
+if(par_level>0)l=par_level,s="parenthes",p=l>1?"es":"is";
+else l=brace_level,s="brace",p=l>1?"s":"";
+print("\n! There %s %d unclosed %s%s"
+,par_level+brace_level>1?"are":"is",l,s,p);
+
+if(par_level>0&&brace_level>0)
+print(" and %d unclosed brace%s"
+,brace_level,brace_level>1?"s":"");
+print(" in the previous ");
+err_print(context==preproc_directive?"macro":"section");
+while(--par_level>=0)store_byte(')');
+while(--brace_level>=0)store_byte('}');
+}/*:74*//*19:*/
+#line 166 "ctangle.w"
+{cur_text=text_ptr++;
+if(text_ptr>=text_table_end)overflow("text");
+tok_begin(text_ptr)=tok_ptr;
+}/*:19*/
+#line 1381 "ctangle.w"
+}/*:71*//*82:*/
+#line 1627 "ctangle.w"
+boolean mark_line(void)
+{while(loc>=limit)
+if(!get_line())return true;
+print_where=false;
+if(line_output)
+{store_byte(0xF9);
+id_first=changing?change.name:cur_file_name;
+store_two_bytes(changing?change_line:cur_line);
+store_two_bytes(id_index(id_lookup(id_first,NULL,0)));
+}
+return false;
+}/*:82*//*83:*/
+#line 1648 "ctangle.w"
+void scan_section(void)
+{++section_count;
+if(loc[-1]=='*')print_section_progress();/*84:*/
+#line 1668 "ctangle.w"
+{next_control=ignore;
+do
+{if(next_control<definition)
+{if((next_control=skip_ahead())==module_name)
+{loc-=2;get_next();}
+
+}
+else if(next_control==definition)
+{/*85:*/
+#line 1694 "ctangle.w"
+{do next_control=get_next();
+while(line_output?next_control=='\n'
+:next_control<0x80&&isspace(next_control));
+if(next_control!=id_code)
+{err_print("! Macro definition ignored, must start with identifier");
+
+continue;
+}/*76:*/
+#line 1496 "ctangle.w"
+if(cur_id==NULL)store_byte(*id_first);
+else store_two_bytes(0x8000+id_index(cur_id));/*:76*/
+#line 1703 "ctangle.w"
+if(isspace((eight_bits)*loc))store_byte(' ');
+
+}/*:85*/
+#line 1677 "ctangle.w"
+scan_repl(preproc_directive);
+cur_text->text_link=macro_flag;
+}
+else
+{scan_repl(preproc_directive);cur_text->text_link=header_flag;}
+if(next_control==module_name)/*86:*/
+#line 1718 "ctangle.w"
+{eight_bits t=get_next();
+if(t=='+')t=get_next();
+if(t!='='&&t!=eq_eq)
+{next_control=ignore;
+if(t!='|'&&!compatibility_mode)
+err_print("! `=' sign missing, module name ignored");
+
+}
+}/*:86*/
+#line 1684 "ctangle.w"
+}while(next_control<begin_C);
+}/*:84*//*87:*/
+#line 1733 "ctangle.w"
+{mod_pointer p;
+switch(next_control)
+{default:return;
+case begin_C:p=NULL;break;
+case module_name:p=cur_mod;
+}
+store_two_bytes(0xD000+section_count);
+scan_repl(section_body);/*88:*/
+#line 1753 "ctangle.w"
+{if(p==NULL)
+{*last_unnamed=cur_text;last_unnamed= &cur_text->text_link;}
+else
+{text_pointer*q= &p->equiv;
+while(*q!=NULL)q= &(*q)->text_link;
+*q=cur_text;
+}
+cur_text->text_link=NULL;
+
+}/*:88*/
+#line 1744 "ctangle.w"
+}/*:87*/
+#line 1653 "ctangle.w"
+}/*:83*//*90:*/
+#line 1777 "ctangle.w"
+void phase_one(void)
+{phase=1;section_count=0;reset_input();
+while((next_control=skip_ahead())!=new_section)
+if(next_control==char_trans)/*91:*/
+#line 1791 "ctangle.w"
+{int c;
+while(loc<limit&&isspace((eight_bits)*loc))++loc;
+if(!(isxdigit((eight_bits)loc[0])&&
+isxdigit((eight_bits)loc[1])&&
+isspace((eight_bits)loc[2])))
+err_print("! Two-digit hex number and space should follow `@l'");
+
+else if(sscanf(loc,"%x",&c),c<0x80)
+err_print("! You cannot translate characters < 0x80");
+
+else
+{char*p=trans_of(c);int i=0;
+loc+=3;
+while(find_char()&&isspace((eight_bits)*loc))++loc;
+if(!input_has_ended)
+while(isalnum((eight_bits)*loc)|| *loc=='_')
+if(++i<=trans_limit)*p++= *loc++;else break;
+if(i>0)*p='\0';/*92:*/
+#line 1824 "ctangle.w"
+if(i==0)err_print("! Translation string absent after `@l'");
+
+else if(i>trans_limit)err_print("! Translation string too long");
+else if(!isspace((eight_bits)*loc))
+err_print("! Translation string not terminated by space");/*:92*/
+#line 1810 "ctangle.w"
+}
+}/*:91*/
+#line 1781 "ctangle.w"
+while(!input_has_ended)scan_section();
+check_complete();
+}/*:90*//*93:*/
+#line 1838 "ctangle.w"
+#ifdef STAT
+void print_stats(void)
+{print("\nMemory usage statistics:\n");
+report("identifier",id_index(id_ptr),max_idents);
+report("module name",mod_index(mod_ptr),max_modules);
+report("byte",byte_ptr-byte_mem,max_bytes);
+report("replacement text",text_ptr-text_table,max_texts);
+report("token",tok_ptr-tok_mem,max_toks);
+}
+#endif/*:93*/
diff --git a/web/c_cpp/cwebx/ctangle.w b/web/c_cpp/cwebx/ctangle.w
new file mode 100644
index 0000000000..5c0eb7a813
--- /dev/null
+++ b/web/c_cpp/cwebx/ctangle.w
@@ -0,0 +1,1856 @@
+% This file is part of CWEBx.
+% This program by Marc van Leeuwen based on earlier versions by
+% D. E. Knuth., Silvio Levy and Frank Jensen.
+% It is distributed WITHOUT ANY WARRANTY, express or implied.
+% CWEB (Revision: 2.0) % Don Knuth, July 1990
+% Version 3.x, Marc van Leeuwen, December 1993
+% CWEBx 2+1.0, Marc van Leeuwen, August 1994
+% CWEBx 3.0, Marc van Leeuwen, Januari 1995
+% CWEBx 3.02, Marc van Leeuwen, April 1996
+% CWEBx 3.02a, Marc van Leeuwen, September 1996
+% CWEBx 3.03, Marc van Leeuwen, January 1998 (ctangle unchanged)
+
+% Copyright (C) 1987,1990 Silvio Levy and Donald E. Knuth
+% Copyright 1994 Marc A. A. van Leeuwen
+
+% Permission is granted to make and distribute verbatim copies of this
+% document provided that the copyright notice and this permission notice
+% are preserved on all copies.
+
+% Permission is granted to copy and distribute modified versions of this
+% document 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.
+
+\def\me.{CTANGLE} \def\myroots{\.{TANGLE}}
+
+% Here is TeX material that gets inserted after \input cwebxmac
+\def\ASCII.{\caps{ASCII}}
+
+@i intro.inc % Here is some text that matches the start of CWEAVE
+
+@d banner "This is CTANGLE (Version x"@+version_string@+")\n"
+
+@ The following parameters are specific to \.{CTANGLE}; those which are
+common to \.{CTANGLE} and \.{CWEAVE} are defined in the file \.{common.inc}
+and appear below. Some of these values have been decreased with respect to
+their earlier values which were sufficient in the original \.{WEB} to handle
+\TeX; a motivation is given at the common declarations. The macro |variant|
+is used in the include file \.{common.h}, and should therefore be defined
+early; it refers to the |struct text| that will be declared later.
+
+@d max_toks 150000L /* number of bytes in compressed \Cee~code */
+@d max_texts 2500 /* number of replacement texts, must be less than 10240 */
+@d max_files 50 /* number of auxiliary output files */
+@d stack_size_max 50 /* module nesting level during output */
+@d max_indent 1000 /* size of buffer for save indentation characters */
+@)
+@d variant @;text
+
+@ The program is built from two compilation units, one with source file
+\.{common.w}, which contains a collection of routines and data shared
+between \.{CTANGLE} and \.{CWEAVE}, and a second with source file
+\.{ctangle.w} containing all code specific to \.{\me.}, and whose
+typeset version you are now reading. All compilation units of the \.{CWEB}
+system incorporate the file \.{common.inc} containing common declarations.
+
+\.{\me.} has a fairly straightforward outline. It operates in
+two phases: first it reads the source file, saving the \Cee~code in
+compressed form; then outputs the code, after shuffling it around.
+It can optionally be compiled with the preprocessor symbol |STAT| defined,
+in which case it will keep track of how much of \.{\me.}'s resources
+were actually used. One command line argument is specifically designated to
+modify the behaviour of \.{\me.}. Normally \.{\me.} will produce
+machine-oriented output that supplies \&{\#line} directives (to allow
+compilers and debuggers to locate the original source lines of statements),
+while preserving line breaks but otherwise ignoring the lay-out and comments
+in the source text. When the flag `\.{-l}' is supplied on the command line
+however, the output cannot be traced back easily to the source lines, but
+will be easier for humans to read: no \&{\#line} directives are produced,
+but original lay-out and comments are preserved as well as possible. The
+flag controlling this behaviour is called |line_output|; in the standard
+mode of operation we have |line_output==true|.
+
+@d line_output flags['l']
+@c
+@< Function prototypes used but not defined in the shared code @>@;
+@< Typedef and enumeration declarations @>@;
+@< Prototypes @>@;
+@< Global variables @>@;
+
+int main (int argc, char** argv)
+{ program=ctangle;
+ line_output=true;
+ common_init(argc,argv);
+ @<Set initial values@>
+ if (show_banner) print(banner); /* print a ``banner line'' */
+ phase_one(); /* read all the user's text and compress it into |tok_mem| */
+ phase_two(); /* output the contents of the compressed tables */
+ wrap_up(); /* and exit gracefully */
+ return 0;
+}
+
+@i common.inc
+
+
+@* Data structures exclusive to {\tt \me.}.
+The basic mission of \.{\me.} is a relatively simple one, namely to
+separate the \Cee~code from the commentary, to forget about the latter, and
+to output the former almost verbatim, but plugging in the program text
+corresponding to a module each time a reference is made. To this end the
+bodies of all the sections are collected during Phase~I, and the proper
+links are laid, after which the code is linearised for output in a
+straightforward manner during Phase~II.
+
+The \Cee~code itself will be stored as a sequence of bytes (more precisely,
+of |eight_bits|) in a single large array |tok_mem|, much in the same way as
+the characters for identifiers and module names are stored in |byte_mem|;
+the encoding used will be described below. The individual sections are
+represented by structures of type |text|, which contain pointers to the
+|tok_mem| array as well as links by which they may be connected into lists;
+the same structures are also used to represent the replacement texts of
+macros. All |text| structures reside in an array |text_table|, which is
+comparable to |id_table| and |mod_table|.
+
+@<Typedef...@>=
+typedef struct text
+{ eight_bits* tok_start; /* pointer into |tok_mem| */
+ struct text* text_link; /* relates replacement texts */
+} text,* text_pointer;
+
+@ Since all allocation is during Phase~I and all deallocation during
+Phase~II, there is no reason for reclaiming memory when it is no longer
+needed. Hence allocation is strictly linear, and a single pointer into
+|tok_mem| for each |text| suffices, since a texts ends where the next one
+starts. The first position of |tok_mem| that is unoccupied by a replacement
+text is called |tok_ptr|, and the first unused location of |text_table| is
+called |text_ptr|. Whenever we are not in the process of adding tokens to
+|tok_mem|, we have the identity |tok_begin(text_ptr)==tok_ptr|.
+
+@d tok_begin(p) (p)->tok_start
+@d tok_end(p) ((p)+1)->tok_start
+@d text_table_end (&text_table[max_texts])
+@d tok_mem_end (&tok_mem[max_toks])
+
+@<Glob...@>=
+text text_table[max_texts];
+text_pointer text_ptr=&text_table[0]; /* first unused position in |text_table| */
+eight_bits tok_mem[max_toks];
+eight_bits *tok_ptr=&tok_mem[0]; /* first unused position in |tok_mem| */
+
+@ Invariants must be initialised.
+
+@<Set init...@>=
+tok_begin(text_ptr)=tok_ptr;
+
+@ The following macro and function are used to enter one- and two-byte
+tokens into |tok_mem| when a replacement text is being generated.
+
+@d store_byte(c) @+
+if (tok_ptr==tok_mem_end) overflow("token"); @+ else *tok_ptr++=c@;
+
+@c
+void store_two_bytes (sixteen_bits x)
+{ if (tok_ptr+2>tok_mem_end) overflow("token");
+ *tok_ptr++ = x >> 8; /* store high byte */
+ *tok_ptr++ = x & 0xFF; /* store low byte */
+}
+
+@ When by successive calls of |store_byte| and |store_two_bytes| a complete
+replacement text has been stored, the following code makes it into an
+official text object by advancing |text_ptr| and storing the starting
+location of the next text to be generated into the |text_table| array.
+
+@< Wrap up the accumulated bytes into a completed text,
+ pointed to by |cur_text| @>=
+{ cur_text=text_ptr++; /* consolidate the replacement text */
+ if (text_ptr>=text_table_end) overflow("text");
+ tok_begin(text_ptr)=tok_ptr; /* mark end of replacement text */
+}
+
+@ The |text_link| field links a section to a possible continuation of it (the
+next section with the same name, or for unnamed sections the next unnamed
+section). The set of all sections linked together in such a way will be termed
+a `module'. Apart from the value |NULL| used to indicate the end of such a
+list, we need two other distinguished values: |macro_flag|, which indicates
+that the text is a macro replacement text rather than a section body, and
+|header_flag| similarly indicating that the text is the (quoted) file name
+of a header file that is included. By a fortunate coincidence, there are two
+unused pointer values near the end of |text_table|: since the macro |tok_end|
+should work for all pointers to a replacement text, the last entry of
+|text_table| is never used to store a replacement text; its address can be
+used as one reserved pointer value, and the definition of~\Cee\ generously
+offers us the address of the non-existent entry following it as another
+valid pointer value. The pointer to the first section of the unnamed module
+appears in |text_root|, and the address of the final link of this module is
+recorded in |last_unnamed|. The named modules are accessed by the extra
+pointer in the |mod_info| structure for a module name, which is a
+|text_pointer| pointing to the body of the first section of that module;
+in~\.{\me.} this field will be called |equiv|.
+
+@d macro_flag (text_table_end-1) /* address of unused entry */
+@d header_flag text_table_end /* address just beyond |text_table| */
+@d next_sec(m) ((m)->text_link) /* next section of the same module, if any */
+@d equiv equiv_or_xref /* info corresponding to names */
+
+@<Glob...@>=
+text_pointer text_root=NULL;
+text_pointer* last_unnamed=&text_root; /* where to link new unnamed sections */
+
+@ Here are the functions specific to \.{\me.}, which are used by the
+common lookup routines. The function |names_match| decides whether a name of
+length~|l| starting at position |q| equals the identifier represented
+by~|x|. The parameter |dummy| is present only for compatibility with
+\.{CWEAVE}, where it contains the |ilk| code. The common lookup routines
+refer to separate routines |init_module_name| and |init_id_name| when the
+data structure grows. Actually |init_id_name| is called only when
+|program==cweave|, but we need to declare a dummy version so that the linker
+won't complain about its absence.
+
+@c
+boolean names_match (id_pointer x,char* q,int l,int dummy)
+{@; char* p=name_begin(x); while (--l>=0) if (*p++!=*q++) return false;
+ return *p=='\0';
+}
+
+void init_module_name(mod_pointer node)
+@+{@; node->equiv=NULL; }
+
+void init_id_name (id_pointer dummy,int ilk) @+ {}
+
+
+@* Tokens.
+Clearly, \.{\me.} must hold all the code for a complete program file at
+the end of Phase~I (not counting the possible multiple use of some modules,
+which will probably not make a great difference), and so it is worth while
+to use a compact representation for the internal storage of the \Cee~code.
+Using full-fledged data compression techniques would probably be overdoing
+things a bit, but a few simple methods will make a great difference. There
+are likely to be many identical occurrences of identifiers and keywords of
+the language, so it is efficient to collect them into a table and replace
+them in the internal format by references to the table; module names have
+to be entered in a table anyway for the purpose of associating occurrences
+of the same name with each other. Furthermore white space and comments can
+be removed upon storing the texts; any necessary white space can be
+reinserted during the output process (but note that newlines must be
+represented internally, in order to be able to match output lines with
+input lines).
+
+@ These compressed texts representing \Cee~code, while physically
+represented as a sequence of eight-bit bytes in |tok_mem|, logically consist
+of streams of `tokens', some of which occupy two or more consecutive byte
+positions, while others take just one byte. If the first byte is |a| and,
+in case |a>=0x80|, the next byte is~|b|, then the interpretation of the
+token is as follows.
+
+\Y
+\item{$\bullet$} |0<=a<0x80|: the token represents the character~|a|;
+\item{$\bullet$} |0x80<=a<0xA8|: the two-byte token represents the
+ identifier with name |id_at((a-0x80)*@t$2^8$@>+b)|;
+\item{$\bullet$} |0xA8<=a<0xD0|: the two-byte token represents the module
+ with name |mod_at((a-0xA8)*@t$2^8$@>+b)|;
+\item{$\bullet$} |0xD0<=a<0xF8|: this two-byte token marks the beginning of
+ (a part of) the repacement text for the current module, defined in section
+ number |(a-0xD0)*@t$2^8$@>+b|;
+\item{$\bullet$} |a==0xF8|: the two-byte token represents the (8-bit)
+ character~|b|.
+\item{$\bullet$} |a==0xF9|: the token consists of 5 bytes, say |a|,~|b|,
+ |c|, |d| and~|e|, and represents a \&{\#line} directive for line number
+ |b*@t$2^8$@>+c| in the file |id_at(d*@t$2^8$@>+e)|.
+\item{$\bullet$} |a==0xFA|: the token consists of a single byte, and
+ represents the location, indicated by the \:p control codes in the source
+ file, where the preprocessor directives produced by \:d and \:h will be
+ included in the output; this location will be marked by the presence of
+ the virtual module called `|@p|' in the typeset output.
+\Y
+
+Any \Cee~token that consists of a single 7-bit character is represented by
+that character itself; in particular, a single-character identifier like
+`|x|' will be a one-byte token, while all longer identifiers will occupy two
+bytes. Some of the 7-bit codes will not be present however, since they are
+control codes and they do not represent a symbol useful for \Cee\ in the
+\caps{MIT} extension of \ASCII., so we can use them for special purposes.
+The following symbolic names are used:
+
+\yskip
+\hang |join| denotes the concatenation of adjacent items with no space or
+ line breaks allowed between them (the \:\& operation of \.{CWEB}).
+
+\hang |verb_quote| denotes the beginning or end of a sequence of bytes that
+ is to be copied verbatim to the output, i.e., no spaces should be inserted.
+ Such sequences are used to transmit numerical constants and strings (in
+ which case the ordinary string quotes appear within the |verb_quote|
+ bytes), and to implement the \:= operation.
+
+@^ASCII code dependencies@>
+
+@d verb_quote 0x2 /* takes the place of extended \ASCII. \.{\char2} */
+@d join 0x3 /* takes the place of extended \ASCII. \.{\char3} */
+
+@< Global var... @>=
+boolean atp_seen=false; /* whether \:p occurs anywhere */
+
+
+@* Phase II processing.
+We will start to explain the structure of the tokens lists built up in
+memory by considering how they are output during Phase~II; this is the
+simpler part of the program. We will proceed in top-down fashion for this
+part.
+
+@<Prototypes@>=
+void phase_two (void); /* output the contents of the compressed tables */
+void output (text_pointer); /* recursively write out modules */
+void output_preproc_directives(void); /* write out all \:d and \:h stuff */
+void C_newline (void); /* send a newline to the \Cee~file */
+void out_char (eight_bits); /* write a single token */
+
+@ Here is the general control routine. After Phase~I, the quantity
+|output_file_count| will be equal to the number of extra output files to be
+written. There should at least be either an unnamed section or one that
+produces an additional output file, for otherwise there will be no output at
+all; if the is no unnamed section, \:d~and~\:h commands will only have
+effect if \:p occurs somewhere.
+
+@c void phase_two (void)
+{ phase=2;
+ if (text_root==NULL && output_file_count==0)
+ @/{@; print("\n! No program text was specified."); mark_harmless(); }
+ @.No program text...@>
+ else
+ { if (show_progress)
+ { print("\nWriting the output file%s" @.Writing the output...@>
+ ,(text_root!=NULL)+output_file_count>1 ? "s" : "");
+ if (text_root!=NULL) printf(" (%s):",C_file_name);
+ update_terminal();
+ }
+ if (text_root==NULL) C_file=NULL;
+ else
+ { open_output_file(); cur_line=1;
+ if (!atp_seen) output_preproc_directives();
+ output(text_root);
+ }
+ @<Write all the named output files@>
+ print_progress("\nDone.\n");
+ }
+}
+
+@ \.{\me.} can write output on multiple files. If a module name is
+introduced in at least one place by \:( instead of \:<, it is treated as the
+name of a file. All these special module names are saved in the array
+|output_files|.
+
+@<Glob...@>=
+mod_pointer output_file[max_files];
+int output_file_count=0;
+
+@ To write the named output files, we proceed as for the unnamed module, the
+only subtlety is that we have to open each one after closing the previous
+one. However, if there is no main file, there is no file to close the first
+time, and this situation can be recognised because we have set |C_file=NULL|
+in that case. The length of a module name can be at most |longest_name|
+(which is rather more generous than allowed elsewhere for file names), so we
+need no test for overflowing |output_file_name|.
+
+@<Write all the named output files@>=
+{ int i;
+ char output_file_name[longest_name+1]; /* name of the file */
+ for (i=0; i<output_file_count; i++)
+ { mod_pointer output_module=output_file[i];
+ @< Copy name of |output_module| into |output_file_name| @>
+ if (C_file!=NULL) fclose(C_file);
+ if (output_module->equiv==NULL)
+ @/{@; print("\n! Module not present");
+ @.Module not present@>
+ print_mod(output_module); err_print("");
+ }
+ else if ((C_file=fopen(output_file_name,"w"))==NULL)
+ @/{@; print("\n! Cannot open \"%s\" as output file",output_file_name);
+ @.Cannot open output file@>
+ err_print("");
+ }
+ else
+ { if (show_progress) print("\n(%s):",output_file_name);
+ cur_line=1;
+ output(output_module->equiv);
+ }
+ }
+}
+
+@ If the module name defining the output file contains any occurrences of
+`\.{@@@@}', they are undoubled in forming the actual file name; apart from
+this should be no control codes in the module name.
+
+@< Copy name of |output_module| into |output_file_name| @>=
+{ char* p=output_file_name, *q=name_begin(output_module);
+ while (*q!='\0')
+ if ((*p++=*q++)=='@@')
+ if (*q++!='@@')
+ { print("\n! Illegal control code in file name");
+ @.Illegal control code in file name@>
+ print_mod(output_module); err_print("");
+ }
+ *p='\0';
+}
+
+@ Here is how a file name gets added to the list of output files.
+
+@<Adjoin |cur_mod| to the set of output files@>=
+{ int i=0;
+ while(i<output_file_count)
+ if (output_file[i]==cur_mod) break; @+ else ++i;
+ if (i==output_file_count) /* if not present, add |cur_mod| */
+ if (output_file_count==max_files) overflow ("output files");
+ else output_file[output_file_count++]=cur_mod;
+}
+
+
+@* Writing replacement texts.
+We now come to the functions |output| and |output_preproc_directives|; the
+task of the former is a recursive one, and it may also call the latter if
+\:p occurs. The function |output| is not recursive, however, but it uses a
+stack to keep track of what is going on at different ``levels'' as the
+sections are being written out. Entries on this stack have five parts:
+
+\yskip
+
+\hang |repl_field| points to replacement text of the active section;
+
+\hang |byte_field| is the |tok_mem| location from which the next token
+ on a particular level will be read;
+
+\hang |end_field| is the |tok_mem| location where the replacement
+ text of a particular level will end;
+
+\hang |sec_nr_field| is the section number.
+
+\hang |indent_field| determines the amount of indentation, for in case
+ |line_output==false|
+
+\yskip\noindent
+The current values of these quantities are referred to quite frequently, so
+they are stored in a separate place instead of in the |stack| array. We call
+the current values |cur_byte|, |cur_end|, |cur_repl|, |cur_sec| and
+|cur_ind|.
+
+@d cur_repl cur_state.repl_field
+@d cur_byte cur_state.byte_field
+@d cur_end cur_state.end_field
+@d cur_sec cur_state.sec_nr_field
+@d cur_ind cur_state.indent_field
+
+@<Typedef...@>=
+typedef struct
+{ text_pointer repl_field; /* replacement text of active section */
+ eight_bits *byte_field; /* present location within replacement text */
+ eight_bits *end_field; /* ending location of replacement text */
+ sixteen_bits sec_nr_field; /* section number */
+ sixteen_bits indent_field; /* amount of indentation */
+} output_state, * stack_pointer;
+
+@ The global variable |stack_ptr| tells how many levels of output are
+currently in progress; the stack grows upwards with |stack_ptr| pointing to
+the first vacant location above the top of the stack. The entry |stack[0]|
+at the bottom of the stack is not used; when |stack_ptr| points to it then
+|cur_state| itself has become invalid and the output process is completed;
+this condition can be tested as |stack_empty()|. This somewhat strange use of
+the stack is forced upon us because the \Cee\ language does not guarantee
+that a pointer value at offset~$-1$ of an allocated array exists. Since the
+location |stack[0]| is vacant we might as well use it to store |cur_state|
+in.
+
+@d cur_state stack[0]
+@d stack_end (&stack[stack_size_max])
+@d stack_empty() (stack_ptr==&stack[0])
+
+@<Global...@>=
+output_state stack[stack_size_max]; /* info for non-current levels */
+stack_pointer stack_ptr; /* points above top of output state stack */
+
+@ When |line_output==false| we keep track of the current indentation level
+in an array of white space characters |indent_buffer|. Every time a newline
+is output, a sequence of |cur_ind| characters from |indent_buffer| are also
+output by invoking |put_indent|. When relevant non-newline characters are
+output, a white space counterpart of the character is appended to
+|indent_buffer| by invoking the macro |append_white|, whose argument should
+not involve any side effects. The current position of writing the characters
+is maintained in |ind_i|, and reset to |cur_ind| on output of a newline.
+
+@d C_printf(format,x) fprintf(C_file,format,x)
+@d C_putc(c) putc(c,C_file)
+@d put_indent()
+ (indent_buffer[ind_i=cur_ind]='\0',C_printf("%s",indent_buffer))
+@d append_white(c)
+ if (ind_i>=max_indent) overflow("indent buffer");
+ else indent_buffer[ind_i++]= isspace(c) ? c : ' ' @;
+@< Global var... @>=
+char indent_buffer[max_indent];
+ /* white space characters to produce indentation */
+sixteen_bits ind_i;
+ /* number of those characters needed to reach current position */
+
+@ When the replacement text for name |p| is to be inserted into the output,
+the following function is called to save the old level of output and get
+the new one going. The value of |cur_sec| is not set since its value is
+recorded in the first token to be read after this function is called. It is
+by calling |push_level| that the current value of |ind_i| becomes
+significant, by being copied to |cur_ind|.
+
+@c
+void push_level (mod_pointer p) /* suspends the current level */
+{ if (stack_ptr==stack_end) overflow("output stack");
+ *stack_ptr++=cur_state;
+@/cur_repl=p->equiv;
+ cur_byte=tok_begin(cur_repl); cur_end=tok_end(cur_repl);
+@/cur_ind=ind_i;
+}
+
+@ When we come to the end of a replacement text, the function
+|continue_or_pop_level| does what its name suggests: it either moves to the
+continuation of this replacement text (i.e., to the next section of the same
+module) or returns the state to the most recently stacked level when a
+module is completed. In the latter case all the fields of |cur_state| are
+restored; in the former case, like for |push_level|, the value of |cur_sec|
+is not yet set, but will be adjusted immediately afterwards.
+
+@c
+void continue_or_pop_level (void)
+{ if (cur_repl->text_link != NULL)
+ /* then link to a continuation, staying on the same level */
+ {@; cur_repl=next_sec(cur_repl);
+ cur_byte=tok_begin(cur_repl); cur_end=tok_end(cur_repl);
+ }
+ else if (--stack_ptr > &stack[0]) cur_state=*stack_ptr;
+ /* otherwise |stack_empty()| holds */
+ ind_i=cur_ind; /* reset indentation to base of current level */
+}
+
+@ The function |output| handles output of tokens by sending them to a lower
+level function |out_char|, until the condition |stack_empty()| holds. The
+task of |output| is to isolate and decode tokens, to handle stacking and
+unstacking as necessary, and to issue special calls to |out_char| to mark
+the beginning and end of replacements texts and to produce appropriate
+\&{\#line} directives. As its name suggests, |out_char| usually handles the
+output of single characters, but some special codes will make it perform a
+few other operations. Some of these, like |verb_quote| and compressed
+operator codes occur, as bytes with values below |0x80| inside the
+replacements texts, and these get no special treatment by |output|. A few
+other ones are generated explicitly by |output|, and these have values from
+|0x80| upwards, defined in the enumeration below. Information about the
+precise value of two-byte tokens is passed to |out_char| via the global
+variable |cur_val|.
+
+@<Global...@>=
+int cur_val; /* additional information corresponding to output token */
+
+@~The code |identifier| is used for identifiers of length two or more, in
+which case |cur_val| indicates the identifier name. The codes
+|section_start| or |section_end| are sent at the beginning and end of parts
+of the replacement text defined in a one section, in which case |cur_val| is
+the section number; this number will be recorded in a comment to aid human
+readers of the \Cee~file produced. When a \&{\#line} directive is to be
+output, |line_mark| is sent to |out_char|, which will fetch the following
+4~bytes (specifying the line number and file name) from the replacement text
+itself; this is the only occasion where |output| does not read a complete
+token before calling |out_char|. Any 8-bit characters that were escaped by a
+byte `|0xF8|' are sent directly to |out_char|; they do not interfere with
+the codes below since the input routine guarantees that they only occur
+between |verb_quote| tokens, at which times |out_char| does not honour any
+special codes.
+
+@< Typedef and enumeration... @>=
+enum {identifier=0x80, section_start, section_end, line_mark };
+
+@ Due to the output stack operations, the function |output| can be written
+iteratively rather than recursively. A user who is not afraid of recursion
+may however easily rewrite this code into a recursive form, and dispose of
+the output stack and its routines altogether; the recursion depth will be
+equal to the level of nesting of modules, which is not likely to cause any
+problems in practice. We have retained the iterative version out of
+reverence for the author of the original |WEB| system; it has the
+additional advantage that, should there be a cycle in the directed graph of
+module references, a reasonable overflow message will be produced by
+|push_level|, whereas otherwise system stack overflow would occur, and it
+would depend on the \Cee~runtime support whether it is properly detected.
+
+@c
+void output (text_pointer repl) /* sends tokens to |out_char| */
+{ stack_ptr=&stack[1];
+@/cur_repl=repl; cur_byte=tok_begin(cur_repl); cur_end=tok_end(cur_repl);
+ cur_ind=ind_i=0;
+ do
+ if (cur_byte==cur_end)
+ { cur_val=cur_sec;
+ continue_or_pop_level();
+ out_char(section_end); /* output ending section number comment */
+ }
+ else
+ @< Output the token starting at |*cur_byte|, advancing |cur_byte|
+ correspondingly @>
+ while(!stack_empty());
+ C_newline();
+}
+
+@ Most tokens lead to calling |out_char| with an appropriate value, after
+possibly setting |cur_val| and |cur_sec|. Exceptions are module names, which
+will push their replacement text on the stack but not produce any direct
+output, and tokens |0xFA| which will produce the collected preprocessor
+directives by calling |output_preproc_directives|, after ensuring that this
+will start on a fresh line of output.
+
+@< Output the token starting at |*cur_byte|... @>=
+{ int a = *cur_byte++;
+ if (a<0x80) out_char(a); /* single byte token */
+ else if (a>=0xF8)
+ if (a<0xFA) out_char(a==0xF8 ? *cur_byte++ : line_mark);
+ else {@; C_newline(); output_preproc_directives(); } /* |a==0xFA| */
+ else
+ { cur_val=(((a-=0x80)%0x28)<<8)+*cur_byte++;
+ switch (a/0x28)
+ { case 0: out_char(identifier); break;
+ case 1: @<Expand module name |cur_val| @> @+ break;
+ case 2: cur_sec=cur_val; out_char(section_start);
+ /* set the correct section number and output comment */
+ }
+ }
+}
+
+@ If any defining occurrence of a module name was encountered during the
+Phase~I, its replacement text will have been be linked into to |equiv| field
+of that name; otherwise that field will contain a null pointer and we must
+report an error.
+
+@<Expand module name...@>=
+{ mod_pointer mod_name=mod_at(cur_val);
+ if (mod_name->equiv!=NULL) push_level(mod_name);
+ else
+ {@; print("\n! Module not present"); print_mod(mod_name); err_print("");
+ @.Module not present@>
+ }
+}
+
+@ Output of macro definitions and inclusions of header files is sufficiently
+different from ordinary output that we use a special function
+|output_preproc_directives| for it. We bypass |output| and call |out_char|
+directly, since in these cases there can be no nesting of replacement texts.
+We go through the list of all replacement texts and copy the ones that refer
+to macros or header files, preceded respectively by \&{\#define} and
+\&{\#include}. During the output of a single directive any line breaks
+present in the source file will be protected by backslashes. We use local
+variables |p| and |end| instead of |cur_byte| and |cur_end|, since the
+current level of the stack is already in use if this function is called from
+|output|.
+
+@c
+void output_preproc_directives (void)
+{ text_pointer repl,l;
+ eight_bits* p, *end;
+ protect=true; /* newlines should be preceded by |'\\'| */
+ for (repl=&text_table[0]; repl<text_ptr; repl++)
+ if ((l=repl->text_link)==macro_flag || l==header_flag)
+ { p=tok_begin(repl); end=tok_end(repl);
+ C_printf ("#%se ",l==macro_flag ? "defin" : "includ");
+ out_state=no_space;
+ while (p<end)
+ @< Output preprocessor token starting at |p|, advancing |p|
+ correspondingly @>
+ C_newline(); /* this newline is not escaped */
+ }
+ protect=false;
+}
+
+@ The situation here is simpler than in |output|, since module names and \:p
+control codes are forbidden in the replacement texts handled here, nor will
+codes for \.{\#line} directives or section number indications have been
+included in them during input. Should any such token nevertheless turn up,
+then one of the two calls of |confusion| below is invoked; the diagnostic is
+not quite exhaustive as to the possible cause in either case, but we do not
+wish to elaborate on code that will never be executed.
+
+@< Output preprocessor token... @>=
+{ int a=*p++;
+ if (a<0x80) out_char(a); /* single byte token */
+ else if (a>=0xF8)
+ if (a==0xF8) out_char(*p++); @+
+ else confusion("`@@p' within macro"); @.`@@p' within macro@>
+ else
+ { cur_val=(((a-=0x80)%0x28)<<8)+*p++;
+ if (a<0x28) out_char(identifier); @+
+ else confusion("module within macro"); @.module within macro@>
+ }
+}
+
+
+@* Writing characters. The |output| routine above handles the global
+structure of output generation; we now present the routines that transform
+the lexical items produced by |output| into characters.
+First we give a function that is called whenever we want to finish off a
+line sent to the \Cee~file.
+It keeps |cur_line| equal to the number of the next line to be output,
+and displays a progress report every 100 lines.
+
+@c
+void C_newline (void) /* writes one line to output file */
+{ C_putc('\n');
+ if (!line_output) put_indent();
+ if (cur_line%100==0 && show_progress)
+ { if (cur_line%500!=0) print("."); /* progress report */
+ else print(cur_line%2500==0 ? "%u\n" : "%u",cur_line);
+ update_terminal();
+ }
+ ++cur_line;
+}
+
+@ The function |out_char| must make sure that the output has the proper
+``surface structure''. When |line_output==false| everything should
+essentially be written as it is stored, but when |line_output==true| only
+the essential tokens have been stored, and white space has to be inserted
+where appropriate. Spaces should not occur at certain places (e.g., not in
+the middle of a string or a constant or an identifier, not at a \:\&
+position where quantities are being joined together), while in other places
+they are required (e.g., between identifiers, which for \.{\me.} includes
+reserved words, and between certain operators that might otherwise be
+considered as a single token). Such surface structure can very nicely be
+obtained by attaching a small finite state machine to the output generator,
+recording information about the most recent token (as a matter of fact, even
+\TeX's fabulous formatting of math formulae is largely based on such a simple
+device). In our present case, the state of the output process is recorded in
+the global variable |out_state|. Furthermore there is a variable |protect|
+that is explicitly managed by the function calling |out_char| (notably by
+|output_preproc_directives|), being set to |true| whenever newlines are to
+be escaped by a backslash.
+
+@<Global...@>=
+eight_bits out_state; /* current status of partial output */
+boolean protect; /* should newline characters be quoted? */
+
+@ The output process can be in one of following states:
+
+\yskip\hang |no_space| means that no space will precede the following item.
+This state is set by \:\&, and after the output of anything that could not
+possibly combine into a larger token, such as punctuation.
+
+\yskip\hang |num_or_id| means that the last item in the buffer is a number or
+identifier, hence a blank space or line break must be inserted if the next
+item is also a number or identifier.
+
+\yskip\hang |operator| means that the last item in the buffer is an operator,
+hence a blank space or line break must be inserted if the next item is also
+an operator.
+
+\yskip\hang |literal| means we're copying only character tokens, and
+that they are to be output exactly as stored. This is the case during
+strings, verbatim constructions and numerical constants; the |verb_quote|
+character serves as a quoting mechanism which switches this state
+on~and~off.
+
+@< Typedef and enum... @>=
+enum { no_space, num_or_id, operator, literal};
+
+@ The function |out_char| is a many-way switch on the kind of character or
+token transmitted to it. The |verb_quote| mechanism is used amongst others
+to encapsulate numeric constants, so we make the whole construction behave
+as an identifier with respect to spacing (the user can still defeat any
+spaces around it by means of \:\&). The code |line_mark| will only be stored
+(and output) if |line_output==true|. We do not anticipate the need of
+indentation across literals, operators and such, and assume that module
+names are preceded on the same line only by white space, identifiers
+(keywords) and things like braces; apart from identifiers all of these come
+through the |default| case below. Therefore we only include an invocation of
+|append_white| in that case and for identifiers; to handle all possible
+cases the assiduous user could add such invocations to all other calls of
+|C_putc| and |C_printf|.
+
+@c
+void out_char (eight_bits c)
+{ if (out_state==literal)
+ if (c==verb_quote) out_state=num_or_id; /* close literal mode */
+ else C_putc(c); /* write literal character, possibly 8-bit */
+ else if (isalnum(c)&&c<0x80 || c=='_')
+ /* single character identifier or number */
+ { if (out_state==num_or_id && line_output) C_putc(' ');
+ C_putc(c); out_state=num_or_id;
+ if (!line_output) append_white(c);
+ }
+ else switch (c)
+ { case verb_quote:
+ if (out_state==num_or_id && line_output) C_putc(' ');
+ out_state=literal; break;
+ case join: out_state=no_space; break;
+ case '\n': @< Output a newline @> @+ break;
+ case identifier: @< Output an identifier @> @+ break;
+ case section_start:
+ if (line_output) C_printf("/*%d:*/",cur_val); @+ else C_newline();
+ out_state=no_space; break;
+ case section_end:
+ if (line_output) C_printf("/*:%d*/",cur_val); @+ else C_newline();
+ out_state=no_space; break;
+ case line_mark: @< Output a \.{\#line} directive @> @+ break;
+ @\@<Cases of operator symbols@>
+ @\@<Cases of compressed operators@>
+ default: C_putc(c); out_state=no_space;
+ if (!line_output) append_white(c);
+ }
+}
+
+@ Newlines are escaped whenever |protect| holds; a space is prepended so
+that the newline is effectively replaced by a space. This also means that
+the user who cannot break the habit of escaping newlines in multi-line
+preprocessor directives, even though this is unnecessary after \:d and \:h,
+is not punished for this by the creation of the sequence `\.{\\\\}' at the
+end of the lines, but rather gets `\.{\\\ \\}', which is harmless.
+
+@< Output a newline @>=
+{ if (protect) {@; C_putc(' '); C_putc('\\'); }
+ C_newline();
+ if (out_state!=literal) out_state=no_space;
+}
+
+@ Apart from alphanumeric characters and underscores, we allow identifiers
+to contain characters in the range |0x80<=c<=UCHAR_MAX|, if a translation
+into a string of legal characters is known to \.{\me.}; such translations
+can be specified by \:l directives in limbo. These translations are stored
+in an array |c_trans|.
+
+@d trans_limit 9 /* maximal length of a translation string */
+@d trans_of(c) c_trans[(unsigned char)(c)-0x80]
+@d translation_exists(c) (trans_of(c)[0]!='\0') /* non-empty translation */
+
+@< Global var... @>=
+char c_trans[UCHAR_MAX+1-0x80][trans_limit+1];
+
+@~In compatibility mode, default translations exist of the form `\.X\\{NN}',
+where \\{NN} is the (two digit) upper case hexadecimal representation of the
+character in question. Otherwise the static initialisation will have made all
+translation strings empty.
+
+@< Set init... @>=
+if (compatibility_mode)
+@/{@; unsigned char c=UCHAR_MAX;
+ do sprintf(trans_of(c),"X%X",c); while (--c>=0x80);
+}
+
+@ In case of identifiers the name indexed by |cur_val| is written out. The
+translation of characters in the range from |0x80| upwards is performed
+here, rather than on input of such characters, since this is slightly more
+convenient. The check that |translations_exists| was done on input, however.
+
+@< Output an identifier @>=
+{ char* p=name_begin(id_at(cur_val)); int l=0;
+ if (out_state==num_or_id && line_output) C_putc(' ');
+ do
+ if ((unsigned char)(*p)<0x80) {@; C_putc(*p);++l; }
+ else
+ {@; char* q=trans_of(*p); do {@; C_putc(*q); ++l; } while (*++q!='\0'); }
+ while (*++p!='\0');
+ out_state=num_or_id;
+ if (!line_output) do append_white(' '); while (--l>0);
+}
+
+@ As indicated above, a call |out_char(line_mark)| causes four further bytes
+to be fetched directly from the token memory, increasing |cur_byte| so that
+|output| will resume at the correct byte.
+
+@< Output a \.{\#line} directive @>=
+{ sixteen_bits a;
+ a=(*cur_byte++)<<8; a+=*cur_byte++; /* get the line number */
+ C_newline(); C_printf("#line %u \"",a); @/
+ a=(*cur_byte++)<<8; a+=*cur_byte++; /* get the file name index */
+ C_printf("%s\"",name_begin(id_at(a)));
+ C_newline(); out_state=no_space;
+}
+
+@ In some cases when two operator symbols are adjacent, a space is required
+in between to avoid interpretation as a compound symbol. The language
+definition is not explicit about when such a space is mandatory, but
+examples are the somewhat unusual constructions | x /@, *p |, | a++ + b != a
++ ++b| and |sum = a - -b|; certain backward \Cee~compilers even think |x=-x|
+is ambiguous without a space before the minus sign. Rather than trying to
+detect precisely the problematic cases we take the conservative approach of
+always putting in a space, unless the second operator is~`\.='; this
+exception is made because we store operators like `\.{+=}' as two separate
+tokens, but they form a single token according to the \caps{ANSI/ISO}
+standard. Note that other multi-character operators like `\.{\&\&}' stay
+intact because they will be compressed on input, and therefore do not involve
+the present section.
+
+@<Cases of operator symbols@>=
+case '+': case '-': case '*': case '/': case '%': case'?':
+case '<': case '>': case '&': case '|':
+ if (out_state==operator && line_output) C_putc(' '); /* fall through */
+case '=': C_putc(c); out_state=operator; break;
+
+@ Compilers don't mind doing repetitive work, so we use a macro to produce
+several almost identical cases. Had the cases been much longer or more
+numerous however, then combining the cases and using an array of strings
+would have been preferable.
+
+@d comp_op(op)
+ (C_printf(out_state==operator && line_output ? " %s" : "%s",op)
+ ,out_state=operator)
+
+@<Cases of compressed operators@>=
+case plus_plus: comp_op("++"); break;
+case minus_minus: comp_op("--"); break;
+case minus_gt: comp_op("->"); break;
+case gt_gt: comp_op(">>"); break;
+case eq_eq: comp_op("=="); break;
+case lt_lt: comp_op("<<"); break;
+case gt_eq: comp_op(">="); break;
+case lt_eq: comp_op("<="); break;
+case not_eq: comp_op("!="); break;
+case and_and: comp_op("&&"); break;
+case or_or: comp_op("||"); break;
+
+
+@* Introduction to the phase I. We have now seen that \.{\me.} will be
+able to output the full \Cee\ program, if we can only get that program into
+the byte memory in the proper format. The input process is something like
+the output process in reverse, since we compress the text as we read it in
+and we expand it as we write it out (but of course, as any programmer knows,
+input requires a bit more work than the corresponding output). To preserve
+the symmetry we shall proceed in a bottom-up fashion in presenting this part
+of the program.
+
+The basic character input routines are defined in the code shared with
+\.{CWEAVE}. At the next higher level there are three main input routines.
+The most interesting is the one that gets the next token of a \Cee\ text;
+the other two are used to scan rapidly past \TeX\ text in the \.{CWEB}
+source code. One of the latter routines will jump to the next token that
+starts with `\.{@@}', and the other skips to the end of a \Cee~comment.
+
+@ Control codes in \.{CWEB} begin with `\.{@@}', and the next character
+identifies the code. Some of these are of interest only to \.{CWEAVE}, so
+\.{\me.} ignores them; the others are converted by \.{\me.} into
+internal code numbers. The code numbers have been chosen such that they are
+distinct from ordinary characters (so that a function can return either a
+character or a control code), and their ordering is such as to simplify the
+program logic; larger numbers are given to the control codes that denote
+more significant milestones. This order is only relevant starting from
+|format| however. The code \:> is treated as ignored because it should not
+occur in places where we are not searching for it. The following enumeration
+lists the non-character values that may be returned from~|get_next|;
+therefore the two values |id_code| and |constant| are included although they
+do not belong to any control code.
+
+@<Typedef and enum...@>=
+enum @/
+{ ignore=0x80, /* control code of no interest to \.{\me.}, or \:> */
+ id_code, constant, /* token codes but not control codes */
+ verbatim, /* control code for \:= */
+ at_sign_image, /* control code for \:@@ */
+ join_code, /* control code for \:\& */
+ ord, /* control code for \:' */
+ control_text, /* control code for \:t, \:\^, etc. */
+ include_preproc, /* control code for \:p */
+ char_trans, /* control code for \:l */
+ format, /* control code for \:f */
+ definition, /* control code for \:d */
+ header, /* control code for \:h */
+ begin_C, /* control code for \:c */
+ module_name, /* control code for \:< or \:( */
+ new_section /* control code for \:\ , \:\~, or \:* */
+};
+
+@ The conversion from the character following `\.@@' to the corresponding
+numeric code is performed by means of the table~|ccode|. Since we don't know
+whether characters are signed or not, we always access |ccode| via the macro
+|code_of|.
+
+@d code_of(c) ccode[(unsigned char)(c)]
+
+@<Global...@>=
+eight_bits ccode[UCHAR_MAX+1]; /* meaning of a char following `\.@@' */
+
+@~Here we initialise |ccode|. The code code for~\:v is the only case where a
+value stored in the |ccode| table is an ordinary character; this is done so
+that it may be used in the \Cee~part of a section to stand for~`|@v|', even
+though there is no need for using it there.
+
+@<Set ini...@>=
+{ unsigned char c=0;
+ do ccode[c] = isspace (c) ? new_section : ignore; while(c++!=UCHAR_MAX);
+@/ccode['v']=ccode['V']='|';
+@/ccode['=']=verbatim;
+@/ccode['@@']=at_sign_image;
+@/ccode['&']=join_code;
+@/ccode['\'']=ord;
+@/ccode['^']=ccode['?']=ccode['.']=ccode[':']=ccode['#']=
+ ccode['t']=ccode['T']=ccode['q']=ccode['Q']=control_text;
+@/ccode['p']=ccode['P']=include_preproc;
+@/ccode['l']=ccode['L']=char_trans;
+@/ccode['f']=ccode['F']=ccode['s']=ccode['S']=format;
+@/ccode['d']=ccode['D']=definition;
+@/ccode['h']=ccode['H']=header;
+@/ccode['c']=ccode['C']=begin_C;
+@/ccode['<']=ccode['(']=module_name;
+@/ccode['~']=ccode['*']=new_section;
+if (compatibility_mode)
+ @< Reset some control codes to match Levy/Knuth \.{CWEB} @>
+}
+
+@ In \.{CWEBx} there are a few control codes that also exist in \LKC. but
+have a different meaning. In compatibility mode we reassign the meaning of
+these codes to that of \LKC., making their usual function inaccessible,
+since it is not intended that hybrid programs should be written using the
+codes of \LKC. together with features particular to \.{CWEBx}. For
+\.{\me.} the change of meaning of \:: (which is used instead of \:? in
+\LKC.) has no effect since it introduces a control text anyway.
+
+@< Reset some control codes... @>=
+{ ccode['h']=ccode['H']=include_preproc; /* \:h means \:p */
+ ccode['p']=ccode['P']=begin_C; /* \:p means \:c */
+ ccode['#']=ignore; /* \:\# means \:) */
+}
+
+@ The function |skip_ahead| reads through the input at fairly high speed
+until finding the next non-ignorable control code, which it returns. It is
+used to skip over \TeX~text, and text in limbo. It uses the fact that
+|get_line| places a~|' '| at~|*limit|, so that placing the sentinel cannot
+inadvertently create a token \:@@.
+
+@c
+eight_bits skip_ahead (void) /* skip to next control code */
+{ eight_bits c; /* control code found */
+ while (find_char())
+ { limit[1]='@@'; /* place a sentinel */
+ while (*loc++!='@@') {}
+ if (loc<=limit && (c=code_of(*loc++))!=ignore) return c;
+ }
+ return new_section;
+}
+
+@ The function |skip_comment| reads through the input until finding the
+end-comment token `\.{*/}' or a newline, or in case of a \Cpp\ one-line
+comment (starting with `$/\!/$') just until finding a newline. The |one_liner|
+parameter tells whether the latter applies, and a boolean result is returned
+telling whether a newline in the middle of a comment was scanned (which can
+only happen if |one_liner==false|). Returning such a newline is necessary so
+that the each newline in the \Cee\ part of a section may be copied to the
+output; otherwise the \&{\#line} commands inserted into the \Cee\ file by
+the output routines become useless. When |line_output==false|, all characters
+encountered are also stored, so that they can be output along with the
+\Cee~code.
+
+The function gives an error message if it encounters a sequence `\.{/*}',
+since this almost certainly means the user has forgotten to close the
+comment. In this way we avoid the most pernicious consequence of \Cee's rule
+that nested comments are forbidden, namely that such an omission often leads
+to a syntactically correct, but unintended program. This means that one
+cannot write either `\.{/*}' or `\.{*/}' in a comment; this difficulty can
+usually be circumvented by inserting something like `\.{\{\}}' between the
+two characters.
+
+As a safety measure, |skip_comment| comes to an end if it runs into the next
+section, and prints an error message; it is slightly non-trivial that this
+test does not interfere with searching for the end of the comment. If a
+module name occurs in a comment (presumably in `\pb'), it is scanned by the
+normal routines that will be given later: this could be the only place where
+the name is spelled out in full, and/or using \:(.
+
+@c
+boolean skip_comment (boolean one_liner) /* skips over comments */
+{ char c; /* current character */
+ do
+ { if (loc>=limit)
+ if (one_liner) return false;
+ else if (get_line ()) return true;
+ else
+ {@; err_print("! Input ended in mid-comment"); return false; }
+ @.Input ended in mid-comment@>
+ if ((c=*loc++)=='/' && *loc=='*')
+ err_print("! `/*' inside comment, did you forget `*/' before? ");
+ @.`/*' inside comment...@>
+ if (c=='@@')
+ { eight_bits cc=code_of(*loc++);
+ if (cc==new_section) /* watch out for \:\ , \:\~, and \:* */
+ @/{@; err_print("! Section ended in mid-comment"); loc-=2; return false; }
+ @.Section ended in mid-comment@>
+ if (cc==module_name) @/{@; @< Scan the module name... @> continue; }
+ }
+ if (!line_output)
+ {@; store_byte(c);
+ if (c=='@@' && (c=loc[-1])!='@@') store_byte(c);
+ }
+ } while (c!='*' || *loc!='/' || one_liner);
+ ++loc; @+ if (!line_output) store_byte('/');
+ return false;
+}
+
+
+@* Getting the next token.
+We now come to the function |get_next|, which does more extensive scanning.
+It will move the input pointer over a single token of input, and if that
+token consists of a single character that is not an identifier or a number,
+it will return that character; certain two-character operators are also
+returned as a single character representing the operator. In the case of
+longer tokens, it will return one of the codes of the enumeration given
+earlier, after possibly setting some global variables in such a way that the
+complete token can be retrieved. For numeric constants |id_first| and
+|id_loc| will be made to point to the beginning and end of the token
+within~|buffer|. For string constants, which need not reside in a single
+line of input, the characters are copied into the separate buffer |mod_text|
+and this is where |id_first| and |id_loc| will then point. Identifiers and
+module names are even looked up, and |cur_id| or |cur_mod| is made to point
+to the name found. In the case of single-character identifiers or bad module
+names, which are not entered into the name tables, |cur_id| respectively
+|cur_mod| is set to~|NULL|; in the former case |id_first| is made to point
+to the character that forms the identifier.
+
+@<Global...@>=
+id_pointer cur_id; /* identifier just scanned */
+mod_pointer cur_mod; /* module name just scanned */
+
+@ As one might expect, |get_next| consists mostly of a big switch that
+branches to the various special cases that can arise. The static flag
+|preprocessing| is raised while we are scanning an explicit preprocessor
+directive (i.e., not one introduced by \:d or \:h). The static flag
+|comment_continues| is raised when |get_next| must return a newline while
+scanning a comment, so that it will remember what it was doing the next time
+it is called. Although we allow 8-bit character input, any characters
+|c>=0x80| should be contained in a comment or a character or string constant,
+or in case |translation_exists(c)| an identifier, since they cannot
+otherwise be part of a valid \Cee~symbol.
+
+@c
+eight_bits get_next (void) /* produces the next input token */
+{ static boolean preprocessing=false; /* did this line start with `\.\#'? */
+ static boolean comment_continues=false; /* were we scanning a comment? */
+ eight_bits c; /* the current character */
+restart:
+ @< Handle cases involving newlines and comments;
+ if a token is found |return| it, or |goto restart| if it is ignored;
+ otherwise read the next character into |c| @>
+ if (c=='L' && (*loc=='\'' || *loc=='\"'))
+ {@; get_string(); return constant; }
+ if (c<0x80 ? isalpha(c) || c=='_' : translation_exists(c))
+ @/{@; @< Get an identifier @> return id_code; }
+ if (c>=0x80) {@; err_print("! Illegal 8-bit character"); goto restart; }
+ @.Illegal 8-bit character@>
+ if (isdigit(c) || c=='.' && isdigit((eight_bits)*loc))
+ @/{@; @< Get a numeric constant @> return constant; }
+ switch(c)
+ { case '\'': case '"': get_string(); return constant;
+ case '@@': @< Get a control code and possibly a complete module name,
+ and either |return| it,
+ or |goto restart| if control code is |ignore| @>
+ @\@< In applicable cases |return| compressed two-symbol operator @>
+ }
+ return c;
+}
+
+@ The flag |preprocessing| raised when the first character of a line
+is~`\.\#', and is lowered at a non-escaped newline; while it is raised spaces
+are not ignored. The test whether a newline is escaped is not entirely
+sound, since a final `\.{\\}' might be part of a \:\\ control code or of a
+\Cpp\ one-line comment (after `$/\!/$'); a completely correct check would be
+more difficult, and leaving |preprocessing| raised a bit too long does no
+real harm. Contrary to |preprocessing|, the flag |comment_continues| will
+always be given a new value on the first call to |get_next| after it is set,
+and therefore can remain set only if |skip_comment| finds another newline.
+
+@< Handle cases involving newlines... @>=
+{ if (loc>=limit)
+ { if (preprocessing && limit>buffer && limit[-1]!='\\')
+ preprocessing=false;
+ return get_line() ? '\n' : new_section;
+ }
+ if (comment_continues
+ ||(c=*loc++)=='/' && (*loc=='*' || C_plus_plus && *loc=='/'))
+ @< Scan to the end of the comment or of the current line,
+ setting |comment_continues| to indicate which case applies;
+ in the former case |goto restart|, in the latter |return '\n'| @>
+ if (isspace(c))
+ if (line_output)
+ if (preprocessing) return ' '; @+ else goto restart;
+ /* ignore other spaces */
+ else return c;
+ /* when |line_output==false| preserve white space faithfully */
+ if (c=='#' && loc==buffer+1) preprocessing=true;
+}
+
+@ When we come to this code |loc| either points to the beginning of a
+multi-line comment or to the second character of `\.{//}' or `\.{/*}'; in
+the latter case we must advance |loc| before looking for `\.{*/}', lest
+`\.{/*/}' would be scanned as a complete comment. Another subtlety arises
+when both |preprocessing| and |comment_continues| are raised, which means
+that a preprocessor line has ended inside a comment; although in \Cee\ this
+means that the preprocessor line continues, \.{\me.} will terminate it
+because the comment is removed and a non-escaped newline remains. The
+warning message below can be ignored by the user unless something follows
+the comment, but the proper way to resolve this is to start the comment on
+the line after the preprocessor line, which avoids all confusion.
+
+@< Scan to the end of the comment... @>=
+{ boolean one_liner=false;
+ if (!comment_continues)
+ { if (!line_output) {@; store_byte('/'); store_byte(*loc); }
+ one_liner=*loc++=='/';
+ /*/ record kind of comment, and advance to comment proper {/}*/
+ }
+ else if (preprocessing)
+ { print("\nWarning: Multi-line comment in preprocessor line");
+ @.Multi-line comment...@>
+ preprocessing=false; mark_harmless();
+ }
+ if (comment_continues=skip_comment(one_liner))
+ /* scan to end of comment or newline */
+ return '\n'; /* comment contains a newline; |get_line| has been called */
+ else goto restart; /* comment complete, get next token */
+}
+
+@ The following code assigns values to the combinations `\.{++}', `\.{--}',
+`\.{->}', `\.{>=}', `\.{<=}', `\.{==}', `\.{<<}', `\.{>>}', `\.{!=}',
+`\.{\v\v}' and `\.{\&\&}'. The compound assignment operators (e.g., `\.{+=}')
+are separate tokens, according to {\sl The C Reference Manual\/} (so there may
+be white space and even comments in between), but according to the
+\caps{ANSI/ISO} standard they are single tokens. We have not allocated
+single-byte codes for them, so we scan them as two separate symbols; these
+will be adjacent on output. Therefore, as far as \.{\me.} is concerned, one
+may write a separation between the two characters even if the \Cee-compiler
+does not accept this; however, this practice should still be avoided because
+it will confuse the parser of |CWEAVE|, leading to ill-formatted output.
+
+@d compress(char2,code) @+
+ if (*loc==char2) return ++loc,code @;
+
+@< In applicable cases... @>=
+case '+': compress('+',plus_plus); break;
+case '-': compress('-',minus_minus); compress('>',minus_gt); break;
+case '=': compress('=',eq_eq); break;
+case '>': compress('=',gt_eq); compress('>',gt_gt); break;
+case '<': compress('=',lt_eq); compress('<',lt_lt); break;
+case '&': compress('&',and_and); break;
+case '|': compress('|',or_or); break;
+case '!': compress('=',not_eq); break;
+
+@ Identifiers are looked up unless they consist of a single character
+|c<0x80|, in which case that character can be found as |*id_first|; there is
+no need to set |id_loc| in either case. In case any 8-bit characters appear in
+identifiers, they are only stored in the name table, and cannot interfere with
+any of the special codes we use.
+
+@< Get an identifier @>=
+{ id_first=--loc; /* mark beginning of identifier */
+ do c=*++loc;
+ while (c<0x80 ? isalnum(c) || c=='_' : translation_exists(c));
+ cur_id=
+ loc==id_first+1 && (eight_bits)(*id_first)<0x80
+ ? NULL : id_lookup(id_first,loc,0);
+}
+
+@ Scanning numeric constants is straightforward. The only subtle point is
+that we must not call functions like |isdigit| with an argument of type
+|char|, like |*loc|, since that may fail for 8-bits characters if |char| is
+a signed type; therefore we copy characters into |c|, which has type
+|unsigned char|, before applying such functions. We don't mind \.{8}'s and
+\.{9}'s appearing in octal constants (although the \Cee~compiler will), so
+there is no need here to distinguish between octal and decimal constants.
+
+@< Get a numeric constant @>=
+{ if (*(id_first=loc-1)=='0' && tolower((eight_bits)*loc)=='x')
+ /* hex constant */
+ do c=*++loc; while (isxdigit(c));
+ else /* octal, decimal or float constant */
+ { while (isdigit(c)) c=*loc++;
+ if (c=='.') @+ do c=*loc++; while (isdigit(c));
+ if (tolower(c)=='e') /* floating point constant with exponent */
+ { if ((c=*loc)=='+' || c=='-') c=*++loc;
+ while (isdigit(c)) c=*++loc;
+ }
+ else --loc; /* back up to first character after constant */
+ }
+ while (isalpha(c)) c=*++loc;
+ /* incorporate any `\.{U}', `\.{L}', or `\.{F}' suffixes */
+ id_loc=loc;
+}
+
+@ After an `\.@@' sign has been scanned, the next character tells us whether
+there is more work to do. Although control codes like \:\^ and \:t are
+ignored by \.{\me.}, their control text has to be skipped, which is
+performed by |get_control_text|. Verbatim constructions also use
+|get_control_text|, but then return the |verbatim| control code, unless their
+control text was empty, in which case they are ignored.
+
+@< Get a control code... @>=
+{ eight_bits cc=code_of(*loc++);
+ switch(cc)
+ { case ignore: goto restart;
+ case control_text: get_control_text(); goto restart;
+ case verbatim: if (get_control_text()) goto restart; @+ else break;
+ case ord: @<Scan an \ASCII. constant@> @+ break;
+ case module_name:
+ @<Scan the module name and make |cur_mod| point to it@>
+ }
+ return cc;
+}
+
+@ Before we scan a module name, we record whether it started with \:(, so
+that we may record it afterwards as an auxiliary file name if necessary.
+
+@<Scan the module name...@>=
+{ boolean file_module= loc[-1]=='(';
+ /* does this module define an output file? */
+ cur_mod=get_module_name();
+ if (file_module && cur_mod!=NULL)
+ @<Adjoin |cur_mod| to the set of output files@>
+}
+
+@ There is no reason why we should allow a newline within an \ASCII.
+constant, even if it is escaped.
+
+@<Scan an \ASCII. constant@>=
+id_first=loc; /* first character after opening quote */
+while (*loc!='\'')
+{ if (*loc++=='\\') loc++; /* accept any character following backslash */
+ if (loc>=limit) {@; err_print("! ASCII constant didn't end"); break; }
+ @.ASCII constant didn't end@>
+}
+id_loc=loc++; /* move past closing quote */
+
+
+@* Scanning a piece of \Cee\ text.
+Having acquired the skills of skipping over text and isolating tokens that
+really matter, we are now ready to tackle complete pieces of \Cee~text. The
+rules for generating the replacement texts for preprocessor directives
+following \:d and \:h and for bodies of sections are almost identical; the
+only differences are that
+
+\yskip \item{a)}
+ Module names are not possible in preprocessor directives; indeed, the
+ appearance of a module name terminates such directives and starts the
+ \Cee~part of the section.
+
+\item{b)}
+ The codes \:d, \:h, \:f, and \:c are not allowed in a \Cee~part, while
+ they terminate preprocessor directives.
+
+\item{c)}
+ The code \:p is not allowed inside preprocessor directives.
+\yskip
+
+\noindent Therefore there is a single function |scan_repl| with a parameter
+|context| indicating which of the two kinds of replacement texts is being
+scanned; its value is either |preproc_directive| or |section_body|. After
+|scan_repl| has acted, |cur_text| will point to the replacement text just
+generated, and |next_control| will contain the control code that terminated
+the activity.
+
+@d preproc_directive 0
+@d section_body 1
+
+@<Global...@>=
+text_pointer cur_text; /* replacement text formed by |scan_repl| */
+eight_bits next_control; /* control code which has already been scanned */
+
+@ We will try to reduce storage requirements by discarding any trailing
+newlines both after preprocessor directives and section bodies. This does not
+affect the line sequencing indicated by \&{\#line} directives in either case,
+since in the former case such directives are not issued in the first place,
+and in the latter case a new \&{\#line} directive will be issued before any
+further code is added. Note that we cannot reliably recognise newlines in a
+right-to-left motion when the end of a replacement text is reached, since
+there is a mixture of one-byte, two-byte and five-byte tokens. Therefore,
+instead of tracing backwards, we mark the position of the last non-discardable
+token every time one is appended, and back up to the last position recorded
+when reaching the end of a replacement text. Given this mechanism, it is easy
+to discard other things than newlines, such as \&{\#line} directives that
+apply to no lines at all, and to back up at other occasions where the line
+sequencing is interrupted as well, like before applied module names.
+
+This is also a good place to add a simple but useful check, namely that in
+each section and macro replacement text the parentheses and braces should be
+matched (failure in this respect can lead to syntax errors that are very
+hard to locate in the \.{CWEB} source, since the real problem may be buried
+inside a module name or macro).
+
+@c
+void scan_repl (eight_bits context) /* creates a replacement text */
+{ eight_bits a; /* the current token */
+ eight_bits* keep=tok_ptr; /* non-discardable stuff up to this point */
+ int brace_level=0, par_level=0;
+ if (context==section_body)
+ @< Insert the line number into |tok_mem| @>
+ do @< Scan and store a token, setting |keep=tok_ptr| afterwards unless it
+ is discardable; when the replacement text has ended |goto done| @>
+ while (true);
+done: tok_ptr=keep; /* backup over trailing newlines and \&{\#line} marks */
+ next_control=a; /* this control code must be reconsidered */
+ if (par_level>0 || brace_level>0) @< Report unmatched opening symbols @>
+ @< Wrap up the accumulated bytes into a completed text,
+ pointed to by |cur_text| @>
+}
+
+@ When the function |scan_repl| is called we have either just scanned \:h or
+the identifier following \:d or a defining occurrence of a module name (with
+the following `\.='); in all cases we start by calling |get_next|.
+
+@< Scan and store a token... @>=
+{ switch (a=get_next())
+ {
+ @\@< Cases where |a| is a special token (|id_code|,
+ |module_name|, etc.): either store the corresponding bytes and
+ |continue|, or |goto done| if |a| signals the end of this
+ replacement text@>
+ case format: case definition: case header: case begin_C:
+ if (context==preproc_directive) goto done;
+ err_print
+ ("! `@@f', `@@d', `@@h', and `@@c' are ignored in section body");
+ @.`@@f', `@@d', ... are ignored...@>
+ continue;
+ case new_section: goto done;
+ @\@< Cases that keep track of |par_level| and |brace_level| @>
+ case '\n': store_byte('\n');
+ if (context==section_body && print_where) /* input file was switched */
+ { tok_ptr=keep; /* back up over discardable items */
+ @< Insert the line number into |tok_mem| @>
+ }
+ continue;
+ case join_code: a=join;
+ }
+ store_byte(a); keep=tok_ptr; /* mark as non-discardable */
+}
+
+@ We test matching parentheses and braces separately because it is easier,
+and in the unlikely case that a mismatch should go undetected the compiler
+will surely report an error that is easy to locate. All parentheses and
+braces that are returned from |get_next| are real ones, i.e., not part of a
+string or comment.
+
+@< Cases that keep track of |par_level| and |brace_level| @>=
+case '(': ++par_level; break;
+case ')':
+ if (par_level<=0)
+ {@; err_print("! Unmatched closing parenthesis"); continue; }
+ @.Unmatched closing...@>
+ --par_level; break;
+case '{': ++brace_level; break;
+case '}':
+ if (brace_level<=0)
+ {@; err_print("! Unmatched closing brace"); continue; }
+ --brace_level; break;
+
+@ The most difficult part of matching parentheses and braces is reporting any
+errors at the end of the macro or section in proper English. We supply the
+missing closing symbols so that there is a slightly larger chance that the
+produced \Cee~code will compile. Note that there is no need to update |keep|
+here, since no backing up will follow.
+
+@< Report unmatched opening symbols @>=
+{ char *p, *s; int l;
+ if (par_level>0) l=par_level, s="parenthes", p= l>1 ? "es" : "is";
+ else l=brace_level, s="brace", p=l>1 ? "s" : "";
+ print("\n! There %s %d unclosed %s%s"
+ ,par_level+brace_level>1 ? "are" : "is", l, s, p );
+ @.There are unclosed...@>
+ if (par_level>0 && brace_level>0)
+ print(" and %d unclosed brace%s"
+ , brace_level, brace_level>1 ? "s" : "");
+ print(" in the previous ");
+ err_print(context==preproc_directive ? "macro" : "section");
+ while (--par_level>=0) store_byte(')');
+ while (--brace_level>=0) store_byte('}');
+}
+
+@ When a module reference is inserted the line sequencing is interrupted,
+so we must restore it afterwards; on the other hand newlines before the
+insertion can be discarded.
+
+@< Cases where |a| is...@>=
+case id_code:
+ @< Store the identifier just scanned @> @+ keep=tok_ptr; continue;
+case module_name: if (context==preproc_directive) goto done;
+ if (cur_mod!=NULL) /* don't record bad module name */
+ { sixteen_bits n = mod_index(cur_mod); /* index of module name */
+ @< If this looks like a defining occurrence, report a runaway section @>
+ if (line_output) tok_ptr=keep; /* back up */
+ store_two_bytes(0xA800+n); keep=tok_ptr;
+ /* store reference to module name */
+ @< Insert the line number into |tok_mem| @>
+ /* to get in phase after module insertion */
+ }
+ continue;
+case constant: case verbatim:
+ @/@< Copy a constant or verbatim construction @> @+ keep=tok_ptr;
+ continue;
+case ord:
+ @<Translate an \ASCII. constant@> @+ keep=tok_ptr; continue;
+case include_preproc:
+ if (context==preproc_directive)
+ err_print("! `@@p' is forbidden in preprocessor directive");
+ @.`@@p' is forbidden...@>
+ else
+ { if (line_output) tok_ptr=keep;
+ store_byte(0xFA); atp_seen=true; keep=tok_ptr;
+ @< Insert the line number... @>
+ }
+ continue;
+case char_trans:
+ err_print("! `@@l' is only allowed in limbo");
+ @.`@@l' is only allowed in limbo@>
+ continue;
+
+@ Identifiers of length~$1$ have no name pointer, but |id_first| still
+points at the relevant character.
+
+@< Store the identifier... @>=
+if (cur_id==NULL) store_byte(*id_first); /* single-character identifier */
+else store_two_bytes(0x8000+id_index(cur_id));
+
+@ Here we look to see whether a module name is followed by~`\.{=}'
+or~`\.{+=}' (whether another `\.{=}' follows is irrelevant at this point),
+in which case we assume that introduces the \Cee-part of a new section, of
+which we somehow missed the opening \:\ . Note that this need not limit the
+use of module names standing for single expressions, even if followed by the
+`\.{=}' or the `\.{+=}' operator, since such names should be followed by
+`\.{@@;@@;}' for proper treatment by \.{CWEAVE}.
+
+@< If this looks like a defining occurrence, report... @>=
+{ char *p=loc;
+ while (*p==' ' && p<limit) ++p;
+ if (*p=='+') ++p; /* an optional `\.+' is allowed */
+ if (*p=='=')
+ err_print
+ ("! Illegal defining occurrence of module name; did you forget `@@ '?");
+ @.Illegal defining occurrence...@>
+}
+
+@ Constants of length one can only be single digit numbers, so they can
+be stored in a single (unquoted) byte like single letter identifiers.
+
+Inside strings (and verbatim constructions) {\it any\/} character may in
+principle show up, including the character |verb_quote| used to delimit the
+verbatim storage of the string. Even if this is hardly a sign of good
+programming, the effect on output would be so disastrous that some counter
+measure is called for: we replace |verb_quote| by its three-digit octal
+escape code, which the user should have written to begin with. Because a \:i
+line or a change file match can occur inside a string, we must test
+|print_where| at the end of a string.
+
+@< Copy a constant... @>=
+if (id_loc==id_first+1) store_byte(*id_first); /* single digit number */
+else
+{ store_byte(verb_quote); /* opening */
+ do
+ if (*id_first==verb_quote)
+ { ++id_first; store_byte('\\'); store_byte('0'+(verb_quote>>6));
+ store_byte('0'+((verb_quote>>3)&7)); store_byte('0'+(verb_quote&7));
+ }
+ else
+ { if ((eight_bits)(*id_first)>=0x80) store_byte(0xF8);
+ /* quote 8-bit characters */
+ store_byte(*id_first++);
+ }
+ while (id_first<id_loc);
+ store_byte(verb_quote); /* closing */
+ if (context==section_body && print_where)
+ @< Insert the line number into |tok_mem| @>
+}
+
+@ This section should be rewritten on machines that don't use \ASCII.
+code internally. It is probably best to use a table indexed by characters
+and containing \ASCII. codes for this purpose (like the |xord| array in
+\TeX). Incidentally, it would be tempting to write statements like
+`|case'\\': c=@'\\';|' here, which would in principle be correct in any
+other place, but which would cause circularity in a bootstrapped system like
+this.
+@^ASCII code dependencies@>
+
+@< Translate an \ASCII. constant @>=
+{ int c=*id_first++;
+ if (c=='@@' && *id_first++ !='@@')
+ @/{@; err_print("! Double `@@' should be used in ASCII constant");
+ @.Double `@@' should be used...@>
+ --id_first;
+ }
+ if (c=='\\')
+ { c=*id_first++;
+ switch (c)
+ { case 't':c='\011';break;
+ case 'n':c='\012';break;
+ case 'b':c='\010';break;
+ case 'f':c='\014';break;
+ case 'v':c='\013';break;
+ case 'r':c='\015';break;
+ case '0':c='\0';break;
+ case '\\':c='\134';break;
+ case '\'':c='\047'; break;
+ case '\"':c='\042'; break;
+ default: err_print("! Unrecognised escape sequence");
+ @.Unrecognised escape sequence@>
+ }
+ }
+ else
+ { /* at this point |c| should be converted to its \ASCII. code number */
+ @+}
+ if (id_first!=id_loc)
+ if (id_loc>id_first)
+ err_print("! ASCII constant should be single character");
+ @.ASCII constant should be...@>
+ else {@; err_print("! Empty ASCII constant"); c=0; }
+ @.Empty ASCII constant@>
+ store_byte(verb_quote);
+ if (c>=100) store_byte('0'+c/100); @+ if (c>=10) store_byte('0'+(c/10)%10);
+ store_byte('0'+c%10); @/
+ store_byte(verb_quote);
+}
+
+@ Line number marks, which will lead to \&{\#line} directives on output, are
+inserted in several places, so we shall call a function to do the necessary
+work. For reasons explained below this function scans ahead a bit through
+the input, and in doing so it may hit the end of the input; when this
+happens it must be reported back to |scan_repl|. Therefore |mark_line|
+returns a boolean value which tells whether |input_has_ended|.
+
+@< Prototypes @>= boolean mark_line(void);
+
+@~When |mark_line| returns |true|, we should terminate |scan_repl| with
+|next_control==new_section|; this is achieved by jumping to |done|, where
+some exitialisations are done, and where |next_control| is assigned from the
+variable~|a|.
+
+@< Insert the line... @>=
+{@; if (mark_line()) {@; a=new_section; goto done; } }
+
+@~If |line_output==true|, the following items are stored for recording the
+line number: first a byte equal to |0xF9|, then the numeric line number,
+and finally the |id_index| of the file name, which is looked up as if it were
+an identifier (except that we use the feature of |id_lookup| to accept
+null-terminated strings as first argument if the second argument is~|NULL|).
+Note that |keep| is not increased; if nothing essential follows this line
+number indication then it need not be recorded. We improve compactness of
+storage and output a bit by discarding any newlines that are immediately
+ahead; the inserted line number will automatically be increased properly.
+While reading we might find there is no input left, in which case no line
+number is recorded and |true| is returned.
+
+@c
+boolean mark_line(void)
+{ while (loc>=limit)
+ @+ if (!get_line()) return true; /* skip over newlines */
+ print_where=false; /* request is being serviced */
+ if (line_output)
+ { store_byte(0xF9);@/
+ id_first=changing ? change.name : cur_file_name;
+ store_two_bytes(changing ? change_line : cur_line);
+ store_two_bytes(id_index(id_lookup(id_first,NULL,0)));
+ }
+ return false;
+}
+
+
+@* Scanning a section.
+The function |scan_section| starts when \:\ , \:\~, or \:* has been sensed
+in the input, and it proceeds until the end of that section. It uses
+|section_count| to keep track of the current section number; hopefully
+\.{CWEAVE} and \.{\me.} will both assign the same numbers to sections.
+
+@c
+void scan_section (void)
+{ ++section_count;
+ if (loc[-1]=='*') print_section_progress();
+ @<Scan the \TeX\ and definition parts of the current section@>
+ @<Scan the \Cee\ part of the current section@>
+}
+
+@ For \.{\me.} there is no real difference between the \TeX\ and
+definition parts of a section; after all, the latter can contain \&{format}
+commands that are ignored just like \TeX~text is. So we set up a loop that
+stops when |next_control>=begin_C|, and handles the cases |definition| and
+|header|, while ignoring anything else. The price we pay for our haste in
+skipping the \TeX~part of a section (and \:f commands) is that we may have
+to back up after finding \:< in order to scan the whole module name and set
+|cur_mod|, which requires calling~|get_next|. In case \:< follows a
+|definition| or |header| code, it is scanned by |scan_repl|, and no backing
+up is required; therefore the code for backing up and rescanning cannot be
+moved outside the loop.
+
+@<Scan the \TeX\ and definition part...@>=
+{ next_control=ignore; /* clear |new_section| */
+ do
+ { if (next_control<definition)
+ { if ((next_control=skip_ahead())==module_name)
+ @/{@; loc -= 2; get_next(); }
+ /* back up and scan the module name itself */
+ }
+ else if (next_control==definition)
+ { @< Scan and store the identifier after \:d, if not found |continue| @>
+ scan_repl(preproc_directive);
+ cur_text->text_link=macro_flag; /* characterise as macro */
+ }
+ else /* |next_control==header| */
+ {@; scan_repl(preproc_directive); cur_text->text_link=header_flag; }
+ if (next_control==module_name)
+ @< If this is not a defining occurrence, set |next_control=ignore| @>
+ } while (next_control<begin_C);
+}
+
+@ We retain the strange lexical rule of the \Cee\ preprocessor that a space
+after the identifier defined as a macro is quite significant, especially
+when followed by `\.{(}'. Together with the spaces in preprocessor lines
+contained in a \Cee~part, these are the only kind of unquoted spaces that
+are ever stored as tokens, when |line_output| holds.
+
+@< Scan and store the id... @>=
+{ do next_control=get_next(); /* allow white space before identifier */
+ while (line_output ? next_control=='\n'
+ : next_control<0x80 && isspace(next_control));
+ if (next_control!=id_code)
+ @/{@; err_print("! Macro definition ignored, must start with identifier");
+ @.Macro definition ignored...@>
+ continue;
+ }
+ @< Store the id... @>
+ if (isspace((eight_bits)*loc)) store_byte(' ');
+ /* separate the replacement text from a parameterless macro */
+}
+
+@ Due to the fact that module names are allowed enclosed in `\pb', it is not
+certain that the occurrence of a module name signals the start of the
+\Cee~part of the section. The decisive factor will be what follows the
+module name: if this is `\.=' or `\.{==}', possibly preceded by `\.+', then
+this is really the name of the module defined in this section. If not, then
+we require that the next token is a `\.\v' (the one closing `\pb'), unless
+we are in compatibility mode, in which case anything goes. We use the fact
+that scanning the `\.+' and `\.=' symbols will not destroy the value in
+|cur_mod|.
+
+@< If this is not a defining occurrence, set |next_control=ignore| @>=
+{ eight_bits t=get_next();
+ if (t=='+') t=get_next(); /* skip an optional `\.+' */
+ if (t!='=' && t!=eq_eq) /* then apparently a cited occurrence, ignore it */
+ { next_control=ignore;
+ if (t!='|' && !compatibility_mode)
+ err_print("! `=' sign missing, module name ignored");
+ @.`=' sign missing, module name ignored@>
+ }
+}
+
+@ If we come to this module with |next_control==module_name|, then the code
+of the previous section has just removed the `\.=' or `\.{==}' and optional
+`\.+' following the module name.
+
+@<Scan the \Cee...@>=
+{ mod_pointer p; /* module name for the current section */
+ switch (next_control)
+ { default: return; /* no \Cee\ part present */
+ case begin_C: p=NULL; break; /* section contributing to unnamed module */
+ case module_name: p=cur_mod; /* section contributing to named module */
+ }
+ store_two_bytes(0xD000+section_count); /* record section number */
+ scan_repl(section_body);
+ /* now |cur_text| points to the replacement text */
+ @< Link the section body at |cur_text| to the module named |p|,
+ or to the unnamed module if |p==NULL| @>
+}
+
+@ Sections whose body starts with a bad name (e.g., an ambiguous prefix) will
+be treated as if they were unnamed, so the user had better not ignore the
+error message. Unnamed sections get a slightly special treatment, which makes
+accumulating many of them a bit more efficient than building up a named module
+that is defined in many sections.
+
+@<Link the section...@>=
+{ if (p == NULL) /* unnamed section, or bad module name */
+ {@; *last_unnamed = cur_text; last_unnamed = &cur_text->text_link; }
+ else
+ { text_pointer* q=&p->equiv; /* text for the current module */
+ while(*q!=NULL) q=&(*q)->text_link; /* find end of list */
+ *q=cur_text; /* add section to module */
+ }
+ cur_text->text_link=NULL;
+ /* end list, also marking replacement text as a non-macro */
+}
+
+
+@* Phase I processing.
+Finally we can wrap everything up and define the global structure
+of~Phase~I.
+
+@<Proto...@>=
+void phase_one (void);
+ /* read all the user's text and compress it into |tok_mem| */
+
+@~The only thing left to do is picking up character translations in the limbo
+part.
+
+@c
+void phase_one (void)
+{ phase=1; section_count=0; reset_input();
+ while ((next_control=skip_ahead())!=new_section)
+ if (next_control==char_trans) @< Store a character translation @>
+ while (!input_has_ended) scan_section(); /* load all sections */
+ check_complete(); /* verify that change file hasn't got out of sync */
+}
+
+@ The code \:l should be followed (after optional space) by a two-digit hex
+number~|c| with |c>=0x80|, white space, and a translation string of at most
+|trans_limit| characters, either alphanumeric or underscores, terminated by
+another space.
+
+@< Store a character translation @>=
+{ int c;
+ while (loc<limit && isspace((eight_bits)*loc)) ++loc; /* skip space */
+ if (!(isxdigit((eight_bits)loc[0])&&
+ isxdigit((eight_bits)loc[1])&&
+ isspace ((eight_bits)loc[2])))
+ err_print("! Two-digit hex number and space should follow `@@l'");
+ @.Two-digit hex number...@>
+ else if (sscanf(loc,"%x",&c),c<0x80)
+ err_print("! You cannot translate characters < 0x80");
+ @.You cannot translate...@>
+ else
+ { char* p=trans_of(c); int i=0;
+ loc+=3; @+
+ while (find_char() && isspace((eight_bits)*loc)) ++loc; /* skip space */
+ if (!input_has_ended)
+ while (isalnum((eight_bits)*loc) || *loc=='_')
+ if (++i<=trans_limit) *p++=*loc++; @+ else break;
+ if (i>0) *p='\0'; /* terminate translation unless none was given */
+ @< Report any problems with the translation string @>
+ }
+}
+
+@ The main contribution of the \:l feature to \.{CWEB} is new syntax,
+leading to a variety of new error messages. It is possible to give an empty
+translation for a character by terminating the translation string by a
+non-space character that is not allowed in identifiers; this is forbidden
+however, since an empty translation for~|c| would just make
+|translation_exists(c)| fail, making~|c| useless anyway. Even if the
+translation string is not empty, terminating it by a non-space character is
+considered an error, since this would make the \TeX\ macro used for
+formatting the corresponding line of the printed document fail.
+
+@< Report any problems... @>=
+if (i==0) err_print("! Translation string absent after `@@l'");
+ @.Translation string...@>
+else if (i>trans_limit) err_print("! Translation string too long");
+else if (!isspace((eight_bits)*loc))
+ err_print("! Translation string not terminated by space");
+
+
+@ At the end of the run, if |STAT| was defined and the `\.{+s}' flag
+present, we report how much of all the arrays was actually needed.
+
+@d report(k,c,m)
+ printf("%lu %ss (out of %lu)\n",(unsigned long)(c),k,(unsigned long)(m))
+
+@c
+#ifdef STAT
+void print_stats (void)
+{ print("\nMemory usage statistics:\n");
+@/report("identifier", id_index(id_ptr), max_idents);
+@/report("module name", mod_index(mod_ptr), max_modules);
+@/report("byte", byte_ptr-byte_mem, max_bytes);
+@/report("replacement text", text_ptr-text_table, max_texts);
+@/report("token", tok_ptr-tok_mem, max_toks);
+}
+#endif
+
+
+@* Index. Here is a cross-reference table for the \.{\me.}
+processor. All sections in which an identifier is used are listed with
+that identifier, except that reserved words are indexed only when they
+appear in format definitions, and the appearances of identifiers in
+module names are not indexed. Underlined entries correspond to where
+the identifier was declared. Error messages and a few other things
+like ``\ASCII. code dependencies'' are indexed here too.
diff --git a/web/c_cpp/cwebx/cweave.w b/web/c_cpp/cwebx/cweave.w
new file mode 100644
index 0000000000..037ebdff3d
--- /dev/null
+++ b/web/c_cpp/cwebx/cweave.w
@@ -0,0 +1,3588 @@
+% This file is part of CWEBx.
+% This program by Marc van Leeuwen based on earlier versions by
+% D. E. Knuth., Silvio Levy and Frank Jensen.
+% It is distributed WITHOUT ANY WARRANTY, express or implied.
+% CWEB (Revision: 2.0) % Don Knuth, July 1990
+% Version 3.x, Marc van Leeuwen, December 1993
+% CWEBx 2+1.0, Marc van Leeuwen, August 1994
+% CWEBx 3.0, Marc van Leeuwen, Januari 1995
+% CWEBx 3.02, Marc van Leeuwen, April 1996
+% CWEBx 3.03, Marc van Leeuwen, January 1998
+
+% Copyright (C) 1987,1990 Silvio Levy and Donald E. Knuth
+% Copyright 1994 Marc A. A. van Leeuwen
+
+% Permission is granted to make and distribute verbatim copies of this
+% document provided that the copyright notice and this permission notice
+% are preserved on all copies.
+
+% Permission is granted to copy and distribute modified versions of this
+% document 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.
+
+\def\me.{CWEAVE} \def\myroots{\.{WEAVE}}
+
+% Here is TeX material that gets inserted after \input cwebxmac
+\def\xr.{cross-reference}
+\def\Cpp{\Cee\PP}
+\def\TeXxstring{\TeX\_string}
+\def\TeXxlike{\TeX\_like}
+\def\skipxTeX{skip\_\TeX}
+\def\copyxTeX{copy\_\TeX}
+
+@i intro.inc % Here is some text that matches the start of CWEAVE
+
+@d banner "This is CWEAVE (Version x"@+version_string@+")\n"
+
+@ The following parameters are specific to \.{\me.}; those which are
+common to \.{CTANGLE} and \.{CWEAVE} are defined in the file \.{common.inc}
+and appear below. Some of these values have been decreased with respect to
+their earlier values which were sufficient in the original |WEB| to handle
+\TeX; a motivation is given at the common declarations.
+
+@d max_refs 10000 /* number of \xr.s; must be less than 65536 */
+@d max_toks 10000 /* number of symbols in \Cee\ texts being parsed;
+ must be less than |65536| */
+@d max_texts 2500 /* number of phrases in \Cee\ texts being parsed;
+ must be less than |10240| */
+@d max_scraps 4000 /* number of tokens in \Cee\ texts being parsed */
+@d max_no_of_nodes 215 /* number of nodes in search trie for grammar rules,
+ must be at most |256| */
+@d line_length 80 /* maximal line length for \TeX\ output;
+ should be less than |256| */
+@d stack_size 400 /* number of simultaneous output levels */
+@d sort_stack_size 500 /* number of identifier lists during sorting */
+
+@ The program is built from two compilation units, one with source file
+\.{common.w}, which contains a collection of routines and data shared
+between \.{CTANGLE} and \.{CWEAVE}, and a second with master source file
+\.{cweave.w} containing all code specific to \.{\me.}, and whose
+typeset version you are now reading. All compilation units of the \.{CWEB}
+system incorporate the file \.{common.inc} containing common declarations.
+
+\.{\me.} has the following outline. It operates in three phases: first
+it reads the source file once for collecting \xr. data, then it
+reads the source file for a second time, meanwhile producing the bulk of
+the \TeX\ output file, and finally it outputs the information in its tables
+from which \TeX\ will produce the list of module names, index and table
+of contents. Syntax errors would often be reported identically in the first
+two phases, and problems in printing module names similarly in the second
+and third phase; to avoid this we check after each phase if any serious
+errors were found, and if so, we stop prematurely. \.{\me.} can optionally
+be compiled with preprocessor symbols |DEBUG| and/or |STAT| defined; the
+former is useful for the user who requires detailed information about the
+parsing process, the latter if one wishes to keep track of how much of the
+static resources were actually used.
+
+@c
+@< Function prototypes used but not defined in the shared code @>@;
+@< Typedef and enumeration declarations @>@;
+@< Prototypes @>@;
+@< Global variables @>@;
+
+int main (int argc,char** argv)
+{ program=cweave;
+ make_xrefs=true;
+ common_init(argc,argv);
+ @< Set initial values @>
+ if (show_banner) print(banner); /* print a ``banner line'' */
+ @< Store all the reserved words @>
+ phase_one (); /* read all the user's text and store the \xr.s */
+ if (history>harmless_message) wrap_up(); /* stop in case of trouble */
+ open_output_file();
+ phase_two (); /* read all the text again and translate it to \TeX\ form */
+ if (history>harmless_message) wrap_up(); /* stop in case of trouble */
+ phase_three (); /* output the \xr. index */
+ wrap_up (); /* and exit gracefully */
+ return 0; /* for completeness---not reached */
+}
+
+@ The macro |variant| needs to be defined before we include the file
+\.{common.h}, in order to affect the definition of |id_info| and |mod_info|
+(see \.{common.w} for an explanation); it refers to the |struct xref_info|
+that will be declared later.
+
+@d variant @;xref_info
+@< Prototypes @>=
+void phase_one (void);
+ /* read all the user's text and store the \xr.s */
+void phase_two (void);
+ /* read all the text again and translate it to \TeX\ form */
+void phase_three (void); /* output the \xr. index */
+
+@i common.inc
+
+
+@* Data structures exclusive to {\tt \me.}. @:title@>
+Although the eventual typeset output produced after running \.{\me.}
+is meant to closely resemble the \.{CWEB} source from which it was created
+(or maybe it is the other way around), the task of \.{\me.} is more
+complicated than that of \.{CTANGLE}, because it involves a much more
+detailed ``understanding'' of the program fragments present in the source.
+Therefore the bulk of the program text is concerned with the parsing
+process during Phase~II. Detailed information about these matters shall be
+given at more appropriate places below; here we only discuss how individual
+tokens are tagged on input, and how \xr. infromation is stored.
+
+The |ilk| field of an |id_info| structure is used to distinguish between
+various types of identifiers, as follows:
+
+\yskip\hang |normal| identifiers are part of the \Cee\ program and
+will usually appear in italic type.
+
+\yskip\hang |roman| identifiers are index entries that appear after \:\^ in
+the \.{CWEB} file.
+
+\yskip\hang |wildcard| identifiers are index entries that appear after \:?
+in the \.{CWEB} file.
+
+\yskip\hang |typewriter| identifiers are index entries that appear after \:.
+in the \.{CWEB} file.
+
+@:section number example@>
+\yskip\hang |reference| identifiers are used for explicit \xr.s by the user
+within pieces of \TeX~text, allowing us for instance to remark that this is
+section@#section number example@> out of a total of@#index@> in this file,
+and that the sections having titles are number@#title@>. These \xr.s marks
+are set by~\:: and referred to by~\:\#.
+
+\yskip\hang |type_defined| identifiers have occurred in a |typedef|
+declaration. They will parse as types like |int|, but \xr.s to
+them will be collected.
+
+\yskip\hang |TeX_like| identifiers like |TeX| are typeset as user-definable
+control sequences.
+
+\yskip\hang |NULL_like| identifiers like `|NULL|' (\.{NULL}) are also
+typeset as (\TeX) control sequences, but in addition are treated like
+reserved words for indexing purposes, i.e., only underlined references are
+generated.
+
+\yskip\hang |case_like|, \dots, |while_like| identifiers are \Cee\
+reserved words that will be typeset in boldface. The further distinction
+between these |ilk| values determines their distinguished behaviour in
+parsing (and consequently in the formatted output), since the values
+are also used as category codes when these reserved words are converted
+into scraps. Their values, which all exceed |NULL_like|, shall be defined
+together with the other category codes. Two special cases of these are
+given here, whose distinction is only needed in the lexical analysis, and
+which will get a category different from their |ilk|: |const_like| and
+|typedef_like| will become |int_like| in parsing (and the same holds for
+|type_defined| identifiers).
+
+@f TeX_like TeX
+
+@d reserved(a) (a->ilk>=type_defined)
+ /* whether identifier automatically gets this |ilk| */
+@d unindexed(a) (a->ilk>=NULL_like)
+ /* whether cross-referencing is suppressed */
+
+@< Typedef and enum... @>=
+enum @/
+{ normal, /* |ilk| of ordinary identifiers */
+ roman, /* |ilk| of roman type index entries */
+ wildcard, /* |ilk| of user-formatted index entries */
+ typewriter, /* |ilk| of typewriter type entries */
+ reference, /* |ilk| of identifiers used for explicit \xr.s */
+ type_defined, /* |ilk| of identifiers that are defined by |typedef| */
+ TeX_like, /* |ilk| of identifiers with user-given control sequences */
+ NULL_like, /* |ilk| of \.{NULL} */
+ const_like, typedef_like /* special reserved words */
+};
+
+@ Besides the memory used for storing names, another large memory area is
+used in \.{\me.} for keeping the \xr. data. All uses of the name~|p| are
+recorded in a linked list beginning at |p->xref|, which is an |xref_pointer|
+pointing into the |xmem| array (here we use the pointer field for additional
+information in |id_info| and |mod_info| structures, which was called |equiv|
+in~\.{CTANGLE}). The elements of |xmem| are structures consisting of an
+integer, |num|, and the index |next| of another element of |xmem|. If
+|x==p->xref|, the value of |x->num| is a section number where |p| occurs,
+plus a multiple of |cite_flag| that indicates the nature of the occurrence,
+or it is |file_flag| marking the fact that |p| is a module name which is the
+name of an auxiliary output file (for \.{CTANGLE}). The next such \xr.
+for~|p|, if any, is |xmem[x->next]|.
+
+Since the entries of |xmem| are small but numerous, and the \xr. lists are
+not traversed very frequently, a significant amount of space is saved by
+storing a |sixteen_bits| index as a link to the next node rather than an
+|xref_pointer|, and at very little cost in performance. The main price paid
+is in terms of elegance, as somewhat different methods of traversal of the
+lists are appropriate depending on whether the traversal may leed to the
+insertion of a new node into the list or not. If no such insertion is
+needed, then we can work with |xref_pointer| values as if we were dealing
+with an ordinary linked list, provided only that the pointer to a successor
+node is obtained by invoking a macro |next_xref| instead of selecting the
+link field. If however we may need to insert a new node into the list, the
+the most convenient method is to use a pointer to a link field, which then
+must have type |(sixteen_bits*)|; for that case the macros |xnum| and
+|xlink|, which select the |num| and |next| fields respectively of a node
+specified by its index, and which yield expressions that one can assign to
+or take the address of, are more useful than |next_xref|. Since the
+beginning of the list is indicated by a |xref_pointer| rather than by its
+index, we need to convert that pointer into an index (for which the macro
+|xref_index| is supplied) when using the second method, and store this
+index in a local variable, not forgetting to update the original
+|xref_pointer| in case an insertion occurs at the front of the list.
+
+During collection of \xr.s, the lists are basically in decreasing order by
+section number, as a result of the fact that new nodes are added at the
+beginning of the list (for module names the situation is actually a bit more
+complicated, as described below), so that in that phase the |next| field
+really refers to the previous \xr. for the same name; at the end of Phase~I,
+however, the lists are reversed.
+
+The global variable |xref_switch| is set either to |def_flag| or to zero,
+depending on whether the next \xr. to an identifier is to be underlined or
+not in the index. This switch is set to |def_flag| when \:! or \:d or \:f is
+scanned, and it is cleared to zero when the next identifier or index entry
+\xr. has been made. Similarly, the global variable |mod_xref_switch| is
+either |def_flag|, |cite_flag|, or zero, depending on whether a module name
+is being defined, cited, or used. During Phase~II a number of \xr.s for
+identifiers will be changed into underlined ones, when the identifier is
+found to occur in a declaration or function definition, since these
+occurrences cannot be reliably recognised in Phase~I.
+
+@d xref equiv_or_xref
+@d next_xref(x) (&xmem[(x)->next])
+@d xnum(i) (xmem[i].num)
+@d xlink(i) (xmem[i].next)
+@d xref_index(p) ((sixteen_bits)((p)-xmem))
+@d cite_flag 0x4000
+ /* a |sixteen_bits| power of 2 that is at least |max_sections+2| */
+@d def_flag 0x8000 /* twice that */
+@d num_mask (cite_flag-1) /* a bit-mask for working modulo |cite_flag| */
+
+@<Typedef...@>=
+typedef struct xref_info
+{ sixteen_bits num; /* section number plus a multiple of |cite_flag| */
+ sixteen_bits next; /* index of the next \xr. in the list */
+} xref_info, *xref_pointer;
+
+@ We use an allocation pointer~|xref_ptr| that indicates how much of |xmem|
+is already in use. Unlike in the other cases of sequential allocation, where
+the allocation pointer points to the first free position, |xref_ptr| points
+to the last occupied position in |xmem|; the first node |xmem[0]| is already
+in use when \.{\me.} starts. All allocation of |xref_info| nodes is
+performed by calling |make_xref(n,i)|, where |n| is the |num| field of the
+new node, and |i| is the index of its successor in the list; after
+|make_xref| has been invoked, |xref_ptr| points to the new node.
+
+@d make_xref(n,i)
+ /* create \xr. node with |num==n| and successor |xmem[i]| */
+ if (++xref_ptr >= &xmem[max_refs])
+ overflow ("cross-reference"); @.cross-reference capacity exceeded@>
+ else xref_ptr->num=n, xref_ptr->next=i @;
+
+@<Global...@>=
+xref_info xmem[max_refs]; /* contains \xr. information */
+xref_pointer xref_ptr = &xmem[0]; /* the last used position in |xmem| */
+sixteen_bits xref_switch = 0, mod_xref_switch = 0;
+ /* either zero or |def_flag| */
+
+@ A first node is initially allocated, with its |num==0|; the node is used
+to initialise \xr. lists (see |init_id_name| and |init_module_name| below),
+and serves as a sentinel at the end of those lists.
+
+@<Set init...@>=
+xnum(0)=0; /* sentinel node terminating \xr. lists */
+
+@ A new \xr. for an identifier~|p| is formed by calling |new_id_xref(p)|
+with |section_count| and |xref_switch| set to the appropriate value.
+Multiple references to the same section are merged (with underlining
+activated if any reference requires so) while non-underlined references to
+one-letter identifiers, reserved words or identifiers with |ilk==NULL_like|
+(like `\.{NULL}') are ignored. Explicit \xr.s set by~\:: are never
+underlined, so |xref_switch| is ignored in this case. If the user has set
+the |no_xref| flag (the \.{-x} option of the command line), |new_id_xref| is
+active only for explicit \xr.s; when are reading a header file included
+by~\:h, it is inactive altogether (but since \:: is disabled in such header
+files, this case is treated together with the |no_xref|~case).
+
+@d no_xref (!flags['x'])
+@d make_xrefs flags['x'] /* should cross references be output? */
+
+@c
+void new_id_xref (id_pointer p)
+{ sixteen_bits f=xref_switch; xref_switch=0;
+ if (p->ilk==reference) f=0;
+ else if (f==0 && (unindexed(p) || length(p)==1)
+ || no_xref || including_header_file) return;
+ if ((p->xref->num&num_mask)==section_count) p->xref->num|=f;
+ else
+ {@; make_xref(section_count|f,xref_index(p->xref)); p->xref=xref_ptr; }
+}
+
+@ The \xr. lists for module names are slightly different. Suppose that a
+module name is defined in sections $d_1$,~\dots,~$d_k$, cited in sections
+$c_1$,~\dots,~$c_l$, and used in sections $u_1$,~\dots,~$u_m$, where the
+sequences of $d$'s, $c$'s and $u$'s each are in increasing order. Then its
+list will contain |@t$d_k$@>+def_flag|, \dots, |d1+def_flag|,
+|@t$c_l$@>+cite_flag|, \dots, |c1+cite_flag|, $u_m$, \dots, $u_1$,~$0$, in
+this order; the final~$0$ is the sentinel node, which allows the loops below
+to be a little faster. If the module name specifies an output file (with the
+\:( feature) then a node containing the special value |file_flag| is
+prepended to this list. The special ordering described here only serves for
+efficiency of insertion, and after Phase~II the order will be adjusted to
+the more natural sequence |d1+def_flag|, \dots, |@t$d_k$@>+def_flag|,
+|c1+cite_flag|, \dots, |@t$c_l$@>+cite_flag|, $u_1$, \dots,~$u_m$,~0.
+
+There can be multiple applied or cited occurrences of some module name
+within one section, but only one defining occurrence. Therefore, in the
+former cases we perform a test to avoid duplicate references.
+
+@d file_flag (cite_flag-1)
+ /* a distinguished value, not divisible by |cite_flag| */
+
+@c
+void new_mod_xref (mod_pointer p)
+{ sixteen_bits head, *q, m=section_count+mod_xref_switch;
+ if (p->xref->num==file_flag) q=&p->xref->next; /* skip |file_flag| */
+ else head=xref_index(p->xref),q=&head;
+ if (mod_xref_switch!=def_flag)
+ { while (xnum(*q)>m)
+ q=&xlink(*q); /* skip the $d_i$'s and possibly $c_i$'s */
+ if (xnum(*q)==m) return; /* don't duplicate */
+ }
+ make_xref(m,*q); mod_xref_switch=0;
+ if (q==&head) p->xref=xref_ptr; @+ else *q=xref_index(xref_ptr);
+}
+
+@ When a module name starts with \:(, we will call |set_file_flag|.
+
+@c
+void set_file_flag (mod_pointer p)
+{@; if (p->xref->num!=file_flag)
+ {@; make_xref(file_flag,xref_index(p->xref)); p->xref=xref_ptr; }
+}
+
+@ A third large area of memory is used for sixteen-bit `tokens', which
+appear in short lists similar to the strings of characters in |byte_mem|.
+Token lists are used to contain the result of \Cee\ code translated into
+\TeX\ form; further details about them will be explained later. Sequences of
+tokens which have been delimited as such are called texts, and can be
+accessed via elements of the array |text_mem|. Only a pointer to the first
+token of the sequence is stored, so in order to be able to compute the
+extent of a token list one needs a pointer into |text_mem|, which is called
+a |text_pointer|.
+
+@<Typedef...@>=
+typedef sixteen_bits token, * token_pointer, ** text_pointer;
+
+@~The first position of |tok_mem| that is unoccupied by replacement text is
+called |tok_ptr|, and the first unused location of |text_mem| is called
+|text_ptr|. Since we already know that the next text to be stored will start
+at |tok_ptr|, we make sure that |*text_ptr==tok_ptr| whenever we are not in
+the process of appending tokens. In this way we can also always find the end
+of any stored text as the beginning of the next one, which is computed by
+the macro |text_end|.
+
+@d tok_mem_end (&tok_mem[max_toks]) /* end of |tok_mem| */
+@d text_mem_end (&text_mem[max_texts]) /* end of |text_mem| */
+@d text_index(p) ((sixteen_bits)((p)-text_mem))
+@d text_at(i) (&text_mem[i])
+@d text_begin(p) (*(p))
+@d text_end(p) (*(p+1))
+
+@<Global...@>=
+token tok_mem[max_toks]; /* tokens */
+token_pointer text_mem[max_texts]; /* directory into |tok_mem| */
+token_pointer tok_ptr = tok_mem; /* first unused position in |tok_mem| */
+text_pointer text_ptr = text_mem; /* first unused position in |text_mem| */
+#ifdef STAT
+token_pointer max_tok_ptr = tok_mem; /* largest value of |tok_ptr| */
+text_pointer max_text_ptr = text_mem; /* largest value of |text_ptr| */
+#endif
+
+@ We initialise our invariant.
+
+@<Set init...@>=
+*text_ptr=tok_ptr;
+
+@ Here are the three functions needed to complete |id_lookup|. For a
+name~|x| stored in the table to match a string of length~|l| starting at~|q|
+and of requested ilk~|ilk|, it is required that the names match exactly, and
+either |x->ilk==ilk|, or |ilk==normal| and |x->ilk| specifies some reserved
+word (where the ilks |TeX_like| and |NULL_like| are considered as reserved).
+This rule means that if we look up an ``identifier'' whose name matches
+reserved word stored in the table, the reserved word rather than an
+identifier is returned, so that recognition of reserved words is automatic
+when the tables are properly initialised. The other two functions install
+the sentinel node |xmem[0]| at the end of each \xr. list as it is created.
+
+@c
+boolean names_match (id_pointer x, char* q, int l, int ilk)
+{ char* p=name_begin(x);
+ if ((x->ilk==ilk || ilk==normal && reserved(x)))
+ @/{@; while (--l>=0) if (*p++!=*q++) return false; return *p=='\0'; }
+ else return false;
+}
+
+void init_id_name (id_pointer p, int t)
+{@; p->ilk = t; p->xref = &xmem[0]; }
+
+void init_module_name (mod_pointer p) {@; p->xref=&xmem[0]; }
+
+
+@* Skipping and copying \TeX\ material. @:title@>
+The source file consists roughly speaking of two sorts of input, namely
+\TeX\ material and pieces of \Cee~text. The limbo part is entirely the
+realm of \TeX, and the sections are divided (possibly quite unevenly)
+into a \TeX~part, and the remainder which is~\Cee, although the distinction
+is not quite as pure here due to `\pb' interjections and comments.
+The meddling of \.{\me.} (and indeed of all of \.{CWEB}) in the \TeX\
+parts is extremely superficial: it is restricted to skipping or copying it,
+only replacing \:@@ by~`\.{@@}', and the main interest in these parts
+of the source is to find out where they end. By contrast the \Cee\ fragments
+have to be broken up into meaningful parts by \.{\me.} in order to perform
+the required operations of collecting \xr.s and formatting for
+pretty-printing output. Before we study that more complicated process of
+lexical scanning, let us study the easier question of what happens with the
+\TeX~parts.
+
+The three tasks of passing over limbo material, over the \TeX~part of a
+section, and over a comment embedded in the \Cee~part are sufficiently
+different that they merit separate routines. Moreover, the entire source is
+scanned twice by \.{\me.}, with different purposes, and so the scanning
+routines have two flavours. We could choose either to use distinct scanning
+routines on both passes, or to have a single all-purpose scanning routine.
+The first option is more attractive if the functions are simple and small,
+and can perform tasks specific to their pass on-the-fly, while the second
+option is to be favoured if the scanning task becomes complicated, to avoid
+near-duplication of substantial pieces of code. We have chosen the first
+option for the routines that pass over ordinary \TeX\ material, both in
+limbo and in sections, and the second option for the function passing over
+comments; for the lexical scanning of \Cee~text we shall also write a single
+function for both phases. Where distinct routines are used we must of
+course make sure that they are sufficiently similar that they will make the
+same decisions about where these parts of the source text end.
+
+@ Although the functions to be described here have a quite trivial task,
+they will eventually run into a control code that terminates their action,
+and so we have to be aware of tokens that do not belong in the \TeX~part.
+The relevant tokens form only a small subset of the tokens that can be
+recognised by the function |get_next| that scans \Cee~text, so we defer
+an enumeration of possible tokens to a later point. At this point it
+is sufficient to know there is an array |ccode| which translates characters
+that may follow `\.{@@}' in a control code into a numeric value greater
+than any (unsigned) character, which values have symbolic names and are
+arranged in order of increasing significance. In particular any value
+greater than or equal to |format| terminates the \TeX~part of a section,
+and the largest value of all is |new_section|. By using the same encoding,
+the \TeX~text scanning functions can return a value directly usable for
+continuing the scan into \Cee~territory. Tokens consisting of a single
+character are represented as that character itself by |get_next|, and at
+this point the relevant case is the character~`\.\v' which interrupts
+\TeX~text.
+
+Like in |CTANGLE|, we always access |ccode| by means of the macro |code_of|.
+
+@d code_of(c) ccode[(unsigned char)(c)]
+
+@<Global...@>=
+int ccode[UCHAR_MAX + 1]; /* meaning of a character following `\.{@@}' */
+
+@ This section performs the simplest of all scanning operations, namely to
+skip through portions of the input that are not in any sections, i.e., that
+precede the first section, on the first pass. It uses the fact that
+|get_line| places a~|' '| at~|*limit|, so that placing the sentinel cannot
+inadvertently create a token \.{@@@@}. Although a few control codes like \:q
+are allowed in limbo, they can be ignored here, since they do not affect the
+recognition of the end of the limbo part. An exception is the format code
+\:s, which must be obeyed in this first phase; the code doing this will be
+given together with the processing of other format codes. After the code
+below is executed, the value of |input_has_ended| will tell whether or not a
+section has actually been found.
+
+@< Skip the limbo part @>=
+while (find_char())
+{ limit[1]='@@'; /* place a sentinel */
+ while (*loc++!='@@') {}
+ if (loc<=limit)
+ { int c=code_of(*loc++);
+ if (c==new_section) break;
+ if (c==format) @< Process a format code in limbo @>
+ }
+}
+
+@ In Phase~II, the corresponding task is slightly less trivial, as the limbo
+material must also be copied to the output; it is performed by the
+|copy_limbo| function. Output is generated by calling |out| for ordinary
+characters, and |finish_line| when a completed line is to be sent out. No
+spaces or tab marks are copied by |copy_limbo| into the beginning of a line
+(indicated by the macro |output_line_empty|), nor by the function |copy_TeX|
+below. As a consequence a line with only spaces and removed items (like \:q,
+\:s, or for |copy_TeX| \xr. entries for the index) will produce a completely
+empty line of output; such lines will only be actually written out by
+|finish_line| if they come from a completely blank input line. Any pair \:@@
+is replaced by `\.{@@}', and apart from this only the control codes \:q,
+\:s, and \:l are allowed to be present before the first section is
+encountered. Note that we have chosen to detect violations of this rule in
+Phase~II; on other occasions however, errors were checked in Phase~I, and we
+can then assume that errors are absent in Phase~II, as we would not even get
+there otherwise.
+
+@c
+void copy_limbo (void) /* copy \TeX\ code until the next section begins */
+{ while (loc<=limit || (finish_line(),get_line()))
+ { eight_bits c;
+ limit[1]='@@'; /* place a sentinel */
+ while ((c=*loc++)!='@@')
+ if (!(output_line_empty() && isspace(c))) out(c);
+ if (loc<=limit)
+ switch(code_of(*loc++))
+ {
+ case new_section: return;
+ case ignored_text: get_control_text(); break;
+ case format: get_next(); get_next(); break; /* skip two identifiers */
+ case char_trans: out_str("\\ATL "); break; @.\\ATL@>
+ default: err_print("! Double @@ required in limbo part");
+ @.Double @@ required...@>
+ /* fall through */
+ case at_sign_image: out('@@');
+ }
+ }
+}
+
+@ The function |skip_TeX| is used on the first pass to skip through the
+\TeX\ code at the beginning of a section. It returns the next control code
+or `\.\v' found in the input. A |new_section| is assumed to exist at the
+very end of the file. Any comment character `\.{\%}' that is not escaped
+(with a backslash) will disable recognition of `\.\v' and cross-referencing
+control codes for the remainder of the line, so that no spurious \xr.s
+will be created to commented-out text. Recognition of control codes that
+terminate the \TeX~part of the section will still be enabled however, to
+maintain synchronisation with the activities of |CTANGLE|.
+
+@f skip_TeX TeX
+
+@c
+int skip_TeX (void) /* skip past pure \TeX\ code */
+{ char c;
+ while (find_char())
+ { limit[1]='@@';
+ while ((c=*loc++)!='@@' && c!='%')
+ if (c=='|') return c;
+ else if (c=='\\' && *loc!='@@') ++loc;
+ /* ignore `\.{\\\%}' and `\.{\\\v}' */
+ if (loc<=limit)
+ if (c=='@@') return code_of(*loc++);
+ else /* ignore remainder of line unless a major control code occurs */
+ do @+
+ if ((c=*loc++)=='@@' && code_of(*loc++)>=format)
+ return code_of(loc[-1]);
+ while (loc<limit);
+ }
+ return new_section;
+}
+
+@ During Phase~II, the function |copy_TeX| processes the \TeX\ code at the
+beginning of a section; for example, the words you are now reading were
+copied in this way. Like |skip_TeX|, it returns the next control code or
+`\.\v' found in the input, and ignores anything that is commented out,
+except control codes that terminate the \TeX~part; the characters after the
+`\.{\%}' are not even copied to the output. (Note that in the limbo part
+comments {\sl are\/} copied, allowing any commented-out header information
+such as copyright notices to be passed on to the \TeX~file.)
+
+@f copy_TeX TeX
+
+@c
+int copy_TeX (void) /* copy pure \TeX\ material */
+{ eight_bits c; /* current character being copied */
+ while (loc<=limit || (finish_line(),get_line()))
+ { limit[1]='@@';
+ while((c=*loc++)!='@@')
+ { if (c=='|') return '|';
+ if (!(output_line_empty() && isspace(c))) out(c);
+ if (c=='%') break;
+ if (c=='\\' && *loc!='@@') out(*loc++);
+ /* copy `\.{\\\%}' and `\.{\\\v}' */
+ }
+ if (loc<=limit)
+ if (c=='@@') return code_of(*loc++);
+ else /* ignore remainder of line unless a major control code occurs */
+ do
+ if ((c=*loc++)=='@@' && code_of(*loc++)>=format)
+ return finish_line(),code_of(loc[-1]);
+ while(loc<limit);
+ }
+ return new_section;
+}
+
+@ The final \TeX~scanning function is |scan_comment| which scans the
+\TeX~text in comments. It is used both in Phase~I and in Phase~II, but
+stores the characters it sees only if |phase==2|. The function returns the
+token that terminated its action, which is one of |end_comment|, `\.\v' or
+(in erroneous cases) |new_module|.
+
+@< Prototypes @>=
+int scan_comment(int* bal, boolean one_liner);
+ /* skip or copy \TeX\ text in comments */
+
+@~The function |scan_comment| counts the braces it encounters to see if they
+are balanced; the parameter |bal| points to an integer variable keeping
+track of the brace level (it can be positive initially if |scan_comment| is
+called after `\pb' occurring within braces in a comment). This feature is
+mainly a remnant from \.{CTANGLE}'s Pascal origins, since there comments are
+closed by `\.\}', and counting is necessary to establish which braces are
+for \TeX\ and which are not. Although there is no such need in \Cee, the
+feature is retained. The parameter |one_liner| tells whether we are dealing
+with a \Cpp\ one-line comment.
+
+@c
+int scan_comment (int* bal, boolean one_liner)
+{ char c; boolean forced_out=false; /* prematurely terminated? */
+ while (one_liner ? loc<limit
+ : find_char() && (*loc!='*' || loc[1]!='/' ))
+ @< Handle next character; if |'|'|, |return| it,
+ if a new section starts, set |forced_out| and |goto done| @>
+ if (input_has_ended)
+ forced_out=true,err_print("! Input ended in mid-comment");
+ @.Input ended in mid-comment@>
+ else if (!one_liner) loc+=2; /* move past `\.{*{}/}' */
+done:
+ if (*bal>0) err_print("! Too few closing braces in comment");
+ @.Too few closing braces...@>
+ return forced_out ? new_section : end_comment;
+}
+
+@ Like elsewhere, `\.@@' should be doubled in comments; |scan_comment|
+replaces them by a single `\.@@'. In Phase~II, instead of copying the \TeX\
+material into the output buffer like |copy_TeX|, |scan_comment| copies it
+into the token memory, since comments will be output together with the rest
+of the formatted \Cee~code. To this end it calls the macro |app_char_tok(c)|
+rather than |out(c)|. When including header files comments should be skipped
+with no processing at all, so this module is almost completely disabled in
+that case.
+
+@< Handle next character... @>=
+if (including_header_file) ++loc; /* don't process characters here */
+else
+{ switch(c=*loc++)
+ {
+ case '|': return '|'; /* beginning of `\pb' inside comment */
+ case '@@':
+ if (*loc++!='@@')
+ if (code_of(loc[-1])!=new_section)
+ err_print("! Double @@ required in comment");
+ @.Double @@ required...@>
+ else
+ {@; err_print("! Section ended in mid-comment");
+ @.Section ended in mid-comment@>
+ forced_out=true; goto done;
+ }
+ break;
+ case '\\':
+ if (*loc!='@@') {@; if (phase==2) app_char_tok(c); c=*loc++; }
+ break;
+ case '{': ++*bal; break;
+ case '}':
+ @+if (*bal>0) --*bal;
+ @+else err_print("! Extra } in comment");
+ @.Extra \} in comment@>
+ @+break;
+ case '/': @+ if (*loc=='*') err_print("! Nested comment");
+ @.Nested comment@>
+
+ }
+ if (phase==2) app_char_tok(c);
+}
+
+
+@* Getting the next token. @:title@>
+We now come to the most important lexical scanning function, |get_next|,
+which locates and classifies the next token of \Cee~text. Before we give the
+function itself, we shall first specify which kind of values it can return.
+The result value is an integer, which can either be at most |UCHAR_MAX|, in
+which case the character code represents that character, or possibly a
+compressed multi-character symbol as defined by the macros
+in~\.{common.inc}, or it is one of the values greater than |UCHAR_MAX|
+defined in the enumeration below, which indicates a particular token or
+class of tokens or a control code. (Actually, |underline| and
+|trace0|,~\dots,~|trace3| are never returned by |get_next| because they are
+treated within the scanner; they are included however because they are
+distinguished control codes.) The ordering of this enumeration is designed
+to simplify \.{\me.}'s logic; for example, from |format| on, larger
+numbers are given to the control codes that denote more significant
+milestones, and the code of |new_section| is the largest of all. Also, the
+sequence |identifier|,~\dots,~|xref_mark| runs parallel to the first five
+|ilk|~codes. For efficiency all codes that produce a fixed scrap are placed
+at the beginning; these are all codes preceding |ignore|. The code \:> is
+treated as ignored because it should not occur in places where we are not
+searching for it.
+
+@f TeX_string TeX
+
+@<Typedef and enum...@>=
+enum @/
+{ at_sign_image = UCHAR_MAX+1, /* quoted `\.{@@}' */
+ or, /* \:v */
+ mul_assign, div_assign, mod_assign, plus_assign, minus_assign,
+ left_assign, right_assign, and_assign, xor_assign, or_assign,
+ sh_sh, ellipsis, colon_colon, @/
+ start_preproc, end_preproc, /* begin and end of a preprocessor directive */
+ join, /* \:\& */
+ thin_space, /* \:, */
+ math_break, /* \:\v */
+ line_break, /* \:/ */
+ big_line_break, /* \:) */
+ no_line_break, /* \:+ */
+ backup_line, /* \:\\ */
+ pseudo_semi, /* \:; */
+ force_expr_open, force_expr_close, /* \:[, \ \:] */
+ include_preproc, /* \:p */
+@)
+ ignore, /* control code of no interest to \.{\me.} */
+ constant, string, /* the next five codes should remain in this order */
+ identifier, /* any (possibly reserved) word found in \Cee\ text */
+ xref_roman, xref_wildcard, xref_typewriter, xref_mark,
+ /* \:\^, \ \:?, \ \:., \ \:: */
+ refer, /* \:\# */
+ TeX_string, /* \:t */
+ verbatim, /* \:= */
+ ignored_text, /* \:q */
+ char_trans, /* \:l */
+ ASCII_code, /* \:' */
+ begin_comment, end_comment,
+ underline, /* \:! */
+#ifdef DEBUG
+ trace0, trace1, trace2, trace3, /* \:0, \dots, \:3 */
+#endif
+ format, /* \:f */
+ definition, /* \:d */
+ header, /* \:h */
+ begin_C, /* \:c */
+ module_name, /* \:< and \:( */
+ new_section /* \:\ , \:\~ and \:* */
+};
+
+@ Here we initialise the |ccode| table in accordance with the comments given
+in the enumeration above.
+
+@<Set ini...@>=
+{ unsigned char c=0;
+ do ccode[c] = isspace(c) ? new_section : ignore; while(c++!=UCHAR_MAX);
+ ccode['@@'] = at_sign_image;
+@/ccode['v'] = ccode['V'] = or;
+@/ccode['!'] = underline; /* set definition flag */
+@/ccode['^'] = xref_roman; /* index entry to be typeset normally */
+@/ccode['?'] = xref_wildcard; /* index entry to be in user format */
+@/ccode['.'] = xref_typewriter; /* index entry to be in typewriter type */
+@/ccode[':'] = xref_mark; ccode['#']=refer; /* explicit \xr.s */
+@/ccode['t'] = ccode['T'] = TeX_string; /* \TeX\ box within \Cee\ text */
+@/ccode['='] = verbatim;
+@/ccode['q'] = ccode['Q'] = ignored_text;
+@/ccode['l'] = ccode['L'] = char_trans;
+@/ccode['\''] = ASCII_code;
+@/ccode['&'] = join; /* concatenate two tokens */
+@/ccode[','] = thin_space;
+@/ccode['|'] = math_break;
+@/ccode['/'] = line_break;
+@/ccode[')'] = big_line_break;
+@/ccode['\\']= backup_line;
+@/ccode['+'] = no_line_break;
+@/ccode[';'] = pseudo_semi;
+@/ccode['['] = force_expr_open; ccode[']'] = force_expr_close;
+ccode['p'] = ccode['P'] = include_preproc;
+#ifdef DEBUG
+ ccode['0'] = trace0; ccode['1'] = trace1;
+ ccode['2'] = trace2; ccode['3'] = trace3;
+#endif
+@/ccode['f'] = ccode['F'] = ccode['s'] = ccode['S'] = format;
+@/ccode['d'] = ccode['D'] = definition;
+@/ccode['h'] = ccode['H'] = header;
+@/ccode['c'] = ccode['C'] = begin_C;
+ /* \Cee\ text in unnamed module */
+@/ccode['<'] = ccode['('] = module_name; /* beginning of a module name */
+@/ccode['~'] = ccode['*'] = new_section; /* beginning of a new section */
+ if (compatibility_mode)
+ @< Reset some control codes to match \LKC. @>
+}
+
+@ In \.{CWEBx} there are a few control codes that also exist in Levy/Knuth
+\.{CWEB} but have a different meaning. In compatibility mode we reassign the
+meaning of these codes to that of \LKC., making their usual function
+inaccessible, since it is not intended that hybrid programs should be
+written using the codes of \LKC. together with features particular to
+\.{CWEBx}.
+@^Levy/Knuth \.{CWEB}@>
+
+@< Reset some control codes... @>=
+{ ccode['h']=ccode['H']=include_preproc; /* \:h means \:p */
+ ccode['p']=ccode['P']=begin_C; /* \:p means \:c */
+ ccode['#']=big_line_break; /* \:\# means \:) */
+ ccode[':']=xref_wildcard; /* \:: means \:? */
+}
+
+@ We come now to the definition of |get_next| itself. When returning certain
+values it will have performed some additional actions, as follows.
+
+\yskip\hang |constant|, |string|, |TeX_string|, |verbatim|: The token is
+ copied into |mod_text|, with slight modifications; the global variables
+ |id_first| and |id_loc| are set to the beginning and ending-plus-one
+ locations in |mod_text|.
+
+\yskip\hang |identifier|, |xref_roman|, |xref_wildcard|, |xref_typewriter|,
+ |xref_mark|, |refer|, |module_name|: The global variable |cur_id| or
+ |cur_mod| will point to the identifier, control text or module name that
+ has just been scanned (for the |xref_roman|, \dots, |xref_mark| this is
+ only true if |phase==1|).
+
+\yskip\hang |underline|: this value is not even returned. If |get_next| sees
+ \:!, it sets |xref_switch| to |def_flag| and goes on to the next token.
+\yskip
+
+Preprocessing directives complicate scanning in two ways: first, their
+lexical structure is different from that of ordinary text, and second, a
+preprocessor directive can occur at any place in a \Cee~text, so
+syntactically it should be treated like a comment. The first issue is
+resolved by maintaining a static variable |preprocessing| which is~$0$ in
+ordinary \Cee~text, $2$ in \&{\#include} directives, and~$1$ in other
+preprocessor directives. The second issue must be dealt with during parsing,
+and in order to be able to do so, |get_next| emits special tokens
+|start_preproc| and |end_preproc| when it has sensed the boundaries of a
+preprocessor directive.
+
+@<Global...@>=
+id_pointer cur_id; /* identifier or index entry just scanned */
+mod_pointer cur_mod; /* module name just scanned */
+int preprocessing=0;
+
+@ As one might expect, |get_next| consists mostly of a big switch that
+branches to the various cases that can arise. Any character |c>=0x80| that
+is not contained in a string or comment is assumed to belong to an
+identifier.
+
+@< Prototypes @>= int get_next (void);
+@~@c
+int get_next (void) /* produces the next input token */
+{ eight_bits c; /* the current character */
+restart:
+ if (!find_char()) {@; preprocessing=0; return new_section; }
+ @< If a preprocessor line has ended, handle it and |return end_preproc| @>
+ if ((c=*loc++)=='@@')
+ @< Get control code and possibly module name, and either |return| it,
+ or |goto restart| if ignored or handled within |get_next| @>
+ if (isspace(c))
+ if (preprocessing>0) return ' '; /* keep spaces in preprocessor lines */
+ else goto restart; /* ignore other white space */
+ if (c=='L' && (*loc=='\'' || *loc=='"'))
+ {@; get_string(); return string; }
+ if (isalpha(c) || c=='_' || c>=0x80)
+ {@; @< Get an identifier @> return identifier; }
+ if (isdigit(c) || c=='.' && isdigit((eight_bits)*loc))
+ @/{@; @< Get a numeric constant @> return constant; }
+ if (c=='\'' || c=='"' || (c=='<' && preprocessing==2))
+ {@; get_string(); return string; }
+ if (c=='#' && loc==&buffer[1])
+ @/{@; @< Handle start of preprocessor directive; maybe |goto restart| @>
+ return start_preproc; }
+ if (c=='\\' && preprocessing>0 && loc==limit)
+ { ++loc; /* move past |limit|, so |get_line| will be called */
+ goto restart;
+ }
+ @< Compress multi-character tokens @>
+ return c;
+}
+
+@ When a `\.\#' is seen as the first character of a line, |get_next| returns
+a special code |start_preproc| and sets |preprocessing| to a non-zero value.
+Because of the freakish use of `\.<' and `\.>' to delimit a file name in
+lines that start with `\.{\#include}', those lines get an extra-special
+treatment, and |preprocessing| is set to~$2$ rather than to~$1$. If however
+we encounter a `\.{\#include}' directive when we are already busy reading a
+header file due to \:h in Phase~I, then we actually execute the directive,
+and start reading the nested header file; this action will be transparent to
+the stream of tokens produced, so we |goto restart| to fetch the first token
+from the newly opened file.
+
+@<Handle start of prep...@>=
+{ while (loc<limit && isspace((eight_bits)*loc)) ++loc;
+ /* allow spaces after `\.\#' */
+ if (limit-loc>=7 && strncmp(loc,"include",7)==0) /* `\.{\#include}' line */
+ if (including_header_file)
+ @/{@; loc+=7; push_input_file(true,false); goto restart; @+}
+ /* start nested header file */
+ else preprocessing=2;
+ else preprocessing=1;
+}
+
+@ When we get to the end of a preprocessor line, we lower the flag and
+send a code |end_preproc| (unless the last character was a `\.\\', but that
+case has already been taken out and never comes here).
+
+@<If a prep...@>=
+if (preprocessing>0 && loc==limit)
+{@; preprocessing=0; return end_preproc; }
+
+@ The following code assigns values to the compound operators `\.{++}',
+`\.{--}', `\.{->}', `\.{>=}', `\.{<=}', `\.{==}', `\.{<<}', `\.{>>}',
+`\.{!=}', `\.{\v\v}', and `\.{\&\&}', to the special symbols `\.{/*}',
+`\.{*/}', `\.{//}', `\.{...}', `\.{::}', and `\.{\#\#}', and moreover, if not
+in compatibility mode, to the assignment operators `\.{*=}', `\.{/=}',
+`\.{+=}', `\.{-=}', `\.{>>=}', `\.{<<=}', `\.{\&=}', `\.{\^=}', `\.{\v=}'.
+Although the comment ending token `\.{*/}' should never occur when we are
+scanning \Cee~text, we must recognise it in order to detect unclosed `\pb'
+constructions within comments (fortunately no legal combination of operators
+causes an adjacent sequence `\.{*/}'; only `\.*' immediately followed by a
+comment could cause it, and the user should simply not do this). The reason
+that in compatibility mode we are forced to follow suit with \LKC.
+@^Levy/Knuth \.{CWEB}@> in not combining assignment operators is a truly
+stupid one: @:truly stupid@> the Stanford GraphBase @^Stanford GraphBase@>
+contains fragments like `\.{\$\v n1\v=n\_1\$}' which will cause trouble if
+`\.{\v=}' is parsed as a single symbol (of course the fragments should have
+been written as `\.{\v n1\v\$\{\}=n\_1\$}', but we have set the goal to handle
+the GraphBase as it is, and moreover its files cannot be changed). For
+splitting up the assignment operators here, we shall have to pay the price of
+including syntax rules (in compatibility mode) for recombining them.
+
+The macros defined below are for strictly local use, so we don't mind that
+they could mess things up if used in the |if|-part of an |if|-|else|
+statement. Also, there is no need to test whether |*loc| or |loc[1]| lie
+beyond |limit|, since if they do, they are not evaluated anyway because we
+know |*limit==' '|. Note that the three-symbol assignment operators
+`\.{>>=}' and~`\.{<<=}' must be tested before their non-assignment
+counterparts `\.{>>}' and~`\.{<<}'.
+
+@d compress2(char2,code) if (*loc==char2) return ++loc, code @;
+@d compress3(char2,char3,code)
+ if (*loc==char2 && loc[1]==char3) return loc+=2, code @;
+@d comp_ass_op2(code)
+ if (*loc=='=' && !compatibility_mode) return ++loc, code @;
+@d comp_ass_op3(char2,code)
+ if (*loc==char2 && loc[1]=='=' && !compatibility_mode) return loc+=2,code @;
+
+@<Compress multi...@>=
+switch (c) {
+case '/': compress2('*',begin_comment); @+
+ if (C_plus_plus) compress2('/',begin_comment);
+ comp_ass_op2(div_assign); break;
+case '*': compress2('/',end_comment); comp_ass_op2(mul_assign); break;
+case '%': comp_ass_op2(mod_assign); break;
+case '+': compress2('+',plus_plus); comp_ass_op2(plus_assign); break;
+case '-': compress2('-',minus_minus); compress2 ('>', minus_gt);
+ comp_ass_op2(minus_assign); break;
+case '=': compress2('=',eq_eq); break;
+case '>': compress2('=',gt_eq); comp_ass_op3('>',right_assign);
+ compress2 ('>',gt_gt); break;
+case '<': compress2('=', lt_eq); comp_ass_op3('<',left_assign);
+ compress2 ('<', lt_lt); break;
+case '&': compress2('&',and_and); comp_ass_op2(and_assign); break;
+case '^': comp_ass_op2(xor_assign); break;
+case '|': compress2('|',or_or); comp_ass_op2(or_assign); break;
+case '!': compress2('=',not_eq); break;
+case '.': compress3('.','.', ellipsis); break;
+case '#': compress2 ('#', sh_sh); break;
+case ':': @+ if (C_plus_plus) compress2 (':',colon_colon);
+}
+
+@ The code below is almost identical to the corresponding module in
+|CTANGLE|; the difference is that we accept characters |c>=0x80| without
+testing whether a translation is defined for them (since we have not
+recorded such information) and that we always look up identifiers, even if
+they have length~$1$.
+
+@< Get an identifier @>=
+{ id_first=--loc; /* mark beginning of identifier */
+ do c=*++loc; while (isalnum(c) || c=='_' || c>=0x80);
+ cur_id= id_lookup(id_first,loc,normal);
+}
+
+@ In \Cee~text, numeric constants are specified in the ordinary \Cee~manner:
+octals start with `\.0', hexadecimals with `\.{0x}', and anything starting
+with a non-zero digit is a decimal constant; however for octal and
+hexadecimal constants \.{\me.} will produce output using italics or
+typewriter font, respectively, and introduced by a raised circle or hash
+mark. Forgivably in contradiction with the definition of~\Cee, we treat the
+ubiquitous constant~`0' as decimal rather than as octal. When the kind of
+constant we are dealing with has been recognised, we represent this
+information internally by special marker characters, which replace the marks
+used in the \Cee~source (like `\.{0x}' for hexadecimal or `\.E' for the
+exponent of a floating point constant). These markers are characters like
+`\.\^' that will get a backslash prepended by the output routine for
+constants, so that formatting of the constants can be controlled by defining
+the corresponding \TeX\ control words (like `\.{\\\^}' in the case
+mentioned) appropriately.
+
+@d shift_and_store(ch) (*id_loc++=ch,c=*++loc)
+
+@<Get a numeric constant@>=
+{ id_first=id_loc=&mod_text[1];
+
+ if (c=='0' && (isdigit(c=*loc) || tolower(c)=='x')) /* octal or hex */
+ { if (isdigit(c)) /* octal constant with at least two digits */
+ { *id_loc++ = '~'; /* store `\.\~' in place of leading `\.0' */
+ do shift_and_store(c); while (isdigit(c));
+ /* copy second and following digits */
+ }
+ else /* hex constant */
+ { shift_and_store('^'); /* replace `\.{0x}' by `\.\^' */
+ while (isxdigit(c)) shift_and_store(c);
+ }
+ }
+ else /* decimal constant */
+ { c=*--loc; /* recover first digit or decimal point */
+ while (isdigit(c)) shift_and_store(c);
+ if (c=='.') @+ do shift_and_store(c); while (isdigit(c));
+ if (tolower(c)== 'e') /* floating point constant with exponent */
+ { shift_and_store('_'); /* replace `\.e' by `\.\_' */
+ if (c=='+' || c=='-') {@; *id_loc++ = c; c=*++loc; }
+ while (isdigit(c)) shift_and_store(c); /* exponent */
+ }
+ }
+ if (isalpha(c)) /* `\.{U}', `\.{L}', and/or `\.{F}' suffix */
+ @/{@; *id_loc++ = '$'; do shift_and_store(c); while (isalpha(c)); }
+}
+
+@ After an `\.{@@}' sign has been scanned, the next character tells us
+whether there is more work to do. This code uses the fact that our internal
+code numbers |xref_roman|, |xref_wildcard|, |xref_typewriter|, and
+|xref_mark| are consecutive in the stated order, as are the |ilk| codes
+|roman|, |wildcard|, |typewriter|, and |reference|. We silently eliminate the
+possibility of indexing the empty string, since it would cause anomalous
+situations in hashing and sorting of the index, and it would look rather
+silly anyway.
+
+@<Get control code and possibly module name...@>=
+if (including_header_file) goto restart; /* ignore `\.@@' in header files */
+else
+{ int cc=code_of(*loc++);
+ switch (cc)
+ { case ignore: goto restart;
+ case underline: xref_switch=def_flag; goto restart;
+#ifdef DEBUG
+ case trace0: case trace1: case trace2: case trace3: @+
+ if (phase==2) tracing=cc; @+ goto restart;
+#endif
+ case char_trans:
+ err_print("! `@@l' only allowed in limbo"); goto restart;
+ @.`@@l' only allowed in limbo@>
+ case ASCII_code: @< Scan an \caps{ASCII} constant @> @+ return string;
+ case module_name:
+ @< Scan the module name and make |cur_mod| point to it @> @+ break;
+ case ignored_text: get_control_text(); goto restart;
+ case verbatim: case TeX_string: get_control_text(); break;
+ case xref_roman: case xref_wildcard: case xref_typewriter:
+ case xref_mark: case refer:
+ if (get_control_text()) goto restart; /* don't index empty strings */
+ if (cc==refer) cur_id=id_lookup(id_first,id_loc,reference);
+ else if (phase==1)
+ cur_id=id_lookup(id_first,id_loc,cc-xref_roman+roman);
+ }
+ return cc;
+}
+
+@ There is no reason why we should allow a newline within an \caps{ASCII}
+constant, even if it is escaped.
+
+@< Scan an \caps{ASCII} constant @>=
+{ id_first=&mod_text[1]; strncpy(id_first,"@@'",2); id_loc=&id_first[2];
+ while ((*id_loc++=c=*loc++)!='\'')
+ { if (c=='\\')
+ *id_loc++=*loc++; /* copy any character following backslash */
+ else if (c=='@@' && *loc++!='@@')
+ {@; err_print("! Double @@ required in strings"); --loc; }
+ @.Double @@ required...@>
+ if (loc>=limit) {@; err_print("! ASCII constant didn't end"); break; }
+ @.ASCII constant didn't end@>
+ }
+}
+
+@ Here |get_module_name| does nearly all the work; we only need to recognise
+when \:( is used rather than~\:<, and if so insert |file_flag| in the
+appropriate \xr. list.
+
+@< Scan the module name... @>=
+{ boolean file_module=loc[-1]=='(';
+ cur_mod=get_module_name();
+ if (file_module && phase==1 && cur_mod!=NULL) set_file_flag(cur_mod);
+}
+
+
+@* Phase I processing. @:title@>
+We now have accumulated enough functions to make it possible to carry out
+\.{\me.}'s first pass over the source file. If everything works right,
+both Phase~I and Phase~II of \.{\me.} will assign the same numbers to
+sections, and these numbers will agree with what \.{CTANGLE} does.
+
+We keep track of the current section number in |section_count|, which
+is the total number of sections that have started. Sections which have
+been altered by a change file entry have their |changed_section| flag
+turned on during the first phase. Meanwhile we also keep track using
+|change_exists| of whether any change was made at all, which will tell us
+whether the index has changed. The global variable |next_control| often
+contains the most recent output of |get_next|; in interesting cases, this
+will be the control code that ended a section or part of a section.
+
+@d shift() (next_control=get_next())
+
+@<Global...@>=
+boolean change_exists=false; /* has any section changed? */
+int next_control; /* control code waiting to be acted upon */
+
+@ The overall processing strategy in Phase~I has the following
+straightforward outline.
+
+@c
+void phase_one (void)
+ /* read all the user's text and store the \xr.s */
+{ phase=1; reset_input(); section_count=0;
+ @< Skip the limbo part @>
+ while (!input_has_ended)
+ @< Store cross-reference data for the current section @>
+ if (change_exists) mark_section_as_changed(section_count);
+ /* the index changes if anything does */
+ @< Print error messages about unused or undefined module names @>
+ @< Reverse the \xr. lists for identifiers @>
+}
+
+@ The outline for each section is equally straightforward.
+
+@< Store cross-reference data... @>=
+{ if (++section_count==max_sections)
+ overflow("section number"); @.section number capacity exceeded@>
+ if (loc[-1]=='*') print_section_progress ();
+ @< Store cross-references in the \TeX~part of a section @>
+ @< Store cross-references in the definition part of a section @>
+ @< Store cross-references in the \Cee~part of a section @>
+ if (section_changed(section_count)) change_exists=true;
+ }
+
+@ We interrupt our refinement of |phase_one| temporarily for some auxiliary
+functions that are used in its various parts.
+
+@< Prototypes @>=
+void C_xref (boolean); /* make \xr.s within in straight \Cee~text */
+void outer_xref (void); /* make \xr.s in \Cee~text with comments */
+void mod_check (mod_pointer); /* check \xr.s for module names */
+
+@ The function |C_xref| stores references to identifiers in \Cee~text,
+either for an entire fragment enclosed in `\pb', or for a portion of a macro
+or section body delimited by comments or module names. The boolean parameter
+|inner| tells whether the former is the case; if so |C_xref| should stop
+with |next_control=='|'|, and otherwise it should stop with either
+|next_control==begin_comment| or |next_control>=format|. In fact, setting
+|inner| will make |C_xref| stop at |'|'| but proceed past module names,
+while comment delimiters and major control codes will make |C_xref| stop
+regardless of |inner|. If |next_control>=format| when |C_xref| is called,
+nothing will happen, but it is safe to call the function when
+|next_control=='|'| or |next_control==end_comment|, which will be stepped
+over rather than considered as termination condition. Thus we can avoid
+saying |shift()| immediately before calling |C_xref| on several occasions.
+After a `\.\#' that starts a preprocessor directive, an identifier must
+follow, which must not be \xr.d; this is achieved by performing an extra
+|shift()|. If no identifier follows, we report an error, but do not perform
+the extra |shift()|. The code below uses the fact that our internal code
+numbers |identifier|, |xref_roman|, |xref_wildcard|, |xref_typewriter|, and
+|xref_mark| are consecutive.
+
+The other task of Phase~I is to collect all unusual |ilk| assignments,
+and the subtler part of this is the processing of |typedef| declarations.
+The details of this process will be explained later, but this is where
+it is hooked into the other actions, since all relevant tokens (which do
+not include module names or comments) pass here one by one.
+
+@c
+void C_xref (boolean inner)
+{ while (next_control<format || next_control==module_name && inner)
+ { @< Keep track of tokens relevant to |typedef| declarations @>
+ if (next_control>=identifier && next_control<=xref_mark)
+ new_id_xref(cur_id);
+ else if (next_control==module_name && cur_mod!=NULL)
+ mod_xref_switch=cite_flag,new_mod_xref(cur_mod);
+ if (next_control==start_preproc && shift()!=end_preproc
+ &&next_control!=identifier)
+ err_print("! Identifier should follow `#'");
+ @.Identifier should follow `\#'@>
+ else shift();
+ if (next_control=='|' && inner
+ || next_control==begin_comment || next_control==end_comment)
+ return;
+ }
+}
+
+@ The function |outer_xref| is like |C_xref|, but is used to scan an entire
+macro body, or a portion of a section body delimited by module names; it
+handles \Cee~text with embedded comments. It is called after \:d, a format
+definition, \:c, or a module name (either defining or applied) has been
+scanned, and after \:h has fired up its header file; in all cases
+|next_control| is already processed, and we start with |shift()|. (There is
+also one call that can occur during Phase~II, namely if illegal items
+following a \:s format definition were found; its purpose then is merely to
+ensure |next_control>=format| without producing any output.)
+
+While a comment is being scanned, tokens that pass |C_xref| should not be
+considered as part of a possible |typedef| that is in progress; this is
+achieved by invoking the macro |typedef_tracking| with the proper boolean
+value at the beginning and end of the comment.
+
+@c
+void outer_xref (void) /* extension of |C_xref| */
+{ shift(); /* move past previously processed token */
+ while (next_control<format)
+ if (next_control!=begin_comment) C_xref(false);
+ else
+ { boolean one_liner=loc[-1]=='/'; int bal=0; /* brace level in comment */
+ typedef_tracking(false);
+ while ((next_control=scan_comment(&bal,one_liner))=='|')
+ @/{@; C_xref(true); if (next_control!='|') break; }
+ typedef_tracking(true);
+ }
+}
+
+@ In the \TeX~part of a section, \xr. entries are made only for the
+identifiers in \Cee\ texts enclosed in `\pb', or for control texts
+introduced by \:\^, \:., \:?, or \::.
+
+@< Store cross-references in the \TeX... @>=
+do
+ switch (next_control=skip_TeX())
+ { case underline: xref_switch=def_flag; break;
+ case '|': C_xref(true); break;
+ case module_name: case refer: loc-=2; get_next(); break;
+ case ignored_text: get_control_text(); break;
+ case char_trans: err_print("! `@@l' only allowed in limbo"); break;
+ @.`@@l' only allowed in limbo@>
+ case xref_roman: case xref_wildcard: case xref_typewriter:
+ case xref_mark: loc-=2; get_next(); new_id_xref(cur_id);
+ }
+while (next_control<format);
+
+@ During the definition and \Cee~parts of a section, \xr.s are made for all
+identifiers except reserved words and the right hand sides of format
+definitions. The \TeX\ code in comments is, of course, ignored, except for
+\Cee\ portions enclosed in `\pb'; the text of a module name is skipped
+entirely, even if it contains `\pb' constructions.
+
+@ When we get to the following code we have |next_control>=format|.
+
+@< Store cross-references in the def... @>=
+while (next_control<begin_C) /* |format|, |definition| or |header| */
+ if(next_control!=header)
+ { xref_switch=def_flag; /* implied \:! for first identifier */
+ if (next_control==format) @< Process a format code in a section @>
+ outer_xref(); /* macro definition or comment after format definition */
+ }
+ else @< Read a header file, scanning it for |typedef| declarations @>
+
+@ Before we handle format codes occurring in a section, let us consider
+their treatment in limbo. Here the code must be a non-printing \:s rather
+than \:f, since we are not prepared to emit formatted output in limbo. The
+syntax and semantics are simple: two identifiers must follow, and the |ilk|
+of the latter is is assigned to the former.
+
+@< Process a format code in limbo @>=
+if (tolower((eight_bits)loc[-1])=='f')
+ err_print("! Double @@ required in limbo part");
+ @.Double @@ required...@>
+else
+{ id_pointer lhs;
+ if (shift()==identifier && (lhs=cur_id,shift()==identifier))
+ lhs->ilk=cur_id->ilk;
+ else err_print("! Improper format definition");
+ @.Improper format definition@>
+}
+
+@ In a section \:s is processed in the same way; for \:f we additionally
+produce a defining \xr. for the left hand side. We do not call |shift| since
+this will be done by |outer_xref|, which is called after this code to
+process any comments that follow the format definition.
+
+@< Process a format code in a section @>=
+{ boolean f= tolower((eight_bits)loc[-1])=='f';
+ id_pointer lhs;
+ if (shift()==identifier && (lhs=cur_id,shift()==identifier))
+ { if (f) new_id_xref(lhs); @+ else xref_switch=0;
+ lhs->ilk=cur_id->ilk;
+ }
+ else err_print("! Improper format definition");
+ @.Improper format definition@>
+}
+
+@ After \:h a file name follows, enclosed in white space, double quotes, or
+angle brackets. We open the header file by the same routine used to open \:i
+files, but here we do suspend reading from the change file. If all is well
+the whole file will contain pure \Cee~text without any control codes, so
+|outer_xref| will come to a halt shortly after returning from that file.
+
+@< Read a header file... @>=
+{ if (push_input_file(true,true)) /* prepare for reading header file */
+ including_header_file=true; /* will be reset on closing the file */
+ typedef_tracking(true); /* this is what we are doing it for */
+ outer_xref();
+ /* |shift()| and collect typedefs until |next_control>=format| */
+ typedef_tracking(false);
+}
+
+
+@ Finally, when the \TeX\ and definition parts have been treated, we have
+|next_control>=begin_C|. The loop repeatedly marks a module name
+\xr. and then calls |outer_xref| to scan everything up to the
+next module name; if |next_control==module_name| initially, we raise
+|mod_xref_switch| which will cause that first module name to be marked as
+defining.
+
+@< Store cross-references in the \Cee... @>=
+{ if (next_control<new_section) /* |begin_C| or |module_name| */
+ { typedef_tracking(true);
+ mod_xref_switch= next_control==module_name ? def_flag : 0;
+ do
+ { if (next_control==module_name && cur_mod!=NULL)
+ new_mod_xref(cur_mod);
+ outer_xref();
+ } while (next_control<new_section);
+ typedef_tracking(false);
+ }
+}
+
+@ After we have seen everything, we want to check that each module name was
+both defined and used. The following recursive function walks through the
+tree of module names alphabetically and prints out anomalies. It also
+reverses the sublists of \xr.s to sections where a module is being defined,
+cited, and used. In this section we use the fact that \xr. lists end with a
+sentinel with |num==0|.
+@^recursion@>
+
+@c
+void mod_check (mod_pointer p) /* print anomalies in subtree |p| */
+{ if (p != NULL)
+ { mod_check (p->llink); /* traverse left subtree */
+ { boolean file_module = p->xref->num==file_flag;
+ sixteen_bits head, *q, threshold;
+ /* lower limit of |num| values of current interest */
+ if (file_module) q=&p->xref->next; @+
+ else head=xref_index(p->xref),q=&head;
+ if (!complete_name(p))
+ @/{@; print("\n! Never completed"); print_mod(p); mark_harmless(); }
+ @.Never completed: <module name>@>
+ if (xnum(*q)<=(threshold=def_flag))
+ @/{@; print("\n! Never defined"); print_mod(p); mark_harmless(); }
+ @.Never defined: <module name>@>
+ else
+ @< Reverse sublist after |*q| with entries |num>threshold|;
+ make |q| point to final |next| field @>
+ if (xnum(*q)>(threshold=cite_flag)) @/@< Reverse sublist... @>
+ if (xnum(*q)==(threshold=0))
+ @/{@; if(!file_module)
+ {@; print("\n! Never used"); print_mod(p); mark_harmless(); }
+ @.Never used: <module name>@>
+ }
+ else @< Reverse sublist... @>
+ if (!file_module) p->xref=&xmem[head];
+ /* set pointer to possibly modified value */
+ }
+ mod_check (p->rlink); /* traverse right subtree */
+ }
+}
+
+@~@<Print error messages about un...@>=
+mod_check(root);
+
+@ We now come to the reversal of the \xr. lists, which is necessary because
+by repeatedly prepending elements to these lists, or in the case of module
+names to one of three sublists, these (sub)lists have obtained reverse
+ordering. The method of traversal of the set of all identifiers is different
+from that for the set of all module names, whence these tasks are linked
+into the program at different points, but the reversal routines themselves
+are quite similar. As we already traverse the module names in |check_root|,
+the reversal code for module \xr.s was simply inserted at the proper place
+in that function; for traversal of the set of identifiers we use the |hash|
+table, by following all non-empty hash lists.
+
+@< Reverse the \xr. lists... @>=
+{ id_pointer name; id_pointer *h; /* pointer into |hash| */
+ for (h=hash; h<hash_end; h++)
+ for (name=*h; name!=NULL; name=name->hash_link)
+ /* traverse all hash lists */
+ @< Reverse the list |name->xref| @>
+}
+
+@ As Knuth keeps reminding us, list reversal can be thought of as a process
+of repeatedly popping values off one list~|x| and pushing them onto the
+reversed list~|y| (or you may read ``stack'' for ``list'' if you like). It
+can also be useful to remember that the basic action can be performed by a
+four-stroke engine, where the left hand side of each assignment equals the
+right hand side of the previous one. The basic cycle can actually take
+different forms, each using an auxiliary variable~|t|. One way is to
+use~|t| to hold the entry moved, repeating |{ t=x; x=t->next; t->next=y;
+y=t;}| until |x==NULL|; another way is to use~|t| to hold the remainder of
+the list to be reversed, repeating |{ t=x->next; x->next=y; y=x; x=t;}|,
+again until |x==NULL|. For reversing the \xr. lists of identifiers, we use
+the first form.
+
+@< Reverse the list |name->xref| @>=
+{ sixteen_bits x=xref_index(name->xref),t,y=0;
+ /* index of the sentinel node */
+ while (xnum(x)!=0) {@; t=x; x=xlink(t); xlink(t)=y; y=t; }
+ name->xref=&xmem[y]; /* don't forget to link in the reversed list */
+}
+
+@ The reversal of sublists of the \xr. list attached to module names is only
+slightly more complicated. At the three places where the code below is used,
+things have been set up so that |q| points to the location of the link
+pointing to the start of the sublist (since this link is going to be
+changed, we need a pointer to it) and the end of the list is implicitly
+indicated by |threshold|: the sublist ends before the first entry with
+|num<=threshold| (which always exists because of the sentinel with
+|num==0|). It has also been ensured that the code is only invoked when the
+indicated sublist is not empty, so that we can use a |do|-|while| loop; we
+have chosen the alternative order of assignments with respect to the
+previous section, mainly to demonstrate the possibility, although it also
+allows the code to be slightly shorter here.
+
+After the sublist has been reversed, some links must be redirected to
+install it in its proper place. The link |*q| must be pointed to the head of
+the reversed list, which is in |y|, while the link at the end of the sublist
+must be pointed to the unaffected remainder of the list (this remainder
+should ideally have been assigned to |y| initially, but it is only located
+once we have arrived at the first entry with |num<=threshold|). Fortunately
+the final node of the sublist is not only pointed to by its predecessor, but
+also by |*q| (before it is changed) since it used to be the first node of
+the sublist; therefore a small sequence of carefully ordered assignments
+will do the trick. It is instructive to check that if the sublist to be
+reversed has length~$1$, then all variables will eventually return to their
+original state. The initialisation of~|y| is only present to keep certain
+compilers from complaining that its value is used before it is first
+assigned to; the initial value is irrelevant since it will be overwritten.
+
+@< Reverse sublist... @>=
+{ sixteen_bits x=*q,y=0,t;
+ do {@; t=xlink(x); xlink(x)=y; y=x; } while (xnum(x=t)>threshold);
+ xlink(t=*q)=x; *q=y; q=&xlink(t);
+}
+
+
+@* Outline of Phase II processing. @:title@>
+With the description of Phase~I still fresh in our memory, let us look at
+the general outline of Phase~II, which is analogous, although it is more
+complicated. The extra complication is due to the fact that much more has to
+be done during Phase~II, notably the \Cee~texts have to be parsed in order
+to determine their proper formatting, and the resulting token lists have to
+be written to a file in a form that \TeX\ will be able to process. Most of
+the actual work however is localised in a few powerful functions that will
+be defined in detail later on, so that the definition of |phase_two| can be
+given here without much problems.
+
+There are three stages in the processing of a piece of \Cee~text during
+Phase~II: first it is scanned lexically (using |get_next|), and the
+resulting tokens are collected in the form of `scraps' that form the input
+for the second stage, the parsing algorithm, which transforms the scraps into
+a recursively nested token list, which is converted in the third stage to
+textual output.
+For the small parts of \Cee~text enclosed in `\pb', a function~|do_C| is
+available which handles all three stages of processing: it is called when an
+opening `\.\v' is seen, and when it is completed one has arrived at the
+closing `\.\v', and the required output is written on the \TeX~file.
+For the larger parts of \Cee~text, the function |outer_read| will read in,
+and convert to scraps, chunks of \Cee~text delimited by control codes
+|c>=format| (so like |outer_xref| it handles comments, but it will not
+incorporate module names), and when enough of these have been accumulated,
+a call on |finish_C| will invoke the parsing algorithm and send the
+resulting tokens to the output file.
+
+A number of simple functions for producing output are also called explicitly
+at certain points. We have already seen |out| and~|finish_line| for
+character-based output; there is also |out_str| for writing a string,
+|out_sec_nr| for a section number, |list_refs| for generating the text for
+\:\#, and |footnote| for producing the module \xr. information at the end of
+sections. Invoking the macro |tex_new_line| immediately after |finish_line|
+was called will produce an empty line on the output. Furthermore certain
+small pieces of code which have been scanned directly rather than via |do_C|
+or |outer_read| (for instance after format or macro definitions) are
+converted into scraps: first a number of tokens are appended by means of
+|app| or~|app_str| and then the whole sequence is converted to a scrap by
+calling |pack_scrap|; |app| and~|pack_scrap| are macros.
+
+@< Prototypes @>=
+void do_C (void); /* handle \Cee~text enclosed in `\pb' */
+void outer_read (void); /* transform input into scraps */
+void finish_C (void); /* finishes a definition or a \Cee~part */
+void finish_line(void); /* send out a line of output */
+void out_str (char*); /* write multiple characters */
+void out_sec_nr (int); /* output a section number */
+xref_pointer list_refs (xref_pointer,sixteen_bits);
+ /* output module \xr.s */
+void footnote(xref_pointer*,sixteen_bits); /* same with heading text */
+void app_str(char*); /* append a sequence of character tokens */
+
+@ Like in |phase_one|, we loop over the sections after passing over the limbo
+part.
+
+@c
+void phase_two (void)
+ /* read all the text again and translate it to \TeX\ form */
+{ phase=2; reset_input ();
+ print_progress("\nWriting the output file...");
+ @.Writing the output file...@>
+ section_count=0; copy_limbo(); finish_line();
+ tex_new_line(); /* insert a blank line, it looks nice */
+ while (!input_has_ended) @<Translate the current section@>
+}
+
+@ The output file will contain the control sequence `\.{\\Y}' before a
+non-empty definition portion of a section, and before a non-empty
+\Cee~portion (the \TeX~portion is always considered to be non-empty, since
+it contains at least the section number). This puts a little white space
+between adjacent portions when they are printed.
+
+@d emit_space() out_str ("\\Y"); @.\\Y@>
+
+@< Translate the current section @>=
+{ section_count++;
+ @< Output the code for the beginning of a new section @>
+ @< Translate the \TeX~part of the current section @>
+ if (next_control<begin_C)
+ @/{@; emit_space();
+ @< Translate the definition part of the current section @>
+ }
+ if (next_control<new_section)
+ { mod_pointer this_module=NULL; /* the current module name */
+ emit_space(); @< Translate the \Cee~part of the current section @>
+ @< Show cross-references to this section @>
+ }
+ @< Output the code for the end of a section @>
+}
+
+@ Sections beginning with the \.{CWEB} control sequence \:{\ } start in the
+output with the \TeX\ control sequence `\.{\\M}', followed by the section
+number. Similarly, \:* sections lead to the control sequence `\.{\\N}', and
+\:\~ sections to `\.{\\n}'. If this is a changed section, we put `\.*' just
+before the section number.
+
+@< Output the code for the beginning... @>=
+{ out('\\'); out(loc[-1]=='*' ? 'N' : loc[-1]=='~' ? 'n' : 'M' );
+ @.\\N@> @.\\n@> @.\\M@>
+ if (loc[-1]=='*')
+ {@; print_section_progress(); @< Handle title level @>@+ }
+ out_sec_nr(section_count); out_str(". ");
+}
+
+@ Between \:* and the title that follows, a level can be specified in the
+form of another `\.*', or a decimal number; the absence of a number will be
+interpreted as level~0. The level will be written out after `\.{\\N}' as a
+first argument, delimited by a space, after which the second argument is the
+section number and the third specifies the title.
+
+@< Handle title level @>=
+{ if (*loc=='*') ++loc,out_str("-1");
+ else if (!isdigit((eight_bits)*loc)) out('0');
+ else do out(*loc++); while (isdigit((eight_bits)*loc));
+ out(' '); /* terminate level by a space */
+}
+
+@ In the \TeX~part of a section, we simply copy the source text, except that
+index entries are not copied and \Cee\ text within `\pb' is translated;
+during this translation we track typedef definitions so that any complete
+typedef declaration within `\pb' will be parsed correctly, as will be
+explained below.
+
+@< Translate the \TeX... @>=
+do
+ switch (next_control=copy_TeX())
+ { case '|': typedef_master=0; do_C(); break;
+ case at_sign_image: out('@@'); break;
+ case thin_space: case math_break: case ASCII_code: case line_break:
+ case big_line_break: case no_line_break: case join: case pseudo_semi:
+ case force_expr_open: case force_expr_close:
+ err_print("! You can't do that in TeX text");
+ @.You can't do that...@>
+ break;
+#ifdef DEBUG
+ case trace0: case trace1: case trace2: case trace3: tracing=next_control;
+ break;
+#endif
+ case module_name: loc-=2; get_next(); break; /* get module name */
+ case refer: loc-=2; get_next(); /* get name referred to */
+ if (cur_id->xref->num==0) err_print("! Undefined reference");
+ else list_refs(cur_id->xref,0);
+ break;
+ case TeX_string: err_print("! TeX string should be in C text only");
+ @.TeX string should be...@>
+ /* fall through */
+ case xref_roman: case xref_wildcard: case xref_typewriter:
+ case xref_mark: case ignored_text:
+ get_control_text(); /* skip to \:> */
+ }
+while (next_control<format);
+
+@ When we get to the following code we have |format<=next_control<begin_C|.
+The first conditional statement below processes the first few tokens of a
+preprocessor directive, which do not follow the ordinary syntax rules; the
+remainder is then treated by |outer_read| using the regular parsing
+mechanism, although in the case of a format definition this should only
+involve possible comments and formatting controls, and in case of \:s even
+these should be absent.
+
+@< Translate the def... @>=
+{ typedef_tracking(false);
+ do
+ { boolean suppressed=false; /* whether output suppressed by \:s */
+ if (next_control==format) @< Start a format definition @>
+ else if (next_control==definition) @< Start a macro definition @>
+ else @< Start a header file inclusion @>
+ if (!suppressed) outer_read(), finish_C();
+ else if (next_control<format)
+ { err_print("! Improper stuff after `@@s' format definition");
+ @.Improper stuff after `@@s'...@>
+ if (next_control==begin_comment) loc-=2; /* try to get back in phase */
+ outer_xref(); /* skip illegal stuff */
+ }
+ } while (next_control<begin_C); /* |format|, |definition|, or |header| */
+}
+
+@ The syntax of a format definition has already been checked. It suffices to
+build scraps that will produce the desired output. The trickiest point is
+formatting the identifiers in a way that is least confusing to readers. We
+try to keep analogy to lines for macro definitions in case these define one
+identifier to stand for another: the left hand side is set in italics
+regardless of its |ilk|, while the right hand side has its normal
+appearance, prescribed by its |ilk|. If the left hand side is a |TeX_like| or
+|NULL_like| identifier, we stick to the representation in italics, even though
+this costs some extra work, and is not what would happen for a macro
+definition; in addition we append the usual formatted form of the identifier
+in parentheses, to show the correspondence of name and printed symbol.
+
+@< Start a format... @>=
+if (tolower((eight_bits)loc[-1])=='s')
+@/{@; suppressed=true; shift(); shift(); shift(); }
+ /* skip format definition */
+else
+{ int saved_code=0,saved_mathness;
+ app_str("\\F"); shift(); /* this will produce `\&{format}' */ @.\\F@>
+ if (cur_id->ilk!=TeX_like && cur_id->ilk!=NULL_like)
+ app(id_flag+id_index(cur_id));
+ else @< Expand identifier and set |saved_code| and |saved_mathness| @>
+ app('~'); pack_scrap(insert,yes_math); shift();
+ app((cur_id->ilk==normal || cur_id->ilk==TeX_like || cur_id->ilk==NULL_like
+ ? id_flag : res_flag
+ )+id_index(cur_id));
+@/check_scrap();
+ pack_scrap(insert,cur_id->ilk==TeX_like ? no_math : yes_math);
+ shift();
+ if (saved_code!=0)
+ { app_str("\\quad("); app(saved_code); app(')');
+ @/check_scrap(); pack_scrap(insert,saved_mathness);
+ }
+}
+
+@ Since conversion of an identifier into a \TeX\ control sequence is
+performed by the output routine, we need to circumvent this to force italic
+type; this is done by expanding the name into characters directly rather
+than leaving this to the output routine.
+
+@< Expand identifier... @>=
+{ char* p=name_begin(cur_id);
+ saved_mathness=cur_id->ilk==TeX_like ? no_math : yes_math;
+ saved_code=id_flag+id_index(cur_id);/* save to print afterwards */
+ app_str("\\\\{"); @.\\\\@>
+ do {@; if (*p=='_') app('\\'); app_tok(*p); } while (*++p!='\0');
+ app('}'); check_toks(10);
+}
+
+@ Keeping in line with the conventions of the \Cee\ preprocessor (and
+otherwise contrary to the rules of \.{CWEB}) we distinguish here between the
+cases that a `\.(' immediately follows the identifier being defined, and the
+case that anything else (possibly a space) does. In the latter case, the
+replacement text starts immediately after the identifier, in the former
+case, it starts after we scan the matching `\.)', which must be simply the
+first `\.)' that follows.
+
+@<Start a macro...@>=
+{ if (shift()!=identifier)
+ err_print("! Improper macro definition");
+ @.Improper macro definition@>
+ else
+ { app_str("\\D$"); /* this will produce \&{\#define} */ @.\\D@>
+ app(id_flag+id_index(cur_id));
+ if (*loc=='(')
+ { shift();
+ do
+ { app_char_tok(next_control);
+ if (shift()!=identifier) break;
+ app(id_flag+id_index(cur_id));
+ } while(shift()==',');
+ check_toks(2);
+ if (next_control==')') {@; app(')'); shift(); }
+ else err_print("! Improper macro definition");
+ }
+ else shift();
+ app('$'); app(break_space); pack_scrap(insert,no_math);
+ }
+}
+
+@ For scanning the token following \:h we temporarily set |preprocessing=2|,
+so that angle brackets will be recognised as string quotes.
+
+@<Start a header file...@>=
+{ app_str("\\h"); /* this will produce \&{\#include} */ @.\\h@>
+ pack_scrap(insert,no_math);
+ { int save=preprocessing; preprocessing=2; /* emulate `\.{\#include}' */
+ while (shift()==' ') {} /* skip spaces and read file name as string */
+ preprocessing=save;
+ }
+}
+
+@ Finally, when the \TeX\ and definition parts have been treated, we have
+|next_control>=begin_C|. If the section defines a module name, we assign the
+name to the variable |this_module|, so that the proper \xr. information can
+be listed at the end of the section. Like in Phase~I it is necessary to pay
+special attention to |typedef| declarations, and this time tracking is
+enabled both within `\pb' in \TeX~text and in the \Cee~part of a section;
+since the former may involve incomplete pieces of syntax like a sole
+`|typedef|', we reset the master counter to its neutral state at the
+beginning of a \Cee~part. After the heading of the \Cee~text has been
+processed we alternatively read ordinary pieces of \Cee~text and module
+names until the module has ended; we start with calling |outer_read| before
+testing termination, in order to ensure that the overflow tests contained in
+|outer_read| will be executed even in case of a section with a \Cee~part
+consisting only of a heading.
+
+@<Translate the \Cee...@>=
+{ typedef_master=0;
+ if (next_control==begin_C) shift();
+ else
+ { this_module=cur_mod; /* register the name for this module */
+ @< Check that `\.{=}' or `\.{==}' follows this module name, and
+ emit the scraps to start the module definition @>
+ }
+ do
+ { outer_read();
+ if (next_control==new_section) break;
+ if (next_control==module_name) @< Append a module name scrap @>
+ else err_print("! You can't do that in C text");
+ @.You can't do that...@>
+ /* |format|, |definition| or |begin_C| */
+ shift();
+ } while (true);
+ finish_C();
+}
+
+@ Despite the name of this module, we allow `\.+' to precede the `\.{=}' or
+`\.{==}', just as |CTANGLE| does. Note however that, unlike in |CTANGLE|,
+the `\.+' will be scanned as part of an `\.{+=}' compound operator (whence
+in fact `\.{+= =}' is allowed here whereas `\.{+ ==}' is not; we hope
+nobody minds this). Note also that if for whatever reason the current
+section number should fail to appear in the \xr. list for the
+module name (e.g., if section numbers have inadvertently got out of
+synchronisation with respect to Phase~I), then listing the
+\xr. information at the end of the section is suppressed by setting
+|this_module=NULL|.
+
+@< Check that `\.{=}' ... @>=
+{ if (shift()=='=' || next_control==eq_eq || next_control==plus_assign)
+ @/{@; if (next_control!=plus_assign || shift()=='=') shift(); }
+ /* accept `\.=', `\.{==}', `\.{+=}' or `\.{+==}' */
+ else err_print("! You need an = sign after the module name");
+ @.You need an = sign...@>
+ if (this_module!=NULL) /* i.e., unless module name was bad */
+ { xref_pointer x=this_module->xref;
+ if (x->num==file_flag) x=next_xref(x);
+ app_str("\\4$"); /* module name will be flush left */ @.\\4@>
+ app(mod_flag+mod_index(this_module));
+ if (x->num != section_count+def_flag)
+ { app_str("\\PE"); /* module has also been defined before */ @.\\PE@>
+ this_module = NULL; /* so we won't give \xr. info here */
+ }
+ else app_str("\\EQ"); /* output a module definition sign */ @.\\EQ@>
+ app_str("{}$"); app(force); pack_scrap(insert,no_math);
+ /* this forces a line break unless \:+ follows */
+ }
+}
+
+@ Cross references relating to a named module are given after its first
+defining section ends (for further defining sections of this name we will
+have put |this_module=NULL|).
+
+@< Show cross-references... @>=
+{ if (this_module != NULL)
+ { xref_pointer foot_ref=this_module->xref;
+ if (foot_ref->num==file_flag) foot_ref=next_xref(foot_ref);
+ foot_ref=next_xref(foot_ref); /* don't \xr. to yourself */
+ footnote(&foot_ref,def_flag);
+ /* display further defining sections; advance |foot_ref| */
+ footnote(&foot_ref,cite_flag); /* display any citations */
+ footnote(&foot_ref,0); /* display uses */
+ }
+}
+
+@ The `\.{\\fi}' closes a \TeX~conditional that was initiated by the macro
+that started off the section; this allows printing of only the changed
+sections in a simple way.
+
+@<Output the code for the end of a section@>=
+{@; out_str ("\\fi"); finish_line (); tex_new_line(); }
+@.\\fi@> /* insert a blank line, it looks nice */
+
+
+@* Auxiliary functions used in Phase~II. @:title@>
+We now define the functions that do the actual processing of \Cee~code
+during Phase~II, but without going into the details of parsing and output.
+We explain the functions |do_C|, |outer_read|, |finish_C|, |list_refs|,
+and |footnote| used above, and also two further auxiliaries |C_read|
+and~|C_translate|.
+
+@< Prototypes @>=
+text_pointer translate(void);
+ /* build formatted text from collected scraps */
+void make_output(text_pointer,mode);
+ /* output text in |inner| or |outer| mode */
+
+@ Before we discuss these functions, we must first discuss what scraps are.
+Scraps are the objects manipulated during parsing, and they have two main
+attributes: a syntactic category |cat|, that determines the way they will be
+treated by the parser, and a translation |trans|, which is a pointer
+into~|text_mem| denoting a (possibly recursively nested) sequence of tokens,
+that determines the representation of the scrap upon output. Since some
+parts of the output are to be processed in \TeX's math mode, and other parts
+in horizontal mode, an additional field |mathness| tells which mode is
+required at each end of the translation of the scrap.
+
+@<Typedef...@>=
+typedef struct
+{ eight_bits cat; /* category code */
+ eight_bits mathness; /* whether in math mode at left and right boundary */
+ text_pointer trans; /* translation text */
+} scrap, *scrap_pointer;
+
+@ When \Cee\ text is converted into scraps for parsing, the resulting scraps
+are placed in an array |scrap_info|, between the locations pointed to by
+|scrap_base| and~|scrap_ptr|. Actually, |scrap_info| is one field of a
+|union|, since the same memory is used for a different purpose during
+Phase~III.
+
+Basic scraps are created by invoking |app|, |app_tok| or |app_char_tok| a
+number of times creating the constituent tokens, and then consolidating the
+text by means of |freeze_text|; the resulting text is accessible as
+|text_ptr| before, and as |text_ptr-1| after the call of |freeze_text|. In
+the common case that the text forms the translation of a new scrap that is
+to be added to the scrap sequence, |pack_scrap| can be used in place of
+|freeze_text|; a category and `mathness' should be supplied in this case.
+The latter can take one of three values as explained later, and by
+multiplying it by~5 (binary~$0101$) it is duplicated into the two least
+significant pairs of bits, because for elementary scraps the value is the
+same at its left and right boundaries. Note that none of |app|, |freeze_text|
+and |pack_scrap| do bound checks, since it is assumed that these have been
+done beforehand; |app_tok| and |app_char_tok| however can be called at more
+uncertain times.
+
+@d scrap_info scrap_union.scrap_field
+@d scrap_info_end (&scrap_info[max_scraps]) /* end of |scrap_info| */
+@)
+@d app(a) (*tok_ptr++ = a)
+@d app_tok(a) @+
+ if (tok_ptr>tok_mem_end-2) overflow("token"); @.token capacity exceeded@>
+ @+ else app(a) @;
+@d app_char_tok(c) app_tok((unsigned char)(c))
+@d freeze_text() (*++text_ptr = tok_ptr)
+@d pack_scrap(c,m)
+ ( scrap_ptr->cat = c, scrap_ptr->trans = text_ptr, freeze_text(),
+ (scrap_ptr++)->mathness = 5*(m) )
+
+@<Global...@>=
+union
+{ scrap scrap_field[max_scraps]; /* memory array for scraps */
+ @< Alternative use of |scrap_union| @>@;
+} scrap_union;
+scrap_pointer scrap_base=scrap_info;
+ /* beginning of the current scrap sequence */
+scrap_pointer scrap_ptr = scrap_info;
+ /* points to end of the current scrap sequence */
+#ifdef STAT
+scrap_pointer max_scr_ptr = scrap_info;
+ /* largest value assumed by |scrap_ptr| */
+#endif
+
+@ Token lists are stored in |tok_mem| and represent text to be output to the
+\TeX~file. Because during parsing token lists will often be formed by
+concatenation of existing ones, a representation is chosen where this can be
+done easily; in particular a token can be a reference to a token list stored
+elsewhere. Also identifiers, reserved words and module names are represented
+by a reference to the name table rather than by their constituent
+characters. All other items are stored as list of characters, which have
+been widened to fill a 16-bit |token|, and special layout codes that will be
+explained below. More precisely, a |token t@;| is interpreted as follows.
+\yskip
+
+\item{$\bullet$} |t<=UCHAR_MAX|: the character~|t|, which possibly is
+ a compressed operator like `\.{\&\&}';
+\item{$\bullet$} |UCHAR_MAX<t<id_flag|: a special layout feature such as
+ |indent|,
+\item{$\bullet$}|id_flag<=t<res_flag|: the identifier with name
+ |id_at(t-id_flag)|;
+\item{$\bullet$}|res_flag<=t<mod_flag|: the reserved word
+ |id_at(t-res_flag)|;
+\item{$\bullet$}|mod_flag<=t<text_flag|: the module named
+ |mod_at(t-mod_flag)|;
+\item{$\bullet$}|text_flag<=t<inner_text_flag|: a reference to the token list
+ |text_at(t-text_flag)|;
+\item{$\bullet$}|inner_text_flag<=t|: a reference to the token list
+ |text_at(t-inner_text_flag)|, which is to be translated without
+ line-break controls.
+
+@d id_flag 10240U /* signifies an identifier */
+@d res_flag (2*id_flag) /* signifies a reserved word */
+@d mod_flag (3*id_flag) /* signifies a module name */
+@d text_flag (4*id_flag) /* signifies a token list */
+@d inner_text_flag (5*id_flag) /* signifies a token list in `\pb' */
+
+@~The special layout tokens are the following:
+\yskip
+
+\item{$\bullet$} |indent| causes future lines to be indented one more unit;
+\item{$\bullet$} |outdent| causes future lines to be indented one less unit;
+\item{$\bullet$} |opt| denotes an optional line break, it is followed by an
+ integer~|n|, and the break will normally occur with penalty~$10n$ (in
+ fact \TeX\ raises some penalties, but this remains invisible to
+ \.{\me.});
+\item{$\bullet$} |flush_left| denotes that the line will be printed flush
+ left, regardless of the current indentation level;
+\item{$\bullet$} |break_space| denotes an optional line break or an ``en''
+ space;
+\item{$\bullet$} |force| denotes a forced line break;
+\item{$\bullet$} |big_force| denotes a forced line break with additional
+ vertical space;
+\item{$\bullet$} |backup| denotes a forced line break followed by a
+ backspace of one indentation unit;
+\item{$\bullet$} |big_backup| denotes a forced line break with additional
+ vertical space, followed by a backspace of one indentation unit;
+\item{$\bullet$} |cancel| obliterates any space, |break_space|, |force|,
+ |big_force|, |backup|, or |big_backup| tokens that immediately precede
+ or follow it and also cancels any |opt| tokens that follow it;
+\item{$\bullet$} |relax| does nothing, but serves as a ``stopper''.
+
+\yskip\noindent The character tokens |' '|~and~|'~'|, together with the
+sequence of tokens from |break_space| to |big_backup| form a hierarchy, in
+the sense that on output any consecutive sequence of such tokens is
+equivalent to their maximum, except that |big_force| and |backup| combine to
+|big_backup|. To facilitate the computation we added |space|~and~|tilde| to
+the enumeration below, that overlay |opt|~and~|flush_left| respectively
+(this causes no problems, since |space|~and~|tilde| are not used as token
+values). Formally, we define a partial ordering on the set |{' ', '~',
+break_space, force, big_force, backup, big_backup }| that differs from the
+linear order in which they were listed only by the fact that |big_force| and
+|backup| are incomparable; then any consecutive list of such tokens is
+replaced by their least upper bound.
+
+@< Typedef and enum... @>=
+enum @/
+{ cancel=UCHAR_MAX+1,/* the following 9 items should remain in this order */
+ indent, outdent, opt, flush_left, break_space, force, big_force,
+ backup, big_backup, @/
+ relax, @/
+ space=opt, tilde=flush_left @/
+};
+
+@ The memory management for tokens follows a simple block regime.
+The source file is divided into blocks, and whenever a block is entered,
+the current states of the |text_mem| and~|tok_mem| are marked, after
+which they will gradually get filled up further; at the end of the block
+all memory used during the block is released by resetting the pointers
+into these arrays to the values they had on block entry. There are three
+kinds of blocks: the global block, which is filled during initialisation and
+is never released, the section blocks, which correspond to each individual
+section with a non-empty \Cee~part (or to a macro or format definition),
+and the inner blocks, which correspond to each `\pb' contained in the
+\TeX~part of a section or in a module name (but not in a comment). Because
+nesting is at most three blocks deep (for `\pb' inside module names) a
+two-element stack will suffice to hold the saved markers (nothing needs to
+be saved for the global block), and we can address these elements directly
+without a stack pointer since we know at which level we are. In fact the
+section blocks butt together, and nothing is added to the global block
+except at initialisation time, so that each section block starts in the same
+state. Therefore, if we call |enter_block(0)| after initialisation to record
+this state, then there is no need to call it any more, and it suffices to
+call |leave_block(0)| each time upon leaving a section.
+
+Scraps follow a different regime than texts and tokens, since they must be
+assembled into a single contiguous sequence before each translation, and can
+be discarded when the translation is over. In particular the scraps used to
+parse `\pb' within a comment can and must be released before reading in the
+\Cee~text following the comment, but the tokens and texts formed while
+translating the comment must remain until they are output.
+
+@d enter_block(i) save[i].txt=text_ptr, save[i].tok=tok_ptr;
+@d leave_block(i) text_ptr=save[i].txt, tok_ptr=save[i].tok;
+
+@< Global variables @>=
+struct {@; text_pointer txt; token_pointer tok; } save[2];
+
+@ The conversion of input tokens as obtained by |get_next| into scraps
+that can be processed by the parser is mainly handled by the function
+|C_read|, which is analogous to the |C_xref| routine used during Phase~I.
+Like |C_xref|, the function |C_read| takes a boolean argument telling
+whether it is processing `\pb'; it starts with the current value of
+|next_control| and it uses the operation |shift| repeatedly to read
+\Cee~text until encountering a terminating token. Also like |C_ref|, the
+initial conditions |next_control=='|'| or |next_control==end_comment| will
+not lead to immediate termination; in these cases the first time through the
+|while| loop will have no effect.
+
+@c
+void C_read (boolean inner) /* creates scraps from \Cee\ tokens */
+{ while (next_control<format || next_control==module_name && inner)
+ { @<Append the scrap appropriate to |next_control|@>
+ if (shift()=='|' && inner
+ || next_control==begin_comment || next_control==end_comment) return;
+ }
+}
+
+@ Many input tokens are completely determined by the value returned from
+|get_next|; we have arranged it that such a value is always less than
+|ignore|. For those tokens we will install corresponding scrap at initialisation
+time in an array |token_trans|, so that when such a token comes along, we
+can simply copy the scrap from |token_trans| into scrap memory.
+
+@< Global variables @>=
+scrap token_trans[ignore];
+
+@~Since the scraps in |token_trans| contain pointers into |tok_mem|, that
+array cannot be initialised statically; rather we do the initialisation
+dynamically based on information stored statically. For each token three
+kinds of information are supplied: the category of its translation, a
+string of characters giving the translation itself, and an indication for
+its the |mathness| (whether the translation must or must not occur in math
+mode, or whether both are allowed). The actual initialisation values will
+be given later.
+
+@< Set initial values @>=
+{ static struct {@; short tok; eight_bits cat, mathness; char* tr; }
+ trans_ini [] = @/{ @< Initialiser for |trans_ini| @>@;@; };@/
+ int i,n=array_size(trans_ini);
+ scrap o={ insert, 5*maybe_math, NULL }; /* completely inert scrap */
+
+ for (i=0; i<n; ++i)
+ { scrap* p=&token_trans[trans_ini[i].tok];
+ p->cat=trans_ini[i].cat; p->mathness=5*trans_ini[i].mathness;
+ app_str(trans_ini[i].tr); p->trans=text_ptr; freeze_text();
+ }
+ @< Install the translations of tokens involving line breaks @>
+
+ o.trans=text_ptr; freeze_text(); /* empty translation */
+ for (i=0; i<=UCHAR_MAX; ++i) /* clear all remaining tokens */
+ if (token_trans[i].cat==0) token_trans[i]=o;
+ enter_block(0); /* fix tokens; will be restored after each section */
+}
+
+@ Having installed |token_trans|, the number of cases in the
+switch statement below is greatly reduced.
+
+@< Append the scr... @>=
+{ check_scrap(); check_toks(6); /* `\.{\\hbox\{}' */
+ switch (next_control)
+ { case string: case constant: case verbatim:
+ @< Append a string or constant @> @+ goto done;
+ case TeX_string: @< Append a \TeX\ string scrap @> @+ goto done;
+ case identifier: @< Append an identifier scrap @> @+ goto done;
+ case module_name: @< Append a module name scrap @> @+ goto done;
+ case start_preproc:
+ @< Append a scrap starting a preprocessing directive @> @+ goto done;
+ case refer:
+ err_print("! You can't use `@@#' in C text"); /*fall through */
+ case ignore: case begin_comment: case end_comment:
+ case xref_roman: case xref_wildcard: case xref_typewriter:
+ case xref_mark: goto done;
+ @\@< Cases necessary for proper parsing of typedefs @>
+ case '|': @+ if (inner) goto done; /* skip initial `\.\v' of `\pb' */
+ }
+ *scrap_ptr=token_trans[next_control]; /* fixed scrap for this input token */
+ @< Possibly scoop up some dangling output tokens in compatibility mode @>
+ ++scrap_ptr; /* incorporate the scrap */
+ done: {}
+}
+
+@ When we need to be sure there is enough space to store |n|~more tokens,
+we say |check_toks(n)|; when a scrap has to be appended we invoke
+|check_scrap|, and when a text is to be formed otherwise than by
+|pack_scrap|, we invoke |check_text|. The key points in the program where
+we make such checks is when reading in \Cee~text in the functions |C_read|
+and |outer_read|, and when translating the text in |reduce|. At these points
+we make sure that there is enough room to spare so that in cases where
+explicit tokens occasionally need to be appended (e.g., by |app_str|) no
+test is necessary. When we cannot be sure about this, for instance because
+an indefinite number of tokens is appended, we use |app_tok| or
+|app_char_tok| instead of |app|; after this it will in fact be safe to do
+one additional |app|.
+
+@d check_toks(n) @+ if (tok_ptr>tok_mem_end-n)
+ overflow("token"); @.token capacity exceeded@> @+ else @;
+@d check_text() @+ if (text_ptr>=text_mem_end-1)
+ overflow("text"); @.text capacity exceeded@> @+ else @;
+@d check_scrap() @+ if (scrap_ptr>=scrap_info_end)
+ overflow("scrap"); @.scrap capacity exceeded@> @+ else check_text() @;
+
+@ As was just explained, we can use |app| rather than |app_char_tok| here.
+
+@c
+void app_str(char* s) @+{@; while(*s!='\0') app(*s++); }
+
+@ In long strings we insert a discretionary break every 20~characters, so
+that \TeX\ is less likely to run into problems, especially if the string
+occurs in the \TeX~part of a section; if we are directly after a backslash
+however, we postpone the break since otherwise the quote escaping the line
+break would appear to be escaped itself. Many of the special characters in
+a string must be prefixed by `\.\\' so that \TeX\ will print them properly.
+In the case of constants however, this `\.\\' converts marker characters
+that were inserted during scanning into control sequences used in formatting
+the constant.
+@^special string characters@>
+
+@< Append a string or... @>=
+{ int count = -1; /* characters remaining before string break */
+
+ if (next_control==constant) app_str("\\T{"); @.\\T@>
+ else if (next_control==string) {@; count=20; app_str("\\.{"); } @.\\.@>
+ else app_str("\\vb{"); @.\\vb@>
+
+ while (id_first<id_loc)
+ { if (count--==0) /* insert a discretionary break in a long string */
+ if (id_first[-1]=='\\') count=0; /* no break after backslash */
+ else {@; check_toks(2); app_str("\\)"); count = 20; } @.\\)@>
+ if (strchr(" \\#%$^{}~&_",*id_first)!=NULL) app('\\');
+@.\\\ @> @.\\\\@> @.\\\#@> @.\\\%@> @.\\\$@> @.\\\^@>
+@.\\\{@> @.\\\}@> @.\\\~@> @.\\\~@> @.\\\&@> @.\\\_@>
+ app_char_tok(*id_first++);
+ }
+ app('}');
+ if (next_control==verbatim) pack_scrap(insert,maybe_math);
+ else pack_scrap(expression,yes_math);
+}
+
+@ A \TeX~string is boxed and copied without further ado; undoubling of any
+\:@@ has already been done by |get_control_text|. In compatibility mode we
+do not however produce a scrap, but rather leave the output tokens produced
+to be picked up by the next scrap appended; this makes
+|dangling_tokens()| hold. In order to make sure that this next scrap
+exists, we will append a dummy scrap in |translate| if necessary.
+@:TeX string@>
+
+@d dangling_tokens() (compatibility_mode && tok_ptr>*text_ptr)
+
+@< Append a \TeX\ string scrap @>=
+{ app_str("\\hbox{");
+ while (id_first<id_loc) app_char_tok(*id_first++);
+ app('}');
+ if (!compatibility_mode) pack_scrap(expression,maybe_math);
+}
+
+@ Input tokens that have prefabricated scraps will not automatically incorporate
+any output tokens left behind by the code in section@#TeX string@> since they do
+not call |freeze_text|, so we must take some action to avoid that
+\TeX~strings will appear too late in the output. When the code below is
+encountered, the fixed scrap has been copied to |*scrap_ptr|. Its category
+and mathness are correct, but we may need to prepend tokens to its
+translation; this is done by appending that translation to the dangling
+tokens, wrapping them up together, and replacing the original translation by
+a pointer to the combined result.
+
+@< Possibly scoop up... @>=
+
+{@; if (dangling_tokens())
+ {@; app_trans(scrap_ptr); scrap_ptr->trans=text_ptr; freeze_text(); }
+}
+
+@ It is during the conversion of identifiers to scraps that their |ilk|
+plays a crucial r\^ole. Ordinary identifiers, and those with |ilk| equal to
+|TeX_like| or |NULL_like|, will get the category |expression|, and are set in
+math mode except in the case of |TeX_like| identifiers. If the |ilk| specifies
+some reserved word on the other hand, that |ilk| becomes the category of the
+identifier, determining its behaviour during parsing. The translation of
+these reserved words is done using |res_flag| rather than |id_flag|, as a
+result of which they will be printed in boldface; they get mathness
+|maybe_math|, indicating that they can be set equally well inside and
+outside math mode. Identifiers whose |ilk| is |type_defined|, |const_like|,
+or |typedef_like| will become reserved words with category |int_like|. These
+special |ilk| values have served their purpose during the scanning of
+typedef declarations; this involves subtle manoeuvres that will be explained
+later.
+
+@< Append an identifier scrap @>=
+{ id_pointer p=cur_id; int cat=p->ilk;
+ @< Track identifiers relevant to typedef;
+ maybe change |cat| from |int_like| to |expression| @>
+ if (cat==normal || cat==TeX_like || cat==NULL_like)
+ { app(id_flag+id_index(p));
+ pack_scrap(expression
+ , cat==TeX_like && !compatibility_mode ? no_math : yes_math);
+ }
+ else
+ { if (cat==type_defined || cat==const_like || cat==typedef_like)
+ cat=int_like;
+ app(res_flag+id_index(p)); pack_scrap(cat,maybe_math);
+ }
+}
+
+@ For bad module names (e.g., an ambiguous prefix) an error has already
+been reported, and they are silently suppressed from the output.
+
+@< Append a module name scrap @>=
+{@; if (cur_mod!=NULL)
+ app(mod_flag+mod_index(cur_mod)), pack_scrap(mod_scrap,yes_math);
+}
+
+@ We tested in Phase~I that `\.\#' is followed by an identifier or by a
+newline (which will cause |get_next| to return |end_preproc|). In the former
+case we incorporate the identifier into the scrap for the preprocessor
+directive; in the latter case the |lproc| scrap will just contain the
+`\.\#', but since we already scanned the following |end_preproc|, we append
+the corresponding |rproc| scrap as well.
+
+@< Append a scrap starting a preprocessing directive @>=
+{ app(force); app(flush_left); app_str("\\&\\#");
+ if (shift()==identifier)
+ {@; app(res_flag+id_index(cur_id)); pack_scrap(lproc,no_math); }
+ else if (next_control==end_preproc)
+ @/{@; pack_scrap(lproc,no_math);
+ check_scrap(); *scrap_ptr++=token_trans[end_preproc];
+ }
+ else confusion("no identifier after `#'");
+ @.no identifier after `\#'@>
+
+}
+
+@ When the `\.\v' that introduces \Cee\ text is sensed, a call on
+|C_translate| will return a pointer to the \TeX\ translation of that
+text. If scraps exist in |scrap_info|, they are unaffected by this
+translation process, which is useful since we convert comments to single
+scraps with help of |C_translate| while building the scrap sequence for the
+surrounding piece of \Cee~text.
+
+@c
+text_pointer C_translate(void)
+{ text_pointer p; scrap_pointer save_base=scrap_base;
+ scrap_base=scrap_ptr;
+ C_read(true); /* get the scraps together */
+ if (next_control != '|') err_print("! Missing `|' after C text");
+ @.Missing `|'...@>
+ p=translate(); /* make the translation */
+#ifdef STAT
+ if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
+#endif
+ scrap_ptr=scrap_base; scrap_base=save_base; return p;
+}
+
+@ The function |outer_read| is to |C_read| as |outer_xref| is to |C_xref|:
+it constructs a sequence of scraps for \Cee~text until
+|next_control>=format|, taking care of embedded comments. It is called
+between each occurrence of \:d, \:f, \:h, or a module name, which makes it a
+convenient place to test whether the memory arrays have enough spare room to
+cater for the stuff that could be needed for processing the next such token;
+the most demanding requirements are for a module name heading the \Cee~part
+of a section. These tests must be made outside the main loop of |outer_read|.
+
+We use that if |next_control==end_comment| when |C_read| is called,
+this value is effectively ignored.
+
+@c
+void outer_read (void) /* makes scraps from \Cee\ tokens and comments */
+{ while (next_control<format)
+ if (next_control!=begin_comment) C_read(false);
+ else @< Read a comment, and convert it into a scrap @>
+ check_scrap(); check_toks(11); /* `\.{\$\\4$m$\\PE\{\}\$$f$}' */
+}
+
+@ Since the call on |C_translate| used to process `\pb' inside comments will
+itself create tokens, the token sequence for the comment under construction
+must be wrapped up each time this happens, and a token referring to that
+initial segment contributed as first new item after the translation is made.
+Tests on the availability of two more tokens and a text must be made inside
+the loop that incorporates successive `\pb' fragments; the space for tokens
+outside these fragments is tested within |scan_comment|.
+
+@< Read a comment, and convert it into a scrap @>=
+{ boolean one_liner=loc[-1]=='/'; int bal=0; /* brace level in comment */
+ typedef_tracking(false);
+ check_scrap(); check_toks(4);
+ app(cancel); app_str(one_liner ? "\\SHC{" : "\\C{"); @.\\C@> @.\\SHC@>
+ while ((next_control=scan_comment(&bal,one_liner))=='|')
+ { text_pointer p=text_ptr, q=(freeze_text(), C_translate());
+ check_toks(7);
+ app_tok(text_flag+text_index(p));
+ if (compatibility_mode) app_str("\\PB{"); @.\\PB@>
+ app(inner_text_flag+text_index(q));
+ if (compatibility_mode) app('}');
+ check_text();
+ }
+ app_char_tok('}'); app(force); pack_scrap(insert, no_math);
+ /* the full comment becomes a scrap */
+ typedef_tracking(true);
+}
+
+@ The function |do_C| does the scanning, translation, and output of
+\Cee~text within `\pb' brackets. It is called during the scanning of the
+\TeX~part of a section and during the output of module names. As we have
+seen, this function is not called when processing comments, where
+|C_translate| is used instead, because no direct output should be produced
+at such times.
+
+@c
+void do_C (void) /* read, translate, and output \Cee~text in `\pb' */
+{ enter_block(1);
+ if (compatibility_mode) out_str("\\PB{"); @.\\PB@>
+ make_output(C_translate(),inner); /* output the list */
+ if (compatibility_mode) out('}');
+#ifdef STAT
+ if (text_ptr>max_text_ptr) max_text_ptr = text_ptr;
+ if (tok_ptr>max_tok_ptr) max_tok_ptr = tok_ptr;
+#endif
+ leave_block(1); /* forget the tokens */
+}
+
+@ The function |finish_C| outputs the translation of the current scraps,
+preceded by the control sequence `\.{\\B}' and followed by the control
+sequence `\.{\\par}'. It also restores the token and scrap memories to their
+state as immediately after initialisation.
+
+@c
+void finish_C (void)
+{ out_str ("\\B"); @.\\B@>
+ make_output(translate(),outer);
+ out_str("\\par"); finish_line();
+#ifdef STAT
+ if (text_ptr>max_text_ptr) max_text_ptr=text_ptr;
+ if (tok_ptr>max_tok_ptr) max_tok_ptr=tok_ptr;
+ if (scrap_ptr>max_scr_ptr) max_scr_ptr=scrap_ptr;
+#endif
+ leave_block(0); scrap_ptr=scrap_info;
+ /* forget the tokens and the scraps */
+}
+
+@ The function |footnote| gives \xr. information about
+further definitions of a module name (if |flag==def_flag|),
+about citations of a module name (if |flag==cite_flag|),
+or about the uses of a module name (if |flag==0|).
+It assumes that |*p| points to the first \xr. entry
+of interest, and it leaves |*p| pointing to the first element
+not printed (possibly the sentinel with |num==0|).
+Typical outputs are `\hbox{\.{\\Q 2001.}}',
+`\hbox{\.{\\Us 370\\ET1009.}}'\ETs `\hbox{\.{\\As 8, 27\\*, 51\\ETs64.}}'.
+
+@c
+void footnote (xref_pointer* p,sixteen_bits flag)
+{ if ((*p)->num<=flag) return;
+ finish_line(); out('\\');
+ out(flag==0 ? 'U' : flag==cite_flag ? 'Q' : 'A'); @.\\A@> @.\\Q@> @.\\U@>
+ *p=list_refs(*p,flag);
+ out('.');
+}
+
+@~The function |list_refs|, which does the main work for |footnote| and is
+also used to produce the text replacing \:\#, distinguishes three cases,
+according as the number of relevant \xr.s is one, two, or more than two. The
+function always produces at least one \xr.: it is never called with
+|x->num<=flag|. The value of |x| after traversing the references is
+returned, for the benefit of |footnote|.
+
+@c
+xref_pointer list_refs (xref_pointer x,sixteen_bits flag)
+{ xref_pointer q=next_xref(x); /* second element in \xr. list */
+ if (q->num>flag) out('s');
+ /* use `\.{\\As}', `\.{\\Qs}' or `\.{\\Us}' */
+ @.\\As@> @.\\Qs@> @.\\Us@>
+ out(' ');
+ while (out_sec_nr(x->num&num_mask),x=next_xref(x),x->num>flag)
+ if (next_xref(x)->num>flag) out_str(", "); /* |x| is not the last */
+ else
+ { out_str("\\ET"); /* next number printed will be the last */
+ if (x!=q) out('s'); /* `\.{\\ETs}' for the last of more than two */
+ } @.\\ET@> @.\\ETs@>
+ return x;
+}
+
+
+@* The problem of typedef declarations. @:title@>
+We now consider how |typedef| declarations are processed. It is a slightly
+problematic matter, since it involves the syntactic structure of the
+program, but we are doing only lexical analysis during Phase~I.
+Nevertheless, we don't want to delay recognition of |typedef| declarations to
+Phase~II, since this would restrict the user's freedom of ordering the
+sections so that all typedef declarations remain before any of their uses,
+and it would make it cumbersome to mention a typedef identifier in the
+commentary directly before its definition. Our approach will be to specify
+simple rules that pinpoint the identifiers which are subject to a |typedef|
+definition in any syntactically correct program; we don't care too much
+about strange behaviour in the presence of syntax errors, and also assume
+some basic decency on the part of the user, e.g., the identifier should
+occur in the same section as the |typedef| token.
+
+Obviously there is little to care about until a |typedef| token
+(recognisable by its |ilk|) comes along, but then it becomes tricky.
+Ordinarily the identifier being defined is the first non-reserved word that
+follows, but |struct| (and |union| and |enum|) tokens complicate the
+situation; also there may be more than one identifier subject to the
+|typedef|, separated by commas from each other. Because of |struct| we must
+keep track of the nesting of braces, and because the mentioned commas should
+be distinguished from those occurring in the parameter specifications of
+functions, we should also keep track of parenthesis nesting. A semicolon at
+the proper level of brace nesting signals the end of a |typedef| declaration.
+
+Fortunately |typedef| declarations cannot be nested inside each other,
+so we can use global variables to keep the proper counts. Three integer
+counters are used, two for the nesting levels of braces and parentheses,
+which are set to~0 whenever a |typedef| is scanned and properly maintained
+thereafter, and a master counter which determines if we are paying
+attention at all.
+
+@d typedef_tracking(b) (typedef_master += b ? 5 : -5)
+
+@< Global... @>=
+local int typedef_master=-5; /* tracking disabled outside \Cee~parts */
+local int brace_level, par_level;
+
+@ The master counter is ordinarily equal to~0 when tracking is enabled, and
+negative if it is disabled. When it is~0 and a |typedef| is seen, it is
+raised to~2, after which an |int_like| or |type_defined| identifier will
+further raise it to~4, indicating that any |normal| identifier coming along
+at the same brace level will be made |type_defined|. When that happens the
+master counter drops to~1, indicating that it can still be rekindled by a
+comma at the proper parenthesis level. We must be prepared to see more than
+one typedef for the same identifier, as we may have scanned a header file
+before seeing the source that produced that file, so we also let the master
+counter drop to~1 if it was~4 and an identifier that is already
+|type_defined| is seen. If however following the |typedef|, when the master
+counter is~2, a |struct_like| identifier is seen, the master counter is
+raised only to~3, so that a following identifier will not be made
+|type_defined|, but rather pass the honour on by setting the master counter
+to~4; this also happens when instead of an identifier a left brace is seen.
+Finally, a semicolon at the right brace level will return a positive value
+of the master counter to~0.
+
+@< Keep track of tokens relevant to |typedef| declarations @>=
+{ if (typedef_master==0 &&
+ next_control==identifier && cur_id->ilk==typedef_like)
+ @/{@; typedef_master=2; brace_level=par_level=0; }
+ else if (typedef_master>0) switch(next_control)
+ { case identifier:
+ if (brace_level==0)
+ if (typedef_master==2)
+ { if (cur_id->ilk==int_like || cur_id->ilk==type_defined)
+ typedef_master=4;
+ else if (cur_id->ilk==struct_like) typedef_master=3;
+ }
+ else if (typedef_master==4)
+ { if(cur_id->ilk==normal||cur_id->ilk==type_defined) /* this is it */
+ cur_id->ilk=type_defined, typedef_master=1;
+ }
+ else if (typedef_master==3) typedef_master=4;
+ break;
+ case '{': @+
+ if (brace_level++==0 && typedef_master==3) typedef_master=4; @+ break;
+ case '}': --brace_level; break;
+ case ',': @+
+ if (typedef_master==1 && par_level==0) typedef_master=4; @+ break;
+ case '(': ++par_level; break;
+ case ')': --par_level; break;
+ case ';': @+ if (brace_level==0) typedef_master=0;
+ }
+ if (C_plus_plus)
+ @< Take action to mark identifiers following \&{class} as |type_defined| @>
+}
+
+@ In \Cpp, any identifier that follows \&{class} (or |struct| of |union|) is
+considered as a typedef identifier, i.e., every time some \&{class~x} is
+encountered, an implicit `|typedef| \&{class~x~x}' is assumed.
+
+@< Take action to mark identifiers following \&{class}... @>=
+{ static boolean class_seen=false;
+ if (class_seen)
+ { if (next_control==identifier && cur_id->ilk==normal)
+ cur_id->ilk=type_defined;
+ class_seen=false;
+ }
+ else if (next_control==identifier && cur_id->ilk==struct_like)
+ class_seen=true;
+}
+
+@ We now consider |typedef| declarations in Phase~II. In Phase~I we have set
+the |ilk| of the defined identifiers to~|type_defined|, which will make them
+behave as |int_like|; although this works fine everywhere else, it thwarts a
+correct parse of their |typedef| declaration itself during Phase~II. In
+fact, according to the \caps{ANSI}/\caps{ISO}~\Cee\ syntax, the identifier
+being declared in a typedef declaration should not be considered to be a
+\\{typedef-name}, since that would make the declaration unsyntactical; this
+is justified by the fact that the typedef identifier only comes into scope
+after the declaration is completed. This is not a problem for single-pass
+compilers, but it is for us: we have recorded the typedef declaration on the
+first pass, and it will be active during the entire second pass, since we
+cannot delimit the declaration to its proper range (we are not processing
+the code in the same order that the \Cee~compiler will, and for the
+commentary parts of sections, the concept of range does not even apply). To
+attempt to write the grammar in such a way that it will accept typedef
+declarations in which the defined identifier is |int_like| would be very
+difficult, since without the help of some rather remote context, a
+declarator of this kind can not always be distinguished form an abstract
+declarator; compare the declaration `\hbox{|typedef char *(example[4]);|}',
+which declares |example| to specify the type ``array of 4 pointers to
+character'', with a valid declaration `|void f(example[3]);|' that might
+follow it, declaring |f| as a function that takes as an argument an array of
+3 such |example| objects (in fact the argument will be passed as a pointer to
+|example|, of course).
+
+So, rather than solving the problem in a syntactic way, we stoop down to
+emulating a one-pass system by setting the |category| of the defining
+occurrence of an identifier in a typedef declaration explicitly to
+|expression|, despite the fact that its |ilk| is |type_defined|. The defining
+occurrence is located by the same lexical means used in Phase~I, in fact, by
+using the same intricate succession of states of |typedef_master| that was
+used there. A difference is that at the {\sl moment supr\`eme\/} the
+identifier found is now |type_defined| rather than |normal|. The fact that
+this identifier is not necessarily the only or first |type_defined|
+identifier in the declaration, and that is has to be recognised in a
+left-to-right pass, may explain some of the details of our code, for
+instance why |const_like| had to be distinguished from both |int_like| and
+|type_defined|; one may compare `\hbox{|typedef unsigned long int * const
+example;|}' with `\hbox{|typedef const example * examp2;|}'.
+
+With respect to the code for Phase~I, there is also a slight difference in
+the way the code is hooked into the program, since the function |C_read|
+already contains a |switch| on the value of |next_control|, which has a
+special case for identifiers. So let us first consider the identifier cases
+(including reserved words).
+
+@f example scrap /* pretend |example| is |type_defined| */
+@f examp2 example /* and |examp2| is another such identifier */
+
+@< Track identifiers... @>=
+{ if (typedef_master==0 && cat==typedef_like)
+ typedef_master=2, brace_level=par_level=0;
+ else if (typedef_master>0 && brace_level==0)
+ if (typedef_master==2)
+ { if (cat==int_like || cat==type_defined) typedef_master=4;
+ else if (cat==struct_like) typedef_master=3;
+ }
+ else if (typedef_master==4 && cat==type_defined) /* this is it */
+ cat=expression, typedef_master=1;
+ else if (typedef_master==3) typedef_master=4;
+}
+
+@ And here are the relevant cases of non-identifiers.
+
+@< Cases necessary for proper parsing of typedefs @>=
+
+case '{': @+
+ if (typedef_master>0 && brace_level++==0 && typedef_master==3)
+ typedef_master=4;
+ @+break;
+case '}':@+ if (typedef_master>0) --brace_level; @+break;
+case ',':@+ if (typedef_master==1 && par_level==0) typedef_master=4; @+break;
+case '(':@+ if (typedef_master>0) ++par_level; @+break;
+case ')':@+ if (typedef_master>0) --par_level; @+break;
+case ';':@+ if (typedef_master>0 && brace_level==0) typedef_master=0; @+break;
+
+
+@i parser.w
+@i rules.w
+
+
+@* Output of tokens. @:title@>
+Now that we have treated the highest level of processing by \.{\me.}, we
+shall have to descend again to the level of character strings, which
+eventually have to written to the output file. Our first concern is to
+linearise the multi-layered token lists into a sequence of output tokens.
+The output of special layout tokens is affected by whether or not they were
+generated from within `\pb', so there are two modes of output: during output
+of `\pb' we are in |inner| mode, and otherwise in |outer| mode.
+A switch from |outer| to |inner| mode can occur in the middle of a text,
+namely for `\pb' fragments inside comments; this is indicated by the fact
+that the reference to the translation of the fragment is tagged with
+|inner_text_flag|. Apart from the fact that the mode is set to |inner|
+during the output of such subtrees, no traces of the tree structure of the
+internal representation of texts are left after linearisation.
+
+Linearising texts is therefore a straightforward process, that is easy to
+implement using a stack. In the linearised stream of tokens certain
+sequences of tokens, particularly layout tokens, have to be considered
+together, e.g., |cancel| will remove any adjacent line-breaking tokens. No
+line-breaking tokens will occur at either end of the output of a complete
+text either; if a line break is required there, the caller of the output
+routines will supply it explicitly. For identifiers, reserved words and
+module names, the transformation of a single token into a sequence of
+characters is handled by separate functions to be discussed later. For
+module names the transformation may result in a recursive call of the output
+routines via the processing of `\pb' fragments by~|do_C|, but this recursion
+in never more than one level deep, since such fragments cannot contain
+module names.
+@^recursion@>
+
+@< Prototypes @>=
+void out_identifier (id_pointer);
+void out_keyword (id_pointer);
+xref_pointer out_module_name(mod_pointer);
+
+@ The stack that is used to keep track of token lists at different levels
+of output is similar to the one used in |CTANGLE|. Entries have three parts:
+for the token list at each level |tok_field| and |end_field| record where we
+are respectively where we should stop, and |mode_field| records the output
+mode. The current values of these quantities are referred to quite
+frequently, so they are stored in a separate place, and are called
+|cur_tok|, |cur_end|, and |cur_mode|.
+
+@d cur_tok cur_state.tok_field /* location of next output token in |tok_mem| */
+@d cur_end cur_state.end_field /* current ending location in |tok_mem| */
+@d cur_mode cur_state.mode_field /* current mode of interpretation */
+
+@<Typedef...@>=
+typedef enum { inner, outer } mode;
+typedef struct
+{ token_pointer tok_field; /* present location within token list */
+ token_pointer end_field; /* ending location of token list */
+ mode mode_field; /* interpretation of control tokens */
+} output_stack_element, *stack_pointer;
+
+@ The stack grows upwards with the global variable |stack_ptr| pointing to
+the first vacant location above the top of the stack. The entry |stack[0]|
+at the bottom of the stack is not used; when |stack_ptr| points to it then
+|cur_state| itself has become invalid and the output process is completed.
+Therefore we can use |stack[0]| to store |cur_state| in.
+
+@d cur_state stack[0] /* the currently active state variables */
+@d stack_end (&stack[stack_size]) /* end of |stack| */
+
+@<Global...@>=
+output_stack_element stack[stack_size]; /* info for non-current levels */
+stack_pointer stack_ptr=&stack[0];
+ /* first unused location in the output state stack */
+#ifdef STAT
+stack_pointer max_stack_ptr = stack; /* largest value assumed by |stack_ptr| */
+#endif
+
+@ To insert token list |p| into the output, the function |push_level| is
+called; it saves the old level of output and gets a new one going.
+Conversely, the macro |pop_level| restores the conditions that were in force
+when the current level was begun. The value of |cur_mode| is not changed by
+|push_level|, but it might be changed explicitly directly after the call; if
+so this setting will remain in effect until the matching invocation of
+|pop_level|. At the beginning of |make_output|, a call to |push_level| is
+made to put the root text into the output stream. If this is not a recursive
+call to |make_output|, the old (undefined) value of |cur_state| will be
+``saved'' into |stack[0]|, which is |cur_state| itself; although this is
+redundant, no harm is done.
+
+@d pop_level() cur_state = *--stack_ptr
+@c
+void push_level (text_pointer p) /* suspends the current level */
+{ if (stack_ptr==stack_end) overflow("stack"); @.stack capacity exceeded@>
+ *stack_ptr++=cur_state;
+#ifdef STAT
+ if (stack_ptr>max_stack_ptr) max_stack_ptr=stack_ptr;
+#endif
+ cur_tok=text_begin(p); cur_end=text_end(p);
+}
+
+@ The function |make_output| traverses the nested token lists using the
+stack, and producing the corresponding output. Since it can be called
+recursively, the initial value of |stack_ptr| is saved in |stack_bot|; we
+return from |make_output| when |stack_ptr| drops back again to this level.
+When we encounter tokens marked with |id_flag|, |res_flag| and |mod_flag|, we
+respectively call |out_identifier|, |out_keyword| and |out_module_name|.
+As mentioned above, the last of these may result in a recursive call to
+|make_output| via |do_C|; because calls of |do_C| also involve
+lexical scanning, the values of |next_control|, |cur_id| are saved, and
+restored when |make_output| is complete.
+@^recursion@>
+
+@c
+void make_output(text_pointer t,mode m) /* output a complete text */
+{ int save_next_control=next_control; id_pointer save_cur_id=cur_id;
+ stack_pointer stack_bot=stack_ptr; token state=cancel;
+ push_level(t); cur_mode=m;
+ do
+ if (cur_tok==cur_end) pop_level();
+ else
+ { token a= *cur_tok % id_flag;
+ switch (*cur_tok++/id_flag)
+ {
+ @\@< Cases 1, 2, 3: identifiers, reserved words and module names @>
+ case 4: push_level(text_at(a)); break;
+ case 5: push_level(text_at(a)); cur_mode=inner; break;
+ case 0: @< Output the character or format control |a| @>
+ }
+ }
+ while(stack_ptr>stack_bot);
+ @< Complete any unfinished work at the end of the translation @>
+ next_control=save_next_control; cur_id=save_cur_id;
+}
+
+@ To handle the proper interaction of adjacent output tokens, we keep track
+of an integer |state| variable to record that a possibly unfinished sequence
+is being processed. The state is mainly affected by the output of format
+control tokens like |break_space|, so for convenience we often set the state
+equal to the value of such a token. If |state==0| the most recent token was
+an ordinary one, and no special action is called for. If |state| has one of
+the values |space|, |tilde|, |break_space|, |force|, |big_force|, |backup|,
+or |big_backup|, it is the upper bound in the sense mentioned before of a
+sequence of such tokens that has recently passed (where |space|~and~|tilde|
+represent the tokens |' '|~and~|'~'|, respectively). We call such states
+`white-space states'; when an ordinary character comes along in a
+white-space state, the token recorded in |state| is first output.
+
+@< Output white space if specified by |state| @>=
+{ if (state>=space)
+ if (state<break_space) out(state==space ? ' ' : '~');
+ else
+ { out('\\');
+ if (state<backup) out(state-break_space+'5');
+ /* `\.{\\5}', `\.{\\6}', or `\.{\\7}' */ @.\\5@> @.\\6@> @.\\7@>
+ else out(state-backup+'6'),out_str("\\4");
+ /* `\.{\\6\\4}' or `\.{\\7\\4}' */ @.\\6@> @.\\7@> @.\\4@>
+ finish_line();
+ }
+ state=0;
+}
+
+@ The following three cases now become easy.
+@< Cases 1, 2, 3... @>=
+case 1: @< Output white space... @>@+ out_identifier(id_at(a)); break;
+case 2: @< Output white space... @>@+ out_keyword(id_at(a)); break;
+case 3: @< Output white space... @>@+ out_module_name(mod_at(a)); break;
+
+@ Whether or not a forced break is required at the end of the translation is
+determined by the function calling |make_output|, not by the code being
+translated; therefore we do not invoke |@< Output white space... @>| at the
+end, and if a white-space state was set, it will sink silently into
+oblivion. An exception is made for |big_force| or |big_backup|, for which we
+output `\.{\\Y}' so that the extra vertical white space (which must have been
+inserted explicitly by a \:) control code) will not vanish, for instance
+when it occurs between macro definitions.
+
+@< Complete any unfinished work... @>=
+{@; if (cur_mode==outer && (state==big_force || state==big_backup))
+ out_str("\\Y");
+}
+
+@ White-space format controls operate by modifying |state| when appropriate,
+as described above. The same holds basically for |' '| and |'~'|, but these
+characters can also occur in ordinary text inside comments, where they must
+not be contracted, so we take some care that in such a position (where
+|cur_mode==outer| holds), they are output as ordinary characters. In
+white-space states |opt| and the digit following it are ignored. Like the
+white-space format controls, the token |cancel| also sets |state| to its own
+value, but it ignores the value it previously had. In this state any spaces
+and format control tokens except |indent|, |outdent| and |flush_left| are
+ignored. We also have set |state==cancel| at the beginning of |make_output|,
+so that there will be no forced break or white space at the beginning of the
+translation.
+
+The tokens |indent| and |outdent| are output directly without altering
+|state|; effectively this means that they will be moved in front of any
+white-space format controls that preceded them. This is important because
+the format controls that are explicitly inserted by codes like \:/ will
+stick to the token to their left, so that any indentation changes generated
+by the syntax rules at the same point will necessarily come {\it after\/}
+them, while in fact these indentation changes must be allowed to affect the
+indentation at explicitly inserted line breaks. With the exceptions noted
+above, |opt| and |flush_left| are transmitted like normal tokens.
+
+When |cur_mode==inner| things are a bit different. The tokens |indent|,
+|outdent|, and |flush_left| are completely ignored, and all white-space
+tokens except |'~'| are treated like |' '|, i.e., they set |state=space|.
+Optional breaks are produced using `\.{\\0}' rather than `\.{\\3}' to avoid
+a ragged right margin within a paragraph.
+
+@< Output the character or format control |a| @>=
+{ switch (a)
+ { case relax: @< Output white space... @>@+ break;
+ case cancel: state=cancel; break;
+ case indent: case outdent:
+ if (cur_mode==outer) {@; out('\\'); out(a-indent+'1'); }
+ break; @.\\1@> @.\\2@>
+ case opt:
+ { int digit=*cur_tok++;
+ if (state==0)
+ {@; out('\\'); out(cur_mode==outer ? '3' : '0'); out(digit); }
+ @.\\3@> @.\\0@>
+ break;
+ }
+ case flush_left:
+ if (cur_mode==outer)
+ {@; @< Output white space... @> out_str("\\8"); } @.\\8@>
+ break;
+ case big_force: case backup:
+ if (a+state==big_force+backup) a=big_backup; /* fall through */
+ case break_space: case force: case big_backup:
+ if (cur_mode==inner) a=space;
+ up_state:
+ if (state!=cancel && state<a) state=a;
+ break;
+ case ' ': case '~':
+ if (cur_mode==inner) {@; a= a==' ' ? space : tilde; goto up_state; }
+ if (state==cancel || state>=break_space) break;
+ /* else fall through */
+ default: @< Output white space... @>@+ out(a);
+ }
+}
+
+@* Low-level output routines. @:title@>
+We now come to the functions that write individual tokens and characters.
+We start with a simple function to output a section number in decimal
+notation. The number to be converted by |out_sec_nr| is known to be less
+than |def_flag|, so it cannot have more than five decimal digits. If the
+section was changed, we output `\.{\\*}' just after the number.
+
+@c
+void out_sec_nr (int n) /* output a section number */
+{ char s[6];
+ sprintf(s,"%d",n); out_str(s);
+ if (section_changed(n)) out_str ("\\*"); @.\\*@>
+}
+
+@ Since we want to typeset identifiers such as \.{catch22} as |catch22|, which
+is achieved by writing the string `\.{\$\\\\\{catch\}\_\{22\}\$}' to the
+\TeX~file, it is useful to have an auxiliary function |out_id_part| that
+will output a substring of an identifier (or reserved word), enclosing it in
+braces if it contains more than one character. The substring is specified by
+a pointer and a length count. A call to |out_id_part| for the full name
+referred to by an |id_pointer p@;| is achieved by invoking |out_id_full(p)|.
+
+
+@d out_id_full(p) out_id_part(name_begin(p),length(p))
+
+@c
+void out_id_part (char* s, int l)
+{ boolean b=l!=1;
+ if (b) out ('{');
+ while (--l>=0) {@; if (*s=='_') out ('\\'); out (*s++); }
+ if (b) out('}');
+}
+
+@ For index entries we do not wish to give underscores a special treatment,
+so we define a function |out_index| to use in place of |out_id_full|. Index
+entries of length~0 are discarded on input, so they never come here; for
+index entries of length~1 we omit braces.
+
+In \LKC., there is no function like |out_index|, and the equivalent of
+|out_id_part| is used instead, and as a consequence, underscores are
+automatically escaped in index entries, but other special characters are
+not. While there is no particular rhyme or reason to such a behaviour, user
+have learned to adapt to it, and so, in an attempt at bug-to-bug
+compatibility, we transfer control to |out_id_part| in compatibility mode.
+
+@c
+void out_index (id_pointer p)
+{ char* s=name_begin(p); boolean b= s[1]!='\0';
+ if (compatibility_mode) {@; out_id_full(p); return; }
+ if (b) out ('{');
+ out_str(s);
+ if (b) out('}');
+}
+
+@ The function |out_keyword| simply prefixes `\.{\\\&}' to the output of
+|out_id_full|.
+
+@c
+void out_keyword(id_pointer p) @+{@; out_str("\\&"); out_id_full(p); }
+@.\\\&@>
+
+@ The function |out_identifier| formats ordinary identifiers (those that
+were stored with |id_flag|). Yet there is some variation in the way these
+are formatted. Identifiers whose |ilk| is |TeX_like| or |NULL_like| are
+converted into control sequences. If only one alphabetic character is
+present, it is set in math (rather than text) italic, otherwise if all
+characters are either upper case letters or digits, the identifier is set in
+typewriter type, and in the remaining, most common, case, it is set in text
+italic. If math or text italic are used, a trailing sequence of digits in
+the name, if present, is set as a subscript to the rest of the identifier.
+
+@c
+void out_identifier (id_pointer p)
+{ int k=length(p); eight_bits* ch=(eight_bits*)name_begin(p);
+@/enum { ord, indexed, caps, single, indexed_single } kind;
+ if (p->ilk==TeX_like || p->ilk==NULL_like) @.\\NULL@> @.\\TeX@>
+ @/{@;
+ @< Output the identifier |p| in the form of a \TeX\ control sequence @>
+ return;
+ }
+ if (!compatibility_mode)
+ { do --k; while (isdigit((eight_bits)ch[k])); /* terminates because |!isdigit(ch[0])| */
+ ++k; /* point to end of identifier without its index (if any) */
+ }
+ @< Determine the |kind| of |p|, and possibly output some
+ leading characters @>
+ if (kind==indexed || kind==indexed_single)
+ { out_id_part(name_begin(p),k); /* main part */
+ out ('_'); out_id_part(name_begin(p)+k,length(p)-k); /* subscript */
+ }
+ else out_id_full (p);
+}
+
+@ When an identifier is output in the form of a control sequence,
+underscores are replaced by `\.x' so that they will become part of the
+control sequence. If the |ilk| of the identifier was |TeX_like|, the control
+sequence will be processed in horizontal mode with italic type selected; if
+the |ilk| was |NULL_like|, it will be processed in math mode.
+
+@< Output the identifier |p| in the form of a \TeX\ control sequence @>=
+{ if (p->ilk==TeX_like) out_str("\\\\{");
+ out('\\'); @+ do out(*ch=='_' ? 'x' : *ch); while (*++ch!='\0');
+ if (p->ilk==TeX_like) out('}');
+}
+
+@ For identifiers that consist of a single character, not counting any
+trailing digits, that character is written in unadorned form, since it will
+be processed in math mode, so that the math italic font will be used. We do
+output a space before the character however, to eliminate the possibility
+that it is captured by a control word at the end of the previous output.
+
+@< Determine the |kind|... @>=
+if (k==1) {@; out(' '); kind= length(p)==1 ? single : indexed_single; }
+else
+{ int i=k; @+
+ while (--i>=0) @+ if (!isupper(ch[i])&&!isdigit(ch[i])&&ch[i]!='_') break;
+ kind= i<0 ? caps : k<length(p) ? indexed : ord;
+ out('\\'); out(kind==caps ? '.' : '\\'); @.\\\\@> @.\\.@>
+}
+
+@ The last function for output of tokens, |out_module_name|, represents the
+most complicated aspect of such output, since up to here we have not paid
+any attention to `\pb' constructions in module names. When these are present
+they will need a complete treatment by the scanning, parsing and general
+output routines described above. Now |out_module_name| does not involve
+itself directly in such actions---they are contained in a call to
+|do_C|---but we do have to be aware that we are in the midst of scanning and
+output operations going on at a different level, and be careful not to
+disturb them. The text between `\pb' will be placed at the end of the active
+input buffer (this is why the buffer has size |long_buf_size| rather than
+|buf_size|) and the translation process uses the end of the active |tok_mem|
+area.
+
+On the other hand |out_module_name| is also used during Phase~III while
+writing the list of module names (which implies that scanning and parsing is
+not over at the end of Phase~II). We want |out_module_name| to behave
+slightly differently in Phase~III however, by printing a full list of
+section numbers in which the module is defined rather than just the first
+one. Also, immediately after calling |out_module_name| we will need a
+pointer to the sublist of \xr.s to sections in which the module is used, and
+since this sublist starts at the end of the list of defining sections, we
+might as well return it as result from |out_module_name|.
+
+@c
+xref_pointer out_module_name(mod_pointer name)
+{ xref_pointer x=name->xref; boolean file_module= x->num==file_flag;
+ if (file_module) x=next_xref(x);
+ out_str ("\\X"); @.\\X@>
+ if (x->num>=def_flag)
+ { out_sec_nr(x->num-def_flag); /* output the defining section number */
+ if (phase==3) /* all of them in Phase III */
+ while (x=next_xref(x), x->num>=def_flag)
+ out_str (", "), out_sec_nr(x->num-def_flag);
+ }
+ else out ('0'); /* section number `0' means `nowhere defined' */
+ out (':'); if (file_module) out_str("\\.{"); @.\\.@>
+ @<Output the text of the module name@>
+ if (file_module) out_str ("}");
+ out_str ("\\X");
+ return x;
+}
+
+@ Copying \TeX\ text from a module name to the output is fairly simple, but
+we shouldn't forget to escape special characters if this is actually a file
+name (which is typeset verbatim), even though they are probably quite rare.
+
+@< Output the text... @>=
+{ char* k=name_begin(name),c;
+ while ((c=*k++)!='\0')
+ { if (file_module) @+{@; if (strchr(" \\#%$^{}~&_",c)!=NULL) out ('\\'); }
+ if (c=='@@' && *k++!='@@') @< Report illegal control code in module name @>
+ if (file_module || c!='|') out(c);
+ else
+ { char* save_loc=loc, *save_limit=limit;
+ @< Copy the \Cee\ text into the |buffer| array @>
+ do_C(); loc=save_loc; *(limit=save_limit)=' ';
+ }
+ }
+}
+
+@ We haven't checked for illegal control codes in module names yet, so
+we should report an error if we encounter one.
+
+@< Report illegal control... @>=
+{@; print("\n! Illegal control code in module name"); print_mod(name);
+ @.Illegal control code...@>
+ mark_error();
+}
+
+@ Within `\pb' we should be aware of character and string constants, since
+any `\.\v' occurring there is not the closing one. The variable |delimiter|
+is zero outside such constants, otherwise it equals the delimiter that began
+the constant. We copy the opening and closing `\.\v' into the buffer, so
+that an error message that displays the whole buffer will look a little bit
+sensible. We also add a space at the end (just like |get_line| does) so that
+the closing `\.\v' cannot by accident be parsed as part of an operator such
+as `\.{\v=}'. Putting |next_control='|'| completes the proper initial
+conditions for calling |do_C|. We need not test for overflow of |buffer|
+here, since we start filling it at position |limit| which is at most
+|&buffer[buf_size-2]|, and add at most |longest_name| characters from the
+module name, so that if worst comes to worst, the final space stored at the
+end is at position |&buffer[long_buf_size-2]| leaving one more place after
+|limit|, which is occasionally needed by |get_next|.
+
+@< Copy the \Cee\ text into... @>=
+{ char delimiter='\0'; /* |'"'| or |'\''|, or |'\0'| outside of strings */
+ next_control=*limit++='|'; loc=limit;
+ do
+ if ((c=*k++)=='\0') @< Report a runaway \Cee~text @>
+ else
+ { *limit++=c;
+ @/@< In special cases copy the character after |c|,
+ or change |delimiter| @>
+ }
+ while (c!='|' || delimiter!='\0');
+ *limit=' ';
+}
+
+@ Here cases like `\.{1+@@\v2}', `\.{@@'\v'}' and `\.{'\\''}' within `\pb'
+in module names are handled properly, as well as the more ordinary cases of
+character constants and strings. In case of a control code, the character
+following the `\.@@' cannot be the null character that terminates the module
+name, because it is impossible to enter a module name that ends with a
+single `\.@@'. If the user is being really devious by saying `\.{@@< Sudden
+\v"death\\ @@>}', then the final `\.\\' is silently removed to avoid
+disaster to \.{\me.}.
+
+@< In special cases... @>=
+{ if (c=='@@') /* control code; now |*k!='\0'| */
+ { if ((*limit++=*k++)=='\'' && delimiter=='\0') /* copy code, test for \:' */
+ delimiter='\''; /* which behaves like `\.'' */
+ }
+ else if (c=='\\' && delimiter!='\0')
+ { char d=*limit++=*k++; /* escaped character, possibly |delimiter| */
+ if (d=='\0') --k,limit-=2; /* remove backslash, error is issued anyway */
+ }
+ else if (c=='\'' || c=='"')
+ if (delimiter=='\0') delimiter=c;
+ else if (delimiter==c) delimiter='\0';
+}
+
+@ If the module name ends before the \Cee~text does, we add an |'|'|, and if
+a string or character constant was left unclosed we prepend the closing
+delimiter to it: we must prevent that |do_C| will ever call |get_line|, even
+in erroneous situations. In these cases there is a slight chance that we
+might overflow |buffer|, in which case we quit since the user is just trying
+to break \.{\me.} anyway.
+
+@< Report a runaway \Cee~text @>=
+{ print("\n! C text in module name didn't end"); print_mod(name);
+ @.C text...didn't end@>
+ mark_error();
+ if (delimiter!='\0') *limit++=delimiter;
+ *limit++='|';
+ if (limit>&buffer[long_buf_size-2])
+ fatal("fix that first, you sneaky devil");
+ @.fix that first...@>
+ break;
+}
+
+@ Finally we come to the point where the characters produced are sent off to
+the \TeX~file. The \TeX\ output is supposed to appear in lines at most
+|line_length| characters long, so we place it into an output buffer
+|out_buf|. The first character of the output buffer is used as a sentinel,
+and is not actually written to the output file, so we usually refer to the
+output buffer via |out_line|. The pointer |out_ptr| indicates the next
+position to be used in the output buffer. During the output process,
+|out_line_nr| will hold the current line number of the line about to be
+output; it is only used for (rather unlikely) diagnostic messages.
+
+@d out_line (&out_buf[1]) /* start of actual output line */
+@d out_buf_end (&out_line[line_length]) /* end of |out_buf| */
+
+@<Global...@>=
+char out_buf[line_length+1]; /* assembled characters */
+char* out_ptr; /* first unused position in |out_buf| */
+int out_line_nr=1; /* number of next line to be output */
+
+@ The auxiliary function |flush_buffer| empties the buffer up to a given
+breakpoint~|b|, and moves any remaining characters to the beginning of the
+buffer, so that they will appear on the next line. If the |percent|
+parameter is |true| a |'%'| is appended to the line that is being output; in
+this case the breakpoint |b| should be strictly less than |out_buf_end|. If
+the |percent| parameter is |false|, trailing blanks are suppressed. The
+characters emptied from the buffer form a new line of output.
+
+@d tex_putc(c) putc (c, tex_file)
+@d tex_new_line() (putc('\n', tex_file),++out_line_nr)
+@d tex_printf(format) fprintf(tex_file, format)
+
+@c
+void flush_buffer(char* b, boolean percent)
+ /* output from |out_line| to |b|, where |b<=out_ptr| */
+{ int j=(int)(b-out_line); /* number of characters to be output */
+ if (!percent) @+ while (j>0 && out_line[j-1]==' ') --j;
+ /* remove trailing blanks */
+ fprintf(tex_file, "%.*s",j,out_line);
+ if (percent) tex_putc('%');
+ tex_new_line();
+ { char* p=out_line;
+ while (b<out_ptr) *p++=*b++; /* shift back remainder of line */
+ out_ptr=p; /* adjust to end of (possibly empty) shifted part */
+ }
+}
+
+@ The usual way to send a completed line to the output is to call
+|finish_line|. When we are copying \TeX\ source material, we retain line
+breaks that occur in the input, except that an empty line is not output when
+the \TeX\ source line was not entirely blank. For example, a line of the
+\TeX\ file that contains only an index \xr. entry will not be copied. Since
+|get_line| has removed trailing blanks, the input line is blank if and only
+if it is empty; similarly the emptiness of the output line is tested by a
+simple comparison because |copy_limbo| and |copy_TeX| have not copied spaces
+into an empty output line. The |finish_line| routine is called just before
+|get_line| inputs a new line, and just after a line break token has been
+emitted during the output of translated \Cee~text.
+
+@d output_line_empty() (out_ptr==out_line)
+
+@c
+void finish_line(void) /* do this at the end of a line */
+{ if (!output_line_empty()) flush_buffer(out_ptr, false);
+ else if (limit==buffer) tex_new_line(); /* copy blank input line */
+}
+
+@ In particular, the function |finish_line| is called near the very
+beginning of Phase~II. We initialize the output buffer in such a way that
+the first line of the output file will be `\.{\\input cwebxmac}', or
+`\.{\\input cwebcmac}' in compatibility mode. At position~0 of the output
+buffer, which is never really output, we put a space that will help make the
+function |break_out| a little faster.
+
+@< Set initial... @>=
+{ char* line1=" \\input cwebxmac";
+ out_ptr=&out_buf[0]; @+ do *out_ptr++=*line1++; while (*line1!='\0');
+ if (compatibility_mode) out_ptr[-4]='c'; /* change to \.{cwebcmac} */
+}
+
+@ When we wish to append one character |c| to the output buffer, we write
+`|out(c)|'; this will cause the buffer to be broken at a sensible place and
+flushed, if it was already full. If we want to append more than one
+character at once, we say |out_str(s)|, where |s| is a string containing the
+characters.
+
+@d out(c)
+ *(out_ptr>=out_buf_end ? (break_out(),out_ptr++) : out_ptr++)=c
+
+@c
+void out_str (char* s) @+{@; while (*s!='\0') out (*s++); }
+
+@ The function |break_out| will determine a good break point in the output
+buffer when it is about to overflow.
+
+@< Prototypes @>=
+void break_out (void);
+
+@~For speed we search from right to left for a proper break point, although
+in this direction we cannot know whether we are inside a control sequence.
+Nevertheless any blank space is a safe break point, as is the position just
+before a backslash that isn't preceded by another backslash. If the break is
+not at a space, a |'%'| is output at the break.
+
+@c
+void break_out (void) /* finds a way to break the output line */
+{ char* k=out_ptr,c; int count=0; /* number of backslashes seen */
+ do @+ if ((c=*--k)==' ') goto found; @+ while (c!='\\');
+ do ++count; while ((c=*--k)=='\\');
+found:
+ if (++k>out_line) flush_buffer(k,c!=' '); @+ else @< Break peculiar line @>
+}
+
+@ We get to this section only in the unusual case that the entire output line
+consists of a string of backslashes followed by a string of characters that
+contains no spaces or backslashes. Depending on the number |count| of
+backslashes we handle this case as well as possible. If the |count>=2| we
+split off a maximal even number of initial backslashes, and if |count==0| we
+break the line by putting a |'%'| at the position of the last character. In
+the latter case we do not place the |'%'| after the last character, since
+that would make the output line one character longer than we promised;
+similarly we are cautious in the former case not to place a |'%'| after a
+buffer completely filled with backslashes. If |count==1| the line is
+probably one enormous control word, and in this unlikely case we simply
+output the whole line as is stands, after issuing a warning message.
+
+@< Break peculiar line @>=
+if (count==0) flush_buffer(out_ptr-1,true);
+else if (count>=2) flush_buffer
+ (&out_line[count&=~1]==out_buf_end ? out_buf_end-2 : &out_line[count],true);
+else
+{ print("\n! Line had to be broken (output l.%d):\n",out_line_nr);
+ @.Line had to be broken@>
+ term_write(out_line,out_ptr-out_line); new_line(); mark_harmless();
+ flush_buffer(out_ptr,false);
+}
+
+
+@* Phase III processing. @:title@>
+After Phase~II is completed, \.{\me.}'s only remaining task is writing out
+the index, after sorting the identifiers and index entries, and a list of
+module names. If the user has set the |no_xref| flag (the \.{-x} option on
+the command line), we just finish off the page, omitting the index, module
+name list, and table of contents.
+
+@d triple_file_output flags['t']
+@d even_out_pages flags['e']
+
+@c
+void phase_three (void) /* output the \xr. index */
+{ finish_line();
+ if (no_xref) out_str("\\endcodemode\\vfill\\end");
+ else
+ { phase=3; print_progress("\nWriting the index...");
+ @.Writing the index...@>
+ typedef_tracking(false); /* during parse of `\pb' in module names */
+ if (change_exists)
+ {@; @<Tell about changed sections @> finish_line(); }
+ if (triple_file_output)
+ @< Finish the \TeX~file and open the index file @>
+ else {@; out_str("\\inx"); finish_line(); } @.\\inx@> /* index */
+ @<Sort and output the index@>
+ if (triple_file_output)
+ @< Finish the index file and open the module listing file @>
+ else {@; out_str("\\fin"), finish_line(); } @.\\fin@> /* end of index */
+ @<Output all the module names@>
+ if (!triple_file_output)
+ { out_str("\\con"); @.\\con@> /* table of contents */
+ if (even_out_pages) out_str("even"); @.\\coneven@>
+ }
+ }
+ finish_line(); fclose(tex_file);
+ print_progress("\nDone.\n");
+ check_complete(); /* was all of the change file used? */
+}
+
+@ When output is to be distributed over three files, we can already finish
+off the main output file, since it ends in a standard way: with `\.{\\input}'
+commands for the two other files (that still have to be written) and either
+`\.{\\con}' or `\.{\\coneven}' to produce the table of contents. Since the
+three output files are written one after the other, we can reuse the file
+pointer |tex_file| for all of them.
+
+@< Finish the \TeX~file and open the index file @>=
+{ out_str("\\inx \\input \\jobname.idx\n" @+
+ "\\fin \\input \\jobname.scn\n" @+
+ "\\con");
+ if (even_out_pages) out_str("even");
+ finish_line(); fclose(tex_file);
+ if ((tex_file=fopen(idx_file_name,"w"))==NULL)
+ fatal("! Cannot open \"%s\" as output file",idx_file_name);
+}
+
+@~The switch from the index file to the module listing file is similar, but
+simpler.
+
+@< Finish the index file and open the module listing file @>=
+{ finish_line(); fclose(tex_file);
+ if ((tex_file=fopen(scn_file_name,"w"))==NULL)
+ fatal("! Cannot open \"%s\" as output file",scn_file_name);
+}
+
+@ Just before the index comes a list of all the changed sections, including
+the index section itself. The outer |while| loop will terminate without
+overstepping the bounds of |changed_section| in the inner loop since
+|section_changed(section_count)| holds.
+
+@<Tell about changed sections@>=
+{ int k=0; boolean first=true;
+ out_str("\\ch "); @.\\ch@> /* changes */
+ while (k<section_count)
+ { do ++k; while (!section_changed(k));
+ if (first) first=false; @+ else out_str(", ");
+ out_sec_nr(k);
+ }
+ out('.');
+}
+
+@ A left-to-right radix sorting method is used, since this makes it easy to
+adjust the collating sequence, and the running time will be at worst
+proportional to the total length of all entries in the index.
+During the sorting phase the partially sorted index entries that have not
+yet been output are held on a stack of identifier lists called |sort_info|.
+Each of these lists is unsorted, but between elements of different lists the
+ordering is completely known: for any pair of lists, all elements of the
+list nearer to the top of the stack precede all elements of the other list
+(this ordering is chosen because elements are output at the top of the
+stack). The entries of |sort_info| are structures of type |sort_node|; they
+have a |head| field that points to the first name of the list, and a
+|depth| field that tells how many initial characters are known to be equal
+among the entries of the list.
+
+@<Typedef...@>=
+typedef struct {@; id_pointer head; int depth; } sort_node, * sort_pointer;
+
+@~In fact |sort_info| shares its memory with the |scrap_info| array that
+serves no purpose at this moment (although it will be used again during
+the output of module names).
+
+@d sort_info scrap_union.id_list_field
+@d sort_info_end (&sort_info[sort_stack_size])
+@< Alternative use... @>=
+sort_node id_list_field[sort_stack_size];
+
+@ The variable |sort_ptr| points to the first unused slot above the top of
+the stack in~|sort_info|.
+
+@<Global...@>=
+sort_pointer sort_ptr=sort_info;
+#ifdef STAT
+sort_pointer max_sort_ptr=sort_info; /* largest value of |sort_ptr| */
+#endif
+
+@ The desired alphabetic order is specified by the |collate| array; namely,
+|collate[0] < collate[1] < @t\dots@> < collate[end_collate-1]|. Upper case
+letters are treated like the corresponding lower case letters, since we want
+to have `|t<TeX<@[token@]|'. Therefore the collation array should have length
+|UCHAR_MAX+1-26|. We are a bit extra cautious however, in case there are
+implementations in which the verdict |isalpha(c)| is given (incorrectly) to
+certain values |c>=128|, which would cause the part of |collate| that is
+actually used to be shorter than that; therefore we compute the actual
+length in |end_collate|.
+
+@<Global...@>=
+eight_bits collate[UCHAR_MAX-25]; /* collation order */
+int end_collate; /* length of the part of |collate| actually used */
+
+@ We use the order |'\0' < ' ' < @tother characters@> < '_' < 'A'=='a' <
+@t\dots@> < 'Z'=='z' < '0' <@t\dots@> < '9'|. If there should be any
+characters~|c| for which |tolower(c)| does not occur in |collate| (this can
+only happen if |isalnum(c)| incorrectly holds), then entries containing the
+character~|c| will not appear in the index. By computing |end_collate|
+rather than using a constant |UCHAR_MAX-25|, we avoid however that the mere
+existence of such characters would disrupt the proper order of the
+index entries that do appear, due to spurious bytes |'\0'| at the end
+of~|collate|.
+
+@<Set init...@>=
+{ char *p="_abcdefghijklmnopqrstuvwxyz0123456789";
+ int c='\1', k=2;
+ collate[0]='\0'; collate[1]=' ';
+ do @+ if (!isalnum(c) && c!='_' && c!=' ') collate[k++]=c; @+
+ while (++c<=UCHAR_MAX);
+ while ((c=*p++)!='\0') collate[k++]=c;
+ end_collate=k; /* record the length */
+}
+
+@ The lists of identifiers used for sorting the index cannot be linked
+together using |hash_link|, since we still need to be able to look up
+identifiers when writing the list of module names. Therefore we declare a
+separate array |index_link| that will provide the necessary links, and a
+macro |ilink| used to access it: |ilink(p)| points to the successor of~|p|
+(or is~|NULL|) for any |id_pointer p@;|.
+
+At each sorting step we partition a list of identifiers into at most
+|UCHAR_MAX-25| sublists, based on the first character position where the
+entries of the list are not known to be equal. After the partitioning step
+the sublist for character~|c| is pointed to by |bucket[tolower(c)]|.
+
+@d ilink(p) index_link[id_index(p)]
+
+@<Global...@>=
+id_pointer index_link[max_idents]; /* links identifiers during sorting */
+id_pointer bucket[UCHAR_MAX+1];
+
+@ The basic sorting step is to pop the list from the top of the stack, and
+either output it, if needs no further refinement, or to split it up into the
+buckets, after which the function |unbucket| collects the non-empty buckets
+and pushes them back on the stack. At the very first step however, the
+identifiers do not come from the stack but directly from the identifier
+table. In the remaining cases, the |depth| field of the element popped off
+the stack is used to determine the character position used for splitting,
+and is passed to |unbucket| so that it can set the proper depth when it
+pushes lists back on the stack. When |depth| has risen to~|255| (or more
+likely, has been set explicitly to that value by a previous |unbucket|), no
+attempt is made to split up a list, even if it is not reduced to a
+singleton.
+
+@d infinity 255 /* $\infty$ (approximately) */
+
+@< Sort and output... @>=
+{ @<Do the first pass of sorting@>
+ /* the first time, entries do not come from |sort_info| */
+ unbucket(1); /* pick up first-order bucketed lists */
+ while (sort_ptr>sort_info) /* i.e., the stack is not empty */
+ { eight_bits depth=(--sort_ptr)->depth;
+ id_pointer name=sort_ptr->head;
+ if (ilink(name)==NULL || depth==infinity)
+ /* singleton or set of look-alikes */
+ @< Output index entries for the list starting at |name| @>
+ else
+ {@; @< Split the list starting at |name| into further lists @>
+ unbucket(depth+1);
+ }
+ }
+}
+
+@ To begin the sorting, we go through all the hash lists and put each entry
+having a non-empty \xr. list into the proper bucket. The buckets are emptied
+initially; they will also be emptied by each call to~|unbucket|. The entries
+of the |index_link| array are initialised when their corresponding
+identifiers are prepended to the list of some bucket.
+
+@<Do the first pass...@>=
+{ id_pointer name;
+ eight_bits c=UCHAR_MAX;
+ id_pointer *h; /* pointer into |hash| */
+
+ do bucket[c]=NULL; while (c--!=0);
+ for (h=hash; h<hash_end; h++)
+ for (name=*h; name!=NULL; name=name->hash_link)
+ /* traverse all hash lists */
+ if (name->ilk!=reference && name->xref->num!=0)
+ /* leave out unreferenced names */
+ {@; c=name_begin(name)[0]; c=tolower(c);
+ ilink(name)=bucket[c]; bucket[c]=name;
+ }
+}
+
+@ Here we split the list at the top of the stack into buckets. Entries of
+length |depth| will bet sent to |bucket['\0']| due to the null character
+stored at the end of identifier names; shorter entries do not come here
+since they will already have been output. Since we are changing the |ilink|
+of the front node of the list when putting it into its bucket, we must be a
+bit more cautious then usual in traversing the list.
+
+@< Split the list... @>=
+do
+{ eight_bits c= tolower((eight_bits)name_begin(name)[depth]);
+ id_pointer next_name=ilink(name); /* save link */
+ ilink(name)=bucket[c]; bucket[c]=name; name=next_name;
+ /* put into bucket */
+}
+while (name!=NULL);
+
+@ The function |unbucket| goes through the buckets in the reverse order of
+the collating sequence specified in the |collate| array, and adds non-empty
+lists to the stack. The parameter |d| to |unbucket| tells the current depth
+in the buckets; it will be recorded in all lists pushed on the stack during
+this call, except that the contents of the bucket containing the identifiers
+of length~|d-1| will be given depth |infinity| so that they will be output
+directly afterwards. Any two sequences that agree up to the case of their
+characters (with any characters beyond position~255 being ignored) are
+regarded as identical and will be output in a random order. It is only
+because of this case-merging that there could possibly be more than one
+identifier of length~|d-1|, which makes setting the depth to |infinity|
+necessary; in other cases the special attention is superfluous, since
+singleton lists will be output directly anyway.
+
+@< Prototypes @>=
+void unbucket (eight_bits);
+
+@~@c
+void unbucket (eight_bits d) /* empties buckets having depth |d| */
+{ int i=end_collate; /* index into |collate| */
+ while(--i>=0) @+ if (bucket[collate[i]]!=NULL)
+ { if (sort_ptr>=sort_info_end)
+ overflow("sorting"); @.sorting capacity exceeded@>
+ sort_ptr->depth= i==0 ? infinity : d;
+ /* |infinity| means there is nothing left to compare */
+ sort_ptr++->head=bucket[collate[i]];
+ bucket[collate[i]]=NULL; /* push and empty bucket */
+#ifdef STAT
+ if (sort_ptr>max_sort_ptr) max_sort_ptr=sort_ptr;
+#endif
+ }
+}
+
+@ Each line in the index file starts with the macro `\.{\\@@}', which will
+be properly defined when it is encountered.
+
+@< Output index... @>=
+do
+{ out_str("\\@@"); @.\\@@@>
+ @<Output the index entry |name|@>
+ @<Output the \xr.s of |name|@>
+} while ((name=ilink(name))!= NULL);
+
+@ In this section the distinction between |xref_roman|, |xref_wildcard|, and
+|xref_typewriter| finally becomes effective. As first character (immediately
+after `\.{\\@@}') we output a character `\.h' or `\.m',indicating whether the
+index entry should be processed in horizontal or in math mode.
+@.\\NULL@> @.\\TeX@>
+
+@<Output the index entry...@>=
+switch (name->ilk)
+{ case normal: case NULL_like: out('m'); out_identifier(name); break;
+ case TeX_like: out('h'); out_identifier(name); break;
+ case roman: out('h'); out_index(name); break;
+ case wildcard: out_str("h\\9"); out_index(name); break; @.\\9@>
+ case typewriter: out_str("h\\."); out_index(name); break; @.\\.@>
+ default: out('h'); out_keyword(name);
+}
+
+@ Section numbers that are to be underlined are enclosed in
+`\.{\\[}\dots\.]'. The first `\.{,\ }' will be scooped up by the macro
+`\.{\\@@}'.
+
+@<Output the \xr.s...@>=
+{ xref_pointer x=name->xref;
+ do
+ { sixteen_bits n=x->num;
+ out_str(", ");
+ if (n<def_flag) out_sec_nr(n);
+ else {@; out_str("\\["); out_sec_nr(n-def_flag); out(']'); } @.\\[@>
+ } while ((x=next_xref(x))->num!=0);
+ out('.'); finish_line();
+}
+
+@ The following recursive function traverses the tree of module names and
+prints them. We use the order already present in the tree, which means that
+we do not use the collation sequence that was employed for sorting the
+index. If the user starts all module names with capital letters however, the
+difference should hardly be noticeable.
+@^recursion@>
+
+@< Prototypes @>=
+void list_modules (mod_pointer);
+
+@~The macro `\.{\\@@}' is redefined to serve for lines in the list of module
+names as well. Since module names are to be processed in math mode, we
+enclose them in dollar signs.
+
+@c
+void list_modules (mod_pointer p) /* print all module names in subtree |p| */
+{ if (p != NULL)
+ { list_modules(p->llink);
+@/ out_str("\\@@$"); @.\\@@@>
+ leave_block(0); scrap_ptr=scrap_info; /* get ready for parsing */
+ {@; xref_pointer x=out_module_name(p); out('$');
+ footnote(&x,cite_flag); footnote(&x,0);
+ }@/
+ finish_line();
+@/ list_modules(p->rlink);
+ }
+}
+
+@~Initially |list_modules| is called for the root of the tree, of course.
+
+@<Output all the module names@>= list_modules(root);
+
+@ At the end of the run, if |STAT| was defined and the `\.{+s}' flag
+present, we report how much of all the arrays was actually needed.
+
+@d report(k,c,m)
+ printf("\t%lu %ss (out of %lu)\n",(unsigned long)(c),k,(unsigned long)(m))
+@c
+#ifdef STAT
+void print_stats()
+{ print("\nMemory usage statistics:\n"); @.Memory usage statistics@>
+@/report("identifier", id_index(id_ptr), max_idents);
+@/report("module name", mod_index(mod_ptr), max_modules);
+@/report("byte", byte_ptr-byte_mem, max_bytes);
+@/report("cross-reference", xref_ptr-xmem, max_refs-1);
+@)printf("Parsing:\n");
+@/report("scrap", max_scr_ptr-scrap_info, max_scraps);
+@/report("text", max_text_ptr-text_mem, max_texts);
+@/report("token", max_tok_ptr-tok_mem, max_toks);
+@/report("trie node", node_no, max_no_of_nodes);
+@/report("level", max_stack_ptr-stack, stack_size);
+@)printf("Sorting:\n");
+@/report("level", max_sort_ptr-sort_info, sort_stack_size);
+}
+#endif
+
+
+@* Index. @:index@> @:title@>
+If you have read and understood the code for Phase~III above,
+you know what is in this index and how it got here. All sections in
+which an identifier is used are listed with that identifier, except
+that reserved words are indexed only when they appear in format
+definitions, and the appearances of identifiers in module names are
+not indexed. Underlined entries correspond to where the identifier
+was declared. Error messages, control sequences put into the output,
+and a few other things like ``recursion'' are indexed here too.
diff --git a/web/c_cpp/cwebx/cwebcmac.tex b/web/c_cpp/cwebx/cwebcmac.tex
new file mode 100644
index 0000000000..42d76748ec
--- /dev/null
+++ b/web/c_cpp/cwebx/cwebcmac.tex
@@ -0,0 +1,77 @@
+% Compatibility mode macros for CWEBx (in addition to cwebxmac.tex)
+% File: cwebcmac.tex, Author: Marc van Leeuwen, Date: November 1994
+
+% This file gives definitions to macros defined in cwebmac.tex that are
+% undefined in cwebxmac.tex, in order to simulate the cwebmac macro
+% environment as much as possible in compatibility mode of CWEBx.
+% In addition \PB is defined so as to get decent behaviour of |...| when used
+% inside math mode (which one should't do, but some do it anyway).
+
+\ifx\documentstyle\undefined\else\endinput\fi % LaTeX will use other macros
+
+\input cwebxmac % that's the standard stuff
+\xdef\fmtversion{\fmtversion c}
+
+\let\mc=\ninerm % medium caps
+\let\sc=\eightrm % small caps (NOT a caps-and-small-caps font)
+%\font\tenss=cmss10 \let\cmntfont\tenss % alternative comment font
+
+\def\CEE/{\Cee}
+\def\UNIX/{\caps{UNIX}}
+\def\TEX/{\TeX}
+\def\CPLUSPLUS/{\Cpp}
+\def\9#1{}
+\let\cmntfont\tenrm
+
+\def\|#1{\leavevmode\hbox{$#1$}} % in case this is used directly
+\def\ATP{\X\kern-.5em:Preprocessor definitions\X}
+\let\ATH=\ATP % in case the user refers to \ATH directly
+\def\PB#1{\ifmmode\hbox{#1}\else#1\fi} % make |...| safe in math mode
+
+\def\DC{\kern.1em{::}\kern.1em} % symbol for ::
+\def\PA{\mathbin{.*}} % symbol for .*
+\def\MGA{\mathbin{\MG*}} % symbol for ->*
+
+% Revert to Levy/Knuth representations of operators
+
+\def\K{=\Penalty2} % assignment operator
+\def\E{\Penalty7\equiv} % equality test
+\newbox\MGbox % symbol for ->
+\setbox\MGbox=\hbox{\kern-2pt\lower3pt\hbox{\teni\char'176}\kern1pt}
+\def\MG{\copy\MGbox}
+
+\secpagedepth=3 % page breaks will occur for depths -1, 0, and 1
+\let\SHC\C % "// short comments" treated like "/* ordinary comments */"
+\outer\def\N#1 #2. #3. % start of `@*' section
+ {\global\gdepth=#1\global\advance\gdepth1 \global\gtitle={#3}\MN#2.%
+ \ifon \ifnum#1<\secpagedepth \vfil\eject
+ \else \vskip 0pt plus .5 \vsize \penalty-1000\vskip 0pt plus -.5 \vsize
+ \vskip\intersecskip
+ \fi
+ \fi
+ \message{*\secno} % progress report
+ \edef\next{\write\cont % to contents file
+ {\ZZ{#3}{\number\gdepth}{\secno}{\noexpand\number\pageno}}}
+ \next
+ \ifon\startsection{\bf#3.\quad}%
+ }
+
+\def\contentsline#1#2#3#4% #1==title, #2=depth+1, #3=secno, #4=pageno
+ {\ifnum#2=0 \smallbreak\fi
+ \line{\consetup{#2}#1 \rm\leaders\hbox to .5em{.\hfil}\hfil
+ \ #3\hbox to3em{\hss#4}%
+ }%
+ }
+\def\consetup#1% #1=depth+1
+ {\ifcase#1 \bf % @**
+ \or % @*
+ \or \hskip2em % @*1
+ \or \hskip4em % @*2
+ \or \hskip6em % @*3
+ \or \hskip8em % @*4
+ \or \hskip10em % @*5
+ \else \hskip12em % depth >=6
+ \fi
+ }
+
+\def\,{\relax\ifmmode\mskip\thinmuskip\else\thinspace\fi}
diff --git a/web/c_cpp/cwebx/cwebhmac.tex b/web/c_cpp/cwebx/cwebhmac.tex
new file mode 100644
index 0000000000..3b55c34e59
--- /dev/null
+++ b/web/c_cpp/cwebx/cwebhmac.tex
@@ -0,0 +1,143 @@
+% This is file cwebhmac.tex, part of the CWEBx distribution.
+
+% This file can be loaded after cwebxmac.tex, in order to automatically
+% insert \specials for use by the xhdvi previewer, or any other HyperTeX
+% dvi-file processing tool. Current version is alpha release.
+
+% Author: Marc van Leeuwen
+% Last modified: 8 november 1996.
+
+% The following macros are redefined
+% \stsec
+% \note<text><section list>.
+% \finnote<text><section list>.
+% \X<number>:<module name>\X
+
+\ifx\hyperloaded\undefined \let\hyperloaded\relax \else \endinput\fi
+
+
+% Low level interface to hyperlinks and targets
+
+% \hyperanchor<attributes><anchor text>
+% general mechanism to define <achor text> as anchor with <attributes>
+\long\def\hyperanchor#1#2{\special{html:<A #1>}{#2}\special{html:</A>}}
+
+% \hyperlink<URL><active text>
+% makes <active text> an active link referring to <URL>
+\def\hyperlink#1{\hyperanchor{href="#1"}}
+
+% \hypertarget<tag><target text>
+% defines a local target for hyperlinks, that can be referenced by <tag>
+\def\hypertarget#1{\hyperanchor{name="#1"}}
+
+% \hyperdef<kind><number><target text>
+% defines a hypertarget classified by <kind> and sequence <number>
+\def\hyperdef#1#2{\hypertarget{#1.#2}}
+
+% \hyperref<assignments><kind><number><active text>
+% creates a hyperlink to local target created by \hyperdef<kind><number>
+% <assignments> are optional assignments for expansion of <kind> and <number>
+{\catcode`\#=12 \gdef\sharp{#}} % to access neutralised '#' character
+\def\hyperref#1#2#3%
+{{#1\xdef\next{{\sharp#2.#3}}}\expandafter\hyperlink\next}
+
+
+% High level interface attached to CWEAVE-produced macros (or to those
+% accessed by them via the definition of cwebxmac.tex)
+
+% Target attached to beginning of each section. <kind>=sec, <number>=\secno.
+\def\stsec
+ {\endcodemode\noindent
+ \hyperdef{sec}\secno{\let\*=\lapstar\bf\secstar.}\quad
+ }
+\let\startsection=\stsec % this one is used; provides hook for extra actions
+
+% List of links attached to end of some sections.
+\def\note#1#2.%
+{\Y\noindent{\hangindent2\indentunit\baselineskip10pt\eightrm
+ #1~\hypersecrefs#2, .\par}}
+
+% Same, but for references from the list of module names.
+\def\finnote#1#2.{\quad{\eightrm#1~\hypersecrefs#2, .}}
+
+% the following two are auxiliary macros that implement reference lists.
+
+% \hypersecrefs<number>, <number>, ..., <number><ETcode><number>, .
+% or \hypersecrefs<number>, .
+% make list of hyperlinks to each of then mentioned sections
+\def\hypersecrefs#1, #2.%
+{\ifx|#2|\def\next{\finalsecrefs#1\ET\ET.#1\ETs\ETs}% final `.' follows below
+ \else\hyperref{\let\*=\empty}{sec}{#1}{#1}, \let\next=\hypersecrefs
+ \fi\next#2.%
+}
+
+% \finalsecref<n><ETcode><m>\ET\ET.<n><ETcode><m>\ETs\ETs.
+% or \finalsecref<n>\ET\ET.<n>\ETs\ETs.
+\def\finalsecrefs#1\ET#2\ET#3.#4\ETs#5\ETs#6.%
+{\ifx|#2#5|\hyperref{\let\*=\empty}{sec}{#1}{#1}% just 1 reference
+ \else % <n>\ET<m> or <n>\ETs<m>
+ \edef\next{\ifx|#5|#1\else#4\fi}% <n>
+ \toks0={\let\*=\empty}%
+ \edef\next{{\the\toks0}{sec}{\next}{\next}}%
+ \expandafter\hyperref\next% link to sec.<n> with text <n>
+ #3#6% one is empty, the other is \ET or \ETs, as appropriate
+ \hyperref{\let\*=\empty}{sec}{#2#5}{#2#5}% similar trick, link to sec.<m>
+ \fi
+}
+
+% we must change \ATP slightly, so that \X can recognise it and avoid a link
+\def\ATP{\X\ATP\kern-.5em:Preprocessor directives\X}
+
+\def\X#1:#2\X % module name
+{\langle\,${#2\eightrm\enspace\ifx\ATP#1\else\hypersecrefs#1, .\fi}$\,\rangle}
+
+{\catcode`_=12 \gdef\usplain{\def\_{_}}}
+
+\let\plainCident=\Cident
+
+\def\Cident#1{\def\idstart{#1}\futurelet\next\testid}
+\let\\=\Cident % cwebx only; a \hbox would prevent us from seeing "subscript"
+
+\def\testid
+{\ifx_\next
+ \def\next_##1%
+ {\hyperref\usplain{id}{\idstart##1}{\plainCident\idstart_{##1}}}%
+ \else \hyperref\usplain{id}\idstart{\plainCident\idstart}%
+ \let\next=\empty
+ \fi\next
+}
+
+\def\indextestid
+{\ifx_\next
+ \def\next_##1%
+ {{\usplain\xdef\next{{id}{\idstart##1}}}%
+ \expandafter\hyperdef\next{\plainCident\idstart_{##1}}%
+ }%
+ \else
+ {\usplain\xdef\next{{id}{\idstart}}}%
+ \expandafter\hyperdef\next{\plainCident\idstart}%
+ \let\next=\empty
+ \fi\next
+}
+
+{\let \inxentry=\relax % remove \outer-ness
+ \toks0=\expandafter{\inx \let\testid=\indextestid}\xdef\inx{\the\toks0 }
+}
+
+\outer\def\inxentry#1#2, #3.% #1 is `h' or `m' for horiz/math mode
+ {\par\hangindent2em\noindent
+ \if#1m$#2$\else#2\relax\fi % \relax avoids fatal \next=\fi in \indextestid
+ :\kern1em\indexrefs#3, .%
+ }
+
+\def\indexrefs#1, #2.%
+{\hyperref{\let\*=\empty\def\[##1]{##1}}{sec}{#1}{#1}%
+ \ifx|#2|\let\next=\empty\else, \let\next=\indexrefs\fi\next#2.%
+}
+
+\def\contentsline#1#2#3#4% #1=depth, #2=title, #3=secno, #4=pageno
+ {\line{\hyperref{}{sec}{#3}{\ignorespaces#2}
+ \leaders\hbox to .5em{.\hfil}\hfil
+ \ \hyperref{}{sec}{#3}{#3 \hbox to3em{\hss#4}}%
+ }%
+ }
diff --git a/web/c_cpp/cwebx/cwebxmac.tex b/web/c_cpp/cwebx/cwebxmac.tex
new file mode 100644
index 0000000000..47157c8aba
--- /dev/null
+++ b/web/c_cpp/cwebx/cwebxmac.tex
@@ -0,0 +1,442 @@
+% Standard macros for CWEBx listings (in addition to plain.tex)
+% File: cwebxmac.tex, Author: Marc van Leeuwen, Date: November 1994
+
+\ifx\documentstyle\undefined\else\endinput\fi % LaTeX will use other macros
+\ifx \cwebxmacloaded\undefined \let\cwebxmacloaded=\relax \else \endinput \fi
+\xdef\fmtversion{\fmtversion+CWEBx3.0}
+\let\:=\. % preserve a way to get the dot accent
+
+\font\ninerm=cmr9
+\font\eightrm=cmr8
+\font\titlefont=cmr7 scaled\magstep4 % title on the contents page
+\font\ttitlefont=cmtt10 scaled\magstep2 % typewriter type in title
+\font\tentex=cmtex10 % TeX extended character set (used in strings)
+\fontdimen7\tentex=0pt % no double space after sentences
+\hyphenchar\tentex=-1 % no automatic hyphenation within strings
+
+\newdimen\indentunit \indentunit 1em
+\parskip 0pt % no stretch between paragraphs
+\parindent\indentunit % for paragraphs and for the first line of C text
+
+\chardef\v=`| % vertical (|)
+\def\caps#1{\hbox{\ninerm #1}}
+\def\Cee{\caps C} \def\Cpp{\Cee\PP} % \def\UNIX{\caps{UNIX}} etc.
+\let\Sec=\S % section mark
+\def\Secs{\Sec\Sec} % as in \Sec@#label@>
+
+\let\mainfont=\tenrm
+
+\def\Cident#1{{\it#1\/\kern.05em}} % italic type for identifiers
+\def\\#1{\leavevmode\hbox\Cident{#1}} % robust version
+\def\Cbold#1{{\bf
+ \def\_{\kern.04em\vbox{\hrule width.3em height .6pt}\kern.08em}%
+ #1\/\kern.05em}} % boldface type for reserved words
+\def\&#1{\leavevmode\hbox\Cbold{#1}} % robust version
+\def\Cstring#1{\ifmmode {}$\typewriter{#1}${}\else\typewriter{#1}\fi}
+\def\typewriter#1{{\tentex % typewriter type for strings
+ \let\\=\BS % backslash in a string
+ \let\{=\LB % left brace in a string
+ \let\}=\RB % right brace in a string
+ \let\~=\TL % tilde in a string
+ \let\ =\SP % space in a string
+ \let\_=\UL % underline in a string
+ \let\&=\AM % ampersand in a string
+ \let\^=\CF % circumflex in a string
+ #1\kern.05em}}
+\def\.#1{\leavevmode\hbox\typewriter{#1}}
+\def\){\discretionary{"}{"}{}} % discretionary string break
+\def\AT{@} % at sign for control text (no longer needed since CWEBx2+1.0)
+\def\a#1{\mathopen{\hbox to \indentunit{$#1$\hss}}} % '{' in tab space
+\def\m#1{\mathord{#1}} % braces required here if #1 generates a penalty
+
+\chardef\AM=`\& % ampersand character in a string
+\chardef\BS=`\\ % backslash in a string
+\chardef\LB=`\{ % left brace in a string
+\chardef\RB=`\} % right brace in a string
+\def\SP{{\tt\char`\ }} % (visible) space in a string
+\chardef\TL=`\~ % tilde in a string
+\chardef\UL=`\_ % underline character in a string
+\chardef\CF=`\^ % circumflex character in a string
+
+\newbox\PPbox % symbol for ++
+\setbox\PPbox=\hbox{\kern.5pt\raise1pt\hbox{\sevenrm+\kern-1pt+}\kern.5pt}
+\def\PP{\copy\PPbox}
+\newbox\MMbox
+\setbox\MMbox=\hbox{\kern.5pt\raise1pt\hbox{\sevensy\char0
+ \kern-1pt\char0}\kern.5pt}
+\def\MM{\copy\MMbox}
+\newbox\SSbox % symbol for ##
+\setbox\SSbox=\hbox{\kern.5pt\raise1pt\hbox{\sevenrm\#\kern-1pt\#}\kern.5pt}
+\def\SS{\mathbin{\copy\SSbox}}
+\def\MG{{\rightarrow}} % symbol for `->'
+\let\GG=\gg
+\let\LL=\ll
+\let\NULL=\odot
+\mathchardef\AND="2026 % bitwise and; also \& (unary operator)
+\def\OR{\Penalty6\mid} % bitwise or
+\let\XOR=\oplus % bitwise exclusive or
+\def\CM{{\sim}} % bitwise complement
+\newbox\MODbox \setbox\MODbox=\hbox{\eightrm\%}
+\def\MOD{\mathbin{\copy\MODbox}}
+\def\CC{::}
+
+\newbox\bak \setbox\bak=\hbox to -\indentunit{} % backspace one em
+\newbox\bakk\setbox\bakk=\hbox to -2\indentunit{} % backspace two ems
+
+\newcount\ind % current indentation level + 2 (for hanging indentation)
+\newcount\pl %level of parentheses
+\mathchardef\lpar=\mathcode`( \mathchardef\rpar=\mathcode`)
+\mathchardef\lbrac=\mathcode`[ \mathchardef\rbrac=\mathcode`]
+\mathchardef\plus=\mathcode`+ \mathchardef\minus=\mathcode`-
+\mathchardef\mcolon=\mathcode`:
+{\catcode`(=\active \catcode`)=\active
+ \catcode`[=\active \catcode`]=\active
+ \gdef({\global\advance\pl 1\lpar}
+ \gdef){\ifnum\pl>0\global\advance\pl-1\fi\rpar}
+ \gdef[{\global\advance\pl 2\lbrac}
+ \gdef]{\ifnum\pl>0\global\advance\pl-2\fi\rbrac}
+ \catcode`+=\active \catcode`-=\active \catcode`*=\active
+ \gdef+{\Penalty8\plus} \gdef-{\Penalty8\minus} \gdef*{\Penalty9\ast}
+ \catcode`:=\active \gdef:{\Penalty3\mcolon}
+}
+\def\cweblbrace{\global\advance\pl 1\lbrace}
+\def\cwebrbrace{\ifnum\pl>0\global\advance\pl-1\fi\rbrace}
+
+% breaking within parentheses will be unattractive,
+% and within brackets even more so
+
+\def\0#1{\penalty\number\pl#10 } % optional break in inner mode
+\def\1{\global\advance\ind by1\global\hangindent\ind\indentunit}
+ % indent one more notch
+\def\2{\global\advance\ind by-1} % indent one less notch
+\def\3#1{\hfil\0#1\hfilneg} % optional break in outer mode
+\def\4{\copy\bak\ignorespaces} % backspace one notch
+\def\5{\hfil\penalty-1\hfilneg\enspace\kern2\indentunit\copy\bakk
+ \ignorespaces}% break space
+\def\6{\ifmmode\else\par % forced break
+ \hangindent\ind\indentunit\noindent\kern\ind\indentunit
+ \copy\bakk\ignorespaces\fi}
+\def\7{\Y\6} % forced break and a little extra space
+\def\8{\hskip-\ind\indentunit\hskip 2\indentunit} % cancel full indentation
+
+\let\yskip=\smallskip % amount of space between subsections, and at `@)'
+\newskip\intersecskip \intersecskip=12pt minus 3pt % space between sections
+\newif\ifcodemode \codemodefalse % whether we are in \Cee part of section
+\newif\ifon % whether a section will produce any printed output
+\let\maybe=\iftrue % \if-like macro; governs printing of unchanged sections
+\def\changesonly{\let\maybe=\iffalse} % the user might set this in limbo
+\def\onmaybe{\let\ifon=\maybe} % this is executed for each unchanged section
+
+\def\Penalty#1{\relax\ifcodemode\3#1\fi} % optional break if in code mode
+
+% Summary of use of \Penalty
+%\def*{\Penalty9\ast}
+%\def+{\Penalty8\plus} \gdef-{\Penalty8\minus}
+%\def\I{\Penalty7\neq} % inequality test
+%\def\S{\Penalty7=} % equality test
+%\def\OR{\Penalty6\mid} % bitwise OR
+%\def\W{\Penalty5\land} % logical AND
+%\def\V{\Penalty4\lor} % logical OR
+%\def\?{\Penalty3\mathrel?} % `?' operator
+%\def:{\Penalty3\mcolon} % colon in math mode matches `?' operator
+%\def\K{\Leftarrow\Penalty2} % assignment operator,
+% comma operator gets \Penalty1 by CWEAVE
+
+\def\note#1#2.% for cross-referencing notes, as at the end of a section
+{\Y\noindent{\hangindent2\indentunit\baselineskip10pt\eightrm#1~#2.\par}}
+\def\defin#1{\global\advance\ind by 2
+ \1\&{#1}\quad} % begin `#define' or `format' of `#include'
+\def\lapstar{\rlap{*}}
+\def\stsec % start up setion
+ {\endcodemode\noindent{\let\*=\lapstar\bf\secstar.\quad}}
+\let\startsection=\stsec % this one is used; provides hook for extra actions
+\newcount\gdepth % depth of last starred section
+\newcount\secpagedepth \secpagedepth=2 % depth where no page break is forced
+\newtoks\gtitle % title of last starred section
+
+\def\A{\note{See also section}} % xref for doubly defined module name
+\def\As{\note{See also sections}} % xref for multiply defined module name
+\def\ATL{\par\noindent\bgroup\catcode`\_=12 \postATL} % print @l in limbo
+\def\postATL#1 #2 {\bf letter \\{\uppercase{\char"#1}}
+ tangles as \tentex "#2"\egroup\par}
+\def\noATL#1 #2 {}
+\def\noatl{\let\ATL=\noATL} % suppress output from @l
+\def\ATP{\X\kern-.5em:Preprocessor directives\X}
+\def\B{\leavevmode % go into C mode
+ \ifcodemode\else
+ \begingroup\codemodetrue
+ \rightskip=0pt plus 300pt
+ \pretolerance 10000
+ \hyphenpenalty 9999 % so strings can be broken (with string break inserted)
+ \exhyphenpenalty 10000
+ \binoppenalty 10000
+ \relpenalty 10000
+ \mathcode`(="8000 \mathcode`)="8000 \mathcode`[="8000 \mathcode`]="8000
+ \mathcode`+="8000 \mathcode`-="8000 \mathcode`*="8000 \mathcode`:="8000
+ \let\{=\cweblbrace \let\}=\cwebrbrace
+ \let\.=\Cstring \let\\=\Cident \let\&=\Cbold
+ \fi
+ \global\ind=2
+ \global\pl=0
+ \1}
+\def\endcodemode
+ {\ifcodemode
+ \endgroup % get out of C mode
+ \global\hangindent=0pt % counteract \global\hangindent in \1
+ \fi
+ }
+\def\C#1% ordinary C comment; try to allow a break if little room is left
+ {\hfil\penalty0\hfilneg\kern4\indentunit\copy\bakk$/\ast\,$#1$\,\ast/$}
+\def\SHC#1% C++ one-line comment; force onto the current line
+ {\nobreak\kern2\indentunit\hbox{$/\!/\,$#1\unskip}}%
+\def\D{\8\defin{\#define}} % macro definition
+\def\E{\Penalty7=} % equality test
+\let\EQ=\equiv % after defining module name
+\def\PE{\mathrel\plus\EQ} % further defining section of a module
+\def\ET{ and~} % conjunction between two section numbers
+\def\ETs{, and~} % conjunction between the last two of several section numbers
+\def\F{\defin{format}} % format definition
+\let\G=\ge % greater than or equal sign
+% \H is long Hungarian umlaut accent
+\def\h{\8\defin{\#include}} % header file inclusion
+\def\I{\Penalty7\neq} % inequality test
+\def\J{\.{@\&}} % TANGLE's join operation
+\def\K{\Leftarrow\Penalty2} % assignment operator,
+ % can be changed to `=' (if \E is redefined) or `\leftarrow', if desired
+\def\KK#1{\mathrel{#1}\K} % composite assignment operators
+ % braces are required for same reason as for \m
+\def\MRL#1{\mathrel{#1}} % for first such operator in compatibility mode
+% \L is Polish letter suppressed-L
+\outer\def\M#1. % start of `@ ' section
+ {\MN#1.\ifon
+ \vskip 0pt plus .5 \vsize \penalty-1000\vskip 0pt plus -.5 \vsize
+ \vskip\intersecskip\startsection
+ }
+\outer\def\n#1. % start of `@~' section
+ {\MN#1.\ifon\vskip\intersecskip\startsection
+ }
+\outer\def\N#1 #2. #3. %start of `@*' section
+ {\global\gdepth=#1\global\gtitle={#3}\MN#2.%
+ \ifon \ifnum\gdepth<\secpagedepth \vfil\eject
+ \else \vskip 0pt plus .5 \vsize \penalty-1000\vskip 0pt plus -.5 \vsize
+ \vskip\intersecskip
+ \fi
+ \fi
+ \message{*\secno}% progress report
+ \edef\next{\write\cont % to contents file
+ {\ZZ{#1}{#3}{\secno}{\noexpand\the\pageno}}}
+ \next
+ \ifon\startsection{\bf#3.\quad}%
+ }
+\def\MN#1.% common code for \M, \N, \n
+ {\par{\xdef\secstar{#1}\let\*=\empty\xdef\secno{#1}}%
+ \ifx\secno\secstar \onmaybe % print unchanged section if \maybe=\iftrue
+ \else\ontrue % changed sections are always printed
+ \fi \mark{{{\tensy x}\secno}{\the\gdepth}{\the\gtitle}}%
+ }% each \mark is {section reference}{depth}{title}
+% \O is Scandinavian letter O-with-slash
+% \P is paragraph sign
+\def\Q{\note{This code is cited in section}} % xref for citation of a module
+\def\Qs{\note{This code is cited in sections}} % xref for citations of a module
+\let\R=\lnot % logical not
+% \S is section sign
+\def\T#1{%
+ {\let\~=\oct \let\^=\hex \let\_=\timestentothepower \let\$=\withsuffix #1}}
+\def\oct{{}^\circ\kern-.2em\it\aftergroup\afteroct}
+\def\afteroct{\kern.2em }
+\def\hex{{}^{\scriptscriptstyle\#}\tt}
+\def\timestentothepower{\cdot 10^{\aftergroup}}
+\def\withsuffix{_{\rm\,\aftergroup}}
+\def\U{\note{This code is used in section}} % xref for use of a module
+\def\Us{\note{This code is used in sections}} % xref for uses of a module
+\def\V{\Penalty4\lor} % logical or
+\def\W{\Penalty5\land} % logical and
+\def\X#1:#2\X{\langle\,${#2\eightrm\enspace#1}$\,\rangle} % module name
+\def\Y{\par\yskip}
+\let\Z=\le % less than or equal sign
+\let\ZZ=\relax % now you can \send the control sequence \ZZ
+\def\?{\Penalty3\mathrel?} % `?' operator
+\def\vb#1{\leavevmode\hbox{\kern2pt\vrule\vtop{\vbox{\hrule
+ \hbox{\strut\kern2pt\.{#1}\kern2pt}}
+ \hrule}\vrule\kern2pt}} % verbatim string
+\let\*=*
+
+
+% output routines
+
+\newif\iftitle % if true suppresses first running head
+\def\lheader{\mainfont\the\pageno\eightrm\qquad\grouptitle\hfill\title\qquad
+ \mainfont\topsecno} % top line on left-hand pages
+\def\rheader{\mainfont\topsecno\eightrm\qquad\title\hfill\grouptitle
+ \qquad\mainfont\the\pageno} % top line on right-hand pages
+\def\grouptitle{\let\i=I\let\j=J\uppercase\expandafter{\expandafter
+ \takethree\topmark}}
+\def\topsecno{\expandafter\takeone\topmark}
+\def\takeone#1#2#3{#1}
+\def\taketwo#1#2#3{#2}
+\def\takethree#1#2#3{#3}
+\def\nullsec{{\eightrm\kern-2em }} % the \kern-2em cancels \qquad in headers
+
+\let\page=\pagebody \normalbottom
+% \def\page{\box255 }% faster, but loses plain TeX footnotes
+\def\normaloutput#1#2#3% #1=page, #2=running head if even, #3 idem if odd
+{\ifodd\pageno\hoffset=\pageshift\fi
+ \shipout\vbox
+ {\vbox to\fullpageheight
+ {\iftitle\global\titlefalse % no running head, but reset for next pages
+ \else\hbox to\pagewidth{\vbox to10pt{}\ifodd\pageno #3\else#2\fi}%
+ \fi
+ \vfill#1% parameter #1 is the page itself
+ }}
+ \global\advance\pageno by1
+}
+
+\def\title{\uppercase\expandafter{\jobname}} % default title
+\def\topofcontents{\centerline{\titlefont\title}\vskip.7in
+ \vfill} % this material will start the table of contents page
+\def\botofcontents{\vfill\vfill
+ \centerline{\covernote}} % this material will end the table of contents page
+\def\covernote{}
+\def\contentspagenumber{0} % default page number for table of contents
+
+\newdimen\pagewidth \pagewidth=6.5in % the width of each page
+\newdimen\pageheight \pageheight=8.7in % the height of each page
+\newdimen\fullpageheight \fullpageheight=9in % page height including headlines
+\newdimen\pageshift \pageshift=0pt % shift righthand pages wrt lefthand ones
+\def\magnify#1{\mag=#1\pagewidth=6.5truein\pageheight=8.7truein
+ \fullpageheight=9truein\setpage}
+\def\setpage{\hsize=\pagewidth \vsize=\pageheight} % use after changing page size
+\def\contentsfile{\jobname.toc } % file that gets table of contents info
+\def\readcontents{\input\contentsfile}
+
+\newwrite\cont
+\output= % temporary for first page, which is emtpy so as to define \topmark
+{\setbox0=\box255 % throw away empty page
+ \openout\cont=\contentsfile % gets written when first real page is shipped
+ \write\cont{\catcode `\noexpand\@=11 } % first line makes `@' letter
+ \global\output={\normaloutput\page\lheader\rheader}% the real \output
+}
+\setpage
+\vbox to 2\vsize{} % dummy page, but the first \topmark won't be null
+\gtitle={\.{CWEB} output} % this running head is reset by starred sections
+\mark{\noexpand\nullsec0{\the\gtitle}}
+% page must be oversized so even a very early \inx won't get the chance
+% to reassign \output before this page is sent off.
+
+\newbox\sbox % one-page buffer for delayed output of page before index
+\newif\ifpagesaved % whether buffer has been filled
+\def\bufferedoutput
+{{\ifpagesaved\normaloutput{\box\sbox}\lheader\rheader\fi % empty buffer
+ \global\setbox\sbox=\page \global\pagesavedtrue % fill buffer
+}}
+
+\def\ch#1.%
+{{\let\*=\relax
+ \note{The following sections were changed by the change file:}{#1}.%
+}}
+
+\newbox\lbox % lefthand column in the index
+\def\inx
+ {\par\vskip6pt plus 1fil \endcodemode % we are beginning the index
+ \def\page{\box255 } \normalbottom
+ \write\cont{\catcode `\noexpand\@=12\relax} % make `@' other char
+ \closeout\cont % the contents information has been fully gathered
+ \output=\bufferedoutput\pagesavedfalse\eject % eject pages, keeping last
+ \setbox\sbox=\vbox{\unvbox\sbox} % allow its glue to reset
+ \vsize=\pageheight \advance\vsize by -\ht\sbox % the remaining height
+ \hsize=.5\pagewidth \advance\hsize by -10pt
+ % column width for the index (20pt between cols)
+ \parfillskip 0pt plus .6\hsize % try to avoid almost empty lines
+ \def\lr{L} % this tells whether the left or right column is next
+ \output=
+ {\if L\lr\global\setbox\lbox=\page \gdef\lr{R}
+ \else
+ \normaloutput
+ {\vbox to\pageheight
+ {\box\sbox \vss \hbox to\pagewidth{\box\lbox \hfil \page}}%
+ }% page argument to \normaloutput
+ \lheader\rheader % other two arguments to \normaloutput
+ \global\vsize\pageheight \gdef\lr{L} \global\pagesavedfalse
+ \fi
+ }%
+ \message{Index:}
+ \parskip 0pt plus .5pt
+ \let\@=\inxentry
+ \def\[##1]{$\underline{##1}$} % underlined index item
+ \rm \rightskip0pt plus 2.5em \tolerance 10000 \let\*=\lapstar
+ \hyphenpenalty 10000 \parindent0pt
+ }
+
+\outer\def\inxentry#1#2, % index entry; #1 is `h' or `m' for horiz/math mode
+ {\par\hangindent2em\noindent\if#1m$#2$\else#2\fi:\kern1em}
+
+\def\fin
+ {\par\vfill\eject % this is done when we are ending the index
+ \ifpagesaved\null\vfill\eject\fi % needed in case index is empty
+ \if R\lr \null\vfill\eject\fi % finish the current page
+ \parfillskip 0pt plus 1fil % restore normal paragraph end
+ \setpage % restore page shape
+ \output={\normaloutput\page\lheader\rheader}% restore output routine
+ \message{Module names:}
+ \def\grouptitle{NAMES OF THE MODULES}
+ \let\topsecno=\nullsec
+ \let\note=\finnote
+ \def\Q{\note{Cited in section}}% crossref for mention of a section
+ \def\Qs{\note{Cited in sections}}% crossref for mentions of a section
+ \def\U{\note{Used in section}}% crossref for use of a module
+ \def\Us{\note{Used in sections}}% crossref for uses of a module
+ \def\@{\par\hangindent 2em}\let\*=*
+ }
+
+\def\finnote#1#2.{\quad{\eightrm#1~#2.}}
+
+\def\con
+ {\par\vfill\eject % finish the module names
+ \rightskip 0pt \hyphenpenalty 50 \tolerance 200
+ \setpage
+ \output={\normaloutput\page\lheader\rheader}
+ \titletrue % prepare to output the table of contents
+ \pageno=\contentspagenumber
+ \def\grouptitle{TABLE OF CONTENTS}
+ \message{Table of contents:}
+ \topofcontents
+ \line{\hfil Section\hbox to3em{\hss Page}}
+ \let\ZZ=\contentsline
+ \readcontents % read the contents info
+ \botofcontents \eject\end % print the contents page(s) and terminate
+ }
+\def\contentsline#1#2#3#4% #1=depth, #2=title, #3=secno, #4=pageno
+ {\line{\ignorespaces#2 \leaders\hbox to .5em{.\hfil}\hfil
+ \ #3\hbox to3em{\hss#4}%
+ }%
+ }
+\def\coneven % force even number of pages before contents
+{\par\vfill\eject\ifodd\pageno\else\shipout\hbox{}\advancepageno\fi\con}
+\def\noinx{\def\inx{\endcodemode\end}} % no indexes or table of contents
+\def\nomods{\let\FIN=\fin \def\fin{\let\parfillskip=\end \FIN}}
+ % no index of module names or table of contents
+\def\nocon{\let\con=\end} % no table of contents
+\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}
+\newcount\twodigits
+\def\hours{\twodigits=\time \divide\twodigits by 60 \printtwodigits
+ \multiply\twodigits by-60 \advance\twodigits by\time \printtwodigits}
+\def\gobbleone1{}
+\def\printtwodigits{\advance\twodigits100
+ \expandafter\gobbleone\number\twodigits
+ \advance\twodigits-100 }
+\def\now{{\eightrm\today\ at \hours}}
+\def\datethis % say `\datethis' in limbo, to get your listing timestamped
+ {\def\startsection{\leftline\now\bigskip\let\startsection=\stsec\stsec}}
+\def\datecontentspage % timestamps the contents page
+ {\def\topofcontents
+ {\leftline\now\bigskip\centerline{\titlefont\title}\vfill}%
+ }
+
+\def\indentation#1{\indentunit#1\relax
+ \parindent\indentunit
+ \setbox\bak\hbox to-\indentunit{}% backspace one unit
+ \setbox\bakk\hbox to-2\indentunit{}% backspace two units
+}
diff --git a/web/c_cpp/cwebx/examples/Makefile b/web/c_cpp/cwebx/examples/Makefile
new file mode 100644
index 0000000000..7fcdba0d84
--- /dev/null
+++ b/web/c_cpp/cwebx/examples/Makefile
@@ -0,0 +1,45 @@
+CFLAGS =
+CWEAVE = cweave +d
+CTANGLE = ctangle
+.SUFFIXES: .tex .dvi .w
+
+.w.tex:
+ $(CWEAVE) $*
+
+.tex.dvi:
+ tex $*
+
+
+.w.dvi:
+ $(CWEAVE) $*
+ tex $*
+
+.w.c:
+ $(CTANGLE) $*
+
+.w.o:
+ $(CTANGLE) $*
+ $(CC) $(CFLAGS) -c $*.c
+
+.w.dvi:
+ make $*.tex
+ make $*.dvi
+
+.w.o:
+ make $*.c
+ make $*.o
+
+treeprint: treeprint.w
+ make treeprint.c
+ make treeprint
+
+wc: wc.w
+ make wc.c
+ make wc
+
+wmerge: wmerge.w
+ make wmerge.o
+ $(CC) $(CFLAGS) -o wmerge wmerge.o ../common.o
+
+
+
diff --git a/web/c_cpp/cwebx/examples/compare.w b/web/c_cpp/cwebx/examples/compare.w
new file mode 100644
index 0000000000..7a52d9b000
--- /dev/null
+++ b/web/c_cpp/cwebx/examples/compare.w
@@ -0,0 +1,108 @@
+@* Comparing text files.
+This is an entirely trivial program, that tests whether two text files are
+equal, and if not so, points out the first point of difference.
+
+@h <stdio.h>
+@h <stdlib.h>
+@c typedef char bool;
+
+@ The outline of the program is simple. We read characters from both input
+files into |c1| and~|c2| until the comparison is complete. Line and column
+counts are maintained in |line| and~|col|.
+
+@d left_margin 1 /* leftmost column number; change to 0 if you prefer */
+@c
+@<Functions@>@;
+int main(int n, char** arg)
+{ FILE *f1,*f2; /* the two input files */
+ int c1,c2,col=left_margin; long line=1;
+ @< Open the files |f1| and~|f2|,
+ taking their names from the command line or from the terminal;
+ in case of an error for which no recovery is possible,
+ call |exit(1)| @>
+ @< Search for first difference,
+ leaving |c1!=c2| if and only if a difference was found @>
+ @< Report the outcome of the comparison @>
+ return 0; /* successful completion */
+}
+
+@ The heart of the program is this simple loop. When we reach the end of
+one of the files, the files match if and only if the other file has also
+reached its end. For this reason the test |c1==c2|, which requires
+characters to be read from both files, must precede the test for file end;
+when only one file ends, it is the former test which breaks the loop.
+
+@< Search for first difference... @>=
+while ((c1=getc(f1))==(c2=getc(f2)) && c1!=EOF)
+ if (c1=='\n') {@; ++line; col=left_margin; } @+ else ++col;
+
+@ When the first difference occurs at the end of one of the files, or at the
+end of a line, we give a message indicating this fact.
+
+@< Report... @>=
+if (c1==c2) printf("Files match.\n");
+else
+{ printf("Files differ.\n");
+ if (c1==EOF || c2==EOF)
+ @/{@;
+ the_file(c1==EOF);
+ printf("is contained in the other as initial segment.\n");
+ }
+ else if (c1=='\n' || c2=='\n')
+ @/{@;
+ the_file(c1=='\n');
+ printf("has a shorter line number %ld than the other.\n",line);
+ }
+ else printf("First difference at line %ld, column %d.\n",line,col);
+}
+
+@ The function |the_file| starts a sentence about the first or second file,
+depending on its boolean argument.
+
+@<Functions@>=
+void the_file(bool is_first)
+@+{@; printf("The %s file ", is_first ? "first" : "second" ); }
+
+@ There can be be zero, one or two command line arguments. If there are none,
+the user is prompted to supply them, and if there are two these are taken as
+the file names, prompting the user only in case a file could not be opened.
+In case just one argument is present, the first file is assumed to be the
+standard input, which does not have to be opened; in this case however we
+will not read a file name from terminal in case the second file cannot be
+opened.
+
+@d read_mode "r"
+@< Open... @>=
+--n; ++arg; /* ignore ``argument'' 0, which is the program name */
+if (n==0)
+@/{@;
+ open_file(&f1,"First file to compare", NULL);
+ open_file(&f2,"Second file to compare", NULL);
+}
+else if (n==1)
+{ f1=stdin;
+ if ((f2=fopen(*arg,read_mode))==NULL)
+ {@; printf("Could not open file %s.\n",*arg); exit(1); }
+}
+else if (n==2)
+{ open_file(&f1,"Give another first file", *arg++);
+ open_file(&f2,"Give another second file", *arg);
+}
+else
+{@; printf("No more than two command line arguments are allowed.\n");
+ exit(1);
+}
+
+@ The function |open_file| will try to open the file |name| for reading, and
+if this fails it will prompt for another file name until it has success. If
+called with |name==NULL|, the function starts with prompting right away.
+
+@<Functions@>=
+void open_file(FILE** f,char* prompt,char* name)
+{ char buf[80];
+ if (name==NULL || (*f=fopen(name,read_mode))==NULL)
+ do {@; printf("%s: ",prompt); fflush(stdout); scanf("%79s",buf); }@/
+ while ((*f=fopen(buf,read_mode))==NULL);
+}
+
+@* Index.
diff --git a/web/c_cpp/cwebx/examples/treeprint.w b/web/c_cpp/cwebx/examples/treeprint.w
new file mode 100644
index 0000000000..ae9dc239d1
--- /dev/null
+++ b/web/c_cpp/cwebx/examples/treeprint.w
@@ -0,0 +1,229 @@
+% Copyright 1987 Norman Ramsey -- Rutgers University
+% Adapted to CWEB version 3.0 by Marc van Leeuwen -- CWI Amsterdam
+
+@*Directory Trees.
+The object is to print out a directory hierarchy in some pleasant way.
+The program takes output from \.{find * -type d -print {\v} sort}
+@^system dependencies@>
+and produces a nicer-looking listing.
+For those of you who may not have \.{find} or \.{sort}, the output is a
+list of fully
+qualified directory names (parent and child separated by slashes |'/'|),
+and everything is already nicely sorted in lexicographic order.
+
+|treeprint| takes one option, |"-p"|, which tells it to use the printer's
+line-drawing set, rather than the terminal's.
+@h <stdio.h>
+
+@c
+@< Global declarations @>@;
+
+main(int argc, char** argv)
+{
+@< Variable declaration for |main| @> @;
+@< Search for options and set special characters on |"-p"| @>
+@< Read output from find and enter into tree @>
+@< Write tree on standard output @>
+exit(0);
+}
+
+@
+We make all the siblings of a directory a linked list off of its left child,
+and the offspring a linked list off the right side.
+Data are just directory names.
+@d sibling left
+@d child right
+
+@< Global decl... @>=
+typedef struct tnode {
+ struct tnode *left, *right;
+ char *data;
+} TNODE;
+@ @< Variable declaration for |main| @>=
+struct tnode *root;
+
+
+
+@*Input.
+Reading the tree is simple---we read one line at a time, and call on the
+recursive |add_tree| procedure.
+@c
+read_tree (FILE* fp,struct tnode** rootptr)
+{
+ char buf[255], *p;
+
+ while ((fgets(buf, 255, fp))!=NULL) {
+ @< If |buf| contains a newline, make it end there @>
+ add_tree(rootptr, buf);
+ }
+ }
+
+@ Depending what system you're on, you may or may not get a newline in |buf|.
+@< If |buf| contains a newline... @>=
+ p=buf; while (*p!='\0'&&*p!='\n') p++;
+@^system dependencies@>
+ *p='\0';
+
+@
+To add a string, we split off the first part of the name and insert it into
+the sibling list. We then do the rest of the string as a child of the new node.
+@c
+add_tree(struct tnode** rootptr, char* p)
+{
+ char *s;
+ int slashed;
+
+ if (*p=='\0') return;
+
+@< Break up the string so |p| is the first word,
+ |s| points at null-begun remainder,
+ and |slashed| tells whether |*s=='/'| on entry @>
+
+ if (*rootptr==NULL) {
+@< Allocate new node to hold string of size |strlen(p)| @>
+ strcpy((*rootptr)->data,p);
+ }
+ if (strcmp((*rootptr)->data,p)==0) {
+ if (slashed) ++s;
+ add_tree(&((*rootptr)->child),s);
+ }
+ else {
+ if (slashed) *s='/';
+ add_tree(&((*rootptr)->sibling),p);
+ }
+ }
+
+@ We perform some nonsense to cut off the string |p| so that |p| just holds
+the first word of a multiword name. |s| points at what was either the end
+of |p| or a slash delimiting names. In either case |*s| is made |'\0'|.
+Later depending on wether we want to pass the whole string or the last piece,
+we will restore the slash or advance |s| one character to the right.
+
+@< Break up... @>=
+ for (s=p;*s!='\0'&&*s!='/';) s++;
+ if (*s=='/') slashed=1, *s='\0';
+ else slashed=0;
+
+@ Node allocation is perfectly standard\dots
+@< Allocate new node... @>=
+ *rootptr=(struct tnode *) malloc (sizeof(struct tnode));
+ (*rootptr)->left = (*rootptr)->right = NULL;
+ (*rootptr)->data = malloc (strlen(p)+1);
+
+@
+@< Global decl... @>= char *malloc();
+
+@ In this simple implementation, we just read from standard input.
+@< Read... @>= read_tree(stdin,&root);
+
+@*Output.
+We begin by defining some lines, tees, and corners.
+The |s| stands for screen and the |p| for printer.
+You will have to change this for your line-drawing set.
+@^system dependencies@>
+
+@d svert '|'
+@d shoriz '-'
+@d scross '+'
+@d scorner '\\' /* lower left corner */
+
+@d pvert '|'
+@d phoriz '-'
+@d pcross '+'
+@d pcorner '\\' /* lower left corner */
+
+@ The default is to use the terminal's line drawing set.
+@< Global declarations @>=
+char vert=svert;
+char horiz=shoriz;
+char cross=scross;
+char corner=scorner;
+
+@ With option |"-p"| use the printer character set.
+@< Search for options... @>=
+while (--argc>0) {
+ if (**++argv=='-') {
+ switch (*++(*argv)) {
+ case 'p':
+ vert=pvert;
+ horiz=phoriz;
+ cross=pcross;
+ corner=pcorner;
+ break;
+ default:
+ fprintf(stderr,"treeprint: bad option -%c\n",**argv);
+ break;
+ }
+ }
+}
+
+@ We play games with a character stack to figure out when to put in vertical
+bars.
+A vertical bar connects every sibling with its successor, but the last sibling
+in a list is followed by blanks, not by vertical bars. The state of
+bar-ness or space-ness for each preceding sibling is recorded in the
+|indent_string| variable, one character (bar or blank) per sibling.
+
+@< Global decl... @>=
+char indent_string[100]="";
+
+@ Children get printed
+before siblings.
+We don't bother trying to bring children up to the same line as their parents,
+because the \caps{UNIX} filenames are so long.
+
+We define a predicate telling us when a sibling is the last in a series.
+@d is_last(S) (S->sibling==NULL)
+
+@c
+print_node(FILE* fp, char* indent_string, struct tnode* node)
+{
+ char string[255];
+ int i;
+ char *p, *is;
+
+ if (node==NULL) {
+ }
+ else {
+ *string='\0';
+ for (i=strlen(indent_string); i>0; i--)
+ strcat(string,@, " | ");
+ strcat(string,@t\ \ @> " +--");
+@< Replace chars in |string| with chars from
+ line-drawing set and from |indent_string| @>
+ fprintf(fp,"%s%s\n",string,node->data);
+
+@)
+ /* Add vertical bar or space for this sibling (claim |*is=='\0'|) */
+ *is++ = (is_last(node) ? ' ' : vert);
+ *is=='\0';
+
+ print_node(fp, indent_string, node->child); /* extended |indent_string| */
+ *--is='\0';
+ print_node(fp, indent_string, node->sibling); /* original |indent_string| */
+ }
+
+}
+@ For simplicity, we originally wrote connecting lines with |'|'|, |'+'|, and
+|'-'|.
+Now we replace those characters with appropriate characters from the
+line-drawing set.
+We take the early vertical bars and replace them with characters from
+|indent_string|, and we replace the other characters appropriately.
+We are sure to put a |corner|, not a |cross|, on the last sibling in
+a group.
+@< Replace chars... @>=
+ is=indent_string;
+ for (p=string; *p!='\0'; p++) switch(*p) {
+ case '|': *p=*is++; break;
+ case '+': *p=(is_last(node) ? corner : cross); break;
+ case '-': *p=horiz; break;
+ default: break;
+ }
+
+
+@ For this simple implementation, we just write on standard output.
+
+@< Write... @>= print_node(stdout, indent_string, root);
+
+@*Index.
diff --git a/web/c_cpp/cwebx/examples/wc.w b/web/c_cpp/cwebx/examples/wc.w
new file mode 100644
index 0000000000..ce741c5f3c
--- /dev/null
+++ b/web/c_cpp/cwebx/examples/wc.w
@@ -0,0 +1,226 @@
+% wc: An example of CWEB by Silvio Levy and Donald E. Knuth
+% Adapted to CWEB version 3.0 by Marc van Leeuwen -- CWI Amsterdam
+
+\nocon % omit table of contents
+\datethis % print date on listing
+
+@* An example of \.{CWEB}. This example presents the ``word count''
+program from \caps{UNIX}, rewritten in \.{CWEB} to demonstrate
+literate programming in \Cee. The level of detail is intentionally
+high, for didactic purposes; many of the things spelled out here don't
+need to be explained in other programs.
+
+The purpose of \.{wc} is to count lines, words, and/or characters in a list
+of files. The number of lines is the number of newline characters in the
+file. The number of characters is the file length in bytes. A ``word'' is a
+maximal sequence of consecutive characters other than white space,
+containing at least one visible character.
+
+@ Most \.{CWEB} programs share a common structure. It's probably a good
+idea to have one module that states this structure explicitly, even though
+the elements could all be introduced in sections contributing to of the
+unnamed module if they don't need to appear in any special order.
+
+@c
+
+@< Global variables @>@;
+@< Functions @>@;
+@< The main program @>@;
+
+@ We must include the standard I/O definitions, since we want to send
+formatted output to |stdout| and |stderr|. We also use the character
+classification macro |isgraph| to detect visible characters.
+
+@h <stdio.h>
+@h <ctype.h>
+@ The |status| variable tells the operating system if the run was
+successful or not, and |prog_name| is used in case there's an error message to
+be printed.
+
+@d OK 0 /* |status| code for successful run */
+@d usage_error 1 /* |status| code for improper syntax */
+@d cannot_open_file 2 /* |status| code for file access error */
+
+@< Global variables @>=
+int status=OK; /* exit status of command, initially |OK| */
+char *prog_name; /* who we are */
+
+@ Now we come to the general layout of the |main| function.
+
+@< The main... @>=
+main (int argc,char** argv)
+{
+ @< Variables local to |main| @>@;
+ prog_name=*argv++; --argc; /* process program name */
+ @< Set up option selection @>
+ @< Process all the files @>
+ @< Print the grand totals if there were multiple files @>
+ exit(status);
+}
+
+@ If the first argument begins with a `\.-' the user is choosing
+the desired counts and specifying the order in which they should be
+displayed. Each selection is given by the initial character
+(lines, words, or characters). For example, `\.{-cl}' would cause
+just the number of characters and the number of lines to be printed.
+
+We do not process this string now. It will be used to control the
+formatting at output time.
+
+@< Var... @>=
+int file_count; /* how many files there are */
+char *which; /* which counts to print */
+
+@ @< Set up o... @>=
+which="lwc"; /* if no option is given, print all three values */
+if (argc>0 && (*argv)[0] == '-') {@; which=&(*argv++)[1]; --argc; }
+file_count=argc;
+
+@ Now we scan the remaining arguments and try to open a file, if
+possible. The file is processed and its statistics are given.
+We use a |do|~\dots~|while| loop because we should read from the
+standard input if no file name is given.
+
+@< Process... @>=
+do {
+ @< If a file is given try to open |*argv|; |continue| if unsuccesful @>
+ @< Initialize pointers and counters @>
+ @< Scan file @>
+ @< Write statistics for file @>
+ @< Close file @>
+ @< Update grand totals @> /* even if there is only one file */
+} while (++argv,--argc>0);
+
+@ Here's the code to open the file. We use the low-level functions |open|,
+|read|, and |close| that operate work file descriptors rather than with
+|FILE|s. A special trick allows us to handle input from |stdin| when no name
+is given. Recall that the file descriptor to |stdin| is 0; that's what we
+initialize our file descriptor to.
+
+@< Variabl... @>=
+int fd=0; /* file descriptor, initialized to |stdin| */
+
+@~@d READ_ONLY 0 /* read access code for system |open| routine */
+
+@< If a fi... @>=
+if (file_count>0 && (fd=open(*argv,READ_ONLY))<0) {
+ fprintf (stderr, "%s: cannot open file %s\n", prog_name, *argv);
+@.cannot open file@>
+ status|=cannot_open_file;
+ --file_count;
+ continue;
+}
+
+@ @< Close file @>=
+close(fd);
+
+@ We will do some homemade buffering in order to speed things up: Characters
+will be read into the |buffer| array before we process them.
+To do this we set up appropriate pointers and counters.
+
+@d buf_size BUFSIZ /* \.{stdio.h}'s |BUFSIZ| is chosen for efficiency*/
+
+@< Var... @>=
+char buffer[buf_size]; /* we read the input into this array */
+register char *ptr; /* the first unprocessed character in |buffer| */
+register char *buf_end; /* the first unused position in |buffer| */
+register int c; /* current character, or number of characters just read */
+int in_word; /* are we within a word? */
+long word_count, line_count, char_count; /* number of words, lines,
+ and characters found in the file so far */
+
+@ @< Init... @>=
+ptr=buf_end=buffer; line_count=word_count=char_count=0; in_word=0;
+
+@ The grand totals must be initialized to zero at the beginning of the
+program. If we made these variables local to |main|, we would have to
+do this initialization explicitly; however, \Cee's globals are automatically
+zeroed. (Or rather, ``statically zeroed.'') (Get it?)
+@^Joke@>
+
+@< Global var... @>=
+long tot_word_count, tot_line_count, tot_char_count; /* total number of words, lines and chars */
+
+@ The present module, which does the counting that is \.{wc}'s {\it raison
+d'\^etre}, was actually one of the simplest to write. We look at each
+character and change state if it begins or ends a word.
+
+@< Scan... @>=
+while (1) {
+ @< Fill |buffer| if it is empty; |break| at end of file @>
+ c=*ptr++;
+ if (isgraph(c)) /* visible character */
+ {@; if (!in_word) ++word_count, in_word=1; }
+ else if (isspace(c))
+ { in_word=0; /* |c| white space */
+ if (c=='\n') ++line_count;
+ }
+}
+
+@ Buffered I/O allows us to count the number of characters almost for free.
+
+@< Fill |buff... @>=
+if (ptr>=buf_end) {
+ ptr=buffer; c=read(fd,ptr,buf_size);
+ if (c<=0) break;
+ char_count+=c; buf_end=buffer+c;
+}
+
+@ It's convenient to output the statistics by defining a new function
+|wc_print|; then the same function can be used for the totals.
+Additionally we must decide here if we know the name of the file
+we have processed or if it was just |stdin|.
+
+@< Write... @>=
+wc_print(which, char_count, word_count, line_count);
+if (file_count) printf (" %s\n", *argv); /* not |stdin| */
+else printf ("\n"); /* |stdin| */
+
+@ @< Upda... @>=
+tot_line_count+=line_count;
+tot_word_count+=word_count;
+tot_char_count+=char_count;
+
+@ We might as well improve a bit on \caps{UNIX}'s \.{wc} by counting the
+files too.
+
+@< Print the... @>=
+if (file_count>1) {
+ wc_print(which, tot_char_count, tot_word_count, tot_line_count);
+ printf(" total in %d files\n",file_count);
+}
+
+@ Here now is the function that prints the values according to the
+specified options. The calling routine is supposed to supply a
+newline. If an invalid option character is found we inform
+the user about proper usage of the command. Counts are printed in
+10-digit fields so that they will line up in columns.
+
+@d print_count(n) printf("%10ld",n)
+
+@< Fun... @>=
+wc_print(char* which, long char_count, long word_count, long line_count)
+{
+ while (*which)
+ switch (*which++) {
+ case 'l': print_count(line_count); break;
+ case 'w': print_count(word_count); break;
+ case 'c': print_count(char_count); break;
+ default: if ((status & usage_error)==0) {
+ fprintf (stderr, "\nUsage: %s [-lwc] [filename ...]\n", prog_name);
+@.Usage: ...@>
+ status|=usage_error;
+ }
+ }
+}
+
+@ Incidentally, a test of this program against the system \.{wc} command
+on a SPARCstation showed that the ``official'' \.{wc} was slower. Furthermore,
+although that \.{wc} gave an appropriate error message for the options
+`\.{-abc}', it made no complaints about the options `\.{-labc}'!
+Perhaps the system routine would have been better if its programmer had
+been more literate?
+
+@* Index.
+Here is a list of the identifiers used, and where they appear. Underlined
+entries indicate the place of definition. Error messages are also shown.
diff --git a/web/c_cpp/cwebx/examples/wmerge.w b/web/c_cpp/cwebx/examples/wmerge.w
new file mode 100644
index 0000000000..4596e97d54
--- /dev/null
+++ b/web/c_cpp/cwebx/examples/wmerge.w
@@ -0,0 +1,52 @@
+% Adapted to CWEB version 3.0 by Marc van Leeuwen -- CWI Amsterdam
+\noinx
+
+@* Introduction. This file contains the program |wmerge|, which takes two
+or more files and merges them according to the conventions of \.{CWEB}. We
+use the routines of \.{CWEB} itself. The function |common_init| takes care of
+processing command line arguments. Since the result of the merge will be
+produced on the standard output, we prevent distraction as much as possible
+by clearing flags |'h'| and |'p'| (for |'b'| it is not required since no
+banner is produced anyway.
+
+@h <stdio.h>
+@h "../common.h" /* the header file for \.{CWEB}'s \.{common.w} */
+@c
+@< Prototype @>@;
+main (int argc,char** argv)
+{ common_init(argc,argv);
+ flags['h']=flags['p']=0;
+ reset_input();
+ while (get_line())
+ put_line();
+ wrap_up();
+}
+
+@ This file should be linked together with the object file produced from
+|"common.w"|, which is also used in both |CTANGLE| and |CWEAVE|.
+That file defines the functions |common_init|, |reset_input|, |get_line|, and
+|wrap_up|. There are however a number of functions that are required by that
+compilation unit although they are not actually used; we define them with
+trivial function bodies. Since the linker doesn't check types anyway we
+don't specify any here either.
+
+@c
+void print_stats() @+ {}
+void names_match () @+ {}
+void init_module_name() @+ {}
+void init_id_name () @+ {}
+
+
+@ All that remains is to define |put_line| which is trivial. The external
+variable |buffer| holds the characters read by |get_line|, up to |limit|,
+and |loc| points to the next character to be read, i.e., after calling
+|get_line| it points to |buffer[0]|.
+
+@< Prototype @>= void put_line(void);
+@~@c
+
+void put_line(void)
+{
+ while (loc<limit) putchar(*loc++);
+ putchar('\n');
+}
diff --git a/web/c_cpp/cwebx/intro.inc b/web/c_cpp/cwebx/intro.inc
new file mode 100644
index 0000000000..49d0376e18
--- /dev/null
+++ b/web/c_cpp/cwebx/intro.inc
@@ -0,0 +1,88 @@
+\def\hang{\hangindent 3em\indent\ignorespaces}
+\def\pb{$\.|\ldots\.|$} % C brackets (|...|)
+\def\LKC.{Levy/Knuth \.{CWEB}}
+\def\:#1{`\.{@@#1}'}
+
+\def\title{\me. (Version x3.04)}
+\def\topofcontents
+{\topglue 0pt plus .5 fill
+ \centerline{\titlefont The {\ttitlefont \me.} program}
+ \vskip 15pt
+ \centerline{(\.{CWEB} version x3.04)}
+ \vfill
+}
+\def\botofcontents
+{\vfill\noindent
+ Copyright \copyright\ 1987,\thinspace1990 Silvio Levy and Donald E. Knuth
+ \par\noindent
+ Copyright 1994 Marc A. A. van Leeuwen
+ \bigskip\noindent
+ Permission is granted to make and distribute verbatim copies of this
+ document provided that the copyright notice and this permission notice
+ are preserved on all copies.
+
+ \smallskip\noindent
+ Permission is granted to copy and distribute modified versions of this
+ document 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.
+}
+
+
+@* Introduction. @:title@>
+This is the main source text for the program \.{\me.}, one of the two text
+processing tools that constitute the \.{CWEB} system. This version of the
+system, identified as \.{CWEB}x3.0, was written by Marc van Leeuwen. The
+history of this system is somewhat complicated, and starts with the
+\.{WEB} system created by D.~E. Knuth (for the programming language Pascal);
+the program corresponding to the current program in that system was
+called~\myroots. That program was converted into \.{\me.}, written in and
+for the \Cee~language, by Silvio Levy, and further developed under joint
+responsibility with Knuth. Based on \.{CWEB}~2.1 by Levy and Knuth, a
+version adapted to \caps{ANSI~C} was made by Frank Jensen. That version has
+served as the starting point for the current author; an intermediate version
+between it and the current version was made public under the name
+\.{CWEB}~3.x. Helpful comments and suggestions by Gareth McCaughan, Werner
+Lemberg, and Andreas Scherer were greatly appreciated.
+
+The name \.{CWEB}~3.x was an unfortunate choice, since the Levy/Knuth
+version of \.{CWEB} had also been independently developed further, and it is
+currently being distributed as \.{CWEB}~3.4f. Both these branches have
+retained the basic functionality of the version of \.{CWEB} they were both
+derived from, making only minor (but different) additions and changes.
+Realising that this divergence is undesirable and confusing, the development
+of this branch from \.{CWEB}~3.x to the current version was mainly concerned
+with improving compatibility and peaceful coexistence with the other branch.
+First of all the name was changed by moving the character~`x' to the front
+of the version number, so that this branch of the system can be referred to
+as `\.{CWEBx}' without mentioning a complete version number; for clarity we
+shall refer to the other branch as `\LKC.'. @^Levy/Knuth \.{CWEB}@>
+Secondly, all the extensions of \LKC. were included, although in a few cases
+in a slightly different form to avoid name conflicts with features already
+present in \.{CWEB}~3.x. Thirdly, in order to accomodate existing programs
+written for \LKC., among which are those of Knuth's impressive collection
+called the Stanford GraphBase, a ``compatibility mode'' was added,
+selectable by a command line option (\.{+c}), in which the remaining, mostly
+trivial, differences in syntax and semantics are removed, and the system
+attempts to be an alternative implementation for exactly the same language
+as accepted by \LKC., at the price of losing a few possibilities particular
+to~\.{CWEBx}.
+
+The major version number `3' now corresponds to the same version number of
+\LKC., and since no further extension of the possibilities of that system
+are anticipated, we do not expect that compatibility will ever require any
+further increase of this major version number. The Stanford GraphBase
+@^Stanford GraphBase@> states that it requires \.{CWEB} version 3.0 or
+greater; this version of \.{CWEBx} can fully process it in a satisfactory
+way, using compatibility mode.
+
+The ``banner line'' defined here should be changed whenever changes to
+\.{\me.} are made publicly available. Users who are discontent with some
+aspect of the program are encouraged to make the necessary modifications in
+their copy of the source files; if this involves an improvement of the
+implementation, they are kindly requested to inform the author responsible
+for the current version. If they choose to make the resulting program
+available under the name \.{\me.}, they should modify the non-numeric
+prefix of the version specification.
+
+@d version_string "3.04"
diff --git a/web/c_cpp/cwebx/man1/cweb.1 b/web/c_cpp/cwebx/man1/cweb.1
new file mode 100644
index 0000000000..5f67708b44
--- /dev/null
+++ b/web/c_cpp/cwebx/man1/cweb.1
@@ -0,0 +1,165 @@
+.TH WEB 1L 7/12/90
+.SH NAME
+ctangle, cweave \- translate CWEB to C (or C++) and/or TeX
+.SH SYNOPSIS
+.B ctangle
+[
+.B \-bhpl
+] [
+.B \+cs+
+] cwebfile[.w] [(changefile[.ch]|+|-) [outputfile[.c]]]
+.br
+.B cweave
+[
+.B \-bhpx
+] [
+.B \+cs+dtefauwm
+] [
+.B +isearchpath
+] cwebfile[.w] [(changefile[.ch]|+|-) [outputfile[.tex]]]
+
+.SH DESCRIPTION
+The
+.I ctangle
+program converts a CWEB
+source document into a C program that may be compiled in the usual way.
+The output file includes #line specifications so that error reporting and
+debugging can be done in terms of the CWEB source file.
+.PP
+The
+.I cweave
+program converts the same CWEB file into a TeX file that may be
+formatted and printed in the usual way.
+It takes appropriate care of typographic details like page layout
+and the use of indentation, italics, boldface, etc., and it supplies
+extensive cross-reference information that it gathers automatically.
+.PP
+CWEB allows you to prepare a single
+document containing all the information that is needed both to produce
+a compilable C program and to produce a well-formatted document
+describing the program in as much detail as the writer may desire. The
+user of CWEB ought to have some familiarity with TeX as well as knowledge
+of C.
+.PP
+The command line should have one, two, or three names on it. The first is
+taken as the CWEB file (and `.w' is added if there is no extension). If that
+file cannot be opened, the extension `.web' is tried instead. If there is a
+second name, it is a change file (and `.ch' is added if there is no
+extension), otherwise the name of the CWEB file with its extension replaced
+by `.ch' is tried as change file name; if there no such file, no change file
+is used. Instead of a change file one may specify `-' or `+'; `-' means do
+not use a change file, and `+' means use a change file only if a file of the
+default name exists (just as if only one name was given). The change file
+overrides parts of the CWEB file, as described in the documentation. A third
+name, if present, specifies the output file name explicitly. The default
+output file name is that of the CWEB file with extension `.c' (for
+.I ctangle
+) or `.tex' (for
+.I cweave
+); the default extension is also applied if a third
+name is given without extension.
+.PP
+Options in the command line may be either turned on with `+'
+and off with `-'; several characters may follow in the same argument, which
+indicate several options that are turned on respectively off simultaneously.
+In fact, the options are processed from left to right,
+so a sequence like `-b +b' is equivalent to `+b' (which is the default).
+.PP
+The
+.B \+b
+option shows a banner line on your terminal. The
+.B \+h
+option shows a happy message if the processing was successful. The
+.B \+p
+option shows progress reports (starred module numbers) as the processing
+takes place. If you say `-bhp', you get no terminal output but error messages.
+.PP
+The
+.B \+c
+option emulates Levy/Knuth CWEB.
+The
+.B \+s
+option prints statistics about memory usage at the end of a run
+(assuming that the programs have been compiled with the -DSTAT switch).
+By setting the option
+.B \++
+one can select the C++ language instead of C.
+.PP
+The option
+.B \-l
+is applicable to
+.I ctangle
+only; when selected, the C output is made more readable for humans by omitting
+.B #line
+directives and preserving layout and comments.
+.PP
+There are several other options applicable to
+.I cweave
+only. The option
+.B \-x
+means omit the index and table of contents. By setting the option
+.B \+d
+one causes
+.I cweave
+to report problems encountered in parsing the program fragments. With
+.B \+t
+the the index and module names will be written to separate files. With
+.B \+e
+the table of contents is forced to start on a new sheet when using a
+two-sided printer.
+The options
+.B \+f
+,
+.B \+a
+,
+.B \+u
+,
+.B \+w
+, and
+.B \+m
+change the style in which programs are
+formatted:
+.B \+f
+means force a newline after every simple statement in the formatted output,
+and
+.B \+a
+means also force a newline before every simple statement, even if it follows
+a label or a condition; the option
+.B \+u
+will change the style so that a line break goes after `{' instead of before,
+thus preventing them from aligning with their matching `}' (this is the
+style of Levy/Knuth CWEB), while the option
+.B \+w
+puts a line break both before and after `{', producing a more symmetric
+layout at the expense of some extra paper. Finally, the option
+.B \+m
+avoids forcing line breaks between successive declarations in a local block.
+With the option
+.B \+isearchpath
+one can specify a place to look for header files, when they are not found in
+the current directory. The string following the `+i' will be stored and
+preprended to a header file name if it cannot be found otherwise (so the
+string should probably end with a pathname separator '/'). More than one
+such search path can be specified; they will be tried in order from left to
+right.
+.PP
+.SH FILES
+/usr/local/lib/tex/macros/cwebxmac.tex TeX macros used by cweave output.
+.br
+/usr/local/lib/tex/macros/cwebcmac.tex TeX macros used in compatibility
+mode.
+.br
+/usr/local/doc/cweb/manual.tex The user manual.
+.SH "SEE ALSO"
+.I Literate Programming
+by D. E. Knuth. (CSLI, Stanford, 1992)
+.br
+tex(1), cc(1), web(1)
+.SH "AUTHORS"
+Don Knuth wrote WEB for TeX and Pascal. Silvio Levy designed and developed
+CWEB by adapting the WEB conventions to C and by recoding everything in CWEB.
+Frank Jensen adapted the programs to ANSI/ISO C, and Marc van Leeuwen made
+numerous changes for version x3.0, and wrote a new manual.
+.SH "BUGS"
+The syntactic support for C++ does not cover that language completely, so
+formatting of complex C++ code may be bad.
diff --git a/web/c_cpp/cwebx/manual.dvi b/web/c_cpp/cwebx/manual.dvi
new file mode 100644
index 0000000000..f8c4a007af
--- /dev/null
+++ b/web/c_cpp/cwebx/manual.dvi
Binary files differ
diff --git a/web/c_cpp/cwebx/manual.pdf b/web/c_cpp/cwebx/manual.pdf
new file mode 100644
index 0000000000..781e87873e
--- /dev/null
+++ b/web/c_cpp/cwebx/manual.pdf
Binary files differ
diff --git a/web/c_cpp/cwebx/manual.tex b/web/c_cpp/cwebx/manual.tex
new file mode 100644
index 0000000000..421542ad4c
--- /dev/null
+++ b/web/c_cpp/cwebx/manual.tex
@@ -0,0 +1,2558 @@
+\input cwebxmac
+
+\def\title{\CWEBx. MANUAL}\titletrue
+\parskip=0pt plus 2pt
+
+\font\boldit=cmbxti10
+\font\twelverm=cmr12
+\font\twelvett=cmtt12
+
+\def\lheader{\mainfont\the\pageno\eightrm\qquad\firstmark\hfill\title}
+\def\rheader{\eightrm\title\hfill\firstmark\qquad\mainfont\the\pageno}
+
+\countdef\secno=1
+\let\oldbeginsection=\beginsection
+{\let\oldbeginsection=\relax % temporarily remove outerness
+ \outer\gdef\beginsection #1 \par
+ {\global\advance\secno by 1
+ \oldbeginsection{\number\secno\space\space#1}\par
+ \edef\next{\write\cont{\Z{\number\secno}{#1}{\noexpand\the\pageno}}}\next
+ \uppercase{\mark{#1}}%
+}}
+
+
+\let\z\relax
+\def\subsection#1 \par
+{\smallskip\noindent{\boldit #1}\quad
+ {\def\.{\noexpand\noexpand\noexpand\.}%
+ \def\do##1{\def##1{\noexpand\noexpand\noexpand##1}}\dospecials
+ \edef\next{\write\cont{\z{#1}{\noexpand\the\pageno}}}\next
+}}
+
+\def\pb{\.{|...|}}
+\def\<#1>{\hbox{\rm\def\ { }$\langle\,$#1$\,\rangle$}}
+\def\sp.{structured programming}
+\def\lp.{literate programming}
+\def\Lp.{Literate programming}
+\def\LP.{Literate Programming}
+\def\WEB.{\caps{WEB}}
+\def\ASCII.{\caps{ASCII}}
+\def\CWEB.{\.{CWEB}}
+\def\CWEBx.{\.{CWEBx}}
+\def\LKC.{Levy/Knuth \CWEB.}
+\def\:#1{`\/\.{@#1}'}
+\def\atspace.{\:{ }}
+
+\outer\def\N#1 #2. #3. %start of `@*' section
+ {\MN#2.%
+ \ifon \vskip 0pt plus .5 \vsize \penalty-1000\vskip 0pt plus -.5 \vsize
+ \vskip\intersecskip
+ \startsection{\bf#3.\quad}%
+ }
+\def\MN#1.% common code for \M, \N, \n
+ {\par\xdef\secstar{#1}\ontrue}% no \mark, no starred sections
+\def\inx
+ {\par\vskip6pt plus 1fil \endcodemode % we are beginning the index
+ \output=\bufferedoutput\pagesavedfalse\eject % eject pages, keeping last
+ \setbox\sbox=\vbox{\unvbox\sbox} % allow its glue to reset
+ \vsize=\pageheight \advance\vsize by -\ht\sbox % the remaining height
+ \hsize=.5\pagewidth \advance\hsize by -10pt
+ % column width for the index (20pt between cols)
+ \parfillskip 0pt plus .6\hsize % try to avoid almost empty lines
+ \def\lr{L} % this tells whether the left or right column is next
+ \output=
+ {\if L\lr\global\setbox\lbox=\page \gdef\lr{R}
+ \else
+ \normaloutput
+ {\vbox to\pageheight
+ {\box\sbox \vss \hbox to\pagewidth{\box\lbox \hfil \page}}%
+ }% page argument to \normaloutput
+ \lheader\rheader % other two arguments to \normaloutput
+ \global\vsize\pageheight \gdef\lr{L} \global\pagesavedfalse
+ \fi
+ }%
+ \parskip 0pt plus .5pt
+ \outer\def\@##1##2, % index entry; ##1 is `h' or `m' for horiz/math mode
+ {\par\hangindent2em\noindent\if##1m$##2$\else##2\fi:\kern1em}
+ \def\[##1]{$\underline{##1}$} % underlined index item
+ \rm \rightskip0pt plus 2.5em \tolerance 10000 \let\*=\lapstar
+ \hyphenpenalty 10000 \parindent0pt
+ }
+\def\fin{\let\@\relax\con}% make these innocuous before scanning argument:
+\def\con#1\con{% ignore stuff after index
+ \par\vfill\eject % this is done when we are ending the index
+ \ifpagesaved\null\vfill\eject\fi % needed in case index is empty
+ \if R\lr \null\vfill\eject\fi % finish the current page
+ \parfillskip 0pt plus 1fil % restore normal paragraph end
+ \setpage % restore page shape
+ \output={\normaloutput\page\lheader\rheader} % restore output routine
+}
+
+\centerline{\titlefont Literate Programming in C}
+\medskip
+\centerline{\twelverm The {\twelvett CWEB} System
+ of Structured Software Documentation}
+\medskip
+\centerline{Manual for \CWEB.x3.0}
+\bigskip
+\centerline{Marc A. A. van Leeuwen}
+
+\bigskip\bigskip
+
+
+\beginsection Overview
+
+This document describes \CWEB.x3.0, a particular implementation of \CWEB., a
+system that supports the concept of ``\lp.'' for programs written in the
+language~\Cee\ (more particularly for this version, in \caps{ANSI/ISO} \Cee).
+As this manual aims to supply all information possibly relevant to a wide
+variety of users, it is necessarily rather extensive. However, \CWEB. is not
+a complicated system, and just a few simple commands suffice for practical
+programming purposes; these are discussed in the section~4 (the remainder
+serves mainly to allow fine-tuning of the presentation of the printed
+documents describing literate programs).
+
+As the somewhat contrived name of the system indicates, \CWEBx. is not the
+only version of \CWEB.; indeed it is based on an older version of \CWEB. by
+Silvio Levy, which is an adaptation to~\Cee\ of the \.{WEB} system (for
+Pascal) written by Donald~E. Knuth, the founder of \lp.. That \CWEB. system
+has independently evolved into a system that is currently distributed, under
+joint responsibility of Levy and Knuth, as \CWEB.~3.4. Those with experience
+using \LKC. will already be acquainted with most aspects of \CWEBx., and may
+turn to section~9 for a summary of the differences between the two systems;
+however, \CWEBx. also provides a compatibility mode (selectable by specifying
+`\.{+c}' on the command line) in which it should be able to process
+\Cee~programs written using \LKC. without any modification.
+
+The structure of this manual is as follows. In section~2 an exposition of
+the ideas underlying the concept of \lp. is given, and a description of how
+systems of the \.{WEB} family provide concrete tools to support this
+programming methodology. This section is directed particularly to those who
+are new to \lp.; it explains the purpose of \CWEB. and the logical
+connection between the various elements that \lp. adds with respect to
+traditional programming. As an illustration we then give a small example
+program using \CWEB. in section~3. The main commands of \CWEB., which define
+the structure of the source text and tell the \CWEB. tools what to do with
+the various pieces of that text, are discussed in section~4. In section~5 we
+discuss how the behaviour of \CWEB. tools can be further affected by means
+of command line options and file name arguments supplied when the programs
+are invoked. In section~6 we discuss some facilities for distributing the
+source text over several input files, including a ``change file'' that
+allows applying local patches without affecting the original source files;
+this is not directly related to \lp., but can be quite useful in larger
+projects. In section~7 the remaining minor \CWEB. commands are explained,
+and section~8 discusses some features of the \TeX\ format employed by
+\CWEB., which can be used to affect the appearance of \CWEB. documents.
+Section~9 is devoted to a comparison with \LKC.; finally section~10
+summarises all \CWEB. codes recognised in the source text.
+
+
+\beginsection About literate programming
+
+\Lp. is a concept that was developed, implemented, and propagated by D.~E.
+Knuth in the early 1980's, as a natural sequel to the concept of ``\sp.''
+that had caused a revolution in the world of software development about a
+decade earlier. (At this moment, another decade further, one may conclude
+that \lp. has not caused a similar revolution, since many programmers
+practicing illiterate programming do not feel at all as guilty about this as
+they would if they were to be found practicing unstructured programming.) So
+let us first consider the idea of \sp. more closely.
+
+\subsection Structured programming
+
+Without attempting a definition of the term, it seems fair to say that \sp.
+involves designing a program by hierarchical decomposition of the task at
+hand, and constructing a program that has a similar decomposition into parts,
+where each part ``solves'' the corresponding subtask. The subdivision of the
+program manifests itself in its division into subroutines (procedures,
+functions), and at the more detailed level in the syntactic composition of
+those routines (control structures, blocks); this explains why much emphasis
+is placed on the use of subroutines, and why languages with a linear program
+model and (conditional) jumps as their main control structure (like assembly
+language) do not form a natural vehicle for \sp.. The question as to which
+criteria should be used in subdividing problems into smaller ones is
+difficult to answer in general, but a good rule of thumb is that at the
+level of abstraction at which a task is defined it should be possible to
+give a reasonably simple informal description of its subtasks, in which a
+new level of detail about the method used to perform the task is given. (It
+would be nice if the subtasks also had simple formal specifications, but in
+general this is too much to ask, since informal descriptions do not only
+abstract from implementation details, they may also conceal numerous obvious
+specification details).
+
+It can be said that the idea of \sp., undone of any dogmatism that has been
+associated with it, has been rather universally accepted, and has proven to
+be an effective methodology in software development. Other methodologies
+have been put forward, such as data encapsulation, but this has been in
+addition to rather than as an alternative for \sp.. \Lp. however is related
+in a different way to \sp., as it concerns not the contents of the program
+itself, but rather the way it is presented. \Lp. presupposes \sp., but is
+independent of other programming paradigms; any program that has been
+designed in a structured way can in principle be rendered as a literate
+program, without requiring a change of the program text itself.
+
+\subsection Limitations of traditional \sp.
+
+Although the composition of a structured program should reflect the design
+decisions that led to its construction, the traditional way of presenting
+such programs lacks appropriate facilities for communicating this
+information effectively to readers of the program, seriously limiting the
+readability, especially to people other than the programmer of the code. Yet
+readability is of vital importance, because it is only by careful reading
+that we can verify that the design of a program is sound and
+well-implemented, and to understand where and how changes can be made when
+such a need arises. Of course the code may be documented by adding an
+arbitrary amount of comments, but there are various reasons why this has a
+limited effectiveness, so that in practice the level of documentation is
+nearly always (much) lower than would be desirable from the point of view of
+maintainability.
+
+The syntactic decomposition of a piece of a structured program into a
+hierarchy of control structures, compound statements, etc., is crucial to
+understanding the way it functions, yet the human eye is much less capable
+of performing this task then a parser is, even when proper indentation is
+applied. The difficulty rapidly increases with the size of the program
+fragment, and can become a serious factor when this size exceeds a dozen or
+two lines (depending on the complexity of the structure). And even when we
+can recognise the structure, the meaning of the individual parts cannot be
+immediately perceived, but must be derived from close inspection of the
+code, or from the comments. However, as comments are localised in the code,
+and it is hard to attach a comment clearly to a construct of some
+considerable extent. Also, adding too many comments may actually decrease the
+readability of the program, by making the structure recognition problem
+worse. Even indentation, useful as it may be, can be more of a nuisance than
+of any help when it becomes so deep that it forces code and comments to be
+squeezed together into (or fall off) the right margin. Finally the fact that
+program sources are usually plain text files, represented in a single rather
+crude font, does not improve human readability. The limitations of the
+character set hamper formulation of comments, where special symbols,
+formulae, tables or illustrations might convey the information much more
+effectively; in the program itself the eye has to do without visual clues
+marking the distinction between various types of program elements
+(identifiers, keywords, constants, literal strings, operators, comments,
+etc.). As a consequence of all this, few people will find much pleasure in
+reading source listings, even if the program is well designed and
+documented, and possibly even contains some interesting and subtle
+algorithms.
+
+Many of these problems would not be too grave if all subroutines were
+severely limited in size and complexity. However, although it might be
+possible to live up to such a restriction for certain kinds of programs (in
+particular if the task involves mostly simple actions of administrative
+nature rather than any really complicated algorithms), it would be a very
+impractical requirement in general, certainly for procedural programming
+languages. First of all, having to break up a subroutine using auxiliary
+subroutines solely because of the size of the code, violates the basic
+principle that such a decomposition should be the result of design
+decisions. Furthermore, there are several technical reasons why such a
+decomposition could be either impossible, or might involve a large amount of
+additional code that has little to do with the actual task being performed,
+and that might deteriorate performance unacceptably. Examples of such
+reasons are for instance the need to perform a large multi-way branching, to
+have local variables that are visible throughout the execution of a complex
+algorithm, or to have the possibility to jump out of nested structures on
+certain (error) conditions (while the language might not allow jumps out of
+a subroutine into the routine calling~it). Finally, introducing many small
+subroutines, for reasons that cannot be described easily outside the
+immediate context in which they will be used, creates a serious problem of
+giving them sensible names and remembering the tasks they perform.
+
+Concluding we may say that \sp. in its traditional form does not encourage
+or even allow the level of documentation that would be desirable for
+maintenance and intelligibility by people other than the author of the
+program.
+
+
+\subsection Requirements for \lp.
+
+The basic idea of \lp. is to take a fundamentally different starting point
+for the presentation of programs to human readers, without any direct effect
+on the program as seen by the computer. Rather than to present the program
+in the form in which it will be compiled (or executed), and to intercalate
+comments to help humans understand what is going on (and which the compiler
+will kindly ignore), the presentation focuses on explaining to humans the
+design and construction of the program, while pieces of actual program code
+are inserted to make the description precise and to tell the computer what
+it should do. The program description should describe parts of the algorithm
+as they occur in the design process, rather than in the completed program
+text. For reasons of maintainability it is essential however that the
+program description defines the actual program text; if this were defined in
+a separate source document, then inconsistencies would be almost impossible
+to prevent. If programs are written in a way that concentrates on explaining
+their design to human readers, then they can be considered as works of
+(technical) literature; it is for this reason that Knuth has named this
+style of software construction and description ``\lp.''. More background
+information about this concept and its history concept can be found in
+Knuths book ``\LP.'', CSLI Lecture notes~\#27, Leland Stanford Junior
+University, 1992 (ISBN 0-937073-81-4).
+
+From the discussion above it will be clear that traditional programming
+languages are not directly suitable for \lp.. We shall now try to formulate
+requirements for a system that supports \lp.. Doing so we shall especially
+keep in mind programs that evolve after their original design, possibly
+altering certain parts of that design, and possibly being realised by
+different persons, since it is in such cases that the benefits of \lp. are
+particularly crucial.
+
+The documentation parts of the program description should allow for the same
+freedom of expression that one would have in an ordinary technical paper.
+This means that the document describing the program should consist of
+formatted text, rather than being a plain text file. This does not exclude
+the possibility that the source is written as a plain text file, but then it
+should undergo some form of processing to produce the actual program
+description. The document should moreover contain fragments of a program
+written in some traditional (structured) programming language, in such a way
+that they can be mechanically extracted and arranged into a complete
+program; in the formatted document on the other hand layout and choice of
+fonts for these program fragments should be so as to maximise readability.
+
+Parts of the program that belong together logically should appear near to
+each other in the description, so that they are visible from the part of the
+documentation that discusses their function. This means that it should be
+possible to rearrange program text with respect to the order in which it
+will be presented to the computer, for otherwise the parts that deal with
+the actions at the outer level of a subroutine will be pushed apart by the
+pieces specifying the details of inner levels. The most obvious and natural
+way to do this is to suppress the program text for those inner levels,
+leaving an outline of the outer level, while the inner levels may be
+specified and documented elsewhere; this is a bit like introducing
+subroutines for the inner levels, but without the semantic implications that
+that would have. There should be no restrictions on the order in which the
+program fragments resulting from this decomposition are presented, so that
+this order can be chosen so as to obtain an optimal exposition; this may
+even involve bringing together fragments whose location in the actual
+program is quite unrelated, but which have some logical connection.
+
+Obviously there should be a clear indication of where pieces of program have
+been suppressed, and which other program fragments give the detailed
+specifications of those pieces. From the programming language point of view
+the most obvious method of identification would be to use identifiers,
+resulting in a simple system of parameterless macros, with as only unusual
+aspect that uses of the macro are allowed to precede the definition, and
+indeed do so more often than not. Actually, \lp. uses a method that differs
+from this only trivially from a formal standpoint, but has a great advantage
+in practical terms: identification is by means of a more or less elaborate
+phrase or sentence, marked in a special way to indicate that it is a
+reference to a program fragment. This description both stands for the
+fragment that is being specified elsewhere, and also serves as a comment
+describing the function of that fragment at a level of detail that is
+appropriate for understanding the part of the program containing it. In this
+way several purposes are served at once: a clear identification between use
+and definition is established, the code at the place of use is readable
+because irrelevant detail is suppressed, with a relevant description of what
+is being done replacing it, and at the place of definition a reminder is
+given of the task that the piece of code presented is to perform. The
+documenting power of such a simple device is remarkable. In some cases the
+result is so clear that there is hardly any need to supply further
+documentation; also it can sometimes be useful to use this method to replace
+small pieces of somewhat cryptic code by a description that is actually
+longer than the code itself. It is hard to give a sharp limit on the length
+of the description for a program fragment, but if substantially more than a
+sentence is needed, say a full paragraph, then the fragment probably does
+not represent a well chosen abstraction, which might be an indication that
+the design of the program has some room for improvement. On the other hand,
+it is good practice to explicitly mention any unusual control flow that
+might be caused by executing the abstracted fragment, like jumping to a
+label outside the fragment, since such information is vital for a proper
+understanding of the program at the place where the fragment is used.
+
+\subsection WEB systems for \lp.
+
+Until now we have discussed \lp. as a general concept, independent of any
+particular implementation; this was done to stress the generality of the
+idea. We shall now indicate how these ideas are realised by ``\WEB.
+systems'', a family of systems that were modelled after Knuth's original
+\.{WEB}, and of which \CWEB. is a member. In these systems the program
+source is written as a plain text file, and a pair of programs is provided,
+which transform this source into other text files suitable for processing by
+a compiler respectively by a typesetting program. Other kinds of \lp. tools
+are conceivable (e.g., ones that would provide the programmer with a direct
+graphical representation of the typeset document while editing, possibly
+with hypertext facilities), but this approach has the advantage of being
+fairly simple and portable across many platforms. The approach is not the
+simplest possible however, as a substantial part of the work done by the
+tools deals with transforming the program fragments from their plain text
+form into typeset text with proper fonts and layout (i.e., with
+pretty-printing); this part of the task also depends essentially on the
+programming language being used. By reverting to verbatim representation of
+program fragments one could make simple tools that support \lp. in a
+language independent way---and indeed such tools exist---but then a price is
+paid in terms of readability. We should also note that \WEB. systems support
+writing documents whose purpose is to simultaneously specify and document a
+program; if one is primarily writing a theoretic paper, in which only
+occasionally pieces of program text are mentioned, then one might prefer a
+slightly different kind of system that does not impose as much global
+structure on the document as \WEB. systems do.
+
+Not surprisingly, \WEB. systems satisfy all the requirements for \lp.
+formulated above, and they do so in a fairly straightforward manner. A
+typeset \WEB. document consists of a sequence of consecutively numbered {\sl
+sections}, whose size is typically less than half a page. Each section may
+contain a program fragment, called a {\sl module}, preceded by a commentary
+in ordinary text, although in some cases either one of these parts might be
+absent. (The programming language used for the program fragments depends on
+the particular \WEB. system used, as does the typesetting system that
+eventually produces the printed document; for the \CWEB. system described
+here these are respectively \Cee\ and \TeX.) In most cases a module is
+headed by a text in angle brackets called its {\sl module name}, which gives
+a description of the task it performs. This name is followed by `$\EQ$' and
+the program code that constitutes the module itself; this is called a
+defining occurrence of the module name. (We make a distinction between the
+words `section' and `module', using the former for a numbered portion of the
+\WEB. document, and the latter for a named portion of the program described
+by it.) A module name can also be used in the body of some other module,
+either before or after its definition in the document, to represent the
+corresponding piece of program text. \WEB. facilitates locating the
+definition of a module from the place where it is used by automatically
+incorporating the number of the defining section in the module name. The
+actual program text is then constructed by recursively replacing module
+names by the text specified in their definition (this should of course
+follow the grammatical structure of the program, lest the most basic
+principles of \lp. be violated). A program fragment occurring at the
+outermost level is distinguished by the fact that it is not headed by a
+module name.
+
+Most module names will have just one defining occurrence, and will also be
+referenced just once; in both cases there may however be exceptions, where a
+module name has more than one occurrence of the indicated kind. If a module
+is multiply referenced, this simply means that the corresponding part of the
+program text is repeated identically in more than one place. If a module
+name has more than one defining occurrence, then the text of the
+corresponding module is obtained by concatenating the program fragments of
+all its definitions in the order in which they occur in the document. In a
+similar fashion all fragments without module name are combined into an
+``unnamed module''. These are the only occasions where the order in which the
+sections are given can have any effect on the final program; apart from this
+the literate programmer has complete freedom of ordering the sections in a
+way that facilitates understanding the program as much as possible.
+
+We need not discuss all aspects of \WEB. systems here, but a few points that
+contribute to \lp. by improving readability should be mentioned. The proper
+formatting of all program fragments is automatically taken care of by the
+\WEB. system, providing a uniform style of presentation. The system also
+provides a large amount of cross-reference information; this greatly
+facilitates reading the program and searching for specific pieces of code.
+Not only is the number of the (first) section defining a module incorporated
+in its name, but in that defining section indications are also given of the
+section(s) in which the module is used, and possibly of any further defining
+occurrences of the same module name. At the end of the document an
+alphabetically sorted index is added, listing for each identifier all the
+sections in which it is defined or used; the programmer may also add
+additional entries to the index by indicating in the program source that
+certain sections should be referenced for particular terms. A list of all
+module names is also given, which may help locating the part of the program
+dealing with some issue. So in many ways the \WEB. system tries to aid human
+understanding of the program, but of course the literacy of the programmer
+will always remain the decisive factor in this respect.
+
+\beginsection What a\/ {\tentt CWEB} program looks like
+
+Enough now of general considerations, let us turn our attention to the
+\CWEB. system this manual is really about. The best way to learn about it is
+probably to read a \CWEB. document. Therefore we include a small but
+complete \CWEB. program below; the program is about as small as possible
+without rendering a decomposition into modules pointless. The example is not
+intended as a showpiece of programming literacy, but it demonstrates various
+aspects of the system. The index at the end of the program is included, but
+not the list of the four module names in this program or the table of
+contents. One will notice that some symbols appear to be different from
+their official representation in \Cee, for instance the assignment
+operator~`\.=' appears as~`$\K$', the equality operator~`\.{==}' as~`$\E$',
+the logical ``and'' and ``or'' operators `\.{\&\&}'~and~`\.{||}' as
+`$\W$'~and~`$\V$' respectively, the variable~`\.{f1}' as~`$f_1$', and the
+null pointer~`\.{NULL}' as~`$\NULL$'; thus the possibilities of the
+typesetting system are used to improve the appearance of the program.
+
+\vfil\eject
+
+\begingroup \input compare \par\endgroup
+
+\subsection Some remarks about the example program
+
+Reading the program should not cause great problems to anyone familiar with
+the \Cee\ language, once one gets used to the representation of the symbols.
+We mention a number of points that will have become clear in the course of
+the example.
+
+The commentary text at the beginning of the sections is set in ordinary
+paragraphs, which contrasts sufficiently with the appearance of the program
+text that the dividing line between the two can be easily perceived, even
+though it is only marked by a bit of white space. In case the section
+defines (part of) a named module, the module name heading the program
+fragment is set flush left, and is followed by~`$\EQ$', or in case this is
+not the first defining occurrence of that name, by~`$\PE$' (therefore, the
+occurrence of the module name `$\X5:Functions\X$' in \Sec2 is not a defining
+one, whereas the occurrences of that name in \Sec5 and~\Sec7 are). The style
+in which the module names and comments contained in the program fragments are
+set is similar to that of ordinary text; indeed if they are too long to fit
+on the line, they will be broken across lines (with proper care taken to
+respect the indentation level). In \CWEB. embedded comments are always
+attached to the right of a program element (usually a statement or
+declaration); in the example we can see there is relatively little need for
+embedded comments, because of the other means provided for documentation.
+An embedded comment that is split across lines will not look very good, and
+should only occur in cases of emergency; in most cases it is better to use
+the commentary part at the beginning of the section for any elaborate
+explanation. On the other hand, long module names (occupying up to about
+four lines) are not uncommon when the task performed by the module calls for
+an extensive description.
+
+As one can see in the example, it is common to refer to small pieces of
+\Cee~code (in most cases just variables or simple expressions) from within
+the commentaries, module names and comments. The \CWEB. system makes it easy
+to include such pieces, by providing a variant of the formatting routines
+used for the actual program fragments (differing from them by the omission
+of any 2-dimensional layout features such as indentation). In many cases the
+pieces of \Cee~code are so simple that they could easily be typeset directly
+(using \TeX's math mode), producing the same formatted output without using
+the facilities of \CWEB.. But even then it is preferable to use \CWEB.
+instead, because it will then guarantee that all identifiers mentioned in
+such a way in the documentation part of a section or in a comment, will be
+included in the index at the end of the program. Although in many cases a
+reference would have been generated anyway by the program fragment in the
+same section (as happens in all cases for our example program), this
+mechanism ensures that even remarks about the use of variables and functions
+made in sections that contain no program fragment at all can be traced from
+the index. Incidentally, identifiers that are used only in a module name are
+not indexed, which is why there is no reference to \Sec2 in the index entry
+for~\\{exit}.
+
+When an index entry is recorded, whether from within a program fragment or a
+piece of \Cee~code embedded in text, the occurrence may be flagged as
+`defining', depending on the context; this happens for instance in the case
+of parameters in an \caps{ANSI/ISO} style function heading, of variable
+declarations and of labels. If at least one occurrence of an identifier in
+some section is a defining one, then the corresponding section number in the
+index entry for that identifier will be underlined. Single-letter
+identifiers, the special identifier \.{NULL} (appearing as `$\NULL$'), and
+keywords of the language are considered so ubiquitous that no index
+references for them are generated, except those that are underlined; e.g.,
+in the example there is no reference to \Sec6 for the variable~$n$. For
+keywords this means that they will not appear in the index at all (unless
+the programmer explicitly marks certain occurrences as defining); note
+however that identifiers defined in a \&{typedef} declaration (like \&{bool}
+in the example) will be indexed, even though they are set in boldface just
+like keywords are.
+
+\subsection Further attributes of\/ {\tentt CWEB} programs
+
+An aspect of \CWEB. programs that does not stand out very clearly in our
+miniature example is that it allows sets of related sections to be grouped
+together into ``chapters''. Each chapter is identified by its title, which
+appears in boldface after the number of its first section; in our example
+sections 1~and~8 start new chapters. The division into chapters has a few
+more effects on the document, which were suppressed in our example, since
+they would interfere with the overall structure of this manual: each chapter
+starts on a fresh page, its title appears in the running head of all its
+pages, and all chapter titles are collected in the table of contents.
+(Style changes such as employed in this manual are easy to obtain, since the
+style is not determined by the \CWEB. system, but rather by a separate
+format consisting of \TeX~macros; a few small changes to standard format can
+change the overall appearance of the document, and it would be equally easy
+to change for instance the page size or the symbols used to represent
+operators.)
+
+There is one important point left to explain about the example, which is the
+special position of the lines starting with \&{\#define} and \&{\#include}.
+Although they look like ordinary preprocessor lines, which
+could have been included in the program fragments, they are in fact separate
+items that are given between the documentation part and the program part of
+a section (this can be seen best in~\Sec6), forming a third type of
+constituent of sections (although in most sections they will be absent).
+Their place in \CWEB. is less distinctive then that of their analogues in
+\WEB. systems for languages that have no preprocessor (like the original
+\.{WEB} for Pascal, which provides a separate macro facility itself): indeed
+the directives are just passed on to the \Cee\ preprocessor. Yet there is
+some advantage in specifying them as special items to \CWEB., and in most
+cases using these facilities is preferable to embedding the directives in
+the \Cee~program fragments.
+
+One reason is that one usually wants the effects of preprocessor directives
+to be visible throughout the \Cee~file that is generated, while this would
+not always be the case if they were specified inside the program fragments;
+for instance if the definition of \\{read\_mode} in \Sec6 had been included
+in the program fragment, it could not have been validly used in \Sec7,
+because that section will precede~\Sec6 in the \Cee~file produced. This
+difficulty could be overcome by collecting all macro definitions in a module
+that is used at the start of the program and defined in many sections
+throughout the \CWEB. document. In fact this is just about how \CWEB. treats
+the separately specified preprocessor directives: they are collected in
+order of appearance, and placed at the very beginning of the \Cee~file.
+(Some other place of insertion for the preprocessor directives can be
+specified by means of a pseudo-module named `$\ATP$', but this is quite
+rare.) Since a section can define only one module, the \CWEB. facility for
+preprocessor directives may help avoid having to split up sections merely
+because they contain such a directive. Furthermore, an important reason to
+specify \&{\#include} directives to \CWEB., is that this allows it to
+inspect those header files for any typedef declarations, so that programs
+can be formatted properly; without this programs using typedef identifiers
+defined in header files would seriously confuse the syntax analysis that
+\CWEB. performs, resulting in very poor quality formatting of program
+fragments.
+
+Preprocessor directives other than those mentioned above can only be
+incorporated in a program by including them in an ordinary program module,
+but there is relatively little need for such directives. In situations where
+one would use conditional compilation in ordinary~\Cee, one can usually use
+the ``change file'' mechanism provided by \CWEB. instead (this will be
+discussed below), especially if it involves system dependent modifications;
+this has the advantage that such modifications do not affect the main source
+files, and only those modifications that are actually applied will be
+visible in the \CWEB. document. In the rare cases that one does include a
+preprocessor directive in a program fragment, the fact that it is not being
+specified as a separate item to \CWEB. is usually easy to recognise in the
+\CWEB. document, because the module name being defined or some program text
+precedes it; however even if this should not be the case then such embedded
+directives can still be distinguished by a slight difference in horizontal
+and vertical spacing.
+
+\subsection Output to multiple files
+
+There is one important construction one may encounter in \CWEB. documents, that
+we have not mentioned yet. There may be module names that consist of a file
+name in typewriter type, like `$\X14:\.{common.h}\X$'; usually such module
+names are nowhere referenced, but only have one or more defining
+occurrences. \CWEB. documents containing such a module will produce a file
+of that name in addition to the \Cee~program that is normally produced. The
+module bearing the name of the file will form the root module of the
+\Cee~code written to that file, in the same way as the unnamed module forms
+the root module for the ordinary output. This feature is particularly useful
+for the production of header files that can be included by other compilation
+units (and even by the program produced as main output). It allows one for
+instance to state function prototype declarations that go to the header file
+and the matching function definitions in the \Cee~program in the immediate
+vicinity of one another within the \CWEB. document. The module with the file
+name can refer to submodules, and so on to any depth, just like the modules
+contributing to the main output. This possibility should be used with some
+restraint however, lest readers have difficulty finding out to which file
+the program fragment defined by some module will be sent. The preprocessor
+lines that are handled by \CWEB. will normally only become part of the main
+program output, not of any additional output files; this provides one valid
+reason for sometimes bypassing the facilities of \CWEB., and incorporating
+\&{\#define} and \&{\#include} directives directly into program modules.
+
+
+\beginsection How to create a\/ {\tentt CWEB} program
+
+In the previous section we have explained how one should read \CWEB.
+documents; in this section we shall discuss how they can be written. The
+``\CWEB. document'' we have been discussing is the printed text that is
+eventually produced from the source file written by the programmer, but
+that file does not look quite like the printed version; on the other hand
+the difference in appearance is not so great that there is any difficulty
+finding the place in the source file corresponding to some part of the
+printed text.
+
+\subsection The general setup
+
+The programmer creates a plain text file using the format explained below,
+which contains both program fragments and commentary, and has file name
+extension `\.{.w}'; e.g., the file from which the example above was produced
+is \.{compare.w} (it is included in the \CWEBx. distribution). The \CWEB.
+system consists of two utility programs `\.{CTANGLE}' and `\.{CWEAVE}' that
+can be applied to this source file. In order to create an executable
+program, one issues the command `\hbox{\.{ctangle compare}}', which will
+read the file \.{compare.w} and write a file \.{compare.c} containing the
+corresponding \Cee~program. This file can then be processed in the ordinary
+way by any \Cee~compiler to produce an executable program. To produce a
+printed document on the other hand, one issues the command `\hbox{\.{cweave
+compare}}', which will again read the file \.{compare.w}, and this time
+write a file \.{compare.tex}. This file serves as input for the typesetting
+program~\TeX: by giving the command `\hbox{\.{tex compare}}' it will be
+processed, and the result is a file \.{compare.dvi}. This file can be either
+previewed or converted to hardcopy output by the system dependent programs
+for this purpose that accompany \TeX. Despite the somewhat elaborate
+processing trajectories, it will become apparent that the programmer has
+good control over the final result produced in both cases.
+
+A word of explanation about the names of \CWEB. and its constituent
+programs. The initial \.C's stand for the programming language, of course;
+the rest of the names are the same as those chosen by Knuth for the original
+\.{WEB}~system (which existed long before the World Wide Web). The \CWEB.
+language allows one to separately describe small parts of a \Cee~program and
+their interconnections, both formal (via module references) and informal (by
+some semantic relationship); with some fantasy this evokes the image of a
+web of connected pieces. These parts are linearised quite differently in
+their presentation for human readability than in the ``official'' form in
+which they are presented to the \Cee~compiler, and it is the program
+\.{CTANGLE} that does the somewhat complicated reordering to obtain the
+latter from the former. This process is traditionally called ``tangling''
+the code, although one could also call it untangling if one prefers formal
+to human order. The \.{CWEAVE} program intertwines the \TeX\ and \Cee~parts
+of the source text and ``weaves'' them together like warp and weft,
+resulting in a beautifully formatted document. Despite these pretty
+metaphors, you will be forgiven if you sometimes get these names mixed up.
+
+This general organisation of \CWEB. has some immediate consequences. First
+of all, one needs to have an operational \TeX~system and (not surprisingly)
+a \Cee~compiler in order to use \CWEB.; the \CWEB. programs form only a
+comparatively small part of the utilities needed. Second, the \CWEB.
+language must be such that both valid \Cee~code and \TeX~input can be
+derived mechanically from it, which are rather different formats.
+Nevertheless the \CWEB. language is quite simple: this is because for almost
+all of the \CWEB. source text the required format is either that of \TeX\ or
+that of \Cee. The main function of the specific \CWEB. commands is to
+structure the source file and determine which parts of the input will be
+processed further in what way. Finally, a somewhat unfortunate consequence
+of \CWEB.'s setup is that errors may be detected by any one of \.{CTANGLE},
+the \Cee~compiler, \.{CWEAVE} and \TeX. The knowledge about \Cee~and~\TeX\
+built into the \CWEB. programs is far from sufficient to ensure that they
+will always produce error-free output code, although of course they do their
+best not to introduce any errors themselves. A bright point in the case of
+\Cee~errors, is that the \&{\#line} directives produced by \.{CTANGLE} enable
+the compiler to refer directly to lines in the \CWEB. source file in its
+errors messages, rather than to the intermediate \Cee~file (but \TeX\ does
+not have a similar facility).
+
+It follows from these facts that the \CWEB. programmer must be acquainted
+both with \Cee\ and with \TeX; however, the depth of the knowledge required
+it not the same in both cases. Obviously, one cannot write a computer
+program without a good understanding of the programming language used, but a
+very superficial knowledge of \TeX\ will suffice: in most cases no \TeX
+pertise beyond the basic facts in chapters~2--6 of {\sl The \TeX book\/} is
+required (but please don't skip chapter~2, as only too many people have
+done). The reason for this is that one rarely needs to instruct \TeX\ to do
+sophisticated formatting. It is true that the proper typesetting of computer
+programs is a subtle matter, but it is precisely this part that is taken
+care of by \.{CWEAVE} (even for references to \Cee~constructs in the
+commentary), and the programmer can just concentrate on writing
+syntactically correct \Cee~code. On the other hand the full power of \TeX\
+is available if one wishes to use it, for instance to illuminate the program
+with things like complicated tables, or math formulae of a different nature
+than those occurring in a computer program.
+
+Since the \CWEB. commands deal only with the structure of the source file,
+not with its contents, they can be very brief: they consist of `\.@' followed
+by one other character, and are commonly referred to as {\sl control codes}.
+For instance, \atspace. (i.e., `\.@' followed by white space) indicates the
+start of a new section, and \:c marks the start of the \Cee~part of a
+section that contributes to the unnamed module. Control codes may placed at
+any position within the source lines, although it is customary to place the
+ones defining the coarse structure of the source file at the beginning of a
+line for better visibility. In some cases a control code marks the beginning
+of a piece of text that will be interpreted by \CWEB. in a special way, as
+for instance \:< which starts a module name; the end of these {\sl control
+texts\/} is always marked by the special code \:>. The character `\.@'
+was selected because it is quite uncommon both in \Cee\ and in \TeX\ source
+code, but in those cases where one does need to pass on the character itself
+(e.g., in \Cee~strings and comments) it should be written as \:@.
+
+We now discuss the various control codes, grouped by their function. Here
+we shall treat only the most important control codes, which are used
+regularly in ordinary programs. Treatment of a number of additional control
+codes, that either serve for fine tuning in special cases, or are intended
+to allow emergency fixes in unforeseen cases, is deferred to a later
+section, in order not to confuse novice \CWEB. users. For the codes that
+are discussed, we do however provide full details of their use; most of
+these can be skipped on first reading. A summary of all \CWEB. control
+codes can be found an the end of this manual.
+
+\subsection Sectioning codes: \:*, \atspace., \:\~
+
+The most important control codes are those that specify the division of the
+\CWEB. program into sections. There are three codes that indicate the start
+of a new section, and are therefore called sectioning codes. Each of them
+has a slightly different effect, and each section must start with one of
+them (i.e., a section is never implicitly started). The three sectioning
+codes are \:*, \atspace., and \:\~, of which the second one is the most
+commonly used. No section numbers should be given in the source file: these
+will be automatically computed and inserted by \CWEB.. A tab or newline
+following `\.@' is considered equivalent to a space, and for any of these
+three control codes, (further) white space separating it from the \TeX~text
+that follows is ignored, as long as there is no completely blank line (which
+\TeX\ would interpret as the end of the paragraph that started with the
+section number).
+
+A section starting with \:* will start a new chapter of the \CWEB.
+document; it should be followed by the title of the chapter, which is
+terminated by the two-character sequence `\hbox{\.{. }}' (again the space
+might be any white space character). The title is not recognised by \CWEB.
+itself, but rather by \TeX, as a delimited macro argument
+\unskip\footnote{${}^\dagger$}
+{Therefore, if no correctly specified title follows~\:*, then
+ \.{CWEAVE} will find nothing wrong, but \TeX\ will complain about a
+ ``Runaway argument'' of a macro that the programmer did not explicitly
+ write (namely `\.{\\N}'); this is one of the scarier error message that
+ novice users can come across, so please be warned.
+}.
+This means that if one wants to have an occurrence of the sequence
+`\hbox{\.{. }}' in the title itself, this can be achieved by enclosing the
+title (but not the `\hbox{\.{. }}' terminating it) in braces. If one wants
+to put other things than plain text in a chapter title, one should be aware
+that it is converted to upper case in the running heads of pages and also
+written to the table of contents file; only items that behave properly under
+these operations should be used in a chapter title. Apart from issuing a
+title that will appear in several places, a section starting a chapter will
+force a page break before it, and it will cause the section number to be
+printed on the terminal during the execution of \.{CTANGLE} and \.{CWEAVE},
+as a progress report.
+
+As a feature for advanced users of \CWEB., some extra information may be
+supplied with the \:* control code: if it is immediately followed by `\.*'
+or by a decimal number, than this is not included in the chapter title, but
+rather interpreted as an indication of the ``level'' of the chapter. Here
+`\.{@**}' indicates the start of a grouping of sections even coarser than a
+chapter, and the grouping started by `\.{@*$n$}' becomes finer as $n$
+increases, with `\.{@*0}' corresponding to unadorned \:*. The effect of this
+level depends on the definition of the \TeX\ macros that format the chapter
+title and the lines in the table of contents, `\.{\\N}' respectively
+`\.{\\contentsline}', to which the level is passed as first argument (for
+`\.{@**}' the level is~$-1$); it could effect for instance the font used for
+the chapter title or the amount of indentation of that title in the table of
+contents. In the default definitions of these macros the level is largely
+ignored, except that `\.{@*$n$}' will not force a page break for $n\geq s$,
+where $s$ is the value of the `\.{\\secpagedepth}' register, which is set
+initially to~2.
+
+In contrast to~\:*, a section starting with~\:\~ instead of~\atspace. will
+tie itself to the previous section, in the sense that a page break between
+these sections will be avoided. More precisely this is what happens:
+normally \.{CWEAVE} will instruct \TeX\ to break pages only between sections
+(except when one is too large too fit on a single page) and put as many
+sections on each page as possible subject to this restriction; however, a
+section starting with~\:\~ will be considered to be continuation of the
+previous section for the purpose of page breaking. A situation where one
+would use \:\~ is the following: suppose we define a function, and also want
+to state its prototype, which will belong to a different module, since it
+has to appear earlier in the program or even on a separate (header) file. A
+natural place to give the prototype in the \CWEB. document is directly
+before the function, so that it can easily be seen that the prototype
+matches the actual definition. Now without special measures there is a
+substantial chance that a page break will occur between these two sections,
+since the short section with the prototype might fit on an already partially
+filled page, whereas the larger section with the definition might not. By
+starting the latter section with~\:\~, it can be achieved that in such cases
+the former section is moved together with the latter to the new page.
+
+Like any other section the very first section starts with s sectioning
+code (usually \:*), and any text that might precede it is not
+part of any section; this text is said to be ``in limbo''. This material is
+ignored by \.{CTANGLE}, and copied literally into the \TeX\ file by
+\.{CWEAVE} (except for the replacement of~\:@ by~`\.@'), following the first
+line which always reads `\.{\\input cwebxmac}' (in order to load the
+standard format). The purpose of the text in limbo is to allow issuing
+\TeX~commands that apply to the whole document (such as macro definitions,
+possibly modifications or additions to the standard format), or producing a
+title page or an introduction preceding the sections of the \CWEB. document.
+No control codes are allowed in the limbo text (well, almost; there are two
+exceptions, that will be mentioned below). The last section ends simply
+at the end of the \CWEB. source file; there is no way to add material after
+it (or elsewhere outside the sections). However, \.{CWEAVE} will append some
+material at the end itself (unless it is invoked with a `\.{-x}' flag): an
+index of identifier uses, a list of module names, and a table of contents.
+Because the index is seamlessly attached to the last section, it is
+customary to give that section the title ``Index'' and not to include any
+program fragment in it.
+
+
+\subsection Subsectioning codes: \:d, \:h, \:f, \:c, `\/\.{@< {\dots} @>=}'
+
+Each section, as delimited by the sectioning codes, contains a \TeX~part
+(although it may be empty), and in addition at most one \Cee~part, which
+always comes at the end of the section, and zero or more intermediate parts,
+of which there are three kinds: those that specify \&{\#define} and
+\&{\#include} directives, and format definitions (see below). Intermediate
+parts can be given in an arbitrary order, as long as they come after the
+\TeX~part and before the \Cee~part, if present. The beginning of any part
+other than the \TeX~part (which starts directly after the sectioning code)
+is marked by an appropriate control code, which is called a subsectioning
+code; these codes are optional in the sense that they need only be given if
+the corresponding part is present. The end of the \TeX~part is determined by
+the first subsectioning code, or in absence of any of them by the next
+sectioning code.
+
+The \Cee~part, if present, begins at the first occurrence of \:< or \:c; the
+former starts a defining occurrence of a module name, and the latter is used
+when the \Cee~part belongs to the unnamed module. The code \:c may also be
+written as \:C (in fact all alphabetic codes are equivalent to their upper
+case counterparts). Once the \Cee~part of a section is started, any further
+module names are interpreted as modules references rather than as defining
+occurrences. A module name, whether defining or not, consists of \TeX~code
+between the \:< and the next occurrence of~\:>. As a measure against
+accidental misinterpretation of module names, due for instance to a
+forgotten \atspace. or \:c, the closing \:> of a defining occurrence must be
+followed (optionally with some white space in between, but no newline) by
+one of `\.=', `\.{==}', `\.{+=}' and `\.{+==}', while for a non-defining
+occurrence this must not be the case. The possibilities `\.{+=}' and
+`\.{+==}' are included for those who like their source code for
+continuations of modules to resemble the printed output, but the distinction
+is ignored by \CWEB.: it will simply print `$\EQ$' after the first defining
+occurrence of a module name and `$\PE$' after any further defining
+occurrences.
+
+The subsectioning codes that mark the beginning of intermediate parts are
+\:d, \:h, and \:f. Of these the first two specify preprocessor directives
+for respectively a macro definition and the inclusion of a header file, and
+the last specifies a so-called format definition. The codes \:d and \:h will
+be replaced by \&{\#define} respectively by \&{\#include} in both the
+program and the printed document. We already mentioned how the effect of
+using \:d or \:h differs from that of using \&{\#define} or \&{\#include}
+directly in the \Cee~part of the section: the directive will be moved to the
+beginning of the \Cee~file, and in case of \:h, the header file will be
+scanned for typedef definitions. Here we mention a few more points that are
+relevant when writing the source file.
+
+Macro definitions following \:d are not line-oriented like those in \Cee:
+everything up to the next subsectioning or sectioning code is considered to
+belong to the macro, and newlines need not be escaped, as \.{CTANGLE} will
+take care of escaping any newlines while writing to the \Cee~file. There are
+some mild restrictions on the replacement text of a \:d macro definition:
+parentheses and braces should be balanced (this is a deliberate requirement,
+made in order to allow detection of programming errors that would otherwise
+be very hard to track; the same requirement also holds for each complete
+\Cee~part of a section), and no module names should be referenced. It is not
+possible to use other preprocessor directives in macro definitions either,
+but that is because this is already impossible in~\Cee. After a \:h command,
+at least one newline should occur before the next sectioning or
+subsectioning code.
+
+Apart from this, \:d and \:h are followed by whatever would follow
+\&{\#define} respectively \&{\#include}, with the same deviant lexical rules
+as in~\Cee. So whether a macro introduced by \:d is defined with or without
+arguments depends on whether the first character after the identifier
+following \:d is a left parenthesis or not, where spaces {\it are\/}
+significant. The file name after~\:h may be enclosed either in double quotes
+or in angle brackets; the latter indicates that the header file is located in
+some system include file area. After the file name a comment may be placed.
+
+The header file specified after \:h itself should of course contain ordinary
+\Cee~code rather than \CWEB. input; after all, it will be read directly by
+the \Cee~compiler. As as mentioned before, the file will be scanned by
+\.{CWEAVE} as well, searching for any typedef definitions; moreover, if it
+contains any lines starting with \&{\#include}, then those files will be
+scanned recursively as well. In the case of system header files (specified
+with angle brackets), \.{CWEAVE} will refrain from scanning the file unless
+the file is found on an explicitly specified search path (see below); in
+fact it is better not to scan any of the \caps{ANSI/ISO} standard header
+files, since \.{CWEAVE} already knows about all typedef definitions that can
+occur in such header files. It is not uncommon that a header file specified
+after~\:h (using quotes) is itself an auxiliary output file produced from a
+\CWEB. source file, possibly even from the very source file containing the
+\:h~command. There is no circularity or other problematic aspect of such a
+situation, but one should remember to run \.{CTANGLE} to produce the header
+file, before the run of \.{CWEAVE} that needs it.
+
+The way \.{CWEAVE} searches for the header file depends on how the name
+following \:h is specified: if it is enclosed in quotes then \.{CWEAVE} will
+look first in the current directory. There may have been specified one or
+more alternative places to look for header files, in the form of strings
+that can be prefixed to the file name (given on the command line or compiled
+into \.{CWEAVE}, or both). If so, these will be tried in order, regardless
+of the delimiters used for the file name, until a match is found; \.{CWEAVE}
+will only insist on actually finding a header file if the file name was
+enclosed in quotes.
+
+There is one aspect of scanning header files that might cause a problem in
+some cases: when scanning a header file, \.{CWEAVE} is unaware of other
+preprocessor directives that may disable certain nested \&{\#include}
+directives; \.{CWEAVE} will therefore obey such \&{\#include} directives
+unconditionally. Such a problem is not very likely, but it could be serious
+if the nested header file cannot be found (and is enclosed in quotes), or if
+there are circular references between header files. Various solutions could
+be found for such a problem, depending on the precise situation, varying
+from creating dummy files or avoiding conditional compilation by the use of
+change files to (as a last resort) avoiding the scan of the header file
+altogether, by using \&{\#include} in a program fragment rather than~\:h; in
+the latter case relevant information could be extracted from the header
+file manually, and converted into format definitions (\:f) described below.
+
+When preprocessor directives are incorporated in the \Cee~part of a section,
+the ordinary rules of \Cee\ apply: they should be spelled out in full, as
+`\.{\#define}' or `\.{\#include}', and occur at the beginning of a line; the
+directive ends at the next non-escaped newline. Although in \Cee\ it is
+permissible to extend a preprocessor directive into the following line by
+placing a multi-line comment that contains the newline, this should not be
+done in \CWEB., since the comment will be removed by \.{CTANGLE} but the
+newline will remain. If one needs a very long comment after a preprocessor
+directive, one should start it on the line following the directive; in the
+formatted document such a comment will be placed on the same line as the
+directive. The same holds for comments placed after a \:h command.
+
+Format definitions, indicated by the code \:f, are entirely specific to
+\CWEB., and have no effect on the \Cee~program that is defined. They are not
+needed very often, but when they are, a proper use of them is essential for
+obtaining acceptably formatted output. To understand why they are sometimes
+needed, one has to consider the way \.{CWEAVE} formats program fragments.
+The input is broken up into tokens (like identifiers, constants, operator
+symbols), and a syntactic category is attached to each; the resulting
+sequence of categories is then analysed according to a grammar, and formatted
+correspondingly. Certain identifier tokens are recognised as reserved words
+and get a corresponding the syntactic category, others are recognised as
+typedef identifiers and get the same syntactic category as for instance
+\&{size\_t}, and the remaining ones are treated as ordinary identifiers. This
+scheme usually works fine, but occasionally there can be problems, caused by
+the fact that \.{CWEAVE} is not aware of all the information that is
+available to the compiler. The main reasons for this are macros (which may
+cause the code seen by the compiler to be quite different from that seen by
+\.{CWEAVE}), typedef declarations that are hidden from \.{CWEAVE}'s sight,
+and module names that stand for a construct of a different syntactic
+category than \\{statement} (which is what \.{CWEAVE} expects them to be by
+default). In all these cases \CWEB. provides mechanisms for the user to put
+\.{CWEAVE} on the right track, and format definitions are one such mechanism
+(others will be discussed below).
+
+Format definitions allow the programmer to explicitly state the syntactic
+category that \.{CWEAVE} should attach to a given identifier. They have the
+form `\.{@f x y}', which will become `\&{format}~$x$~$y$' in the typeset
+output; here $x$ and $y$ can be arbitrary identifiers or keywords. This
+definition has the effect of associating to~$x$ the same syntactic category
+that is associated to~$y$. Such a change of category is required when an
+identifier is defined as a macro to stand for a keyword: whenever you say
+`\.{@d ident keyword}', say `\.{@f ident keyword}' as well. For instance,
+the author of this manual thinks the keyword \&{static} is not very
+informative when applied to functions, and therefore often creates an alias
+for it by saying `\hbox{\&{\#define} \\{local} \&{static}}'; this directive
+is then followed by `\hbox{\&{format} \\{local} \&{static}}'. We see that
+the first identifier after \:d~or~\:f is always typeset in italics; this is
+so despite the fact that in the example, as a consequence of the format
+definition, this identifier will be typeset as \&{local} in all other
+places. Another reason to change a category could be that an identifier is
+in fact a typedef identifier, but \.{CWEAVE} cannot deduce this fact
+(presumably the declaration occurs in some header file that is not scanned
+by \.{CWEAVE}); in such cases one can use a standard defined type like
+\&{FILE} or \&{size\_t} as the second argument to \:f. Finally, it is
+possible that some \Cee~implementation uses additional, non-standard
+keywords (or macros that behave as a keyword); such an identifier should be
+formatted like a standard keyword that has a similar syntactic function as
+it (which hopefully exists). In fact the identifier \&{va\_dcl}, which is
+used in a convention for functions with variable argument lists that is not
+part of \caps{ANSI/ISO}~\Cee, is nevertheless built into \.{CWEAVE}, because
+there is no keyword that has the required syntax category (namely
+\\{declaration}), so that it would otherwise not be possible to introduce
+it; one can on the other hand easily undo the reservation by saying
+`\&{format}~\\{va\_dcl}~$x$'.
+
+Format definitions can also be used for a reason that does not have to do
+with syntax analysis. There are two classes of identifiers that are parsed
+like ordinary identifiers, but are nevertheless treated specially; these
+classes consist initially of the identifiers \\{TeX} respectively \\{NULL}.
+The main distinction of these classes is that their identifiers are typeset
+differently, namely as \TeX~macros; the mentioned identifiers will therefore
+be written to the \TeX~file as `\.{\\TeX}' respectively `\.{\\NULL}', which
+causes them to be typeset as `\TeX' respectively `$\NULL$'. This mechanism
+gives the user the ability to change the appearance of identifiers in any
+desired way, simply by defining the macro appropriately. The class
+of~\\{TeX} is intended for identifiers that are still alphabetic in
+appearance (possibly with letters being accented or shifted), while the
+class of~\\{NULL} is intended for identifiers that are represented by
+mathematical symbols. Hence the \TeX~macro will be processed in
+horizontal mode with italic font selected in the first case, and in math mode
+in the second case. Simply saying `\.{@f alpha NULL}' suffices to make
+\\{alpha} print as~$\alpha$; the format definition is typeset as
+`\hbox{\&{format} \\{alpha} $\NULL$\quad($\alpha$)}' to make the
+correspondence of the identifier and typeset symbol evident.
+
+Unlike \Cee~identifiers, \TeX~macros cannot contain underscores and digits.
+On writing of the macros to the \TeX~file, underscores are replaced by~`\.x',
+so that they will become part of the macro. Digits however are not changed,
+so identifiers containing digits should not be put into the class of~\\{TeX}
+or~\\{NULL} by a format definition, unless special care is taken: the macro
+will only consist of the part up to the first digit. No index entries for
+identifiers of the class of~\\{NULL} are recorded (the same holds for
+keywords); on the other hand index entries for typedef identifiers are
+recorded, despite the fact that they are formatted as keywords.
+
+\subsection Text within \Cee~program fragments: comments and module names
+
+Within the program part of a section, the input should basically follow the
+rules of the \Cee~syntax, but amidst the \Cee~tokens there may also occur
+module names and comments. In both cases the \Cee~code is temporarily
+interrupted by a piece of ordinary text that is processed directly by~\TeX,
+just like the \TeX~part of a section. In the case of module names this text
+is delimited by \:<~and~\:>, in the case of comments by
+`\.{/*}'~and~`\.{*/}'. So comments are actually valid \Cee~comments, but the
+converse is not true: the contents of a comment is processed by~\TeX, so not
+all \Cee~comments can be used without modification; a point to keep in mind
+if one is converting ordinary \Cee~code to \CWEB.. Like \Cee~comments, the
+comments of \CWEB. cannot contain the two-character sequence `\.{*/}'
+(regardless of the \TeX~context, because comments are recognised before
+\TeX\ even gets to see them). The sequence `\.{/*}' is forbidden as well,
+which allows \.{CTANGLE} to warn the programmer about unclosed comments,
+that might otherwise lead to particularly elusive errors. In the \TeX~texts
+of comments and module names no control codes are allowed (except in
+embedded pieces of \Cee~code, described below), but \:@ can be used to
+represent the character `\.@' (this is true in all contexts); a module name
+is terminated by the first occurrence of the code \:>. During the processing
+of these \TeX~texts, line ends are replaced by spaces, which implies that
+\TeX~comments (starting with `\.\%') cannot be used. (In the \TeX~part of a
+section on the other hand, such comments can safely be used: they are
+completely ignored by \.{CWEAVE}, and not even copied to the \TeX~file.)
+
+The text for module names serves a dual purpose: apart from determining the
+text representing the module in the printed output, it also serves to
+identify defining occurrences of a module name with references to it. For
+the latter purpose it is irrelevant how the contents of a module name will
+be further processed; there should basically be a character-by-character
+match. This rule is however alleviated in two ways to make matching easier.
+First, any amount of consecutive white space is replaced by a single space,
+and white space at either end of a module name is discarded. Second, an
+abbreviation mechanism for module names may be used. A module name may be
+specified by a prefix of the full name, followed by~`\.{...}'. A few
+conditions must be satisfied to allow this mechanism to work. All
+specifications of one same module name must be extensions of the one among
+them of minimal length, which must not be a prefix of any other (full)
+module name. All specifications of the name that do not end with~`\.{...}'
+must be equal; there must be at least one such specification, which defines
+the full module name of which all other specifications give a prefix.
+Loosely speaking, the minimal specification is used for identification
+purposes, and the maximal specification is used for typesetting all
+occurrences. With the help of these rules, and a text editor, there should
+be little reason to choose module names any shorter than what is needed to
+express the function of a module clearly. There is a limit on the length of
+a module name, but it is so generous that this could hardly be a problem:
+1000~characters after replacement of consecutive white space characters by
+single spaces.
+
+The parser of \.{CWEAVE} normally assumes that references to modules stand
+for (compound) statements, which is likely to be a valid assumption in the
+majority of the cases (or at least one that does not upset parsing, for
+instance when the module is actually a statement sequence). Occasionally
+however, one of two other syntactic categories applies instead, namely
+\\{declaration} or \\{expression} (the remaining categories are extremely
+unlikely). When this is the case, the programmer should make it clear to
+\.{CWEAVE}, lest the parser might choke on the input and produce badly
+formatted output. This can be done by placing the control code \:; once (for
+a \\{declaration}) respectively twice (for an \\{expression}) directly after
+the module name (in the latter case this also conveniently provides a
+separation from any `\.=' or `\.{+=}' that might follow).
+
+At the end of the \CWEB. document, after the index, a list will be placed of
+all module names used. This list sorted lexicographically, with sorting
+based on the source strings for the full module names, collated (unlike the
+identifier index) in the order of the internal (\ASCII.) character codes.
+For this reason it is a good convention to ensure that all module names are
+already distinguished by a prefix consisting of alphabetic characters and
+spaces only, of which the first word is capitalised; then the order of the
+list will be natural and independent of any internal details that the reader
+is not aware of.
+
+\subsection \Cee~code within text: `\pb' fragments
+
+In order to mention a piece of \Cee~code within \TeX~text, it can simply be
+enclosed in vertical bar characters (`\.|'); then \.{CWEAVE} will format it
+in a way similar to to \Cee~code of modules. This feature may be used in any
+kind of \TeX~text except in limbo, i.e., in the ordinary \TeX~part of a
+section, in comments and in module names. The piece of \Cee~code itself
+should not contain any comment.
+
+The ``lightweight'' construction with vertical bars resembles the math shift
+characters (`\.\$') for \TeX's math mode, and indeed in simple cases like
+`\.{|a[i+3]|}' the output would be identical if the `\.|' characters were
+replaced by `\.\$'. The two modes should not be confused however: the
+``\Cee~mode'' is implemented by \.{CWEAVE}, which translates the
+\Cee~constructs before \TeX\ ever gets to see them; it often uses math mode
+itself, and as a consequence it should never be used when \TeX\ is already
+in math mode. The syntax used by \.{CWEAVE} is of a stricter kind than that
+of \TeX's math mode, but it can still be used for some expressions that are
+not quite proper~\Cee; in particular there is no objection to writing things
+like $\\{begin}\Z p<\\{end}$, which humans understand better than compilers.
+On the other hand an incomplete formula like `$\leq n$' (which can be used in
+sentences, with the missing operand expressed in words) is better written as
+`\.{\$\\leq n\$}' than as `\.{|<=n|}': the latter is not understood by
+\.{CWEAVE}'s parser, and therefore the `\.{<=}' and the `\.n' are translated
+separately with an ordinary space in between; the result looks reasonable,
+but \TeX\ may very well decide to break the line at the space.
+
+There is a lexical price to pay for using delimiters that are not control
+codes: it is impossible to use character `\.|' in any piece of \TeX~text
+where `\pb' constructions are allowed (even if one tries for instance to set
+up a verbatim context, because \.{CWEAVE} acts before \TeX\ does). This
+should not cause great problems however, since `\.|' is not a character in
+ordinary text fonts, and for `\.|'~and~`\.{\\|}' in math mode, plain \TeX\
+already has the substitutes `\.{\\vert}' and~`\.{\\Vert}'; for exceptional
+text fonts (like typewriter type) that do have `\.|', the standard format
+for \CWEB. provides `\.{\\v}' as a substitute (by means of \.{\\chardef})
+for~`\.|'. Inside `\pb' one has a similar problem of not being able to write
+the bitwise-or operator~`$\OR$' in the usual way. For this purpose \CWEB.
+provides the control code~\:v to represent that operator (which you may also
+use in an actual program fragment, although there is no need to do so
+there). Note that the composite operators `\.{|=}'~and~`\.{||}' can be used
+without problem; consequently no `\pb' should be immediately followed
+by~`\.=' or by another `\pb'.
+
+Although \Cee~comments are forbidden inside `\pb', it is possible to mention
+a module in \TeX~text by enclosing the module name in vertical bars; this
+\TeX~text can either be the \TeX~part of a section or a comment, but not
+another module name. Mentioning a module in this way does not imply any
+inclusion of the module body, so it is not considered to be a use of the
+module; in the cross-references it is referred to as a ``citation'' of the
+module. For the module name itself the same rules apply as for other
+occurrences of module names; in particular the abbreviation mechanism can be
+used, and \.{CWEAVE} will automatically insert the relevant section number
+in the module name. Citing a module may form an exception to the rule that an
+occurrence of a module name when the \Cee~part of a section has not already
+started must be a defining one. Since \.{CTANGLE} normally ignores the
+vertical bars of `\pb' constructions together with the surrounding
+\TeX~text, it needs a simple rule to decide whether a module is being cited
+or defined. It does this by inspecting the next token (where a newline
+counts as a token, but codes like \:; that are ignored by \.{CTANGLE} are
+skipped): if this is `\.=' (or `\.{+=}' etc.), then it assumes that the
+module is being defined, and if it is `\.|' that the module is being cited;
+in other cases it signals an error (this could for instance happen if a \:c
+code is missing). Therefore it is not really necessary that the module name
+is the only item in the `\pb' construction, as long as it is the final item;
+this extra freedom is not likely to be of much practical use, however.
+
+\subsection Modules producing additional output files: `\/\.{@( {\dots} @>}'
+
+As was mentioned before, there are special module names that will cause the
+program produced by that module to be written to a separate output file.
+Such a module name is specified by enclosing the file name in \:(~and~\:>;
+in fact it is sufficient to use \:( instead of~\:< in just one occurrence of
+the module name. The file name will be set in typewriter type by \.{CWEAVE},
+so that the difference with an ordinary module name is easily perceived.
+Although hardly relevant for this case, the compression of white space and
+the abbreviation mechanism for module names also applies to these special
+module names. The file name can contain any special characters, including
+`\.|' and `\.@'; the latter must as always be doubled.
+
+\subsection Control codes that help parsing in special situations:
+ \:;, \:[, \:]
+
+In the discussion of the \&{format} command we already mentioned the way
+\.{CWEAVE} parses and formats program fragments, and the fact that some
+programming constructions can confuse the parser, leading to badly formatted
+output. Like \:f, the control codes in this subsection provide ways to avoid
+such problems, but they do so on a local basis in the code itself, rather
+than by global definitions. They are mainly used in connection with macros
+with replacement texts and/or arguments that are not expressions. Since
+macro invocations look like identifiers or function calls, and macro
+arguments appear to be function arguments, a piece of code containing a
+macro invocation whose replacement text and arguments are not all
+expressions may seem syntactically incorrect when not expanded. An example
+of such a scenario is a macro whose replacement text is a compound
+statement; an invocation of such a macro needs no semicolon following it,
+and sometimes placing a semicolon would actually cause an error (e.g., if
+the invocation is used as the first branch of an \&{if}-\&{else} statement,
+since the semicolon would be taken to be an empty statement {\it after\/}
+the conditional statement, and the \&{else} would be unmatched). Since the
+parser of \.{CWEAVE} does not expand macros, it will fail to recognise a
+macro invocation without a following semicolon as a statement, and like many
+parsers it is not good at recovering from such a failure. Although no error
+message is usually issued, formatting can be severely disrupted; indeed,
+correct formatting will only be inserted locally for constructions that do
+not contain the ``error'', so one unrecognised construction can easily
+destroy the layout of the entire program fragment it occurs in.
+
+\.{CWEAVE} provides some simple mechanisms for guiding the parser through
+such unusual code, and by applying them in several ways nearly all problems
+that arise in practice can be solved. One of these is the control code~\:;,
+which produces no \Cee~code (nor any printed output), but which can be used
+in places where the \.{CWEAVE} parser would require a semicolon for a
+successful parse; another is the combination \:[,~\dots,~\:], used as
+a pair of parentheses, which will cause whatever is enclosed to get the
+syntactic category `expression', regardless of its actual category.
+
+The most obvious use of~\:;\ is in the case already mentioned of a macro
+invocation that expands to a (compound) statement: placing \:; after such a
+macro invocation will cause it to be recognised as a statement by \.{CWEAVE},
+keeping its parser happy while not affecting the actual \Cee~program. There
+are other situations as well where one does not want to place a semicolon,
+yet wishes \.{CWEAVE} to act as if it were there. If a macro stands for
+statement that happens to end in a semicolon, then it is a good idea to
+suppress the final semicolon in the definition: in that case all invocations
+can supply the semicolon, and one does not have to remember writing \:;
+instead of~`\.;' at the invocations of this macro. For instance, the macro
+replacement text could be `\&{do}~\<statement>~\&{while}~(\<condition>)', or
+`\&{if}~(\<condition>)~\<statement>~\&{else}~\<expression>', or even
+`\&{if}~(\<condition>)~\<statement>~\&{else}', where the final \&{else} was
+placed with the purpose of picking up the following semicolon as an empty
+statement; in all these cases the macro invocation together with the
+following semicolon is a complete statement that can be used without special
+precaution, even as the first branch of an \&{if}-\&{else} statement.
+However, in these cases the macro definition itself needs a bit of extra
+care: a~\:; should be placed at the end to represent the semicolon that will
+follow in invocations, so that \.{CWEAVE} can properly format the
+replacement text of the macro. Finally, it there can be purely aesthetic
+reasons for wanting to suppress a semicolon at the end of a `\pb'
+construction, for instance when referring to a declaration as
+`$\&{char}~\m*p$', which strictly speaking requires a final semicolon to
+become a declaration; to let \.{CWEAVE} format this properly, one should
+write `\.{\v char *p @;\v}'. Constructions like `$\&{return}~\\{home}$' and
+`$\&{goto}~\\{sleep}$', which are fairly common to mention in module names,
+would also fall into this category, but in this particular case no \:; is
+necessary, since \.{CWEAVE} parses these as expressions, even though strictly
+speaking they are not.
+
+Since \:; is invisible in the output, yet can be sensed by the parser, it
+can conveniently be used to pass information to the parser, and there are a
+few instances of such use where it does not stand for a semicolon. We
+already mentioned placing one or two copies of \:; after a module name to
+indicate the syntactic category. Another use is to place it before a typedef
+identifier to cause it to be treated as an ordinary identifier; this is
+useful if the identifier is locally redeclared, or used as field selector in
+a \&{struct} or \&{union} specifier. When the identifier is used as a tag
+immediately after \&{struct} or \&{union}, or as a selector after
+`$.$'~or~`$\MG$', it is not necessary to place \:; before it.
+
+Unlike \:;, the control codes \:[~and~\:] themselves do not participate in
+parsing. The material between them is parsed normally, which may or may not
+succeed in recognising a single construct; then the pieces recognised are
+concatenated (without separation), and the result is given the category
+\\{expression} for the purpose of parsing further items outside. The most
+obvious use of this mechanism is to encapsulate any arguments in a macro
+invocation that are not expressions (e.g., some storage allocation macros
+have a type as argument), so that the invocation can be parsed as a function
+call. There need not be anything in between \:[~and~\:], so `\hbox{\.{@[
+@]}}' can be used as an ``invisible expression'' in the same way as \:; can
+be used an invisible semicolon. An example where this is useful, is a module
+standing for an initialiser list, that is moreover defined in multiple
+sections (see for instance the module `$\X157:Rules\X$' in the source
+document for \.{CWEAVE}): it is natural to end each program fragment
+defining a part of such a module with a comma, but this will not be parsed
+properly unless an expression follows, which can be achieved by adding
+`\hbox{\.{@[ @]}}'. Finally, if for some tricky piece of code none of the
+mentioned methods suffice to get it parsed properly by \.{CWEAVE}, one may
+use \:[~and~\:] (followed by \:; if necessary) to minimise the damage: by
+placing \:[~and~\:] around an appropriate part of the program containing of
+the problem area, we can ignore the fact that the parser failed to recognise
+it, and force it to continue as if it ad recognised an expression; thus we
+can contain the problem, and prevent the effects from spreading any further.
+
+
+\beginsection Invocation of {\tentex CTANGLE} and {\tentex CWEAVE}
+
+The simplest form of calling \.{CTANGLE} and \.{CWEAVE} is to supply one
+command line argument, which is the name of the \CWEB. source file without
+the `\.{.w}' suffix. It is possible however to modify the behaviour of the
+programs by selecting certain optional settings, and small patches to the
+master source file can be achieved by supplying a ``change file''. The
+general syntax for invoking \.{CTANGLE} is
+$$ \hbox
+{ \.{ctangle}\quad
+ [$(\.+\mid\.-)$\<options>]\quad
+ \<\CWEB. file>[\.{.w}]\quad
+ [$(\<change file>[\.{.ch}]\mid\.+\mid\.-)$ \quad
+ [\<output file>[\.{.c}]]]
+}
+$$
+where square brackets indicate optionality, vertical bars separate
+alternatives, and parentheses are used for grouping. Here \<options> is a
+string of one or more characters designating options, as described below;
+there may be more than one such string of options, and they may be given
+between or after the files names instead of before them, with no difference
+in meaning. For \.{CWEAVE} the situation is entirely similar, except that the
+default extension for the output file is `\.{.tex}' instead of `\.{.c}'.
+
+\subsection Command line options
+
+A command parameter that starts with `\.+' or `\.-' and has at least one
+more character, serves to control optional settings of the program being
+invoked. The characters after the initial character `\.+'~or~`\.-' denote
+individual options that are turned on respectively off; option characters are
+case-insensitive. The character `\.i' forms an exception, since it is used
+to supply a string argument rather than to set a switch; the string is the
+remainder of the option string (following the `\.i'), and
+`\.{+i}'~and~`\.{-i}' are equivalent. All option characters will be
+accepted, but only the ones listed below have any effect on the operation of
+the program. We list the switches in the direction that alters the default
+setting.
+$$\vcenter{\tabskip=1em \halign{\tentex#\hfil & #\hfil & #\hfil \cr
+\omit\it switch& \it program& \it effect \cr
+\noalign{\yskip}
+-b & both & do not write a banner line to the terminal \cr
+-p & both & do not show a progress report on the terminal \cr
+-h & both & omit confirmation of successful completion \cr
+\noalign{\yskip}
+-l &\.{CTANGLE} & omit \&{\#line} directives, make \Cee~file look nice \cr
+\noalign{\yskip}
+-x & \.{CWEAVE} & do not attach index and other information
+ at the end of the document \cr
++d & \.{CWEAVE} & report failure to completely parse pieces of \Cee~code \cr
++t & \.{CWEAVE} & write three files,
+ with separate ones for index and list of module names \cr
++e & \.{CWEAVE} & even out number of pages before table of contents \cr
+\noalign{\yskip}
++i & \.{CWEAVE} & add alternative search path for header files
+ (takes argument) \cr
+\noalign{\yskip}
++f & \.{CWEAVE} & force a line break after each statement \cr
++a & \.{CWEAVE} & force all statements to be on a line by themselves \cr
++u & \.{CWEAVE} & ``unaligned brace style'': do not align `$\{$' and `$\}$'
+ vertically \cr
++w & \.{CWEAVE} & ``wide brace style'':
+ force line breaks before and after `$\{$' \cr
++m & \.{CWEAVE} & ``merged declarations style'':
+ do not force line breaks between local declarations \cr
+\noalign{\yskip}
+ +c & both & run in compatibility mode with \LKC. \cr
+ +s & both & show memory usage statistics at completion \cr
+ ++ & both & handle \Cpp~language instead of \Cee \cr
+}}
+$$
+The options `\.{+d}'~and~`\.{+s}' only operate if \.{CWEAVE} or \.{CTANGLE}
+was compiled with the preprocessor symbol \.{DEBUG} respectively \.{STAT}
+defined (with most \Cee~compilers this can be accomplished by including a
+command line parameter \.{-DDEBUG} respectively \.{-DSTAT} when compiling
+the \CWEB. system).
+
+The options `\.b', `\.h', and `\.p' can be used to control the amount of
+output that \CWEB. writes to the user terminal; the combination `\.{-bph}'
+will eliminate terminal output altogether when no errors are encountered.
+
+The option `\.{-l}' of \.{CTANGLE} is intended either for use with broken
+compilers or debuggers that cannot handle \&{\#line} directives properly,
+or for cases where the \Cee~file is of more importance than just as an
+intermediate file, for instance when the program is transferred to
+people who do not wish to practice \lp.. Apart from omitting \&{\#line}
+directives and comments that indicate the section number from which code
+originates, an attempt is made to make the \Cee~file more readable to humans:
+the spacing and (almost all) comments of the source file are preserved in
+the \Cee~output, and when modules are substituted into others, indentation
+levels are accumulated, so as to produce indentation that looks natural.
+Doubtlessly the result is not perfect (and lines may get quite long), but it
+is definitely more readable than the output normally produced. Since layout
+and comments of the source file need to be preserved by \.{CTANGLE}, this
+option consumes significantly more memory than its contrary.
+
+The option `\.{+d}' causes \.{CWEAVE} to issue a warning when it
+could not properly parse some piece of \Cee~code; this could happen either
+because a code fragment is incomplete in the sense that it does not
+represent a single complete syntactic entity (as in the `\.{|<=n|}' example
+above, or when a module body ends with a label without a following
+statement), or because the code is actually unsyntactic, or because
+\.{CWEAVE} has been fooled by an unusual construction. In all cases however
+the result can be (very) badly formatted output, and a correction should be
+made; users who care about the quality of the typeset output are advised to
+always set this option (or at least when the document is being finalised).
+Setting the `\.{+d}' switch is equivalent to placing a control code \:1 at
+the beginning of the first section; the nature of the warning messages and
+possible remedies will be discussed later in this manual.
+
+The two output files that the option `\.{+t}' will cause \.{CWEAVE} to create
+in addition to its main output file, are called \.{\<name>.idx} and
+\.{\<name>.scn}, where \<name> is the name of the main output file without
+its extension. These files will be read by `\.{\\input}' commands in the
+main output file, so that the typeset document will not be any different; on
+large projects however it can be helpful to have this information on
+separate files, for instance for making a global index. The option `\.{+e}'
+is intended for use with two-sided printers: it ensures that the table of
+contents comes out on a fresh sheet of paper, so that it can conveniently be
+moved to the front.
+
+The option `\.{+i}' (or equivalently `\.{-i}') can be used to specify a
+directory for \.{CWEAVE} to search for header files in \:h commands.
+Although directory structures are system-dependent, \CWEB. assumes that a
+file can be looked up in a specified directory by prefixing a string
+indicating that directory to the file name (this works for many systems);
+the desired prefix string should then be supplied as the remainder of the
+option string after the `\.i' character. E.g., on the \caps{UNIX} system the
+author uses, \.{CWEAVE} can be told about the location of the `Xlib' header
+files by supplying an argument `\.{+i/usr/local/X11R5/include/}' (one could
+replace `\.{+i}' by `\.{-I}' to make it look more like the similar option
+passed to the \Cee~compiler); the important thing to note is the final
+pathname separator `\./'. Up to~8 additional prefixes can be specified by
+giving several such arguments; they will be tried in order from left to
+right. It is also possible to fix one such prefix at compile time, by
+defining the preprocessor symbol `\.{CWEBHEADERS}' to be the desired prefix
+string when compiling the compilation unit \.{common.c} of \CWEB.; this will
+behave as if it were the first prefix specified by a `\.{+i}'~argument.
+
+The last five options mentioned will alter layout style of program fragments.
+The option `\.{+f}' will result in a more vertical style than the default,
+and `\.{+a}' will do so even more; the difference between them is that
+`\.{+f}' will not force a simple statement to start on a new line if it
+follows a label or the condition of an \&{if} or \&{while} statement,
+whereas `\.{+a}' will start a new line in such cases. The option `\.{+u}'
+selects a style in which corresponding opening and closing braces are
+unaligned because a line break is inserted after~`$\{$' instead of before~it.
+The option `\.{+w}' on the other hand selects a brace style that has more
+vertical symmetry than the default one, since opening braces will appear on
+a line by themselves, like closing braces; the price is that listings will
+consume more paper. The option `\.{+a}' overrides `\.{+f}', and similarly
+`\.{+w}' overrides `\.{+u}'. Finally, the option `\.{+m}' is for people
+(like the author) who are extremely keen on saving paper: it avoids forced
+line breaks between the declarations in a compound statement, just like they
+are not placed by default between the statements; the separation between
+declarations and statements within a compound statement is still indicated by
+a line break, that even has some extra vertical space, because this
+separation is significant in the \Cee~syntax (unlike the \Cpp~syntax).
+
+In compatibility mode, specified by `\.{+c}', both \.{CTANGLE} and
+\.{CWEAVE} modify their behaviour in such a way that they try to ensure that
+they can handle any file that can be correctly processed by \LKC., and that
+the output is an equivalent \Cee~program, respectively a valid \TeX~file
+(this is the hard part) that produces a comparable printed document. In the
+current version this claim can only be made for programs written in~\Cee; a
+wholehearted attempt to do the same for \Cpp~programs would cost a
+substantial amount of extra work. There are so many differences in the
+details of formatting between \CWEBx. and \LKC. that one cannot expect
+formatted output that is identical to what would be produced under \LKC.,
+but to get the best approximation, one should in addition to~`\.{+c}'
+specify the options~`\.{+uft}'.
+
+The option `\.{+s}' is included because the \CWEB. utilities use statically
+allocated memory areas, which may therefore run out; using this option one
+can see how close one is to the limits of \CWEB.. The most important limited
+resources that it provides information about are are: \ (a)~The name tables
+in which \.{CTANGLE} and \.{CWEAVE} store all distinct identifiers and index
+entires, respectively module names (the entries `identifiers', `module
+names', and `bytes'); \ (b)~\.{CTANGLE}'s main memory, in which the complete
+\Cee~program file processed during a single run has to be stored, albeit in a
+compactified form (`replacement texts' and~`tokens'); \ (c)~\.{CWEAVE}'s
+cross-reference memory, in which all the data for the index and list of
+module names are stored (`cross-references'); \ (d)~its parsing buffers,
+which must be able to hold any one program fragment or piece of
+\Cee~code (`scraps', `texts', and~`tokens'). There should be no immediate
+need to increase the size of these memory areas, since even for the main
+program of \.{CWEAVE}, the largest of \CWEB.'s own compilation units, the
+use of any of these resources is less than a third of the amount available.
+There is one resource of which a larger fraction is used, namely `trie
+nodes', but its usage depends only on the set of grammar rules used, which
+is independent of the particular \CWEB. source file. When for some source
+file \CWEB. is approaching its limits, one can of course try to recompile
+\CWEB. with larger arrays, but alternatively one may restructure the source
+file: when one of (a),~(b), or~(c) runs out, one might consider breaking up
+the file into several separately processed pieces; when (d) runs out, a
+remedy could be splitting up some huge module body into smaller ones, by
+introducing submodules or multiple definitions of the module.
+
+Switching to the \Cpp~language has only a minor influence on the operation
+of \CWEB.: one-line comments starting with `\.{//}' will be recognised, the
+main output file produced by \.{CTANGLE} will have default extension `\.{.C}'
+instead of~`\.{.c}', and \.{CWEAVE} will recognise a few more reserved words
+and use a slightly different syntax. Since there is no general agreement
+about the proper extension for \Cpp~files, and alternative default extension
+for \Cpp~mode (instead of \.{"C"}) may be built in by setting the
+preprocessor symbol \.{CPPEXT} to the desired string (that should not
+contain the leading period) when compiling \.{common.c}. Currently the
+\.{CWEAVE} grammar will handle only a basic subset of the \Cpp~language,
+which does not include templates or exception handling.
+
+\subsection File name arguments
+
+Any command line arguments that do not have the form of an option are taken to
+indicate file names; their number can vary from 1~to~3. The first one specifies
+the main source file, the second (if present) indicates the change file, and
+the third optionally defines a non-standard name for the main output file.
+The contents and function of the change file is discussed in the next
+section; here we we just indicate how the actual file names used are derived
+from the given file name arguments. As far as \CWEB. is concerned a file
+name is composed of a base name and an extension. Loosely speaking, the
+extension of the main file defaults to~`\.{w}', that of the change file
+to~`\.{ch}', and that of the output files to `\.{c}' or `\.{tex}' for
+\.{CTANGLE} respectively \.{CWEAVE} (but see also the discussion of the
+`\.{++}' option above); the base names of the change file and the main
+output file default to that of the main file. If in place of a change file
+name an argument `\.-' is specified, no change file is used; also if only
+one file name argument was given, or if the change file name was specified
+as `\.+', then the default change file name is tried, but if no such file
+exists, processing proceeds without a change file. (Specifying the change
+file as `\.+' is only useful if a third file name argument is given.)
+Therefore, assuming regular naming conventions, there is no need to specify
+more than the main file name without extension, whether or not a change file
+is being used.
+
+The precise rules are as follows. On file systems where an extension is not
+a standard property of file names, like that of \caps{UNIX}, it is assumed
+the a period is a valid character in file names; a full file name is then
+formed by concatenation of the base name, a period and the extension (note
+that this implies that on such systems \CWEB. cannot access files whose name
+contains no period at all). Conversely, a string designating a full file
+name is broken up into a base name and an extension at the last occurrence
+of a period; if no period is present, then the string is taken to specify a
+base name only, and is said to have no extension. If the first file name
+argument has an extension, it specifies both base name and extension of the
+main source file, otherwise it specifies the base name, and the extension is
+taken to be~`\.w' (if no such file is found, the extension `\.{web}' is also
+tried, but this feature is obsolete). The base name of the main source file
+is also the default base name of the change file and the main output file;
+their default extensions are as described above. If a second and possibly
+third file name argument is present and is not `\.+'~or~`\.-', it overrides
+the base name, and also the extension if it has one, of the change file
+respectively of the main output file. No change file will be used either if
+the second file name argument is `\.-', or if no change file is found when the
+second file name argument is `\.+' or absent.
+
+
+\beginsection Subsidiary input files and change files
+
+As we have described it so far, the \CWEB. tools read a single source file,
+from which a main output file and possibly some auxiliary output files are
+produced. Since \Cee~programs can be built from several compilation units,
+it is not uncommon that several \CWEB. source files contribute independently
+to the same program, and there might be non-\CWEB. source files as well.
+However, even what is conceptually a single \CWEB. source, described by a
+single printed document, may in fact be composed from several input files.
+Two mechanisms are provided for combining information from several files,
+with different purposes. First, subsidiary files may be read in from the
+main source file in a way similar to the way \&{\#include} files are handled
+by a \Cee~compiler. In the case of \CWEB. however, the main purpose is
+usually not to share information among several sources, but merely to allow
+breaking up large source files into more easily manageable parts. Second
+there is the change file mechanism already mentioned above, which serves to
+install system dependent patches to a master source, allowing that master to
+remain free of system dependencies.
+
+When a line of the form `\.{@i}~\<file name>' appears in a \CWEB. source
+file, \CWEB. will read in the indicated file at that point, and continue
+reading at the next line when it reaches the end of the subsidiary file. The
+\<file name> may either be delimited by white space, or be enclosed in
+double-quote characters (but not in angle brackets). Source files may be
+nested in this way up to 10~levels deep. Nothing in the printed \CWEB.
+document will indicate the switch from one source file to another, nor will
+there be any effect on the \Cee~file(s) written by \.{CTANGLE}, except that
+\&{\#line} directives will of course always point to the proper point of
+origin for each piece of code written to such files.
+
+Like for header files, there is a way to indicate that if a file included by
+\:i is not found in the current directory, an alternative place can be
+tried; unlike header files however there is relatively little need to use
+this facility, unless one has files that are useful to include identically
+in more than one project. At most one alternative place to search can be
+given, and it is specified by a prefix to be applied to the file name, in
+the same way as for header files. This prefix may either be compiled into
+the \CWEB. programs by setting the preprocessor symbol \.{CWEBINPUTS} equal
+to that string when compiling \.{common.c} (analogously to \.{CWEBHEADERS}),
+or it can be specified at run time by setting the environment variable
+\.{CWEBINPUTS}; when both methods are used, the latter takes precedence.
+
+The change file, if present, contains a sequence of ``changes'', each of
+which specifies the replacement of one or more lines from the main input
+stream by another set of lines. Each change has the form `\.{@x} \<original
+lines> \.{@y} \<replacement lines> \.{@z}', where each of the codes \:x,
+\:y, and~\:z occupies a line by itself. The \<original lines> is a non-empty
+set of lines that should match exactly with some sequence of lines in the
+main input stream (except for the fact that trailing white space on any line
+is ignored). Furthermore, different changes should affect non-overlapping
+sets of lines, and their order in the change file should be the same as that
+of the parts of the main input stream that they replace. For each change in
+succession, a sequence of lines matching \<original lines> is searched for,
+and replaced by the corresponding \<replacement lines>; like for \:i file
+insertions, the resulting stream of lines will be processed in the usual way
+as if it constituted a single \CWEB. source file. The ``main input stream''
+referred to here is the result of (recursively) inserting any auxiliary
+files indicated by \:i lines into the main \CWEB. source file. It therefore
+makes no sense to specify \:i in the \<original lines>, nor is \:i allowed
+in the \<replacement lines>: it should simply not occur anywhere in the
+change file. On the other hand it is legitimate for the \<original lines> to
+match a sequence of lines coming from more than one physical source file.
+
+The fact that input is temporarily switched to the change file is not
+entirely transparent to the \CWEB. document, as it was in the case if \:i
+files: \.{CWEAVE} will mark all sections that were modified under control of
+the change file, by attaching an asterisk to their section number, and to all
+references to that number. (If some changes should add or remove entire
+sections in the middle of the \CWEB. source, which is allowed although not
+encouraged, then the section numbering will be altered, but sections for
+which this is the only change will not be flagged with an asterisk.) If one
+is only interested in sections that are modified, then it is even possible
+to restrict printing to only those sections, by including the \TeX~command
+`\.{\\changesonly}' in the text in limbo, preferably by means of the change
+file.
+
+In order to facilitate efficient implementation of the change file
+mechanism, an additional constraint is placed on the changes: once an exact
+match of a line in the main input stream with the first line of a change is
+found, the remaining lines of the change (up to the \:y) should also match.
+Any empty lines immediately following \:x are not used for matching (and are
+in fact completely ignored) so the first matching line is never an empty
+one; it is preferable to choose changes such that their first line matches a
+unique line of the main input. It is a good idea to start changes in the
+\TeX~part of sections (after all, if the program changes, so should its
+explanation); in this case uniqueness of the match of the first change line
+can always be ensured (even when the \TeX~part is empty) by placing a
+\TeX~comment in the main input, that serves merely as a target for
+replacement by the change file. All text in the change file that is not
+part of a change is ignored, except that there should be no lines starting
+with \:i, \:y, or~\:z; this text can be used for instance to explain the
+purpose of the change to the person installing the program on a new system,
+rather than to the ordinary reader of the program.
+
+As we have said earlier, the change file mechanism provides an alternative
+to system dependent conditional compilation, and it is usually a much more
+elegant way to incorporate system dependencies. The main reason for this is
+that one does not have to anticipate all possible systems that a program
+could be ported to, nor is the main source polluted by such considerations:
+it suffices to provide a separate change file each time the program is moved
+to a system with different system dependent requirements. Users of a
+particular system need to know about the change file for that system only,
+and the responsibility for maintaining main source and the change file might
+lie with different persons; additional effort is only required when the main
+source changes in such a way that a change file fails to match.
+
+One should not get carried away by the benefits of change files though: they
+provide only a rather crude mechanism (due to the inflexible matching
+rules), and if there are many changes, they will become difficult to
+maintain when the master file evolves. Portability is still best obtained by
+limiting system dependent features as much as possible, and if inevitable,
+confining them to some well defined part of the program. If one should wish
+to create variants of a program that involve significant changes, then
+writing extensive change files is probably not the best way to go. This
+method could lead to a form of ``rigor mortis'' for the original version of
+the program, caused by fear that any alterations could upset one of the
+change files, even trivial changes that only involve the commentary, or even
+just the layout of the source file. A better approach would be to collect
+routines of general utility as much as possible into separate compilation
+units used by all variants, and to complement these with completely
+independent compilation units to define the specific behaviour of each of
+the variants. It is certainly pointless to use a change file for such things
+as bug fixes or further development of a program; the whole idea is that
+such modifications can be made in the master file while the change files for
+various systems need little or no adjustment.
+
+The codes \:i, \:x, \:y, and~\:z of this section have the appearance of
+control codes, but they are not really part of the \CWEB. language, and
+obey different rules than control codes. For instance, they are line
+oriented (and rightly so, since their goal is to select which lines will be
+actually processed by \CWEB.): they should appear at the beginning of a
+line, and any further text on the line (in case of \:i, after the file name)
+is ignored. Also they act quite independently of \CWEB.'s current mode of
+operation: rules such as the one forbidding control codes in limbo do not
+apply to these codes.
+
+
+\beginsection Control codes for advanced or emergency use
+
+In this section we discuss control codes that are not essential for everyday
+use of \CWEB., but are provided to enable either refinements in the
+presentation of the \CWEB. document, or special manoeuvres to deal with
+certain unusual situations or requirements. Most of them serve to allow the
+programmer some form direct control over the contents of either the \CWEB.
+document, the \Cee~file, or the source file, bypassing the automatic
+processing by which these are normally related to each other; there are also
+a few that serve as debugging aid, eliciting explicit information from the
+\.{CWEAVE} parser about its actions.
+
+\subsection Control codes for cross-referencing:
+ \:!, \:\^, \:., \:?, \::, \:\#
+
+Some control codes are provided that allow the programmer to influence
+indexing and to perform explicit cross-referencing. The codes in this
+subsection are the only ones that are allowed to occur in the \TeX~part of
+sections, outside `\pb'; with the exception of~\:\#, they can also be used
+in \Cee~text. Control codes such as these, that are intended only to affect
+the printed document, are ignored completely by \.{CTANGLE}. Incidentally,
+cross-referencing in \CWEB. always means referring to section numbers rather
+than to page numbers: \.{CWEAVE} cannot know about page numbers since these
+are determined only at the \TeX\ processing stage. It would be possible to
+have \TeX\ produce a table mapping section numbers to page numbers; in fact
+the table of contents provides a coarse approximation to such a map.
+
+Whenever \.{CWEAVE} can determine from the context that an occurrence of an
+identifier is a defining one, it will make the corresponding section
+reference in the index underlined. If some case is missed by \.{CWEAVE}'s
+normal rules, or if one wants to make a reference to a reserved word (which
+is only made if it is underlined), then one can place the code \:! in front
+of the identifier to create an underlined reference. Cases where this may be
+required include arguments of functions with an old-style (pre-\caps{ANSI})
+heading for which no declaration is given before the function body (i.e.,
+the default type \&{int} applies), and enumeration constants that appear out
+of context of the \&{enum} keyword (e.g., because the enumeration list
+is given as a separate module). In general, the occasions where one needs
+\:! are quite rare.
+
+A group of three codes serves to include additional entries in the index,
+amidst those generated automatically by \.{CWEAVE} for identifiers. It may
+be useful for instance to maintain references to concepts like `system
+dependencies', or to all error messages that can be generated. The three
+codes are \:\^, \:., and~\:?; they differ only in the way the index entry
+will be typeset. In each case the index entry is specified as a control text
+terminated by \:>; control code and control text will be removed by
+\.{CWEAVE}, but the control text will appear in the index, followed by the
+section number(s) where the control code occurred. For \:\^,~\:., and~\:?,
+the index entry will be set respectively in roman type, in typewriter type,
+and as argument to the control sequence `\.{\\9}' (which is undefined in the
+standard format, but which the programmer may define in limbo). The first
+possibility is most suited for general concepts, the second for strings that
+occur in the program, and the third for any further special purpose one may
+think of. These control codes can be put either in the \TeX~part of a
+section or within \Cee~code; the effect will be the same, but this allows
+the programmer to put the control code in such a place that it is most
+likely to remain in the right place in case the section should be
+reorganised and possibly subdivided. Like for references to identifiers, one
+can make an index reference underlined by prefixing the corresponding
+control code with~\:!.
+
+Unlike the control text forming a module name, the control texts discussed
+here (as well as those that have not been introduced yet) should be
+contained in a single line of input; also, no spaces are contracted or
+removed. The control texts are passed unchanged to \TeX\ (with only `\.{@@}'
+being undoubled as usual), so that they can use \TeX~commands for special
+effects. Inside `\.{@.\dots@>}' one can get the special characters occurring
+in `\.{\#\$\%\^\&\{\}\~\_\\}' by prepending a backslash, `\.{\\v}' gives a
+vertical bar~`\.\v', and `\.{\\ }' gives a visible space `\.\ '.
+
+The control texts are also used as a sort key to determine the place in the
+index where the entry appears. Different occurrences of these control codes
+are combined in the index only if there is an exact match of both control
+code and control text, and no merging takes place with identifiers whose
+name happens to be equal to the control text (however, their relative order
+in the index is unpredictable). In sorting, a collating sequence is used
+that differs from the standard \ASCII. order: alphanumeric characters appear
+at the end of the sequence, with upper and lower case being considered
+equivalent, and the space character appears at the beginning of the
+sequence. In case there are entries that cannot be correctly positioned by
+ordinary means, the following trick has been suggested by Knuth: define
+`\hbox{\.{\\def\\9\#1\{\}}}' and represent the tricky entries as
+`\.{@?\<sort key>\}\{\<\TeX~code>@>}', where \<sort key> contains
+sufficiently many characters to uniquely determine the position of the entry
+in the index, and \<\TeX\ code> produces the index entry itself; this works
+because \.{CWEAVE} will write the index entry
+`\.{\\9\{\<sort~key>\}\{\<\TeX~code>\}}', which ``expands'' to
+`\.{\{\<\TeX~code>\}}'.
+
+Besides references from the index, \.{CWEAVE} provides cross-references, in
+the form of the section numbers that link the (first) defining occurrence of
+a module name with the places where it is used and cited. There is also a
+mechanism for the user to explicitly state similar cross-references in the
+\TeX~part of a section, so that it is possible make a reference to another
+section (where some related matters are treated), that will remain correct
+if sections are renumbered. The mechanism is simple: in the section referred
+to, one places the control code~\::, followed by a control text serving as a
+label, and at the place of reference one uses \:\#, followed by the
+identical control text (both control texts are terminated by~\:>). The rules
+for placing \::\ are the same as for \:\^ and its relatives, except that
+\:!\ has no effect here; the control text will not appear in the index, and
+there is no conflict when the same string is used as an identifier or index
+entry.
+
+For~\:\# and its control text, \.{CWEAVE} basically substitutes the section
+number of the matching \::~code, but because there might be multiple
+occurrences of \:: with the same control text, the precise replacement rule
+is a bit more complicated. The replacing text is precisely what would follow
+``See also section'' in a cross-reference for a module name: one or more
+section numbers in increasing order, separated by commas and ``and'' as
+appropriate, and preceded by a space and, in case there is more than one
+section number, by an `\.s' before that space. This is set up so that a
+reference of the form `\.{section@\#label@>}' will generate a proper
+reference, whether or not there are multiple definitions of the label. One
+can also use `\.{\\Sec@\#label@>}' since in the standard format `\.{\\Sec}'
+expands to `\Sec' and `\.{\\Secs}' to `\Secs' (in this case the space
+produced by~\:\# is ignored after the \TeX\ control sequence); by defining
+other \TeX~macros one could do anything one likes with the text provided
+by~\:\#. Although \:\# cannot be used directly in comments and module names,
+it is possible to capture its text in a macro definition (within a
+\TeX~part) and use that macro instead.
+
+\subsection Control codes for layout in programs:
+ \:,, \:|, \:/, \:), \:\\, \:+, \:;
+
+As we mentioned before, \.{CWEAVE} formats the program fragments and pieces
+of \Cee~code by inserting formatting controls in the the output based on a
+syntactic analysis of the \Cee~tokens of the program fragments; in
+particular the layout of the code in the source file is completely ignored.
+Although this automatic formatting usually works well provided that
+\.{CWEAVE} succeeds in parsing the program fragment (possibly with help of
+some codes already discussed), there may still be occasions where one is not
+quite satisfied by the result. If one wishes certain constructions to be
+systematically treated in a different way, then a more pleasing style might
+be available by calling \.{CWEAVE} with certain options set; if not, then
+there is always the possibility of changing the grammar or layout rules of
+\.{CWEAVE} (that program was written in a way that tries to make this as
+easy as possible, but it still requires some careful study of the relevant
+chapters of the \.{CWEAVE} source document). However in some cases one
+simply wants to override the general rules in specific cases by adding or
+removing a few formatting controls. There are a number of control codes
+which can be used to do that. These codes are ignored by~\.{CTANGLE}; since
+most of them deal with line breaks, their importance for `\pb' fragments is
+minimal.
+
+The control code \:, will insert a thinspace (a small amount of horizontal
+white space) where it is placed. Within an statement \:| may be used to
+indicate a place where a line break may be optionally taken (with no
+associated penalty), when the statement is too long to fit on a single line.
+Note however that optional breaks are already allowed at most operator
+symbols, with a penalty that increases with the operator priority and the
+number of enclosing parentheses, so \CWEB. will almost always succeed in
+finding very a reasonable break point in long expressions. A line break can
+be forced by~\:/; this can be used for instance between statements (if line
+breaks are not already forced there), in order to group related statements
+on one line rather than simply as much as possible. The code \:) will also
+force a line break, and in addition create a bit of vertical white space to
+give an even more visible separation. (\.{CWEAVE} will never issue more than
+one line break on the same place, so there is no problem if a line break was
+already present on that spot.) The code \:\\ is another variation: it forces
+a line break and backs up the next line by one indentation unit. It is
+useful before a module name that represents one or more cases in a
+\&{switch} statement: this will make the name line up with the case labels.
+
+Finally, \:+ cancels any (forced) line break that might be inserted by
+\.{CWEAVE} at the point where it is placed, and replaces it by a space with
+optional line break (the kind of space that is usually inserted between
+statements). Its main use is to force small conditional or loop statements
+onto a single line when \.{CWEAVE} would otherwise use a multiple-line
+layout. Because the line can still be broken at the inserted space, such
+one-liners do not make it impossible to retypeset the program in a narrower
+column. A warning is in place however if, as a result of applying \:+, a
+substantial stretch of \Cee~code is void of forced breaks, and that code
+contains constructions that affect the indentation level. \TeX nically
+speaking, the indentation at optional breaks is governed by the hanging
+indentation parameter of \TeX, whose value is constant throughout a
+paragraph, which in this case is everything between two forced breaks; under
+the mentioned circumstances the amount of indentation at optional breaks can
+be unexpected and inappropriate.
+
+For convenience, an alternative method is provided to fit compound
+statements on a single line, and similarly for \&{struct} and \&{union}
+specifiers. Instead of writing \:+ on every place where \.{CWEAVE} would
+otherwise force a line break (which incidentally depends on the chosen
+layout style), it suffices to place \:; immediately after the opening brace.
+This will activate a different set of layout rules than is normally used,
+which will not insert forced breaks between the declarations and statements
+of the compound statement, respectively between the fields of the \&{struct}
+or \&{union} specifier. In the case of a compound statement, any forced
+breaks caused by conditional or loop statements appearing directly inside
+the compound statement are also avoided (but nested statements are not
+affected, so they should be handled separately if present, possibly using
+another~\:;). Compound statements starting with `\.{\{@;}' will be treated
+as if they were simple statements in further parsing, which may affect
+formatting; for instance, if the statement is the branch of a conditional it
+will be placed on the same line as the \&{if} or \&{else} controlling it.
+If this is too much of a good thing, a forced break may be explicitly
+inserted at the beginning and/or end of the compound statement; in fact the
+sequence `\.{@/\{@;}' is a fairly common one.
+
+There is another use of~\:+, which does not cause any breaks to be
+cancelled, but where on the contrary the purpose is insert white space.
+It applies when a long string constant is needed, for which the
+string-break feature is used: a sequence of strings separated by white space
+only will be concatenated by the compiler into a single string. Although
+\.{CTANGLE} will correctly insert a space between any two consecutive
+strings, \.{CWEAVE} (guided by syntax rather than by lexical structure) will
+simply juxtapose them; by inserting \:+ between the strings, one guarantees
+that in the printed document there will either be a horizontal separation or
+(if the constituent strings themselves are already long) a line break.
+Incidentally, if the problem of breaking a string is in the source file
+rather than in the printed output, one can use the traditional solution of
+an escaped newline within the string; \.{CWEAVE} will treat this as if the
+parts of the string were on the same source line. If one should create a
+string in this way that does no fit on a single line of output, a break will
+be introduced automatically at a some point, which will be typeset as if a
+string-break was used. In very long strings however it is better to write
+string-breaks explicitly; for strings broken only by escaped newlines, the
+same length limit holds as for module names (1000~characters).
+
+\subsection Codes for special items in\/ \Cee~code:
+ \:p, \:v, \:t, \:\&, \:=, \:'
+
+Contrary to \TeX~text, pieces of \Cee~code are broken up into tokens by both
+\.{CTANGLE} and \.{CWEAVE}, stored internally and output at some later time
+after having undergone some processing. This makes it potentially difficult
+to put something into \Cee~code that \CWEB. is not prepared to handle. Since
+\Cee\ is a much more regular language that \TeX, occasions where one would
+need to do such a thing should be quite rare, yet some escape mechanisms
+have been provided, which we treat in this subsection.
+
+The code \:p can be used to explicitly specify the place where the
+preprocessor directives generated by \:d and \:h commands will be placed in
+the \Cee~file. Multiple use of \:p is allowed; as soon as it is used at
+least once, the default placement at the beginning of the \Cee~file is
+cancelled. This code provides the only way to write the directives generated
+by \:d and \:h to an auxiliary output file. In the formatted output this
+code is represented by the pseudo-module `$\ATP$', which (like preprocessor
+directives embedded in a program fragment) is set on a separate line and
+does not otherwise affect the formatting of the surrounding code.
+
+Two other codes are intended mainly for use within `\pb'. As mentioned
+earlier, \:v represents the bitwise-or operator. The code \:t is followed by
+a control text, which can be used to insert any \TeX\ symbols into a
+\Cee~expression; the result gets category \\{expression} but (if used in a
+program fragment) does not produce any actual \Cee~code. It is for instance
+possible to obtain `$\\{phi}<\hbox{$\pi$}/\T{2}$' by writing
+`\hbox{\.{| phi < @t\$\\pi\$@> / 2 |}}', or if one prefers, to get
+`$\\{phi}<\hbox{$\pi\over2$}$' by writing `\hbox{\.{| phi <
+@t\$\\pi\\over2\$@> |}}'. The control text is put into an \.{\\hbox} that
+will appear at the specified point in the formula. One might imagine using
+\:t as a means to sneak in \TeX\ commands that will modify the formatting
+produced by \.{CWEAVE}, but this is strongly discouraged unless one
+thoroughly understands that formatting and the way it is obtained.
+
+The codes \:\& and \:= are intended as a means to alter or bypass the
+processing of \Cee~tokens by \.{CTANGLE}; they should only be used in very
+exceptional situations. The code \:\& forces \.{CTANGLE} to output the
+symbols to the left and right of it directly adjacent to each other. Normally
+\.{CTANGLE} inserts space between two symbols if it thinks this is necessary
+for lexical reasons, regardless of whether a space was present in the input.
+Items with a lexical structure unknown to \.{CTANGLE} might confuse it, so
+that it would output a spurious space; this space could then be eliminated
+by~\:\&. For instance, an earlier version of \.{CTANGLE} would not recognise
+`\.{1000000UL}' as a constant, and consequently it output a space before
+the `\.U', so that the \Cee~compiler could not recognise it either; this
+problem could then be remedied by inserting~\:\&. No similar cases are known
+for the current version of \.{CTANGLE}.
+
+The code \:= can be used to place some text in the \Cee~file that \.{CTANGLE}
+will not produce by ordinary means: the control text following~\:=, up to
+the next \:> is copied verbatim to the \Cee~file (with `\.{@@}' undoubled as
+usual). If some special compiler activity, or some action by another tool, is
+triggered by the occurrence of some special form of comment in the \Cee~code,
+then such a comment can be placed using \:= (normally comments are removed
+by \.{CTANGLE}). Also, should \.{CTANGLE} unjustly decide that two symbols
+need no space in between them, then a space can be forced by writing
+`\hbox{\.{@= @>}}'
+\unskip\footnote{${}^\dagger$}
+{One case where this would be necessary is the famous example
+ `$\T{\^123E}+\T{1}$': the \Cee~standard states that unless a space is put
+ between the `\.E' and the `\.+', the preprocessor should treat this as a
+ single number (a~kind of mixture of a hexadecimal and a floating point
+ constant), which turns out not to be valid, causing an error. \.{CTANGLE}
+ however never places a space between an identifier and an operator (even if
+ one was present in the input), so the way to get this expression properly
+ through the compiler is to write `\hbox{\.{0x123E @= @> + 1}}' (since this
+ bug is now documented, it has become a feature).
+}.
+The control text will be set in typewriter type and
+framed in a box by \.{CWEAVE}, so that it stands out clearly; it is
+syntactically neutral (like a comment).
+
+Finally, the code \:' can be used to introduce a single-character constant,
+in the same way as the character `\.'' does in~\Cee. The difference between
+the two ways of specifying this value is that \.{CTANGLE} will replace
+\.{@'}$c$\.' by the (decimal) numeric \ASCII. value of the character~$c$,
+whereas \.'$c$\.' is passed on to the \Cee~compiler, which will evaluate it
+to the same value. The feature is therefore of little use in the current
+version of \CWEB., which assumes the \ASCII. character set, but is provided
+as an aid in writing programs that will be easier to port to non-\ASCII.
+versions of \CWEB.. In such systems \.{CTANGLE} should still use the \ASCII.
+code to compute \.{@'}$c$\.', while \.'$c$\.' represents the internal code
+for~$c$. The idea is that one can then (as is done in the program \TeX) map
+all characters on input to their \ASCII. equivalents, perform all internal
+manipulations independently of the externally used character set, and
+convert back to that code on output.
+
+\subsection Control codes behind the scenes: \:s, \:q, \:l
+
+The control codes of this subsection have in common that their use is never
+essential, but can be convenient in some situations, and is largely or
+completely invisible in the \CWEB. document. They are also the only control
+codes allowed in limbo.
+
+The code \:s has the same effect as \:f, but produces no output in the \CWEB.
+document. It can be used as a subsectioning code, just like \:f, but no
+comment should follow the two identifiers it applies to in this case (since
+there is nothing to attach the comments to); alternatively \:s can be used in
+limbo. In either case the format definition is noted but nothing is written
+to the \TeX~file. One might prefer to use \:s in situations where showing a
+\&{format} definition is considered to be more distracting than informative.
+Also, if a header file~$h$ is included by \&{\#include} rather than by \:h
+or is located in a place where \.{CWEAVE} cannot find it, and it contains
+typedef declarations, then~$h$ could be accompanied by a file containing a
+line `\hbox{\.{@s ident FILE}}' for each typedef identifier defined in~$h$,
+which can be read in by means of \:i by any \CWEB. file that includes~$h$.
+This method of passing information between files is more error-prone than
+having \.{CWEAVE} scan the header file however, so the latter method is to
+be preferred whenever possible.
+
+The code \:q is followed by a control text, and is completely ignored both
+by \.{CTANGLE} and \.{CWEAVE}; it can be used either in \TeX~text (even in
+limbo) or in \Cee~code. It can be used to make comments relevant only when
+the source file itself is being read, particularly within \Cee~code, where
+\TeX~comments cannot be used for this purpose. For instance, it can be used
+to put a descriptive or identifying comment at the beginning of a file
+included using \:i. This code can also be used to accommodate any other
+tools than \.{CTANGLE} and \.{CWEAVE} that might inspect the source file,
+e.g., if a text editor tries to match braces and the like, it is unlikely to
+correctly handle the complicated lexical structure of \CWEB. files in all
+cases, and an occasional brace contained in a \:q control text may help to
+keep it happy. Such occurrences of \:q are best removed however when source
+files are made public.
+
+The code \:l is used to allow certain 8-bit characters (i.e., characters
+with values in the range 128--255) to be used in identifiers. Doing so is
+only useful if measures are taken to ensure that \TeX\ can handle these
+characters properly. \TeX~version~3.0 and newer can handle 8-bit characters
+in the input, but the standard fonts do not have any characters in positions
+128--255, so one has to either load other fonts that do have characters in
+those positions, or define such characters to be active characters that
+somehow produce an appropriate glyph in the current font. For identifiers
+the relevant font is text italic (selected by `\.{\\it}'), but if these
+characters are available for identifiers, one will probably also want to use
+them in \TeX~text (including module names and comments), so other fonts
+should be provided for as well. \.{CWEAVE} does not take any special
+measures for 8-bit characters, and just passes them on to \TeX\ (when they
+occur in \Cee~code outside comments and module names, they are assumed to be
+part of an identifier). However, since such characters cannot be used in
+actual \Cee~identifiers, \.{CTANGLE} must replace them by characters that
+are valid in \Cee~identifiers (letters, digits, and underscores). The
+code~\:l can be used to specify which translation \.{CTANGLE} is to use for
+a given 8-bit character. The code should only be used in limbo, and have the
+form `\.{@l}~\<char number>~\<translation>', where \<char number> specifies
+the character by a pair of hexadecimal digits in the range \.{80}--\.{FF}
+(without leading `\.{0x}'), and \<translation> is a string of up to~9
+characters that are valid in \Cee~identifiers, terminated by a space. While
+copying limbo material, \.{CWEAVE} replaces \:l by `\.{\\ATL}'; its default
+definition will make `\.{@l}~fc~ue~' print a paragraph saying `{\bf letter
+\\{\"u} tangles as \tentex "ue"}', assuming that `\hbox{\.{\{\\it\\char
+"FC\}}}' indeed produces `\\{\"u}'; by stating `\.{\\noatl}' the definition
+can be changed so that nothing appears at all.
+
+\subsection Control codes for tracing {\tentex CWEAVE}:
+ \:0, \:1, \:2, \:3
+
+As will have become clear by now, the most sensitive part of \CWEB. is
+\.{CWEAVE}'s parsing mechanism, and occasionally something may go wrong
+with it, so that an awful result is produced. We have already discussed the
+means available for corrective action, but sometimes it can be a problem to
+find out just what is causing the trouble. Sometimes the reason is an actual
+syntax error, which is best located by applying \.{CTANGLE} and a
+\Cee~compiler to the \CWEB. source, but as noted before, \.{CWEAVE} may have
+a problem that a \Cee~compiler does not experience. For this reason, its
+parser can produce diagnostic messages on the terminal, showing details
+about its actions and any anomalies found. The amount of diagnostics
+produced is controlled by a level that may take values from~0 to~3, and can
+be selected by one of the control codes \:0, \:1, \:2, and~\:3. These codes
+can be placed in the \TeX~part of sections or within \Cee~code, and they
+determine the level until the next such code or the end of the file; the
+initial level is~0, or~1 if \.{CWEAVE} was called with the option~`\.{+d}'.
+Since a complete \Cee~fragment is read in before parsing starts, the level
+is constant throughout each fragment, and determined by the value at the end
+of the fragment.
+
+The diagnostic output uses abbreviations for syntactic categories, e.g.,
+`\.{unop}' and `\.{binop}' stand for unary respectively binary operators,
+and `\.{op}' stands for operators like `$*$' that can be used either way;
+`\.{exp}' stands for an expression, `\.{decl}' for one or more declarations,
+`\.{stmt}' for one or more statements. Simple symbols like braces and commas
+stand for themselves, as do many keywords; `\.{for}' stands for `\&{for}'
+or~`\&{while}', and `\.{int}' for a type, storage class specifier or typedef
+identifier. A complete list of category abbreviations can be found in the
+source code for the function $\\{print\_cat}$ in~\.{CWEAVE}.
+(To fully understand the parser's diagnostic messages one has to be familiar
+ with the parsing algorithm and the grammar rules, but for error detection
+ a detailed understanding is usually not required.)
+
+At level~$0$ the parser will not produce any diagnostic output. At level~$1$
+it will report any \Cee~fragment that could not be recognised as a single
+syntactic entity, which is a good indicator of grammatical problems and
+possibly of ugly output. It can be argued that level~1 is the natural level
+to use (which is why the `\.{+d}' option is provided), since not getting any
+diagnostics when there are syntax problems only gives a false impression
+that things are in order; after all, nobody would want to use a compiler
+that would spare the programmer its diagnostics for syntax errors, but
+instead would produce unreliable code. In a syntactically correct \CWEB.
+program it is almost always possible to apply \:f, \:;, \:[ and~\:] in such
+a way that no diagnostic output is produced at level~$1$; indeed this is has
+been done for all sources of \CWEBx. itself.
+
+The diagnostic messages produced at level~1 print the successive categories
+of the sequence of recognised items, which could not be combined into any
+larger entity. Interpreting such a message takes a bit of practice, as one
+has to guess which part of the program fragment corresponds to each category
+printed; however, a look at the (badly) formatted output can often be
+helpful. The boundaries between the entities corresponding to the printed
+categories can often be recognised by the fact that some form of layout is
+obviously missing, and a space appears instead; for instance, if a closing
+brace of a compound statement is not preceded by a line break, then
+something inside that statement must have prevented it from being recognised
+by the parser, and its opening and closing brace will occur among the
+printed categories.
+
+At levels $2$~and~$3$ the parser will print the result of every single step
+it takes; this extremely verbose mode can be used to trace the exact steps
+by which the parser obtains its result. Detailed knowledge of the set of
+grammar rules is assumed, and these levels are mostly useful to those who
+wish to study or modify the rules. The set of rules can be found as a
+chapter of the \CWEB. source document for \.{CWEAVE}, or can be obtained
+separately by running `\hbox{\.{cweave -x rules}}' (ignoring the warning
+about an unused module) and `\hbox{\.{tex rules}}'. After each reduction
+step the number of the rule used is printed, followed by a list of
+categories after reduction, with the one that was formed by the reduction
+step enclosed in inverted angle brackets. Tracing at level~$3$ is even more
+esoteric than at level~$2$: all categories printed will have an additional
+character at both ends, indicating whether \TeX\ should be in math mode
+(`\.+') or in horizontal mode (`\.-') at that end of the item, or that it
+doesn't matter (`\.?'); this may help to explain the positioning of math
+shifts (`\.\$') in the \TeX\ output, which is controlled indirectly by the
+grammar rules.
+
+To reduce the amount of output, all categories that have not yet been
+considered by the parser are replaced by an ellipsis. The sequence of
+categories before the reduction can be found by looking up the reduction
+rule with the given number. Here is some sample output for a simple piece
+of \Cee~code at level~$2$.
+\vfil\penalty500\vfilneg\smallskip\vbox
+{\narrower\obeylines\catcode`\_=12 \tentex \let\\=\BS \obeyspaces\let =\ %
+Tracing after l.3:
+@2 |if (n>0) printf("n-1 = \%d.\\n",n-1);|
+ 2: if ( >exp< ) ...
+ 10: if >exp< exp ...
+110: >if_head< exp ( ...
+ 6: if_head exp ( >exp< op ...
+ 3: if_head exp ( >exp< ) ...
+ 10: if_head exp >exp< ;.
+ 7: if_head >exp< ;.
+ 80: if_head >stmt<.
+117: >stmt<.
+}
+\smallskip
+We see that the first three steps reduce `\&{if}~$(n<\T{0})$' to an
+\.{if\_head}; then `$\.{"n-1\ =\ \%d.\\n"},n$' is combined to an expression,
+after which `${}-1$' is incorporated as well; then the statement calling
+\\{printf} is reduced in three steps, and finally it is combined with the
+`\.{if\_head}' to form another statement.
+
+Even this small example shows that \.{CWEAVE} parses the code in a
+different way than a \Cee~compiler would. This is partly due to its strict
+bottom-up strategy, which is largely unaware of context: parentheses
+(rule~10) and a comma (rule~6) are incorporated by the expression syntax,
+even when they actually figure in a conditional statement or function call.
+Furthermore, some distinctions are irrelevant for determining the
+proper layout: the ``comma operator'' is unjustly given precedence over the
+minus operator, but the printed output will be no different for it.
+
+
+\beginsection Some features of the standard format
+
+The \TeX~file produced by \.{CWEAVE} will begin with loading the standard
+format from the file \.{cwebxmac.tex}, whose definitions control the
+typesetting process: \.{CWEAVE} communicates with \TeX\ mostly by using
+macros defined there. Most of them have very short names, in order to limit
+the size of the \TeX~file; one should be aware that most of the
+single-letter control sequences and numerous two-letter ones are in use by
+\.{CWEB}, and are not available for other uses (when in doubt, consult
+\.{cwebxmac.tex}). All of the macros defined in plain \TeX\ for accenting
+letters have retained their meaning however, except `\.{\\.}' (for the dot
+accent), which is replaced by~`\.{\\:}'. Some of the macros of the standard
+format can be of interest to the literate programmer, either because they
+can be used directly in \TeX~text (indeed, some are not used by
+\.{CWEAVE}, and are only intended for this purpose), or because they can be
+redefined in limbo to alter the formatting of the program.
+
+In formatted \Cee~text, many operators are represented by macros that
+produce the appropriate symbols; by changing the definition of these macros,
+one can alter their appearance. Here is a table of the relevant cases.
+$$
+\everycr{\noalign{\hrule}}
+\def\:#1 #2
+{\vrule\vbox{\halign
+ {\strut\ \hfil##\hfil\ \cr \.{#1}\cr \.{\\#2}\cr $\csname#2\endcsname$\cr}
+}}
+\hbox
+{\vrule\vbox
+ {\hrule\hbox{ \strut\it operator }\hrule
+ \hbox{ \strut\it macro }\hrule
+ \hbox{ \strut\it symbol }\hrule
+ }%
+ \:= K \:== E \:!= I \:<= Z \:>= G
+ \:\&\& W \:|| V \:! R
+ \:\& AND \:| OR \:\^ XOR \:\~ CM \:<< LL \:>> GG
+ \:++ PP \:-- MM \:\% MOD \:-> MG \:\#\# SS
+ \vrule
+}
+$$
+When such a macro is redefined, it is best to consult the original
+definition first, since it often issues a penalty, and it is best to retain
+this. Formatting of ordinary identifiers and keywords is performed by
+`\.{\\\\}' and `\.{\\\&}', which have one argument, that is typeset in italic
+respectively boldface type; similarly `\.{\\.}' is used for items in
+typewriter type, such as strings and all-caps identifiers. In the argument of
+`\.{\\.}' special characters can be used if escaped, as discussed for \:..
+For `\AM' in ordinary text `\.{\\AM}' can be used (rather than `\.{\\\&}').
+For names in all caps, like `\caps{ASCII}', or `\caps{UNIX}', the macro
+`\.{\\caps}' is provided, which makes them slightly less obtrusive by
+selecting a smaller font; for `\Cee' and `\Cpp' the macros `\.{\\Cee}' and
+`\.{\\Cpp}' are provided. Typesetting of comments, \Cpp\ one-line comments,
+and numeric constants is controlled by the macros `\.{\\C}', `\.{\\SHC}',
+and~`\.{\\T}', respectively; these can be redefined if a different style is
+desired.
+
+The dimensions of the pages can be controlled by setting the parameters
+`\.{\\pagewidth}', `\.{\\pageheight}' (the height of the text area),
+`\.{\\fullpageheight}' (the height including running head), and
+`\.{\\pageshift}' (extra displacement of odd numbered pages with respect to
+even numbered ones), and then invoking the macro `\.{\\setpage}'. A
+magnification can be applied to the entire document by saying
+`\.{\\magnify\{$n$\}}',where $n$ is the magnification in thousandths of the
+ordinary scale; this should precede any changes of the page dimensions,
+but if no changes are made, the page dimensions will be set to their
+standard values, unmagnified. The unit of indentation can be set by
+`\.{\\indentation\{\<size>\}}'.
+
+The title of the program is taken from the macro `\.{\\title}', whose
+default value is the basename of the program source file, converted to upper
+case. It is used in running heads and in the table of contents. Another part
+of the running heads is set to the chapter title by sections starting
+with~\:*, but by defining the macro `\.{\\gtitle}' in limbo the
+corresponding text for the running heads on any pages before the first such
+section can be set (the default is `\.{CWEB} output'). By invoking
+`\.{\\titletrue}' the running head can be suppressed for one page; this is
+useful if the text in limbo produces a title page. The date of processing
+(by \TeX) can be included in the document before the first section by
+putting `\.{\\datethis}' in limbo; it can be placed on the table of contents
+by saying `\.{\\datecontentspage}'. At the end of the document one normally
+has an index, a list of module names and the table of contents, in that
+order, but \TeX\ can be made to stop short of any one of these by invoking
+respectively `\.{\\noinx}', `\.{\\nomods}', or `\.{\\nocon}'; as already
+mentioned, stating `\.{\\changesonly}' will limit the printed output to the
+sections affected by the change file. The appearance of the table of
+contents can be controlled by redefining `\.{\\topofcontents}' and
+`\.{\\botofcontents}': these macros determine the material that comes above
+the table and below it, including its title and the glue needed to fill up
+the page height. The page number of the table of contents is assigned from
+`\.{\\contentspagenumber}' (the default is~0), but it will not appear in
+print because the running head is suppressed on that page.
+
+It may be noted that \CWEB. documents contain some fixed phrases in the
+English language, such as the cross-references at the end of sections. These
+are not produced directly by \.{CWEAVE} however: one could adapt \CWEB. to a
+different language by redefining the macros `\.{\\A}', `\.{\\As}', `\.{\\Q}',
+`\.{\\Qs}', `\.{\\U}', `\.{\\Us}', `\.{\\ET}', `\.{\\ETs}', `\.{\\ch}',
+`\.{\\postATL}', `\.{\\ATP}', `\.{\\today}', `\.{\\now}', and parts of
+`\.{\\fin}' and~`\.{\\con}'.
+
+
+\beginsection Comparison with Levy/Knuth {\tentex CWEB}
+
+As was mentioned in the introduction, \CWEBx. is derived from an earlier
+\CWEB. system (itself derived from Knuth's \.{WEB}), that was written and
+distributed by Sylvio Levy and Donald~E. Knuth, and that \CWEB. system has
+independently evolved into a version currently distributed as \CWEB.~3.3.
+Both \CWEBx. and \LKC. have undergone changes with respect to their common
+ancestor, although the spirit of the system has not fundamentally changed in
+either case. Since we considered it undesirable to have a great divergence
+between systems that both intend to be ``a \caps{WEB} system for~\Cee'', we
+made a conscious effort to reduce the differences between \CWEBx. and \LKC.
+by including the extensions of the latter into \CWEBx. as well. There was
+one deliberate exception: we made no attempt to extend the grammar used by
+\.{CWEAVE} to handle the full \Cpp~language
+\unskip\footnote{${}^\dagger$}
+{\Cpp\ has a significantly more complicated syntax than that of~\Cee, which
+ is already far from simple, and it has some forms of context dependence
+ that make it doubtful whether to \.{CWEAVE} could ever reliably handle
+ \Cpp\ in full generality (and even then, \Cpp\ is a moving target). Most
+ effort was spent on getting the grammar for \Cee\ correct; support for
+ \Cpp\ was restricted to some extensions of~\Cee\ that could be incorporated
+ easily.
+}.
+On the other hand, hoping to fully bridge the gap between \LKC. and \CWEBx.
+for \Cee~programs, a compatibility mode was added to \CWEBx. in which it
+tries to mimic the behaviour of \LKC. in all aspects that are relevant to
+the programmer (even in cases where that behaviour is undocumented), at the
+price of losing some possibilities that \CWEBx. normally has.
+
+The description of the differences between \LKC. and \CWEBx. can be divided
+into two parts: the differences between \LKC. and the compatibility mode
+of~\CWEBx., and the differences between \CWEBx. with and without
+compatibility mode. The former differences are minimal, but hard to
+enumerate precisely, as they are mainly a matter of difference in
+implementation. The latter differences are much more significant, but they
+can easily be listed, since precise details of those differences can be
+found by looking up all index references of the identifier
+\\{compatibility\_mode} in the sources for the programs of~\CWEBx., and (for
+the differences that only involve processing by \TeX) the contents of the
+file \.{cwebcmac.tex} that modifies the \.{cwebxmac} format to emulate the
+environment provided by the \.{cwebmac} format of \LKC..
+
+As was stated, the differences between \LKC. and the compatibility mode
+of~\CWEBx. should not be relevant to the programmer, but if one uses \LKC.
+in a way that relies on knowledge of intimate details of its implementation
+(which are not described in the manual but can be learned from studying the
+sources), then it is certainly possible to find such differences; this
+applies particularly to using the \TeX~code produced by \.{CWEAVE} in
+unusual ways. Unfortunately there is no clear specification of which aspects
+of \CWEB. are well defined so that the user can safely rely on them, and
+which aspects are implementation details. We have taken a pragmatic attitude
+by reproducing all aspects that are described in the manual, and moreover
+many undocumented aspects, enough to process the sources of \LKC. itself and
+of the Stanford GraphBase without problems. To give an impression of the
+kind of differences that remain, we shall list some of the known ones.
+
+The output files written by \CWEBx. are not equal to those written by \LKC.,
+so processing them otherwise than directly by a \Cee~compiler respectively
+by~\TeX\ may reveal some deviations. For instance, entries for the index and
+the list of module names are written using the control sequence `\.{\\I}' by
+\LKC., but since `\.{\\I}' is also used for representing the operator
+`$\I$', this causes problems for module names in which that operator is
+used; therefore, \CWEBx. uses `\.{\\@}' instead. In \CWEBx. unbalanced
+braces or parentheses in program fragments or macro replacement texts are
+reported and corrected by \.{CTANGLE}, as an aid in catching programming
+errors early; in \LKC. this is not done (but programs with such unbalanced
+symbols will still bring \.{CWEAVE} into serious problems). In compatibility
+mode the definition of `\.{\\PB}' ensures that `\pb' can always be used from
+within math mode; in \LKC. this is true only in simple cases. Comments in
+the \TeX~parts of sections (following a non-escaped `\.{\%}' character) are
+ignored and removed by \CWEBx., whereas in \LKC. they are processed normally
+and copied to the output, which may cause spurious index entries, and in
+exceptional cases may cause part of the comment to appear in print. The
+grammars used by \.{CWEAVE} in the two systems are quite unrelated; for
+\CWEBx., the only guideline in constructing the grammar has been the
+\caps{ANSI/ISO~C} syntax. When processed by \CWEBx. with the proper options
+selected, \CWEB. documents will look similar to the result produced by
+\LKC., but not identical. Unlike \LKC., \CWEBx. places optional breaks at
+operators, reflecting their priority and nesting inside parentheses. In
+\LKC., if \:{\ } is immediately followed by a subsectioning code, then the
+output from the subsectioning code (e.g., \.{\#define} for~\:d) will be
+placed on the same line as the section number, but if anything, even an
+extra space, comes in between, or if the `\.@' in the sectioning code was
+followed by a newline rather than by a space, then that output is moved to
+the beginning of a fresh line; in \CWEBx. output from a subsectioning code
+never appears on the same line as the section number.
+
+\CWEBx. has a number of control codes and a number of command line options
+that \LKC. does not have; moreover there are some control codes that \LKC.
+does have, but under different names (that are used for other purposes
+in~\CWEBx.). In compatibility mode such control codes have the same
+interpretation as in \LKC., but if there is no such interpretation while
+there is one in \CWEBx., the latter is taken;. This means that in
+compatibility mode one can use the control codes \:v, \:\\, and \:\~, which
+are ignored in \LKC., while \:?~and~\:) can be used as aliases for
+\::~and~\:\#, respectively; furthermore the command line options controlled
+by the characters `\.l', `\.d', `\.t', `\.e', `\.a', `\.u', `\.w', `\.m',
+and~`\.+' are also extras with respect to \LKC.. Finally the control code \:;
+retains all its \CWEBx. uses in compatibility mode, except that of modifying
+the category of module names (which is different anyway), whereas in \LKC.
+it can only be used as an invisible semicolon.
+
+The most direct difference between \CWEBx. with and without compatibility
+mode is that in compatibility mode the control codes \:h, \::, \:\#, and~\:p
+are translated into respectively \:p, \:?, \:), and~\:c, which implies that
+the meaning of \:h, \::, and~\:\# as described in this manual are not
+available in compatibility mode. There is also an important syntactic
+adjustment: in compatibility mode module names are always treated as
+expressions (which means they must almost always followed by \:; to make the
+combination behave as a statement, or by `\.;', which will however become an
+empty statement in the \Cee~program). Then there are a few points where
+compatibility mode lifts certain restrictions (thereby reducing the
+diagnostic capabilities). All 8-bit characters will be accepted by
+\.{CTANGLE}, whether or not an explicit translation was specified using \:l;
+the default translation used corresponds to `\hbox{\.{@l \Cident{NN}
+X}\\{NN}}', where \\{NN} is the 2-digit hexadecimal code, in upper case, for
+the character. Module names used within `\pb' do not have to be the final
+item. Rather than performing \:i inclusions before the change file is
+matched, the order is more or less reversed (but if some \:i~line is not
+replaced by the change file, then the included file will again be scanned
+for changes); consequently \:i is allowed (and meaningful) in the change
+file.
+
+The remaining alterations affected by compatibility mode are fairly minor.
+Trailing digits in identifiers will not be set as subscripts. The \TeX\
+control sequence corresponding to identifiers that are given the category of
+\\{\TeX} by means of a format definition will be processed in math mode
+rather than horizontal mode. The code \:t together with the following
+control text will not be treated as an expression in parsing, but as an
+inert item that sticks to the token to the right of it (unlike comments that
+are attached to the token to their left); this allows `\.{@/@t\\4@>}' to be
+used in place of `\.{@\\}'. Compound assignment operators like `\.{+=}' are
+treated as two separate tokens; this implies among other things that the
+operator `\.{|=}' must be entered as `\.{@v=}' when used inside `\pb'. In
+index entries produced by \:\^, \:., or~\::, the underscore character will
+be automatically escaped by a backslash, unlike other special characters
+(this makes it harder to enter formulas with subscripts into the index).
+The output of `\pb' is made an argument to the control sequence `\.{\\PB}',
+whose default definition puts its argument into an `\.{\\hbox}'; this makes
+it safe to use `\pb' inside math mode when using compatibility mode.
+Finally there are a few other small changes to the format used: \Cpp\
+one-line comments will be formatted as if they were ordinary \Cee~comments,
+and the formatting of lines in the table of contents will be affected in
+font and spacing by the ``depth'' specified for that chapter title.
+
+
+\beginsection Summary of\/ {\tentt CWEB} codes
+
+For reference, we give a table with all the codes used in \CWEB. with their
+main characteristics. The letters in the column {\it where\/} indicate in
+which parts of the source text may immediately precede the code:
+`L'~indicates text in limbo, `T'~the \TeX~part of a section, `M'~indicates
+an intermediate part of a section (from \:d, \:h, ~\:f, or~\:s), `C'~the
+\Cee~part of a section, and `c' pieces of \Cee~code within~`\pb' (the
+letter~`M' is only used when the code terminates an intermediate part;
+inside the parts after \:d, \:h, and~\:f, the letter `C' applies). The
+column {\it frequency\/} indicates how commonly the code is used, with
+$\\{regular} > \\{incidental} > \\{rare} > \\{emergency}$; for the codes with
+$\\{frequency}\leq\\{rare}$, no sensible use could be found within any
+source file for the \CWEB. system itself. The codes \:0--\:3 that are only
+of temporary use are omitted from the table.
+
+\vfil\eject
+$$\vrule\vcenter{\hrule\smallskip\tabskip 1em
+\let\par=\cr\obeylines \def\title #1
+ {\noalign{\smallskip\hrule\smallskip\hbox{\sl\enspace#1}}}%
+\halign{\strut\.{#\unskip}\hfil & #\unskip\hfil & #\unskip\hfil & %
+ {\it#\unskip\/}\hfil & #\unskip\hfil
+\omit\strut\it code & \it meaning & \it where & \it frequency & \it remarks
+\title Sectioning codes
+@* & Start of chapter & LTMC & regular %
+ & \.{@**}, \.{@*$n$}, or \.{@*} Title\..
+@~ & Start of section & LTMC & regular
+@\~ & Start of section tied to previous one & LTMC & regular
+\title Subsectioning codes
+@c & Start of unnamed program fragment & TM & regular %
+ & also \.{@C}
+@< & Start of module name & TMCc & regular %
+ & \.{@<} Module name \.{@>}
+@d & `\.{\#define}'; start macro definition & TM & regular %
+ & also \.{@D}
+@h & `\.{\#include}'; specify included header file & TM & regular %
+ & also \.{@H}
+@f & Format definition; change syntactic category & TM & incidental %
+ & also \.{@F}
+@( & Start module name defining output file & TMCc & incidental %
+ & \.{@(} file name \.{@>}
+\title Parsing control codes
+@; & Invisible semicolon, or magic wand for syntax & Cc & incidental
+@[ & Start of item forced to expression & Cc & incidental
+@] & End of item forced to expression & Cc & incidental
+\title Cross-referencing codes
+@! & Make index reference underlined & TCc & rare
+@\^ & Index entry in roman type & TCc & regular %
+ & \.{@\^}index entry\.{@>}
+@. & Index entry in typewriter type & TCc & regular %
+ & \.{@.}index entry\.{@>}
+@? & Index entry formatted by `\.{\\9}' & TCc & rare %
+ & \.{@?}index entry\.{@>}
+@: & Define label for explicit cross-reference & TCc & incidental %
+ & \.{@:}label\.{@>}
+@\# & Explicit cross-reference to defined label & T & incidental %
+ & \.{@\#}label\.{@>}
+\title Layout control codes
+@, & Thin space & Cc & rare
+@| & Optional line break & Cc & rare
+@/ & Forced line break & Cc & incidental
+@) & Forced line break with vertical white space & Cc & incidental
+@\\ & Forced line break, next line backed up & Cc & incidental
+@+ & Cancel any line break, replace by space & Cc & incidental
+\title \Cee\ control codes
+@p & Insert output from \:d and \:h & Cc & rare %
+ & also \.{@P}
+@v & Bitwise or operator `$|$' & Cc & incidental %
+ & also \.{@V}
+@t & \TeX~code within expression & Cc & incidental %
+ & \.{@t}\TeX~code\.{@>}; also \.{@T}
+@\& & Glue together adjacent tokens & Cc & emergency
+@= & Insert verbatim \Cee~code & Cc & emergency %
+ & \.{@=}verbatim \Cee~code\.{@>}
+@' & \ASCII. constant converted to number & Cc & rare & \.{@'}$c$\.'
+\title Silent control codes
+@s & Non-printing version of \:f & LTM & rare
+@q & Ignored control text & LTCc & rare %
+ & \.{@q}any text\.{@>}; also \.{@Q}
+@l & Specify translation of 8-bit character & L & rare %
+ & \.{@l} $xx$ string ; also \.{@L}
+%\title Debugging level switches
+%@0 & Debugging off & TCc & temporary
+%@1 & Report parsing failures & TCc & temporary
+%@2 & Trace every parsing step & TCc & temporary %
+% & grammar maintenance
+%@3 & Trace every parsing step, show mathnesses & TCc & temporary %
+% & implementors only
+\title Miscellaneous codes (these are not control codes)
+@@ & Representation of `\.@' & LTCc & incidental %
+ & legal in control text too
+@i & Insert subsidiary source file & any & incidental %
+ & also \.{@I}
+@x & Start of change; old lines follow & any & incidental %
+ & also \.{@X}
+@y & Middle of change; replacement lines follow & any & incidental %
+ & also \.{@Y}
+@z & End of change & any & incidental %
+ & also \.{@Z}
+}\smallskip\hrule}\vrule
+$$
+
+\closeout\cont % the contents information has been fully gathered
+\vfill\eject
+\pageno=\contentspagenumber \secno=0 \titletrue
+\message{Table of contents:}
+\topglue 0pt plus 1.618 fil
+\centerline{\ttitlefont CWEBx\titlefont\space Manual}
+\vfil
+\def\Z#1#2#3{\line{\kern.1\hsize\indent\llap{#1}\quad #2
+ \leaders\hbox to .5em{.\hss}\hfil \enspace#3\kern.1\hsize}}
+\def\z#1#2{\line{\kern.1667\hsize #1
+ \leaders\hbox to .5em{.\hss}\hfil \enspace#2\kern.1\hsize}}
+\readcontents
+\vskip 0pt plus 2.618 fil
+\eject
+
+\bye
diff --git a/web/c_cpp/cwebx/parser.w b/web/c_cpp/cwebx/parser.w
new file mode 100644
index 0000000000..ecc46d119b
--- /dev/null
+++ b/web/c_cpp/cwebx/parser.w
@@ -0,0 +1,1233 @@
+@* Introduction to the grammar. @:title@>
+The most intricate part of \.{CWEAVE} is its mechanism for converting
+\Cee-like code into \TeX\ code, and we shall consider this aspect of the
+program now. This parsing mechanism must be able to deal with fragmentary
+constructions whose overall ``part of speech'' is not known (e.g., those
+within~`\pb'), which implies that recognition must in principle be able to
+proceed without any context information. Therefore a ``bottom-up'' approach
+is used, that collects successive tokens, and only takes action once it has
+seen enough to recognise a complete match with a syntax rule. Bottom-up
+parsing is a very powerful technique (it can handle grammars that are not
+tractable by many other parsing methods); it is one of the many significant
+contributions to computer science that the designer of the original \.{WEB}
+system, D.~E. Knuth, has made. Even so, the technique used here is less
+powerful than that of traditional bottom-up parsers produced by parser
+generators, since those can use information derived from the full
+left-context (and a small amount of right-context) to help decide difficult
+situations. In practice such context is not often required to unambiguously
+parse program fragments, and most situations where there is a possibility of
+incorrect recognition can be avoided be careful specification of the syntax
+rules to be used; this does however make formulation of the grammar a
+slightly subtle matter.
+
+As we have already seen, the input is represented as a sequence of
+{\sl scraps}, each of which specifies a {\sl category\/} and a
+{\sl translation}. The category defines a syntactic class, and the
+translation is a token list that represents \TeX\ code; the latter is
+effectively just a single string of characters, although it is stored in a
+different form for efficiency reasons. Rules of syntax and semantics tell us
+how to combine adjacent scraps into larger ones, and if we are lucky an
+entire \Cee\ text that starts out as hundreds of small scraps will join
+together into one gigantic scrap whose translation is the desired
+\TeX\ code. If we are unlucky (i.e., if the input is not properly formed
+for recognition by our parser), we will be left with several scraps that
+don't combine; their translations will simply be output, one by one.
+
+The parsing process is governed by a set of reduction rules, each of which
+specifies how a sequence of consecutive scraps with certain given categories
+can be combined into a single new scrap, and it also tells what category the
+new scrap has and how its translation is obtained from those of the original
+scraps. The set of reduction rules is given by a table, which is actually
+an initialiser for a static array, starting in section@#rules@>.
+In many cases a rule is simply given by listing the category codes
+forming its pattern (its left hand side) and the category code of the
+resulting scrap (the right hand side). For example, one of the reduction
+rules could be represented as
+$$
+\hbox{|expression| |binop| |expression|}\Rightarrow\hbox{|expression|}.
+$$
+For such simple rules the translations of the original scraps are simply
+concatenated to form the translation of the resulting scrap. The line in the
+table corresponding to this rule actually looks like this:
+$$
+\hbox{|{2,{{expression,binop,expression}},{expression, NULL}}|}.
+$$
+The `2' is the number used to identify the rule, which is useful when
+tracing the activities of the parser, and the |NULL| signifies that the
+default translation applies; the braces reflect the structure used to
+represent syntax rules, which has some additional components that are not
+specified explicitly here, and that are therefore initialised to~0.
+
+For other rules specific additional items are to be inserted in between the
+translations of the scraps that match the pattern. For instance, here is
+another rule present in the table
+$$
+\hbox{|{ 6,{{expression, comma, expression}},{expression,"__p1_"}}|}.
+$$
+Here the translation is specified by the ``format string'' |"__p1_"|, where
+the underscores stand for the translations of the three participating
+scraps, the `\.{p1}' for an |opt| token with argument~`\.1' (eventually
+producing `\.{\\penalty10}') that comes after the translation of the second
+scrap, with category |comma|. That translation will almost always be |","|,
+since there are no rules with |comma| as their right hand side, but if a
+comment follows the comma, it will have been incorporated into its scrap
+while preparing for the reduction, and in this case the optional break will
+follow the comment (and have no effect, because there is already a forced
+break after comments). The interpretation of all characters that can appear
+in the format strings can be found in section@#format@>.
+
+To handle all cases that can arise in programs, in combination with a large
+number of formatting options that might be selected, our mechanism for rules
+of a somewhat more general form than those presented above, but the
+extensions are used only for a few rules. Consider the following rule:
+$$
+\hbox{|{132,{{lpar,statement,statement},1},
+ {statement,"_B_"},forced_statements}|}.
+$$
+Here, the `1' indicates that the first scrap from the left in the pattern,
+|lpar|, serves as context only, and does not take part in the actual
+reduction. The rule therefore reduces a sequence of two consecutive
+statements into a single one, inserting a |break_space| (from the `\.B'
+format character) between their translations, but only if the statements are
+preceded by a left parenthesis (category~|lpar|); this restriction means
+that the rule will only apply to the first two semicolon-separated
+expressions following `|for|~|(|'. The entry |forced_statements| means
+moreover that the rule will not be used at all unless a `\.{+f}'~or~`\.{+a}'
+command line option was specified, which forces line breaks between
+consecutive statements; this rule then avoids such line breaks between the
+controlling expressions of a |for|-loop, since it takes precedence (see
+below) over the rule that normally combines statements.
+
+@ The rules are applied from left to right, as follows. Suppose we are
+currently working on the sequence of scraps with categories $c_1\,c_2\ldots
+c_n$. We try first to find a rule whose pattern matches an initial substring
+$c_1\,c_2\ldots\,$, and if no such rule exists, we try to find a rule
+applicable to the next substring $c_2\,c_3\ldots\,$; if that fails, we try
+to match $c_3\,c_4\ldots\,$, etc. When several patterns match, starting at
+the same scrap, the longest one is selected (no two rules can have identical
+patterns). For instance, there is a rule that reduces `|struct_like|
+|expression| |lbrace|' to `|struct_head|', and another one that reduces
+`|struct_like| |expression|' to `|int_like|'; the latter is only applied
+when no |lbrace| scrap follows. This is a sensible rule, since the longer
+pattern is the more specific one, and without such a rule it could never
+match. One should be aware however that this only works because the scrap
+with category |lbrace| represents a single token that requires no reduction
+to create it, for otherwise the two-scrap reduction would be applied before
+the three-scrap reduction would have a chance to match.
+
+One might say that we use a left-to-right eager strategy for choosing
+reductions; this strategy is chosen on heuristic grounds, and there is no
+guarantee that it will find a successful sequence of reductions if one
+exists. In other words, if we interchange left and right hand sides of the
+rules and view them as {\sl production\/} rules of a context free grammar,
+then the language generated by this grammar can be much larger than the one
+recognised by our parser. For instance, the context free grammar would, from
+the rules given above, generate expressions with multiple operators where
+implicit parentheses are placed arbitrarily (and therefore it would be
+ambiguous); our parsing strategy however will always place implicit
+parentheses to the left. (We don't care if implicit parentheses are placed
+incorrectly, because it does not influence typesetting.) It is an
+interesting theoretic problem to find an algorithm that will transform a
+set of reductions rules into a context free grammar generating exactly the
+language recognised; that would help to verify that the rules will work as
+intended. We must be cautious in formulating the rules, not only to give
+rules that are sufficient to reduce all desired programs, but also not to
+specify rules that could in certain circumstances match with precedence over
+the ones we intended for the situation.
+
+Some of the formatting of the output is controlled by the \TeX~format in the
+file \.{cwebxmac.tex}, rather than directly by \.{CWEAVE}. For instance, the
+`\.{\\penalty10}' mentioned above is actually written as `\.{\\31}'; the
+macro `\.{\\3}' will in fact raise the penalty for any enclosing pair of
+braces or parentheses; thus breaks in argument lists or initialiser lists
+will be avoided in favour of ones outside those lists. There are other
+effects not visible in the grammar, like optional breaks automatically
+associated with certain operators. In the whole it is a delicate interplay
+between the set of reduction rules, the reduction mechanism, the macro
+definitions, and the (mathematical) typesetting rules of \TeX\ that
+determines how programs will be typeset. This division of labour is quite
+convenient (e.g., it would tremendously complicate the task of \.{CWEAVE} if
+it had to decide which optional breaks should actually be taken), but it has
+the unfortunate consequence that it is not easy to gain a comprehensive
+understanding of the translation process. Indeed there have been quite a few
+surprises during the construction of the system, and we cannot be sure that
+there are no more to come; yet we believe the situation is more transparent
+than in the original |WEAVE|, since we have avoided rules that are oriented
+towards the target language (\TeX) rather than towards the source language
+(\Cee).
+
+@ Here is a list of the category codes that scraps can have. The category
+codes that apply to reserved words (e.g., |while_like|, but also
+|declaration| for |va_dcl|) as well as |expression| (that is used for
+|type_defined| identifiers in their typedef declaration) are sufficiently
+high that they can be distinguished from |ilk| values that are not category
+codes, like |type_defined|, |TeX_like|, |NULL_like|, |const_like|,
+and~|typedef_like|. A number of categories can occur in scraps, but do not
+occur in any of the reduction rules, since they are handled by other means;
+they have values exceeding |max_rule_cat|. The macro |valid_cat| checks
+whether |c| is a category that might match in a rule; it uses its argument
+twice, so its argument should not cause a side effect. If this section is
+changed, section@#category output@> should be changed correspondingly.
+
+@d max_category end_expr /* largest scrap category */
+@d max_rule_cat return_like /* largest category in rules */
+@d valid_cat(c) ((c)>0 && (c)<=max_rule_cat)
+
+@<Typedef and enum...@>=
+enum @/ @:categories@>
+{ unop = 1, /* a unary operator like `|!|' */
+ binop, /* a binary operator like `|<|' */
+ unorbinop, /* an operator that can be either, like `|-|' */
+ select, /* structure selection: `|.|' or `|->|' */
+ question, /* a question mark operator */
+ lbrace, rbrace, lpar, rpar, lbrack, rbrack,
+ /* `|{|', \ `|}|', `(', \ `)', `[', \ `]' */
+ comma, semi, colon, colcol, magic, /* `,', `;', `:', `$\CC$', \:; */
+ subscript, /* an array subscript, like `|[]|' or `|[i++]|' */
+ struct_head, /* the beginning of a struct specifier, like `|struct s{|' */
+ short_lbrace, short_struct_head, /* from `\.{\{@@;}', for one-liners */
+ compound_statement, /* a complete compound statement */
+ statement, /* a complete statement, possibly compound */
+ function, /* a complete function definition */
+ function_head, /* a function identifier followed by formal parameters */
+ parameters,
+ /* parameters in function declaration, or casting operator like `|(int)|' */
+ label, /* a statement label */
+ if_head, /* `|if|' followed by a (parenthesised) expression */
+ if_else_head, /* \lq|if @t\dots@>@; else|', \lq|while(@t\dots@>)|'
+ or \lq|switch(@t\dots@>)|' */
+ do_head, /* `|do @t\dots@>@; while|' */
+ mod_scrap, /* module name */
+ declarator, /* abstract declarator, like `|(*)(int,char*[])|' */
+ declaration, /* a complete declaration */
+ expression, /* an expression, possibly a single identifier */
+ while_like, /* `|for|', `|while|', `|switch|' */
+ do_like, /* `|do|' */
+ if_like, /* `|if|' */
+ else_like, /* `|else|' */
+ int_like, /* `|int|', `|char|', `|extern|', \dots */
+ case_like, /* `|case|', `|default|' */
+ sizeof_like, /* `|sizeof|' */
+ struct_like, /* `|struct|', `|union|', `|enum|' */
+ return_like, /* `|return|', `|break|', `|continue|', `|goto|' */
+ lproc, /* `\&\#' and following identifier starting preprocessor directive */
+ rproc, /* end of a preprocessor directive */
+ insert, /* comment or other syntactically inert item */
+ begin_expr, end_expr /* \:[ and \:] */
+};
+
+@ As we have already seen, tokens are converted to elementary scraps by
+the function |C_read|; these scraps form the `terminal symbols' of our
+grammar. The translation of tokens to scraps is largely governed by the
+static array |trans_ini|, whose initialisation values we shall now give.
+
+@d yes_math 1 /* should be in math mode */
+@d no_math 2 /* should be in horizontal mode */
+@d maybe_math 0 /* works in either horizontal or math mode */
+
+@< Initialiser for |trans_ini| @>=
+{ '!', unop, yes_math, "\\R" }, @/ @.\\R@>
+{ '~', unop, yes_math, "\\CM" }, @/ @.\\CM@>
+{ '/', binop, yes_math, "/" }, @/
+{ '<', binop, yes_math, "<" }, @/
+{ '>', binop, yes_math, ">" }, @/
+{ '.', select, yes_math, "." }, @/
+{ '=', binop, yes_math, "\\K" }, @/ @.\\K@>
+{ '|', binop, yes_math, "\\OR" }, @.\\OR@>
+ { or, binop, yes_math, "\\OR" }, @/
+{ '^', binop, yes_math, "\\XOR" }, @/ @.\\XOR@>
+{ '%', binop, yes_math, "\\MOD" }, @/ @.\\MOD@>
+{ '+', unorbinop, yes_math, "+" }, @/
+{ '-', unorbinop, yes_math, "-" }, @/
+{ '*', unorbinop, yes_math, "*" }, @/
+{ '&', unorbinop, yes_math, "\\AND" }, @/ @.\\AND@>
+{ '?', question, yes_math, "\\?" }, @/
+{ '(', lpar, yes_math, "(" }, @/
+{ ')', rpar, yes_math, ")" }, @/
+{ '[', lbrack, maybe_math, "[" }, @/
+{ ']', rbrack, maybe_math, "]" }, @/
+{ '{', lbrace, yes_math, "\\{" }, @/
+{ '}', rbrace, yes_math, "\\}" }, @/
+{ ',', comma, yes_math, "," }, @/
+{ ';', semi, yes_math, ";" }, @/
+{ ':', colon, maybe_math, ":" }, @/
+{ '#', insert, maybe_math, "\\#" }, @/ @.\\\#@>
+ /* this should occur only in macro definitions */
+{ at_sign_image, insert, maybe_math, "@@" },
+ /* this should not occur in legal \Cee~text */
+@)
+{ not_eq, binop, yes_math, "\\I" }, @/ @.\\I@>
+{ lt_eq, binop, yes_math, "\\Z" }, @/ @.\\Z@>
+{ gt_eq, binop, yes_math, "\\G" }, @/ @.\\G@>
+{ eq_eq, binop, yes_math, "\\E" }, @/ @.\\E@>
+{ and_and, binop, yes_math, "\\W" }, @/ @.\\W@>
+{ or_or, binop, yes_math, "\\V" }, @/ @.\\V@>
+{ plus_plus, unop, yes_math, "\\PP" }, @/ @.\\PP@>
+{ minus_minus, unop, yes_math, "\\MM" }, @/ @.\\MM@>
+{ minus_gt, select, yes_math, "\\MG" }, @/ @.\\MG@>
+{ gt_gt, binop, yes_math, "\\GG" }, @/ @.\\GG@>
+{ lt_lt, binop, yes_math, "\\LL" }, @/ @.\\LL@>
+{ mul_assign, binop, yes_math, "\\KK*" }, @/ @.\\KK@>
+{ div_assign, binop, yes_math, "\\KK/" }, @/
+{ mod_assign, binop, yes_math, "\\KK\\MOD" }, @/ @.\\MOD@>
+{ plus_assign, binop, yes_math, "\\KK+" }, @/
+{ minus_assign, binop, yes_math, "\\KK-" }, @/
+{ left_assign, binop, yes_math, "\\KK\\LL" }, @/
+{ right_assign, binop, yes_math, "\\KK\\GG" }, @/
+{ and_assign, binop, yes_math, "\\KK\\AND" }, @/ @.\\AND@>
+{ xor_assign, binop, yes_math, "\\KK\\XOR" }, @/ @.\\XOR@>
+{ or_assign, binop, yes_math, "\\KK\\OR" }, @/ @.\\OR@>
+{ thin_space, insert, yes_math, "\\," }, @/ @.\\,@>
+{ pseudo_semi, magic, maybe_math, "" }, @/
+{ force_expr_open, begin_expr, maybe_math, "" }, @/
+{ force_expr_close, end_expr, maybe_math, "" }, @/
+{ join, insert, no_math, "\\J" }, @/ @.\\J@>
+{ ellipsis, int_like, yes_math, "\\ldots" }, @/
+{ sh_sh, binop, yes_math, "\\SS" }, @/ @.\\SS@>
+{ colon_colon, colcol, yes_math, "\\CC" }
+
+@ Certain tokens that lead to fixed scraps are not included in the
+|trans_ini| array because their translations involve non-character tokens.
+Since there are only a few of them the easiest solution is to install each
+one explicitly into the |token_trans| array.
+@d start_scrap(s,c,m) p=&token_trans[s],p->cat=c, p->mathness=5*(m)
+@d end_scrap p->trans=text_ptr, freeze_text();
+
+@< Install the translations of tokens involving line breaks @>=
+{ scrap* p;
+ start_scrap(math_break,insert,maybe_math); /* \:\v */
+ app(opt), app('0'); end_scrap;
+@/start_scrap(line_break,insert,no_math); /* \:/ */
+ app(force); end_scrap;
+@/start_scrap(end_preproc,rproc,no_math); /* end of preprocessor directive */
+ app(force); end_scrap;
+@/start_scrap(' ',insert,no_math); /* space within preprocessor directive */
+ app(break_space); end_scrap;
+@/start_scrap(big_line_break,insert,no_math); /* \:) */
+ app(big_force); end_scrap;
+@/start_scrap(backup_line,insert,no_math); /* \:\\ */
+ app(backup); end_scrap;
+@/start_scrap(no_line_break,insert,no_math); /* \:+ */
+ app(cancel),app(relax),app(break_space),app(relax),app(cancel); end_scrap;
+@/start_scrap(include_preproc,insert,yes_math); /* \:p */
+ app(force),app_str("\\ATP"),app(force); end_scrap; @.\\ATP@>
+}
+
+@ When \.{CWEAVE} is compiled with the |DEBUG| switch, it can display
+its parsing steps. The order of strings in |cat_name| must match that
+in the |enum| declaration in section@#categories@>.
+
+@c
+@:category output@>
+#ifdef DEBUG
+void print_cat (int c) /* symbolic printout of a category */
+{ static char* cat_name[]=
+ { "unop", "binop", "op", "select"
+ , "?", "{", "}", "(", ")", "[", "]", ",", ";", ":", "::", "@@;"
+ , "subscr", "struct_head", "short_{", "short_struct_head"
+ , "cmp_stmt", "stmt"
+ , "function", "function_head", "params", "label"
+ , "if_head", "if_else_head", "do_head"
+ , "mod_name", "declarator", "decl", "exp", "for", "do", "if", "else"
+ , "int", "case", "sizeof", "struct", "return"
+ , "#{", "#}", "insert", "@@[", "@@]"
+ };
+ if (c<=max_category && c>0) printf(cat_name[c-1]);
+ else printf ("IMPOSSIBLE");
+}
+#endif /* |DEBUG| */
+
+@ Another major class of terminal symbols is formed by the reserved words.
+If a name exists in the hash table with an |ilk| specifying a reserved word,
+then |id_lookup| will return the reserved word when called with that name,
+and |C_read| will use the |ilk| to set the category of the resulting scrap.
+So all that has to be done is to get all the reserved words into the hash
+table with the right ilks initially. The simplest way to do this is to call
+|id_lookup| for all reserved words with the proper |ilk| at the beginning of
+each run of \.{CWEAVE}. Fortunately there are not too many reserved words.
+This code below uses the fact that instead of using pointers to beginning
+and end of a string for |id_lookup|, one may also pass a single pointer to a
+null-terminated string provided the other pointer is null.
+
+@^reserved words@>
+
+@<Store all the reserved words@>=
+{ int i; static char* int_likes[]=
+ { "auto","char","double","extern","float","int","long","register"
+ , "short","signed","static","unsigned","void" };
+ static char* defined_types[] =
+ { "FILE", "size_t", "ptrdiff_t", "wchar_t"
+ , "jmp_buf", "sig_atomic_t", "fpos_t", "div_t", "ldiv_t"
+ , "clock_t","time_t"
+ , "va_list"
+ };
+ static char* return_likes[]=
+ {"break","continue","goto","return"};
+ int int_like_nr=array_size(int_likes),
+ defined_type_nr=array_size(defined_types),
+ return_like_nr=array_size(return_likes);
+
+ for (i=0; i<int_like_nr; ++i) id_lookup(int_likes[i],NULL,int_like);
+ for (i=0; i<defined_type_nr; ++i)
+ id_lookup(defined_types[i],NULL,type_defined);
+ for (i=0; i<return_like_nr; ++i) id_lookup(return_likes[i],NULL,return_like);
+
+ id_lookup("case", NULL, case_like);
+ id_lookup("const", NULL, const_like);
+ id_lookup("default", NULL, case_like);
+ id_lookup("do", NULL, do_like);
+ id_lookup("else", NULL, else_like);
+ id_lookup("enum", NULL, struct_like);
+ id_lookup("for", NULL, while_like);
+ id_lookup("if", NULL, if_like);
+ id_lookup("sizeof", NULL, sizeof_like);
+ id_lookup("struct", NULL, struct_like);
+ id_lookup("switch", NULL, while_like);
+ id_lookup("typedef", NULL, typedef_like);
+ id_lookup("union", NULL, struct_like);
+ id_lookup("va_dcl",NULL, declaration);
+ id_lookup("volatile", NULL, const_like);
+ id_lookup("while", NULL, while_like);
+ id_lookup("NULL", NULL, NULL_like);
+ id_lookup("TeX", NULL, TeX_like);
+ if (C_plus_plus) @<Store reserved words for \Cpp@>
+}
+
+@ The main difference between \Cee\ and \Cpp, as far as \.{CWEAVE} is
+concerned, is that the latter has a number of additional reserved words. Most
+of them are sufficiently like some \Cee-reserved word (or category) that we
+can simply make it behave like that \Cee~symbol, without changing the syntax.
+For `\&{new}' and `\&{operator}', some additional syntax rules will be needed
+however; nevertheless we do not need to extend the set of syntactic
+categories. For `\&{operator}' we abuse the category |case_like|, since its
+proper use is rather restricted (`|case|' it is always followed by an
+expression, while `|default|', `\&{private}' and its relatives are always
+followed by a colon), so there will be no confusion with `\&{operator}', which
+is always followed by an operator symbol.
+
+@<Store reserved words...@>=
+{ id_lookup("asm", NULL, int_like);
+ id_lookup("class", NULL, struct_like);
+ id_lookup("delete", NULL, sizeof_like);
+ id_lookup("friend", NULL, int_like);
+ id_lookup("inline", NULL, int_like);
+ id_lookup("new", NULL, sizeof_like);
+ id_lookup("operator", NULL, case_like);
+ id_lookup("private", NULL, case_like);
+ id_lookup("protected", NULL, case_like);
+ id_lookup("public", NULL, case_like);
+ id_lookup("this", NULL, expression);
+ id_lookup("virtual", NULL, int_like);
+}
+
+@ There are a few more kinds of elementary scraps that the functions we have
+given before can produce, which we mention here for completeness. Ordinary
+identifiers get category |expression|, and their names will be expanded on
+output as argument to a control sequence that provides the proper formatting.
+For strings, constants, verbatim constructions, and \TeX~strings, the
+applicable control sequences and the constituent characters (escaped with
+backslashes where necessary) are written explicitly into token memory;
+their scraps also have category |expression|. Comments are converted to
+scraps of category |insert|, and their contents are also stored literally;
+in case of `\pb' fragments a reference to a text marked with
+|inner_text_flag| is stored, for the production of which the parsing
+mechanism has in fact already been invoked. By contrast module names are
+stored by reference to the name table, just like identifiers, and their
+scraps have category |mod_scrap|; in their case the parsing mechanism may
+be called during the {\sl output\/} process, if any `\pb' constructions
+occur.
+
+The final \TeX\ output produced for elementary scraps will often be marked
+with special control sequences. Ordinary multi-character identifiers are
+enclosed in `\.{\\\\\{}$\,\ldots\,$\.\}' (single character identifiers are
+merely preceded by a space; they will be set in math italic), identifiers
+whose |ilk| is |TeX_like| will become control sequences that are
+also enclosed in `\.{\\\\\{}$\,\ldots\,$\.\}' (to establish italic type),
+reserved words are enclosed in `\.{\\\&\{}$\,\ldots\,$\.\}', strings and
+all-caps identifiers in `\.{\\.\{}$\,\ldots\,$\.\}', constants in
+`\.{\\T\{}$\,\ldots\,$\.\}', and verbatim constructions in
+`\.{\\vb\{}$\,\ldots\,$\.\}'. Comments are enclosed in
+`\.{\\C\{}$\,\ldots\,$\.\}' and usually followed by `\.{\\6}' (a forced
+break), and module names take the form `\.{\\X$n$:}$\,\ldots\,$\.{\\X}'
+where |n| is the section number (since module names have
+|mathness==yes_math|, there is no danger that the final `\.{\\X}' will
+disable a following space when coming from a `\hbox{\.{\v@@< ... @@>\v}}'
+construction).
+
+@* The parsing mechanism. @:title@>
+Conceptually the working sequence of scraps is like a deck of cards, in
+which we repeatedly replace a sequence of consecutive cards by a single new
+card. Since such replacements never increase the number of cards, we can use
+sequential allocation for the current sequence of scraps, and our only
+difficulty will be how to conveniently fill the holes that might be left after
+each reduction step. Now reduction usually takes place near the beginning of
+the scrap sequence (assuming that the scrap sequence makes syntactical sense)
+because that is where we are looking first, and we want to avoid shifting
+down the whole remainder of the scrap sequence each time. Therefore the
+sequence of scraps, which initially occupies the positions from |scrap_base|
+to |scrap_ptr|, is allowed to have a hole in its middle, the low and high
+end of which are pointed to by variables |lo_ptr| and~|hi_ptr|. There is
+also a variable that points to the place where reductions are currently
+taking place, which is the parsing pointer~|pp|. It will always point into
+the area below the hole, and when it approaches the hole so closely that a
+potential reduction might involve scraps from above, the situation is
+remedied by sliding down scraps to the lower region, effectively raising the
+hole. Therefore the scraps in the higher region are those that have never
+been considered for a reduction yet. Eventually all scraps have been moved
+down (i.e., we have |hi_ptr==scrap_ptr|), and after that has happened a
+scrap with category~0 (which is not otherwise used) is copied down to signal
+the imminent end of the reduction process. When finally no more rules
+match the scraps in the lower region, the parsing stops.
+
+@< Global variables @>=
+scrap_pointer pp; /* current position for reducing scraps */
+scrap_pointer lo_ptr; /* end of sequence of scraps that have been examined */
+scrap_pointer hi_ptr; /* first scrap that has not been examined */
+
+@ The |mathness| is an attribute of scraps that says whether their
+translation is to be processed in a math mode context or not. Since the
+translation can be concatenated from a large number of other scraps, there
+can be switches in and out of math inside the translation, and we need to
+specify the mathness at each of the boundaries. For some scraps it either
+makes no difference whether their translation is processed in math mode or
+not, or the required mathness is to be determined by the grammatical context
+rather than by the scrap itself. Such scraps have mathness |maybe_math| at
+both ends; otherwise a definite mathness is specified at either end. The
+least significant pair of bits of the |mathness| field of a scrap controls
+the right boundary, and the pair of bits to its left controls the left
+boundary.
+
+@d left_math(a) (a->mathness>>2)
+@d right_math(a) (a->mathness&0x3)
+
+@ If we combine two scraps neither of which has mathness |maybe_math| at its
+boundaries, then a `\.\$' is inserted in between if and only if the
+mathnesses at the common boundary do not agree; if a scrap with |maybe_math|
+joins one with a definite mathness, that mathness is propagated across the
+former scrap to its other boundary. In order to implement this, we maintain
+two mathness values while building up a text: |init_mathness| and
+|cur_mathness| which represent the values at the left and right boundaries
+of the part contributed so far; these are local variables of whatever
+function is concatenating translations, but they should be called by these
+names since they are addressed by the macros below. As a consequence of the
+left-to-right order of combining translations, a |maybe_math| scrap that is
+combined with scraps with definite mathnesses, will actually be set in the
+mode inherited from its left (unless it appears as the leftmost scrap in a
+reduction); this can be used to make certain symbols, such as colons, behave
+in two slightly different ways depending on their syntactic function. (This
+method is not infallible however, as a comment following the symbol will
+always force it to be processed in horizontal mode; this happens because
+|insert| scraps are tacked onto the scrap before them before any ordinary
+reduction can affect it.)
+
+@ Before scraps requiring some definite mathness are contributed, we invoke
+|set_mode(yes_math)| or |set_mode(no_math)| as appropriate; the first time
+this happens will determine the value of |init_mathness|.
+
+@d set_mode(x)
+if (cur_mathness==maybe_math) cur_mathness=init_mathness=x;
+else if (cur_mathness!=x) {@; app('$'); cur_mathness=x; }
+else @; /* expect semicolon */
+
+@ The macro |app_trans| is invoked with a |scrap_pointer| as argument,
+and appends its translation as a single token; |add_trans| will in addition
+to this administrate |init_mathness| and |cur_mathness|, and interpolate
+any necessary math shifts.
+
+@d app_trans(a) app_tok(text_flag+text_index((a)->trans))
+@d add_trans(a)
+{ scrap_pointer scr=a; /* so that evaluating |a| may have side effects */
+ if (left_math(scr)!=maybe_math)
+ { if (cur_mathness==maybe_math) init_mathness=left_math(scr);
+ else if (cur_mathness!=left_math(scr)) app('$');
+ cur_mathness=right_math(scr);
+ }
+ app_trans(scr);
+}
+
+@ The function call |fuse(s,n)| will concatenate the translations of |n|
+scraps starting with |*s|, taking care of the mathnesses, and install the
+resulting text into |s->trans|.
+
+@c
+void fuse (scrap_pointer s, int n)
+{ int cur_mathness=maybe_math, init_mathness=maybe_math; scrap_pointer p=s;
+ check_toks(n); check_text();
+ do add_trans(p++)@; while (--n>0); /* gather all the translations */
+ s->trans=text_ptr; freeze_text();
+ s->mathness=(init_mathness<<2)+cur_mathness;
+}
+
+@ An |int_like| identifier following a |struct_like| token, a selection
+operator (`|.|' or `|->|'), or the special code \:;, is to be typeset as an
+ordinary identifier. The function |make_nonreserved| alters the flag of the
+token representing such an identifier occurrence. The scrap representing the
+|int_like| identifier should not be formed by any reduction, but come
+directly from |C_read|, so in principle we expect the translation of our
+scrap to be an unnested text consisting of a single token. However, a
+comment (or other |insert|) directly following the |int_like| identifier may
+complicate this picture slightly, because |insert| scraps are tacked onto
+the previous scrap before it gets the chance to take part in any reduction;
+this means our token may be buried inside one or more levels of text
+nesting, but still is the very first token of the translation. Any such
+levels of nesting are soaked off by the |while| loop below; after this
+process a single-token text should remain containing a reserved word, of
+which we replace |res_flag| by |id_flag| to make it print as an ordinary
+identifier.
+
+@c
+void make_nonreserved (scrap_pointer p)
+{ text_pointer q=p->trans; token t;
+ while (text_flag<=(t=text_begin(q)[0]) && t<inner_text_flag)
+ q=text_at(t-text_flag);
+ if (text_end(q)==text_begin(q)+1 && res_flag<=t && t<mod_flag)
+ text_begin(q)[0] = t-res_flag+id_flag;
+}
+
+@ We wish to mark defining occurrences of identifiers, triggered by the
+matching of certain reduction rules. Thanks to the unsurpassed
+declaration syntax of~\Cee, it is a non-trivial task to locate the
+identifier in question, since it may already have been wrapped up in a more
+or less complicated declarator or function heading. Fortunately the
+identifier is always the first one occurring in that expression
+\unskip\footnote{${}^\dagger$}
+{Due to the possible occurrence of the keywords |const| and |volatile| in
+ strange places within declarations, this is not entirely true. We will
+ arrange things however in such a way that unless we are forced otherwise by
+ enclosing parentheses, these keywords will remain outside the text that is
+ passed to |first_ident|. If we ignore the possibility of specifying
+ redundant parentheses, this only causes problems when one wishes to
+ declare certain peculiar things like constant function pointers.
+}, so a left-to-right scan through the, possibly nested, text forming the
+translation of the expression should reveal it. We accept either an ordinary
+identifier or a reserved word; the latter possibility is needed for typedef
+declarations. @^recursion@>
+
+@c
+id_pointer first_ident(text_pointer p)
+{ token_pointer q; token t;
+ if (p>=text_ptr) confusion("first_ident"); @.first\_ident@>
+ for (q=text_begin(p); q<text_end(p); ++q)
+ if (id_flag<=(t=*q) && t<mod_flag) return id_at(t%id_flag);
+ else if (text_flag<=t) /* text or inner text */
+ {@; id_pointer r=first_ident(text_at(t%id_flag));
+ if (r!=NULL) return r;
+ }
+ return NULL;
+}
+
+@ In the following situations we want to mark the occurrence of an
+identifier as a definition: in a declaration of a variable, as in
+`|xref_pointer *r@;|', when a label is declared, as in `|found:|', in the
+declaration of a function, as in `|char* f(int n){@t\dots@>@;}|', after a
+|struct_like| token (declaring a structure-, union-, or enumeration tag) and
+for all identifiers in an enumeration list. This is accomplished by the
+invocation of |make_underlined| at appropriate times.
+
+@c
+void make_underlined (scrap_pointer p)
+ /* underline entry for first identifier in |p->trans| */
+{ id_pointer name=first_ident(p->trans); /* name of first identifier */
+ if (name==NULL) return;
+ /* this happens for unsyntactical things like `|int 3;|' */
+ { sixteen_bits head=xref_index(name->xref),* r=&head; int n;
+ while ((n=xnum(*r)&num_mask)!=0 && n<section_count) r=&xlink(*r);
+ if (n==section_count) xnum(*r)|=def_flag;
+ else /* this may happen for one-letter identifiers */
+ { make_xref(section_count+def_flag,*r);
+ if (r==&head) name->xref=xref_ptr; @+ else *r=xref_index(xref_ptr);
+ }
+ }
+}
+
+@ We will now consider the how the reduction rules themselves are
+represented and used. As we have seen, a rule must define a sequence of
+categories for its left hand side, and for its right hand side a category
+and a prescription for constructing its translation. In addition, some
+categories of the left hand side may be marked as context, so that they will
+not take part in the reduction, and there is a way to specify conditional
+loading of rules. A few more pieces of information are included for
+convenience and efficiency.
+
+Individual reduction rules are stored in a structure called |reduction|.
+It is organised in a way that allows for semi-static initialisation, i.e.,
+the essential parts of information are stored near the beginning of the
+structure or of one of its sub-structures, so that they can be defined by
+an initialiser expression, while some further fields are computed from them
+and assigned at startup time. Within the fields that are statically
+initialised some fields that usually are~0 are put at the end, so that in
+the default case they can be omitted from the initialiser.
+
+The field |id| holds an identification number for the rule, which is used in
+debugging. Then follows the left hand side information, consisting of an
+array of at most |max_lhs_length| categories (which include those of a
+possible context; if less than the maximal number of categories are present
+they are padded with zeros), followed by integers |context| and |length|.
+The field |context| specifies which categories, if any, form the context:
+this can be a sequence of one or more categories at either end of the left
+hand side of the rule, but not at both ends. If |context==0| (as is the
+case if no explicit initialiser is specified), there are no context
+categories; when |context>0|, the first |context| categories form the left
+context, and when |context<0|, the last |abs(context)| categories form the
+right context. (In practice it is wise to use only token categories (ones
+that do not require reduction to be formed) for a right context, unless one
+can be quite sure that no unintended reduction will affect the categories
+taking part in the intended reduction before the right context has been
+reduced.) There must be at least one category that is not part of the
+context, lest a ``reduction'' would increase the number of scraps. The right
+hand side of a rule specifies a category and a string used as a format to
+build up the translation; for the common case that the translation is formed
+by concatenating the translations of all scraps of the left hand side (not
+including those those of the context), a null pointer may be given instead
+of a format string. The following field |mask| can be used to specify
+selective loading of rule at startup time: any bit set in it will suppress
+loading under some condition dependent on the setting of option flags in the
+call of \.{CWEAVE}. The field |displacement| is computed at startup time to
+record the number of positions (usually negative) by which the parsing
+pointer~|pp| should be changed after application of the rule.
+
+@d max_lhs_length 4
+
+@< Typedef and enumeration declarations @>=
+
+typedef struct
+{ short id; /* for debugging */
+ struct
+ {@; eight_bits category[max_lhs_length]; signed char context,length; } lhs;
+ struct {@; eight_bits category; char *translation; } rhs;
+ sixteen_bits mask;
+ short displacement;
+} reduction;
+
+@ We shall organise the rules in a ``trie'' structure for fast matching. If
+|q| points to a trie node reached after matching some sequence of
+categories, and that sequence corresponds to the left hand side (including
+context) of some rule (which should be unique), then |q->rule| points to
+that rule, otherwise |q->rule==NULL|. If that sequence of categories is a
+proper prefix of the left hand side of a rule (which may happen whether or
+not |q->rule==NULL|), and $c$ is the next category in that left hand side
+(which implies |0<c<=max_rule_cat|), then |q->next[c-1]| is the index of the
+trie node reached after a further match of~$c$. The entries of |q->next|
+that do not correspond to any such successor node are set to~0, which is
+unambiguous because the root of the trie does not figure as a successor of
+any node. We do not attempt a sparse representation (which would avoid
+storage of such 0's), but we do use a compact |eight_bits| representation
+for the entries of |q->next|; this saves a considerable amount of space,
+since there is a total of |max_rule_cat*max_no_of_nodes| such entries.
+
+@<Typedef...@>=
+
+typedef struct {@; reduction* rule; eight_bits next[max_rule_cat]; } trie_node;
+
+@ Trie nodes are allocated from an array |trie_node_mem|, with the root of
+the trie at |trie_node_mem[0]|. We introduce some macros that will help us
+find our way around the trie. The address the successor of the trie node
+pointed to by |q| for category |c| can be written as |successor(q,c)|. The
+absence of such a successor can be found by testing |no_successor(q,c)|. If
+|x| is the address of any node in the tree (except the root), then we can
+make that node the successor of |q| for category |c| by invoking
+|set_successor(q,c,x)|.
+
+@d trie_root (&trie_node_mem[0])
+@d successor(q,c)
+ (&trie_node_mem[(q)->next[(c)-1]]) /* category codes start at 1 */
+@d no_successor(q,c) ((q)->next[(c)-1]==0)
+@d set_successor(q,c,x) ((q)->next[(c)-1]=(eight_bits)((x)-trie_node_mem))
+
+@<Global...@>=
+trie_node trie_node_mem[max_no_of_nodes];
+int node_no = 1; /* number of trie nodes allocated */
+#ifdef DEBUG
+boolean install_failed=false;
+#endif
+
+@ Trie nodes are allocated in a straightforward sequential way. We don't
+trust that uninitialised statically allocated pointers will be |NULL|
+(although they should), especially not on machines where |NULL| is not
+represented as ``all bits cleared'', so we do a bit of extra work here. For
+the entries of the array |next| we expect no problems however (since
+|eight_bits| is an integral type), so we do not explicitly initialise them.
+
+@c trie_node *get_new_trie_node(void)
+{ if (node_no>=max_no_of_nodes)
+ overflow("trie node"); @.trie node capacity exceeded@>
+ trie_node_mem[node_no].rule=NULL;
+ return &trie_node_mem[node_no++];
+}
+
+@ The function |install_rule| installs a reduction, and if \.{CWEAVE} was
+compiled with |DEBUG| set, it also performs some checks on the validity of
+the rule; if any check fails the variable |install_failed| is set to |true|.
+Since |print| has a variable number of arguments, the macro |rule_error|
+does not incorporate them but just prepends |print| to the argument list;
+the replacement text of |rule_error| can therefore not be parenthesised, and
+the macro should be used with some care.
+
+@d rule_error install_failed=true,print
+ /* report a problematic syntax rule */
+
+@ A global variable |rule_mask| is set at startup time according to the
+relevant option flags; any rules~|r| for which |rule_mask & r->mask!=0| are
+suppressed. For each set of mutually exclusive settings, a number of bits in
+|rule_mask| is reserved equal to the size of the set; the current setting
+will have its corresponding bit set while the others are cleared. Therefore
+the bits set in |r->mask| specify the option settings for which the rule is
+disabled, and the default state |r->rule==0| means that the rule always
+applies, regardless of any optional settings.
+
+@< Global... @>= sixteen_bits rule_mask;
+
+@ The function |install_rule| enters a rule into the trie structure, and if
+|DEBUG| is defined, performs some sanity checks on the rule.
+
+@< Prototypes @>=
+void install_rule (reduction* rule);
+
+@~The length of rules can be found because category~0 is not used for scraps.
+@c
+void install_rule(reduction *rule)
+{ if ((rule_mask & rule->mask)==0)
+ { eight_bits* p=rule->lhs.category, i=0;
+ while (i<max_lhs_length && p[i]!=0) ++i;
+ rule->lhs.length=i;
+#ifdef DEBUG
+ @< Check left-hand side of |rule| @>
+ @< Check right-hand side of |rule| @>
+#endif
+ @< Install |rule| in the trie structure @>
+ @< Compute |rule->displacement|,
+ and modify |rule->lhs.length| and |rule->context| @>
+ }
+}
+
+@ The left-hand side should not be only context, and all categories should
+be legal ones.
+
+@< Check left... @>=
+{ if (rule->lhs.length<=abs(rule->lhs.context))
+ rule_error("\nNo scraps to replace in rule %d.\n", rule->id);
+ @.No scraps to replace...@>
+ for(i=0; i<rule->lhs.length; ++i)
+ if (!valid_cat(p[i]))
+ rule_error("\nUnknown category %d in LHS of rule %d.\n", p[i], rule->id);
+ @.Unknown category...@>
+}
+
+@ The right-hand side should have a valid category, and unless its
+translation is |NULL| (or |""| which we treat as if it were |NULL|), it
+should contain as many times |'_'| as there are non-context categories in
+the left-hand side.
+
+@< Check right... @>=
+{ int c=rule->rhs.category; char* s=rule->rhs.translation;
+ if (!valid_cat(c))
+ rule_error("\nUnknown category %d in RHS of rule %d.\n", c, rule->id);
+ @.Unknown category...@>
+ if (s!=NULL)
+ { if (*s=='\0') s=rule->rhs.translation=NULL; /* replace empty string */
+ else
+ { i=0;
+ do
+ if (*s!='p') i+= *s++=='_'; /* count underscores */
+ else if (++s,isdigit((eight_bits)*s)) ++s; /* skip digit and advance */
+ else rule_error("\nDigit should follow 'p' in format of rule %d.\n"
+ @.Digit should follow 'p'...@> , rule->id);
+ while (*s!='\0');
+ if (i!=rule->lhs.length-abs(rule->lhs.context))
+ rule_error("\nCount of '_' not equal to length LHS in rule %d.\n"
+ @.Count of '\_' ...@> , rule->id);
+ }
+ }
+}
+
+@ Since trie nodes are not represented sparsely, insertion is easy.
+
+@<Install |rule|...@>=
+{ trie_node* q=trie_root;
+ for (i=0; i<rule->lhs.length; ++i)
+ { if (no_successor(q,p[i])) set_successor(q,p[i],get_new_trie_node());
+ q=successor(q,p[i]);
+ }
+#ifdef DEBUG
+ if (q->rule!=NULL)
+ rule_error("\nIdentical left-hand sides in rules %d and %d.\n"
+ @.Identical left-hand sides...@> , q->rule->id, rule->id);
+#endif
+ q->rule=rule;
+}
+
+@ We compute |displacement| conservatively, based on local considerations;
+alternatively we might also consider the whole set of rules to find
+larger (less negative) values that would make parsing go a bit faster. A
+rule can have a left hand side of length |max_lhs_length|. This means that
+it is safe to move |pp| so that it will afterwards be |max_lhs_length-1|
+positions to the left of the first scrap that may have got a new category.
+
+After a rule has been installed, there is no need to record the full length
+of the left hand side, including context, since this is implicit from the
+place in the trie where the pointer to this rule is located; rather we store
+the number of scraps that will be replaced. Similarly it is more useful to
+know the offset of the first scrap to be replaced (which is~0 in case of a
+right context) rather than the value of |context| as stored at
+initialisation.
+
+@< Compute |rule->displacement|... @>=
+{ int k=rule->lhs.context,d;
+ if (k<0) {@; rule->lhs.length+=k; k=0; } @+else rule->lhs.length-=k;
+ d=1-max_lhs_length+k; /* this cannot be positive */
+ if (rule->lhs.category[k]==rule->rhs.category) /* no category change */
+ { ++d;
+#ifdef DEBUG
+ if (rule->lhs.length==1)
+ rule_error("\nNo categories change in rule %d.\n", rule->id);
+ @.No categories change...@>
+#endif
+ }
+ rule->lhs.context=k;
+ rule->displacement=d; /* if positive, an error was reported */
+}
+
+@ The function |match| tests whether the category pointed to by~|p|,
+and its successors, match the categories in the trie structure, starting
+at the root of the trie, and up to a node that contains a rule.
+Multiple matches are possible, in which case the longest one takes
+precedence. We avoid using a side effect in the argument of |valid_cat|.
+
+@c
+reduction *match (scrap_pointer p)
+{ trie_node* q=trie_root; reduction* rule=NULL; int c;
+ while (c=p++->cat,valid_cat(c) && !no_successor(q,c))
+ if ((q=successor(q,c))->rule!=NULL) rule=q->rule;
+ return rule;
+}
+
+@ When a matching rule has been found, the function |reduce| is called to
+perform the corresponding actions. At that point |pp| points to the first
+scrap involved in the match, and the argument |rule| to |reduce| points to
+the matching rule.
+
+If a rule has a left hand side of length~1 (not counting context) and also
+the default translation (plain concatenation), then all that is to be done
+is to change the category of a scrap, and part of the processing can be
+skipped.
+
+@c
+void reduce (reduction* rule)
+{ int k=rule->lhs.context, l=rule->lhs.length;
+ scrap_pointer s = pp+k, p=s;/* position of the new scrap */
+ char* f=rule->rhs.translation; /* format string for translation */
+
+ s->cat=rule->rhs.category;
+
+ if (l>1 || f!=NULL) /* otherwise ready already */
+ { if (f==NULL) fuse(s,l), p+=l; /* default translation */
+ else @<Generate token list according to format string |f| @>
+ if (l>1) @<Fill vacant scrap positions@>
+ }
+
+ @<Print a snapshot of the scrap list if debugging@>
+ @<Change |pp| to |max(pp+rule->displacement,scrap_base)| @>
+}
+
+@ When we have applied a reduction to the sequence of scraps, we usually
+remove scraps (we never create more scraps than we remove), thereby creating
+a small ``hole'' in the sequence. We fix that hole by sliding scraps
+downward across it, thereby moving the hole upwards, until it reaches the
+``official'' hole at |lo_ptr|; then |lo_ptr| is adjusted so that the small
+hole is incorporated in the official hole. During the translation process
+the pointer~|p| was moved across all scraps that took part in the reduction,
+so the scraps to move are at positions~|i| with |p<=i<lo_ptr|.
+
+@<Fill vacant...@>=
+{ scrap_pointer q=s+1; /* position after the newly formed scrap */
+ while (p<lo_ptr) *q++=*p++;
+ lo_ptr=q;
+}
+
+@ Here we are careful not to create any pointers below |scrap_base|,
+since they are not guaranteed to exist (but mentioning them in the module
+name will do no harm).
+
+@<Change |pp| to...@>=
+if (pp<scrap_base-rule->displacement) pp=scrap_base; @+
+else pp+=rule->displacement;
+
+@ We need no extensive coding mechanism for describing translations, since
+they all follow a similar pattern. In all cases all the translations of the
+scraps in the left hand side (not including the context scraps) are used
+exactly once, in left to right order (violation of these principles would
+result in very strange effects indeed for the printed output). The only
+things that need to be added are formatting controls like |indent|, |force|
+or |break_space|, math shifts (but these are already taken care of by
+|add_trans|), and white space. We may also specify calls of
+|make_underlined| or |make_unreserved| for certain scraps in the left hand
+side. Although the items inserted are of a modest variety, one should
+realise that their presence is the only reason we need to parse at all;
+without them the translations could have been computed by purely lexical
+means.
+
+In format strings an underscore indicates the translation of the next scrap
+of the left hand side. Other characters each encode a formatting control; the
+character `\.p' encodes |opt| and is followed by a digit that becomes its
+argument. The characters `\.!' and `\.\$' respectively cause
+|make_underlined| and |make_nonreserved| to be called for the next scrap;
+`\.\ ' and~`\.\~' produce a space in the translation, where the latter is
+non-breakable and the former forces horizontal mode. To just force
+horizontal or math mode there are `\.h'~and~`\.m'; the latter avoids the
+possibility of a completely empty formula by adding a space inside math
+mode. The precise meaning of these and other formatting characters is easily
+read off from the code below. The `\.o' and `\.r' format characters (the
+latter is used only in compatibility mode) affect the math category used by
+\TeX\ for the next symbol (character or control sequence); the syntax rules
+using them do not put braces around that symbol, since these could also
+capture a following comment, causing a \TeX\ error.
+
+The number of free tokens we require to be available by calling |check_toks|
+is a conservative estimate, based on a hypothetic ``worst case'' reduction
+rule with a left hand side of length~4 and with 8 additional items in its
+translation (counting format codes with multi-character translations with
+multiplicity), whose mathnesses alternate, so that a maximal number of math
+shifts is required.
+
+@< Generate token list... @>=
+{ int cur_mathness=maybe_math, init_mathness=maybe_math;
+ check_toks(23); check_text();
+ do
+ switch (*f++) @:format@>
+ { case '+': app(indent); break;
+ case '-': app(outdent); break;
+ case 'p': app(opt); app(*f++); break;
+ case 'f': set_mode(no_math); app(force); break;
+ case 'F': set_mode(no_math); app(big_force); break;
+ case 'b': set_mode(no_math); app(backup); break;
+ case 'B': set_mode(no_math); app(break_space); break;
+ case 't': set_mode(yes_math); app_str("\\a"); break; @.\\a@>
+ /* next item in tab space */
+ case ',': set_mode(yes_math); app_str("\\,"); break; @.\\,@>
+ /* thin space */
+ case 'h': set_mode(no_math); break; /* force horizontal mode */
+ case 'm': set_mode(yes_math); app(' '); break;
+ /* force math mode, avoid `\.{\$\$}' */
+ case 'o': set_mode(yes_math); app_str("\\m"); break; @.\\m@>
+ /* make ``mathord'' */
+ case 'r': set_mode(yes_math); app_str("\\MRL"); break; @.\\MRL@>
+ /* make ``mathrel'' */
+ case '!': make_underlined(p); break;
+ case '$': make_nonreserved(p); break;
+ case ' ': set_mode(no_math); app(' '); break;
+ case '~': app('~'); break;
+ default: printf("%c: ",f[-1]);
+ confusion("illegal character in format string");
+ case '_': add_trans(p++);
+ }
+ while (*f!='\0');
+ s->trans=text_ptr; freeze_text();
+ s->mathness=(init_mathness<<2)+cur_mathness;
+}
+
+@ We have now seen how a match is made, and what is done once a matching
+rule is found; we still have to consider how everything is set up properly,
+and how rules are repeatedly applied until no more reduction is possible,
+responding properly to successful and failing matches. All this is
+performed by the function |translate|; as we have seen it is called by
+|do_C| and |finish_C| after scraps have been stored from |scrap_base|
+to |scrap_ptr| of the |scrap_info| array, and it returns a pointer to the
+text representing the result of parsing all those scraps.
+
+We start with appending a dummy scrap if either no scraps are present at
+all, or some tokens remain that have not been packed into a scrap yet; the
+latter can only be due to `\.{@@t...@@>}' as a final item in compatibility
+mode. Then we set |lo_ptr| and |hi_ptr| appropriately, and begin to apply
+rules as long as possible. When this is done and more than one scrap
+remains, their translations are wrapped rather bluntly together to a single
+text.
+
+@c
+text_pointer translate (void) /* converts a sequence of scraps */
+{ pp=lo_ptr=hi_ptr=scrap_base;
+ if (scrap_ptr==pp || dangling_tokens()) /* then append dummy scrap */
+ {@; check_scrap(); pack_scrap(insert,no_math); }
+ @< If tracing, print an indication of where we are @>
+ @< Reduce the scraps using the rules until no more rules apply @>
+ @< Combine the irreducible scraps that remain,
+ and |return| the resulting text @>
+}
+
+@ Before applying |match|, we must make sure it has good input (at least
+|max_lhs_length| scraps). If a match at |pp| exists, |reduce| will perform
+the required processing and updating of |pp| (in this case |pp| is
+certainly not increased), if not, we move to the right and try again.
+
+
+@< Reduce the scraps... @>=
+do
+{ reduction *rule;
+ @< Make sure the entries |pp| through |pp+max_lhs_length-1|
+ of |scrap_info| are defined, or that |lo_ptr->cat==0| @>
+ if ((rule=match(pp))!=NULL) reduce(rule);
+ else
+ {@; ++pp;
+ @< Take special action if |pp->cat| is |end_expr| or |rproc| @>
+ }
+}
+while (pp<lo_ptr);
+
+@ If we get to the end of the scrap list, we set |lo_ptr->cat=0|, which will
+prevent any matches to scraps beyond those that are actually present. All
+scraps of category |insert| pass across the hole between |lo_ptr| and
+|hi_ptr|, and we take the opportunity to remove them, tacking their
+translation to the scrap below the hole. We even make sure that
+|hi_ptr->cat!=insert|, so that the scraps with which the |insert| scrap is
+combined will not have undergone any ordinary reduction yet. The only
+possible remaining |insert| scrap is one at the very start of the list; it
+will be handled at the end of all reductions.
+
+@< Make sure the entries... @>=
+{ scrap_pointer lo_min = pp+max_lhs_length;
+ while (lo_ptr<lo_min && lo_ptr->cat!=0)
+ if (hi_ptr>=scrap_ptr) lo_ptr->cat=0;
+ else
+ { *lo_ptr++ = *hi_ptr++;
+ while (hi_ptr<scrap_ptr && hi_ptr->cat==insert)
+ {@; *lo_ptr = *hi_ptr++; fuse(lo_ptr-1,2); }
+ }
+}
+
+@ The category pairs |lproc|--|rproc| and |begin_expr|--|end_expr| are
+special in that the don't occur in any rules, but rather serve only as
+markers. When the material in between will not reduce any further the whole
+construction will be wrapped up, their translations concatenated, and the
+result treated as an |insert| respectively an |expression|. We do not
+actually form an |insert| scrap if it is not at the start of the scrap
+sequence, but rather combine everything directly with the scrap immediately
+before the |lproc| scrap, leaving the category of that scrap as it is; this
+is necessary, because the code that combines ordinary |insert| scraps with
+their predecessor only looks at scraps when they cross the hole from |hi_ptr|
+to~|lo_ptr|. We use here that |rproc-lproc==end_expr-begin_expr==1|. The
+variable names |s| and |p| are chosen with the same meaning as in |reduce|,
+so that we could reuse a module.
+
+@< Take special action... @>=
+if (pp->cat==end_expr || pp->cat==rproc)
+{ int start=pp->cat-1; /* the opening category matching |pp->cat| */
+ scrap_pointer s=pp, p=pp+1;
+ while ((--s)->cat!=start && s>scrap_base) {}
+ if (s->cat==start) /* if opening symbol is missing, take no action */
+ { if (start==begin_expr) s->cat=expression;
+ else if (s==scrap_base) s->cat=insert; @+
+ else --s; /* position of new scrap */
+ fuse(s,(int)(p-s));
+ @< Fill vacant scrap positions @> /* using values of |p| and |s| */
+ pp= s-scrap_base<max_lhs_length ? scrap_base : s+1-max_lhs_length;
+ }
+}
+
+@ If the initial sequence of scraps does not reduce to a single scrap,
+we concatenate the translations of all remaining scraps, separated by
+blank spaces, with dollar signs surrounding the translations of scraps
+where appropriate. Because of this last action we must build a new text
+even if only one scrap remains.
+
+@< Combine the irreducible... @>=
+{ scrap_pointer j;
+ if (scrap_base->cat==insert && lo_ptr>scrap_base+1)
+ { fuse(scrap_base,2); /* merge initial |insert| into the next scrap */
+ j=scrap_base; j->cat=j[1].cat; --lo_ptr; while (++j<lo_ptr) *j=j[1];
+ }
+ @<If semi-tracing, show the irreducible scraps@>
+ check_toks(1);
+ for (j=scrap_base; j<lo_ptr; j++)
+ { if (j!=scrap_base) app_char_tok(' ');
+ if (left_math(j)==yes_math) app('$');
+ app_trans(j);
+ if (right_math(j)==yes_math) app('$');
+ }
+ freeze_text();
+ return text_ptr-1;
+}
+
+@ If \.{CWEAVE} is compiled with |DEBUG| defined, it can be put into
+debugging mode by setting |tracing| to a positive value by means of \:1,
+\:2, or \:3. When |tracing| is set to level~1 any sequence of two or more
+irreducible scraps remaining at the end of a call to |translate| will be
+printed out. When |tracing| is set to level~2, the rule numbers and current
+scrap categories will be printed out after each reduction that takes place,
+and if it is set to level~3, then mathnesses at the boundaries of scraps
+will also be indicated.
+
+@<Global...@>=
+#ifdef DEBUG
+int tracing; /* how much parsing details to show */
+#endif
+
+@ When parsing fails to reduce everything to a single scrap, pleasing results
+will probably not be obtained; it is therefore advisable to run
+\.{CWEAVE} with |tracing==trace1| before a final version of a |CWEB|
+program is fixed. In order to allow this without changing the source file
+itself, we initialise |tracing| to |trace1| if the flag `\.{+d}' is supplied
+to \.{CWEAVE}.
+
+@< Set initial values @>=
+#ifdef DEBUG
+tracing = flags['d'] ? trace1 : trace0;
+#endif
+
+@ The following code is activated by the `\.{+d}' flag or the \:1 control
+code.
+
+@<If semi-tracing, show the irreducible scraps@>=
+#ifdef DEBUG
+{ if (tracing==trace1 && lo_ptr>=scrap_base+2)
+ { print("\nIrreducible scrap sequence at line %d in section %d:\n"
+ @.Irreducible scrap sequence...@> ,cur_line, section_count);
+ mark_harmless();
+ for (j=scrap_base; j<lo_ptr-1; j++)
+ print_cat(j->cat), putchar(' ');
+ print_cat(j->cat); new_line(); /* |term_line_empty| is still valid */
+ }
+}
+#endif
+
+@ When full tracing is enabled the following message indicates which piece
+of \Cee~text is being parsed (but for section bodies it will generally show
+the first line of the next section, since that has already been fetched).
+
+@<If tracing,...@>=
+#ifdef DEBUG
+{ if (tracing>=trace2)
+ { print("\nTracing after l.%d:\n", cur_line); @.Tracing after...@>
+ if (loc>buffer+50) /* shorten long lines to keep within margins */
+ {@; printf("..."); term_write (loc-50,50); }
+ else term_write(buffer,loc-buffer);
+ new_line(); /* |term_line_empty| is still valid */
+ }
+}
+#endif
+
+@ After each reduction, full tracing will print a line starting with the
+rule number, followed by a display of all the categories of scraps which
+have been considered until now, i.e., those at positions below |lo_ptr|.
+The scrap that was produced by this reduction, which is pointed to by~|s|,
+has its category highlighted by enclosing it in inverted angle brackets.
+If tracing is set to~3, extra-full tracing is active, and mathnesses at the
+boundaries of scraps are indicated.
+
+@d math_char(x) ((x)==yes_math ? '+' : (x)==no_math ? '-' : '?')
+
+@<Print a snapsh...@>=
+#ifdef DEBUG
+{ scrap_pointer k; /* pointer into |scrap_info| */
+ if (tracing>=trace2)
+ { print("\n%3d:", rule->id);
+ for (k=scrap_base; k<lo_ptr; k++)
+ { putchar (' ');
+ if (tracing==trace3) putchar(math_char(left_math(k)));
+ if (k==s) putchar('>'), print_cat(k->cat), putchar('<');
+ else print_cat(k->cat);
+ if (tracing==trace3) putchar(math_char(right_math(k)));
+ }
+ print("%s\n", hi_ptr<scrap_ptr ? " ..." : ".");
+ }
+}
+#endif
+
diff --git a/web/c_cpp/cwebx/rules.w b/web/c_cpp/cwebx/rules.w
new file mode 100644
index 0000000000..d58144e99e
--- /dev/null
+++ b/web/c_cpp/cwebx/rules.w
@@ -0,0 +1,701 @@
+@* Rules of the grammar. @:title@>
+\def\:#1{`\.{@@#1}'}% for in case this file is processed in isolation
+We first arrange the proper setting of |rule_mask|, which will control the
+selection of rules actually used. Recall that any bits set in the mask of a
+rule prescribe its {\it suppression\/} when the same bit is set in
+|rule_mask|; therefore for instance the bit characterising \Cpp\ is called
+|no_plus_plus|, so that rules specifying it will not be loaded for \Cpp. In
+some cases two masks will be combined using the bitwise-or operator `|@v|',
+this means (somewhat counterintuitively) that the rule will only be selected
+if the conditions represented by the two masks are {\it both\/} satisfied.
+The use of the bitwise-and operator `|&|' is even more exceptional: it is
+only meaningful if its two operands both select one setting of the same
+three-way switch; the rule will then be selected if that switch is in either
+of the two indicated positions. The |merged_decls| flag is special in that
+setting `\.{+m}' only enables an extra rule, but does no disable any rules;
+therefore only one bit is used for this option, and raising this bit in
+|rule_mask| suppresses the rule marked with |merged_decls|.
+
+@d cwebx 0x0001 /* use normally */
+@d compatibility 0x0002 /* use in compatibility mode */
+@d only_plus_plus 0x0004 /* use in \Cpp\ */
+@d no_plus_plus 0x0008 /* use in ordinary \Cee\ only */
+@d unaligned_braces 0x0050 /* use if `\.{+u}' flag was set */
+@d aligned_braces 0x0020 /* use unless `\.{+u}' flag was set */
+@d wide_braces 0x0030 /* use if `\.{+w}' set */
+@d standard_braces 0x0060 /* use unless `\.{+u}' or `\.{+w}' set */
+@d merged_decls 0x0080 /* use if `\.{+m}' set */
+@d forced_statements 0x0100 /* use if `\.{+a}' or `\.{+f}' set */
+@d no_forced_statements 0x0600 /* use unless `\.{+a}' or `\.{+f}' set */
+@d all_stats_forced 0x0300 /* use if `\.{+a}' set */
+@d not_all_stats_forced 0x0400 /* use unless `\.{+a}' set */
+
+@< Set initial values @>=
+rule_mask= (compatibility_mode ? 0x0001 : 0x0002)
+ | (C_plus_plus ? 0x0008 : 0x0004)
+ | (flags['w'] ? 0x0040 : flags['u'] ? 0x0020 : 0x0010)
+ | (flags['m'] ? 0x0000 : 0x0080)
+ | (flags['a'] ? 0x0400 : flags['f'] ? 0x0200 : 0x0100)
+ ;
+{ static reduction rule[] = { @< Rules @>@;@; };
+@/int i=array_size(rule); @+ do install_rule(&rule[--i]); while (i>0);
+#ifdef DEBUG
+ if (install_failed) fatal("inconsistent grammar",0);
+#endif
+}
+
+@ {\it Expressions}. @:rules@>
+These rules should be obvious. Rule~5 allows typedef identifiers to be used
+as field selectors in structures; rules 7~and~8 attach a parameter list in a
+function call. In rule~14 we prefix a potentially binary operator such as
+`|*|' that is used in a unary way by a `\.{\\mathord}' command to make sure
+that \TeX\ will not mistake it for a binary operator. In simple cases such
+as |*p| this is redundant, but if such operators are repeated more than one
+level deep, as in |**p|, \TeX\ would otherwise treat the first operator as
+the left operand of the second, and insert the wrong spacing. Moreover,
+typical \Cee~constructions as a cast |(void*) &x| or a declaration
+|char *p@;| would confuse \TeX\ even more. In rule~13 we need not insert
+`\.{\\mathord}', since operators of category |unop| are already treated as
+ordinary symbols by~\TeX.
+
+@< Rules @>=
+{ 1, {{expression, unop}}, {expression, NULL}}, @/
+{ 2, {{expression, binop, expression}}, {expression, NULL}}, @/
+{ 3, {{expression, unorbinop, expression}}, {expression, NULL}}, @/
+{ 4, {{expression, select, expression}}, {expression, NULL}}, @/
+{ 5, {{expression, select, int_like}}, {expression, "__$_"}}, @/
+{ 6, {{expression, comma, expression}}, {expression, "__p1_"}}, @/
+{ 7, {{expression, expression}}, {expression, NULL}}, @/
+{ 8, {{expression, lpar, rpar}}, {expression, "__,_"}}, @/
+{ 9, {{expression, subscript}}, {expression, NULL}}, @/
+{10, {{lpar, expression, rpar}}, {expression, NULL}}, @/
+{11, {{lbrack, expression, rbrack}}, {subscript, NULL}}, @/
+{12, {{lbrack, rbrack}}, {subscript, "_,_"}}, @/
+{13, {{unop, expression}}, {expression, NULL}}, @/
+{14, {{unorbinop, expression}}, {expression, "o__"}}, @[@]
+
+@~Here are some less common kinds of formulae. Processing the colon belonging
+to the question mark operator in math mode will give it the proper spacing,
+which is different from that of a colon following a label. Rule~21 processes
+casts, since the category |parameters|, which represents parenthesised lists
+specifying function argument types, encompasses the case of a single
+parenthesised type specification. The argument of |sizeof| may be a type
+specification rather than an expression; in \Cee\ (unlike \Cpp) it then must
+be parenthesised. %, but not in \Cpp\ (and |sizeof_like| might be `\&{new}').
+
+@< Rules @>=
+{20, {{question, expression, colon}}, {binop, "__m_"}}, @/
+{21, {{parameters, expression}}, {expression, "_,_"}}, @/
+{22, {{sizeof_like, parameters}}, {expression, NULL}}, @/
+{23, {{sizeof_like, expression}}, {expression, NULL}}, @/
+{24, {{sizeof_like, int_like}}, {expression,"_~_"},only_plus_plus}, @[@]
+
+@ {\it Declarations}.
+In a declaration in \Cee, the identifier being declared is wrapped up in a
+declarator, which looks like an expression of a restricted kind: only prefix
+asterisk, postfix subscript and formal parameters, and parentheses are used.
+In a bottom-up parser of the kind we are using, it is natural, and hardly
+avoidable, that declarators are parsed as expressions. Therefore we start
+recognising a declaration when we see a type specifier followed by the first
+declarator; at that point we have a succession `|int_like| |expression|
+|semi|' or `|int_like| |expression| |comma|' (rules 31~and~33). It is also
+possible that there are no declarators at all, namely when a |struct|,
+|union|, or~|enum| specifier is introduced without declaring any variables;
+in that case we have `|int_like| |semi|' (rule~32). Because the type
+specifier might be composite, like |unsigned long int|, and there might
+moreover be storage class specifiers and type modifiers (like `|const|'), we
+first contract any sequence of |int_like| items to a single one (rule~30).
+In case the declarator was followed by a comma we reduce to |int_like|, so
+that the next declarator can be matched, otherwise we reduce to
+|declaration|.
+
+It is not quite true that declarators always look like expressions, since
+the type modifiers `|const|' and `|volatile|' may penetrate into
+declarators. When they do they will almost always be preceded by an
+asterisk, and rule~34 will treat such cases. The choice for |int_like| as
+the result category is not completely obvious, since it makes the modifier
+and the preceding asterisk part of the type specifier rather than of the
+declarator, which strictly speaking is not correct; the choice for |unop| or
+|unorbinop| might therefore seem a more logical one. One reason for not
+doing that is that a space would have to be inserted in the translation
+after the modifier scrap, which would not look right in abstract declarators
+for contrived cases like \hbox{|int f(char *const)@;|}; more importantly, if
+the modifier would become part of the declarator, it would be a (reserved)
+identifier that precedes the identifier actually being declared, and when
+the declarator then receives a call from |make_underlined| by rule 31~or~33,
+it would mislead |first_ident|. The current solution has a small flaw as
+well, since it cannot handle the situation where the modifier is separated
+from the type specifier by a parenthesis, as in
+$\&{void}~(\m*\&{const}~\m*f)~(\&{int})$; such cases are quite uncommon, are
+hard to handle by rules that will not spuriously match in other situations,
+and even then they would still cause problems with |make_underlined|, so we
+do not attempt to handle them.
+
+@< Rules @>=
+{30, {{int_like, int_like}}, {int_like, "_~_"}}, @/
+{31, {{int_like, expression, semi}}, {declaration, "_~!__"}}, @/
+{32, {{int_like, semi}}, {declaration, NULL}}, @/
+{33, {{int_like, expression, comma}}, {int_like, "_~!__p1"}}, @/
+{34, {{unorbinop, int_like}}, {int_like, "o__"}}, @[@]
+
+@ If a typedef identifier is simultaneously used as a field selector in a
+|struct| or |union| declaration, it must be made to parse as expression and
+be printed in italic type; this can be achieved by placing the magic wand
+\:; before the identifier, by rule~35. The reason that we place \:; at the
+beginning rather than at the end of the construction here, is to prevent the
+|int_like| identifier from combining with something before it first.
+Rule~35 only applies if the \:; does not match by any rule with what comes
+before it.
+
+Rule~36 handles the case that a function is declared with specified argument
+types, which is not handled by the expression syntax given until now. It
+also parses new-style (\caps{ANSI/ISO}) headings of function definitions; in
+that case, the resulting |function_head| will not be incorporated into a
+|declaration| (unless a comma or semicolon follows) but rather into a
+|function|. If the parameter specifications include identifiers (as in the
+case of function headings), the arguments look like declarations without the
+final semicolon; rule~37 (with aid of rule~33) constructs such parameter
+lists. Parameter specifications using abstract declarators (without
+identifiers) will be treated below. In |struct| declarations we may
+encounter bit-field specifications with or without an identifier; these are
+handled by rules 38~and~39 (the constant expression following the colon will
+later receive a spurious call from |make_underlined|, but in case of numeric
+constants this does no harm).
+
+@< Rules @>=
+{35, {{magic, int_like}}, {expression, "_$_"}}, @/
+{36, {{expression, parameters}}, {function_head, "_B_"}}, @/
+{37, {{lpar, int_like, expression, rpar}}, {parameters, "_+++_~!_---_"}},@/
+{38, {{int_like, expression, colon}}, {int_like, "_~!_m_"}}, @/
+{39, {{int_like, colon}}, {int_like, "_m_"}}, @[@]
+
+@ Abstract declarators are used after type specifiers in casts and for
+specifying the argument types in declarations of functions or function
+pointers. They are like ordinary declarators, except that the defined
+identifier has been ``abstracted''; an example is `|**(* )(int)|' in `|void
+g(char**(* )(int))@;|', which tells that |g| takes as argument a pointer to
+a function with |int| parameter yielding a pointer to pointer to |char|. A
+difficulty with abstract declarators is that they are built up around the
+vacuum left by abstracting the identifier, and since for more than one
+reason we cannot allow rules with empty left hand side, we have to find an
+alternative way to get them started.
+
+The natural solution to this problem is to look for sequences that can only
+occur if an identifier has been abstracted from between them, for instance
+`\.{*)}' (in categories: |unorbinop| |rpar|). The most compelling reason why
+in |C_read| we had to laboriously change the category of a |type_defined|
+identifier to |expression| instead of |int_like| inside its defining typedef
+declaration, is that it allows us to ensure that any remaining |int_like|
+scrap that is followed by a |subscript| is a sure sign of an abstract
+declarator.
+
+Here are the cases that start off abstract declarators (these are the first
+examples of rules that need context categories in their left hand side). As
+a visual hint to the reader we leave a little bit of white space on the spot
+where the identifier has vanished. Rules 40~and~41 handle declarators for
+pointer arguments, where the vanished identifier is preceded by an asterisk,
+which either stands at the end of the declarator, or is parenthesised (for
+function pointer arguments). In these rules there is no need to prefix the
+asterisk with `\.{\\mathord}', since the right context makes an
+interpretation as binary operator impossible. Rules 42~and~43 treat
+declarators for arrays, possibly of pointers; there are no corresponding
+rules with |parameters| instead of |subscript| since abstract declarators
+never specify functions themselves, only function pointers. In fact the
+``function analogue'' of rule~43 would incorrectly match a cast following an
+operator like `|*|' or `|-|'. Rule~44 treats an abstract declarator
+consisting of subscripts only, which are redundantly parenthesised; here too
+the corresponding pattern with |parameters| is not only never needed, it
+would also spuriously trigger on parenthesised expressions that start with a
+cast.
+
+@< Rules @>=
+{40, {{unorbinop, rpar}, -1}, {declarator, "_,"}}, @/
+{41, {{unorbinop, comma},-1}, {declarator, "_,"}}, @/
+{42, {{int_like, subscript},1}, {declarator, ",_"}}, @/
+{43, {{unorbinop, subscript},1}, {declarator, ",_"}}, @/
+{44, {{lpar, subscript},1}, {declarator, ",_"}}, @[@]
+
+@~ Abstract declarators may grow just like ordinary declarators, to include
+prefixed asterisks, as well as postfixed subscripts and parameters, and
+grouping parentheses.
+
+@< Rules @>=
+{45, {{unorbinop, declarator}}, {declarator, "o__"}}, @/
+{46, {{declarator, subscript}}, {declarator, NULL}}, @/
+{47, {{declarator, parameters}}, {declarator, NULL}}, @/
+{48, {{lpar, declarator, rpar}}, {declarator, NULL}}, @[@]
+
+@~ Here is how abstract declarators are assembled into |parameters|, keeping
+in mind that the ``abstract declarator'' might be completely empty (i.e.,
+absent) as in `|void f(int);|' (rules 51~and~53). We put no space after the
+type specifier here, since it is followed either by an abstract declarator,
+a right parenthesis or comma, so certainly not by an identifier; therefore a
+space is neither necessary, nor would it improve readability. The
+\caps{ANSI/ISO} syntax allows empty parentheses as a parameter specification
+in abstract declarators, although this is an old-style form; rule~54 has
+been included to handle this case. Fortunately a parenthesised list of
+identifiers (which would parse as |expression|) is not allowed as parameter
+specification.
+
+@< Rules @>=
+{50, {{lpar, int_like, declarator, comma}}, {lpar, "____p5"}}, @/
+{51, {{lpar, int_like, comma}}, {lpar, "___p5"}}, @/
+{52, {{lpar, int_like, declarator, rpar}}, {parameters, NULL}}, @/
+{53, {{lpar, int_like, rpar}}, {parameters, NULL}}, @/
+{54, {{lpar, rpar}}, {parameters, "_,_"}}, @[@]
+
+@ {\it Structure, union, and enumeration specifiers}. It is permissible to
+use typedef identifiers as structure, union, or enumeration tags as well, so
+we include cases where an |int_like| follows a |struct_like| token. In \Cpp,
+we may also find things like `\&{private}:' in a class specifier; these are
+parsed just like `|default:|', i.e., as a |label| (rule~66).
+
+@< Rules @>=
+{60, {{struct_like, lbrace}}, {struct_head, "_ft_"},standard_braces}, @/
+{60, {{struct_like, lbrace}}, {struct_head, "_~_"},unaligned_braces}, @/
+{60, {{struct_like, lbrace}}, {struct_head, "_f_"},wide_braces}, @/
+{61, {{struct_like, expression, lbrace}},
+ {struct_head, "_~!_ft_"},standard_braces}, @/
+{61, {{struct_like, expression, lbrace}},
+ {struct_head, "_~!_~_"},unaligned_braces}, @/
+{61, {{struct_like, expression, lbrace}},
+ {struct_head, "_~!_f_"},wide_braces}, @/
+{62, {{struct_like, int_like, lbrace}},
+ {struct_head, "_~!$_ft_"},standard_braces|no_plus_plus}, @/
+{62, {{struct_like, int_like, lbrace}},
+ {struct_head, "_~!_ft_"},standard_braces|only_plus_plus}, @/
+{62, {{struct_like, int_like, lbrace}},
+ {struct_head, "_~!$_~_"},unaligned_braces|no_plus_plus}, @/
+{62, {{struct_like, int_like, lbrace}},
+ {struct_head, "_~!_~_"},unaligned_braces|only_plus_plus}, @/
+{62, {{struct_like, int_like, lbrace}},
+ {struct_head, "_~!$_f_"},wide_braces|no_plus_plus}, @/
+{62, {{struct_like, int_like, lbrace}},
+ {struct_head, "_~!_f_"},wide_braces|only_plus_plus}, @/
+{63, {{struct_like, expression}}, {int_like, "_~_"}}, @/
+{64, {{struct_like, int_like}}, {int_like, "_~$_"},no_plus_plus}, @/
+{64, {{struct_like, int_like}}, {int_like, "_~_"},only_plus_plus}, @/
+{65, {{struct_head, declaration, rbrace}},
+ {int_like, "_+_-f_"},standard_braces}, @/
+{65, {{struct_head, declaration, rbrace}},
+ {int_like, "_+f_-f_"},unaligned_braces & wide_braces}, @/
+{66, {{label, declaration}}, {declaration, "b_f_"},only_plus_plus}, @[@]
+
+@ Rules 67--70 are for enumerations; they avoid forced line breaks and call
+|make_underlined| for all the enumeration constants.
+
+@< Rules @>=
+{67, {{struct_like, lbrace, expression},-1}, {struct_head, "_B_"}}, @/
+{68, {{struct_like, expression, lbrace, expression},-1},
+ {struct_head, "_~_B_"}}, @/
+{69, {{struct_head, expression, comma, expression},1},
+ {expression, "__B!_"}}, @/
+{70, {{struct_head, expression, rbrace}}, {int_like, "_~+!_-B_"}}, @[@]
+
+@ The following rules are added to allow short structure and union
+specifiers to be kept on one line without having to repeatedly specify \:+.
+The idea is to place \:; after the left brace; this will cause the rules
+below to be invoked instead of those above, which avoids introducing forced
+line breaks.
+
+@< Rules @>=
+{71, {{struct_like, lbrace, magic}}, {short_struct_head, "_B__+"}}, @/
+{72, {{struct_like, expression, lbrace, magic}},
+ {short_struct_head, "_~!_B__+"}}, @/
+{73, {{struct_like, int_like, lbrace, magic}},
+ {short_struct_head, "_~!$_B__+"}, no_plus_plus}, @/
+{73, {{struct_like, int_like, lbrace, magic}},
+ {short_struct_head, "_~!_B__+"}, only_plus_plus}, @/
+{74, {{short_struct_head, declaration}}, {short_struct_head, "_B_"}}, @/
+{75, {{short_struct_head, rbrace}}, {int_like, "_-B_"}}, @[@]
+
+
+@ {\it Statements}.
+Rule~80 gives the usual way statements are formed, while rule~81 handles the
+anomalous case of an empty statement. Its use can always be avoided by using
+an empty pair of braces instead, which much more visibly indicates the
+absence of a statement (e.g., an empty loop body); when the empty statement
+is used however, it will either be preceded by a space or start a new line
+(like any other statement), so there is always some distinction between a
+|while| loop with empty body and the |while| that ends a |do|~statement. A
+rule like this with left hand side of length~1 makes the corresponding
+category (viz.~|semi|) ``unstable'', and can only be useful for categories
+that usually are scooped up (mostly from the left) by a longer rule. Rules
+82--84 make labels (ordinary, case and default), and rules 85~and~86 attach
+the labels to statements. Rule~87 makes \:; behave like an invisible
+semicolon when it does not match any of the rules designed for it, for
+instance if it follows an expression.
+
+@< Rules @>=
+{80, {{expression, semi}}, {statement, NULL}}, @/
+{81, {{semi}}, {statement, NULL}}, @/
+{82, {{expression, colon}}, {label, "!_h_"}}, @/
+{83, {{case_like, expression, colon}}, {label, "_ _h_"}}, @/
+{84, {{case_like, colon}}, {label, "_h_"}}, @/
+{85, {{label, label}}, {label, "_B_"}}, @/
+{86, {{label, statement}}, {statement, "b_B_"},not_all_stats_forced}, @/
+{86, {{label, statement}}, {statement, "b_f_"},all_stats_forced}, @/
+{87, {{magic}}, {semi, NULL}}, @[@]
+
+@ The following rules format compound statements and aggregate initialisers.
+Rules 90--94 combine declarations and statements within compound statements.
+A newline is forced between declarations by rule~90, unless the declarations
+are local (preceded by a left brace) and `\.{+m}' was specified (rule~91);
+this rule does not apply to structure specifiers, because the left brace
+will already have been captured in a |struct_head| before the rule can match.
+If `\.{+f}'~or~`\.{+a}' was specified, then a newline is forced between
+statements as well (rule~93). Between the declarations and statements some
+extra white space appears in ordinary \Cee\ (rule~92), but not in \Cpp, where
+declarations and statements may be arbitrarily mixed (rule~94). Rules
+95--97 then build compound statements, where the last case is the unusual
+one where a compound statement ends with a declaration; empty compound
+statements are made into simple statements so that they will look better
+when used in a loop statement or after a label. If compound statements are
+not engulfed by a conditional or loop statement (see below) then they decay
+to ordinary statements by rule~98. Rules 99~and~100 reduce aggregate
+initialiser expressions, where the reduction of comma-separated lists of
+expressions is already handled by the expression syntax.
+
+@< Rules @>=
+{90, {{declaration, declaration}}, {declaration, "_f_"}}, @/
+{91, {{lbrace, declaration, declaration},1},
+ {declaration, "_B_"},merged_decls}, @/
+{92, {{declaration, statement}}, {statement, "_F_"},no_plus_plus}, @/
+{92, {{declaration, statement}}, {statement, "_f_"},only_plus_plus}, @/
+{93, {{statement, statement}}, {statement, "_f_"},forced_statements}, @/
+{93, {{statement, statement}}, {statement, "_B_"},no_forced_statements},@/
+{94, {{statement, declaration}}, {declaration, "_f_"},only_plus_plus}, @/
+{95, {{lbrace, rbrace}}, {statement, "_,_"}}, @/
+{96, {{lbrace, statement, rbrace}},
+ {compound_statement, "ft_+_-f_"},standard_braces}, @/
+{96, {{lbrace, statement, rbrace}},
+ {compound_statement, "_+f_-f_"},unaligned_braces}, @/
+{96, {{lbrace, statement, rbrace}},
+ {compound_statement, "f_+f_-f_"},wide_braces}, @/
+{97, {{lbrace, declaration, rbrace}},
+ {compound_statement, "ft_+_-f_"},standard_braces}, @/
+{97, {{lbrace, declaration, rbrace}},
+ {compound_statement, "_+f_-f_"},unaligned_braces}, @/
+{97, {{lbrace, declaration, rbrace}},
+ {compound_statement, "f_+f_-f_"},wide_braces}, @/
+{98, {{compound_statement}}, {statement, "f_f"}}, @/
+{99, {{lbrace, expression, comma, rbrace}}, {expression, "_,__,_"}},@/
+{100, {{lbrace, expression, rbrace}}, {expression, "_,_,_"}}, @[@]
+
+@ Like for structure and union specifiers, we allow compound statements to
+be kept on one line by inserting \:; after the left brace. Such statements
+will reduce to |statement| rather that to |compound_statement|, so that they
+will be treated as if they were simple statements.
+
+@< Rules @>=
+{101, {{lbrace, magic}}, {short_lbrace, "__+"}}, @/
+{102, {{short_lbrace, declaration}}, {short_lbrace, "_B_"}}, @/
+{103, {{short_lbrace, statement}}, {short_lbrace, "_B_"}}, @/
+{104, {{short_lbrace, rbrace}}, {statement, "_-B_"}}, @[@]
+
+@ {\it Selection, iteration and jump statements}.
+There are three intermediate categories involved in the recognition of
+conditional statements. The category |if_like| stands for `|if|' or an
+initial segment of a repeated if-clause, up to and including `|else|~|if|'.
+An |if_head| is an |if_like| followed by its (parenthesised) condition
+(rules 110~and~111). If the statement following the condition is followed by
+`|else|~|if|', the whole construct reduces to |if_like| (so that the
+indentation will not increase after the second condition, rules 112~and~113),
+otherwise, if only `|else|' follows, reduction is to an |if_else_head|
+(rules 114~and~115), and finally, if no |else| follows at all, we reduce with
+only the if-branch to |statement| (rules 116~and~117). The reduction rules for
+|if_else_head| differ from those for |if_head| in that it will not combine
+with an |else|, even if it is present; the formatting is identical to that
+of an |else|-less |if_head| (rules 118~and~119). (It might be tempting to
+replace rules 116~and~117 by a reduction from |if_head| to |if_else_head| to
+be applied if no matching `|else|' is found, but that would require some
+subtle measures to prevent this decay at times when the right context is
+insufficiently reduced to decide whether an `|else|' is present or not.) The
+formatting of the if and else branches depends on whether they are compound
+statements or some other kind of statement (possibly another conditional
+statement), and on the flags for statement forcing and brace alignment.
+
+@< Rules @>=
+{110, {{if_like, expression}}, {if_head, "f_~_"}}, @/
+{111, {{lbrace,if_like,expression},1}, {if_head, "_~_"},standard_braces},@/
+{112, {{if_head, compound_statement, else_like, if_like}},
+ {if_like, "__f_~_"},aligned_braces}, @/
+{112, {{if_head, compound_statement, else_like, if_like}},
+ {if_like, "_~_~_~_"},unaligned_braces}, @/
+{113, {{if_head, statement, else_like, if_like}},
+ {if_like, "_+B_-f_~_"},not_all_stats_forced}, @/
+{113, {{if_head, statement, else_like, if_like}},
+ {if_like, "_+f_-f_~_"},all_stats_forced}, @/
+{114, {{if_head, compound_statement, else_like}},
+ {if_else_head, "__f_"},aligned_braces}, @/
+{114, {{if_head, compound_statement, else_like}},
+ {if_else_head, "_~_~_"},unaligned_braces}, @/
+{115, {{if_head, statement, else_like}},
+ {if_else_head, "_+B_-f_"},not_all_stats_forced},@/
+{115, {{if_head, statement, else_like}},
+ {if_else_head, "_+f_-f_"},all_stats_forced}, @/
+{116, {{if_head, compound_statement}},
+ {statement, "__f"},aligned_braces}, @/
+{116, {{if_head, compound_statement}},
+ {statement, "_~_f"},unaligned_braces}, @/
+{117, {{if_head, statement}},
+ {statement, "_+B_-f"},not_all_stats_forced}, @/
+{117, {{if_head, statement}},
+ {statement, "_+f_-f"},all_stats_forced}, @/
+{118, {{if_else_head, compound_statement}},
+ {statement, "__f"},aligned_braces}, @/
+{118, {{if_else_head, compound_statement}},
+ {statement, "_~_f"},unaligned_braces}, @/
+{119, {{if_else_head, statement}},
+ {statement, "_+B_-f"},not_all_stats_forced}, @/
+{119, {{if_else_head, statement}},
+ {statement, "_+f_-f"},all_stats_forced}, @[@]
+
+@ The following rules prevent forced line breaks from conditional statements
+that occur within a one-line compound statement.
+
+@< Rules @>=
+{120, {{short_lbrace, if_like, expression},1},
+ {if_head, "_~_"}}, @/
+{121, {{short_lbrace, if_head, statement, else_like}},
+ {short_lbrace, "_B_B_B_"}}, @/
+{122, {{short_lbrace, if_head, statement}},
+ {short_lbrace, "_B_B_"}}, @[@]
+
+@ Switch and loop statements make use of the syntax for conditionals by
+reducing to |if_else_head| which will take one further statement and indent
+it (rules 130~and~131). Recall that `|for|' and `|switch|' are both
+|while_like|; the parenthesised object following `|for|' looks like nothing
+we have seen before, however, so we need extra rules to come to terms with
+it (rules 132--134). Rule~132 is needed to avoid a line break when these are
+normally inserted between statements, and rule~134 is needed in case the
+third expression is empty. The |do|-|while| loops have to be treated
+separately. Because we want to distinguish the case of a
+|compound_statement| as loop body from other kinds of statements, we cannot
+wait until the |while| combines with the loop control condition to an
+|if_else_head|, since by then a |compound_statement| will have decayed to
+|statement|. Hence we pick up the unreduced `|while|' token and form a new
+category |do_head| (rules 135~and~136); in case of a compound statement the
+`|while|' will be on the same line as the closing brace. Rules 137~and~138
+then combine this with the condition and the ridiculous mandatory semicolon
+at the end to form a |statement|.
+
+@< Rules @>=
+{130, {{while_like, expression}}, {if_else_head, "f_~_"}}, @/
+{131, {{lbrace, while_like, expression},1},
+ {if_else_head, "_~_"},standard_braces}, @/
+{132, {{lpar, statement, statement}, 1},
+ {statement, "_B_"}, forced_statements}, @/
+{133, {{lpar, statement, expression, rpar}}, {expression, "__B__"}}, @/
+{134, {{lpar, statement, rpar}}, {expression, NULL}}, @/
+{135, {{do_like, compound_statement, while_like}},
+ {do_head, "__~_"},standard_braces}, @/
+{135, {{do_like, compound_statement, while_like}},
+ {do_head, "_~_~_"},unaligned_braces}, @/
+{135, {{do_like, compound_statement, while_like}},
+ {do_head, "__f_"},wide_braces}, @/
+{136, {{do_like, statement, while_like}},
+ {do_head, "_+B_-B_"},not_all_stats_forced}, @/
+{136, {{do_like, statement, while_like}},
+ {do_head, "_+f_-f_"},all_stats_forced}, @/
+{137, {{do_head, expression, semi}}, {statement, "f_~__f"}}, @/
+{138, {{lbrace, do_head, expression, semi},1}, {statement, "_~__f"}}, @[@]
+
+@ The following rules prevent forced line breaks from loop statements
+that occur within a one-line compound statement. Since no special layout is
+required between the heading of a |while| loop and its body, rule~139
+incorporates the heading as if it were a separate statement. For a
+|do|-|while| loop we must take a bit more effort to get the spacing
+following the |while| correct.
+
+@< Rules @>=
+{139, {{short_lbrace, while_like, expression}},
+ {short_lbrace, "_B_~_"}}, @/
+{140, {{short_lbrace, do_like, statement, while_like},1},
+ {do_head, "_B_B_"}}, @/
+{141, {{short_lbrace, do_head, expression, semi}},
+ {short_lbrace, "_B_~__"}}, @[@]
+
+@ The tokens `|goto|', `|continue|', `|break|', and `|return|' are all
+|return_like|; although what may follow them is not the same in all cases,
+the following two rules cover all legal uses. Note that rule~146 does not
+wait for a semicolon to come along; this may lead to a premature match as in
+`|return a+b;|', but this does not affect formatting, while the rule allows
+saying things like `|return home|' in a module name (or elsewhere) without
+risking irreducible scraps.
+
+@< Rules @>=
+{145, {{return_like, semi}}, {statement, NULL}}, @/
+{146, {{return_like, expression}}, {expression, "_~_"}}, @[@]
+
+@ {\it Function definitions and external declarations}.
+Apart from the initial specification of the result type (which is optional,
+defaulting to |int|), a new-style function heading will parse as an
+|function_head| (see the declaration syntax above), while an old-style function
+heading is an |expression| possibly followed by a |declaration| (specifying
+the function parameters). Rules 150--152 parse these two kinds of
+function headings together with the function body, yielding category
+|function|; rule~153 attaches the optional result type specifier. Although
+the \Cee~syntax requires that the function body is a compound statement, we
+allow it to be a |statement| (to which |compound_statement| will decay), for
+in case a very short function body is specified using `\.{\{@@;}'.
+
+At the outer level declarations and functions can be mixed; when they do a bit
+of white space surrounds the functions (rules 154--156). The combination of
+several declarations is already taken care of by the syntax for compound
+statements; no extra white space is involved there. Rules 157--159 take care
+of function declarations that are not definitions (i.e., there is no function
+body); if followed by a semicolon, a comma or a right parenthesis, the
+|function_head| decays to an |expression|, and the rest of the syntax will
+take care of recognising a |declaration| or |parameters|. Rules 153~and~157
+will be replaced in~\Cpp, for reasons explained below (incidentally, this is
+the reason the category |function_head| was introduced; it used to be simply
+|expression|).
+
+@< Rules @>=
+{150, {{function_head, statement}}, {function, "!_f_"}}, @/
+{151, {{expression, statement}}, {function, "!_f_"}}, @/
+{152, {{expression, declaration, statement}},
+ {function, "!_++f_--f_"}}, @/
+{153, {{int_like, function}}, {function, "_ _"}}, @/
+{154, {{declaration, function}}, {function, "_F_"}}, @/
+{155, {{function, declaration}}, {declaration, "_F_"}}, @/
+{156, {{function, function}}, {function, "_F_"}}, @/
+{157, {{function_head, semi},-1}, {expression, NULL},no_plus_plus}, @/
+{158, {{function_head, comma},-1}, {expression, NULL}}, @/
+{159, {{function_head, rpar},-1}, {expression, NULL}}, @[@]
+
+@ {\it Module names}.
+Although module names nearly always stand for statements, they can be made
+to stand for a declaration by appending \:;, or for an expression by
+appending `\.{@@;@@;}'. The latter possibility is most likely to be useful
+if the module stands for (part of) an initialiser list. A module name can
+also be made into an expression by enclosing it in \:[ and~\:], but in that
+case rule~160 will apply first, placing a forced break after the module
+name. Rules 161, 164,~and~165 prevent a module name from generating forced
+breaks if it occurs on a one-line compound statement or structure or union
+specifier, while rules 167~and~168 serve to prevent rules 163~and~164 from
+matching with priority over rule~166. The rules given here will be replaced by
+other ones in compatibility mode.
+
+@< Rules @>=
+{160, {{mod_scrap}}, {statement, "_f"},cwebx}, @/
+{161, {{short_lbrace, mod_scrap},1}, {statement, NULL},cwebx}, @/
+{162, {{mod_scrap, magic}}, {declaration, "f__f"},cwebx}, @/
+{163, {{lbrace, mod_scrap, magic},1},
+ {declaration, "__f"},cwebx|standard_braces}, @/
+{164, {{short_lbrace, mod_scrap, magic},1}, {declaration, NULL},cwebx}, @/
+{165, {{short_struct_head, mod_scrap, magic},1},
+ {declaration,NULL},cwebx}, @/
+{166, {{mod_scrap, magic, magic}}, {expression, NULL},cwebx}, @/
+{167, {{lbrace, mod_scrap, magic, magic},1},
+ {expression, NULL},cwebx|standard_braces}, @/
+{168, {{short_lbrace, mod_scrap, magic, magic},1},
+ {expression, NULL},cwebx}, @[@]
+
+@ {\it Additional rules for compatibilty mode}.
+@^Levy/Knuth \.{CWEB}@>
+Although our grammar differs completely from the one used in \LKC., we use
+most of it also in compatibility mode (the exception is formed by the rules
+concerning module names). We do add a few rules in compatibility mode, mostly
+do deal with circumstances that are different for some reason or other.
+
+We start with module names, which behave in a completely different way. In
+compatibility mode, as in \LKC., a module name normally stands for an
+expression (rule~164) and in practice is almost always followed by a visible
+or invisible (|magic|) semicolon. Rules 160~and~161 treat these cases
+explicitly, in order to insert a forced break after the semicolon; rule~161
+for the case of an invisible semicolon is needed because if we would wait for
+the |magic| semicolon to decay to an ordinary one, it might instead combine
+with an |int_like| token following it. Rules 162~and~163 are provided to allow
+the short form of compound statements even in compatibility mode (even though
+it is not present in \LKC.): they preempt rules 160~and~161, avoiding the
+forced break. Since in compatibility mode one has no means of indicating that
+a module name stands for a set of declarations, we add rule~165 to allow them
+nevertheless to be used before a function definition.
+
+Rules 170~and~171 compensate for the fact that compound assignment operators
+like `|+=|' are scanned as two tokens in compatibility mode (see
+section@#truly stupid@> for an explanation why this is done).
+Rule~172 allows types to be used in the argument lists of macros, without
+enclosing them between \:[~and~\:], in compatibility mode; this is done
+frequently in the Stanford GraphBase. @^Stanford GraphBase@> It is sufficient
+to remove expressions from the beginning of the argument list, since types,
+and more generally types followed by declarators, are already removed by the
+standard rules for |parameters|. As a result the argument list will either
+reduce to an |expression| or to |parameters|, depending on whether the final
+item was an expression. In both cases it will combine with the macro name to
+an |expression|, although the spacing will be a bit too wide in the
+|parameters| case. But then, one ought to use \:[~and~\:] anyway, which avoids
+this problem.
+
+@< Rules @>=
+{160, {{mod_scrap, semi}}, {statement, "__f"},compatibility}, @/
+{161, {{mod_scrap, magic}}, {statement, "__f"},compatibility}, @/
+{162, {{short_lbrace, mod_scrap, semi},1},
+ {statement, NULL},compatibility}, @/
+{163, {{short_lbrace, mod_scrap, magic},1},
+ {statement, NULL},compatibility}, @/
+{164, {{mod_scrap}}, {expression, NULL},compatibility}, @/
+{165, {{statement, function}}, {function, "_F_"},compatibility}, @/
+@)
+{170, {{binop, binop}}, {binop,"r__"},compatibility}, @/
+{171, {{unorbinop, binop}}, {binop,"r__"},compatibility}, @/
+{172, {{lpar, expression, comma}}, {lpar, "___p1"}, compatibility}, @[@]
+@[@]
+
+@ {\it Additional rules for \Cpp}.
+Up to this point we have included some specific rules for \Cpp, in places
+where a slight deviation from the \Cee~syntax was required. There are however
+a large number of syntactic possibilities of \Cpp\ that are not even remotely
+similar to those of~\Cee, so it is most convenient to collect them in a
+separate section. The author of \.{CWEBx} wishes to make it clear that he is
+quite aware of the incompleteness of the set of rules specified below, and
+that he assumes no responsibility for correcting this. One reason for this is
+that he has no readable formal grammar of \Cpp, which possibly could be used
+for validation (nor does he use \Cpp\ himself), another is that the pieces
+of grammar that he has seen show so little coherence that he seriously doubts
+whether it is possible at all to parse \Cpp\ reliably with a grammar of the
+type implemented here. In fact, the rules here were merely added in an
+attempt to cope with problems reported by users.
+
+We start with rules for `\&{operator}', which are simple: it should combine
+with a following operator symbol of any type to form an expression (rules
+180--182). Then rules 183--186 take care of the `::'~operator: either a class
+name or nothing is expected at the left, and either an ordinary or class
+identifier at the right; the resulting category is that of the right hand
+side. Type identifiers may appear as the left hand side of an assignment
+within a list of formal parameters, indicating a default argument; in this
+case the while assignment should behave as a type identifier (rule~187).
+
+Next we give rules catering with constructor declarations in class
+definitions. First of all we must recognise the fact that the class name is
+being used as a function name here; the simplest solution is to recognise the
+combination of an |int_like| followed by a (possibly empty) parameter list
+(rules 190~and~191). We cannot let a |function_head| (possibly created by the
+rules kust mentioned) decay to an |expression| when followed be a semicolon,
+as we do for~\Cee, since declarations of constructor members of a class lack
+an initial type specification, so the |expression| would fail to become part
+of a |declaration|. Therefore, special measures are necessary: the simplest
+solution is to simply absorb (rule~192) any preceding type specifier into the
+|function_head| (thereby removing the distinction between its presence or
+absence), and construct de |declaration| explicitly from the |function_head|
+and the following semicolon (rule~193).
+
+@< Rules @>=
+{180, {{case_like, binop}}, {expression, "_o_"},only_plus_plus}, @/
+{181, {{case_like, unorbinop}}, {expression, "_o_"},only_plus_plus}, @/
+{182, {{case_like, unop}}, {expression, NULL},only_plus_plus}, @/
+{183, {{int_like, colcol, expression}},
+ {expression, NULL},only_plus_plus}, @/
+{184, {{colcol, expression}}, {expression, "o__"},only_plus_plus}, @/
+{185, {{int_like, colcol, int_like}},
+ {int_like, NULL},only_plus_plus}, @/
+{186, {{colcol, int_like}}, {int_like, "o__"},only_plus_plus}, @/
+{187, {{int_like, binop, expression}},
+ {int_like, NULL},only_plus_plus}, @/
+{190, {{int_like, parameters}}, {function_head, "_B_"},only_plus_plus}, @/
+{191, {{int_like, lpar,rpar}}, {function_head, "_B_,_"},only_plus_plus},@/
+{192, {{int_like, function_head}},
+ {function_head, "_ _"},only_plus_plus}, @/
+{193, {{function_head, semi}}, {declaration, "!__"},only_plus_plus}, @[@]
diff --git a/web/c_cpp/cwebx/sample.ps b/web/c_cpp/cwebx/sample.ps
new file mode 100644
index 0000000000..53ae91cb63
--- /dev/null
+++ b/web/c_cpp/cwebx/sample.ps
@@ -0,0 +1,621 @@
+%!PS-Adobe-2.0
+%%Creator: dvipsk 5.58a Copyright 1986, 1994 Radical Eye Software
+%%Pages: 2
+%%PageOrder: Ascend
+%%BoundingBox: 0 0 596 842
+%%DocumentPaperSizes: a4
+%%EndComments
+%DVIPSCommandLine: dvips -f -p6 -l7
+%DVIPSParameters: dpi=300, compressed, comments removed
+%DVIPSSource: TeX output 1998.01.13:1225
+%%BeginProcSet: texc.pro
+/TeXDict 250 dict def TeXDict begin /N{def}def /B{bind def}N /S{exch}N
+/X{S N}B /TR{translate}N /isls false N /vsize 11 72 mul N /hsize 8.5 72
+mul N /landplus90{false}def /@rigin{isls{[0 landplus90{1 -1}{-1 1}
+ifelse 0 0 0]concat}if 72 Resolution div 72 VResolution div neg scale
+isls{landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div
+hsize mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul
+TR[matrix currentmatrix{dup dup round sub abs 0.00001 lt{round}if}
+forall round exch round exch]setmatrix}N /@landscape{/isls true N}B
+/@manualfeed{statusdict /manualfeed true put}B /@copies{/#copies X}B
+/FMat[1 0 0 -1 0 0]N /FBB[0 0 0 0]N /nn 0 N /IE 0 N /ctr 0 N /df-tail{
+/nn 8 dict N nn begin /FontType 3 N /FontMatrix fntrx N /FontBBox FBB N
+string /base X array /BitMaps X /BuildChar{CharBuilder}N /Encoding IE N
+end dup{/foo setfont}2 array copy cvx N load 0 nn put /ctr 0 N[}B /df{
+/sf 1 N /fntrx FMat N df-tail}B /dfs{div /sf X /fntrx[sf 0 0 sf neg 0 0]
+N df-tail}B /E{pop nn dup definefont setfont}B /ch-width{ch-data dup
+length 5 sub get}B /ch-height{ch-data dup length 4 sub get}B /ch-xoff{
+128 ch-data dup length 3 sub get sub}B /ch-yoff{ch-data dup length 2 sub
+get 127 sub}B /ch-dx{ch-data dup length 1 sub get}B /ch-image{ch-data
+dup type /stringtype ne{ctr get /ctr ctr 1 add N}if}B /id 0 N /rw 0 N
+/rc 0 N /gp 0 N /cp 0 N /G 0 N /sf 0 N /CharBuilder{save 3 1 roll S dup
+/base get 2 index get S /BitMaps get S get /ch-data X pop /ctr 0 N ch-dx
+0 ch-xoff ch-yoff ch-height sub ch-xoff ch-width add ch-yoff
+setcachedevice ch-width ch-height true[1 0 0 -1 -.1 ch-xoff sub ch-yoff
+.1 sub]/id ch-image N /rw ch-width 7 add 8 idiv string N /rc 0 N /gp 0 N
+/cp 0 N{rc 0 ne{rc 1 sub /rc X rw}{G}ifelse}imagemask restore}B /G{{id
+gp get /gp gp 1 add N dup 18 mod S 18 idiv pl S get exec}loop}B /adv{cp
+add /cp X}B /chg{rw cp id gp 4 index getinterval putinterval dup gp add
+/gp X adv}B /nd{/cp 0 N rw exit}B /lsh{rw cp 2 copy get dup 0 eq{pop 1}{
+dup 255 eq{pop 254}{dup dup add 255 and S 1 and or}ifelse}ifelse put 1
+adv}B /rsh{rw cp 2 copy get dup 0 eq{pop 128}{dup 255 eq{pop 127}{dup 2
+idiv S 128 and or}ifelse}ifelse put 1 adv}B /clr{rw cp 2 index string
+putinterval adv}B /set{rw cp fillstr 0 4 index getinterval putinterval
+adv}B /fillstr 18 string 0 1 17{2 copy 255 put pop}for N /pl[{adv 1 chg}
+{adv 1 chg nd}{1 add chg}{1 add chg nd}{adv lsh}{adv lsh nd}{adv rsh}{
+adv rsh nd}{1 add adv}{/rc X nd}{1 add set}{1 add clr}{adv 2 chg}{adv 2
+chg nd}{pop nd}]dup{bind pop}forall N /D{/cc X dup type /stringtype ne{]
+}if nn /base get cc ctr put nn /BitMaps get S ctr S sf 1 ne{dup dup
+length 1 sub dup 2 index S get sf div put}if put /ctr ctr 1 add N}B /I{
+cc 1 add D}B /bop{userdict /bop-hook known{bop-hook}if /SI save N @rigin
+0 0 moveto /V matrix currentmatrix dup 1 get dup mul exch 0 get dup mul
+add .99 lt{/QV}{/RV}ifelse load def pop pop}N /eop{SI restore userdict
+/eop-hook known{eop-hook}if showpage}N /@start{userdict /start-hook
+known{start-hook}if pop /VResolution X /Resolution X 1000 div /DVImag X
+/IE 256 array N 0 1 255{IE S 1 string dup 0 3 index put cvn put}for
+65781.76 div /vsize X 65781.76 div /hsize X}N /p{show}N /RMat[1 0 0 -1 0
+0]N /BDot 260 string N /rulex 0 N /ruley 0 N /v{/ruley X /rulex X V}B /V
+{}B /RV statusdict begin /product where{pop product dup length 7 ge{0 7
+getinterval dup(Display)eq exch 0 4 getinterval(NeXT)eq or}{pop false}
+ifelse}{false}ifelse end{{gsave TR -.1 .1 TR 1 1 scale rulex ruley false
+RMat{BDot}imagemask grestore}}{{gsave TR -.1 .1 TR rulex ruley scale 1 1
+false RMat{BDot}imagemask grestore}}ifelse B /QV{gsave newpath transform
+round exch round exch itransform moveto rulex 0 rlineto 0 ruley neg
+rlineto rulex neg 0 rlineto fill grestore}B /a{moveto}B /delta 0 N /tail
+{dup /delta X 0 rmoveto}B /M{S p delta add tail}B /b{S p tail}B /c{-4 M}
+B /d{-3 M}B /e{-2 M}B /f{-1 M}B /g{0 M}B /h{1 M}B /i{2 M}B /j{3 M}B /k{
+4 M}B /w{0 rmoveto}B /l{p -4 w}B /m{p -3 w}B /n{p -2 w}B /o{p -1 w}B /q{
+p 1 w}B /r{p 2 w}B /s{p 3 w}B /t{p 4 w}B /x{0 S rmoveto}B /y{3 2 roll p
+a}B /bos{/SS save N}B /eos{SS restore}B end
+%%EndProcSet
+TeXDict begin 39158280 55380996 1000 300 300 () @start
+/Fa 1 1 df<B512C0A212027D871A>0 D E /Fb 21 121 df<EB01FCEB0703130CEB1C07
+1403EB18001338A45B3807FFFC3800701CA3EBE038A41470EA01C0A314E2A3380380E414
+641438140090C7FC5A120612C612E412CC12701825819C17>12 D<903901FC0FEE903907
+0E307E010C136091380CE07C90391C00C01C140113381638A2EC0380A20003B612F03A00
+70038070A2EC070016E013E0A391380E01C0A2EA01C0A2ED0388141CA201801490000314
+01ED00E04A13001300A248133038C63060EAE63838CC3180D8781FC8FC2725819C25>15
+D<EA03CCEA063C120CEA181CEA383812301270A2EAE070A413E212C0A2EA61E4EA6264EA
+3C380F127B9115>97 D<123F1207A2120EA45AA4EA39C0EA3E60EA3830A2EA7038A4EAE0
+70A3136013E0EAC0C012C1EA6180EA6300123C0D1D7B9C13>I<EA01F0EA0708120CEA18
+1CEA3838EA30001270A25AA513081310EA6020EA30C0EA1F000E127B9113>I<EB1F8013
+03A2EB0700A4130EA4EA03DCEA063C120CEA181CEA383812301270A2485AA413E212C0A2
+EA61E4EA6264EA3C38111D7B9C15>I<EA01E0EA0710120CEA1808EA381012701360EA7F
+80EAE000A51308EA60101320EA30C0EA1F000D127B9113>I<EB03C0EB0670130CEB1C60
+1400A25BA53803FF8038007000A55BA5485AA5485AA390C7FCA25A12C612E65A12781425
+819C0D>I<13F3EA018FEA030FEA0607EA0E0E120C121CA2EA381CA413381230A2EA1878
+13F0EA0F701200A213E0A2EAC0C012E1EAC300127E101A7D9113>I<EA0FC01201A2485A
+A448C7FCA4EA0E78138CEA0F0E120E121CA4485AA35B00701380A21370EB7100EAE032EA
+601C111D7D9C15>I<EA01801203EA0100C7FCA7121C12261247A2128EA2120E5AA35AA2
+1271A31272A2123C091C7C9B0D>I<EA1F801203A2EA0700A4120EA45AA45AA45AA412E4
+A412681238091D7C9C0B>108 D<393C1E078039266318C0394683A0E0384703C0008E13
+80A2120EA2391C0701C0A3EC0380D8380E1388A2EC0708151039701C032039300C01C01D
+127C9122>I<EA3C3CEA2646EA4687EA4707128EA2120EA2EA1C0EA35B00381340A21338
+148038701900EA300E12127C9117>I<EA01E0EA0718EA0C0C12181238EA300E1270A2EA
+E01CA31318133813301360EA60C0EA3180EA1E000F127B9115>I<EA07873804D9803808
+E0C0A23811C0E0A21201A2380381C0A31480EA070314005B1306EA0E8C137090C7FCA25A
+A4123CB47E131A7F9115>I<EA3C3CEA26C2EA4687EA4707EA8E061300120EA25AA45AA4
+5A123010127C9112>114 D<EA01F0EA0608120C131CEA1818EA1C00121F13C0EA0FF012
+07EA00781338EA603012E012C0EA8060EA60C0EA1F000E127D9111>I<13C01201A3EA03
+80A4EAFFE0EA0700A3120EA45AA4EA3840A31380EA1900120E0B1A7D990E>I<EA1E03EA
+27071247A2EA870EA2120EA2485AA438383880A21218EB3900EA1C59EA078E11127C9116
+>I<EA070EEA19913810E38012203841C30013C01201A2485AA4EA07021267EAE70412CB
+EA8B08EA70F011127D9113>120 D E /Fc 3 51 df<1360AAB512F0A238006000AA1416
+7E9119>43 D<120C121C12EC120CAFEAFFC00A137D9211>49 D<121FEA60C01360EAF070
+13301260EA0070A2136013C012011380EA02005AEA08101210EA2020EA7FE012FF0C137E
+9211>I E /Fd 5 111 df<126012F0A212701210A41220A212401280040C7C830C>59
+D<130113031306A3130CA31318A31330A31360A213C0A3EA0180A3EA0300A31206A25AA3
+5AA35AA35AA35AA210297E9E15>61 D<EA01F0EA030C120CEA1C1EEA383CEA3018EA7000
+A25AA51304EA60081310EA3060EA1F800F127E9112>99 D<EB01E0EB0630EB0E7814F0EB
+1C601400A45BA23803FFC038003800A25BA55BA5485AA55B1203A20063C7FC12F312F612
+E4127815257E9C14>102 D<EA3C1F384E6180384681C0EA4701128F128E120EA2381C03
+80A3EB070000381310A2130E1420387006403830038014127E9119>110
+D E /Fe 11 106 df<1203A4EAC30CEAE31CEA7338EA1FE0EA0780A2EA1FE0EA7338EAE3
+1CEAC30CEA0300A40E127D9215>3 D<EB3F80EBC0603803001800041304487F487F48EB
+0080A2481440A2481420130E131FA4130E90C7FC00401440A26C1480A26CEB01006C1302
+6C5B000313183800C060EB3F801B1C7E9720>12 D<B612E07EC9FCA7B612E0A2C9FCA700
+7FB512E0B6FC1B147E9320>17 D<1306A25B131C13185B017FB512F090B612F8D80380C8
+FC48C9FC123C12F0123C120E12036C7E6CB612F86D14F00130C8FC7F7FA27FA225187E95
+2A>40 D<1460A214C0A2EB0180A3EB0300A21306A25BA25BA35BA25BA25BA2485AA248C7
+FCA31206A25AA25AA25AA35AA25A124013287A9D00>54 D<13101338A2136CA313C6A2EA
+0183A238030180A2380600C0A3481360A2481330A2481318A348130CA24813061402171A
+7E981C>94 D<00C0130214060060130CA26C1318A36C1330A26C1360A26C13C0A3380301
+80A238018300A2EA00C6A2136CA31338A21310171A7E981C>I<133C13E0EA01C0138012
+03AD13005A121C12F0121C12077E1380AD120113C0EA00E0133C0E297D9E15>102
+D<12F0121C12077E1380AD120113C0EA00E0133C13E0EA01C013801203AD13005A121C12
+F00E297D9E15>I<134013C0EA0180A3EA0300A21206A35AA25AA35AA25AA35AA21260A3
+7EA27EA37EA27EA37EA2EA0180A3EA00C013400A2A7D9E10>I<12C0A21260A37EA27EA3
+7EA27EA37EA2EA0180A3EA00C0A2EA0180A3EA0300A21206A35AA25AA35AA25AA35AA20A
+2A7E9E10>I E /Ff 5 88 df<38C00180AEB5FCA211107E8916>32
+D<EA7FF8EAFFFE6C7EEA1C0FEB07801303A313071400EA1FFF5BA2EA1C1FEB038014C013
+01A41303EB0780EA7FFFB51200EA7FFC12197F9816>66 D<3801F180EA07FBEA0FFFEA1F
+0FEA3C07EA38031270A200F0C7FC5AA77E38700380A21238383C0700EA1F0FEA0FFE6C5A
+EA01F011197E9816>I<387FFFC0B5FC7EEA1C01A490C7FCA2131CA2EA1FFCA3EA1C1CA2
+90C7FC14E0A5EA7FFFB5FC7E13197F9816>69 D<38FC07E0EAFE0FEAFC07387001C0A300
+301380EA3803A313E3EA39F3A213B300191300A61313EA1B1BEA0F1EA2EA0E0E13197F98
+16>87 D E /Fg 35 118 df<126012F0A2126004047D830A>46 D<EA0F80EA30E0EA4070
+EA8030EAC03812E0124012001370A2136013C0EA0180EA03001206EA0C081208EA1018EA
+3FF0127F12FF0D157E9412>50 D<EA0FE0EA3030EA6018EA701CA21200131813381360EA
+07E0EA00301318130C130EA212E0A2EAC00CEA4018EA3030EA0FE00F157F9412>I<1330
+A2137013F012011370120212041208121812101220124012C0EAFFFEEA0070A5EA03FE0F
+157F9412>I<EA2030EA3FE013C0EA24001220A4EA2F80EA30E0EA2070EA00301338A212
+4012E0A2EA8030EA4060EA20C0EA1F000D157E9412>I<EA01F0EA0608EA080CEA181C12
+30EA7000126012E0EAE3E0EAEC30EAF018130CEAE00EA31260A2EA300C1318EA1830EA07
+C00F157F9412>I<1240EA7FFE13FC13F8EAC008EA80101320EA00401380A2EA0100A25A
+12021206A2120EA512040F167E9512>I<13101338A3135CA3138EA3EA0107A200031380
+EA0203A23807FFC0EA0401A2380800E0A21218003813F038FE03FE17177F961A>65
+D<B512E0EA1C00146014201410A3EB0400A3130CEA1FFCEA1C0C13041408A21300141814
+10A2143014F0B5FC15177F9618>69 D<EB7E0838038198380600584813384813185A0070
+1308A25A1400A4EB03FEEB00381270A212307E7E7E380380D838007F0817177E961C>71
+D<38FF83FE381C0070AA381FFFF0381C0070AA38FF83FE17177F961A>I<EAFFE0EA0E00
+B3A3EAFFE00B177F960D>I<38FF80FE381C0078146014401480EB0100130613085B1338
+1378139CEA1D0E121EEA1C07EB0380EB01C0A2EB00E014701478147C38FF80FF18177F96
+1B>75 D<EAFFC0001CC7FCAD1420A31460A2144014C01303B5FC13177F9616>I<00FEEB
+03F8001E14C000171305A338138009A23811C011A33810E021A2EB7041A3EB3881A2EB1D
+01A2130EA2123839FE040FF81D177F9620>I<00FC13FE001E1338001F13101217EA1380
+EA11C0A2EA10E013701338A2131C130E130F1307EB0390EB01D0A2EB00F0147014301238
+00FE131017177F961A>I<13FCEA0303380E01C0381C00E0481370003013300070133800
+60131800E0131CA700701338A200301330003813706C13E0380E01C038030300EA00FC16
+177E961B>I<EAFFFE381C0380EB00C014601470A4146014C0EB0380381FFE00001CC7FC
+AAB47E14177F9618>I<EAFFFC381C0380EB00C014E01470A414E014C0EB0380381FFE00
+381C0780EB01C0EB00E0A514E1A2147238FF803C18177F961A>82
+D<EA0FC4EA302CEA601CEA400CEAC004A3EAE0001270127FEA3FE0EA0FF8EA01FCEA001C
+130E13061280A3EAC004EAE008EAD810EA87E00F177E9614>I<387FFFF8386038180040
+1308A200801304A300001300AF3807FFC016177F9619>I<38FF80FE381C00381410B06C
+132012066C13403801818038007E0017177F961A>I<3AFF07FC3F803A3C01E00E00D81C
+001304A2EB0170000E5CA2EB023800075CA2EB041CD803845BA2EB880ED801C85BA2EBD8
+0F3900F00780A3D96003C7FCA321177F9624>87 D<EA1FC0EA38601330EA10381200EA03
+F8EA1E3812301270EAE039A21379EA70FFEA1F1E100E7F8D12>97
+D<EA07F0EA18381230EA7010EA600012E0A41260EA70081230EA1830EA07C00D0E7F8D10
+>99 D<137E130EA8EA07CEEA1C3EEA300E1270126012E0A412601270EA301EEA182E3807
+CFC012177F9614>I<EA0FC0EA1860EA3030EA7038EAE018EAFFF8EAE000A31260EA7008
+EA3010EA1830EA07C00D0E7F8D10>I<12FC121CA8137CEA1D8EEA1E07121CAA38FF9FE0
+1317809614>104 D<1218123CA212181200A5127C121CAC12FF081780960A>I<12FC121C
+B3A3EAFF80091780960A>108 D<EAFC7CEA1D8EEA1E07121CAA38FF9FE0130E808D14>
+110 D<EA07C0EA1830EA3018EA600CA2EAE00EA5EA701CEA3018EA1830EA07C00F0E7F8D
+12>I<EA1F40EA60C0EAC040A2EAE000B4FCEA7F80EA1FC0EA01E0EA8060A212C0EAE0C0
+EA9F000B0E7F8D0E>115 D<1208A31218A21238EAFF80EA3800A71340A4EA1C80EA0F00
+0A147F930E>I<EAFC3FEA1C07AA5BEA0E173803E7E0130E808D14>I
+E /Fh 38 122 df<EB3FC03801F0303803C0380007137CEA0F80A2143891C7FCA4B512FC
+A2380F807CAE397FE1FF80A2191D809C1B>12 D<903801C070A349485AA490380701C0A4
+90380E0380B71280A27E26001C07C7FCEB380EA5495A007FB61280B7FCA22600E038C7FC
+48485AA448485AA4380701C0A321257D9C28>35 D<127812FCA4127806067D850D>46
+D<1360EA01E0120F12FF12F31203B3A2387FFF80A2111B7D9A18>49
+D<EA07F8EA1FFE38383F8038780FC0EAFC0714E01303A21278EA000714C0A2EB0F80EB1F
+00131E13385B5B38018060EA03001206000813E0381FFFC05A5AB5FCA2131B7E9A18>I<
+EA03F8EA1FFEEA3C1FEB0F80387C07C0127E127C123838000F80A2EB1E005BEA03F8EA00
+1EEB0F80EB07C0A214E01230127812FCA214C038780F80EB1F00EA1FFEEA07F8131B7E9A
+18>I<EB018013031307130F131F133F136F13CF138F1201EA030F1206120C1218123012
+6012C0B512F8A238000F80A63801FFF8A2151B7F9A18>I<38180180381FFF005B5B5B13
+C00018C7FCA4EA19F8EA1E0E38180F80EA1007000013C014E0A3127812F8A214C012F038
+600F8038381F00EA1FFEEA07F0131B7E9A18>I<137EEA03FF38078180380F03C0EA1E07
+123CEB038048C7FCA212F813F8EAFB0E38FA0780EAFC0314C000F813E0A41278A214C012
+3CEB0780381E0F00EA07FEEA03F8131B7E9A18>I<1260387FFFE0A214C01480A238E003
+00EAC0065B5BC65AA25B13E0A212015B1203A41207A66C5A131C7D9B18>I<EA03F8EA0F
+FE381E0F80EA3807EB03C01278A2127E387F8380EBC700EA3FFE6C5A6C7E3807FF80121D
+38387FC038781FE0EAF00713031301A3007813C0EB0380EA3E07381FFE00EA03F8131B7E
+9A18>I<90381FE0209038FFF8E03803F80F3807C003380F800148C7FC123E1560127E12
+7C00FC1400A8007C1460127E123E15C07E390F8001803907C003003803F80E3800FFFCEB
+1FE01B1C7D9B22>67 D<B6FCA2380FC01F1407801580A2EBC181A3EC800013C313FFA213
+C313C1A21560A29038C000E015C0A21401A21403EC0F80B6FCA21B1C7E9B1F>69
+D<B6FCA2380FC01F1407801580A21401EBC181A2EC8000A213C313FFA213C313C1A401C0
+C7FCA6B5FCA2191C7E9B1E>I<B5FCA2EA07E0B3A6B5FCA2101C7F9B12>73
+D<B5FCA2EA0FC0AF1403A31407A21406140E141E147EB512FEA2181C7E9B1D>76
+D<EA0FF8EA1C1E383E0F80130714C0121C1200137FEA07E7EA1F07123C127C12F8A3EA78
+0B383E13F8EA0FE115127F9117>97 D<B4FCA2121FA9EB3F80EBE1E0EB8070EB0078143C
+A2143EA6143CA21478EB8070381EC1E0381C3F00171D7F9C1B>I<EA03FCEA0E0EEA1C1F
+123C1278130E00F8C7FCA61278EB0180123C381C0300EA0E0EEA03F811127E9115>I<EB
+0FF0A21301A9EA01F9EA0F07EA1C03EA3C011278A212F8A61278A2123CEA1C03380F0FFE
+EA03F9171D7E9C1B>I<EA01FCEA0F07381C0380383C01C0127814E012F8A2B5FC00F8C7
+FCA31278007C1360123C6C13C0380F03803801FC0013127F9116>I<137F3801E3803803
+C7C0EA0787120FEB8380EB8000A5EAFFF8A2EA0F80AEEA7FF8A2121D809C0F>I<3803F8
+F0380E0F38121E381C0730003C1380A4001C1300EA1E0FEA0E0EEA1BF80010C7FC1218A2
+EA1FFF14C06C13E04813F0387801F838F00078A300701370007813F0381E03C03807FF00
+151B7F9118>I<B4FCA2121FA9EB0FC0EB31E0EB40F0EB80F8A21300AB38FFE7FFA2181D
+7F9C1B>I<121E123FA4121EC7FCA6B4FCA2121FAEEAFFE0A20B1E7F9D0E>I<B4FCA2121F
+B3A7EAFFE0A20B1D7F9C0E>108 D<39FF0FC07E903831E18F3A1F40F20780D980FC13C0
+A2EB00F8AB3AFFE7FF3FF8A225127F9128>I<38FF0FC0EB31E0381F40F0EB80F8A21300
+AB38FFE7FFA218127F911B>I<EA01FC380F0780381C01C0003C13E0387800F0A200F813
+F8A6007813F0A2383C01E0381E03C0380F07803801FC0015127F9118>I<38FF3F80EBE1
+E0381F80F0EB0078147C143C143EA6143C147C1478EB80F0EBC1E0EB3F0090C7FCA6EAFF
+E0A2171A7F911B>I<EAFE3E1347381E8F80A3381F070090C7FCAAEAFFF0A211127F9114>
+114 D<EA1FD8EA3078EA601812E0A2EAF000EAFF80EA7FE013F0EA1FF8EA07FCEA007CEA
+C01CA212E01318EAF830EACFC00E127E9113>I<1203A45AA25AA2EA3FFC12FFEA1F00A9
+130CA4EA0F08EA0798EA03F00E1A7F9913>I<38FF07F8A2EA1F00AC1301120F380786FF
+EA01F818127F911B>I<38FFC1FCA2381F0060EB80E0000F13C013C03807C180A23803E3
+00A2EA01F6A213FE6C5AA21378A2133016127F9119>I<39FF8FF8FEA2391F03E030A201
+831370000FEBF0601386D807C613C0EBCEF8EBEC790003EB7D80EBF83D0001EB3F00A249
+7E0000131EEBE00EA21F127F9122>I<38FFC7FCA2381F8180EA0F833807C700EA03EEEA
+01FC5B1200137C13FEEA01DFEA039F38070F80380607C0380C03E038FF07FCA216127F91
+19>I<38FFC1FCA2381F0060EB80E0000F13C013C03807C180A23803E300A2EA01F713F6
+EA00FE5BA21378A21330A21370EA706012F85BEAF9800073C7FC123E161A7F9119>I
+E /Fi 42 121 df<EAE038EAF078A7EAE038A2EA60300D0B7C9816>34
+D<38380180EA7C03A238EE0700A2130EA35B127C5B1238C65AA35BA2485AA3485AEB8380
+380707C0A2380E0EE0A3121CA2383807C0A23818038013207F9C16>37
+D<12301278127C123C121CA41238127812F012E01240060D789816>39
+D<1238127C127EA2123E120E121E121C127812F01260070B798416>44
+D<127012F8A312700505788416>46 D<12E0B51280A338E00F00131EEA001C5B13781370
+5BA2485AA3485AA448C7FCA7111A7E9916>55 D<EA03E0EA0FF8487EEA3C1EEA700E7F12
+E014801303A213071270EA780FEA3FFFEA1FFBEA0FE338000700A21230EA780E5BEA7078
+EA3FF06C5AEA0F8011197E9816>57 D<127012F8A312701200A8127012F8A31270051278
+9116>I<EB01801307131FEB3E0013F8485AEA07C0485A003EC7FC12FC12F012FC123EEA
+0F806C7EEA01F06C7E133EEB1F801307130111157E9616>60 D<12C012F012FC123EEA0F
+806C7EEA01F06C7E133EEB1F801307131FEB3E0013F8485AEA07C0485A003EC7FC12FC12
+F012C011157E9616>62 D<EA7FF8EAFFFE6C7EEA1C0FEB07801303A313071400EA1FFF5B
+A2EA1C1FEB038014C01301A41303EB0780EA7FFFB51200EA7FFC12197F9816>66
+D<3801F180EA07FBEA0FFFEA1F0FEA3C07EA38031270A200F0C7FC5AA77E38700380A212
+38383C0700EA1F0FEA0FFE6C5AEA01F011197E9816>I<387FFFC0B5FC7EEA1C01A490C7
+FCA2131CA2EA1FFCA3EA1C1CA290C7FC14E0A5EA7FFFB5FC7E13197F9816>69
+D<B512E0A3EA1C00A41400A2131CA2EA1FFCA3EA1C1CA290C7FCA6B47E7F5B13197F9816
+>I<EA03E348B4FC5AEA1E1F487EEA38071270A200F0C7FC5AA4EB3F80EB7FC0EB3F8038
+F007001270A26C5A123C6C5A6CB4FCEA07F7EA03E712197E9816>I<387E1FC038FF3FE0
+387F1FC0381D07001387A313C7A2121CA213E7A31367A21377A21337A31317EA7F1FEAFF
+9FEA7F0F13197F9816>78 D<EA1FFC487E487EEA780F38F00780EAE003AEEAF007A23878
+0F00EA7FFF6C5A6C5A11197E9816>I<EA07E3EA1FFF5AEA781FEAF00712E0A290C7FC7E
+1278EA3F80EA1FF0EA07FCC67E130F7FEB0380A2126012E0EB0700EAF80FEAFFFE5BEAC7
+F011197E9816>83 D<387FFFE0B5FCA2EAE0E0A400001300AFEA07FC487E6C5A13197F98
+16>I<38FC07E0EAFE0FEAFC07387001C0A300301380EA3803A313E3EA39F3A213B30019
+1300A61313EA1B1BEA0F1EA2EA0E0E13197F9816>87 D<12C07EA21270A27EA27EA27EA2
+7EA26C7EA26C7EA26C7EA21370A27FA27FA27FA27FA2EB0380A2130111207E9C16>92
+D<EA1FE0487E487EEA783CEA300E1200A2EA03FE121FEA3E0E127012E0A3EA783E387FFF
+E0EA3FE7EA0F8313127E9116>97 D<127E12FE127E120EA4133E13FF000F1380EB83C0EB
+00E0120E1470A614E0EA0F01EB83C0EBFF80000E1300EA063C1419809816>I<EA03F8EA
+0FFCEA1FFEEA3C1EEA780CEA70005AA57EEA70071278EA3E0EEA1FFCEA0FF8EA03F01012
+7D9116>I<133F5B7F1307A4EA03C7EA0FF748B4FCEA3C1F487EEA700712E0A6EA700FA2
+EA3C1F381FFFE0380FE7F03807C7E014197F9816>I<EA03E0EA0FF8EA1FFCEA3C1EEA78
+0EEA700712E0B5FCA3EAE000A2EA70071278EA3C0FEA1FFEEA0FFCEA03F010127D9116>
+I<131FEB7F8013FFEA01E7EBC30013C0A2EA7FFFB5FCA2EA01C0ACEA3FFE487E6C5A1119
+7F9816>I<3803E3C03807F7E0EA0FFF381C1CC038380E00A56C5AEA0FF8485AEA1BE000
+38C7FC1218EA1FFC13FF481380387803C038E000E0A4387001C0EA7C07383FFF80380FFE
+00EA03F8131C7F9116>I<127E12FE127E120EA4133C13FEEA0FFFEB87801303120EAA38
+7FC7F038FFE7F8387FC7F01519809816>I<EA0180EA03C0A2EA0180C7FCA4EA7FC0A312
+01ACEA7FFFB5FC7E101A7D9916>I<EAFFC0A31201B3B51280A311197E9816>108
+D<38F9C38038FFEFC0EBFFE0EA3C78A2EA3870AA38FE7CF8A2EB3C781512809116>I<EA
+7E3CEAFEFEEA7FFF380F87801303120EAA387FC7F038FFE7F8387FC7F01512809116>I<
+EA03E0EA0FF8487EEA3C1E487EEA700738E00380A5EAF00700701300EA780FEA3C1EEA1F
+FC6C5AEA03E011127E9116>I<EA7E3EEAFEFF007F1380380F83C0EB00E0120E1470A614
+E0EA0F01EB83C0EBFF80000E1300133C90C7FCA6EA7FC0487E6C5A141B809116>I<38FF
+0FC0EB3FE0137F3807F040EBC0005BA290C7FCA8EAFFFCA313127F9116>114
+D<EA0FECEA3FFC127FEAF03CEAE01CA2EA7000EA7F80EA1FF0EA07F8EA003CEA600E12E0
+12F0EAF81EEAFFFC13F8EAC7E00F127D9116>I<12035AA4EA7FFFB5FCA20007C7FCA75B
+EB0380A3EB8700EA03FE6C5A6C5A11177F9616>I<387E1F80EAFE3FEA7E1FEA0E03AB13
+0F380FFFF03807FBF83803E3F01512809116>I<387F1FC000FF13E0007F13C0381C0700
+EA1E0FEA0E0EA36C5AA4EA03B8A3EA01F0A26C5A13127F9116>I<38FF1FE013BF131F38
+380380A413E33819F300A213B3EA1DB7A4EA0F1EA313127F9116>I<387F1FC0133F131F
+380F1C00EA073CEA03B813F012016C5A12017FEA03B8EA073C131CEA0E0E387F1FC038FF
+3FE0387F1FC013127F9116>I E /Fj 59 123 df<EB7E1F3901C1B180390303E3C00007
+13C3000EEBC180903801C000A6B512FC380E01C0B0387F87FC1A1D809C18>11
+D<137E3801C180EA0301380703C0120EEB018090C7FCA5B512C0EA0E01B0387F87F8151D
+809C17>I<EA6060EAF0F0EAF8F8EA6868EA0808A3EA1010A2EA2020EA4040EA80800D0C
+7F9C15>34 D<13E0EA0310EA0608A2120EA45BA25B6C5AEC3FE09038800F80EC06000003
+130412073809C00800115BEA30E03820F020EA607038E03840EB3C80131C90380F00207F
+0070EB8040383009C0391830E180390FC03F001B1F7E9D20>38 D<1380EA010012021206
+5AA25AA25AA35AA412E0AC1260A47EA37EA27EA27E12027EEA0080092A7C9E10>40
+D<7E12407E12307EA27EA27EA37EA41380AC1300A41206A35AA25AA25A12205A5A092A7E
+9E10>I<1306ADB612E0A2D80006C7FCAD1B1C7E9720>43 D<126012F0A212701210A412
+20A212401280040C7C830C>I<126012F0A2126004047C830C>46
+D<EA03C0EA0C30EA1818EA300CA2EA700EEA6006A2EAE007ADEA6006A2EA700EEA300CA2
+EA1818EA0C30EA07E0101D7E9B15>48 D<5A1207123F12C71207B3A5EAFFF80D1C7C9B15
+>I<EA07C0EA1830EA201CEA400C130EEAF00F12F81307A21270EA000F130EA2131CA213
+381370136013C0EA0180EA0300EA0601120C1218EA1002EA3FFE127F12FF101C7E9B15>
+I<EA07E0EA1830EA201CA2EA781E130E131E1238EA001CA2131813301360EA07C0EA0030
+131CA2130E130FA2127012F8A3EAF00EEA401C1220EA1830EA07C0101D7E9B15>I<130C
+A2131C133CA2135C13DC139CEA011C120312021204120C1208121012301220124012C0B5
+12C038001C00A73801FFC0121C7F9B15>I<EA300CEA3FF813F013C0EA2000A6EA23E0EA
+2C30EA3018131CEA200E1200130FA3126012F0A3EA800EEA401E131CEA2038EA1870EA07
+C0101D7E9B15>I<13F0EA030CEA0404EA0C0EEA181E1230130CEA7000A21260EAE3E0EA
+E430EAE818EAF00C130EEAE0061307A51260A2EA7006EA300E130CEA1818EA0C30EA03E0
+101D7E9B15>I<1240387FFF801400A2EA4002485AA25B485AA25B1360134013C0A21201
+5BA21203A41207A66CC7FC111D7E9B15>I<EA03E0EA0C30EA1008EA200C13061260A212
+70A2EA7C0CEA3E18EA3FB0EA1FE0EA07F013F8EA18FCEA307EEA601E130FEAC0071303A4
+EA60021304EA300CEA1C10EA07E0101D7E9B15>I<126012F0A212601200AA126012F0A2
+126004127C910C>58 D<126012F0A212601200AA126012F0A212701210A41220A2124012
+80041A7C910C>I<007FB512C0B612E0C9FCA8B612E06C14C01B0C7E8F20>61
+D<EA0FE0EA3038EA401CEAE00E12F0A3EA000C131C1330136013C0138012011300A6C7FC
+A51203EA0780A2EA03000F1D7E9C14>63 D<B512F8380F007814181408A2140C1404A213
+011400A35B13FF13037FA490C7FCA8EAFFF8161C7E9B1B>70 D<EAFFF0EA0F00B3A8EAFF
+F00C1C7F9B0F>73 D<EAFFF8EA0F8090C7FCB01408A31418A2141014301470EB01F0B5FC
+151C7E9B1A>76 D<EB3F80EBE0E03803803848487E000E7F487F003C1480003813030078
+14C0A20070130100F014E0A8007014C000781303A200381480003C1307001C14006C130E
+6C5B6C6C5A3800E0E0EB3F801B1E7E9C20>79 D<B5FC380F01E0EB007880141C141EA414
+1C143C5CEB01E001FFC7FCEB01E0EB0070147880A61510A2141CA239FFF00E20C7EA03C0
+1C1D7E9B1F>82 D<3807E080EA1C19EA30051303EA600112E01300A36C13007E127CEA7F
+C0EA3FF8EA1FFEEA07FFC61380130FEB07C0130313011280A300C01380A238E00300EAD0
+02EACC0CEA83F8121E7E9C17>I<007FB512C038700F010060130000401440A200C01420
+1280A300001400B1497E3803FFFC1B1C7F9B1E>I<3AFFE1FFC0FF3A1F003E003C001E01
+3C13186C6D1310A32607801F1320A33A03C0278040A33A01E043C080A33A00F081E100A3
+9038F900F3017913F2A2017E137E013E137CA2013C133C011C1338A20118131801081310
+281D7F9B2B>87 D<12FEA212C0B3B312FEA207297C9E0C>91 D<EA0808EA1010EA2020EA
+4040A2EA8080A3EAB0B0EAF8F8EA7878EA30300D0C7A9C15>I<12FEA21206B3B312FEA2
+0729809E0C>I<EA1FC0EA3070EA78387F12301200A2EA01FCEA0F1C12381270126000E0
+1340A3EA603C38304E80381F870012127E9115>97 D<12FC121CAA137CEA1D87381E0180
+381C00C014E014601470A6146014E014C0381E018038190700EA10FC141D7F9C17>I<EA
+03F8EA0C0CEA181E1230EA700CEA600012E0A61260EA70021230EA1804EA0C18EA03E00F
+127F9112>I<EB1F801303AAEA03F3EA0E0BEA1807EA30031270126012E0A61260127012
+30EA1807EA0E1B3803E3F0141D7F9C17>I<EA07E0EA0C30EA1818EA300CEA700EEA6006
+12E0EAFFFEEAE000A41260EA70021230EA1804EA0C18EA03E00F127F9112>I<13F8EA01
+8CEA071E1206EA0E0C1300A6EAFFE0EA0E00B0EA7FE00F1D809C0D>I<EB03803807C4C0
+EA1C783838388038301800EA701CA4EA3018EA38386C5AEA27C00020C7FCA21230EA3FF8
+6CB4FC1480EA2003386001C0EAC000A33860018038300300EA1C0EEA07F8121C7F9215>
+I<12FC121CAA137C1387EA1D03001E1380121CAD38FF9FF0141D7F9C17>I<1218123CA2
+1218C7FCA712FC121CB0EAFF80091D7F9C0C>I<13C0EA01E0A2EA00C01300A7EA07E012
+00B3A21260EAF0C012F1EA6180EA3E000B25839C0D>I<12FC121CAAEB0FE0EB0780EB06
+005B13105B5B13E0121DEA1E70EA1C781338133C131C7F130F148038FF9FE0131D7F9C16
+>I<12FC121CB3A9EAFF80091D7F9C0C>I<39FC7E07E0391C838838391D019018001EEBE0
+1C001C13C0AD3AFF8FF8FF8021127F9124>I<EAFC7CEA1C87EA1D03001E1380121CAD38
+FF9FF014127F9117>I<EA03F0EA0E1CEA1806487E00701380EA600100E013C0A6006013
+80EA700300301300EA1806EA0E1CEA03F012127F9115>I<EAFC7CEA1D87381E0180001C
+13C0EB00E0A21470A614E0A2EB01C0001E1380381D0700EA1CFC90C7FCA7B47E141A7F91
+17>I<3803E080EA0E19EA1805EA3807EA7003A212E0A61270A2EA38071218EA0E1BEA03
+E3EA0003A7EB1FF0141A7F9116>I<EAFCE0EA1D38EA1E78A2EA1C301300ACEAFFC00D12
+7F9110>I<EA1F90EA2070EA4030EAC010A212E0EAF800EA7F80EA3FE0EA0FF0EA00F8EA
+8038131812C0A2EAE010EAD060EA8FC00D127F9110>I<1204A4120CA2121C123CEAFFE0
+EA1C00A91310A5120CEA0E20EA03C00C1A7F9910>I<38FC1F80EA1C03AD1307120CEA0E
+1B3803E3F014127F9117>I<38FF07E0383C0380381C0100A2EA0E02A2EA0F06EA0704A2
+EA0388A213C8EA01D0A2EA00E0A3134013127F9116>I<39FF3FC7E0393C0703C0001CEB
+01801500130B000E1382A21311000713C4A213203803A0E8A2EBC06800011370A2EB8030
+000013201B127F911E>I<38FF0FE0381E0700EA1C06EA0E046C5AEA039013B0EA01E012
+007F12011338EA021C1204EA0C0E487E003C138038FE1FF014127F9116>I<38FF07E038
+3C0380381C0100A2EA0E02A2EA0F06EA0704A2EA0388A213C8EA01D0A2EA00E0A31340A2
+5BA212F000F1C7FC12F312661238131A7F9116>I<EA7FFCEA70381260EA407013F013E0
+EA41C012031380EA0700EA0F04120E121CEA3C0CEA380812701338EAFFF80E127F9112>
+I E end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 300dpi
+TeXDict begin
+%%PaperSize: a4
+%%BeginPaperSize: a4
+a4
+%%EndPaperSize
+
+%%EndSetup
+%%Page: 6 1
+6 0 bop 0 42 a Fj(6)70 b Fg(WHA)m(T)14 b(A)e Ff(CWEB)f
+Fg(PR)o(OGRAM)h(LOOKS)h(LIKE)893 b Fi(CWEBx)13 b Fg(MANUAL)0
+132 y Fh(1.)48 b(Compar)q(in)o(g)12 b(t)o(ext)g(\014le)q(s.)47
+b Fj(Thi)q(s)11 b(i)q(s)g(an)h(en)o(t)o(irely)f(tr)q(ivial)f(program,)g
+(t)n(h)o(a)o(t)i(t)o(e)q(st)o(s)i(wh)o(et)n(h)o(er)f(t)o(w)o(o)e(t)o
+(ext)h(\014le)q(s)h(are)f(equal,)0 181 y(an)o(d)i(if)f(not)g(so,)h(p)q
+(oin)o(t)o(s)g(ou)o(t)g(t)n(h)o(e)h(\014rst)g(p)q(oin)o(t)e(of)g
+(di\013erence.)0 244 y Fh(#includ)o(e)41 b Fi(<stdio.h>)0
+294 y Fh(#includ)o(e)g Fi(<stdlib.h>)42 357 y Fh(t)o(yp)q(e)q(d)o(ef)18
+b(c)o(h)o(ar)d(b)q(o)q(o)o(l)r Fj(;)0 457 y Fh(2.)48
+b Fj(Th)o(e)15 b(ou)o(t)n(lin)o(e)f(of)g(t)n(h)o(e)h(program)e(i)q(s)h
+(s)q(imple.)j(W)m(e)d(read)h(c)o(h)o(aract)o(ers)i(f)q(rom)12
+b(b)q(ot)n(h)j(inpu)o(t)f(\014le)q(s)h(in)o(t)o(o)f Fd(c)1634
+463 y Fc(1)1667 457 y Fj(an)o(d)h Fd(c)1766 463 y Fc(2)1799
+457 y Fj(u)o(n)o(t)o(il)e(t)n(h)o(e)0 506 y(compar)q(i)q(son)f(i)q(s)h
+(complet)o(e.)k(Lin)o(e)c(an)o(d)h(colu)o(mn)e(cou)o(n)o(t)o(s)k(are)e
+(m)o(ain)o(t)o(ain)o(e)q(d)d(in)j Fb(line)19 b Fj(an)o(d)13
+b Fb(c)n(ol)6 b Fj(.)0 569 y Fh(#d)o(e\014n)o(e)42 b
+Fb(left)p 268 569 13 2 v 18 w(mar)n(gin)26 b Fj(1)83
+b Fd(=)p Fe(\003)20 b Fj(left)o(most)13 b(colu)o(mn)f(n)n(u)o(m)n(b)q
+(er;)h(c)o(h)o(an)o(ge)i(t)o(o)f(0)g(if)f(y)o(ou)g(prefer)22
+b Fe(\003)p Fd(=)42 632 y Fe(h)7 b Fj(F)m(u)o(nct)o(ions)18
+b Fg(5)6 b Fe(i)42 694 y Fh(in)o(t)14 b Fb(main)26 b
+Fj(\()p Fh(in)o(t)14 b Fd(n;)20 b Fh(c)o(h)o(ar)c Fe(\003)o(\003)p
+Fb(ar)n(g)6 b Fj(\))42 744 y Fe(f)20 b Fh(FILE)c Fe(\003)p
+Fd(f)248 750 y Fc(1)267 744 y Fd(;)k Fe(\003)p Fd(f)340
+750 y Fc(2)359 744 y Fj(;)83 b Fd(=)p Fe(\003)20 b Fj(t)n(h)o(e)15
+b(t)o(w)o(o)e(inpu)o(t)h(\014le)q(s)21 b Fe(\003)p Fd(=)83
+794 y Fh(in)o(t)14 b Fd(c)174 800 y Fc(1)193 794 y Fd(;)20
+b(c)243 800 y Fc(2)262 794 y Fd(;)g Fb(c)n(ol)e Fe(\()11
+b Fb(left)p 477 794 V 18 w(mar)n(gin)5 b Fj(;)83 844
+y Fh(lon)o(g)16 b Fb(line)g Fe(\()11 b Fj(1;)83 907 y
+Fe(h)c Fj(Op)q(en)15 b(t)n(h)o(e)f(\014le)q(s)h Fd(f)391
+913 y Fc(1)424 907 y Fj(an)o(d)f Fd(f)524 913 y Fc(2)543
+907 y Fj(,)f(t)o(akin)o(g)h(t)n(h)o(e)q(ir)g(n)o(am)o(e)q(s)g(f)q(rom)e
+(t)n(h)o(e)i(comm)o(an)o(d)e(lin)o(e)h(or)h(f)q(rom)e(t)n(h)o(e)j(t)o
+(ermin)o(al;)d(in)h(cas)q(e)i(of)166 957 y(an)f(error)h(for)e(whic)o(h)
+h(no)f(reco)o(v)o(ery)j(i)q(s)d(p)q(oss)q(ible,)h(call)f
+Fb(exit)6 b Fj(\(1\))17 b Fg(6)7 b Fe(i)83 1007 y(h)g
+Fj(Searc)o(h)15 b(for)f(\014rst)h(di\013erence,)g(lea)o(vin)o(g)f
+Fd(c)745 1013 y Fc(1)775 1007 y Fe(6)p Fj(=)e Fd(c)837
+1013 y Fc(2)869 1007 y Fj(if)h(an)o(d)h(only)f(if)g(a)g(di\013erence)j
+(w)o(as)e(fou)o(n)o(d)k Fg(3)6 b Fe(i)83 1057 y(h)h Fj(Rep)q(ort)14
+b(t)n(h)o(e)h(ou)o(t)o(com)o(e)e(of)g(t)n(h)o(e)i(compar)q(i)q(son)g
+Fg(4)7 b Fe(i)83 1107 y Fh(ret)o(ur)q(n)13 b Fj(0;)83
+b Fd(=)p Fe(\003)20 b Fj(su)o(cce)q(ssful)c(complet)o(ion)j
+Fe(\003)p Fd(=)42 1157 y Fe(g)0 1257 y Fh(3.)48 b Fj(Th)o(e)12
+b(h)o(eart)h(of)f(t)n(h)o(e)h(program)d(i)q(s)i(t)n(hi)q(s)g(s)q(imple)
+d(lo)q(o)o(p.)17 b(Wh)o(en)12 b(w)o(e)g(reac)o(h)i(t)n(h)o(e)f(en)o(d)f
+(of)g(on)o(e)g(of)f(t)n(h)o(e)i(\014le)q(s,)g(t)n(h)o(e)f(\014le)q(s)h
+(m)o(a)o(t)o(c)o(h)e(if)0 1307 y(an)o(d)i(only)g(if)g(t)n(h)o(e)h(ot)n
+(h)o(er)h(\014le)f(h)o(as)f(also)g(reac)o(h)o(e)q(d)j(it)o(s)e(en)o(d.)
+k(F)m(or)c(t)n(hi)q(s)f(reason)i(t)n(h)o(e)f(t)o(e)q(st)h
+Fd(c)1357 1313 y Fc(1)1387 1307 y Fj(=)d Fd(c)1449 1313
+y Fc(2)1468 1307 y Fj(,)h(whic)o(h)g(require)q(s)i(c)o(h)o(aract)o(ers)
+0 1357 y(t)o(o)h(b)q(e)g(read)g(f)q(rom)e(b)q(ot)n(h)i(\014le)q(s,)g(m)
+n(ust)f(prece)q(d)o(e)k(t)n(h)o(e)d(t)o(e)q(st)h(for)e(\014le)h(en)o
+(d;)g(wh)o(en)h(only)d(on)o(e)i(\014le)g(en)o(ds,)g(it)g(i)q(s)f(t)n(h)
+o(e)h(form)o(er)f(t)o(e)q(st)0 1406 y(whic)o(h)f(breaks)h(t)n(h)o(e)f
+(lo)q(o)o(p.)0 1469 y Fe(h)7 b Fj(Searc)o(h)15 b(for)f(\014rst)h
+(di\013erence,)g(lea)o(vin)o(g)f Fd(c)662 1475 y Fc(1)692
+1469 y Fe(6)p Fj(=)e Fd(c)754 1475 y Fc(2)786 1469 y
+Fj(if)h(an)o(d)h(only)f(if)g(a)g(di\013erence)j(w)o(as)e(fou)o(n)o(d)k
+Fg(3)6 b Fe(i)12 b(\021)42 1519 y Fh(while)i Fj(\(\()p
+Fd(c)217 1525 y Fc(1)248 1519 y Fe(\()d Fb(getc)t Fj(\()p
+Fd(f)412 1525 y Fc(1)431 1519 y Fj(\)\))h(=)g(\()p Fd(c)553
+1525 y Fc(2)583 1519 y Fe(\()f Fb(getc)5 b Fj(\()p Fd(f)748
+1525 y Fc(2)767 1519 y Fj(\)\))k Fe(^)g Fd(c)863 1525
+y Fc(1)893 1519 y Fe(6)p Fj(=)j Fi(EOF)r Fj(\))83 1569
+y Fh(if)20 b Fj(\()p Fd(c)166 1575 y Fc(1)196 1569 y
+Fj(=)12 b Fi('\\n')r Fj(\))20 b Fe(f)410 1565 y Fc(+)l(+)458
+1569 y Fb(line)5 b Fj(;)21 b Fb(c)n(ol)c Fe(\()12 b Fb(left)p
+745 1569 V 18 w(mar)n(gin)5 b Fj(;)20 b Fe(g)h Fh(els)q(e)1064
+1565 y Fc(+)l(+)1113 1569 y Fb(c)n(ol)6 b Fj(;)0 1623
+y Fg(This)12 b(co)q(d)o(e)f(is)h(us)q(e)q(d)e(in)h(s)q(ect)o(ion)f(2.)0
+1723 y Fh(4.)48 b Fj(Wh)o(en)14 b(t)n(h)o(e)h(\014rst)g(di\013erence)h
+(o)q(ccurs)f(a)o(t)f(t)n(h)o(e)h(en)o(d)f(of)f(on)o(e)h(of)g(t)n(h)o(e)
+h(\014le)q(s,)f(or)g(a)o(t)f(t)n(h)o(e)i(en)o(d)f(of)g(a)g(lin)o(e,)e
+(w)o(e)j(giv)o(e)e(a)h(m)o(e)q(ssage)0 1773 y(in)o(dica)o(t)o(in)o(g)f
+(t)n(hi)q(s)g(f)q(act.)0 1836 y Fe(h)7 b Fj(Rep)q(ort)14
+b(t)n(h)o(e)h(ou)o(t)o(com)o(e)e(of)g(t)n(h)o(e)i(compar)q(i)q(son)g
+Fg(4)7 b Fe(i)12 b(\021)42 1886 y Fh(if)19 b Fj(\()p
+Fd(c)124 1892 y Fc(1)154 1886 y Fj(=)12 b Fd(c)216 1892
+y Fc(2)235 1886 y Fj(\))21 b Fb(printf)10 b Fj(\()p Fi("Files)p
+Ff( )p Fi(match.\\n")r Fj(\);)42 1936 y Fh(els)q(e)42
+1986 y Fe(f)20 b Fb(printf)10 b Fj(\()p Fi("Files)p Ff( )p
+Fi(differ.\\n")r Fj(\);)83 2036 y Fh(if)20 b Fj(\()p
+Fd(c)166 2042 y Fc(1)196 2036 y Fj(=)12 b Fi(EOF)e Fe(_)f
+Fd(c)371 2042 y Fc(2)401 2036 y Fj(=)j Fi(EOF)r Fj(\))125
+2086 y Fe(f)20 b Fb(the)p 226 2086 V 19 w(\014le)5 b
+Fj(\()p Fd(c)331 2092 y Fc(1)361 2086 y Fj(=)12 b Fi(EOF)r
+Fj(\);)20 b Fb(printf)10 b Fj(\()p Fi("is)p Ff( )p Fi(contained)p
+Ff( )p Fi(in)p Ff( )p Fi(th)o(e)p Ff( )p Fi(oth)o(er)p
+Ff( )p Fi(a)o(s)p Ff( )p Fi(ini)o(tial)p Ff( )o Fi(segme)o(nt.\\n)o(")r
+Fj(\);)18 b Fe(g)83 2136 y Fh(els)q(e)d(if)20 b Fj(\()p
+Fd(c)259 2142 y Fc(1)289 2136 y Fj(=)12 b Fi('\\n')e
+Fe(_)f Fd(c)486 2142 y Fc(2)516 2136 y Fj(=)j Fi('\\n')r
+Fj(\))125 2186 y Fe(f)20 b Fb(the)p 226 2186 V 19 w(\014le)5
+b Fj(\()p Fd(c)331 2192 y Fc(1)361 2186 y Fj(=)12 b Fi('\\n')r
+Fj(\);)20 b Fb(printf)10 b Fj(\()p Fi("has)p Ff( )p Fi(a)p
+Ff( )p Fi(shorter)p Ff( )p Fi(lin)o(e)p Ff( )p Fi(num)o(ber)p
+Ff( )o Fi(\045ld)p Ff( )p Fi(t)o(han)p Ff( )p Fi(t)o(he)p
+Ff( )p Fi(ot)o(her.\\)o(n")r Fd(;)d Fb(l)o(ine)s Fj(\);)20
+b Fe(g)83 2236 y Fh(els)q(e)i Fb(printf)10 b Fj(\()p
+Fi("First)p Ff( )p Fi(difference)p Ff( )p Fi(a)o(t)p
+Ff( )p Fi(lin)o(e)p Ff( )p Fi(\045ld)o(,)p Ff( )p Fi(co)o(lumn)p
+Ff( )o Fi(\045d.\\n)o(")r Fd(;)d Fb(l)o(ine)s Fd(;)g
+Fb(c)n(ol)f Fj(\);)42 2286 y Fe(g)0 2341 y Fg(This)12
+b(co)q(d)o(e)f(is)h(us)q(e)q(d)e(in)h(s)q(ect)o(ion)f(2.)0
+2440 y Fh(5.)48 b Fj(Th)o(e)13 b(fu)o(nct)o(ion)g Fb(the)p
+385 2440 V 15 w(\014le)18 b Fj(st)o(art)o(s)c(a)f(s)q(en)o(t)o(ence)h
+(a)o(b)q(ou)o(t)f(t)n(h)o(e)h(\014rst)g(or)f(s)q(econ)o(d)g(\014le,)g
+(d)o(ep)q(en)o(din)o(g)g(on)g(it)o(s)g(b)q(o)q(olean)f(argu)o(m)o(en)o
+(t.)0 2503 y Fe(h)7 b Fj(F)m(u)o(nct)o(ions)18 b Fg(5)7
+b Fe(i)k(\021)42 2553 y Fh(v)o(oid)j Fb(the)p 205 2553
+V 19 w(\014le)26 b Fj(\()p Fh(b)q(o)q(o)o(l)16 b Fb(is)p
+455 2553 V 18 w(\014rst)6 b Fj(\))21 b Fe(f)f Fb(printf)10
+b Fj(\()p Fi("The)p Ff( )p Fi(\045s)p Ff( )p Fi(file)p
+Ff( )p Fi(")r Fd(;)d Fb(is)p 1116 2553 V 16 w(\014rst)17
+b Fj(?)11 b Fi("first")h Fj(:)f Fi("second")r Fj(\);)19
+b Fe(g)0 2607 y Fg(See)11 b(also)f(s)q(ect)o(ion)g(7.)0
+2662 y(This)i(co)q(d)o(e)f(is)h(us)q(e)q(d)e(in)h(s)q(ect)o(ion)f(2.)p
+eop
+%%Page: 7 2
+7 1 bop 0 42 a Fi(CWEBx)13 b Fg(MANUAL)895 b(WHA)m(T)13
+b(A)f Ff(CWEB)f Fg(PR)o(OGRAM)i(LOOKS)g(LIKE)70 b Fj(7)0
+132 y Fh(6.)48 b Fj(Th)o(ere)16 b(can)f(b)q(e)g(b)q(e)h(zero,)f(on)o(e)
+h(or)f(t)o(w)o(o)f(comm)o(an)o(d)e(lin)o(e)j(argu)o(m)o(en)o(t)o(s.)21
+b(If)15 b(t)n(h)o(ere)h(are)g(non)o(e,)f(t)n(h)o(e)h(us)q(er)g(i)q(s)e
+(prompt)o(e)q(d)h(t)o(o)0 181 y(sup)o(ply)h(t)n(h)o(em,)f(an)o(d)h(if)f
+(t)n(h)o(ere)j(are)f(t)o(w)o(o)f(t)n(h)o(e)q(s)q(e)h(are)g(t)o(ak)o(en)
+f(as)g(t)n(h)o(e)h(\014le)g(n)o(am)o(e)q(s,)e(prompt)o(in)o(g)g(t)n(h)o
+(e)i(us)q(er)g(only)e(in)h(cas)q(e)h(a)f(\014le)0 231
+y(could)d(not)g(b)q(e)h(o)o(p)q(en)o(e)q(d.)k(In)13 b(cas)q(e)h(just)g
+(on)o(e)f(argu)o(m)o(en)o(t)f(i)q(s)h(pre)q(s)q(en)o(t,)h(t)n(h)o(e)g
+(\014rst)h(\014le)e(i)q(s)g(assu)o(m)o(e)q(d)g(t)o(o)h(b)q(e)f(t)n(h)o
+(e)h(st)o(an)o(d)o(ard)g(inpu)o(t,)0 281 y(whic)o(h)h(do)q(e)q(s)h(not)
+f(h)o(a)o(v)o(e)g(t)o(o)h(b)q(e)g(o)o(p)q(en)o(e)q(d;)f(in)g(t)n(hi)q
+(s)h(cas)q(e)g(h)o(o)o(w)o(ev)o(er)g(w)o(e)g(will)e(not)h(read)h(a)g
+(\014le)f(n)o(am)o(e)f(f)q(rom)f(t)o(ermin)o(al)h(in)h(cas)q(e)0
+331 y(t)n(h)o(e)g(s)q(econ)o(d)f(\014le)g(cannot)g(b)q(e)g(o)o(p)q(en)o
+(e)q(d.)0 393 y Fh(#d)o(e\014n)o(e)42 b Fb(r)n(e)n(ad)p
+287 393 13 2 v 19 w(mo)n(de)27 b Fi("r")0 455 y Fe(h)7
+b Fj(Op)q(en)15 b(t)n(h)o(e)g(\014le)q(s)f Fd(f)308 461
+y Fc(1)341 455 y Fj(an)o(d)g Fd(f)441 461 y Fc(2)460
+455 y Fj(,)g(t)o(akin)o(g)g(t)n(h)o(e)q(ir)g(n)o(am)o(e)q(s)g(f)q(rom)e
+(t)n(h)o(e)j(comm)o(an)o(d)c(lin)o(e)j(or)g(f)q(rom)e(t)n(h)o(e)j(t)o
+(ermin)o(al;)d(in)i(cas)q(e)h(of)e(an)125 505 y(error)i(for)e(whic)o(h)
+h(no)f(reco)o(v)o(ery)i(i)q(s)f(p)q(oss)q(ible,)f(call)h
+Fb(exit)5 b Fj(\(1\))18 b Fg(6)7 b Fe(i)k(\021)44 551
+y Fa(\000)l(\000)93 555 y Fd(n)p Fj(;)153 551 y Fc(+)l(+)202
+555 y Fb(ar)n(g)5 b Fj(;)83 b Fd(=)p Fe(\003)20 b Fj(ignore)14
+b(\\argu)o(m)o(en)o(t")e(0,)h(whic)o(h)h(i)q(s)f(t)n(h)o(e)i(program)d
+(n)o(am)o(e)19 b Fe(\003)p Fd(=)42 605 y Fh(if)g Fj(\()p
+Fd(n)12 b Fj(=)g(0\))83 655 y Fe(f)21 b Fb(op)n(en)p
+213 655 V 19 w(\014le)5 b Fj(\(&)p Fd(f)352 661 y Fc(1)371
+655 y Fd(;)i Fi("First)p Ff( )p Fi(file)p Ff( )p Fi(to)p
+Ff( )p Fi(co)o(mpar)o(e")r Fd(;)g Fe(\014)p Fj(\);)17
+b Fb(op)n(en)p 1080 655 V 20 w(\014le)5 b Fj(\(&)p Fd(f)1220
+661 y Fc(2)1239 655 y Fd(;)i Fi("Second)p Ff( )p Fi(file)p
+Ff( )p Fi(to)p Ff( )o Fi(compa)o(re")r Fd(;)f Fe(\014)p
+Fj(\);)18 b Fe(g)42 704 y Fh(els)q(e)d(if)k Fj(\()p Fd(n)12
+b Fj(=)g(1\))42 754 y Fe(f)20 b Fd(f)103 760 y Fc(1)133
+754 y Fe(\()12 b Fb(stdin)5 b Fj(;)83 804 y Fh(if)20
+b Fj(\(\()p Fd(f)184 810 y Fc(2)214 804 y Fe(\()11 b
+Fb(fop)n(en)6 b Fj(\()p Fe(\003)p Fb(ar)n(g)g Fd(;)h
+Fb(r)n(e)n(ad)p 568 804 V 18 w(mo)n(de)f Fj(\)\))12 b(=)g
+Fe(\014)p Fj(\))21 b Fe(f)f Fb(printf)11 b Fj(\()p Fi("Could)p
+Ff( )p Fi(not)p Ff( )p Fi(open)p Ff( )o Fi(file)p Ff( )o
+Fi(\045s.\\n)o(")r Fd(;)c Fe(\003)l Fb(ar)n(g)f Fj(\);)20
+b Fb(exit)6 b Fj(\(1\);)21 b Fe(g)42 854 y(g)42 904 y
+Fh(els)q(e)15 b(if)k Fj(\()p Fd(n)12 b Fj(=)g(2\))42
+953 y Fe(f)20 b Fb(op)n(en)p 171 953 V 19 w(\014le)6
+b Fj(\(&)p Fd(f)311 959 y Fc(1)330 953 y Fd(;)h Fi("Give)p
+Ff( )p Fi(another)p Ff( )o Fi(first)o Ff( )p Fi(file)o(")r
+Fd(;)g Fe(\003)m Fb(ar)n(g)998 949 y Fc(+)l(+)1047 953
+y Fj(\);)83 1003 y Fb(op)n(en)p 171 1003 V 19 w(\014le)f
+Fj(\(&)p Fd(f)311 1009 y Fc(2)330 1003 y Fd(;)h Fi("Give)p
+Ff( )p Fi(another)p Ff( )o Fi(secon)o(d)p Ff( )p Fi(fil)o(e")r
+Fd(;)g Fe(\003)l Fb(ar)n(g)f Fj(\);)42 1053 y Fe(g)42
+1103 y Fh(els)q(e)21 b Fe(f)g Fb(printf)10 b Fj(\()p
+Fi("No)p Ff( )p Fi(more)p Ff( )p Fi(than)p Ff( )p Fi(two)p
+Ff( )p Fi(c)o(omman)o(d)p Ff( )p Fi(lin)o(e)p Ff( )p
+Fi(ar)o(gumen)o(ts)p Ff( )p Fi(ar)o(e)p Ff( )p Fi(all)o(owed.)o(\\n")r
+Fj(\);)17 b Fb(exit)6 b Fj(\(1\);)21 b Fe(g)0 1157 y
+Fg(This)12 b(co)q(d)o(e)f(is)h(us)q(e)q(d)e(in)h(s)q(ect)o(ion)f(2.)0
+1256 y Fh(7.)48 b Fj(Th)o(e)18 b(fu)o(nct)o(ion)g Fb(op)n(en)p
+423 1256 V 16 w(\014le)23 b Fj(will)17 b(try)h(t)o(o)g(o)o(p)q(en)g(t)n
+(h)o(e)g(\014le)g Fb(name)24 b Fj(for)18 b(readin)o(g,)h(an)o(d)e(if)g
+(t)n(hi)q(s)h(f)q(ails)f(it)g(will)g(prompt)f(for)0 1306
+y(anot)n(h)o(er)h(\014le)g(n)o(am)o(e)f(u)o(n)o(t)o(il)g(it)g(h)o(as)h
+(su)o(cce)q(ss.)30 b(If)16 b(calle)q(d)h(wit)n(h)f Fb(name)22
+b Fj(=)17 b Fe(\014)p Fj(,)g(t)n(h)o(e)h(fu)o(nct)o(ion)f(st)o(art)o(s)
+h(wit)n(h)e(prompt)o(in)o(g)g(r)q(igh)o(t)0 1356 y(aw)o(ay)m(.)0
+1418 y Fe(h)7 b Fj(F)m(u)o(nct)o(ions)18 b Fg(5)7 b Fe(i)k
+Fj(+)p Fe(\021)42 1468 y Fh(v)o(oid)j Fb(op)n(en)p 233
+1468 V 19 w(\014le)26 b Fj(\()p Fh(FILE)17 b Fe(\003\003)p
+Fd(f)r(;)j Fh(c)o(h)o(ar)c Fe(\003)o Fb(pr)n(ompt)6 b
+Fd(;)20 b Fh(c)o(h)o(ar)c Fe(\003)o Fb(name)6 b Fj(\))42
+1518 y Fe(f)20 b Fh(c)o(h)o(ar)15 b Fb(buf)c Fj([80)o(];)83
+1580 y Fh(if)20 b Fj(\()p Fb(name)d Fj(=)12 b Fe(\014)d(_)g
+Fj(\()p Fe(\003)p Fd(f)17 b Fe(\()11 b Fb(fop)n(en)5
+b Fj(\()p Fb(name)h Fd(;)h Fb(r)n(e)n(ad)p 831 1580 V
+19 w(mo)n(de)f Fj(\)\))12 b(=)f Fe(\014)p Fj(\))125 1630
+y Fh(do)22 b Fe(f)f Fb(printf)10 b Fj(\()p Fi("\045s:)p
+Ff( )p Fi(")r Fd(;)d Fb(pr)n(ompt)t Fj(\);)21 b Fb(\017ush)5
+b Fj(\()p Fb(stdout)i Fj(\);)20 b Fb(sc)n(anf)12 b Fj(\()p
+Fi("\04579s")r Fd(;)7 b Fb(buf)i Fj(\);)21 b Fe(g)125
+1680 y Fh(while)14 b Fj(\(\()p Fe(\003)p Fd(f)j Fe(\()11
+b Fb(fop)n(en)5 b Fj(\()p Fb(buf)12 b Fd(;)7 b Fb(r)n(e)n(ad)p
+676 1680 V 18 w(mo)n(de)f Fj(\)\))12 b(=)g Fe(\014)p
+Fj(\);)42 1730 y Fe(g)0 1829 y Fh(8.)48 b(In)o(d)o(ex.)0
+1896 y Fb(ar)n(g)5 b Fj(:)42 b(2)p 115 1903 21 2 v -1
+w(,)23 b(6.)0 1946 y Fh(b)q(o)q(o)o(l)r Fj(:)41 b(1)p
+145 1953 V(,)22 b(5.)0 1996 y Fb(buf)11 b Fj(:)41 b(7)p
+118 2003 V(.)0 2047 y Fb(c)n(ol)6 b Fj(:)41 b(2)p 108
+2054 V(,)22 b(3,)g(4.)0 2097 y Fd(c)18 2103 y Fc(1)37
+2097 y Fj(:)41 b(2)p 90 2104 V -1 w(,)23 b(3,)f(4.)0
+2147 y Fd(c)18 2153 y Fc(2)37 2147 y Fj(:)41 b(2)p 90
+2154 V -1 w(,)23 b(3,)f(4.)0 2197 y Fi(EOF)r Fj(:)41
+b(3,)22 b(4.)0 2248 y Fb(exit)6 b Fj(:)41 b(6.)0 2298
+y Fd(f)t Fj(:)h(7)p 78 2305 V(.)0 2348 y Fb(\017ush)6
+b Fj(:)41 b(7.)0 2398 y Fb(fop)n(en)6 b Fj(:)41 b(6,)22
+b(7.)0 2449 y Fd(f)20 2455 y Fc(1)39 2449 y Fj(:)41 b(2)p
+92 2456 V(,)22 b(3,)g(6.)0 2499 y Fd(f)20 2505 y Fc(2)39
+2499 y Fj(:)41 b(2)p 92 2506 V(,)22 b(3,)g(6.)0 2549
+y Fb(getc)5 b Fj(:)41 b(3.)0 2599 y Fb(is)p 33 2599 13
+2 v 15 w(\014rst)6 b Fj(:)41 b(5)p 176 2606 21 2 v -1
+w(.)0 2650 y Fb(left)p 60 2650 13 2 v 14 w(mar)n(gin)6
+b Fj(:)41 b(2)p 256 2657 21 2 v -1 w(,)21 b(3.)0 2700
+y Fb(line)5 b Fj(:)41 b(2)p 124 2707 V(,)22 b(3,)g(4.)1017
+1896 y Fb(main)5 b Fj(:)41 b(2)p 1166 1903 V(.)1017 1946
+y Fd(n)p Fj(:)f(2)p 1094 1953 V(.)1017 1995 y Fb(name)5
+b Fj(:)41 b(7)p 1172 2002 V(.)1017 2045 y Fb(op)n(en)p
+1102 2045 13 2 v 16 w(\014le)5 b Fj(:)41 b(6,)21 b(7)p
+1280 2052 21 2 v(.)1017 2095 y Fb(printf)10 b Fj(:)41
+b(4,)20 b(5,)h(6,)g(7.)1017 2145 y Fb(pr)n(ompt)5 b Fj(:)41
+b(7)p 1202 2152 V(.)1017 2195 y Fb(r)n(e)n(ad)p 1095
+2195 13 2 v 15 w(mo)n(de)5 b Fj(:)41 b(6)p 1258 2202
+21 2 v(,)21 b(7.)1017 2244 y Fb(sc)n(anf)11 b Fj(:)41
+b(7.)1017 2294 y Fb(stdin)5 b Fj(:)41 b(6.)1017 2344
+y Fb(stdout)6 b Fj(:)41 b(7.)1017 2394 y Fb(the)p 1074
+2394 13 2 v 15 w(\014le)5 b Fj(:)41 b(4,)22 b(5)p 1252
+2401 21 2 v(.)p eop
+%%Trailer
+end
+userdict /end-hook known{end-hook}if
+%%EOF
diff --git a/web/c_cpp/macweave b/web/c_cpp/macweave
new file mode 120000
index 0000000000..221e337e3c
--- /dev/null
+++ b/web/c_cpp/macweave
@@ -0,0 +1 @@
+../systems/mac/macweave \ No newline at end of file