summaryrefslogtreecommitdiff
path: root/web/tango-weevil
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/tango-weevil
Initial commit
Diffstat (limited to 'web/tango-weevil')
-rw-r--r--web/tango-weevil/CHANGES3
-rw-r--r--web/tango-weevil/COPYING339
-rw-r--r--web/tango-weevil/Makefile86
-rw-r--r--web/tango-weevil/README34
-rw-r--r--web/tango-weevil/c_tango.c798
-rw-r--r--web/tango-weevil/c_weevil.tw173
-rw-r--r--web/tango-weevil/hello.tw69
-rw-r--r--web/tango-weevil/latex.tw304
-rw-r--r--web/tango-weevil/tango.c1017
-rw-r--r--web/tango-weevil/tango.h120
-rw-r--r--web/tango-weevil/tw.sty114
-rw-r--r--web/tango-weevil/userguid.tpc506
-rw-r--r--web/tango-weevil/weevdoc.tex44
-rw-r--r--web/tango-weevil/weevil.tw1367
-rw-r--r--web/tango-weevil/weevinfo.tw418
15 files changed, 5392 insertions, 0 deletions
diff --git a/web/tango-weevil/CHANGES b/web/tango-weevil/CHANGES
new file mode 100644
index 0000000000..bbd4bcd31e
--- /dev/null
+++ b/web/tango-weevil/CHANGES
@@ -0,0 +1,3 @@
+
+v1.0 - 08/24/95 - First official release
+
diff --git a/web/tango-weevil/COPYING b/web/tango-weevil/COPYING
new file mode 100644
index 0000000000..a43ea2126f
--- /dev/null
+++ b/web/tango-weevil/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/tango-weevil/Makefile b/web/tango-weevil/Makefile
new file mode 100644
index 0000000000..938e231bff
--- /dev/null
+++ b/web/tango-weevil/Makefile
@@ -0,0 +1,86 @@
+
+unexport GCC_EXEC_PREFIX
+
+CC = gcc
+
+CFLAGS=$(CDEBUGFLAGS)
+
+all: weevil
+
+TANGO_OBJS = tango.o c_tango.o
+
+TANGO_SRCS = tango.c c_tango.c
+
+WEEVIL_OBJS = weevil.o c_weevil.o latex.o
+
+WEEVIL_SRCS = weevil.c c_weevil.c latex.c
+
+WEEVIL_TANGOS = weevil.tw c_weevil.tw latex.tw
+
+WEEVIL_DOCS = weevinfo.tex weevil.tex c_weevil.tex latex.tex
+
+weevil: $(WEEVIL_OBJS)
+ $(CC) $(CFLAGS) -o weevil $(WEEVIL_OBJS)
+
+weevil.c: tango weevil.tw weevinfo.h
+ ./tango -autoxref -lang c weevil.tw >weevil.c
+
+c_weevil.c: tango c_weevil.tw weevinfo.h
+ ./tango -autoxref -lang c c_weevil.tw >c_weevil.c
+
+latex.c: tango latex.tw weevinfo.h
+ ./tango -autoxref -lang c latex.tw >latex.c
+
+weevinfo.h: tango weevinfo.tw
+ ./tango -autoxref -lang c weevinfo.tw >weevinfo.h
+
+weevdoc.dvi: $(WEEVIL_DOCS)
+ latex weevdoc
+
+weevinfo.tex: weevil weevinfo.tw
+ ./weevil -lang c weevinfo.tw >weevinfo.tex
+
+weevil.tex: weevil weevil.tw weevilref.xfr
+ ./weevil -lang c weevil.tw >weevil.tex
+
+weevilref.xfr: c_weevil.xfr latex.xfr
+ cat c_weevil.xfr latex.xfr >weevilref.xfr
+
+c_weevil.tex: weevil c_weevil.tw
+ ./weevil -lang c c_weevil.tw >c_weevil.tex
+
+latex.tex: weevil latex.tw
+ ./weevil -lang c latex.tw >latex.tex
+
+tango: $(TANGO_OBJS)
+ $(CC) $(CFLAGS) -o tango $(TANGO_OBJS)
+
+tango.o: tango.c tango.h
+
+c_tango.o: c_tango.c
+
+co:
+ co tango.c weevil.tw tw.sty
+
+doc: weevdoc.dvi userguid.dvi
+
+userguid.dvi: userguid.tex
+ latex userguid.tex
+ latex userguid.tex
+
+userguid.tex: userguid.tpc
+ gpic -t userguid.tpc >userguid.tex
+
+clean:
+ rm -f $(TANGO_OBJS) $(WEEVIL_OBJS)
+ rm -f weevil tango
+ rm -f weevinfo.xfr weevinfo.h weevinfo.tex weevinfo.aux
+ rm -f weevil.xfr weevil.c weevil.tex weevil.aux weevilref.xfr
+ rm -f c_weevil.xfr c_weevil.c c_weevil.tex c_weevil.aux
+ rm -f latex.xfr latex.c latex.tex latex.aux
+ rm -f hello.xfr hello.idx hello.ilg hello.ind hello.tex hello.aux
+ rm -f hello.log hello.dvi hello hello.c
+ rm -f weevdoc.idx weevdoc.ilg weevdoc.ind weevdoc.aux weevdoc.log
+ rm -f weevdoc.dvi weevdoc.toc
+ rm -f userguid.idx userguid.ilg userguid.ind userguid.aux
+ rm -f userguid.log userguid.dvi userguid.tex
diff --git a/web/tango-weevil/README b/web/tango-weevil/README
new file mode 100644
index 0000000000..4d72bc00b6
--- /dev/null
+++ b/web/tango-weevil/README
@@ -0,0 +1,34 @@
+This is the tango/weevil literate programming tool. It is a rather
+simple system for literate programming (much in the spirit of noweb)
+but it has some features I have not seen in other tools:
+
+ It is able to generate intra-file cross references. This
+ way, a code chunk can refer to code chunks in another
+ file without linking the files together.
+
+ The tangler is used to generate the cross references.
+ This makes it easy, since the tangler knows where the
+ output code is going (making determination of variable
+ instances easier) and it knows what code chunks it came
+ from.
+
+ It is written completely in ANSI-C; no esoteric languages
+ like icon are used so porting should be easy. Note that
+ this is ANSI C, if you are using old K&R you are working
+ in the dark.
+
+Tango/weevil will support multiple languages and output formats,
+although only ANSI C and LaTeX2e are currently supported. If you
+don't have LaTeX2e, get it, it is much nicer to use than plain LaTeX.
+Otherwise, you will have to write you own output routine for plain
+LaTeX, since many LaTeX2e features are used.
+
+A start of a user's document is included. It is named userguid.tpc
+and has gpic pictures in it. A file named userguid.tex is also
+included, it has the pictures already converted to tpic specials.
+
+This software has been tested for a while and seems stable. Still,
+it might not work for you. No guarantees.
+
+Corey Minyard
+minyard@metronet.com
diff --git a/web/tango-weevil/c_tango.c b/web/tango-weevil/c_tango.c
new file mode 100644
index 0000000000..78d11de8d7
--- /dev/null
+++ b/web/tango-weevil/c_tango.c
@@ -0,0 +1,798 @@
+/*
+ Tango/Weevil - A WEB Tangler and Weaver
+ Copyright (C) 1995 Corey Minyard
+
+ 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.
+
+ Corey Minyard - minyard@metronet.com
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "tango.h"
+
+#define GLOBAL 1
+#define PROC_DEFN 2
+#define INPROC 3
+#define PROC_CAN_DEF 4
+
+#define DEFINE 3
+#define VARDEF 4
+#define FOUND_OPER 5
+
+#define OPER 6
+#define NAME 7
+#define NONE 8
+#define PERIOD 9
+#define RESERVED_WORD 10
+#define SEMI 11
+#define NUMSIGN 12
+#define STRUCT 13
+
+typedef struct
+{
+ int code_state;
+ int last_token;
+ int nest_level;
+ int sqbrace_nest;
+ int paren_level;
+ bool name_seen;
+ bool is_static;
+ bool in_define;
+ bool in_number;
+ bool define_name_found;
+ bool lastescape;
+ char quotechar;
+ bool in_struct;
+ bool in_enum;
+ bool in_enum_define;
+ bool in_extern_c;
+ int struct_nest;
+ bool comment_after_star;
+ t_namelist *local_vars;
+ t_namelist *last_name;
+ int rword;
+ int extern_c_nest;
+} t_codeinfo_c;
+
+#define WHILE_RW 1
+#define DO_RW 2
+#define FOR_RW 3
+#define IF_RW 4
+#define SWITCH_RW 5
+#define CASE_RW 6
+#define DEFAULT_RW 7
+#define GOTO_RW 8
+#define CONTINUE_RW 9
+#define BREAK_RW 10
+#define RETURN_RW 11
+#define AUTO_RW 12
+#define REGISTER_RW 13
+#define STATIC_RW 14
+#define EXTERN_RW 15
+#define TYPEDEF_RW 16
+#define CONST_RW 17
+#define VOLATILE_RW 18
+#define STRUCT_RW 19
+#define UNION_RW 20
+#define SIZEOF_RW 21
+#define ELSE_RW 22
+#define ENUM_RW 23
+
+static struct rword_s
+{
+ char *name;
+ int val;
+ int length;
+} rwords[] =
+{
+ { "while", WHILE_RW, 5 },
+ { "do", DO_RW, 2 },
+ { "for", FOR_RW, 3 },
+ { "if", IF_RW, 2 },
+ { "switch", SWITCH_RW, 6 },
+ { "case", CASE_RW, 4 },
+ { "default", DEFAULT_RW, 7 },
+ { "goto", GOTO_RW, 4 },
+ { "continue", CONTINUE_RW, 8 },
+ { "break", BREAK_RW, 5 },
+ { "return", RETURN_RW, 6 },
+ { "auto", AUTO_RW, 4 },
+ { "register", REGISTER_RW, 8 },
+ { "static", STATIC_RW, 6 },
+ { "extern", EXTERN_RW, 6 },
+ { "typedef", TYPEDEF_RW, 7 },
+ { "const", CONST_RW, 5 },
+ { "volatile", VOLATILE_RW, 8 },
+ { "struct", STRUCT_RW, 6 },
+ { "union", UNION_RW, 5 },
+ { "sizeof", SIZEOF_RW, 6 },
+ { "else", ELSE_RW, 4 },
+ { "enum", ENUM_RW, 4 }
+};
+static const int num_rw = (sizeof(rwords) / sizeof(struct rword_s));
+
+static int
+is_reserved_word(char *name,
+ int length)
+{
+ int i;
+
+ for (i=0; i<num_rw; i++)
+ {
+ if ( (length == rwords[i].length)
+ && (strncmp(name, rwords[i].name, length) == 0))
+ {
+ return(rwords[i].val);
+ }
+ }
+
+ return(-1);
+}
+
+static char *(intrinsic_types[]) =
+{
+ "int", "void", "char", "long", "unsigned", "float", "double",
+ "short", NULL
+};
+
+static bool
+is_intrinsic_type(char *name)
+{
+ int i;
+
+ for (i=0; intrinsic_types[i] != NULL; i++)
+ {
+ if (strcmp(name, intrinsic_types[i]) == 0)
+ {
+ break;
+ }
+ }
+
+ return(intrinsic_types[i] != NULL);
+}
+
+static void
+add_name_define(t_lptangodat *lptd,
+ t_namelist *item,
+ t_codeinfo_c *ci)
+{
+ if (! (lptd->auto_xref))
+ {
+ free_namelist_item(lptd, item);
+ }
+ else if (ci->in_define)
+ {
+ list_insert_unique(lptd, &(lptd->curr_macro->pounddefs), item);
+ }
+ else if (! ci->in_struct)
+ {
+ switch(ci->code_state)
+ {
+ case GLOBAL:
+ if (ci->is_static)
+ {
+ list_insert_unique(lptd, &(lptd->curr_macro->staticdefs), item);
+ }
+ else
+ {
+ list_insert_unique(lptd, &(lptd->curr_macro->globaldefs), item);
+ }
+ break;
+
+ case PROC_DEFN:
+ case PROC_CAN_DEF:
+ list_insert_unique(lptd, &(ci->local_vars), item);
+ item->u.nest_val = ci->nest_level;
+ break;
+
+ default:
+ free_namelist_item(lptd, item);
+ }
+ }
+ else
+ {
+ free_namelist_item(lptd, item);
+ }
+}
+
+static void
+add_name_use(t_lptangodat *lptd,
+ t_namelist *item,
+ t_codeinfo_c *ci)
+{
+ if (! (lptd->auto_xref))
+ {
+ free_namelist_item(lptd, item);
+ }
+ else if (find_name_in_list(lptd, ci->local_vars, item) != NULL)
+ {
+ /* Don't track uses of local variables. */
+ free_namelist_item(lptd, item);
+ }
+ else if (!is_intrinsic_type(item->name))
+ {
+ list_insert_unique(lptd, &(lptd->curr_macro->uses), item);
+ }
+ else
+ {
+ free_namelist_item(lptd, item);
+ }
+}
+
+static void
+destroy_locals(t_lptangodat *lptd,
+ t_codeinfo_c *ci)
+{
+ t_namelist *hold;
+
+
+ while ( (ci->local_vars != NULL)
+ && (ci->local_vars->u.nest_val >= ci->nest_level))
+ {
+ hold = ci->local_vars;
+ ci->local_vars = hold->next;
+ free_namelist_item(lptd, hold);
+ }
+}
+
+void
+c_scan_input(t_lptangodat *lptd,
+ char *line,
+ int length,
+ int lineno)
+{
+ char *cp;
+ char *start_tok;
+ int count;
+ t_namelist *defname;
+ t_codeinfo_c *ci;
+
+ ci = lptd->code_info;
+ count = 0;
+ cp = line;
+ start_tok = NULL;
+ while (count < length)
+ {
+ if (lptd->instring)
+ {
+ while (TRUE)
+ {
+ if ( (*cp == ci->quotechar)
+ && (! ci->lastescape))
+ {
+ lptd->instring = FALSE;
+ break;
+ }
+
+ if (count >= length)
+ {
+ break;
+ }
+ if ( (*cp == '\\')
+ && (! ci->lastescape))
+ {
+ ci->lastescape = TRUE;
+ }
+ else
+ {
+ ci->lastescape = FALSE;
+ }
+ cp++;
+ count++;
+ }
+ if ( (ci->last_token == RESERVED_WORD)
+ && (ci->rword == EXTERN_RW)
+ && (count > 2)
+ && ((*(cp-1) == 'C') && (*(cp-2) == '"')))
+ {
+ ci->in_extern_c = TRUE;
+ ci->extern_c_nest = ci->nest_level;
+ }
+ ci->last_token = NAME;
+ }
+ else if (lptd->in_comment)
+ {
+ while (TRUE)
+ {
+ if (count >= length)
+ {
+ break;
+ }
+ else
+ {
+ if ( (ci->comment_after_star)
+ && (*cp == '/'))
+ {
+ lptd->in_comment = FALSE;
+ break;
+ }
+
+ if (*cp == '*')
+ {
+ ci->comment_after_star = TRUE;
+ }
+ else
+ {
+ ci->comment_after_star = FALSE;
+ }
+ }
+
+ cp++;
+ count++;
+ }
+ }
+ else if ( ((*cp >= 'a') && (*cp <= 'z'))
+ || ((*cp >= 'A') && (*cp <= 'Z'))
+ || ((start_tok != NULL) && ((*cp >= '0') && (*cp <= '9')))
+ || (*cp == '_'))
+ {
+ if ((start_tok == NULL) && (!ci->in_number))
+ {
+ start_tok = cp;
+ }
+ }
+ else if ( ((*cp >= '0') && (*cp <= '9'))
+ || ( ci->in_number
+ && ( (*cp == '.')
+ || (*cp == '+')
+ || (*cp == '-'))))
+ {
+ ci->in_number = TRUE;
+ }
+ else
+ {
+ ci->in_number = FALSE;
+
+ if (ci->in_define)
+ {
+ if ( (*cp == '/')
+ && ((count+1) < length)
+ && (*(cp+1) == '*'))
+ {
+ cp++;
+ count++;
+ lptd->in_comment = TRUE;
+ }
+ else if (ci->last_token == NUMSIGN)
+ {
+ ci->last_token = NONE;
+
+ /* got a # directive. We are only really
+ interested in defines */
+ if ( (start_tok != NULL)
+ && ((cp - start_tok) == 6)
+ && (strncmp(start_tok, "define", 6) == 0))
+ {
+ ci->define_name_found = FALSE;
+ }
+ else
+ {
+ ci->define_name_found = TRUE;
+ }
+ }
+ else if ( (start_tok != NULL)
+ && (! ci->define_name_found))
+ {
+ defname = create_namelist_item(lptd,
+ start_tok,
+ cp - start_tok);
+ add_name_define(lptd, defname, ci);
+ ci->define_name_found = TRUE;
+ }
+ else if ( (*cp == '\\')
+ && ((count+1) < length))
+ {
+ cp++;
+ count++;
+ }
+ else if (*cp == '\n')
+ {
+ ci->in_define = FALSE;
+ }
+ start_tok = NULL;
+ }
+ else
+ {
+ if ( (start_tok != NULL) /* We just finished with a name */
+ && (ci->last_token != PERIOD)) /* Ignore struct elements */
+ {
+ ci->rword = is_reserved_word(start_tok, cp - start_tok);
+ if (ci->rword != -1)
+ {
+ ci->last_token = RESERVED_WORD;
+
+ /* If static, save that for later. */
+ if (ci->rword == STATIC_RW)
+ {
+ ci->is_static = TRUE;
+ }
+ if ( ( (ci->rword == STRUCT_RW)
+ || (ci->rword == UNION_RW))
+ && (! ci->in_struct))
+ {
+ ci->in_struct = TRUE;
+ ci->struct_nest = ci->nest_level;
+ ci->last_token = STRUCT;
+ }
+ else if (ci->rword == ENUM_RW)
+ {
+ ci->in_enum = TRUE;
+ }
+ /* no other reserved words really matter. */
+ }
+
+ /* The first name in a line is a name use, the rest
+ must be definitions unless then are in {}. Also,
+ a name right after struct or union is a define */
+ else
+ {
+ if (ci->code_state == GLOBAL)
+ {
+ /* The nesting level must be 0 or at the same
+ level as an extern "C", a name see, and not
+ in square braces. */
+ if ( ( (ci->nest_level == 0)
+ || ( (ci->in_extern_c)
+ && (ci->nest_level <= (ci->extern_c_nest+1)))
+ || (ci->in_struct))
+ && (ci->name_seen)
+ && (ci->sqbrace_nest == 0))
+ {
+ /* This is a variable or type declaration. */
+ ci->last_name = create_namelist_item(lptd,
+ start_tok,
+ cp - start_tok);
+ add_name_define(lptd, ci->last_name, ci);
+ }
+ /* Everything in an enum is a definition */
+ else if (ci->in_enum_define)
+ {
+ /* This is a variable or type declaration. */
+ ci->last_name = create_namelist_item(lptd,
+ start_tok,
+ cp - start_tok);
+ add_name_define(lptd, ci->last_name, ci);
+ }
+ else
+ {
+ /* This is a variable or type use. */
+
+ ci->name_seen = TRUE;
+ ci->last_name = create_namelist_item(lptd,
+ start_tok,
+ cp - start_tok);
+ add_name_use(lptd, ci->last_name, ci);
+ }
+ }
+ else
+ {
+ /* Handle a name in a procedure or parameter list. */
+ if ( ( (ci->code_state == PROC_CAN_DEF)
+ || (ci->code_state == PROC_DEFN))
+ && (ci->name_seen)
+ && (ci->sqbrace_nest == 0))
+ {
+ /* This is a variable or type declaration. */
+ ci->last_name = create_namelist_item(lptd,
+ start_tok,
+ cp - start_tok);
+ add_name_define(lptd, ci->last_name, ci);
+ }
+ else
+ {
+ /* This is a variable or type use. */
+
+ ci->name_seen = TRUE;
+ ci->last_name = create_namelist_item(lptd,
+ start_tok,
+ cp - start_tok);
+ add_name_use(lptd, ci->last_name, ci);
+ }
+ }
+ ci->last_token = NAME;
+ }
+ }
+ start_tok = NULL;
+
+ switch(*cp)
+ {
+ case ' ': case '\t':
+ break;
+
+ case ';':
+ if ( ( (ci->nest_level == 0)
+ || ( (ci->in_extern_c)
+ && (ci->nest_level <= (ci->extern_c_nest+1))))
+ && (ci->code_state == INPROC))
+ {
+ destroy_locals(lptd, ci);
+ ci->code_state = GLOBAL;
+ }
+ if ( (ci->in_struct)
+ && (ci->nest_level <= ci->struct_nest))
+ {
+ ci->in_struct = FALSE;
+ }
+
+ ci->last_name = NULL;
+ ci->is_static = FALSE;
+ ci->name_seen = FALSE;
+
+ ci->last_token = SEMI;
+ break;
+
+ case ',':
+ if (ci->code_state == PROC_DEFN)
+ {
+ /* In a list of procedure parameters, make commas
+ look like semicolons. */
+ ci->last_name = NULL;
+ ci->last_token = SEMI;
+ ci->is_static = FALSE;
+ ci->name_seen = FALSE;
+ }
+ else if (ci->last_token != NAME)
+ {
+ /* Probably passing parameters to a procedure call,
+ just ignore. */
+ }
+ break;
+
+ case ')':
+ ci->paren_level--;
+ if ( (ci->paren_level == 0)
+ && (ci->code_state == PROC_DEFN))
+ {
+ ci->code_state = INPROC;
+ }
+ break;
+
+ case '=':
+ if (ci->code_state == PROC_CAN_DEF)
+ {
+ /* We've seen an assign, we are no longer
+ in definition mode. */
+ ci->code_state = INPROC;
+
+ if ( (ci->last_name != NULL)
+ && (ci->last_name == ci->local_vars))
+ {
+ /* I thought the last name was a define,
+ it is acually a use. */
+ ci->local_vars = ci->last_name->next;
+
+ add_name_use(lptd, ci->last_name, ci);
+ }
+ }
+
+ ci->last_token = OPER;
+ break;
+
+ case '(':
+ if ( (ci->code_state == GLOBAL)
+ && (ci->last_token == NAME))
+ {
+ ci->code_state = PROC_DEFN;
+ ci->paren_level = 1;
+ ci->last_name = NULL;
+ ci->name_seen = FALSE;
+ }
+ else
+ {
+ ci->paren_level++;
+ if ( (ci->last_token == NAME)
+ && (ci->code_state == PROC_CAN_DEF)
+ && (ci->last_name != NULL)
+ && (ci->last_name == ci->local_vars))
+ {
+ /* I thought the last name was a define,
+ it is acually a use. */
+ ci->local_vars = ci->last_name->next;
+
+ add_name_use(lptd, ci->last_name, ci);
+ }
+ }
+ break;
+
+ case '.':
+ ci->last_token = PERIOD;
+ break;
+
+ case '-':
+ if ( ((count+1) < length)
+ && (*(cp+1) == '>'))
+ {
+ cp++;
+ count++;
+ /* Even though '->' is not a period, it works
+ about the same for our purposes. */
+ ci->last_token = PERIOD;
+ }
+ else
+ {
+ ci->last_token = OPER;
+ }
+ break;
+
+ case '{':
+ if (ci->code_state == INPROC)
+ {
+ ci->code_state = PROC_CAN_DEF; /* Can define local
+ vars now. */
+ }
+ else if ( (ci->code_state == GLOBAL)
+ && (ci->last_name != NULL)
+ && (lptd->curr_macro->uses != NULL)
+ && (lptd->curr_macro->uses == ci->last_name)
+ && ( ( (ci->in_struct)
+ && (ci->struct_nest == ci->nest_level))
+ || (ci->in_enum)))
+ {
+ /* I thought the last item was a use, it was actually
+ a structure or enum define. */
+ lptd->curr_macro->uses = ci->last_name->next;
+
+ if (ci->in_struct)
+ {
+ ci->in_struct = FALSE;
+ add_name_define(lptd, ci->last_name, ci);
+ ci->in_struct = TRUE;
+ }
+ else
+ {
+ ci->in_enum_define = TRUE;
+ add_name_define(lptd, ci->last_name, ci);
+ }
+ }
+ ci->nest_level++;
+ ci->last_name = NULL;
+ ci->name_seen = FALSE;
+
+ ci->last_token = NONE;
+ break;
+
+ case '}':
+ /* Make sure to get rid of anything declared in this block */
+ destroy_locals(lptd, ci);
+ ci->nest_level--;
+
+ ci->in_enum = FALSE; /* an rbrace will alway finish an enum */
+ ci->in_enum_define = FALSE;
+
+ /* check to see if this is the end of an extern "C" { } */
+ if ((ci->in_extern_c) && (ci->extern_c_nest == ci->nest_level))
+ {
+ ci->in_extern_c = FALSE;
+ }
+
+ /* An end brace can be like a name, such as at the end of
+ a structure definition. */
+ ci->last_token = NAME;
+ ci->name_seen = TRUE;
+
+ if ( (ci->in_struct)
+ && (ci->struct_nest >= ci->nest_level))
+ {
+ ci->in_struct = FALSE;
+ }
+
+ if ( ( (ci->nest_level == 0)
+ || ( (ci->in_extern_c)
+ && (ci->nest_level <= (ci->extern_c_nest+1))))
+ && ( (ci->code_state == INPROC)
+ || (ci->code_state == PROC_CAN_DEF)))
+ {
+ ci->code_state = GLOBAL;
+ ci->name_seen = FALSE;
+ ci->last_token = NONE;
+ }
+ else if (ci->code_state == PROC_CAN_DEF)
+ {
+ ci->code_state = INPROC;
+ }
+ break;
+
+ case '"':
+ case '\'':
+ ci->quotechar = *cp;
+ lptd->instring = TRUE;
+ ci->lastescape = FALSE;
+ break;
+
+ case '[':
+ (ci->sqbrace_nest)++;
+ break;
+
+ case ']':
+ (ci->sqbrace_nest)--;
+ break;
+
+ case '#':
+ ci->in_define = TRUE;
+ ci->last_token = NUMSIGN;
+ break;
+
+ case '/':
+ if ( ((count+1) < length)
+ && (*(cp+1) == '*'))
+ {
+ cp++;
+ count++;
+ lptd->in_comment = TRUE;
+ ci->comment_after_star = FALSE;
+ }
+ else
+ {
+ ci->last_token = OPER;
+ }
+ break;
+
+ default:
+ ci->last_token = OPER;
+ break;
+ }
+ }
+ }
+
+ cp++;
+ count++;
+ }
+}
+
+void
+c_output_linenum(t_lptangodat *lptd,
+ int lineno,
+ char *filename)
+{
+ fprintf(lptd->outfile, "#line %d \"%s\"\n", lineno, filename);
+}
+
+void
+init_c_lang(t_lptangodat *lptd)
+{
+ t_codeinfo_c *ci;
+
+ lptd->code_info = malloc(sizeof(t_codeinfo_c));
+ if (lptd->code_info == NULL)
+ {
+ fprintf(stderr, "Unable to allocate enough memory\n");
+ exit(1);
+ }
+
+ ci = lptd->code_info;
+ ci->code_state = GLOBAL;
+ ci->last_token = NONE;
+ ci->nest_level = 0;
+ ci->sqbrace_nest = 0;
+ ci->paren_level = 0;
+ ci->name_seen = FALSE;
+ ci->is_static = FALSE;
+ ci->in_define = FALSE;
+ ci->in_number = FALSE;
+ ci->define_name_found = FALSE;
+ ci->lastescape = FALSE;
+ ci->comment_after_star = FALSE;
+ ci->quotechar = '\0';
+ ci->local_vars = NULL;
+ ci->last_name = NULL;
+ ci->in_struct = FALSE;
+ ci->in_enum = FALSE;
+ ci->in_enum_define = FALSE;
+ ci->in_extern_c = FALSE;
+ ci->struct_nest = 0;
+}
diff --git a/web/tango-weevil/c_weevil.tw b/web/tango-weevil/c_weevil.tw
new file mode 100644
index 0000000000..a856fdef5a
--- /dev/null
+++ b/web/tango-weevil/c_weevil.tw
@@ -0,0 +1,173 @@
+%
+% Tango/Weevil - A WEB Tangler and Weaver
+% Copyright (C) 1995 Corey Minyard
+%
+% 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.
+%
+% Corey Minyard - minyard@metronet.com
+%
+@includefile weevinfo.xfr
+
+\section{C Language Handler Intro}
+This module holds the routines used to process ``C'' code for weevil.
+
+@code <*>
+@<Includes>
+@<Structures>
+@<c_handle_char>
+@<init_c_lang>
+@endcode
+
+\section{Includes}
+
+@code <Includes>
+#include <stdio.h>
+#include <stdlib.h>
+#include "weevinfo.h"
+@endcode
+
+\section{Structures}
+
+@code <Structures>
+typedef struct
+{
+ bool in_comment;
+ int quote_char;
+} t_c_lang;
+@endcode
+
+\section{c\_handler\_char}
+
+\begin{twproc}{c\_handle\_char}
+\Description Handles a character for the ``C'' language. It will
+ scan the input and return the proper code depending
+ on if the code is currently in a string or comment.
+\ReturnValues \verb|int| - May be one of the following:
+ \begin{twparmlist}
+ \item[PROCESS\_CHAR\_NORMALLY] This is a standard
+ character that
+ should be handled normally by weevil.
+ \item[PROCESS\_CHAR\_INSTRING] This character is in
+ a string or
+ comment, it should not be scanned for special
+ weevil characters.
+ \item[PROCESS\_CHAR\_SKIPNEXT] This character and the
+ following character should be skipped without
+ being scanned for special weevil characters.
+ \end{twparmlist}
+\Inputs \begin{twparmlist}
+ \item[lpwd] Weevil information.
+ \item[c] The current input character.
+ \item[next\_c] The next input character.
+ \end{twparmlist}
+\StartCode
+@code <c_handle_char>
+int
+c_handle_char(t_lpweevildat *lpwd,
+ char c,
+ char next_c)
+{
+ int retval;
+ t_c_lang *c_info;
+
+
+ c_info = lpwd->lang_data;
+ if (c_info->in_comment)
+ {
+ if ((c == '*') && (next_c == '/'))
+ {
+ c_info->in_comment = FALSE;
+ retval = PROCESS_CHAR_SKIPNEXT;
+ }
+ else
+ {
+ retval = PROCESS_CHAR_INSTRING;
+ }
+ }
+ else if (c_info->quote_char != -1)
+ {
+ if (c == c_info->quote_char)
+ {
+ c_info->quote_char = -1;
+ retval = PROCESS_CHAR_INSTRING;
+ }
+ else if (c == '\\')
+ {
+ retval = PROCESS_CHAR_SKIPNEXT;
+ }
+ else
+ {
+ retval = PROCESS_CHAR_INSTRING;
+ }
+ }
+ else
+ {
+ retval = PROCESS_CHAR_NORMALLY;
+ switch(c)
+ {
+ case '\'':
+ case '"':
+ c_info->quote_char = c;
+ retval = PROCESS_CHAR_INSTRING;
+ break;
+
+ case '/':
+ if (next_c == '*')
+ {
+ c_info->in_comment = TRUE;
+ retval = PROCESS_CHAR_INSTRING;
+ break;
+ }
+ break;
+
+ default:
+ /* Nothing to do. */
+ break;
+ }
+ }
+
+ return(retval);
+}
+@endcode
+\end{twproc}
+
+\section{init\_c\_lang}
+
+\begin{twproc}{init\_c\_lang}
+\Description Initializes the ``C'' language handler. It allocates
+ some memory and initializes it.
+\Inputs \begin{twparmlist}
+ \item[lpwd] Weevil information.
+ \end{twparmlist}
+\StartCode
+@code <init_c_lang>
+void
+init_c_lang(t_lpweevildat *lpwd)
+{
+ t_c_lang *c_info;
+
+ c_info = malloc(sizeof(*c_info));
+ if (c_info == NULL)
+ {
+ fprintf(stderr, "Unable to allocate enough memory\n");
+ exit(1);
+ }
+
+ c_info->quote_char = -1;
+ c_info->in_comment = FALSE;
+ lpwd->lang_data = c_info;
+}
+@endcode
+\end{twproc}
diff --git a/web/tango-weevil/hello.tw b/web/tango-weevil/hello.tw
new file mode 100644
index 0000000000..b43f32f45d
--- /dev/null
+++ b/web/tango-weevil/hello.tw
@@ -0,0 +1,69 @@
+\documentclass{article}
+\usepackage{tw,makeidx}
+\title{Hello World --- A Famous Program}
+\author{Corey Minyard}
+\date{\today}
+\makeindex
+\begin{document}
+\maketitle
+\section{Description}
+
+This program is the famous ``hello world'' program. Certainly we have
+all written one of these programs.
+
+\section{Code}
+
+\subsection{Start Macro}
+This is the main part of the program.
+@code <*>
+@<Includes>
+@<Routines>
+@endcode
+
+\subsection{Includes}
+This program needs \texttt{stdio.h} because it uses printf.
+@code <Includes>
+#include <stdio.h>
+@endcode
+
+\subsection{Routines}
+This program only has one routine, the main routine.
+
+@code <Routines>
+@<main>
+@endcode
+
+\begin{twproc}{main}
+\Description The main routine.
+\ReturnValues \verb|int| - Program return code
+\SideEffects Well, it prints something!
+\Inputs \begin{twparmlist}
+ \item[argc] Argument count
+ \item[argv] The arguments
+ \end{twparmlist}
+\StartCode
+@code <main>
+int
+main(int argc,
+ char *argv)
+{
+ @<Output Hello>
+ @<Leave Program>
+}
+@endcode
+
+\subsection{Output Hello}
+This macro actually does the output.
+@code <Output Hello>
+ printf("hello world\n");
+@endcode
+
+\subsection{Leave Program}
+This macro causes the program to exit.
+@code <Leave Program>
+ exit(0);
+@endcode
+\end{twproc}
+
+\printindex
+\end{document}
diff --git a/web/tango-weevil/latex.tw b/web/tango-weevil/latex.tw
new file mode 100644
index 0000000000..33d0352c24
--- /dev/null
+++ b/web/tango-weevil/latex.tw
@@ -0,0 +1,304 @@
+%
+% Tango/Weevil - A WEB Tangler and Weaver
+% Copyright (C) 1995 Corey Minyard
+%
+% 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.
+%
+% Corey Minyard - minyard@metronet.com
+%
+@includefile weevinfo.xfr
+
+\section{\LaTeX\ Output Handler Intro}
+Due to the large number of functions of such a trivial nature, this
+routine is not currently commented very well. The formatting given
+depends a lot on the tw.sty file that holds the \LaTeX\ macros used
+by this file.
+
+Note that in labels, the names are stripped of everything but periods
+and asterisks, so names must be unique to that level.
+
+@code <*>
+#include <stdio.h>
+#include <stdlib.h>
+#include "weevinfo.h"
+
+@<t_latex_data>
+@<output_name>
+@<strip_name>
+@<Init>
+@<Macro Routines>
+@<Output Character>
+@<Uses Routines>
+@<Declare Routines>
+@endcode
+
+@code <t_latex_data>
+typedef struct s_latex_data
+{
+ int column;
+} t_latex_data;
+@endcode
+
+@code <output_name>
+static void
+output_name(t_lpweevildat *lpwd,
+ char *name)
+{
+ while (*name != '\0')
+ {
+ if ( ((*name >= 'a') && (*name <= 'z'))
+ || ((*name >= 'A') && (*name <= 'Z'))
+ || ((*name >= '0') && (*name <= '9'))
+ || ((*name == ' ')))
+ {
+ fputc(*name, lpwd->outfile);
+ }
+ else if (*name == '_')
+ {
+ fputs("\\_", lpwd->outfile);
+ }
+ else
+ {
+ fprintf(lpwd->outfile, "\\char%d ", *name);
+ }
+
+ name++;
+ }
+}
+@endcode
+
+@code <strip_name>
+static void
+strip_name(t_lpweevildat *lpwd,
+ char *name)
+{
+ while (*name != '\0')
+ {
+ if ( ((*name >= 'a') && (*name <= 'z'))
+ || ((*name >= 'A') && (*name <= 'Z'))
+ || ((*name >= '0') && (*name <= '9')))
+ {
+ fputc(*name, lpwd->outfile);
+ }
+ else
+ {
+ switch(*name)
+ {
+ case '.':
+ case '*':
+ fputc(*name, lpwd->outfile);
+ break;
+ }
+ }
+
+ name++;
+ }
+}
+@endcode
+
+@code <Init>
+void
+latex_mode_init(t_lpweevildat *lpwd)
+{
+ t_latex_data *ltd;
+
+ ltd = malloc(sizeof(*ltd));
+ if (ltd == NULL)
+ {
+ fprintf(stderr, "Unable to allocate memory\n");
+ exit(1);
+ }
+ ltd->column = 1;
+ lpwd->mode_data = ltd;
+}
+@endcode
+
+@code <Macro Routines>
+void
+latex_begin_macro(t_lpweevildat *lpwd,
+ char *name)
+{
+ fprintf(lpwd->outfile, "\\begin{twcodechunk}\n");
+ fprintf(lpwd->outfile, "\\begingroup\\medskip\n");
+ fprintf(lpwd->outfile, "\\twmacrodecl{");
+ output_name(lpwd, name);
+ fprintf(lpwd->outfile, "}{");
+ strip_name(lpwd, lpwd->curr_filename);
+ fprintf(lpwd->outfile, ":macro:");
+ strip_name(lpwd, name);
+ fprintf(lpwd->outfile, "}\n");
+ fprintf(lpwd->outfile, "\\begin{verbatimcmd}\\twstartcode\n");
+}
+
+void
+latex_end_macro(t_lpweevildat *lpwd)
+{
+ fprintf(lpwd->outfile, "\\twendcode\\end{verbatimcmd}\n");
+ fprintf(lpwd->outfile, "\\endgroup");
+}
+
+void
+latex_finalend_chunk(t_lpweevildat *lpwd)
+{
+ fprintf(lpwd->outfile, "\\end{twcodechunk}\n");
+}
+
+void
+latex_output_macro_use(t_lpweevildat *lpwd,
+ char *macro_name)
+{
+ fprintf(lpwd->outfile, "\\twmacrouse{");
+ output_name(lpwd, macro_name);
+ fprintf(lpwd->outfile, "}{");
+ strip_name(lpwd, lpwd->curr_filename);
+ fprintf(lpwd->outfile, ":macro:");
+ strip_name(lpwd, macro_name);
+ fprintf(lpwd->outfile, "}");
+}
+
+void
+latex_output_linenum(t_lpweevildat *lpwd)
+{
+ t_latex_data *ltd;
+
+ ltd = lpwd->mode_data;
+ fprintf(lpwd->outfile, "%4d ", lpwd->code_lineno);
+ ltd->column = 1;
+}
+
+void
+latex_output_after_xrefs(t_lpweevildat *lpwd)
+{
+ fprintf(lpwd->outfile, "\\medskip\n");
+}
+@endcode
+
+@code <Output Character>
+void
+latex_output_char(t_lpweevildat *lpwd,
+ char c)
+{
+ t_latex_data *ltd;
+
+ ltd = lpwd->mode_data;
+ if ((c == '{') || (c == '}'))
+ {
+ fputc('\\', lpwd->outfile);
+ fputc(c, lpwd->outfile);
+ ltd->column++;
+ }
+ else if (c == '\\')
+ {
+ fputs("\\(\\backslash\\)", lpwd->outfile);
+ ltd->column++;
+ }
+ else if (c == '\t')
+ {
+ fputc(' ', lpwd->outfile);
+ ltd->column++;
+ while ((ltd->column % 8) != 1)
+ {
+ fputc(' ', lpwd->outfile);
+ ltd->column++;
+ }
+ }
+ else if (c == '\n')
+ {
+ fputc(c, lpwd->outfile);
+ ltd->column = 1;
+ }
+ else
+ {
+ fputc(c, lpwd->outfile);
+ ltd->column++;
+ }
+}
+@endcode
+
+@code <Uses Routines>
+void
+latex_output_begin_uses(t_lpweevildat *lpwd)
+{
+ fprintf(lpwd->outfile, "\\begin{twuses}\n");
+}
+
+void
+latex_output_end_uses(t_lpweevildat *lpwd)
+{
+ fprintf(lpwd->outfile, "\\end{twuses}\n");
+}
+
+void
+latex_output_use_start(t_lpweevildat *lpwd,
+ char *name)
+{
+ fprintf(lpwd->outfile, "\\twuse{");
+ output_name(lpwd, name);
+ fprintf(lpwd->outfile, "} ");
+}
+
+void
+latex_output_use_end(t_lpweevildat *lpwd,
+ char *name)
+{
+ fprintf(lpwd->outfile, "\\\\\n");
+}
+
+void
+latex_output_use_ref(t_lpweevildat *lpwd,
+ char *file,
+ char *macro,
+ char *name)
+{
+ fputc('(', lpwd->outfile);
+ if (file != NULL)
+ {
+ output_name(lpwd, file);
+ fputc(':', lpwd->outfile);
+ }
+ output_name(lpwd, macro);
+ fputc(')', lpwd->outfile);
+}
+
+void
+latex_output_between_use_refs(t_lpweevildat *lpwd,
+ char *name)
+{
+ fputc(' ', lpwd->outfile);
+}
+@endcode
+
+@code <Declare Routines>
+void
+latex_output_begin_decls(t_lpweevildat *lpwd)
+{
+ fprintf(lpwd->outfile, "\\begin{twdecls}\n");
+}
+
+void
+latex_output_end_decls(t_lpweevildat *lpwd)
+{
+ fprintf(lpwd->outfile, "\\end{twdecls}\n");
+}
+
+void
+latex_output_decl(t_lpweevildat *lpwd,
+ char *name)
+{
+ fprintf(lpwd->outfile, "\\twdecl{");
+ output_name(lpwd, name);
+ fprintf(lpwd->outfile, "}\\\\\n");
+}
+@endcode
diff --git a/web/tango-weevil/tango.c b/web/tango-weevil/tango.c
new file mode 100644
index 0000000000..0ef355e22a
--- /dev/null
+++ b/web/tango-weevil/tango.c
@@ -0,0 +1,1017 @@
+/*
+ Tango/Weevil - A WEB Tangler and Weaver
+ Copyright (C) 1995 Corey Minyard
+
+ 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.
+
+ Corey Minyard - minyard@metronet.com
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+
+#define SKIP_DOCUMENTATION 1
+#define OUTPUT_CODE 2
+
+#define GOT_LINE 1
+#define END_OF_FILE 0
+
+#define MAX_FILENAME_LENGTH 200
+
+#include "tango.h"
+
+char *
+r_strtok(char *data,
+ char *sstr,
+ char **next_data)
+{
+ char *retval;
+
+
+ while ( (*data != '\0')
+ && (strchr(sstr, *data) != NULL))
+ {
+ data++;
+ }
+
+ retval = data;
+ while ( (*data != '\0')
+ && (strchr(sstr, *data) == NULL))
+ {
+ data++;
+ }
+
+ if (retval == data)
+ {
+ retval = NULL;
+ }
+ else
+ {
+ if (*data != '\0')
+ {
+ *data = '\0';
+ data++;
+ }
+
+ if (next_data != NULL)
+ {
+ *next_data = data;
+ }
+ }
+
+ return(retval);
+}
+
+char *
+stralloc(char *str,
+ int length)
+{
+ char *retval;
+
+ if (length == 0)
+ {
+ length = strlen(str);
+ }
+
+ retval = malloc(length+1);
+ if (retval == NULL)
+ {
+ fprintf(stderr,
+ "Fatal: Unable to allocate memory\n");
+ exit(1);
+ }
+
+ strncpy(retval, str, length);
+ retval[length] = '\0';
+ return(retval);
+}
+
+void
+free_namelist_item(t_lptangodat *lptd,
+ t_namelist *item)
+{
+ if (item->name != NULL)
+ {
+ free(item->name);
+ }
+ if (item != NULL)
+ {
+ free(item);
+ }
+}
+
+t_namelist *
+create_namelist_item(t_lptangodat *lptd,
+ char *str,
+ int length)
+{
+ t_namelist *retval;
+
+ retval = malloc(sizeof(*retval));
+ if (retval == NULL)
+ {
+ fprintf(stderr,
+ "Fatal: Unable to allocate memory\n");
+ exit(1);
+ }
+
+ retval->name = stralloc(str, length);
+
+ return(retval);
+}
+
+t_namelist *
+find_name_in_list(t_lptangodat *lptd,
+ t_namelist *list,
+ t_namelist *item)
+{
+ while (list != NULL)
+ {
+ if (strcmp(list->name, item->name) == 0)
+ {
+ break;
+ }
+
+ list = list->next;
+ }
+
+ return(list);
+}
+
+void
+list_insert_unique(t_lptangodat *lptd,
+ t_namelist **list,
+ t_namelist *item)
+{
+ if (find_name_in_list(lptd, *list, item) == NULL)
+ {
+ item->next = *list;
+ *list = item;
+ }
+ else
+ {
+ free_namelist_item(lptd, item);
+ }
+}
+
+/****************************************************************************/
+
+static int
+get_input_line(t_lptangodat *lptd)
+{
+#define FLUSHSIZE 20
+ int retval;
+ int length;
+ char flushbuf[FLUSHSIZE];
+ int flushlength;
+
+
+ (lptd->curr_lineno)++;
+
+ if (fgets(lptd->line, lptd->maxlinesize, lptd->infile) == NULL)
+ {
+ retval = END_OF_FILE; /* Did not get a line, end of file. */
+ }
+ else
+ {
+ retval = GOT_LINE;
+ length = strlen(lptd->line);
+
+ /* If the line was too long (it was the max size and the last character
+ was not a newline), print a log and flush to end of line. */
+ if ( (length == (lptd->maxlinesize - 1))
+ && (lptd->line[length-1] != '\n'))
+ {
+ lptd->line[length-1] = '\n';
+
+ fprintf(stderr,
+ "Warning, line %d too long, flushing to end of line\n",
+ lptd->curr_lineno);
+ if (fgets(flushbuf, FLUSHSIZE, lptd->infile) == NULL)
+ {
+ flushlength = 0;
+ }
+ else
+ {
+ flushlength = strlen(flushbuf);
+ }
+ while ( (flushlength == (FLUSHSIZE - 1))
+ && (lptd->line[flushlength-1] != '\n'))
+ {
+ if (fgets(flushbuf, FLUSHSIZE, lptd->infile) == NULL)
+ {
+ flushlength = 0;
+ }
+ else
+ {
+ flushlength = strlen(flushbuf);
+ }
+ }
+ }
+ }
+
+ return(retval);
+}
+
+static void
+process_cmd(t_lptangodat *lptd)
+{
+ char *strhold;
+ char *cmd;
+ char *name;
+ int namelength;
+
+
+ cmd = r_strtok(&(lptd->line[1]), " \t\n", &strhold);
+ if (cmd == NULL)
+ {
+ fprintf(stderr,
+ "Error on line %d: Missing command\n",
+ lptd->curr_lineno);
+ lptd->retcode = 2;
+ }
+ else if (strcmp(cmd, "code") == 0)
+ {
+ if (lptd->outstate == OUTPUT_CODE)
+ {
+ fprintf(stderr,
+ "Error on line %d: Macro begin when already processing a macro\n",
+ lptd->curr_lineno);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ lptd->curr_macro = malloc(sizeof(*(lptd->curr_macro)));
+ if (lptd->curr_macro == NULL)
+ {
+ fprintf(stderr,
+ "Fatal: Unable to allocate memory\n");
+ exit(1);
+ }
+
+ while ((*strhold == ' ') || (*strhold == '\t') || (*strhold == '\n'))
+ {
+ strhold++;
+ }
+
+ if (*strhold != '<')
+ {
+ fprintf(stderr,
+ "Error on line %d: Macro name must be surrounded by <>\n",
+ lptd->curr_lineno);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ strhold++;
+ }
+
+ name = r_strtok(strhold, ">", &strhold);
+ lptd->curr_macro->name = stralloc(name, 0);
+ lptd->curr_macro->filename = lptd->curr_filename;
+ lptd->curr_macro->startline = lptd->curr_lineno + 1;
+ lptd->curr_macro->firstline = NULL;
+ lptd->curr_macro->lastline = NULL;
+ lptd->curr_macro->staticdefs = NULL;
+ lptd->curr_macro->globaldefs = NULL;
+ lptd->curr_macro->pounddefs = NULL;
+ lptd->curr_macro->uses = NULL;
+
+ lptd->outstate = OUTPUT_CODE;
+ }
+ }
+ else if (strcmp(cmd, "file") == 0)
+ {
+ if (lptd->outstate == OUTPUT_CODE)
+ {
+ fprintf(stderr,
+ "Error on line %d: File name change not allowed in code\n",
+ lptd->curr_lineno);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ name = r_strtok(strhold, " \t\n", &strhold);
+ if (name == NULL)
+ {
+ fprintf(stderr,
+ "Error on line %d: File name not given with file command\n",
+ lptd->curr_lineno);
+ lptd->retcode = 2;
+ }
+ lptd->curr_filename = stralloc(name, 0);
+ namelength = strlen(name);
+
+ name = r_strtok(strhold, " \t\n", &strhold);
+ if (name == NULL)
+ {
+ lptd->curr_lineno = 0;
+ }
+ else
+ {
+ lptd->curr_lineno = atoi(name) - 1;
+ }
+ }
+ }
+ else if (strcmp(cmd, "line") == 0)
+ {
+ if (lptd->outstate == OUTPUT_CODE)
+ {
+ fprintf(stderr,
+ "Error on line %d: Line number change not allowed in code\n",
+ lptd->curr_lineno);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ name = r_strtok(strhold, " \t\n", &strhold);
+ if (name == NULL)
+ {
+ fprintf(stderr,
+ "Error on line %d: Line number not specified in line command\n",
+ lptd->curr_lineno);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ lptd->curr_lineno = atoi(name) - 1;
+ }
+ }
+ }
+ else if ( (strcmp(cmd, "includefile") == 0)
+ || (strcmp(cmd, "reffile") == 0))
+ {
+ if (lptd->outstate == OUTPUT_CODE)
+ {
+ fprintf(stderr,
+ "Error on line %d: %s not allowed in code\n",
+ lptd->curr_lineno,
+ cmd);
+ lptd->retcode = 2;
+ }
+ /* This is ignored in tangling. */
+ }
+ else
+ {
+ fprintf(stderr,
+ "Error on line %d: Invalid command\n",
+ lptd->curr_lineno);
+ lptd->retcode = 2;
+ }
+}
+
+static void
+process_codeline(t_lptangodat *lptd)
+{
+ t_linelist *thisline;
+
+ thisline = malloc(sizeof(*thisline));
+ if (thisline == NULL)
+ {
+ fprintf(stderr,
+ "Fatal: Unable to allocate memory\n");
+ exit(1);
+ }
+
+ thisline->line = stralloc(lptd->line, 0);
+ thisline->next = NULL;
+ if (lptd->curr_macro->lastline == NULL)
+ {
+ lptd->curr_macro->lastline = thisline;
+ lptd->curr_macro->firstline = thisline;
+ }
+ else
+ {
+ lptd->curr_macro->lastline->next = thisline;
+ lptd->curr_macro->lastline = thisline;
+ }
+}
+
+static void output_macro(t_lptangodat *lptd,
+ t_lpmac *outmac);
+
+static void
+output_line(t_lptangodat *lptd,
+ t_linelist *outline,
+ char *filename,
+ int lineno)
+{
+ t_lpmac *cm;
+ t_lpmac *prev_macro;
+ char *cp;
+ int currchar;
+ char *name;
+
+
+ currchar = 0;
+ cp = outline->line;
+
+ while (cp[currchar] != '\0')
+ {
+ if (cp[currchar] == '@')
+ {
+ if (currchar > 0)
+ {
+ fwrite(cp, 1, currchar, lptd->outfile);
+ lptd->scan_input(lptd, cp, currchar, lineno);
+ }
+ if ( (lptd->instring)
+ || (lptd->in_comment))
+ {
+ fputc('@', lptd->outfile);
+ lptd->scan_input(lptd, "@", 1, lineno);
+ currchar++;
+ cp = &(cp[currchar]);
+ currchar = 0;
+ }
+ else
+ {
+ currchar++;
+ if (cp[currchar] == '@')
+ {
+ fputc('@', lptd->outfile);
+ lptd->scan_input(lptd, "@", 1, lineno);
+ currchar++;
+ cp = &(cp[currchar]);
+ currchar = 0;
+ }
+ else if (cp[currchar] == '<')
+ {
+ fputc('\n', lptd->outfile);
+ currchar++;
+ name = r_strtok(&(cp[currchar]), ">", &cp);
+ currchar = 0;
+
+ cm = lptd->macros;
+ while ( (cm != NULL)
+ && (strcmp(cm->name, name) != 0))
+ {
+ cm = cm->next;
+ }
+
+ if (cm == NULL)
+ {
+ fprintf(stderr,
+ "Error: macro %s used on line %d but not found\n",
+ name,
+ lineno);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ prev_macro = lptd->curr_macro;
+ lptd->curr_macro = cm;
+ output_macro(lptd, cm);
+ lptd->curr_macro = prev_macro;
+ if (lptd->do_linenums)
+ {
+ lptd->output_linenum(lptd, lineno, filename);
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr,
+ "Error on line %d: Invalid operation \"@%c\"\n",
+ lineno,
+ cp[currchar]);
+ lptd->retcode = 2;
+ }
+ }
+ }
+ else
+ {
+ currchar++;
+ }
+ }
+
+ if (currchar > 0)
+ {
+ fwrite(cp, 1, currchar, lptd->outfile);
+ lptd->scan_input(lptd, cp, currchar, lineno);
+ }
+}
+
+static void
+output_macro(t_lptangodat *lptd,
+ t_lpmac *outmac)
+{
+ t_linelist *cl;
+ int lineno;
+
+
+ lineno = outmac->startline;
+ cl = outmac->firstline;
+ if (lptd->do_linenums)
+ {
+ lptd->output_linenum(lptd, lineno, outmac->filename);
+ }
+ while (cl != NULL)
+ {
+ lptd->curr_line = cl;
+ output_line(lptd, cl, outmac->filename, lineno);
+ lineno++;
+ cl = cl->next;
+ }
+}
+
+static void
+output_macros(t_lptangodat *lptd)
+{
+ t_lpmac *cm;
+
+ cm = lptd->macros;
+ while ( (cm != NULL)
+ && (strcmp(cm->name, lptd->start_macro) != 0))
+ {
+ cm = cm->next;
+ }
+
+ if (cm == NULL)
+ {
+ fprintf(stderr,
+ "Fatal: Start macro %s not found\n",
+ lptd->start_macro);
+ exit(1);
+ }
+
+ lptd->curr_macro = cm;
+ output_macro(lptd, cm);
+}
+
+static char *
+get_arg_str(int *argidx,
+ int argc,
+ char *argv[],
+ int start_offset)
+{
+ char *retval;
+
+
+ if (argv[*argidx][start_offset] == '\0')
+ {
+ (*argidx)++;
+ if ((*argidx) == argc)
+ {
+ retval = NULL;
+ }
+ else
+ {
+ retval = argv[*argidx];
+ }
+ }
+ else
+ {
+ retval = &(argv[*argidx][start_offset]);
+ }
+
+ return(retval);
+}
+
+void c_scan_input(t_lptangodat *lptd,
+ char *line,
+ int length,
+ int lineno);
+
+void c_output_linenum(t_lptangodat *lptd,
+ int lineno,
+ char *filename);
+
+void init_c_lang(t_lptangodat *lptd);
+
+static struct s_langs
+{
+ char *lang_name;
+ input_scanner scanner;
+ linenum_output output_linenum;
+ scanner_init init;
+} langs[] =
+{
+ { "c", &c_scan_input, &c_output_linenum, &init_c_lang }
+};
+
+static const num_langs = sizeof(langs) / sizeof(struct s_langs);
+
+static void
+process_args(t_lptangodat *lptd,
+ int argc,
+ char *argv[],
+ int *argidx)
+{
+ char *str;
+ int i;
+
+
+ *argidx = 1;
+ while (argv[*argidx][0] == '-')
+ {
+ if (strcmp(argv[*argidx], "--") == 0)
+ {
+ (*argidx)++;
+ break;
+ }
+ else if (strncmp(argv[*argidx], "-autoxref", 5) == 0)
+ {
+ lptd->do_xref = TRUE;
+ lptd->auto_xref = TRUE;
+ }
+ else if (strncmp(argv[*argidx], "-xref", 5) == 0)
+ {
+ lptd->do_xref = TRUE;
+ }
+ else if (strncmp(argv[*argidx], "-lang", 5) == 0)
+ {
+ if (lptd->scan_input != NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: only 1 -lang is allowed\n",
+ argv[0]);
+ exit(1);
+ }
+
+ str = get_arg_str(argidx, argc, argv, 5);
+ if (str == NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: -lang specified but no lang given\n",
+ argv[0]);
+ exit(1);
+ }
+
+ for (i=0; i<num_langs; i++)
+ {
+ if (strcmp(str, langs[i].lang_name) == 0)
+ {
+ lptd->scan_input = langs[i].scanner;
+ lptd->output_linenum = langs[i].output_linenum;
+ langs[i].init(lptd);
+ break;
+ }
+ }
+
+ if (lptd->scan_input == NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: Invalid lang given: %s\n",
+ argv[0], str);
+ exit(1);
+ }
+ }
+ else if (strncmp(argv[*argidx], "-nolinenum", 10) == 0)
+ {
+ lptd->do_linenums = FALSE;
+ }
+ else if (strncmp(argv[*argidx], "-xreffile", 9) == 0)
+ {
+ lptd->do_xref = TRUE;
+ str = get_arg_str(argidx, argc, argv, 9);
+ if (str == NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: -xreffile specified but no file given\n",
+ argv[0]);
+ exit(1);
+ }
+
+ lptd->xreffile = fopen(str, "w");
+ if (lptd->xreffile == NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: Could not open cross ref file: %s\n",
+ argv[0],
+ str);
+ exit(1);
+ }
+ }
+ else if (strncmp(argv[*argidx], "-start_macro", 11) == 0)
+ {
+ lptd->start_macro = get_arg_str(argidx, argc, argv, 11);
+ if (lptd->start_macro == NULL)
+ {
+ fprintf(stderr,
+ "Error: -s specified but no start macro given\n");
+ exit(1);
+ }
+ }
+ else
+ {
+ fprintf(stderr,
+ "Error: Invalid option specified: %s\n", argv[*argidx]);
+ exit(1);
+ }
+
+ (*argidx)++;
+ }
+}
+
+static void
+print_list(t_lptangodat *lptd,
+ char *prefix,
+ t_namelist *names)
+{
+ while (names != NULL)
+ {
+ fprintf(lptd->xreffile, "%s %s\n", prefix, names->name);
+ names = names->next;
+ }
+}
+
+static void
+output_xref(t_lptangodat *lptd)
+{
+ t_lpmac *macros;
+
+ fprintf(lptd->xreffile, "f %s\n", lptd->curr_filename);
+ macros = lptd->macros;
+ while (macros != NULL)
+ {
+ fprintf(lptd->xreffile, "m %s\n", macros->name);
+ print_list(lptd, "d", macros->pounddefs);
+ print_list(lptd, "e", macros->globaldefs);
+ print_list(lptd, "s", macros->staticdefs);
+ print_list(lptd, "u", macros->uses);
+
+ macros = macros->next;
+ }
+}
+
+int
+main(int argc,
+ char *argv[])
+{
+ t_lptangodat *lptd;
+ int argidx;
+ char *str;
+ char fname[MAX_FILENAME_LENGTH+1];
+ int len;
+ char *name;
+ t_namelist *item;
+
+
+ lptd = malloc(sizeof(*lptd));
+ if (lptd == NULL)
+ {
+ fprintf(stderr, "Unable to allocate enough memory\n");
+ exit(1);
+ }
+
+ lptd->scan_input = NULL;
+
+ lptd->maxlinesize = MAXLINESIZE;
+ lptd->curr_lineno = 0;
+ lptd->macros = NULL;
+ lptd->start_macro = "*";
+ lptd->outfile = stdout;
+ lptd->xreffile = NULL;
+ lptd->do_xref = FALSE;
+ lptd->auto_xref = FALSE;
+ lptd->in_comment = FALSE;
+ lptd->do_linenums = TRUE;
+ lptd->instring = FALSE;
+ lptd->retcode = 0;
+
+ process_args(lptd, argc, argv, &argidx);
+
+ if (lptd->scan_input == NULL)
+ {
+ fprintf(stderr, "%s: No lang specified\n", argv[0]);
+ exit(1);
+ }
+
+ if (argc != (argidx + 1))
+ {
+ fprintf(stderr, "%s: No input file specified\n", argv[0]);
+ exit(1);
+ }
+ else
+ {
+ lptd->infile = fopen(argv[argidx], "r");
+ if (lptd->infile == NULL)
+ {
+ fprintf(stderr, "%s: Unable to open file %s\n",
+ argv[0], argv[argidx]);
+ exit(1);
+ }
+ lptd->curr_filename = argv[argidx];
+ }
+
+ if ((lptd->do_xref) && (lptd->xreffile == NULL))
+ {
+ str = strrchr(argv[argidx], '.');
+ if (str != NULL)
+ {
+ len = str - argv[argidx];
+ }
+ else
+ {
+ len = strlen(argv[argidx]);
+ }
+
+ if ((len+4) >= MAX_FILENAME_LENGTH) /* Add 4 for the .xfr */
+ {
+ fprintf(stderr, "filename to long, no xref file generated\n");
+ }
+ else
+ {
+ memcpy(fname, argv[argidx], len);
+ strcpy(&(fname[len]), ".xfr");
+
+ lptd->xreffile = fopen(fname, "w");
+ if (lptd->xreffile == NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: Could not open cross ref file: %s\n",
+ argv[0],
+ str);
+ exit(1);
+ }
+ }
+ }
+
+ lptd->outstate = SKIP_DOCUMENTATION;
+
+ while (get_input_line(lptd) == GOT_LINE)
+ {
+ if (lptd->outstate == OUTPUT_CODE)
+ {
+ if (strncmp(lptd->line, "@endcode", 8) == 0)
+ {
+ lptd->curr_macro->next = lptd->macros;
+ lptd->macros = lptd->curr_macro;
+
+ lptd->outstate = SKIP_DOCUMENTATION;
+ }
+ else if (strncmp(lptd->line, "@uses", 5) == 0)
+ {
+ if (lptd->outstate != OUTPUT_CODE)
+ {
+ fprintf(stderr,
+ "Error on line %d: %s not allowed outside of code\n",
+ lptd->curr_lineno,
+ lptd->line);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ name = r_strtok(&(lptd->line[5]), " \t\n", NULL);
+ if (name == NULL)
+ {
+ fprintf(stderr,
+ "Error on line %d: name not given with uses command\n",
+ lptd->curr_lineno);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ item = create_namelist_item(lptd,
+ name,
+ 0);
+ list_insert_unique(lptd, &(lptd->curr_macro->uses), item);
+ }
+ }
+
+ strcpy(lptd->line, "\n");
+ process_codeline(lptd);
+ }
+ else if (strncmp(lptd->line, "@defines", 8) == 0)
+ {
+ if (lptd->outstate != OUTPUT_CODE)
+ {
+ fprintf(stderr,
+ "Error on line %d: %s not allowed outside of code\n",
+ lptd->curr_lineno,
+ lptd->line);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ name = r_strtok(&(lptd->line[8]), " \t\n", NULL);
+ if (name == NULL)
+ {
+ fprintf(stderr,
+ "Error on line %d: name not given with defines command\n",
+ lptd->curr_lineno);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ item = create_namelist_item(lptd,
+ name,
+ 0);
+ list_insert_unique(lptd, &(lptd->curr_macro->pounddefs), item);
+ }
+ }
+
+ strcpy(lptd->line, "\n");
+ process_codeline(lptd);
+ }
+ else if (strncmp(lptd->line, "@externdecls", 12) == 0)
+ {
+ if (lptd->outstate != OUTPUT_CODE)
+ {
+ fprintf(stderr,
+ "Error on line %d: %s not allowed outside of code\n",
+ lptd->curr_lineno,
+ lptd->line);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ name = r_strtok(&(lptd->line[12]), " \t\n", NULL);
+ if (name == NULL)
+ {
+ fprintf(stderr,
+ "Error on line %d: name not given with externdecls command\n",
+ lptd->curr_lineno);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ item = create_namelist_item(lptd,
+ name,
+ 0);
+ list_insert_unique(lptd, &(lptd->curr_macro->globaldefs), item);
+ }
+ }
+
+ strcpy(lptd->line, "\n");
+ process_codeline(lptd);
+ }
+ else if (strncmp(lptd->line, "@staticdecls", 12) == 0)
+ {
+ if (lptd->outstate != OUTPUT_CODE)
+ {
+ fprintf(stderr,
+ "Error on line %d: %s not allowed outside of code\n",
+ lptd->curr_lineno,
+ lptd->line);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ name = r_strtok(&(lptd->line[12]), " \t\n", NULL);
+ if (name == NULL)
+ {
+ fprintf(stderr,
+ "Error on line %d: name not given with staticdecls command\n",
+ lptd->curr_lineno);
+ lptd->retcode = 2;
+ }
+ else
+ {
+ item = create_namelist_item(lptd,
+ name,
+ 0);
+ list_insert_unique(lptd, &(lptd->curr_macro->staticdefs), item);
+ }
+ }
+
+ strcpy(lptd->line, "\n");
+ process_codeline(lptd);
+ }
+ else
+ {
+ process_codeline(lptd);
+ }
+ }
+ else if (lptd->line[0] == '@')
+ {
+ process_cmd(lptd);
+ }
+ /* Ignore documentation. */
+ }
+
+ if (lptd->outstate == OUTPUT_CODE)
+ {
+ fprintf(stderr,
+ "Warning: File %s ended while outputting code",
+ lptd->curr_filename);
+ lptd->retcode = 2;
+ lptd->outstate = SKIP_DOCUMENTATION;
+ }
+
+ output_macros(lptd);
+
+ if (lptd->xreffile != NULL)
+ {
+ output_xref(lptd);
+ }
+
+ return(lptd->retcode);
+}
diff --git a/web/tango-weevil/tango.h b/web/tango-weevil/tango.h
new file mode 100644
index 0000000000..834c0a02a5
--- /dev/null
+++ b/web/tango-weevil/tango.h
@@ -0,0 +1,120 @@
+/*
+ Tango/Weevil - A WEB Tangler and Weaver
+ Copyright (C) 1995 Corey Minyard
+
+ 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.
+
+ Corey Minyard - minyard@metronet.com
+*/
+
+
+#define MAXLINESIZE 200
+
+typedef struct linelist
+{
+ char *line;
+ struct linelist *next;
+} t_linelist;
+
+typedef struct namelist
+{
+ char *name;
+ struct namelist *next;
+ union
+ {
+ int nest_val;
+ } u;
+} t_namelist;
+
+typedef int bool;
+#define TRUE 1
+#define FALSE 0
+
+
+
+typedef struct lpmac
+{
+ char *name;
+ t_linelist *firstline;
+ t_linelist *lastline;
+ struct lpmac *next;
+ char *filename;
+ int startline;
+ t_namelist *staticdefs;
+ t_namelist *globaldefs;
+ t_namelist *pounddefs;
+ t_namelist *uses;
+} t_lpmac;
+
+struct s_lptangodat;
+
+typedef void (*input_scanner)(struct s_lptangodat *lptd,
+ char *line,
+ int length,
+ int lineno);
+
+typedef void (*linenum_output)(struct s_lptangodat *lptd,
+ int lineno,
+ char *filename);
+
+typedef void (*scanner_init)(struct s_lptangodat *lptd);
+
+typedef struct s_lptangodat
+{
+ FILE *infile;
+ FILE *outfile;
+ FILE *xreffile;
+ char line[MAXLINESIZE];
+ int outstate;
+ char *curr_filename;
+ int maxlinesize;
+ int curr_lineno;
+ t_lpmac *curr_macro;
+ t_linelist *curr_line;
+ t_lpmac *macros;
+ char *start_macro;
+ bool do_xref;
+ bool auto_xref;
+ bool instring;
+ bool in_comment;
+ bool do_linenums;
+ void *code_info; /* Language-dependant info. */
+ input_scanner scan_input;
+ linenum_output output_linenum;
+ int retcode; /* Program return code. */
+} t_lptangodat;
+
+
+void list_insert_unique(t_lptangodat *lptd,
+ t_namelist **list,
+ t_namelist *item);
+
+t_namelist *find_name_in_list(t_lptangodat *lptd,
+ t_namelist *list,
+ t_namelist *item);
+
+char *r_strtok(char *data,
+ char *sstr,
+ char **next_data);
+
+char *stralloc(char *str,
+ int length);
+
+void free_namelist_item(t_lptangodat *lptd,
+ t_namelist *item);
+
+t_namelist *create_namelist_item(t_lptangodat *lptd,
+ char *str,
+ int length);
diff --git a/web/tango-weevil/tw.sty b/web/tango-weevil/tw.sty
new file mode 100644
index 0000000000..64ffd9b3d8
--- /dev/null
+++ b/web/tango-weevil/tw.sty
@@ -0,0 +1,114 @@
+\def\filedate{1995/2/6}
+\def\fileversion{v1.0}
+%
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{tw}
+\RequirePackage{moreverb}
+\RequirePackage{multicol}
+\typeout{Package: `tw' \fileversion \space <\filedate>}
+%
+\newlength{\tw@width}
+%
+\newcommand{\twstartcode}{\begingroup\footnotesize}
+\newcommand{\twendcode}{\endgroup}
+\newcommand{\twmacrodecl}[2]{\par\parindent=0pt\parskip=0pt\label{#2}%
+ {\noindent\sffamily\bfseries Code Chunk: #1}%
+ \index{#1@\textit{#1}|textbf}}
+\newcommand{\twmacrouse}[2]{{\rm @\(<\)#1\(>\)%
+ (Macro \ref{#2} on page \pageref{#2})}%
+ \index{#1@\textit{#1}}}
+\newcommand{\tw@use}[1]{\index{#1}#1}%
+\newcommand{\tw@decl}[1]{\index{#1|textbf}#1}%
+\newcommand{\u@line}[1]{\settowidth{\tw@width}{#1}\parbox{\tw@width}%
+ {#1\hspace{-\tw@width}\rule[-2pt]{\tw@width}{.2pt}}}
+\newenvironment{twuses}
+{
+ \parindent=0pt%
+ \multicolsep=0pt%
+ \let\twuse\tw@use%
+ \begin{multicols}{2}[\u@line{\sffamily Uses:}]
+ \raggedright
+}
+{\end{multicols}\smallskip}
+%
+\newenvironment{twdecls}
+{
+ \parindent=0pt%
+ \multicolsep=0pt%
+ \let\twdecl\tw@decl%
+ \begin{multicols}{2}[\u@line{\sffamily Declares:}]
+ \raggedright
+}
+{\end{multicols}\smallskip}
+%
+\newcommand{\tw@Description}{\end{minipage}\par\smallskip
+\parbox[t]{1in}{\hfill Description:\hspace*{1em}}\begin{minipage}[t]{3.5in}}
+%
+\newcommand{\tw@SideEffects}{\end{minipage}\par\smallskip
+\parbox[t]{1in}{\hfill Side Effects:\hspace*{1em}}\begin{minipage}[t]{3.5in}}
+%
+\newcommand{\tw@ReturnValues}{\end{minipage}\par\smallskip
+\parbox[t]{1in}{\hfill Return Vals:\hspace*{1em}}\begin{minipage}[t]{3.5in}}
+%
+\newcommand{\tw@Inputs}{\end{minipage}\par\smallskip
+\parbox[t]{1in}{\hfill Inputs:\hspace*{1em}}\begin{minipage}[t]{3.5in}}
+%
+\newcommand{\tw@Outputs}{\end{minipage}\par\smallskip
+\parbox[t]{1in}{\hfill Outputs:\hspace*{1em}}\begin{minipage}[t]{3.5in}}
+%
+\newcommand{\tw@StartCode}{\end{minipage}\par}
+\newcommand{\twiscode}{\expandafter\ifx\csname twnocode\endcsname\relax}%
+\newcommand{\twisproc}{\expandafter\ifx\csname twnoproc\endcsname\relax}%
+%
+\twisproc
+ \newenvironment{twproc}[1]
+ {
+ \par
+ \parskip=0pt%
+ \let\Description\tw@Description%
+ \let\SideEffects\tw@SideEffects%
+ \let\ReturnValues\tw@ReturnValues%
+ \let\Inputs\tw@Inputs%
+ \let\Outputs\tw@Outputs%
+ \let\StartCode\tw@StartCode%
+ \begin{minipage}{4.5in}\textbf{Procedure: #1}}
+ {}
+\else%
+ \newenvironment{twproc}[1]
+ {
+ \@bsphack
+ \let\do\@makeother\dospecials\catcode`\^^M\active
+ \let\verbatim@startline\relax
+ \let\verbatim@addtoline\@gobble
+ \let\verbatim@processline\relax
+ \let\verbatim@finish\relax
+ \verbatim@
+ }
+ {\@esphack}
+\fi
+%
+\twiscode
+ \newenvironment{twcodechunk}{}{}
+\else%
+ \newenvironment{twcodechunk}
+ {
+ \@bsphack
+ \let\do\@makeother\dospecials\catcode`\^^M\active
+ \let\verbatim@startline\relax
+ \let\verbatim@addtoline\@gobble
+ \let\verbatim@processline\relax
+ \let\verbatim@finish\relax
+ \verbatim@
+ }
+ {\@esphack}
+\fi
+%
+\newcommand{\twparmlist@label}[1]{\mbox{\texttt{#1} - }\hfil}
+\newenvironment{twparmlist}
+{%
+ \begin{list}{}%
+ {\setlength{\itemsep}{0pt}%
+ \setlength{\parsep}{0pt}%
+ \renewcommand{\makelabel}{\twparmlist@label}}%
+}%
+{\end{list}}
diff --git a/web/tango-weevil/userguid.tpc b/web/tango-weevil/userguid.tpc
new file mode 100644
index 0000000000..b9843d5805
--- /dev/null
+++ b/web/tango-weevil/userguid.tpc
@@ -0,0 +1,506 @@
+\expandafter\ifx\csname DocumentPart\endcsname\relax
+\documentclass{book}
+\usepackage{tw}
+\title{Tango/Weevil --- A WEB Tangler and Weaver}
+\author{Corey Minyard}
+\date{\today}
+\makeindex
+\begin{document}
+\maketitle
+\fi
+\section{Introduction}
+
+Tango/Weevil was born out of my frustration with the state of literate
+programming software available. All the stuff I found was inadequate
+for large projects, made you do to much work, or didn't do everything
+a nice literate programming tool should do. The \texttt{noweb}
+package came very close, but it didn't support inter-document cross
+references and it used somewhat esoteric programming languages.
+
+Although I don't claim Tango/Weevil is the end-all for literate
+programming, it is a start onto something more useful in a broad
+sense. It is written completely in C. It generates cross-references
+for variables in C programs. It generates variable cross-references
+that may be shared between files.
+
+I came up with the name Tango/Weevil on a late-night programming
+session. I don't guess my mind was working clearly and it sounded
+good at the time. It sounds a little hokey now.
+
+\section{Requirements}
+
+Tango/Weevil requires a C compiler and \LaTeX2e. It will not work
+with the old \LaTeX. \LaTeX2e\ is a whole lot better, anyway, so you
+should get it if you haven't already.
+
+\section{Theory of Operation}
+
+Tango/Weevil consists of two programs named \texttt{tango} and
+\texttt{weevil}. The \texttt{tango} program takes a literate program
+and extracts code onto standard out. It also generates the cross
+reference file (if invoked with the proper parameters). The
+\texttt{weevil} program takes a literate program and generates a
+\LaTeX document from it. It will use the cross reference file
+generated by \texttt{tango} to list the variables.
+Figure~\ref{fig:tango-weevil-operation} shows this operations.
+
+\begin{figure}[ht]
+.PS
+right
+If: box "Input File" "(\textit{file}.tw)" invis
+arrow
+Tb: ellipse "tango"
+arrow
+Of: box width 1.5 * boxwid "Program Source" "(\textit{file}.c)" invis
+move to Tb.b
+down
+arrow
+Cb: box "Cross Reference" "(\textit{file}.xfr)" invis
+arrow
+Wb: ellipse "weevil"
+move to If.b
+line to Wb.l + (-linewid,0)
+right
+arrow to Wb.l
+move to Wb.r
+arrow
+box width 1.1 * boxwid "\LaTeX Source" "(\textit{file}.tex)" invis
+.PE
+\centerline{\box\graph}
+\caption{Tango/Weevil operation}
+\label{fig:tango-weevil-operation}
+\end{figure}
+
+A Tango/Weevil file has two main parts: code and documentation. These
+may be interspersed in the document. Both programs start in
+documentation mode, a \verb|@code| directive switches to code mode and
+a \verb|@endcode| switched back to documentation mode. The
+\verb|code| directive takes a macro name, everything between that
+\verb|@code| and the next \verb|@endcode| is called a macro and may be
+referred to with the macro's name.
+
+\section{Procedure Headers}
+
+The tango/weevil styles provide a nice format for documenting
+procedures and functions in \LaTeX. Other document processor could be
+designed to take this information and use it. The format is:
+
+\begin{verbatim}
+\begin{twproc}{Procedure\_Name}
+\Description Describes the function. The format of the input is not
+ really important, the output will indent it properly.
+\ReturnValues \verb|int| - A function return value
+\SideEffects Things that the procedure changes that will have effects
+ on other things.
+\Inputs \begin{twparmlist}
+ \item[inparm1] This is an input parameter
+ \item[inparm2] This is another input parameter
+ \end{twparmlist}
+\Outputs \begin{twparmlist}
+ \item[outparm] This is for non-return value output
+ parameters.
+ \end{twparmlist}
+\StartCode % @code should come after this statement.
+@code <Procedure_Name>
+int
+Procedure_Name(int inparm1,
+ char *inparm2,
+ int *outparm)
+{
+}
+@endcode
+\end{twproc}
+\end{verbatim}
+
+The output from this would be:
+
+\begin{twproc}{Procedure\_Name}
+\Description Describes the function. The format of the input is not
+ really important, the output will indent it properly.
+\ReturnValues \verb|int| - A function return value
+\SideEffects Things that the procedure changes that will have effects
+ on other things.
+\Inputs \begin{twparmlist}
+ \item[inparm1] This is an input parameter
+ \item[inparm2] This is another input parameter
+ \end{twparmlist}
+\Outputs \begin{twparmlist}
+ \item[outparm] This is for non-return value output
+ parameters.
+ \end{twparmlist}
+\StartCode
+\begingroup\medskip
+\twmacrodecl{Procedure\_Name}{userguid.tpc:macro:ProcedureName}
+\begin{verbatimcmd}\twstartcode
+ 1 int
+ 2 Procedure_Name(int inparm1,
+ 3 char *inparm2,
+ 4 int *outparm)
+ 5 {
+ 6 }
+\twendcode\end{verbatimcmd}
+\endgroup
+\end{twproc}
+
+\noindent All the sections (except \verb|\StartCode|) are optional.
+
+\section{Conditional Documentation}
+
+A special macro is created for including/excluding sections in
+certain situations. If the command
+
+\begin{verbatim}
+ \def\twnocode{}
+\end{verbatim}
+
+is included before the ``tw'' package is included (at the very top
+of the file), everything between the \verb|@code| and \verb|@endcode|
+will not be output. If the command
+
+\begin{verbatim}
+ \def\twnoproc{}
+\end{verbatim}
+
+is included before the ``tw'' package is included (at the very top
+of the file), everything between the \verb|\begin{twproc}|
+and \verb|\end{twproc}| will not be output. The commands
+
+\begin{verbatim}
+ \twiscode
+ text
+ \fi
+\end{verbatim}
+
+will not generate any output for anything between \verb|\twiscode| and
+\verb|\fi| if \verb|\twnocode| was defined. Similarly,
+
+\begin{verbatim}
+ \twisproc
+ text
+ \fi
+\end{verbatim}
+
+will not generate any output for anything between \verb|\twisproc| and
+\verb|\fi| if \verb|\twnoproc| was defined.
+
+\section{File Processing}
+
+When \texttt{tango} processes a file, it does not spit out the macro
+text as it receives it. Instead, it collects all the macro chunks
+until the end. After it has collected all the macro chunks, it looks
+for a special macro named ``*'', that is the start macro. It starts
+outputting that macro. Whenever it sees a \verb|@<name>|, it will go
+to the macro with the given name and output it. Assuming no recursive
+macro references exit, the process will eventually end and a source
+file will be produced. For example, consider this small program:
+
+\begin{verbatim}
+\documentclass{article}
+\usepackage{tw,makeidx}
+\title{Hello World --- A Famous Program}
+\author{Corey Minyard}
+\date{\today}
+\makeindex
+\begin{document}
+\maketitle
+\section{Description}
+
+This program is the famous ``hello world'' program. Certainly
+we have all written one of these programs.
+
+\section{Code}
+
+\subsection{Start Macro}
+This is the main part of the program.
+@code <*>
+@<Includes>
+@<Routines>
+@endcode
+
+\subsection{Includes}
+This program needs \texttt{stdio.h} because it uses printf.
+@code <Includes>
+#include <stdio.h>
+@endcode
+
+\subsection{Routines}
+This program only has one routine, the main routine.
+
+@code <Routines>
+@<main>
+@endcode
+
+\begin{twproc}{main}
+\Description The main routine.
+\ReturnValues \verb|int| - Program return code
+\SideEffects Well, it prints something!
+\Inputs \begin{twparmlist}
+ \item[argc] Argument count
+ \item[argv] The arguments
+ \end{twparmlist}
+\StartCode
+@code <main>
+int
+main(int argc,
+ char *argv)
+{
+ @<Output Hello>
+ @<Leave Program>
+}
+@endcode
+
+\subsection{Output Hello}
+This code chunk actually does the output.
+@code <Output Hello>
+ printf("hello world\n");
+@endcode
+
+\subsection{Leave Program}
+This code chunk causes the program to exit.
+@code <Leave Program>
+ exit(0);
+@endcode
+\end{twproc}
+
+\printindex
+\end{document}
+\end{verbatim}
+
+You can notice a few things about the program. Standard \LaTeX\ stuff
+is used in the documentation. The code is not in the file in the same
+order that it will be output to the C file to be compiled. A file
+named hello.tw should be included in the distribution that is the same
+as this file, try the following commands on that file:
+
+\begin{verbatim}
+ tango -autoxref -lang c hello.tw >hello.c
+ cc -o hello hello.c
+ ./hello
+ weevil -lang c hello.tw >hello.tex
+ latex hello
+ latex hello
+ makeindex hello.idx
+ latex hello
+\end{verbatim}
+
+These command will create an executable \verb|hello| program and a
+\verb|hello.dvi| file. Look at the dvi file by using a dvi previewer
+or by printing it out. The output will be nicely formatted with the
+code line numbered and cross references after every macro chunk.
+
+\section{Use}
+Most of the major features of and concepts of Tango/Weevil have been
+presented. This section presents the rest.
+
+\subsection{Cross Referencing to Other Files}
+As mentioned before, Tango/Weevil lets you reference other files for
+cross references. This is done with the following directives followed
+by a filename. This must be the entire filename, including the
+\verb|.xfr| suffix.
+
+\begin{tabular}{lp{3in}}
+\verb|@includefile| & The given file is included (using a \#include) in
+ the current file.\\
+\verb|@reffile| & This file uses variables and functions in the
+ given file.\\
+\end{tabular}
+
+\subsection{Creating Your Own Cross References}
+If you don't trust the cross reference generator or you are using a
+language that \texttt{tango} will not generate cross references for,
+you can put the cross references in yourself. The following
+directives define different types of cross references. They are all
+followed by a string that is the cross reference name.
+
+\begin{tabular}{lp{3in}}
+\verb|@uses| & The given variable is used in the code chunk.\\
+\verb|@defines| & The given variable is a \#define in the code chunk.\\
+\verb|@externdecls| & The given variable is declared in the code chunk
+ and may be used outside the file.\\
+\verb|@staticdecls| & The given variable is declared in the code chunk
+ but may only be used in the file.\\
+\end{tabular}
+
+These directives must appear in the code chunk they are referencing.
+They may not occur outside a code chunk. When these are used, auto
+cross reference generation should be turned off but cross referencing
+should be turned on.
+
+\subsection{Controlling Input Files and Line Numbers}
+Since Tango/Weevil files may be produced by another program, some way
+must exist for that file name and the proper line numbers to be passed
+along to the compiler so debuggers work correctly. This is done using
+the following directives:
+
+\begin{tabular}{lp{3in}}
+\verb|@line| & The line number is set to the number following
+ the directive.\\
+\verb|@file| & The file name is set to the name following the
+ directive.\\
+\end{tabular}
+
+\subsection{Other Stuff}
+
+If an \verb|@| is needed in the code (outside of a quote or comment)
+then \verb|@@| will produce on at-sign.
+
+\subsection{Running the programs}
+
+\subsubsection{tango}
+
+The \verb|tango| program has the following format:
+
+\begin{verbatim}
+ tango [options] inputfile
+\end{verbatim}
+
+The output is sent to standard out. Valid options are:
+
+\begin{tabular}{lp{3in}}
+-xref & Generate cross references\\
+-autoxref & Automatically generate cross references.
+ This will only work for ``C'' programs.\\
+-xreffile \emph{fname} & Send the output for the crossreferences
+ to \emph{fname} instead of the input file
+ prefix with \verb|.xfr| on the end.\\
+-lang \emph{lang} & Sets the programming language mode.
+ Currently only ``c'' is supported. This
+ options is required, so it's not really
+ an option.\\
+-nolinenum & Don't generate \#line references in the
+ output file.\\
+\end{tabular}
+
+\subsubsection{weevil}
+
+The \verb|weevil| program takes several options for specifying input
+language modes, output formatter modes, and include directories for
+cross reference files.
+
+\begin{tabular}{lp{3in}}
+-I \emph{inc dir} & Adds a directory to the list of places to look
+ for cross reference (.xfr) files.\\
+-lang \emph{lang} & Sets the programming language mode.
+ Currently only ``c'' is supported. This
+ options is required, so it's not really
+ an option.\\
+-mode \emph{formatter} & Sets the output formatter mode.
+ Currently only ``latex'' is supported. This
+ options is required, so it's not really
+ an option.\\
+\end{tabular}
+
+\section{Internals}
+
+\subsection{The Cross Reference Document Format}
+
+The cross reference files have a very simple line-oriented format.
+The first character on a line identifies the type of cross reference,
+or identifies the file or macro name. The second character must be a
+space. The third character to the end of the line gives a name. The
+hello world program presented earlier has the following cross
+reference file:
+\begin{verbatim}
+f hello.tw
+m Leave Program
+u exit
+m Output Hello
+u printf
+m Routines
+e main
+m Includes
+m *
+\end{verbatim}
+
+The following first characters are valid:
+
+\begin{tabular}{lp{4in}}
+f & The file name. This must be the first entry in the file, but
+ may occur more than once in the file. This allows multiple
+ files to be concatenated into one big file with the filenames
+ the entries come from preserved.\\
+m & A macro name. This sets the current macro; all cross references
+ between this line and the next macro name will belong to this
+ macro.\\
+u & A variable use. A variable (static, external, or \#defined)
+ was used.\\
+e & An external define. A variable visible to other modules was
+ defined.\\
+s & A static define. A variable was defined that will not be
+ visible to modules that cross reference this module. The
+ variable will be visible to modules that include this module.\\
+d & A \#define. A constant or macro was defined. This will only
+ be visible to modules that include this module.\\
+\end{tabular}
+
+\subsection{Adding New Languages}
+
+Adding new languages to \verb|tango| and \verb|weevil| is relatively
+easy. The language must provide two routines and must add these to
+the array of valid languages in \verb|tango| and \verb|weevil|. For
+\verb|tango| the routines are:
+
+\begin{tabular}{lp{3in}}
+init\_\emph{x}\_mode & Initialize the language \emph{x} mode. A
+ variable name \verb|code_info| is available
+ in the \verb|t_lptangodat| structure that the
+ language mode may use to store a pointer.\\
+\emph{x}\_scan\_input & Takes an input block of data as a character
+ pointer, a length, and a line number. At
+ a minimum, it must set the \verb|inquote|
+ and \verb|in_comment| variables in the
+ \verb|t_lptangodat| structure if the code
+ was in a quote or a comment at the end of
+ each code block. Cross reference may also
+ be created if the \verb|auto_xref|
+ variable in the structure is set TRUE.\\
+\end{tabular}
+
+For \verb|weevil| the routines are:
+
+\begin{tabular}{lp{3in}}
+init\_\emph{x}\_mode & Initialize the language \emph{x} mode. A
+ variable name \verb|code_info| is available
+ in the \verb|t_lptangodat| structure that the
+ language mode may use to store a pointer.\\
+\emph{x}\_handle\_char & Takes a single character at a time from
+ the input file. It must set the \verb|inquote|
+ and \verb|in_comment| variables in the
+ \verb|t_lptangodat| structure if the code
+ was in a quote or a comment after each
+ character.\\
+\end{tabular}
+
+The reason for quote and comment sensing is to avoid having the user
+have to enter \verb|@@| in comments and quotes.
+
+If a language mode is emitting cross references, it must put those
+into lists of names. Four types of lists are kept for each macro; one
+for each type of cross reference. These lists are kepts in one-way
+linked lists of \verb|t_namelist| items. Each item has a character
+pointer with the name and a pointer to the next item. The routine
+\verb|create_namelist_item| should be used to allocate this structure.
+The routine \verb|free_namelist_item| should be used to free the
+structure. To add a structure to a list, use the
+\verb|list_insert_unique| routine:
+\begin{verbatim}
+ /* Add the item to the macro's list of variable uses. */
+ list_insert_unique(lptd, &(lptd->curr_macro->uses), item);
+ /* Add the item to the list of external declarations. */
+ list_insert_unique(lptd, &(lptd->curr_macro->globaldefs), item);
+ /* Add the item to the list of static declarations. */
+ list_insert_unique(lptd, &(lptd->curr_macro->staticdefs), item);
+ /* Add the item to the list of #defines. */
+ list_insert_unique(lptd, &(lptd->curr_macro->pounddefs), item);
+\end{verbatim}
+
+The following routines are also available for use:
+\begin{verbatim}
+ find_name_in_list - Find a name in a namelist.
+ r_strtok - A reentrant strtok.
+ stralloc - Allocates and copies a string.
+\end{verbatim}
+
+\expandafter\ifx\csname DocumentPart\endcsname\relax
+\end{document}
+\fi
diff --git a/web/tango-weevil/weevdoc.tex b/web/tango-weevil/weevdoc.tex
new file mode 100644
index 0000000000..8e9e236b07
--- /dev/null
+++ b/web/tango-weevil/weevdoc.tex
@@ -0,0 +1,44 @@
+\documentclass{book}
+\def\twnocode{}
+%\def\twnoproc{}
+\usepackage{tw,makeidx}
+\title{Weevil - A WEB Weaver}
+\author{Corey Minyard}
+\date{\today}
+\pagenumbering{roman}
+\makeindex
+\newcommand{\clearemptydoublepage}{\newpage{\pagestyle{empty}\cleardoublepage}}
+\begin{document}
+\maketitle
+\clearemptydoublepage
+\tableofcontents
+\clearemptydoublepage
+\pagenumbering{arabic}
+\chapter{Introduction}
+
+This \verb|weevil| program generates \LaTeX2e\ output from a literate
+program. It doesn't do a whole lot; it just takes the code and
+converts it to \LaTeX\ format and generates the appropriate stuff to
+go around the code. It is up to the user to supply the appropriate
+\LaTeX\ headers, trailers and documentation for the code.
+
+\section{Operation}
+
+All directives except \verb|code| and \verb|endcode| are ignored by
+\verb|weevil|. These directives are converted to \verb|\begin{alltt}|
+and \verb|\end{alltt}| respectively. The code inbetween has all
+braces and backslashes converted to appropriate \LaTeX\ codes so they
+will print properly. Variable use and define directives are collected
+and issued at the bottom of the list. Macro definitions and uses are
+cross-referenced.
+
+\chapter{weevinfo}
+\include{weevinfo}
+\chapter{weevil}
+\include{weevil}
+\chapter{c\_weevil}
+\include{c_weevil}
+\chapter{\LaTeX}
+\include{latex}
+\printindex
+\end{document}
diff --git a/web/tango-weevil/weevil.tw b/web/tango-weevil/weevil.tw
new file mode 100644
index 0000000000..89b46f5f72
--- /dev/null
+++ b/web/tango-weevil/weevil.tw
@@ -0,0 +1,1367 @@
+%
+% Tango/Weevil - A WEB Tangler and Weaver
+% Copyright (C) 1995 Corey Minyard
+%
+% 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.
+%
+% Corey Minyard - minyard@metronet.com
+%
+\section{Weevil Main File Intro}
+
+The following code holds the main file structure:
+
+@includefile weevinfo.xfr
+%The following holds cross references for all the file used by weevil
+@reffile weevilref.xfr
+@reffile c_weevil.xfr
+@reffile latex.xfr
+
+@code <*>
+@<Includes>
+@<Defines>
+@<Code>
+@endcode
+
+\subsection{Includes}
+Just some standard stuff to include. The \verb|weevinfo| file
+contains all the major data structures for weevil.
+
+@code <Includes>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "weevinfo.h"
+@endcode
+
+\subsection{Defines}
+Since all the language and output specific information is not in this
+file, not much is left to define.
+
+@code <Defines>
+/* Return values for the get_input_line routine. */
+#define GOT_LINE 1
+#define END_OF_FILE 0
+
+/* These are for input_xreffile(). */
+#define INCLUDE_TYPE 1
+#define XREF_TYPE 2
+#define MAIN_TYPE 3
+
+#define MAX_FILENAME_LENGTH 200
+@endcode
+
+\subsection{Code}
+Herer is the meat of the matter here. The actual code.
+
+@code <Code>
+@<Utils>
+@<open_include_file>
+@<input_xreffile>
+@<process_cmd>
+@<process_codeline>
+@<output_xref>
+@<Get Args>
+@<main>
+@endcode
+
+\subsubsection{Utils}
+These are various utilities that may be used both inside and outside
+this module.
+
+@code <Utils>
+@<get_input_line>
+@<r_strtok>
+@<stralloc>
+@<find_name_in_xref>
+@<find_macro_in_xref>
+@endcode
+
+\begin{twproc}{r\_strtok}
+\Description A re-entrant strtok. This routine scans the
+ string \verb|data| for tokens. These tokens
+ are separated by characters in the \verb|sstr|
+ string. A pointer to the next token and a
+ starting place for the next \verb|r_strtok| call is
+ returned.
+\SideEffects The string in the \verb|data| variable is modified
+ by insertion of null characters (\verb|'\0'|) to
+ separate the tokens.
+\ReturnValues \verb|char *| - A pointer to the next token.
+\Inputs \begin{twparmlist}
+ \item[data] The string to scan for token
+ \item[sstr] A string containing characters that
+ should separate the tokens.
+ \end{twparmlist}
+\Outputs \begin{twparmlist}
+ \item[next\_data] A pointer to the next place
+ to start scanning. This may be used as
+ the next \verb|data| parameter to get
+ successive tokens from a string.
+ \end{twparmlist}
+\StartCode
+@code <r_strtok>
+char *
+r_strtok(char *data,
+ char *sstr,
+ char **next_data)
+{
+ char *retval;
+
+
+ while ( (*data != '\0')
+ && (strchr(sstr, *data) != NULL))
+ {
+ data++;
+ }
+
+ retval = data;
+ while ( (*data != '\0')
+ && (strchr(sstr, *data) == NULL))
+ {
+ data++;
+ }
+
+ if (retval == data)
+ {
+ retval = NULL;
+ }
+ else
+ {
+ if (*data != '\0')
+ {
+ *data = '\0';
+ data++;
+ }
+
+ if (next_data != NULL)
+ {
+ *next_data = data;
+ }
+ }
+
+ return(retval);
+}
+@endcode
+\end{twproc}
+
+\begin{twproc}{stralloc}
+\Description Allocates some memory for a string and copies the
+ string into it.
+\ReturnValues \verb|char *| - The newly allocated string.
+\Inputs \begin{twparmlist}
+ \item[str] The string to allocate the data for
+ and copy data into.
+ \end{twparmlist}
+\StartCode
+@code <stralloc>
+char *
+stralloc(char *str)
+{
+ char *retval;
+
+ retval = malloc(strlen(str) + 1);
+ if (retval == NULL)
+ {
+ fprintf(stderr,
+ "Fatal: Unable to allocate memory\n");
+ exit(1);
+ }
+
+ strcpy(retval, str);
+ return(retval);
+}
+@endcode
+\end{twproc}
+
+\begin{twproc}{get\_input\_line}
+\Description Get a line of text from the input file. If the line
+ is too long, it will truncate the line and skip
+ everything after the maximum line size.
+\SideEffects The input file is read from. The current line number
+ is advanced. The current input line string is set
+ to the new input line.
+\ReturnValues \verb|int| - This will be either \verb|END_OF_FILE|
+ or \verb|GOT_LINE|.
+\Inputs \begin{twparmlist}
+ \item[lpwd] Holds ``global'' data for the program
+ \end{twparmlist}
+\StartCode
+@code <get_input_line>
+int
+get_input_line(t_lpweevildat *lpwd)
+{
+#define FLUSHSIZE 20
+ int retval;
+ int length;
+ char flushbuf[FLUSHSIZE];
+ int flushlength;
+
+
+ (lpwd->curr_lineno)++;
+
+ if (fgets(lpwd->line, lpwd->maxlinesize, lpwd->infile) == NULL)
+ {
+ retval = END_OF_FILE; /* Did not get a line, end of file. */
+ }
+ else
+ {
+ retval = GOT_LINE;
+ length = strlen(lpwd->line);
+
+ /* If the line was too long (it was the max size and the
+ last character was not a newline), print a log and flush
+ to end of line. */
+ if ( (length == (lpwd->maxlinesize - 1))
+ && (lpwd->line[length-1] != '\n'))
+ {
+ fprintf(stderr,
+ "Warning, line %d too long,"
+ " flushing to end of line\n",
+ lpwd->curr_lineno);
+ if (fgets(flushbuf, FLUSHSIZE, lpwd->infile) == NULL)
+ {
+ flushlength = 0;
+ }
+ else
+ {
+ flushlength = strlen(flushbuf);
+ }
+ while ( (flushlength == (FLUSHSIZE - 1))
+ && (lpwd->line[flushlength-1] != '\n'))
+ {
+ if (fgets(flushbuf, FLUSHSIZE, lpwd->infile) == NULL)
+ {
+ flushlength = 0;
+ }
+ else
+ {
+ flushlength = strlen(flushbuf);
+ }
+ }
+ }
+ else
+ {
+ lpwd->line[length-1] = '\0'; /* Get rid of the newline. */
+ }
+ }
+
+ return(retval);
+}
+@endcode
+\end{twproc}
+
+\begin{twproc}{find\_name\_in\_xref}
+\Description Finds a name (string in a name field) the same
+ as a specified string.
+\ReturnValues \verb|xreflist *| - A pointer to the list item
+ holding the name.
+\Inputs \begin{twparmlist}
+ \item[start] The list start
+ \item[name] The name to search for
+ \end{twparmlist}
+\StartCode
+@code <find_name_in_xref>
+xreflist *
+find_name_in_xref(xreflist *start,
+ char *name)
+{
+ while (start != NULL)
+ {
+ if (strcmp(start->name, name) == 0)
+ {
+ break;
+ }
+
+ start = start->next;
+ }
+
+ return(start);
+}
+@endcode
+\end{twproc}
+
+\begin{twproc}{find\_macro\_in\_xref}
+\Description Finds a macro name (string in a macro field) the same
+ as a specified string.
+\ReturnValues \verb|xreflist *| - A pointer to the list item
+ holding the macro name.
+\Inputs \begin{twparmlist}
+ \item[start] The list start
+ \item[name] The macro name to search for
+ \end{twparmlist}
+\StartCode
+@code <find_macro_in_xref>
+xreflist *
+find_macro_in_xref(xreflist *start,
+ char *macro)
+{
+ while (start != NULL)
+ {
+ if ( (start->file == NULL)
+ && (strcmp(start->macro, macro) == 0))
+ {
+ break;
+ }
+ start = start->next;
+ }
+
+ return(start);
+}
+@endcode
+\end{twproc}
+
+\subsubsection{Command Processing}
+All commands encountered (commands start with \verb|@| and must start
+in column 1) while processing documentation will be handled by this
+code.
+
+\begin{twproc}{process\_cmd}
+\Description Handles a \verb|@| command while in documentation (not code)
+ state.
+\SideEffects \begin{twparmlist}
+ \item[codestate]
+ \item[curr\_filename]
+ \item[curr\_macro]
+ \end{twparmlist}
+\Inputs \begin{twparmlist}
+ \item[lpwd] Holds ``global'' data for the program
+ \end{twparmlist}
+\StartCode
+@code <process_cmd>
+void
+process_cmd(t_lpweevildat *lpwd)
+{
+ char *strhold;
+ char *cmd;
+ char *name;
+ int namelength;
+
+
+ cmd = r_strtok(&(lpwd->line[1]), " \t", &strhold);
+ if (cmd == NULL)
+ {
+ fprintf(stderr,
+ "Error on line %d: Missing command\n",
+ lpwd->curr_lineno);
+ lpwd->retcode = 2;
+ }
+ @<Handle code command>
+ @<Handle file command>
+ else if (strcmp(cmd, "includefile") == 0)
+ {
+ name = r_strtok(strhold, " \t", &strhold);
+ input_xreffile(lpwd, name, INCLUDE_TYPE);
+ }
+ else if (strcmp(cmd, "reffile") == 0)
+ {
+ name = r_strtok(strhold, " \t", &strhold);
+ input_xreffile(lpwd, name, XREF_TYPE);
+ }
+ else if (strcmp(cmd, "line") == 0)
+ {
+ /* Ignored when weevilling. */
+ }
+ else
+ {
+ fprintf(stderr,
+ "Error on line %d: Invalid command\n",
+ lpwd->curr_lineno);
+ lpwd->retcode = 2;
+ }
+}
+@endcode
+
+The following code handle a \verb|@code| command. It will get the
+name of the code macro (between \verb|<| and \verb|>|) and call the
+output routines to handle macro beginnings.
+
+@code <Handle code command>
+else if (strcmp(cmd, "code") == 0)
+{
+ if (lpwd->codestate == IN_CODE)
+ {
+ fprintf(stderr,
+ "Error on line %d:"
+ " Macro begin when already processing a macro\n",
+ lpwd->curr_lineno);
+ lpwd->retcode = 2;
+ }
+ else
+ {
+ while ((*strhold == ' ') || (*strhold == '\t'))
+ {
+ strhold++;
+ }
+
+ if (*strhold != '<')
+ {
+ fprintf(stderr,
+ "Error on line %d:"
+ " Macro name must be surrounded by <>\n",
+ lpwd->curr_lineno);
+ lpwd->retcode = 2;
+ }
+ else
+ {
+ strhold++;
+ }
+
+ name = r_strtok(strhold, ">", &strhold);
+ lpwd->curr_macro = stralloc(name);
+
+ lpwd->codestate = IN_CODE;
+
+ lpwd->begin_macro(lpwd, name);
+ }
+}
+@endcode
+
+The following code handles a file command. It scans for the file name
+and sets the current file name to the name specified in the command.
+
+@code <Handle file command>
+else if (strcmp(cmd, "file") == 0)
+{
+ if (lpwd->codestate == IN_CODE)
+ {
+ fprintf(stderr,
+ "Error on line %d:"
+ " File name change not allowed in code\n",
+ lpwd->curr_lineno);
+ lpwd->retcode = 2;
+ }
+ else
+ {
+ name = r_strtok(strhold, " \t", &strhold);
+ if (name == NULL)
+ {
+ fprintf(stderr,
+ "Error on line %d:"
+ " File name not given with file command\n",
+ lpwd->curr_lineno);
+ lpwd->retcode = 2;
+ }
+ lpwd->curr_filename = stralloc(name);
+ namelength = strlen(name);
+ }
+}
+@endcode
+\end{twproc}
+
+\subsubsection{Process Code}
+Output code goes through the following routine where it will be output
+by the mode-dependent output routines.
+
+\begin{twproc}{process\_codeline}
+\Description Processed a line of code. This will scan for
+ \verb|@<>| macro uses in the code and format
+ the macro name. It will also convert
+ \verb|@@| in the input to \verb|@|.
+\SideEffects \begin{twparmlist}
+ \item[code\_lineno]
+ \end{twparmlist}
+\Inputs \begin{twparmlist}
+ \item[lpwd] Holds ``global'' data for the program
+ \end{twparmlist}
+\StartCode
+@code <process_codeline>
+void
+process_codeline(t_lpweevildat *lpwd)
+{
+ char *cp;
+ char *macro_name;
+ int code_proc;
+
+ cp = lpwd->line;
+ lpwd->output_linenum(lpwd);
+ lpwd->code_lineno++;
+ while (*cp != '\0')
+ {
+ code_proc = lpwd->handle_char(lpwd, *cp, *(cp+1));
+ if (code_proc == PROCESS_CHAR_INSTRING)
+ {
+ lpwd->output_char(lpwd, *cp);
+ cp++;
+ }
+ else if (code_proc == PROCESS_CHAR_SKIPNEXT)
+ {
+ lpwd->output_char(lpwd, *cp);
+ cp++;
+ lpwd->output_char(lpwd, *cp);
+ cp++;
+ }
+ else
+ {
+ switch(*cp)
+ {
+ case '@':
+ cp++;
+ switch(*cp)
+ {
+ case '@':
+ lpwd->output_char(lpwd, '@');
+ lpwd->output_char(lpwd, '@');
+ cp++;
+ break;
+
+ case '<':
+ cp++;
+ macro_name = r_strtok(cp, ">", &cp);
+ lpwd->output_macro_use(lpwd, macro_name);
+ break;
+
+ default:
+ fprintf(stderr,
+ "Error on line %d:"
+ " Invalid @ operator: %c\n",
+ lpwd->curr_lineno,
+ *cp);
+ lpwd->retcode = 2;
+ break;
+ }
+ break;
+
+ default:
+ lpwd->output_char(lpwd, *cp);
+ cp++;
+ }
+ }
+ }
+
+ lpwd->output_char(lpwd, '\n');
+}
+@endcode
+\end{twproc}
+
+\subsubsection{Cross Reference Routines}
+These routine handle inputting and outputting cross-references.
+
+\begin{twproc}{output\_xref}
+\Description Outputs the cross references for a macro. This
+ routine will scan all cross reference lists for the
+ given macro name. Uses references will be output
+ with the declaration location(s), if available.
+ All other references will just be output. Many
+ output-mode dependent handlers do the dirty work
+ of the output; they are called form this routine.
+\Inputs \begin{twparmlist}
+ \item[lpwd] Holds ``global'' data for the program
+ \end{twparmlist}
+\StartCode
+@code <output_xref>
+void
+output_xref(t_lpweevildat *lpwd)
+{
+ xreflist *list;
+ xreflist *def;
+ bool declares_output;/* Since declarations can come from
+ multiple sources, this tracks if
+ any declarations have been output
+ so appropriate cleanup can be
+ done. */
+ bool any_xrefs; /* This tells if any references have
+ been output. This is used because
+ a special output routine is called
+ if any references have been output. */
+
+
+ any_xrefs = FALSE;
+ list = find_macro_in_xref(lpwd->uses, lpwd->curr_macro);
+ if (list != NULL)
+ {
+ any_xrefs = TRUE;
+ lpwd->output_begin_uses(lpwd);
+ while (list != NULL)
+ {
+ def = find_name_in_xref(lpwd->pounddefs, list->name);
+ if (def == NULL)
+ {
+ def = find_name_in_xref(lpwd->vardefs, list->name);
+ }
+
+ lpwd->output_use_start(lpwd, list->name);
+ while (def != NULL)
+ {
+ lpwd->output_use_ref(lpwd,
+ def->file,
+ def->macro,
+ list->name);
+
+ def = find_name_in_xref(def->next, list->name);
+ if (def != NULL)
+ {
+ lpwd->output_between_use_refs(lpwd, list->name);
+ }
+ }
+ lpwd->output_use_end(lpwd, list->name);
+ list = find_macro_in_xref(list->next, lpwd->curr_macro);
+ }
+ lpwd->output_end_uses(lpwd);
+ }
+
+ declares_output = FALSE;
+ list = find_macro_in_xref(lpwd->vardefs, lpwd->curr_macro);
+ if (list != NULL)
+ {
+ any_xrefs = TRUE;
+ declares_output = TRUE;
+ lpwd->output_begin_decls(lpwd);
+ while (list != NULL)
+ {
+ lpwd->output_decl(lpwd, list->name);
+
+ list = find_macro_in_xref(list->next, lpwd->curr_macro);
+ }
+ }
+
+ list = find_macro_in_xref(lpwd->pounddefs, lpwd->curr_macro);
+ if (list != NULL)
+ {
+ any_xrefs = TRUE;
+ if (!declares_output)
+ {
+ declares_output = TRUE;
+ lpwd->output_begin_decls(lpwd);
+ }
+ while (list != NULL)
+ {
+ lpwd->output_decl(lpwd, list->name);
+
+ list = find_macro_in_xref(list->next, lpwd->curr_macro);
+ }
+ }
+
+ if (declares_output)
+ {
+ lpwd->output_end_decls(lpwd);
+ }
+
+ if (any_xrefs)
+ {
+ lpwd->output_after_xrefs(lpwd);
+ }
+}
+@endcode
+\end{twproc}
+
+\begin{twproc}{open\_include\_file}
+\Description Opens a cross-reference file, looking in the include
+ list if necessary.
+\Inputs \begin{twparmlist}
+ \item[lpwd] Holds ``global'' data for the program
+ \item[filename] The file name to open
+ \end{twparmlist}
+\StartCode
+@code <open_include_file>
+FILE *
+open_include_file(t_lpweevildat *lpwd,
+ char *filename)
+{
+ xreflist *includes;
+ FILE *file;
+ char fname[MAX_FILENAME_LENGTH+1];
+ int filename_length;
+
+
+ filename_length = strlen(filename);
+ file = NULL;
+ if (filename[0] != '/')
+ {
+ includes = lpwd->includes;
+ while ((file == NULL) && (includes != NULL))
+ {
+ if ( (strlen(includes->name) + filename_length + 1)
+ > MAX_FILENAME_LENGTH)
+ {
+ fprintf(stderr,
+ "Warning: Include path + filename too long: %s/%s\n",
+ includes->name,
+ filename);
+ }
+ else
+ {
+ strcpy(fname, includes->name);
+ strcat(fname, "/");
+ strcat(fname, filename);
+ file = fopen(fname, "r");
+ }
+ includes = includes->next;
+ }
+ }
+ if (file == NULL)
+ {
+ file = fopen(filename, "r");
+ }
+
+ return(file);
+}
+@endcode
+\end{twproc}
+
+\begin{twproc}{input\_xreffile}
+\Description Reads a cross reference file and store the references
+ in the reference tables.
+\SideEffects \begin{twparmlist}
+ \item[pounddefs]
+ \item[vardefs]
+ \item[uses]
+ \end{twparmlist}
+\Inputs \begin{twparmlist}
+ \item[lpwd] Holds ``global'' data for the program
+ \item[filename] The file name the references are to
+ be read from.
+ \item[incltype] The type of include. This may be
+ \begin{twparmlist}
+ \item[INCLUDE\_TYPE] a \verb|@includefile|
+ \item[XREF\_TYPE] a \verb|@reffile|
+ \item[MAIN\_TYPE] the cross reference file for the
+ file being processed.
+ \end{twparmlist}
+ \end{twparmlist}
+\StartCode
+@code <input_xreffile>
+void
+input_xreffile(t_lpweevildat *lpwd,
+ char *filename,
+ int incltype)
+{
+ char *line;
+ FILE *in_file;
+ char linebuf[MAXLINESIZE];
+ xreflist *elem;
+ char *curr_macro;
+ char *actfilename;
+ curr_macro = "invalid";
+ in_file = open_include_file(lpwd, filename);
+ if (in_file == NULL)
+ {
+ fprintf(stderr, "Unable to open xref file: %s\n",
+ filename);
+ }
+ else
+ {
+ line = fgets(linebuf, MAXLINESIZE, in_file);
+ if ( (line == NULL)
+ || (strncmp(line, "f ", 2) != 0))
+ {
+ fprintf(stderr,
+ "Invalid xref file: %s\n",
+ filename);
+ fclose(in_file);
+ }
+ else
+ {
+ if (incltype == MAIN_TYPE)
+ {
+ actfilename = NULL;
+ }
+ else
+ {
+ actfilename = stralloc(r_strtok(&(line[2]),
+ "\n",
+ NULL));
+ }
+
+ line = fgets(linebuf, MAXLINESIZE, in_file);
+ while (line != NULL)
+ {
+ elem = malloc(sizeof(*elem));
+ elem->file = actfilename;
+ elem->macro = curr_macro;
+ if (elem == NULL)
+ {
+ fprintf(stderr,
+ "Unable to allocate enough memory\n");
+ exit(1);
+ }
+
+ if (strncmp(line, "f ", 2) == 0)
+ {
+ actfilename = stralloc(r_strtok(&(line[2]),
+ "\n",
+ NULL));
+ }
+ else if (strncmp(line, "u ", 2) == 0)
+ {
+ if (incltype == MAIN_TYPE)
+ {
+ elem->name = stralloc(r_strtok(&(line[2]),
+ "\n",
+ NULL));
+ elem->next = lpwd->uses;
+ lpwd->uses = elem;
+ }
+ }
+ else if (strncmp(line, "s ", 2) == 0)
+ {
+ if ( (incltype == MAIN_TYPE)
+ || (incltype == INCLUDE_TYPE))
+ {
+ elem->name = stralloc(r_strtok(&(line[2]),
+ "\n",
+ NULL));
+ elem->next = lpwd->vardefs;
+ lpwd->vardefs = elem;
+ }
+ }
+ else if (strncmp(line, "d ", 2) == 0)
+ {
+ if ( (incltype == MAIN_TYPE)
+ || (incltype == INCLUDE_TYPE))
+ {
+ elem->name = stralloc(r_strtok(&(line[2]),
+ "\n",
+ NULL));
+ elem->next = lpwd->pounddefs;
+ lpwd->pounddefs = elem;
+ }
+ }
+ else if (strncmp(line, "e ", 2) == 0)
+ {
+ elem->name = stralloc(r_strtok(&(line[2]),
+ "\n",
+ NULL));
+ elem->next = lpwd->vardefs;
+ lpwd->vardefs = elem;
+ }
+ else if (strncmp(line, "m ", 2) == 0)
+ {
+ curr_macro = stralloc(r_strtok(&(line[2]),
+ "\n",
+ NULL));
+ free(elem);
+ }
+ else
+ {
+ fprintf(stderr,
+ "Invalid prefix (%c%c) in xreffile: %s\n",
+ line[0], line[1], filename);
+ free(elem);
+ }
+
+ line = fgets(linebuf, MAXLINESIZE, in_file);
+ }
+ }
+ }
+}
+@endcode
+\end{twproc}
+
+\subsubsection{Get Args}
+The following code will process the command line for arguments.
+
+@code <Get Args>
+@<get_arg_str>
+@<Argument Data>
+@<set_mode>
+@<process_args>
+@endcode
+
+\begin{twproc}{get\_arg\_str}
+\Description Returns a parameter for an argument. If the
+ argument is in the same string as the command,
+ that will be returned. Otherwise, the next
+ argument will be returned.
+\ReturnValues \verb|static char *| - A pointer to the
+ argument parameter.
+\Inputs \begin{twparmlist}
+ \item[argidx] A index for the current argument.
+ \item[argc] The argument count
+ \item[argv] The arguments
+ \item[start\_offset] The character offset into the
+ current argument that is right after the
+ command finishes.
+ \end{twparmlist}
+\Outputs \begin{twparmlist}
+ \item[argidx] The next argument
+ \end{twparmlist}
+\StartCode
+@code <get_arg_str>
+static char *
+get_arg_str(int *argidx,
+ int argc,
+ char *argv[],
+ int start_offset)
+{
+ char *retval;
+
+
+ if (argv[*argidx][start_offset] == '\0')
+ {
+ (*argidx)++;
+ if ((*argidx) == argc)
+ {
+ retval = NULL;
+ }
+ else
+ {
+ retval = argv[*argidx];
+ }
+ }
+ else
+ {
+ retval = &(argv[*argidx][start_offset]);
+ }
+
+ return(retval);
+}
+@endcode
+\end{twproc}
+
+The following holds a list of languages that are supported and a list
+of output modes that are supported. Each language and output mode has
+a set of handler routines that are given in these lists.
+
+@code <Argument Data>
+static struct s_langs
+{
+ char *lang_name;
+ char_handler handler;
+ handler_init init;
+} langs[] =
+{
+ { "c", &c_handle_char, &init_c_lang }
+};
+
+static const num_langs = sizeof(langs) / sizeof(struct s_langs);
+
+static struct s_modes
+{
+ char *mode_name;
+ mode_init init;
+ begin_macro_handler begin_macro;
+ end_macro_handler end_macro;
+ finalend_chunk_handler finalend_chunk;
+ output_macro_use_handler output_macro_use;
+ output_linenum_handler output_linenum;
+ output_char_handler output_char;
+ output_begin_uses_handler output_begin_uses;
+ output_end_uses_handler output_end_uses;
+ output_use_start_handler output_use_start;
+ output_use_end_handler output_use_end;
+ output_use_ref_handler output_use_ref;
+ output_between_use_refs_handler output_between_use_refs;
+ output_begin_decls_handler output_begin_decls;
+ output_end_decls_handler output_end_decls;
+ output_decl_handler output_decl;
+ output_after_xrefs_handler output_after_xrefs;
+} modes[] =
+{
+ { "latex", &latex_mode_init,
+ &latex_begin_macro, &latex_end_macro,
+ &latex_finalend_chunk,
+ &latex_output_macro_use, &latex_output_linenum,
+ &latex_output_char, &latex_output_begin_uses,
+ &latex_output_end_uses, &latex_output_use_start,
+ &latex_output_use_end, &latex_output_use_ref,
+ &latex_output_between_use_refs, &latex_output_begin_decls,
+ &latex_output_end_decls, &latex_output_decl,
+ &latex_output_after_xrefs }
+};
+
+static const num_modes = sizeof(modes) / sizeof(struct s_modes);
+@endcode
+
+\begin{twproc}{set\_mode}
+\Description Sets the output mode.
+\SideEffects The left side of every assignment in the routine
+ is a side-effect.
+\Inputs \begin{twparmlist}
+ \item[lpwd] Holds ``global'' data for the program
+ \item[mode] The mode to set.
+ \end{twparmlist}
+\StartCode
+@code <set_mode>
+void
+set_mode(t_lpweevildat *lpwd,
+ struct s_modes *mode)
+{
+ lpwd->begin_macro = mode->begin_macro;
+ lpwd->end_macro = mode->end_macro;
+ lpwd->finalend_chunk = mode->finalend_chunk;
+ lpwd->output_macro_use = mode->output_macro_use;
+ lpwd->output_linenum = mode->output_linenum;
+ lpwd->output_char = mode->output_char;
+ lpwd->output_begin_uses = mode->output_begin_uses;
+ lpwd->output_end_uses = mode->output_end_uses;
+ lpwd->output_use_start = mode->output_use_start;
+ lpwd->output_use_end = mode->output_use_end;
+ lpwd->output_use_ref = mode->output_use_ref;
+ lpwd->output_between_use_refs = mode->output_between_use_refs;
+ lpwd->output_begin_decls = mode->output_begin_decls;
+ lpwd->output_end_decls = mode->output_end_decls;
+ lpwd->output_decl = mode->output_decl;
+ lpwd->output_after_xrefs = mode->output_after_xrefs;
+}
+@endcode
+\end{twproc}
+
+\begin{twproc}{process\_args}
+\Description Actually handles the high-level processing of
+ arguments. It scans for each argument and
+ handles each one individually. It will return
+ after the last argument.
+\Inputs \begin{twparmlist}
+ \item[lpwd] Holds ``global'' data for the program
+ \item[argc] The argument count
+ \item[argv] The argument data
+ \end{twparmlist}
+\Outputs \begin{twparmlist}
+ \item[argidx] The index of the first argument
+ after the option arguments.
+ \end{twparmlist}
+\StartCode
+@code <process_args>
+void
+process_args(t_lpweevildat *lpwd,
+ int argc,
+ char *argv[],
+ int *argidx)
+{
+ char *str;
+ int i;
+ int my_mode;
+
+
+ my_mode = 0;
+
+ *argidx = 1;
+ while (argv[*argidx][0] == '-')
+ {
+ /* This forces the end of option processing. */
+ if (strcmp(argv[*argidx], "--") == 0)
+ {
+ (*argidx)++;
+ break;
+ }
+ @<Handle lang option>
+ @<Handle mode option>
+ @<Handle include option>
+ else
+ {
+ fprintf(stderr,
+ "%s: Error: Invalid option specified: %s\n",
+ argv[0],
+ argv[*argidx]);
+ exit(1);
+ }
+
+ (*argidx)++;
+ }
+
+ set_mode(lpwd, &(modes[i]));
+ modes[i].init(lpwd);
+}
+@endcode
+
+The following code get a language option and tries to find it in the
+language list. If it is successful, it will set the language handlers
+to the ones for the language. If an error occurs, it will print an
+error and exit.
+
+@code <Handle lang option>
+else if (strncmp(argv[*argidx], "-lang", 5) == 0)
+{
+ if (lpwd->handle_char != NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: only 1 -lang is allowed\n",
+ argv[0]);
+ exit(1);
+ }
+
+ str = get_arg_str(argidx, argc, argv, 5);
+ if (str == NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: -lang specified but no lang given\n",
+ argv[0]);
+ exit(1);
+ }
+
+ for (i=0; i<num_langs; i++)
+ {
+ if (strcmp(str, langs[i].lang_name) == 0)
+ {
+ lpwd->handle_char = langs[i].handler;
+ langs[i].init(lpwd);
+ break;
+ }
+ }
+
+ if (lpwd->handle_char == NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: Invalid lang given: %s\n",
+ argv[0], str);
+ exit(1);
+ }
+}
+@endcode
+
+The following handles an output mode. It scans the mode list for the
+output mode. If it finds it, it sets the mode handlers. If it
+doesn't, it prints an error and returns.
+
+@code <Handle mode option>
+else if (strncmp(argv[*argidx], "-mode", 5) == 0)
+{
+ if (lpwd->begin_macro != NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: only 1 -mode is allowed\n",
+ argv[0]);
+ exit(1);
+ }
+
+ str = get_arg_str(argidx, argc, argv, 5);
+ if (str == NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: -mode specified but no mode given\n",
+ argv[0]);
+ exit(1);
+ }
+
+ for (i=0; i<num_modes; i++)
+ {
+ if (strcmp(str, modes[i].mode_name) == 0)
+ {
+ my_mode = i;
+ break;
+ }
+ }
+
+ if (lpwd->handle_char == NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: Invalid mode given: %s\n",
+ argv[0], str);
+ exit(1);
+ }
+}
+@endcode
+\end{twproc}
+
+@code <Handle include option>
+else if (strncmp(argv[*argidx], "-I", 2) == 0)
+{
+ xreflist *newinclude;
+ xreflist *includelist;
+
+
+ str = get_arg_str(argidx, argc, argv, 2);
+ if (str == NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: -I specified but no include directory given\n",
+ argv[0]);
+ exit(1);
+ }
+
+ newinclude = malloc(sizeof(*newinclude));
+ if (newinclude == NULL)
+ {
+ fprintf(stderr,
+ "%s: Error: Out of memory\n",
+ argv[0]);
+ exit(1);
+ }
+
+ newinclude->name = str;
+ newinclude->next = NULL;
+ includelist = lpwd->includes;
+ if (includelist == NULL)
+ {
+ lpwd->includes = newinclude;
+ }
+ else
+ {
+ while (includelist->next != NULL)
+ {
+ includelist = includelist->next;
+ }
+ includelist->next = newinclude;
+ }
+}
+@endcode
+
+\begin{twproc}{main}
+\Description The main routine. This routine initializes some data,
+ processes the input options, then crunches on input
+ lines.
+\ReturnValues \verb|int| - system return value.
+\Inputs \begin{twparmlist}
+ \item[argc] The number of arguments given to the program
+ \item[argv] The actual arguments.
+ \end{twparmlist}
+\StartCode
+@code <main>
+int
+main(int argc,
+ char *argv[])
+{
+ t_lpweevildat *lpwd;
+ int argidx;
+ int len;
+ char *str;
+ char fname[MAX_FILENAME_LENGTH+1];
+
+
+ @<Main init>
+
+ process_args(lpwd, argc, argv, &argidx);
+
+ if (lpwd->handle_char == NULL)
+ {
+ fprintf(stderr, "%s: No lang specified\n", argv[0]);
+ exit(1);
+ }
+
+ if (lpwd->begin_macro == NULL)
+ {
+ /* No mode specified, default to the first one. */
+ set_mode(lpwd, &(modes[0]));
+ }
+
+ if (argc <= argidx)
+ {
+ fprintf(stderr, "%s: No filename specified\n",
+ argv[0]);
+ exit(1);
+ }
+
+ @<Open input file>
+
+ @<Scan input>
+
+ if (lpwd->codestate == IN_CODE)
+ {
+ fprintf(stderr,
+ "Warning: File %s ended while outputting code",
+ lpwd->curr_filename);
+ lpwd->codestate = NOT_IN_CODE;
+ lpwd->retcode = 2;
+ }
+
+ return(lpwd->retcode);
+}
+@endcode
+
+Allocate an initialize the global data structure.
+
+@code <Main init>
+ lpwd = malloc(sizeof(*lpwd));
+ if (lpwd == NULL)
+ {
+ fprintf(stderr, "Unable to allocate enough memory\n");
+ exit(1);
+ }
+
+ lpwd->maxlinesize = MAXLINESIZE;
+ lpwd->curr_lineno = 0;
+ lpwd->code_lineno = 1;
+ lpwd->outfile = stdout;
+ lpwd->pounddefs = NULL;
+ lpwd->vardefs = NULL;
+ lpwd->uses = NULL;
+ lpwd->begin_macro = NULL;
+ lpwd->handle_char = NULL;
+ lpwd->includes = NULL;
+ lpwd->retcode = 0;
+@endcode
+
+Open an input file. Also, get the prefix (everything before the last
+period in the name), generate a cross reference filename, and input
+the cross reference file.
+
+@code <Open input file>
+ lpwd->infile = fopen(argv[argidx], "r");
+ while ((argidx < argc) && (lpwd->infile == NULL))
+ {
+ fprintf(stderr, "%s: Unable to open file %s\n",
+ argv[0], argv[argidx]);
+ argidx++;
+ lpwd->infile = fopen(argv[argidx], "r");
+ }
+ lpwd->curr_filename = argv[argidx];
+
+ str = strrchr(argv[argidx], '.');
+ if (str != NULL)
+ {
+ len = str - argv[argidx];
+ }
+ else
+ {
+ len = strlen(argv[argidx]);
+ }
+
+ if ((len+4) >= MAX_FILENAME_LENGTH) /* Add 4 for the .xfr */
+ {
+ fprintf(stderr, "filename to long, no xref file input\n");
+ }
+ else
+ {
+ memcpy(fname, argv[argidx], len);
+ strcpy(&(fname[len]), ".xfr");
+ input_xreffile(lpwd, fname, MAIN_TYPE);
+ }
+@endcode
+
+Get the input file a line at a time and process it. The program
+toggles between two input states. When \verb|IN_CODE|, it is handling
+stuff between \verb|@code| and \verb|@endcode|. Otherwise, it is
+processing documentation.
+
+@code <Scan input>
+ lpwd->codestate = NOT_IN_CODE;
+ while (get_input_line(lpwd) == GOT_LINE)
+ {
+ if (lpwd->codestate == IN_CODE)
+ {
+ if (strncmp(lpwd->line, "@endcode", 8) == 0)
+ {
+ lpwd->end_macro(lpwd);
+ lpwd->codestate = NOT_IN_CODE;
+ output_xref(lpwd);
+ lpwd->finalend_chunk(lpwd);
+ }
+ else if ( (strncmp(lpwd->line, "@staticdecls", 12) == 0)
+ || (strncmp(lpwd->line, "@defines", 8) == 0)
+ || (strncmp(lpwd->line, "@externdecls", 12) == 0)
+ || (strncmp(lpwd->line, "@uses", 5) == 0))
+ {
+ /* These are ignored */
+ }
+ else
+ {
+ process_codeline(lpwd);
+ }
+ }
+ else if (lpwd->line[0] == '@')
+ {
+ process_cmd(lpwd);
+ }
+ else
+ {
+ fputs(lpwd->line, lpwd->outfile);
+ fputc('\n', lpwd->outfile);
+ }
+ }
+@endcode
+\end{twproc}
+
diff --git a/web/tango-weevil/weevinfo.tw b/web/tango-weevil/weevinfo.tw
new file mode 100644
index 0000000000..7f800b4a95
--- /dev/null
+++ b/web/tango-weevil/weevinfo.tw
@@ -0,0 +1,418 @@
+%
+% Tango/Weevil - A WEB Tangler and Weaver
+% Copyright (C) 1995 Corey Minyard
+%
+% 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.
+%
+% Corey Minyard - minyard@metronet.com
+%
+\section{Weevil Information Include Introduction}
+
+This file contains the information used by weevil and the language and
+output handlers that interface to weevil.
+
+@code <*>
+#ifdef __cplusplus__
+extern "C"
+{
+#endif
+
+@<Defines>
+@<Structures>
+@<C Language Routines>
+@<LaTeX Routines>
+
+#ifdef __cplusplus__
+}
+#endif
+@endcode
+
+\section{Interfacing Languages to Weevil}
+
+A language definition requires two simple procedure calls. A
+character handler handles all code a character at a time. It's job is
+to tell weevil how to handle the character. It is passed the standard
+weevil data, a character, and the next character in the sequence. It
+returns the following codes:
+
+\begin{description}
+\item[PROCESS\_CHAR\_NORMALLY] This is a standard character that
+should be handled normally by weevil.
+\item[PROCESS\_CHAR\_INSTRING] This character is in a string or
+comment, it should not be scanned for special weevil characters.
+\item[PROCESS\_CHAR\_SKIPNEXT] This character and the following
+character should be skipped without being scanned for special weevil
+characters.
+\end{description}
+
+The other procedure is an initialization handler, which may initialize
+the language handler.
+
+\section{Interfacing Output Types to Weevil}
+
+An output type requires a lot of function calls but is conceptually
+simple. Each function call output a certain portion of the output,
+just provide the proper output mechanism, add all the functions to the
+list of output modes, and it's done. Section~\ref{weevinfo-defines}
+has the typedefs and descriptions for all the functions.
+
+\begin{sloppypar}
+Weevil has a number of output modes. Documentation modes is the mode
+weevil starts in, it will just output everything as-is until it finds
+a code chunk (marked by \verb|@code|). Then it switches to code mode
+after calling \verb|begin_macro_handler|. Code mode calls the
+language character handler on each character to find out if it is in a
+string, comment, etc. It will output characters normally until it
+sees an \verb|@| (unless in a string or comment). If it sees an
+\verb|@@|, it will output a single \verb|@|. If it sees a
+\verb|@<name>|, it will call \verb|output_macro_use_handler| with the
+name. It will \emph{not} output the \verb|@<name>|. At the end of
+the code chunk, \verb|end_macro_handler| will be called. At the
+beginning of each line, \verb|output_linenum_handler| will be called.
+\end{sloppypar}
+
+After a code chunk has been output, if cross references for any
+variable uses exist for the code chunk then uses mode will be entered,
+where each variable used by the code chunk will be output. A begin
+handler is called, then for each cross reference the name handle is
+called and a handler is called for each place where the name is
+declared is given. Then an end name handler is called. After all
+uses have been output, an end handler is called.
+
+If declaration cross references exist, they are output next. A begin
+handler is called, then a handler for each variable name, then an end
+handler for the declaration list.
+
+If any cross references were output, a handler is called after all
+cross references have been output. Then documentation mode is entered
+again.
+
+\section{Defines}
+\label{weevinfo-defines}
+The following code chunk has miscellaneous definitions and the
+typedefs for all the language-specific and output-specific procedures
+used by weevil. Each procedure is also described in detail in the
+comment before it.
+
+@code <Defines>
+#define MAXLINESIZE 200
+
+#define TRUE 1
+#define FALSE 0
+typedef int bool;
+
+
+/* Is the processor processing stuff between @code and @endcode or
+ is is processing documentation? Used by the codestate
+ variable. */
+#define IN_CODE 1
+#define NOT_IN_CODE 2
+
+
+#define PROCESS_CHAR_NORMALLY 0
+#define PROCESS_CHAR_INSTRING 1
+#define PROCESS_CHAR_SKIPNEXT 2
+
+struct s_lpweevildat;
+
+/****************************************************************
+**
+** These are for languages.
+**
+****************************************************************/
+
+/*
+ * Process the code a character at a time. The current and next
+ * character are provided. Return PROCESS_CHAR_NORMALLY for
+ * standard output, PROCESS_CHAR_INSTRING if in a string or
+ * comment, or PROCESS_CHAR_SKIPNEXT if the current and next
+ * character should not be processed (just output).
+ */
+typedef int (*char_handler)(struct s_lpweevildat *lpwd,
+ char c,
+ char next_c);
+
+/*
+ * Initialize the language handler. This may use the
+ * language-specific pointer in lpwd to store info for
+ * itself.
+ */
+typedef void (*handler_init)(struct s_lpweevildat *lpwd);
+
+
+/****************************************************************
+**
+** These are for documentation output.
+**
+****************************************************************/
+
+/*
+ * Initialize the mode handler. This may use the mode-specific
+ * pointer in lpwd to store info for itself.
+ */
+typedef void (*mode_init)(struct s_lpweevildat *lpwd);
+
+/*
+ * Handle the beginning of a code chunk. The name of the code
+ * chunk is passed in.
+ */
+typedef void (*begin_macro_handler)(struct s_lpweevildat *lpwd,
+ char *name);
+
+/*
+ * Handle the end of a code chunk.
+ */
+typedef void (*end_macro_handler)(struct s_lpweevildat *lpwd);
+
+/*
+ * Handle the end after all cross references and everything.
+ */
+typedef void (*finalend_chunk_handler)(struct s_lpweevildat *lpwd);
+
+/*
+ * Output the use of a code chunk in some code. The name of
+ * the code chunk is given.
+ */
+typedef void
+(*output_macro_use_handler)(struct s_lpweevildat *lpwd,
+ char *macro_name);
+
+/*
+ * Output the line number at the beginning of the code chunk.
+ */
+typedef void
+(*output_linenum_handler)(struct s_lpweevildat *lpwd);
+
+/*
+ * Output a single normal character.
+ */
+typedef void
+(*output_char_handler)(struct s_lpweevildat *lpwd,
+ char c);
+
+/*
+ * Handle the beginning of a list of uses cross-references.
+ */
+typedef void
+(*output_begin_uses_handler)(struct s_lpweevildat *lpwd);
+
+/*
+ * Handle the end of a list of uses cross-references.
+ */
+typedef void
+(*output_end_uses_handler)(struct s_lpweevildat *lpwd);
+
+/*
+ * Handle the start of a single use cross reference. The name of
+ * the variable is given.
+ */
+typedef void
+(*output_use_start_handler)(struct s_lpweevildat *lpwd,
+ char *name);
+
+/*
+ * Handle the end of a single use cross reference. The name of
+ * the variable is given.
+ */
+typedef void
+(*output_use_end_handler)(struct s_lpweevildat *lpwd,
+ char *name);
+
+/*
+ * Output a use cross reference location. The file and macro
+ * of the declaration is given. The name being cross-referenced
+ * is also given.
+ */
+typedef void
+(*output_use_ref_handler)(struct s_lpweevildat *lpwd,
+ char *file,
+ char *macro,
+ char *name);
+
+/*
+ * Handle between each use of a cross reference.
+ */
+typedef void
+(*output_between_use_refs_handler)(struct s_lpweevildat *lpwd,
+ char *name);
+
+/*
+ * Handle the beginning of a list of declares cross-references.
+ */
+typedef void
+(*output_begin_decls_handler)(struct s_lpweevildat *lpwd);
+
+/*
+ * Handle the end of a list of declares cross-references.
+ */
+typedef void
+(*output_end_decls_handler)(struct s_lpweevildat *lpwd);
+
+/*
+ * Handle the output of a single declaration.
+ */
+typedef void
+(*output_decl_handler)(struct s_lpweevildat *lpwd,
+ char *name);
+
+/*
+ * Handle the end of cross references. This is only called if
+ * cross-references were created.
+ */
+typedef void
+(*output_after_xrefs_handler)(struct s_lpweevildat *lpwd);
+@endcode
+
+\section{Structures}
+Various structures used by weevil are put here.
+
+@code <Structures>
+@<xreflist>
+@<lpweevildat>
+@endcode
+
+\subsection{xreflist}
+This list contains list of cross references and information on where
+they are declared.
+
+@code <xreflist>
+typedef struct s_xreflist
+{
+ struct s_xreflist *next;
+ char *file;
+ char *macro;
+ char *name;
+} xreflist;
+@endcode
+
+\subsection{lpweevildat}
+This large structure contains everything there is to know about what
+weevil is doing.
+
+@code <lpweevildat>
+typedef struct s_lpweevildat
+{
+ FILE *infile; /* File to get input from. */
+ FILE *outfile; /* File to send output. */
+ char line[MAXLINESIZE]; /* Current input line. */
+
+ int codestate; /* Current output state. */
+ char *curr_filename; /* Name of the input file being
+ processed. */
+ char *curr_macro; /* Current macro being input. */
+ int maxlinesize; /* Maximum size of an input line. */
+ int curr_lineno; /* Current input line number. */
+ int code_lineno; /* Current code output line number. */
+
+ int retcode; /* Program return code. */
+
+ void *lang_data; /* Data for language mode. */
+ void *mode_data; /* Data for output mode. */
+
+ xreflist *pounddefs; /* List of #defines. */
+ xreflist *vardefs; /* List of variable defines. */
+ xreflist *uses; /* List of variable uses. */
+
+ xreflist *includes; /* List of places to look for
+ .xfr files. */
+
+ /* Routine to scan code in a language-specific way. */
+ char_handler handle_char;
+
+ /* Routines to output data for the output mode. */
+ begin_macro_handler begin_macro;
+ end_macro_handler end_macro;
+ finalend_chunk_handler finalend_chunk;
+ output_macro_use_handler output_macro_use;
+ output_linenum_handler output_linenum;
+ output_char_handler output_char;
+ output_begin_uses_handler output_begin_uses;
+ output_end_uses_handler output_end_uses;
+ output_use_start_handler output_use_start;
+ output_use_end_handler output_use_end;
+ output_use_ref_handler output_use_ref;
+ output_between_use_refs_handler output_between_use_refs;
+ output_begin_decls_handler output_begin_decls;
+ output_end_decls_handler output_end_decls;
+ output_decl_handler output_decl;
+ output_after_xrefs_handler output_after_xrefs;
+} t_lpweevildat;
+@endcode
+
+\section{Language Dependent Routines}
+Here are forward-declared all the routines for the various languages
+handled by weevil.
+
+\subsection{C}
+
+@code <C Language Routines>
+int c_handle_char(t_lpweevildat *lpwd,
+ char c,
+ char next_c);
+
+void init_c_lang(t_lpweevildat *lpwd);
+@endcode
+
+\section{Output Mode Routines}
+Here are forward-declared all the routines for the various output modes
+handled by weevil.
+
+\subsection{\LaTeX}
+
+@code <LaTeX Routines>
+void latex_mode_init(t_lpweevildat *lpwd);
+
+void latex_begin_macro(t_lpweevildat *lpwd,
+ char *name);
+
+void latex_end_macro(t_lpweevildat *lpwd);
+
+void latex_finalend_chunk(t_lpweevildat *lpwd);
+
+void latex_output_macro_use(t_lpweevildat *lpwd,
+ char *macro_name);
+
+void latex_output_linenum(t_lpweevildat *lpwd);
+
+void latex_output_char(t_lpweevildat *lpwd,
+ char c);
+
+void latex_output_begin_uses(t_lpweevildat *lpwd);
+
+void latex_output_end_uses(t_lpweevildat *lpwd);
+
+void latex_output_use_start(t_lpweevildat *lpwd,
+ char *name);
+
+void latex_output_use_end(t_lpweevildat *lpwd,
+ char *name);
+
+void latex_output_use_ref(t_lpweevildat *lpwd,
+ char *file,
+ char *macro,
+ char *name);
+
+void latex_output_between_use_refs(t_lpweevildat *lpwd,
+ char *name);
+
+void latex_output_begin_decls(t_lpweevildat *lpwd);
+
+void latex_output_end_decls(t_lpweevildat *lpwd);
+
+void latex_output_decl(t_lpweevildat *lpwd,
+ char *name);
+
+void latex_output_after_xrefs(t_lpweevildat *lpwd);
+@endcode