summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbehdad <behdad>2004-05-03 05:17:48 +0000
committerbehdad <behdad>2004-05-03 05:17:48 +0000
commit577ed4095383ef5284225d45709e6b5f0598a064 (patch)
tree6c7d0ce55124a688b4d7050e684d9d7a1e3aa71d
downloadc2man-master.tar.gz
Initial revisionHEADoriginmaster
-rw-r--r--C++autodoc292
-rw-r--r--CHANGES127
-rw-r--r--ChangeLog29
-rwxr-xr-xConfigure4822
-rw-r--r--FAQ204
-rw-r--r--INSTALL74
-rw-r--r--MANIFEST64
-rwxr-xr-xMakefile.SH172
-rw-r--r--README112
-rw-r--r--autodoc.c554
-rw-r--r--c2man.c928
-rw-r--r--c2man.h284
-rw-r--r--c2man.man906
-rw-r--r--catalog44
-rw-r--r--config_h.SH353
-rw-r--r--confmagic.h27
-rw-r--r--ctype_ex.h38
-rw-r--r--eg/boxcomment.c41
-rw-r--r--eg/ccomment.h41
-rw-r--r--eg/commentaft.c1
-rw-r--r--eg/cppcomment.h32
-rw-r--r--eg/dash.h2
-rw-r--r--eg/ellipsis.c15
-rw-r--r--eg/grouped.c23
-rw-r--r--eg/multidecl.c3
-rw-r--r--eg/namedash.h9
-rw-r--r--eg/oldstyle.c24
-rw-r--r--eg/retdecl.c10
-rw-r--r--eg/returnerr.h16
-rw-r--r--eg/returnlist.h16
-rw-r--r--eg/sections.c17
-rw-r--r--eg/simplesect.c13
-rw-r--r--eg/surround.c6
-rw-r--r--eg/underscore.h21
-rw-r--r--eg/variable.c5
-rw-r--r--enum.c179
-rw-r--r--enum.h41
-rw-r--r--example.h18
-rw-r--r--fixexamp.in60
-rw-r--r--flatten.SH51
-rw-r--r--grammar.y947
-rw-r--r--html.c453
-rw-r--r--latex.c356
-rw-r--r--lex.l621
-rw-r--r--libc/COPYING339
-rw-r--r--libc/README.libc10
-rw-r--r--libc/alloca.c186
-rw-r--r--libc/getopt.c735
-rw-r--r--libc/getopt.h129
-rw-r--r--libc/getopt1.c176
-rw-r--r--manpage.c1347
-rw-r--r--manpage.h64
-rw-r--r--nroff.c424
-rw-r--r--output.h149
-rw-r--r--patchlevel.h2
-rw-r--r--semantic.c732
-rw-r--r--semantic.h121
-rw-r--r--strappend.c64
-rw-r--r--strappend.h6
-rw-r--r--strconcat.c74
-rw-r--r--strconcat.h6
-rw-r--r--string.c82
-rw-r--r--symbol.c119
-rw-r--r--symbol.h41
-rw-r--r--texinfo.c465
65 files changed, 17322 insertions, 0 deletions
diff --git a/C++autodoc b/C++autodoc
new file mode 100644
index 0000000..468f1dd
--- /dev/null
+++ b/C++autodoc
@@ -0,0 +1,292 @@
+From greyham Thu Oct 28 18:42:35 1993
+Newsgroups: comp.lang.c++,comp.programming.literate
+Subject: An Automatic C++ documentation compilation project.
+Summary: Anyone willing to add C++ support to c2man?
+Keywords: c2man, C, C++, Literate Programming, Documentation
+
+Copyright 1993, 1994 by Graham Stoney.
+This may be freely redistributed or quoted, so long as it's attributed to me.
+
+Writing and maintaining documentation has often been a thorn in the side of the
+Software Engineer and Programmer. After spending a great deal of time and
+effort writing documentation about a program or software system, the code
+invariably changes, quickly rendering the documentation out of date. The
+documentation becomes misleading, gets neglected, and quickly becomes useless.
+
+"Literate Programming" is one approach to solving this problem. It effectively
+introduces a whole new (typesetting) language, requires a quite radical shift
+on the part of the "non-literate" programmer and still requires a good deal of
+effort on the part of the programmer[1].
+
+I'd like to suggest a different approach which lies considerably closer to
+more traditional programming practices, and can offer quite immediate benefits
+when functional interface documentation is the main documentation required.
+
+The primary philosophy here is to use the programming language as far as
+possible to express the programmer's intentions, and to use comments only when
+the programming language is not sufficiently expressive. A comment can then
+become part of the language grammar which is recognised by a "documentation
+compiler". This tool parses a superset of the programming language and can
+automatically generate documentation in human-readable form by associating the
+programmer's comments with the objects in the code by their context.
+
+Whilst the idea of extracting documentation from comments in source code is by
+no means new, the difference here is that the comments actually form part of
+the grammar of the language recognised by the documentation compiler[2].
+
+Comments should not repeat information that is already represented in the
+program code; for instance, a comment describing a function argument should not
+repeat the name and type of that argument (since that information has already
+been included, for the compiler), but should appear near the argument.
+
+For example, in C, the programmer should write this:
+
+ /* include an example in the article */
+ enum Result example(int page /* page it appears on */);
+
+Rather than this:
+
+ /* include an example in the article
+ *
+ * PARAMETERS:
+ * int page page it appears on
+ *
+ * RETURNS:
+ * RESULT_YES The readers agreed
+ * RESULT_NO The readers disagreed
+ * RESULT_YOURE_JOKING The readers disagreed strongly
+ * RESULT_BLANK_LOOKS The readers didn't understand
+ */
+ enum Result example(int page);
+
+
+Also in this example, the documentation compiler knows the possible enumerated
+values that the function can return (as does the "real" compiler), so it is
+unnecessary for the programmer to restate them. The comments need simply be
+included in the definition for "enum Result" for the "RETURNS" information to
+be generated automatically:
+
+ enum Result {
+ RESULT_YES, /* The readers agreed */
+ RESULT_NO, /* The readers disagreed */
+ RESULT_YOURE_JOKING, /* The readers disagreed strongly */
+ RESULT_BLANK_LOOKS /* The readers didn't understand */
+ };
+
+Critics have suggested that the latter style in the example is easier to read
+for someone wishing to call the function in question. Of course, this is a
+style question which depends on each person's tastes; but the criticism is tied
+to the notion that the source code needs to look "beautiful" because it is the
+primary reference for someone wishing to use that function. This becomes much
+less significant once documentation is available which is known to _always_ be
+up to date. Of course, the latter style takes longer to write and maintain,
+and can become out of date should the name or type of the parameter be
+changed, yet the comment get neglected.
+
+I have implemented one such documentation compiler for the C language called
+"c2man", which is freely available[3]. The response from users has been
+extremely encouraging; I suspect this is partly because of the wide variety of
+styles of comment placement that are recognised: it often correctly recognises
+comments that weren't written with c2man in mind at all. While it's use is
+focused solely on functional interface documentation and it doesn't have
+anywhere near the power of a full Literate Programming system, the focus is on
+reducing the effort required by the programmer to the absolute minimum, and
+seeing how much documentation we can get essentially "for free".
+
+Many people have requested C++ support be added to c2man, and I suspect that
+this philosophy would be even more suitable and powerful for documenting
+interfaces to C++ classes automatically.
+
+Here is an example of how I envisage this philosophy would work when applied to
+C++. It's interesting to note that this code was written a couple of years ago
+exactly as you see it here, without the idea of generating documentation from
+it in mind at all:
+
+
+ // generic Timer class
+ class Timer
+ {
+ private:
+ static int numactive; // number of constructed timers.
+ static Timer *first; // first one in list.
+ Timer *next; // next one in linked list.
+ Time ticksdiff; // ticks we take to expire once at front.
+
+ enum
+ {
+ INACTIVE, // timer is not in chain.
+ STARTED, // one-shot
+ RUNNING // continuous.
+ } state;
+
+ // original interrupt vector value.
+ static void interrupt (far *old_vector)(...);
+
+ void (*timeout_function)(int); // function called when we time out
+ int timeout_parameter; // gets passed to timeout_function
+ Time duration; // timer length (ticks)
+
+ static void interrupt far tick(...); // clock tick routine.
+
+ void insert(); // add into active chain.
+ void remove(); // remove from active chain.
+ void set(Time milliseconds); // set duration from ms.
+
+ public:
+ // constructor
+ Timer(Time time=0, // milliseconds
+ void (*function)(int)=0, // called at timeout
+ int param=-1); // param for function
+
+ // destructor
+ ~Timer();
+
+ // start (or restart) a timer running.
+ void Start();
+ void Start(Time duration); // how long to run for
+
+ // start a timer running continuous.
+ void Run();
+
+ // stop a timer.
+ void Stop();
+
+ // is a timer active?
+ boolean Active() const { return state != INACTIVE; };
+ };
+
+
+Processing this class declaration could generate the following automatically:
+
+ NAME
+ Timer - generic timer class
+
+ SYNOPSIS
+ class Timer
+ {
+ public:
+ Timer(Time time=0,
+ void (*function)(int)=0,
+ int param=-1);
+ ~Timer();
+ void Start();
+ void Start(Time duration);
+ void Run();
+ void Stop();
+ boolean Active() const;
+ };
+
+ PARAMETERS
+ Time time
+ Milliseconds
+
+ void (*function)(int)
+ called at timeout.
+
+ int param
+ Param for function.
+
+ Time duration
+ How long to run for.
+
+ DESCRIPTION
+ Timer
+ Constructor
+
+ ~Timer
+ Destructor
+
+ Start
+ Start (or restart) a timer running.
+
+ Run
+ Start a timer running continuous.
+
+ Stop
+ Stop a timer.
+
+ Active
+ Is a timer active?.
+
+
+It should also be possible to extract this information from the implementation
+of the class (rather than the declaration), if that's where the user prefers to
+put the comments describing each member function and their parameters.
+
+The ideal tool should:
+1. Avoid imposing a style on the programmer.
+2. Work out section names (NAME, SYNOPSIS etc) without the programmer having
+ to specify them explicitly.
+3. Handle C++ and C style code equally well.
+4. Not require the programmer to restate information which is already expressed
+ in the syntax of the programming language.
+5. Work reasonably well with existing code.
+6. Flatten the class hierarchy so that the documentation for each class
+ includes virtually everything the user needs to know about it.
+
+A number of tools already exist which attempt to tackle this problem, such as
+class2man, genman, classdoc and docclass. They vary in sophistication,
+utility, and the demands they place on the programmer; however, none as yet
+meet all the criteria set out above, and no one tool will suit the tastes of
+all programmers.
+
+Pouring lots of effort into a really ``smart'' documentation generator makes
+sense because once it's done, you get a payback for every document you
+generate. Every little feature added to the documentation generator to make
+things easier for the programmer pays off multiple times, and minimising the
+effort required by the programmer is the key.
+
+The logical starting point would be to graft Jim Roskind's C++ grammar[4] into
+c2man, modifying it to recognise comments in the relevant places, and adding
+all the necessary structures to hold the information from the parser that will
+get included in the output. Very little functional change should be needed in
+the lexer, which already recognises C++ comments.
+
+Unfortunately, at present I do not have sufficient spare time to make the
+additions to c2man required to support C++. It would be a great contribution to
+the C++ community, not to mention the documentation time saved by themselves,
+for someone involved in C++ work to add this support and release the result[5].
+
+If you work with a team developing C++ code, please consider having one of your
+developers on a ``Usenet Sabbatical'' to extend this philosophy to C++, and
+start reaping the benefits in documentation time savings.
+
+It could also make an ideal Computer Science student compiler project.
+
+Please contact me via E-mail if you are interested in undertaking such a
+project.
+
+
+Graham Stoney
+greyham@research.canon.com.au
+
+Footnotes:
+1. Advocates of Literate Programming would argue that Literate Programming is
+ much more than snazzy documents and that it encourages this extra effort to
+ focus early on in the design of the software, which pays off later.
+
+2. To get a better idea, see the file grammar.y in the c2man distribution.
+
+3. c2man has been posted to comp.sources.misc. It should be available from:
+location: ftp from any comp.sources.misc archive, in volume42
+ (the version in the comp.sources.reviewed archive is obsolete)
+ ftp /pub/Unix/Util/c2man-2.0.*.tar.gz from dnpap.et.tudelft.nl
+ Australia: ftp /usenet/comp.sources.misc/volume42/c2man-2.0/*
+ from archie.au
+ N.America: ftp /usenet/comp.sources.misc/volume42/c2man-2.0/*
+ from ftp.wustl.edu
+ Europe: ftp /News/comp.sources.misc/volume42/c2man-2.0/*
+ from ftp.irisa.fr
+ Japan: ftp /pub/NetNews/comp.sources.misc/volume42/c2man-2.0/*
+ from ftp.iij.ad.jp
+ Patches: ftp pub/netnews/sources.bugs/volume93/sep/c2man* from lth.se
+
+4. Jim Roskind's yaccable C++ grammar is available via ftp from
+ ics.uci.edu in the ftp/pub directory as:
+
+ c++grammar2.0.tar.Z
+ byacc1.8.tar.Z
+
+5. c2man's copyright requires that all derivative works remain freely
+ available.
+
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..01fbeea
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,127 @@
+Version 1.1:
+ This was the first release, so there were no changes yet.
+
+Version 1.2:
+ The README in 1.1 incorrectly stated that c2man was public domain. It
+ is in fact copyright, but freely redistributable. See the updated
+ README for details.
+
+ You can use flex instead of lex now.
+
+ Comments on parameters in old-style function definitions work OK now.
+
+ Generates man pages for global variables (with -v) as well as
+ functions.
+
+ Major mods to parser to support comments at the end of lines; this
+ makes it much more tolerant about comment placement.
+
+ c2man will now parse its own source!. The manual pages it generates are
+ pretty bad since the comments haven't been strategically placed, but
+ it's better than you might expect without trying.
+
+ Rewrote a lot of the manual page to make it comprehensible.
+
+Version 1.3:
+ Ignores all comments in included files, except those in enum
+ specifications; this should virtually eliminate trouble with errors in
+ files you may have no control over, like system headers.
+
+ Add "-o -" functionality to write manual pages to stdout.
+
+ Run /lib/cpp when reading from stdin too.
+
+ Rewrite comment parsing to be neater & easier to modify.
+
+ Replace -DSYSV option with its inverse -DBSD so ANSI string functions
+ are used by default.
+
+ enum tag/description spacing in output varies automatically.
+
+ Sprinkle output heavily with Bold for troff.
+
+Version 1.4:
+ Recognise that an end-of-line comment after a function definition or
+ declaration applies to the last parameter of a function, so we handle:
+
+ /* try to do something that requires 2 parameters */
+ int try(int a, /* description of first parameter */
+ int b); /* description of second parameter */
+
+ Fix comment lexing problem that sometimes rejected the '# ...' lines
+ that cpp generates on the line immediately after a comment.
+
+ Don't capitalise n/troff dot commands.
+
+ make -V option act verbosely.
+
+ By popular demand, added -G option to group manual pages from the
+ same file together, ala ctype(3).
+
+ Output function prototype on a single line for all functions with one
+ or less parameters (ignoring -f...).
+
+Version 1.5:
+ Recognise end-of-line comments after K&R style function parameters.
+
+ Specify C-preprocessor command in Makefile and add -P option to specify
+ a different preprocessor at runtime.
+
+ Add -g option like -G, but read the terse description from the file.
+
+ Don't disable nroff line filling in SYNOPSIS section so very long lines
+ still get broken.
+
+ Require a white-space after a period before capitalising the next
+ letter. i.e. Don't damage "i.e.".
+
+Version 1.6:
+ Don't reduce pointer-to-pointers down to a single indirection level;
+ eg: "char **argv" got output as "char *argv". Ugh!.
+
+Version 1.7:
+ Don't try to free a string constant right at the very end!.
+
+ Rename old -i option to -H, and add new -i option so user can specify
+ extra #include lines for the SYNOPSIS section, and prerequisites for .h
+ file compilation.
+
+ Work around Sun acc -E problem where .h files were ignored.
+
+ Semantic change: multiple input files all get cross-referenced in the
+ SEE ALSO section (or grouped together if -g or -G).
+
+Version 1.8:
+ Add -lPW I'd dropped from HPUX configuration.
+
+ Fix multiple -i arguments appearing on the one line.
+
+Version 1.9:
+ Fix silly missing fprintf arguments in c2man.c
+
+ Ignore trailing spaces after a comment at the end of a line.
+
+ Don't error on "typedef int NewType; NewType a;"
+
+ -Ssection option added by jerry@kesa24.kesa.com (Jerry E. Dunmire).
+
+Version 1.10:
+ Accept comments around a final ellipsis parameter.
+
+ Make parameter declarations in the prototype and the PARAMETERS section
+ identical.
+
+Version 2.0:
+ Major modifications to use Configure for easy installation.
+
+ Many, many portability fixes; converted to K&R 1 C.
+
+ Accept stdin even if preprocessor doesn't.
+
+ Don't error on: int fred() {
+ } /* fred */
+
+ Allow extra manual page sections not recognized by c2man.
+
+From version 2.0 onwards, the change log for each patch is contained in the
+top of the patch itself. This file is no longer updated.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..0dc65b1
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,29 @@
+Wed Apr 24 12:08:09 EST 1996 Graham Stoney <greyham@research.canon.com.au>
+
+. Description:
+
+ -k doesn't take an option, reported by J.Thompson@swansea.ac.uk.
+
+ Add Marco Nijdam to the awards list.
+
+ Handle RETURNS comment next to declarator, from Marco Nijdam.
+ Also add an example of its usage in the eg directory.
+
+ Allow spaces in a section heading, from Marco Nijdam.
+
+ Make #include more flexible, from Steven E. Haehn.
+
+ Handle comments boxed with ---- and =====.
+
+ Update the README a bit.
+
+ Add ChangeLog file, to track changes.
+
+ Update my E-mail address.
+ The '.oz.au' in my address has now officially changed to '.com.au',
+ although the old address will continue to work indefinitely.
+
+ Fix a couple of minor manual page things.
+
+ Update the Free Compilers Catalog entry.
+
diff --git a/Configure b/Configure
new file mode 100755
index 0000000..87e16cd
--- /dev/null
+++ b/Configure
@@ -0,0 +1,4822 @@
+#! /bin/sh
+#
+# If these # comments don't work, trim them. Don't worry about any other
+# shell scripts, Configure will trim # comments from them for you.
+#
+# (If you are trying to port this package to a machine without sh,
+# I would suggest you have a look at the prototypical config_h.SH file
+# and edit it to reflect your system. Some packages may include samples
+# of config.h for certain machines, so you might look for one of those.)
+#
+# Yes, you may rip this off to use in other distribution packages. This
+# script belongs to the public domain and cannot be copyrighted.
+#
+# (Note: this Configure script was generated automatically. Rather than
+# working with this copy of Configure, you may wish to get metaconfig.
+# The dist-3.0 package (which contains metaconfig) was posted in
+# comp.sources.misc and is available on CPAN under authors/id/RAM so
+# you may fetch it yourself from your nearest archive site.)
+#
+
+# $Id: Configure,v 1.1 2004-05-03 05:17:48 behdad Exp $
+#
+# Generated on Thu Feb 19 19:32:00 CST 2004 [metaconfig 3.0 PL70]
+
+cat >/tmp/c1$$ <<EOF
+ARGGGHHHH!!!!!
+
+SCO csh still thinks true is false. Write to SCO today and tell them that next
+year Configure ought to "rm /bin/csh" unless they fix their blasted shell. :-)
+
+(Actually, Configure ought to just patch csh in place. Hmm. Hmmmmm. All
+we'd have to do is go in and swap the && and || tokens, wherever they are.)
+
+[End of diatribe. We now return you to your regularly scheduled programming...]
+EOF
+cat >/tmp/c2$$ <<EOF
+
+OOPS! You naughty creature! You didn't run Configure with sh!
+I will attempt to remedy the situation by running sh for you...
+EOF
+
+true || cat /tmp/c1$$ /tmp/c2$$
+true || exec sh $0 $argv:q
+
+(exit $?0) || cat /tmp/c2$$
+(exit $?0) || exec sh $0 $argv:q
+rm -f /tmp/c1$$ /tmp/c2$$
+
+: compute my invocation name
+me=$0
+case "$0" in
+*/*)
+ me=`echo $0 | sed -e 's!.*/\(.*\)!\1!' 2>/dev/null`
+ test "$me" || me=$0
+ ;;
+esac
+
+: Proper PATH separator
+p_=:
+: On OS/2 this directory should exist if this is not floppy only system :-]
+if test -d c:/.; then
+ p_=\;
+ PATH=`cmd /c "echo %PATH%" | tr '\\\\' / `
+ OS2_SHELL=`cmd /c "echo %OS2_SHELL%" | tr '\\\\' / | tr '[A-Z]' '[a-z]'`
+fi
+
+: Proper PATH setting
+paths='/bin /usr/bin /usr/local/bin /usr/ucb /usr/local /usr/lbin'
+paths="$paths /opt/bin /opt/local/bin /opt/local /opt/lbin"
+paths="$paths /usr/5bin /etc /usr/gnu/bin /usr/new /usr/new/bin /usr/nbin"
+paths="$paths /opt/gnu/bin /opt/new /opt/new/bin /opt/nbin"
+paths="$paths /sys5.3/bin /sys5.3/usr/bin /bsd4.3/bin /bsd4.3/usr/ucb"
+paths="$paths /bsd4.3/usr/bin /usr/bsd /bsd43/bin /usr/ccs/bin"
+paths="$paths /etc /usr/lib /usr/ucblib /lib /usr/ccs/lib"
+paths="$paths /sbin /usr/sbin /usr/libexec"
+
+for p in $paths
+do
+ case "$p_$PATH$p_" in
+ *$p_$p$p_*) ;;
+ *) test -d $p && PATH=$PATH$p_$p ;;
+ esac
+done
+
+PATH=.$p_$PATH
+export PATH
+
+: shall we be using ksh?
+inksh=''
+needksh=''
+avoidksh=''
+newsh=/bin/ksh
+changesh=''
+if (PATH=.; alias -x) >/dev/null 2>&1; then
+ inksh=true
+fi
+if test -f /hp-ux -a -f /bin/ksh; then
+ needksh='to avoid sh bug in "here document" expansion'
+fi
+if test -d /usr/lpp -a -f /usr/bin/bsh -a -f /usr/bin/uname; then
+ if test X`/usr/bin/uname -v` = X4; then
+ avoidksh="to avoid AIX 4's /bin/sh"
+ newsh=/usr/bin/bsh
+ fi
+fi
+case "$inksh/$needksh" in
+/[a-z]*)
+ unset ENV
+ changesh=true
+ reason="$needksh"
+ ;;
+esac
+case "$inksh/$avoidksh" in
+true/[a-z]*)
+ changesh=true
+ reason="$avoidksh"
+ ;;
+esac
+case "$inksh/$needksh-$avoidksh-" in
+true/--)
+ cat <<EOM
+(I see you are using the Korn shell. Some ksh's blow up on $me,
+mainly on older exotic systems. If yours does, try the Bourne shell instead.)
+EOM
+ ;;
+esac
+case "$changesh" in
+true)
+ echo "(Feeding myself to $newsh $reason.)"
+ case "$0" in
+ Configure|*/Configure) exec $newsh $0 "$@";;
+ *) exec $newsh Configure "$@";;
+ esac
+ ;;
+esac
+
+: Configure runs within the UU subdirectory
+test -d UU || mkdir UU
+unset CDPATH
+cd UU && rm -f ./*
+
+d_bsd=''
+d_eunice=''
+d_xenix=''
+eunicefix=''
+Mcc=''
+ar=''
+awk=''
+bash=''
+bison=''
+byacc=''
+cat=''
+chgrp=''
+chmod=''
+chown=''
+comm=''
+compress=''
+cp=''
+cpio=''
+cpp=''
+csh=''
+date=''
+echo=''
+egrep=''
+emacs=''
+expr=''
+find=''
+flex=''
+gcc=''
+grep=''
+gzip=''
+inews=''
+ksh=''
+less=''
+line=''
+lint=''
+ln=''
+lp=''
+lpr=''
+ls=''
+mail=''
+mailx=''
+make=''
+mkdir=''
+more=''
+mv=''
+nroff=''
+perl=''
+pg=''
+pmake=''
+pr=''
+rm=''
+rmail=''
+sed=''
+sendmail=''
+shar=''
+sleep=''
+smail=''
+sort=''
+submit=''
+tail=''
+tar=''
+tbl=''
+test=''
+touch=''
+tr=''
+troff=''
+uname=''
+uniq=''
+uuname=''
+vi=''
+zcat=''
+zip=''
+hint=''
+myuname=''
+osname=''
+osvers=''
+Author=''
+Date=''
+Header=''
+Id=''
+Locker=''
+Log=''
+RCSfile=''
+Revision=''
+Source=''
+State=''
+archobjs=''
+firstmakefile=''
+afs=''
+bin=''
+binexp=''
+installbin=''
+cc=''
+gccversion=''
+ccflags=''
+cppflags=''
+ldflags=''
+lkflags=''
+locincpth=''
+optimize=''
+cf_by=''
+cf_time=''
+contains=''
+cppfilecom=''
+cppstdinflags=''
+d_cppcanstdin=''
+d_cppignhdrs=''
+cpplast=''
+cppminus=''
+cpprun=''
+cppstdin=''
+d_access=''
+d_attribut=''
+d_const=''
+d_flexfnam=''
+d_gnulibc=''
+d_link=''
+d_open3=''
+d_portable=''
+d_index=''
+d_strchr=''
+d_strftime=''
+d_strstr=''
+d_symlink=''
+d_time=''
+timetype=''
+d_voidsig=''
+signal_t=''
+d_volatile=''
+h_fcntl=''
+h_sysfile=''
+i_fcntl=''
+i_stddef=''
+i_stdlib=''
+i_string=''
+strings=''
+i_sysfile=''
+i_systypes=''
+i_systime=''
+i_systimek=''
+i_time=''
+timeincl=''
+i_unistd=''
+i_stdarg=''
+i_varargs=''
+i_varhdr=''
+lex=''
+lexflags=''
+libc=''
+glibpth=''
+libpth=''
+loclibpth=''
+plibpth=''
+xlibpth=''
+libs=''
+libyacc=''
+lns=''
+installmansrc=''
+manext=''
+mansrc=''
+mansrcexp=''
+mkdep=''
+c=''
+n=''
+package=''
+spackage=''
+prefix=''
+prefixexp=''
+installprivlib=''
+privlib=''
+privlibexp=''
+prototype=''
+sh=''
+so=''
+sharpbang=''
+shsharp=''
+spitshell=''
+src=''
+startsh=''
+sysman=''
+nm_opt=''
+nm_so_opt=''
+runnm=''
+usenm=''
+incpath=''
+mips=''
+mips_type=''
+usrinc=''
+vaproto=''
+defvoidused=''
+voidflags=''
+warnflags=''
+yacc=''
+yaccflags=''
+CONFIG=''
+
+define='define'
+undef='undef'
+smallmach='pdp11 i8086 z8000 i80286 iAPX286'
+rmlist=''
+
+: We must find out about Eunice early
+eunicefix=':'
+if test -f /etc/unixtovms; then
+ eunicefix=/etc/unixtovms
+fi
+if test -f /etc/unixtovms.exe; then
+ eunicefix=/etc/unixtovms.exe
+fi
+
+: No trailing extension on UNIX executables
+_exe=''
+: Extra object files, if any, needed on this platform.
+archobjs=''
+gccversion=''
+: Possible local include directories to search.
+: Set locincpth to "" in a hint file to defeat local include searches.
+locincpth="/usr/local/include /opt/local/include /usr/gnu/include"
+locincpth="$locincpth /opt/gnu/include /usr/GNU/include /opt/GNU/include"
+:
+: no include file wanted by default
+inclwanted=''
+
+i_sysselct=''
+: change the next line if compiling for Xenix/286 on Xenix/386
+xlibpth='/usr/lib/386 /lib/386'
+
+: Possible local library directories to search.
+loclibpth="/usr/local/lib /opt/local/lib /usr/gnu/lib"
+loclibpth="$loclibpth /opt/gnu/lib /usr/GNU/lib /opt/GNU/lib"
+
+: general looking path for locating libraries
+glibpth="/shlib /usr/shlib /lib/pa1.1 /usr/lib/large"
+glibpth="$glibpth /lib /usr/lib $xlibpth"
+glibpth="$glibpth /lib/large /usr/lib/small /lib/small"
+glibpth="$glibpth /usr/ccs/lib /usr/ucblib /usr/local/lib"
+
+: Private path used by Configure to find libraries. Its value
+: is prepended to libpth. This variable takes care of special
+: machines, like the mips. Usually, it should be empty.
+plibpth=''
+
+: default library list
+libswanted=''
+large=''
+: full support for void wanted by default
+defvoidused=15
+
+
+: Find the basic shell for Bourne shell scripts
+case "$sh" in
+'')
+ case "$SYSTYPE" in
+ *bsd*|sys5*) xxx="/$SYSTYPE/bin/sh";;
+ *) xxx='/bin/sh';;
+ esac
+ if test -f "$xxx"; then
+ sh="$xxx"
+ else
+ : Build up a list and do a single loop so we can 'break' out.
+ pth=`echo $PATH | sed -e "s/$p_/ /g"`
+ for xxx in sh bash ksh pdksh ash; do
+ for p in $pth; do
+ try="$try ${p}/${xxx}"
+ done
+ done
+ for xxx in $try; do
+ if test -f "$xxx"; then
+ sh="$xxx";
+ break
+ elif test -f "$xxx.exe"; then
+ sh="$xxx";
+ break
+ fi
+ done
+ fi
+ ;;
+esac
+
+case "$sh" in
+'') cat <<EOM >&2
+$me: Fatal Error: I can't find a Bourne Shell anywhere.
+
+Usually it's in /bin/sh. How did you even get this far?
+Please contact me (Manoj Srivastava) at srivasta@debian.org and
+we'll try to straighten this all out.
+EOM
+ exit 1
+ ;;
+esac
+
+: see if sh knows # comments
+if `$sh -c '#' >/dev/null 2>&1`; then
+ shsharp=true
+ spitshell=cat
+ xcat=/bin/cat
+ test -f $xcat || xcat=/usr/bin/cat
+ echo "#!$xcat" >try
+ $eunicefix try
+ chmod +x try
+ ./try > today
+ if test -s today; then
+ sharpbang='#!'
+ else
+ echo "#! $xcat" > try
+ $eunicefix try
+ chmod +x try
+ ./try > today
+ if test -s today; then
+ sharpbang='#! '
+ else
+ sharpbang=': use '
+ fi
+ fi
+else
+ echo " "
+ echo "Your $sh doesn't grok # comments--I will strip them later on."
+ shsharp=false
+ cd ..
+ echo "exec grep -v '^[ ]*#'" >spitshell
+ chmod +x spitshell
+ $eunicefix spitshell
+ spitshell=`pwd`/spitshell
+ cd UU
+ echo "I presume that if # doesn't work, #! won't work either!"
+ sharpbang=': use '
+fi
+rm -f try today
+
+: figure out how to guarantee sh startup
+case "$startsh" in
+'') startsh=${sharpbang}${sh} ;;
+*)
+esac
+cat >try <<EOSS
+$startsh
+set abc
+test "$?abc" != 1
+EOSS
+
+chmod +x try
+$eunicefix try
+if ./try; then
+ : echo "Yup, it does."
+else
+ echo "Hmm... '$startsh' does not guarantee sh startup..."
+ echo "You may have to fix up the shell scripts to make sure $sh runs them."
+fi
+rm -f try
+
+: produce awk script to parse command line options
+cat >options.awk <<'EOF'
+BEGIN {
+ optstr = "dD:eEf:hKOrsSU:V"; # getopt-style specification
+
+ len = length(optstr);
+ for (i = 1; i <= len; i++) {
+ c = substr(optstr, i, 1);
+ if (i < len) a = substr(optstr, i + 1, 1); else a = "";
+ if (a == ":") {
+ arg[c] = 1;
+ i++;
+ }
+ opt[c] = 1;
+ }
+}
+{
+ expect = 0;
+ str = $0;
+ if (substr(str, 1, 1) != "-") {
+ printf("'%s'\n", str);
+ next;
+ }
+ len = length($0);
+ for (i = 2; i <= len; i++) {
+ c = substr(str, i, 1);
+ if (!opt[c]) {
+ printf("-%s\n", substr(str, i));
+ next;
+ }
+ printf("-%s\n", c);
+ if (arg[c]) {
+ if (i < len)
+ printf("'%s'\n", substr(str, i + 1));
+ else
+ expect = 1;
+ next;
+ }
+ }
+}
+END {
+ if (expect)
+ print "?";
+}
+EOF
+
+: process the command line options
+set X `for arg in "$@"; do echo "X$arg"; done |
+ sed -e s/X// | awk -f options.awk`
+eval "set $*"
+shift
+rm -f options.awk
+
+: set up default values
+fastread=''
+reuseval=false
+config_sh=''
+alldone=''
+error=''
+silent=''
+extractsh=''
+override=''
+knowitall=''
+rm -f optdef.sh
+cat >optdef.sh <<EOS
+$startsh
+EOS
+
+
+: option parsing
+while test $# -gt 0; do
+ case "$1" in
+ -d) shift; fastread=yes;;
+ -e) shift; alldone=cont;;
+ -f)
+ shift
+ cd ..
+ if test -r "$1"; then
+ config_sh="$1"
+ else
+ echo "$me: cannot read config file $1." >&2
+ error=true
+ fi
+ cd UU
+ shift;;
+ -h) shift; error=true;;
+ -r) shift; reuseval=true;;
+ -s) shift; silent=true; realsilent=true;;
+ -E) shift; alldone=exit;;
+ -K) shift; knowitall=true;;
+ -O) shift; override=true;;
+ -S) shift; silent=true; extractsh=true;;
+ -D)
+ shift
+ case "$1" in
+ *=)
+ echo "$me: use '-U symbol=', not '-D symbol='." >&2
+ echo "$me: ignoring -D $1" >&2
+ ;;
+ *=*) echo "$1" | \
+ sed -e "s/'/'\"'\"'/g" -e "s/=\(.*\)/='\1'/" >> optdef.sh;;
+ *) echo "$1='define'" >> optdef.sh;;
+ esac
+ shift
+ ;;
+ -U)
+ shift
+ case "$1" in
+ *=) echo "$1" >> optdef.sh;;
+ *=*)
+ echo "$me: use '-D symbol=val', not '-U symbol=val'." >&2
+ echo "$me: ignoring -U $1" >&2
+ ;;
+ *) echo "$1='undef'" >> optdef.sh;;
+ esac
+ shift
+ ;;
+ -V) echo "$me generated by metaconfig 3.0 PL70." >&2
+ exit 0;;
+ --) break;;
+ -*) echo "$me: unknown option $1" >&2; shift; error=true;;
+ *) break;;
+ esac
+done
+
+case "$error" in
+true)
+ cat >&2 <<EOM
+Usage: $me [-dehrsEKOSV] [-f config.sh] [-D symbol] [-D symbol=value]
+ [-U symbol] [-U symbol=]
+ -d : use defaults for all answers.
+ -e : go on without questioning past the production of config.sh.
+ -f : specify an alternate default configuration file.
+ -h : print this help message and exit (with an error status).
+ -r : reuse C symbols value if possible (skips costly nm extraction).
+ -s : silent mode, only echoes questions and essential information.
+ -D : define symbol to have some value:
+ -D symbol symbol gets the value 'define'
+ -D symbol=value symbol gets the value 'value'
+ -E : stop at the end of questions, after having produced config.sh.
+ -K : do not use unless you know what you are doing.
+ -O : let -D and -U override definitions from loaded configuration file.
+ -S : perform variable substitutions on all .SH files (can mix with -f)
+ -U : undefine symbol:
+ -U symbol symbol gets the value 'undef'
+ -U symbol= symbol gets completely empty
+ -V : print version number and exit (with a zero status).
+EOM
+ exit 1
+ ;;
+esac
+
+: Sanity checks
+case "$fastread$alldone" in
+yescont|yesexit) ;;
+*)
+ if test ! -t 0; then
+ echo "Say 'sh Configure', not 'sh <Configure'"
+ exit 1
+ fi
+ ;;
+esac
+
+exec 4>&1
+case "$silent" in
+true) exec 1>/dev/null;;
+esac
+
+: run the defines and the undefines, if any, but leave the file out there...
+touch optdef.sh
+. ./optdef.sh
+
+: set package name
+package=c2man
+first=`echo $package | sed -e 's/^\(.\).*/\1/'`
+last=`echo $package | sed -e 's/^.\(.*\)/\1/'`
+case "`echo AbyZ | tr '[:lower:]' '[:upper:]' 2>/dev/null`" in
+ABYZ) spackage=`echo $first | tr '[:lower:]' '[:upper:]'`$last;;
+*) spackage=`echo $first | tr '[a-z]' '[A-Z]'`$last;;
+esac
+
+: Some greps do not return status, grrr.
+echo "grimblepritz" >grimble
+if grep blurfldyick grimble >/dev/null 2>&1 ; then
+ contains=contains
+elif grep grimblepritz grimble >/dev/null 2>&1 ; then
+ contains=grep
+else
+ contains=contains
+fi
+rm -f grimble
+: the following should work in any shell
+case "$contains" in
+contains*)
+ echo " "
+ echo "AGH! Grep doesn't return a status. Attempting remedial action."
+ cat >contains <<'EOSS'
+grep "$1" "$2" >.greptmp && cat .greptmp && test -s .greptmp
+EOSS
+chmod +x contains
+esac
+
+: first determine how to suppress newline on echo command
+echo " "
+echo "Checking echo to see how to suppress newlines..."
+(echo "hi there\c" ; echo " ") >.echotmp
+if $contains c .echotmp >/dev/null 2>&1 ; then
+ echo "...using -n."
+ n='-n'
+ c=''
+else
+ cat <<'EOM'
+...using \c
+EOM
+ n=''
+ c='\c'
+fi
+echo $n "The star should be here-->$c"
+echo '*'
+rm -f .echotmp
+
+: compute the number of columns on the terminal for proper question formatting
+case "$COLUMNS" in
+'') COLUMNS='80';;
+esac
+
+: set up the echo used in my read
+myecho="case \"\$xxxm\" in
+'') echo $n \"\$rp $c\" >&4;;
+*) case \"\$rp\" in
+ '') echo $n \"[\$xxxm] $c\";;
+ *)
+ if test \`echo \"\$rp [\$xxxm] \" | wc -c\` -ge $COLUMNS; then
+ echo \"\$rp\" >&4
+ echo $n \"[\$xxxm] $c\" >&4
+ else
+ echo $n \"\$rp [\$xxxm] $c\" >&4
+ fi
+ ;;
+ esac;;
+esac"
+
+: now set up to do reads with possible shell escape and default assignment
+cat <<EOSC >myread
+$startsh
+xxxm=\$dflt
+$myecho
+ans='!'
+case "\$fastread" in
+yes) case "\$dflt" in
+ '') ;;
+ *) ans='';
+ case "\$silent-\$rp" in
+ true-) ;;
+ *) echo " " >&4;;
+ esac;;
+ esac;;
+*) case "\$silent" in
+ true) case "\$rp" in
+ '') ans='';;
+ esac;;
+ esac;;
+esac
+while expr "X\$ans" : "X!" >/dev/null; do
+ read answ
+ set x \$xxxm
+ shift
+ aok=''; eval "ans=\\"\$answ\\"" && aok=y
+ case "\$answ" in
+ "!")
+ sh 1>&4
+ echo " "
+ $myecho
+ ;;
+ !*)
+ set x \`expr "X\$ans" : "X!\(.*\)\$"\`
+ shift
+ sh 1>&4 -c "\$*"
+ echo " "
+ $myecho
+ ;;
+ "\$ans")
+ case "\$ans" in
+ \\&*)
+ set x \`expr "X\$ans" : "X&\(.*\)\$"\`
+ shift
+ case "\$1" in
+ -d)
+ fastread=yes
+ echo "(OK, I'll run with -d after this question.)" >&4
+ ;;
+ -*)
+ echo "*** Sorry, \$1 not supported yet." >&4
+ ;;
+ esac
+ $myecho
+ ans=!
+ ;;
+ esac;;
+ *)
+ case "\$aok" in
+ y)
+ echo "*** Substitution done -- please confirm."
+ xxxm="\$ans"
+ ans=\`echo $n "\$ans$c" | tr '\012' ' '\`
+ xxxm="\$ans"
+ ans=!
+ ;;
+ *)
+ echo "*** Error -- try again."
+ ans=!
+ ;;
+ esac
+ $myecho
+ ;;
+ esac
+ case "\$ans\$xxxm\$nostick" in
+ '')
+ ans=!
+ $myecho
+ ;;
+ esac
+done
+case "\$ans" in
+'') ans="\$xxxm";;
+esac
+EOSC
+
+: Find the path to the source tree
+case "$src" in
+'') src=`echo $0 | sed -e 's%/[^/][^/]*$%%'`;;
+esac
+case "$src" in
+'')
+ src=.
+ rsrc=..
+ ;;
+/*) rsrc="$src/..";;
+*) rsrc="../$src";;
+esac
+if test -f $rsrc/Configure && \
+ $contains "^package=$package" $rsrc/Configure >/dev/null 2>&1
+then
+ : found it, so we are ok.
+else
+ rsrc=''
+ for src in . .. ../.. ../../.. ../../../..; do
+ if test -f ../$src/Configure && \
+ $contains "^package=$package" ../$src/Configure >/dev/null 2>&1
+ then
+ rsrc=../$src
+ break
+ fi
+ done
+fi
+case "$rsrc" in
+'')
+ echo " "
+ dflt=
+ rp="Directory where sources for $package are located?"
+ . ./myread
+ src="$ans"
+ rsrc="$src"
+ if test -f $rsrc/Configure && \
+ $contains "^package=$package" $rsrc/Configure >/dev/null 2>&1
+ then
+ echo "Ok, I've found them under $src"
+ else
+ echo "Sorry, I can't seem to be able to locate $package sources." >&4
+ exit 1
+ fi
+ ;;
+../.) ;;
+*)
+ echo " "
+ echo "Sources for $package found in $src" >&4
+ ;;
+esac
+
+: script used to extract .SH files with variable substitutions
+cat >extract <<'EOS'
+CONFIG=true
+echo "Doing variable substitutions on .SH files..."
+if test -f $src/MANIFEST; then
+ set x `awk '{print $1}' <$src/MANIFEST | grep '\.SH'`
+else
+ echo "(Looking for .SH files under the source directory.)"
+ set x `(cd $src; find . -name "*.SH" -print)`
+fi
+shift
+case $# in
+0) set x `(cd $src; echo *.SH)`; shift;;
+esac
+if test ! -f $src/$1; then
+ shift
+fi
+mkdir_p='
+name=$1;
+create="";
+while test $name; do
+ if test ! -d "$name"; then
+ create="$name $create";
+ name=`echo $name | sed -e "s|^[^/]*$||"`;
+ name=`echo $name | sed -e "s|\(.*\)/.*|\1|"`;
+ else
+ name="";
+ fi;
+done;
+for file in $create; do
+ mkdir $file;
+done
+'
+for file in $*; do
+ case "$src" in
+ ".")
+ case "$file" in
+ */*)
+ dir=`expr X$file : 'X\(.*\)/'`
+ file=`expr X$file : 'X.*/\(.*\)'`
+ (cd $dir && . ./$file)
+ ;;
+ *)
+ . ./$file
+ ;;
+ esac
+ ;;
+ *)
+ case "$file" in
+ */*)
+ dir=`expr X$file : 'X\(.*\)/'`
+ file=`expr X$file : 'X.*/\(.*\)'`
+ (set x $dir; shift; eval $mkdir_p)
+ sh <$src/$dir/$file
+ ;;
+ *)
+ sh <$src/$file
+ ;;
+ esac
+ ;;
+ esac
+done
+if test -f $src/config_h.SH; then
+ if test ! -f config.h; then
+ : oops, they left it out of MANIFEST, probably, so do it anyway.
+ . $src/config_h.SH
+ fi
+fi
+EOS
+
+: extract files and exit if asked to do so
+case "$extractsh" in
+true)
+ case "$realsilent" in
+ true) ;;
+ *) exec 1>&4;;
+ esac
+ case "$config_sh" in
+ '') config_sh='config.sh'; config="$rsrc/config.sh";;
+ /*) config="$config_sh";;
+ *) config="$rsrc/$config_sh";;
+ esac
+ echo " "
+ echo "Fetching answers from $config_sh..."
+ . $config
+ test "$override" && . ./optdef.sh
+ echo " "
+ cd ..
+ . UU/extract
+ rm -rf UU
+ echo "Done."
+ exit 0
+ ;;
+esac
+
+: Eunice requires " " instead of "", can you believe it
+echo " "
+: Here we go...
+echo "Beginning of configuration questions for $package."
+
+trap 'echo " "; test -d ../UU && rm -rf X $rmlist; exit 1' 1 2 3 15
+
+: Now test for existence of everything in MANIFEST
+echo " "
+if test -f $rsrc/MANIFEST; then
+ echo "First let's make sure your kit is complete. Checking..." >&4
+ awk '$1 !~ /PACK[A-Z]+/ {print $1}' $rsrc/MANIFEST | split -l -50
+ rm -f missing
+ tmppwd=`pwd`
+ for filelist in x??; do
+ (cd $rsrc; ls `cat $tmppwd/$filelist` >/dev/null 2>>$tmppwd/missing)
+ done
+ if test -s missing; then
+ cat missing >&4
+ cat >&4 <<'EOM'
+
+THIS PACKAGE SEEMS TO BE INCOMPLETE.
+
+You have the option of continuing the configuration process, despite the
+distinct possibility that your kit is damaged, by typing 'y'es. If you
+do, don't blame me if something goes wrong. I advise you to type 'n'o
+and contact the author (srivasta@debian.org).
+
+EOM
+ echo $n "Continue? [n] $c" >&4
+ read ans
+ case "$ans" in
+ y*)
+ echo "Continuing..." >&4
+ rm -f missing
+ ;;
+ *)
+ echo "ABORTING..." >&4
+ kill $$
+ ;;
+ esac
+ else
+ echo "Looks good..."
+ fi
+else
+ echo "There is no MANIFEST file. I hope your kit is complete !"
+fi
+rm -f missing x??
+
+: create .config dir to save info across Configure sessions
+test -d ../.config || mkdir ../.config
+cat >../.config/README <<EOF
+This directory created by Configure to save information that should
+persist across sessions for $package.
+
+You may safely delete it if you wish.
+EOF
+
+: general instructions
+needman=true
+firsttime=true
+user=`(logname) 2>/dev/null`
+case "$user" in
+'') user=`whoami 2>&1`;;
+esac
+if $contains "^$user\$" ../.config/instruct >/dev/null 2>&1; then
+ firsttime=false
+ echo " "
+ rp='Would you like to see the instructions?'
+ dflt=n
+ . ./myread
+ case "$ans" in
+ [yY]*) ;;
+ *) needman=false;;
+ esac
+fi
+if $needman; then
+ cat <<EOH
+
+This installation shell script will examine your system and ask you questions
+to determine how the c2man package should be installed. If you get
+stuck on a question, you may use a ! shell escape to start a subshell or
+execute a command. Many of the questions will have default answers in square
+brackets; typing carriage return will give you the default.
+
+On some of the questions which ask for file or directory names you are allowed
+to use the ~name construct to specify the login directory belonging to "name",
+even if you don't have a shell which knows about that. Questions where this is
+allowed will be marked "(~name ok)".
+
+EOH
+ rp=''
+ dflt='Type carriage return to continue'
+ . ./myread
+ cat <<'EOH'
+
+The prompter used in this script allows you to use shell variables and
+backticks in your answers. You may use $1, $2, etc... to refer to the words
+in the default answer, as if the default line was a set of arguments given to a
+script shell. This means you may also use $* to repeat the whole default line,
+so you do not have to re-type everything to add something to the default.
+
+Everytime there is a substitution, you will have to confirm. If there is an
+error (e.g. an unmatched backtick), the default answer will remain unchanged
+and you will be prompted again.
+
+If you are in a hurry, you may run 'Configure -d'. This will bypass nearly all
+the questions and use the computed defaults (or the previous answers if there
+was already a config.sh file). Type 'Configure -h' for a list of options.
+You may also start interactively and then answer '& -d' at any prompt to turn
+on the non-interactive behaviour for the remaining of the execution.
+
+EOH
+ . ./myread
+ cat <<EOH
+
+Much effort has been expended to ensure that this shell script will run on any
+Unix system. If despite that it blows up on yours, your best bet is to edit
+Configure and run it again. If you can't run Configure for some reason,
+you'll have to generate a config.sh file by hand. Whatever problems you
+have, let me (srivasta@debian.org) know how I blew it.
+
+This installation script affects things in two ways:
+
+1) it may do direct variable substitutions on some of the files included
+ in this kit.
+2) it builds a config.h file for inclusion in C programs. You may edit
+ any of these files as the need arises after running this script.
+
+If you make a mistake on a question, there is no easy way to back up to it
+currently. The easiest thing to do is to edit config.sh and rerun all the SH
+files. Configure will offer to let you do this before it runs the SH files.
+
+EOH
+ dflt='Type carriage return to continue'
+ . ./myread
+ case "$firsttime" in
+ true) echo $user >>../.config/instruct;;
+ esac
+fi
+
+: find out where common programs are
+echo " "
+echo "Locating common programs..." >&4
+cat <<EOSC >loc
+$startsh
+case \$# in
+0) exit 1;;
+esac
+thing=\$1
+shift
+dflt=\$1
+shift
+for dir in \$*; do
+ case "\$thing" in
+ .)
+ if test -d \$dir/\$thing; then
+ echo \$dir
+ exit 0
+ fi
+ ;;
+ *)
+ for thisthing in \$dir/\$thing; do
+ : just loop through to pick last item
+ done
+ if test -f \$thisthing; then
+ echo \$thisthing
+ exit 0
+ elif test -f \$dir/\$thing.exe; then
+ : on Eunice apparently
+ echo \$dir/\$thing
+ exit 0
+ fi
+ ;;
+ esac
+done
+echo \$dflt
+exit 1
+EOSC
+chmod +x loc
+$eunicefix loc
+loclist="
+awk
+cat
+cp
+echo
+expr
+grep
+mv
+rm
+sed
+sort
+touch
+tr
+uniq
+"
+trylist="
+Mcc
+bison
+byacc
+cpp
+date
+flex
+ln
+nroff
+test
+uname
+"
+pth=`echo $PATH | sed -e "s/$p_/ /g"`
+pth="$pth /lib /usr/lib"
+for file in $loclist; do
+ eval xxx=\$$file
+ case "$xxx" in
+ /*|?:[\\/]*)
+ if test -f "$xxx"; then
+ : ok
+ else
+ echo "WARNING: no $xxx -- ignoring your setting for $file." >&4
+ xxx=`./loc $file $file $pth`
+ fi
+ ;;
+ '') xxx=`./loc $file $file $pth`;;
+ *) xxx=`./loc $xxx $xxx $pth`;;
+ esac
+ eval $file=$xxx
+ eval _$file=$xxx
+ case "$xxx" in
+ /*)
+ echo $file is in $xxx.
+ ;;
+ ?:[\\/]*)
+ echo $file is in $xxx.
+ ;;
+ *)
+ echo "I don't know where '$file' is, and my life depends on it." >&4
+ echo "Go find a public domain implementation or fix your PATH setting!" >&4
+ exit 1
+ ;;
+ esac
+done
+echo " "
+echo "Don't worry if any of the following aren't found..."
+say=offhand
+for file in $trylist; do
+ eval xxx=\$$file
+ case "$xxx" in
+ /*|?:[\\/]*)
+ if test -f "$xxx"; then
+ : ok
+ else
+ echo "WARNING: no $xxx -- ignoring your setting for $file." >&4
+ xxx=`./loc $file $file $pth`
+ fi
+ ;;
+ '') xxx=`./loc $file $file $pth`;;
+ *) xxx=`./loc $xxx $xxx $pth`;;
+ esac
+ eval $file=$xxx
+ eval _$file=$xxx
+ case "$xxx" in
+ /*)
+ echo $file is in $xxx.
+ ;;
+ ?:[\\/]*)
+ echo $file is in $xxx.
+ ;;
+ *)
+ echo "I don't see $file out there, $say."
+ say=either
+ ;;
+ esac
+done
+case "$egrep" in
+egrep)
+ echo "Substituting grep for egrep."
+ egrep=$grep
+ ;;
+esac
+case "$ln" in
+ln)
+ echo "Substituting cp for ln."
+ ln=$cp
+ ;;
+esac
+case "$test" in
+test)
+ echo "Hopefully test is built into your sh."
+ ;;
+*)
+ if `sh -c "PATH= test true" >/dev/null 2>&1`; then
+ echo "Using the test built into your sh."
+ test=test
+ _test=test
+ fi
+ ;;
+esac
+case "$echo" in
+echo)
+ echo "Hopefully echo is built into your sh."
+ ;;
+'') ;;
+*)
+ echo " "
+echo "Checking compatibility between $echo and builtin echo (if any)..." >&4
+ $echo $n "hi there$c" >foo1
+ echo $n "hi there$c" >foo2
+ if cmp foo1 foo2 >/dev/null 2>&1; then
+ echo "They are compatible. In fact, they may be identical."
+ else
+ case "$n" in
+ '-n') n='' c='\c';;
+ *) n='-n' c='';;
+ esac
+ cat <<FOO
+They are not compatible! You are probably running ksh on a non-USG system.
+I'll have to use $echo instead of the builtin, since Bourne shell doesn't
+have echo built in and we may have to run some Bourne shell scripts. That
+means I'll have to use '$n$c' to suppress newlines now. Life is ridiculous.
+
+FOO
+ $echo $n "The star should be here-->$c"
+ $echo "*"
+ fi
+ $rm -f foo1 foo2
+ ;;
+esac
+
+: determine whether symbolic links are supported
+echo " "
+$touch blurfl
+if $ln -s blurfl sym > /dev/null 2>&1 ; then
+ echo "Symbolic links are supported." >&4
+ lns="$ln -s"
+else
+ echo "Symbolic links are NOT supported." >&4
+ lns="$ln"
+fi
+$rm -f blurfl sym
+
+: see whether [:lower:] and [:upper:] are supported character classes
+echo " "
+up='[A-Z]'
+low='[a-z]'
+case "`echo AbyZ | $tr '[:lower:]' '[:upper:]' 2>/dev/null`" in
+ABYZ)
+ echo "Good, your tr supports [:lower:] and [:upper:] to convert case." >&4
+ up='[:upper:]'
+ low='[:lower:]'
+ ;;
+*)
+ echo "Your tr only supports [a-z] and [A-Z] to convert case." >&4
+ ;;
+esac
+: set up the translation script tr, must be called with ./tr of course
+cat >tr <<EOSC
+$startsh
+case "\$1\$2" in
+'[A-Z][a-z]') exec $tr '$up' '$low';;
+'[a-z][A-Z]') exec $tr '$low' '$up';;
+esac
+exec $tr "\$@"
+EOSC
+chmod +x tr
+$eunicefix tr
+
+: Try to determine whether config.sh was made on this system
+case "$config_sh" in
+'')
+myuname=`( ($uname -a) 2>/dev/null || hostname) 2>&1`
+myuname=`echo $myuname | $sed -e 's/^[^=]*=//' -e 's/\///g' | \
+ ./tr '[A-Z]' '[a-z]' | tr '\012' ' '`
+newmyuname="$myuname"
+dflt=n
+case "$knowitall" in
+'')
+ if test -f ../config.sh; then
+ if $contains myuname= ../config.sh >/dev/null 2>&1; then
+ eval "`grep myuname= ../config.sh`"
+ fi
+ if test "X$myuname" = "X$newmyuname"; then
+ dflt=y
+ fi
+ fi
+ ;;
+*) dflt=y;;
+esac
+
+: Get old answers, if there is a config file out there
+hint=default
+hintfile=''
+if test -f ../config.sh; then
+ echo " "
+ rp="I see a config.sh file. Shall I use it to set the defaults?"
+ . ./myread
+ case "$ans" in
+ n*|N*) echo "OK, I'll ignore it.";;
+ *) echo "Fetching default answers from your old config.sh file..." >&4
+ tmp_n="$n"
+ tmp_c="$c"
+ . ../config.sh
+ cp ../config.sh .
+ n="$tmp_n"
+ c="$tmp_c"
+ hint=previous
+ ;;
+ esac
+fi
+;;
+*)
+ echo " "
+ echo "Fetching default answers from $config_sh..." >&4
+ tmp_n="$n"
+ tmp_c="$c"
+ cd ..
+ cp $config_sh config.sh 2>/dev/null
+ chmod +w config.sh
+ . ./config.sh
+ cd UU
+ cp ../config.sh .
+ n="$tmp_n"
+ c="$tmp_c"
+ hint=previous
+ ;;
+esac
+test "$override" && . ./optdef.sh
+myuname="$newmyuname"
+
+: Restore computed paths
+for file in $loclist $trylist; do
+ eval $file="\$_$file"
+done
+
+: who configured the system
+cf_time=`$date 2>&1`
+cf_by=`(logname) 2>/dev/null`
+case "$cf_by" in
+"")
+ cf_by=`(whoami) 2>/dev/null`
+ case "$cf_by" in
+ "") cf_by=unknown ;;
+ esac ;;
+esac
+
+: decide how portable to be
+case "$d_portable" in
+"$define") dflt=y;;
+*) dflt=n;;
+esac
+$cat <<'EOH'
+
+I can set things up so that your shell scripts and binaries are more portable,
+at what may be a noticable cost in performance. In particular, if you
+ask to be portable, the following happens:
+
+ 1) Shell scripts will rely on the PATH variable rather than using
+ the paths derived above.
+ 2) ~username interpretations will be done at run time rather than
+ by Configure.
+
+EOH
+rp="Do you expect to run these scripts and binaries on multiple machines?"
+. ./myread
+case "$ans" in
+ y*) d_portable="$define"
+ ;;
+ *) d_portable="$undef" ;;
+esac
+
+: set up shell script to do ~ expansion
+cat >filexp <<EOSS
+$startsh
+: expand filename
+case "\$1" in
+ ~/*|~)
+ echo \$1 | $sed "s|~|\${HOME-\$LOGDIR}|"
+ ;;
+ ~*)
+ if $test -f /bin/csh; then
+ /bin/csh -f -c "glob \$1"
+ failed=\$?
+ echo ""
+ exit \$failed
+ else
+ name=\`$expr x\$1 : '..\([^/]*\)'\`
+ dir=\`$sed -n -e "/^\${name}:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\).*"'\$'"/\1/" -e p -e q -e '}' </etc/passwd\`
+ if $test ! -d "\$dir"; then
+ me=\`basename \$0\`
+ echo "\$me: can't locate home directory for: \$name" >&2
+ exit 1
+ fi
+ case "\$1" in
+ */*)
+ echo \$dir/\`$expr x\$1 : '..[^/]*/\(.*\)'\`
+ ;;
+ *)
+ echo \$dir
+ ;;
+ esac
+ fi
+ ;;
+*)
+ echo \$1
+ ;;
+esac
+EOSS
+chmod +x filexp
+$eunicefix filexp
+
+: now set up to get a file name
+cat <<EOS >getfile
+$startsh
+EOS
+cat <<'EOSC' >>getfile
+tilde=''
+fullpath=''
+already=''
+skip=''
+none_ok=''
+exp_file=''
+nopath_ok=''
+orig_rp="$rp"
+orig_dflt="$dflt"
+
+case "$fn" in
+*\(*)
+ expr $fn : '.*(\(.*\)).*' | tr ',' '\012' >getfile.ok
+ fn=`echo $fn | sed 's/(.*)//'`
+ ;;
+esac
+
+case "$fn" in
+*:*)
+ loc_file=`expr $fn : '.*:\(.*\)'`
+ fn=`expr $fn : '\(.*\):.*'`
+ ;;
+esac
+
+case "$fn" in
+*~*) tilde=true;;
+esac
+case "$fn" in
+*/*) fullpath=true;;
+esac
+case "$fn" in
+*+*) skip=true;;
+esac
+case "$fn" in
+*n*) none_ok=true;;
+esac
+case "$fn" in
+*e*) exp_file=true;;
+esac
+case "$fn" in
+*p*) nopath_ok=true;;
+esac
+
+case "$fn" in
+*f*) type='File';;
+*d*) type='Directory';;
+*l*) type='Locate';;
+esac
+
+what="$type"
+case "$what" in
+Locate) what='File';;
+esac
+
+case "$exp_file" in
+'')
+ case "$d_portable" in
+ "$define") ;;
+ *) exp_file=true;;
+ esac
+ ;;
+esac
+
+cd ..
+while test "$type"; do
+ redo=''
+ rp="$orig_rp"
+ dflt="$orig_dflt"
+ case "$tilde" in
+ true) rp="$rp (~name ok)";;
+ esac
+ . UU/myread
+ if test -f UU/getfile.ok && \
+ $contains "^$ans\$" UU/getfile.ok >/dev/null 2>&1
+ then
+ value="$ans"
+ ansexp="$ans"
+ break
+ fi
+ case "$ans" in
+ none)
+ value=''
+ ansexp=''
+ case "$none_ok" in
+ true) type='';;
+ esac
+ ;;
+ *)
+ case "$tilde" in
+ '') value="$ans"
+ ansexp="$ans";;
+ *)
+ value=`UU/filexp $ans`
+ case $? in
+ 0)
+ if test "$ans" != "$value"; then
+ echo "(That expands to $value on this system.)"
+ fi
+ ;;
+ *) value="$ans";;
+ esac
+ ansexp="$value"
+ case "$exp_file" in
+ '') value="$ans";;
+ esac
+ ;;
+ esac
+ case "$fullpath" in
+ true)
+ case "$ansexp" in
+ /*) value="$ansexp" ;;
+ *)
+ redo=true
+ case "$already" in
+ true)
+ echo "I shall only accept a full path name, as in /bin/ls." >&4
+ echo "Use a ! shell escape if you wish to check pathnames." >&4
+ ;;
+ *)
+ echo "Please give a full path name, starting with slash." >&4
+ case "$tilde" in
+ true)
+ echo "Note that using ~name is ok provided it expands well." >&4
+ already=true
+ ;;
+ esac
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ case "$redo" in
+ '')
+ case "$type" in
+ File)
+ if test -f "$ansexp"; then
+ type=''
+ elif test -r "$ansexp" || (test -h "$ansexp") >/dev/null 2>&1
+ then
+ echo "($value is not a plain file, but that's ok.)"
+ type=''
+ fi
+ ;;
+ Directory)
+ if test -d "$ansexp"; then
+ type=''
+ fi
+ ;;
+ Locate)
+ if test -d "$ansexp"; then
+ echo "(Looking for $loc_file in directory $value.)"
+ value="$value/$loc_file"
+ ansexp="$ansexp/$loc_file"
+ fi
+ if test -f "$ansexp"; then
+ type=''
+ fi
+ case "$nopath_ok" in
+ true) case "$value" in
+ */*) ;;
+ *) echo "Assuming $value will be in people's path."
+ type=''
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+
+ case "$skip" in
+ true) type='';
+ esac
+
+ case "$type" in
+ '') ;;
+ *)
+ if test "$fastread" = yes; then
+ dflt=y
+ else
+ dflt=n
+ fi
+ rp="$what $value doesn't exist. Use that name anyway?"
+ . UU/myread
+ dflt=''
+ case "$ans" in
+ y*) type='';;
+ *) echo " ";;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+done
+cd UU
+ans="$value"
+rp="$orig_rp"
+dflt="$orig_dflt"
+rm -f getfile.ok
+EOSC
+
+: determine root of directory hierarchy where package will be installed.
+case "$prefix" in
+'')
+ dflt=`./loc . /usr/local /usr/local /local /opt /usr`
+ ;;
+*)
+ dflt="$prefix"
+ ;;
+esac
+$cat <<EOM
+
+By default, $package will be installed in $dflt/bin, manual
+pages under $dflt/man, etc..., i.e. with $dflt as prefix for
+all installation directories. Typically set to /usr/local, but you
+may choose /usr if you wish to install $package among your system
+binaries. If you wish to have binaries under /bin but manual pages
+under /usr/local/man, that's ok: you will be prompted separately
+for each of the installation directories, the prefix being only used
+to set the defaults.
+
+EOM
+fn=d~
+rp='Installation prefix to use?'
+. ./getfile
+oldprefix=''
+case "$prefix" in
+'') ;;
+*)
+ case "$ans" in
+ "$prefix") ;;
+ *) oldprefix="$prefix";;
+ esac
+ ;;
+esac
+prefix="$ans"
+prefixexp="$ansexp"
+
+: set the prefixit variable, to compute a suitable default value
+prefixit='case "$3" in
+""|none)
+ case "$oldprefix" in
+ "") eval "$1=\"\$$2\"";;
+ *)
+ case "$3" in
+ "") eval "$1=";;
+ none)
+ eval "tp=\"\$$2\"";
+ case "$tp" in
+ ""|" ") eval "$1=\"\$$2\"";;
+ *) eval "$1=";;
+ esac;;
+ esac;;
+ esac;;
+*)
+ eval "tp=\"$oldprefix-\$$2-\""; eval "tp=\"$tp\"";
+ case "$tp" in
+ --|/*--|\~*--) eval "$1=\"$prefix/$3\"";;
+ /*-$oldprefix/*|\~*-$oldprefix/*)
+ eval "$1=\`echo \$$2 | sed \"s,^$oldprefix,$prefix,\"\`";;
+ *) eval "$1=\"\$$2\"";;
+ esac;;
+esac'
+
+: is AFS running?
+echo " "
+case "$afs" in
+$define|true) afs=true ;;
+$undef|false) afs=false ;;
+*) if test -d /afs; then
+ afs=true
+ else
+ afs=false
+ fi
+ ;;
+esac
+if $afs; then
+ echo "AFS may be running... I'll be extra cautious then..." >&4
+else
+ echo "AFS does not seem to be running..." >&4
+fi
+
+: determine where public executables go
+echo " "
+set dflt bin bin
+eval $prefixit
+fn=d~
+rp='Pathname where the public executables will reside?'
+. ./getfile
+if $test "X$ansexp" != "X$binexp"; then
+ installbin=''
+fi
+bin="$ans"
+binexp="$ansexp"
+if $afs; then
+ $cat <<EOM
+
+Since you are running AFS, I need to distinguish the directory in which
+executables reside from the directory in which they are installed (and from
+which they are presumably copied to the former directory by occult means).
+
+EOM
+ case "$installbin" in
+ '') dflt=`echo $binexp | sed 's#^/afs/#/afs/.#'`;;
+ *) dflt="$installbin";;
+ esac
+ fn=de~
+ rp='Where will public executables be installed?'
+ . ./getfile
+ installbin="$ans"
+else
+ installbin="$binexp"
+fi
+
+: determine where private executables go
+set dflt privlib lib/$package
+eval $prefixit
+$cat <<EOM
+
+There are some auxiliary files for $package that need to be put into a
+private library directory that is accessible by everyone.
+
+EOM
+fn=d~+
+rp='Pathname where the private library files will reside?'
+. ./getfile
+if $test "X$privlibexp" != "X$ansexp"; then
+ installprivlib=''
+fi
+privlib="$ans"
+privlibexp="$ansexp"
+if $afs; then
+ $cat <<EOM
+
+Since you are running AFS, I need to distinguish the directory in which
+private files reside from the directory in which they are installed (and from
+which they are presumably copied to the former directory by occult means).
+
+EOM
+ case "$installprivlib" in
+ '') dflt=`echo $privlibexp | sed 's#^/afs/#/afs/.#'`;;
+ *) dflt="$installprivlib";;
+ esac
+ fn=de~
+ rp='Where will private files be installed?'
+ . ./getfile
+ installprivlib="$ans"
+else
+ installprivlib="$privlibexp"
+fi
+
+: determine where manual pages are on this system
+echo " "
+case "$sysman" in
+'')
+ syspath='/usr/man/man1 /usr/man/mann /usr/man/manl /usr/man/local/man1'
+ syspath="$syspath /usr/man/u_man/man1 /usr/share/man/man1"
+ syspath="$syspath /usr/catman/u_man/man1 /usr/man/l_man/man1"
+ syspath="$syspath /usr/local/man/u_man/man1 /usr/local/man/l_man/man1"
+ syspath="$syspath /usr/man/man.L /local/man/man1 /usr/local/man/man1"
+ sysman=`./loc . /usr/man/man1 $syspath`
+ ;;
+esac
+if $test -d "$sysman"; then
+ echo "System manual is in $sysman." >&4
+else
+ echo "Could not find manual pages in source form." >&4
+fi
+
+: set the prefixup variable, to restore leading tilda escape
+prefixup='case "$prefixexp" in
+"$prefix") ;;
+*) eval "$1=\`echo \$$1 | sed \"s,^$prefixexp,$prefix,\"\`";;
+esac'
+
+: determine where manual pages go
+set mansrc mansrc none
+eval $prefixit
+$cat <<EOM
+
+$spackage has manual pages available in source form.
+EOM
+case "$nroff" in
+nroff)
+ echo "However, you don't have nroff, so they're probably useless to you."
+ case "$mansrc" in
+ '') mansrc="none";;
+ esac;;
+esac
+echo "If you don't want the manual sources installed, answer 'none'."
+case "$mansrc" in
+'')
+ lookpath="$prefixexp/man/man1 $prefixexp/man/u_man/man1"
+ lookpath="$lookpath $prefixexp/man/l_man/man1"
+ lookpath="$lookpath /usr/local/man/man1 /opt/man/man1 /usr/man/manl"
+ lookpath="$lookpath /usr/man/local/man1 /usr/man/l_man/man1"
+ lookpath="$lookpath /usr/local/man/u_man/man1 /usr/local/man/l_man/man1"
+ lookpath="$lookpath /usr/man/man.L"
+ mansrc=`./loc . $prefixexp/man/man1 $lookpath`
+ if $test -d "$mansrc"; then
+ dflt="$mansrc"
+ else
+ dflt="$sysman"
+ fi
+ set dflt
+ eval $prefixup
+ ;;
+' ') dflt=none;;
+*) dflt="$mansrc"
+ ;;
+esac
+echo " "
+fn=dn~
+rp='Where do the manual pages (source) go?'
+. ./getfile
+if test "X$mansrcexp" != "X$ansexp"; then
+ installmansrc=''
+fi
+mansrc="$ans"
+mansrcexp="$ansexp"
+case "$mansrc" in
+'') mansrc=' '
+ installmansrc='';;
+esac
+if $afs && $test "$mansrc"; then
+ $cat <<EOM
+
+Since you are running AFS, I need to distinguish the directory in which
+manual pages reside from the directory in which they are installed (and from
+which they are presumably copied to the former directory by occult means).
+
+EOM
+ case "$installmansrc" in
+ '') dflt=`echo $mansrcexp | sed 's#^/afs/#/afs/.#'`;;
+ *) dflt="$installmansrc";;
+ esac
+ fn=de~
+ rp='Where will man pages be installed?'
+ . ./getfile
+ installmansrc="$ans"
+else
+ installmansrc="$mansrcexp"
+fi
+
+case "$mansrc" in
+' ') manext='0';;
+*l) manext=l;;
+*n) manext=n;;
+*o) manext=l;;
+*p) manext=n;;
+*C) manext=C;;
+*L) manext=L;;
+*L1) manext=L1;;
+*) manext=1;;
+esac
+
+: make some quick guesses about what we are up against
+echo " "
+$echo $n "Hmm... $c"
+echo exit 1 >bsd
+echo exit 1 >usg
+echo exit 1 >v7
+echo exit 1 >osf1
+echo exit 1 >eunice
+echo exit 1 >xenix
+echo exit 1 >venix
+echo exit 1 >os2
+d_bsd="$undef"
+$cat /usr/include/signal.h /usr/include/sys/signal.h >foo 2>/dev/null
+if test -f /osf_boot || $contains 'OSF/1' /usr/include/ctype.h >/dev/null 2>&1
+then
+ echo "Looks kind of like an OSF/1 system, but we'll see..."
+ echo exit 0 >osf1
+elif test `echo abc | tr a-z A-Z` = Abc ; then
+ xxx=`./loc addbib blurfl $pth`
+ if $test -f $xxx; then
+ echo "Looks kind of like a USG system with BSD features, but we'll see..."
+ echo exit 0 >bsd
+ echo exit 0 >usg
+ else
+ if $contains SIGTSTP foo >/dev/null 2>&1 ; then
+ echo "Looks kind of like an extended USG system, but we'll see..."
+ else
+ echo "Looks kind of like a USG system, but we'll see..."
+ fi
+ echo exit 0 >usg
+ fi
+elif $contains SIGTSTP foo >/dev/null 2>&1 ; then
+ echo "Looks kind of like a BSD system, but we'll see..."
+ d_bsd="$define"
+ echo exit 0 >bsd
+else
+ echo "Looks kind of like a Version 7 system, but we'll see..."
+ echo exit 0 >v7
+fi
+case "$eunicefix" in
+*unixtovms*)
+ $cat <<'EOI'
+There is, however, a strange, musty smell in the air that reminds me of
+something...hmm...yes...I've got it...there's a VMS nearby, or I'm a Blit.
+EOI
+ echo exit 0 >eunice
+ d_eunice="$define"
+: it so happens the Eunice I know will not run shell scripts in Unix format
+ ;;
+*)
+ echo " "
+ echo "Congratulations. You aren't running Eunice."
+ d_eunice="$undef"
+ ;;
+esac
+case "$p_" in
+:) ;;
+*)
+ $cat <<'EOI'
+I have the feeling something is not exactly right, however...don't tell me...
+lemme think...does HAL ring a bell?...no, of course, you're only running OS/2!
+EOI
+ echo exit 0 >os2
+ ;;
+esac
+if test -f /xenix; then
+ echo "Actually, this looks more like a XENIX system..."
+ echo exit 0 >xenix
+ d_xenix="$define"
+else
+ echo " "
+ echo "It's not Xenix..."
+ d_xenix="$undef"
+fi
+chmod +x xenix
+$eunicefix xenix
+if test -f /venix; then
+ echo "Actually, this looks more like a VENIX system..."
+ echo exit 0 >venix
+else
+ echo " "
+ if ./xenix; then
+ : null
+ else
+ echo "Nor is it Venix..."
+ fi
+fi
+chmod +x bsd usg v7 osf1 eunice xenix venix os2
+$eunicefix bsd usg v7 osf1 eunice xenix venix os2
+$rm -f foo
+
+: see if we need a special compiler
+echo " "
+if ./usg; then
+ case "$cc" in
+ '') case "$Mcc" in
+ /*) dflt='Mcc';;
+ *) case "$large" in
+ -M*) dflt='cc';;
+ *) if $contains '\-M' $sysman/cc.1 >/dev/null 2>&1 ; then
+ if $contains '\-M' $sysman/cpp.1 >/dev/null 2>&1; then
+ dflt='cc'
+ else
+ dflt='cc -M'
+ fi
+ else
+ dflt='cc'
+ fi;;
+ esac;;
+ esac;;
+ *) dflt="$cc";;
+ esac
+ $cat <<'EOM'
+On some systems the default C compiler will not resolve multiple global
+references that happen to have the same name. On some such systems the "Mcc"
+command may be used to force these to be resolved. On other systems a "cc -M"
+command is required. (Note that the -M flag on other systems indicates a
+memory model to use!) If you have the Gnu C compiler, you might wish to use
+that instead.
+
+EOM
+ rp="What command will force resolution on this system?"
+ . ./myread
+ cc="$ans"
+else
+ case "$cc" in
+ '') dflt=cc;;
+ *) dflt="$cc";;
+ esac
+ rp="Use which C compiler?"
+ . ./myread
+ cc="$ans"
+fi
+echo " "
+echo "Checking for GNU cc in disguise and/or its version number..." >&4
+$cat >gccvers.c <<EOM
+#include <stdio.h>
+int main() {
+#ifdef __GNUC__
+#ifdef __VERSION__
+ printf("%s\n", __VERSION__);
+#else
+ printf("%s\n", "1");
+#endif
+#endif
+ exit(0);
+}
+EOM
+if $cc -o gccvers gccvers.c >/dev/null 2>&1; then
+ gccversion=`./gccvers`
+ case "$gccversion" in
+ '') echo "You are not using GNU cc." ;;
+ *) echo "You are using GNU cc $gccversion." ;;
+ esac
+else
+ echo " "
+ echo "*** WHOA THERE!!! ***" >&4
+ echo " Your C compiler \"$cc\" doesn't seem to be working!" >&4
+ case "$knowitall" in
+ '')
+ echo " You'd better start hunting for one and let me know about it." >&4
+ exit 1
+ ;;
+ esac
+fi
+$rm -f gccvers*
+case "$gccversion" in
+1*) cpp=`./loc gcc-cpp $cpp $pth` ;;
+esac
+
+: What should the include directory be ?
+echo " "
+$echo $n "Hmm... $c"
+dflt='/usr/include'
+incpath=''
+mips_type=''
+if $test -f /bin/mips && /bin/mips; then
+ echo "Looks like a MIPS system..."
+ $cat >usr.c <<'EOCP'
+#ifdef SYSTYPE_BSD43
+/bsd43
+#endif
+EOCP
+ if $cc -E usr.c > usr.out && $contains / usr.out >/dev/null 2>&1; then
+ dflt='/bsd43/usr/include'
+ incpath='/bsd43'
+ mips_type='BSD 4.3'
+ else
+ mips_type='System V'
+ fi
+ $rm -f usr.c usr.out
+ echo "and you're compiling with the $mips_type compiler and libraries."
+ xxx_prompt=y
+ echo "exit 0" >mips
+else
+ echo "Doesn't look like a MIPS system."
+ xxx_prompt=n
+ echo "exit 1" >mips
+fi
+chmod +x mips
+$eunicefix mips
+case "$usrinc" in
+'') ;;
+*) dflt="$usrinc";;
+esac
+case "$xxx_prompt" in
+y) fn=d/
+ echo " "
+ rp='Where are the include files you want to use?'
+ . ./getfile
+ usrinc="$ans"
+ ;;
+*) usrinc="$dflt"
+ ;;
+esac
+
+: see how we invoke the C preprocessor
+echo " "
+echo "Now, how can we feed standard input to your C preprocessor..." >&4
+cat <<'EOT' >testcpp.c
+#define ABC abc
+#define XYZ xyz
+ABC.XYZ
+EOT
+cd ..
+echo 'cat >.$$.c; '"$cc"' -E ${1+"$@"} .$$.c; rm .$$.c' >cppstdin
+chmod 755 cppstdin
+wrapper=`pwd`/cppstdin
+ok='false'
+cd UU
+
+if $test "X$cppstdin" != "X" && \
+ $cppstdin $cppminus <testcpp.c >testcpp.out 2>&1 && \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1
+then
+ echo "You used to use $cppstdin $cppminus so we'll use that again."
+ case "$cpprun" in
+ '') echo "But let's see if we can live without a wrapper..." ;;
+ *)
+ if $cpprun $cpplast <testcpp.c >testcpp.out 2>&1 && \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1
+ then
+ echo "(And we'll use $cpprun $cpplast to preprocess directly.)"
+ ok='true'
+ else
+ echo "(However, $cpprun $cpplast does not work, let's see...)"
+ fi
+ ;;
+ esac
+else
+ case "$cppstdin" in
+ '') ;;
+ *)
+ echo "Good old $cppstdin $cppminus does not seem to be of any help..."
+ ;;
+ esac
+fi
+
+if $ok; then
+ : nothing
+elif echo 'Maybe "'"$cc"' -E" will work...'; \
+ $cc -E <testcpp.c >testcpp.out 2>&1; \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "Yup, it does."
+ x_cpp="$cc -E"
+ x_minus='';
+elif echo 'Nope...maybe "'"$cc"' -E -" will work...'; \
+ $cc -E - <testcpp.c >testcpp.out 2>&1; \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "Yup, it does."
+ x_cpp="$cc -E"
+ x_minus='-';
+elif echo 'Nope...maybe "'"$cc"' -P" will work...'; \
+ $cc -P <testcpp.c >testcpp.out 2>&1; \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "Yipee, that works!"
+ x_cpp="$cc -P"
+ x_minus='';
+elif echo 'Nope...maybe "'"$cc"' -P -" will work...'; \
+ $cc -P - <testcpp.c >testcpp.out 2>&1; \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "At long last!"
+ x_cpp="$cc -P"
+ x_minus='-';
+elif echo 'No such luck, maybe "'$cpp'" will work...'; \
+ $cpp <testcpp.c >testcpp.out 2>&1; \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "It works!"
+ x_cpp="$cpp"
+ x_minus='';
+elif echo 'Nixed again...maybe "'$cpp' -" will work...'; \
+ $cpp - <testcpp.c >testcpp.out 2>&1; \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "Hooray, it works! I was beginning to wonder."
+ x_cpp="$cpp"
+ x_minus='-';
+elif echo 'Uh-uh. Time to get fancy. Trying a wrapper...'; \
+ $wrapper <testcpp.c >testcpp.out 2>&1; \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ x_cpp="$wrapper"
+ x_minus=''
+ echo "Eureka!"
+else
+ dflt=''
+ rp="No dice. I can't find a C preprocessor. Name one:"
+ . ./myread
+ x_cpp="$ans"
+ x_minus=''
+ $x_cpp <testcpp.c >testcpp.out 2>&1
+ if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 ; then
+ echo "OK, that will do." >&4
+ else
+echo "Sorry, I can't get that to work. Go find one and rerun Configure." >&4
+ exit 1
+ fi
+fi
+
+case "$ok" in
+false)
+ cppstdin="$x_cpp"
+ cppminus="$x_minus"
+ cpprun="$x_cpp"
+ cpplast="$x_minus"
+ set X $x_cpp
+ shift
+ case "$1" in
+ "$cpp")
+ echo "Perhaps can we force $cc -E using a wrapper..."
+ if $wrapper <testcpp.c >testcpp.out 2>&1; \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1
+ then
+ echo "Yup, we can."
+ cppstdin="$wrapper"
+ cppminus='';
+ else
+ echo "Nope, we'll have to live without it..."
+ fi
+ ;;
+ esac
+ case "$cpprun" in
+ "$wrapper")
+ cpprun=''
+ cpplast=''
+ ;;
+ esac
+ ;;
+esac
+
+case "$cppstdin" in
+"$wrapper") ;;
+*) $rm -f $wrapper;;
+esac
+$rm -f testcpp.c testcpp.out
+
+: Set private lib path
+case "$plibpth" in
+'') if ./mips; then
+ plibpth="$incpath/usr/lib /usr/local/lib /usr/ccs/lib"
+ fi;;
+esac
+case "$libpth" in
+' ') dlist='';;
+'') dlist="$loclibpth $plibpth $glibpth";;
+*) dlist="$libpth";;
+esac
+
+: Now check and see which directories actually exist, avoiding duplicates
+libpth=''
+for xxx in $dlist
+do
+ if $test -d $xxx; then
+ case " $libpth " in
+ *" $xxx "*) ;;
+ *) libpth="$libpth $xxx";;
+ esac
+ fi
+done
+$cat <<'EOM'
+
+Some systems have incompatible or broken versions of libraries. Among
+the directories listed in the question below, please remove any you
+know not to be holding relevant libraries, and add any that are needed.
+Say "none" for none.
+
+EOM
+case "$libpth" in
+'') dflt='none';;
+*)
+ set X $libpth
+ shift
+ dflt=${1+"$@"}
+ ;;
+esac
+rp="Directories to use for library searches?"
+. ./myread
+case "$ans" in
+none) libpth=' ';;
+*) libpth="$ans";;
+esac
+
+: determine optimize, if desired, or use for debug flag also
+case "$optimize" in
+' ') dflt='none';;
+'') dflt='-O';;
+*) dflt="$optimize";;
+esac
+$cat <<EOH
+
+Some C compilers have problems with their optimizers. By default, $package
+compiles with the -O flag to use the optimizer. Alternately, you might want
+to use the symbolic debugger, which uses the -g flag (on traditional Unix
+systems). Either flag can be specified here. To use neither flag, specify
+the word "none".
+
+EOH
+rp="What optimizer/debugger flag should be used?"
+. ./myread
+optimize="$ans"
+case "$optimize" in
+'none') optimize=" ";;
+esac
+
+dflt=''
+: We will not override a previous value, but we might want to
+: augment a hint file
+case "$hint" in
+none|recommended)
+ case "$gccversion" in
+ 1*) dflt='-fpcc-struct-return' ;;
+ esac
+ case "$optimize" in
+ *-g*) dflt="$dflt -DDEBUGGING";;
+ esac
+ case "$gccversion" in
+ 2*) if test -d /etc/conf/kconfig.d &&
+ $contains _POSIX_VERSION $usrinc/sys/unistd.h >/dev/null 2>&1
+ then
+ dflt="$dflt -posix"
+ fi
+ ;;
+ esac
+ ;;
+esac
+
+case "$mips_type" in
+*BSD*|'') inclwanted="$locincpth $usrinc";;
+*) inclwanted="$locincpth $inclwanted $usrinc/bsd";;
+esac
+for thisincl in $inclwanted; do
+ if $test -d $thisincl; then
+ if $test x$thisincl != x$usrinc; then
+ case "$dflt" in
+ *$thisincl*);;
+ *) dflt="$dflt -I$thisincl";;
+ esac
+ fi
+ fi
+done
+
+inctest='if $contains $2 $usrinc/$1 >/dev/null 2>&1; then
+ xxx=true;
+elif $contains $2 $usrinc/sys/$1 >/dev/null 2>&1; then
+ xxx=true;
+else
+ xxx=false;
+fi;
+if $xxx; then
+ case "$dflt" in
+ *$2*);;
+ *) dflt="$dflt -D$2";;
+ esac;
+fi'
+
+if ./osf1; then
+ set signal.h __LANGUAGE_C__; eval $inctest
+else
+ set signal.h LANGUAGE_C; eval $inctest
+fi
+
+case "$hint" in
+none|recommended) dflt="$ccflags $dflt" ;;
+*) dflt="$ccflags";;
+esac
+
+case "$dflt" in
+''|' ') dflt=none;;
+esac
+$cat <<EOH
+
+Your C compiler may want other flags. For this question you should include
+-I/whatever and -DWHATEVER flags and any other flags used by the C compiler,
+but you should NOT include libraries or ld flags like -lwhatever. If you
+want $package to honor its debug switch, you should include -DDEBUG here.
+
+To use no flags, specify the word "none".
+
+EOH
+set X $dflt
+shift
+dflt=${1+"$@"}
+rp="Any additional cc flags?"
+. ./myread
+case "$ans" in
+none) ccflags='';;
+*) ccflags="$ans";;
+esac
+
+: the following weeds options from ccflags that are of no interest to cpp
+cppflags="$ccflags"
+case "$gccversion" in
+1*) cppflags="$cppflags -D__GNUC__"
+esac
+case "$mips_type" in
+'');;
+*BSD*) cppflags="$cppflags -DSYSTYPE_BSD43";;
+esac
+case "$cppflags" in
+'');;
+*)
+ echo " "
+ echo "Let me guess what the preprocessor flags are..." >&4
+ set X $cppflags
+ shift
+ cppflags=''
+ $cat >cpp.c <<'EOM'
+#define BLURFL foo
+
+BLURFL xx LFRULB
+EOM
+ previous=''
+ for flag in $*
+ do
+ case "$flag" in
+ -*) ftry="$flag";;
+ *) ftry="$previous $flag";;
+ esac
+ if $cppstdin -DLFRULB=bar $ftry $cppminus <cpp.c \
+ >cpp1.out 2>/dev/null && \
+ $cpprun -DLFRULB=bar $ftry $cpplast <cpp.c \
+ >cpp2.out 2>/dev/null && \
+ $contains 'foo.*xx.*bar' cpp1.out >/dev/null 2>&1 && \
+ $contains 'foo.*xx.*bar' cpp2.out >/dev/null 2>&1
+ then
+ cppflags="$cppflags $ftry"
+ previous=''
+ else
+ previous="$flag"
+ fi
+ done
+ set X $cppflags
+ shift
+ cppflags=${1+"$@"}
+ case "$cppflags" in
+ *-*) echo "They appear to be: $cppflags";;
+ esac
+ $rm -f cpp.c cpp?.out
+ ;;
+esac
+
+: flags used in final linking phase
+case "$ldflags" in
+'') if ./venix; then
+ dflt='-i -z'
+ else
+ dflt=''
+ fi
+ case "$ccflags" in
+ *-posix*) dflt="$dflt -posix" ;;
+ esac
+ ;;
+*) dflt="$ldflags";;
+esac
+
+: Try to guess additional flags to pick up local libraries.
+for thislibdir in $libpth; do
+ case " $loclibpth " in
+ *" $thislibdir "*)
+ case "$dflt " in
+ *"-L$thislibdir "*) ;;
+ *) dflt="$dflt -L$thislibdir" ;;
+ esac
+ ;;
+ esac
+done
+
+case "$dflt" in
+'') dflt='none' ;;
+esac
+
+$cat <<EOH
+
+Your C linker may need flags. For this question you should
+include -L/whatever and any other flags used by the C linker, but you
+should NOT include libraries like -lwhatever.
+
+Make sure you include the appropriate -L/path flags if your C linker
+does not normally search all of the directories you specified above,
+namely
+ $libpth
+To use no flags, specify the word "none".
+
+EOH
+
+rp="Any additional ld flags (NOT including libraries)?"
+. ./myread
+case "$ans" in
+none) ldflags='';;
+*) ldflags="$ans";;
+esac
+rmlist="$rmlist pdp11"
+
+: coherency check
+echo " "
+echo "Checking your choice of C compiler and flags for coherency..." >&4
+set X $cc $optimize $ccflags $ldflags try.c -o try
+shift
+$cat >try.msg <<EOM
+I've tried to compile and run a simple program with:
+
+ $*
+ ./try
+
+and I got the following output:
+
+EOM
+$cat > try.c <<'EOF'
+#include <stdio.h>
+main() { exit(0); }
+EOF
+dflt=y
+if sh -c "$cc $optimize $ccflags try.c -o try $ldflags" >>try.msg 2>&1; then
+ if sh -c './try' >>try.msg 2>&1; then
+ dflt=n
+ else
+ echo "The program compiled OK, but exited with status $?." >>try.msg
+ rp="You have a problem. Shall I abort Configure"
+ dflt=y
+ fi
+else
+ echo "I can't compile the test program." >>try.msg
+ rp="You have a BIG problem. Shall I abort Configure"
+ dflt=y
+fi
+case "$dflt" in
+y)
+ $cat try.msg
+ case "$knowitall" in
+ '')
+ echo "(The supplied flags might be incorrect with this C compiler.)"
+ ;;
+ *) dflt=n;;
+ esac
+ echo " "
+ . ./myread
+ case "$ans" in
+ n*|N*) ;;
+ *) echo "Ok. Stopping Configure." >&4
+ exit 1
+ ;;
+ esac
+ ;;
+n) echo "OK, that should do.";;
+esac
+$rm -f try try.* core
+
+: Initialize h_fcntl
+h_fcntl=false
+
+: Initialize h_sysfile
+h_sysfile=false
+
+: compute shared library extension
+case "$so" in
+'')
+ if xxx=`./loc libc.sl X $libpth`; $test -f "$xxx"; then
+ dflt='sl'
+ else
+ dflt='so'
+ fi
+ ;;
+*) dflt="$so";;
+esac
+$cat <<EOM
+
+On some systems, shared libraries may be available. Answer 'none' if
+you want to suppress searching of shared libraries for the remaining
+of this configuration.
+
+EOM
+rp='What is the file extension used for shared libraries?'
+. ./myread
+so="$ans"
+
+: Define several unixisms.
+: Hints files or command line option can be used to override them.
+case "$_a" in
+'') _a='.a';;
+esac
+case "$_o" in
+'') _o='.o';;
+esac
+
+: Looking for optional libraries
+echo " "
+echo "Checking for optional libraries..." >&4
+case "$libs" in
+' '|'') dflt='';;
+*) dflt="$libs";;
+esac
+case "$libswanted" in
+'') libswanted='c_s';;
+esac
+for thislib in $libswanted; do
+
+ if xxx=`./loc lib$thislib.$so.[0-9]'*' X $libpth`; $test -f "$xxx"; then
+ echo "Found -l$thislib (shared)."
+ case " $dflt " in
+ *"-l$thislib "*);;
+ *) dflt="$dflt -l$thislib";;
+ esac
+ elif xxx=`./loc lib$thislib.$so X $libpth` ; $test -f "$xxx"; then
+ echo "Found -l$thislib (shared)."
+ case " $dflt " in
+ *"-l$thislib "*);;
+ *) dflt="$dflt -l$thislib";;
+ esac
+ elif xxx=`./loc lib$thislib$_a X $libpth`; $test -f "$xxx"; then
+ echo "Found -l$thislib."
+ case " $dflt " in
+ *"-l$thislib "*);;
+ *) dflt="$dflt -l$thislib";;
+ esac
+ elif xxx=`./loc $thislib$_a X $libpth`; $test -f "$xxx"; then
+ echo "Found -l$thislib."
+ case " $dflt " in
+ *"-l$thislib "*);;
+ *) dflt="$dflt -l$thislib";;
+ esac
+ elif xxx=`./loc lib${thislib}_s$_a X $libpth`; $test -f "$xxx"; then
+ echo "Found -l${thislib}_s."
+ case " $dflt " in
+ *"-l$thislib "*);;
+ *) dflt="$dflt -l${thislib}_s";;
+ esac
+ elif xxx=`./loc Slib$thislib$_a X $xlibpth`; $test -f "$xxx"; then
+ echo "Found -l$thislib."
+ case " $dflt " in
+ *"-l$thislib "*);;
+ *) dflt="$dflt -l$thislib";;
+ esac
+ else
+ echo "No -l$thislib."
+ fi
+done
+set X $dflt
+shift
+dflt="$*"
+case "$libs" in
+'') dflt="$dflt";;
+*) dflt="$libs";;
+esac
+case "$dflt" in
+' '|'') dflt='none';;
+esac
+
+$cat <<EOM
+
+Some versions of Unix support shared libraries, which make executables smaller
+but make load time slightly longer.
+
+On some systems, mostly System V Release 3's, the shared library is included
+by putting the option "-lc_s" as the last thing on the cc command line when
+linking. Other systems use shared libraries by default. There may be other
+libraries needed to compile $package on your machine as well. If your system
+needs the "-lc_s" option, include it here. Include any other special libraries
+here as well. Say "none" for none.
+EOM
+
+echo " "
+rp="Any additional libraries?"
+. ./myread
+case "$ans" in
+none) libs=' ';;
+*) libs="$ans";;
+esac
+
+: set up the script used to warn in case of inconsistency
+cat <<EOS >whoa
+$startsh
+EOS
+cat <<'EOSC' >>whoa
+dflt=y
+echo " "
+echo "*** WHOA THERE!!! ***" >&4
+echo " The $hint value for \$$var on this machine was \"$was\"!" >&4
+rp=" Keep the $hint value?"
+. ./myread
+case "$ans" in
+y) td=$was; tu=$was;;
+esac
+EOSC
+
+: function used to set $1 to $val
+setvar='var=$1; eval "was=\$$1"; td=$define; tu=$undef;
+case "$val$was" in
+$define$undef) . ./whoa; eval "$var=\$td";;
+$undef$define) . ./whoa; eval "$var=\$tu";;
+*) eval "$var=$val";;
+esac'
+
+echo " "
+echo "Checking for GNU C Library..." >&4
+cat >gnulibc.c <<EOM
+int
+main()
+{
+ return __libc_main();
+}
+EOM
+if $cc $ccflags $ldflags -o gnulibc gnulibc.c $libs >/dev/null 2>&1 && \
+ ./gnulibc | $contains '^GNU C Library' >/dev/null 2>&1; then
+ val="$define"
+ echo "You are using the GNU C Library"
+else
+ val="$undef"
+ echo "You are not using the GNU C Library"
+fi
+$rm -f gnulibc*
+set d_gnulibc
+eval $setvar
+
+: see if nm is to be used to determine whether a symbol is defined or not
+case "$usenm" in
+'')
+ case "$d_gnulibc" in
+ $define)
+ dflt=n
+ ;;
+ *)
+ dflt=`egrep 'inlibc|csym' ../Configure | wc -l 2>/dev/null`
+ if $test $dflt -gt 20; then
+ dflt=y
+ else
+ dflt=n
+ fi
+ ;;
+ esac
+ ;;
+*)
+ case "$usenm" in
+ true) dflt=y;;
+ *) dflt=n;;
+ esac
+ ;;
+esac
+$cat <<EOM
+
+I can use 'nm' to extract the symbols from your C libraries. This is a time
+consuming task which may generate huge output on the disk (up to 3 megabytes)
+but that should make the symbols extraction faster. The alternative is to skip
+the 'nm' extraction part and to compile a small test program instead to
+determine whether each symbol is present. If you have a fast C compiler and/or
+if your 'nm' output cannot be parsed, this may be the best solution.
+You shouldn't let me use 'nm' if you have the GNU C Library.
+
+EOM
+rp='Shall I use nm to extract C symbols from the libraries?'
+. ./myread
+case "$ans" in
+n|N) usenm=false;;
+*) usenm=true;;
+esac
+
+runnm=$usenm
+case "$reuseval" in
+true) runnm=false;;
+esac
+
+: nm options which may be necessary
+case "$nm_opt" in
+'') if $test -f /mach_boot; then
+ nm_opt=''
+ elif $test -d /usr/ccs/lib; then
+ nm_opt='-p'
+ elif $test -f /dgux; then
+ nm_opt='-p'
+ else
+ nm_opt=''
+ fi;;
+esac
+
+: nm options which may be necessary for shared libraries but illegal
+: for archive libraries. Thank you, Linux.
+case "$nm_so_opt" in
+'') case "$myuname" in
+ *linux*)
+ if nm --help | $grep 'dynamic' > /dev/null 2>&1; then
+ nm_so_opt='--dynamic'
+ fi
+ ;;
+ esac
+ ;;
+esac
+
+case "$runnm" in
+true)
+: get list of predefined functions in a handy place
+echo " "
+case "$libc" in
+'') libc=unknown
+ case "$libs" in
+ *-lc_s*) libc=`./loc libc_s$_a $libc $libpth`
+ esac
+ ;;
+esac
+libnames='';
+case "$libs" in
+'') ;;
+*) for thislib in $libs; do
+ case "$thislib" in
+ -lc|-lc_s)
+ : Handle C library specially below.
+ ;;
+ -l*)
+ thislib=`echo $thislib | $sed -e 's/^-l//'`
+ if try=`./loc lib$thislib.$so.'*' X $libpth`; $test -f "$try"; then
+ :
+ elif try=`./loc lib$thislib.$so X $libpth`; $test -f "$try"; then
+ :
+ elif try=`./loc lib$thislib$_a X $libpth`; $test -f "$try"; then
+ :
+ elif try=`./loc $thislib$_a X $libpth`; $test -f "$try"; then
+ :
+ elif try=`./loc lib$thislib X $libpth`; $test -f "$try"; then
+ :
+ elif try=`./loc $thislib X $libpth`; $test -f "$try"; then
+ :
+ elif try=`./loc Slib$thislib$_a X $xlibpth`; $test -f "$try"; then
+ :
+ else
+ try=''
+ fi
+ libnames="$libnames $try"
+ ;;
+ *) libnames="$libnames $thislib" ;;
+ esac
+ done
+ ;;
+esac
+xxx=normal
+case "$libc" in
+unknown)
+ set /lib/libc.$so
+ for xxx in $libpth; do
+ $test -r $1 || set $xxx/libc.$so
+ $test -r $1 || \
+ set `echo blurfl; echo /usr/lib/libc.$so.[0-9]* | \
+ tr ' ' '\012' | egrep -v '\.[A-Za-z]*$' | $sed -e '
+ h
+ s/[0-9][0-9]*/0000&/g
+ s/0*\([0-9][0-9][0-9][0-9][0-9]\)/\1/g
+ G
+ s/\n/ /' | \
+ sort | $sed -e 's/^.* //'`
+ eval set \$$#
+ done
+ $test -r $1 || set /usr/ccs/lib/libc.$so
+ $test -r $1 || set /lib/libsys_s$_a
+ ;;
+*)
+ set blurfl
+ ;;
+esac
+if $test -r "$1"; then
+ echo "Your (shared) C library seems to be in $1."
+ libc="$1"
+elif $test -r /lib/libc && $test -r /lib/clib; then
+ echo "Your C library seems to be in both /lib/clib and /lib/libc."
+ xxx=apollo
+ libc='/lib/clib /lib/libc'
+ if $test -r /lib/syslib; then
+ echo "(Your math library is in /lib/syslib.)"
+ libc="$libc /lib/syslib"
+ fi
+elif $test -r "$libc" || (test -h "$libc") >/dev/null 2>&1; then
+ echo "Your C library seems to be in $libc, as you said before."
+elif $test -r $incpath/usr/lib/libc$_a; then
+ libc=$incpath/usr/lib/libc$_a;
+ echo "Your C library seems to be in $libc. That's fine."
+elif $test -r /lib/libc$_a; then
+ libc=/lib/libc$_a;
+ echo "Your C library seems to be in $libc. You're normal."
+else
+ if tans=`./loc libc$_a blurfl/dyick $libpth`; $test -r "$tans"; then
+ :
+ elif tans=`./loc libc blurfl/dyick $libpth`; $test -r "$tans"; then
+ libnames="$libnames "`./loc clib blurfl/dyick $libpth`
+ elif tans=`./loc clib blurfl/dyick $libpth`; $test -r "$tans"; then
+ :
+ elif tans=`./loc Slibc$_a blurfl/dyick $xlibpth`; $test -r "$tans"; then
+ :
+ elif tans=`./loc Mlibc$_a blurfl/dyick $xlibpth`; $test -r "$tans"; then
+ :
+ else
+ tans=`./loc Llibc$_a blurfl/dyick $xlibpth`
+ fi
+ if $test -r "$tans"; then
+ echo "Your C library seems to be in $tans, of all places."
+ libc=$tans
+ else
+ libc='blurfl'
+ fi
+fi
+if $test $xxx = apollo -o -r "$libc" || (test -h "$libc") >/dev/null 2>&1; then
+ dflt="$libc"
+ cat <<EOM
+
+If the guess above is wrong (which it might be if you're using a strange
+compiler, or your machine supports multiple models), you can override it here.
+
+EOM
+else
+ dflt=''
+ echo $libpth | tr ' ' '\012' | sort | uniq > libpath
+ cat >&4 <<EOM
+I can't seem to find your C library. I've looked in the following places:
+
+EOM
+ $sed 's/^/ /' libpath
+ cat <<EOM
+
+None of these seems to contain your C library. I need to get its name...
+
+EOM
+fi
+fn=f
+rp='Where is your C library?'
+. ./getfile
+libc="$ans"
+
+echo " "
+echo $libc $libnames | tr ' ' '\012' | sort | uniq > libnames
+set X `cat libnames`
+shift
+xxx=files
+case $# in 1) xxx=file; esac
+echo "Extracting names from the following $xxx for later perusal:" >&4
+echo " "
+$sed 's/^/ /' libnames >&4
+echo " "
+$echo $n "This may take a while...$c" >&4
+
+for file in $*; do
+ case $file in
+ *$so*) nm $nm_so_opt $nm_opt $file 2>/dev/null;;
+ *) nm $nm_opt $file 2>/dev/null;;
+ esac
+done >libc.tmp
+
+$echo $n ".$c"
+$grep fprintf libc.tmp > libc.ptf
+xscan='eval "<libc.ptf $com >libc.list"; $echo $n ".$c" >&4'
+xrun='eval "<libc.tmp $com >libc.list"; echo "done" >&4'
+xxx='[ADTSIW]'
+if com="$sed -n -e 's/__IO//' -e 's/^.* $xxx *_[_.]*//p' -e 's/^.* $xxx *//p'";\
+ eval $xscan;\
+ $contains '^fprintf$' libc.list >/dev/null 2>&1; then
+ eval $xrun
+elif com="$sed -n -e 's/^__*//' -e 's/^\([a-zA-Z_0-9$]*\).*xtern.*/\1/p'";\
+ eval $xscan;\
+ $contains '^fprintf$' libc.list >/dev/null 2>&1; then
+ eval $xrun
+elif com="$sed -n -e '/|UNDEF/d' -e '/FUNC..GL/s/^.*|__*//p'";\
+ eval $xscan;\
+ $contains '^fprintf$' libc.list >/dev/null 2>&1; then
+ eval $xrun
+elif com="$sed -n -e 's/^.* D __*//p' -e 's/^.* D //p'";\
+ eval $xscan;\
+ $contains '^fprintf$' libc.list >/dev/null 2>&1; then
+ eval $xrun
+elif com="$sed -n -e 's/^_//' -e 's/^\([a-zA-Z_0-9]*\).*xtern.*text.*/\1/p'";\
+ eval $xscan;\
+ $contains '^fprintf$' libc.list >/dev/null 2>&1; then
+ eval $xrun
+elif com="$sed -n -e 's/^.*|FUNC |GLOB .*|//p'";\
+ eval $xscan;\
+ $contains '^fprintf$' libc.list >/dev/null 2>&1; then
+ eval $xrun
+elif com="$grep '|' | $sed -n -e '/|COMMON/d' -e '/|DATA/d' \
+ -e '/ file/d' -e 's/^\([^ ]*\).*/\1/p'";\
+ eval $xscan;\
+ $contains '^fprintf$' libc.list >/dev/null 2>&1; then
+ eval $xrun
+elif com="$sed -n -e 's/^.*|FUNC |GLOB .*|//p' -e 's/^.*|FUNC |WEAK .*|//p'";\
+ eval $xscan;\
+ $contains '^fprintf$' libc.list >/dev/null 2>&1; then
+ eval $xrun
+elif com="$sed -n -e 's/^__//' -e '/|Undef/d' -e '/|Proc/s/ .*//p'";\
+ eval $xscan;\
+ $contains '^fprintf$' libc.list >/dev/null 2>&1; then
+ eval $xrun
+elif com="$sed -n -e '/Def. Text/s/.* \([^ ]*\)\$/\1/p'";\
+ eval $xscan;\
+ $contains '^fprintf$' libc.list >/dev/null 2>&1; then
+ eval $xrun
+elif com="$sed -n -e 's/^[-0-9a-f ]*_\(.*\)=.*/\1/p'";\
+ eval $xscan;\
+ $contains '^fprintf$' libc.list >/dev/null 2>&1; then
+ eval $xrun
+elif com="$sed -n -e 's/.*\.text n\ \ \ \.//p'";\
+ eval $xscan;\
+ $contains '^fprintf$' libc.list >/dev/null 2>&1; then
+ eval $xrun
+else
+ nm -p $* 2>/dev/null >libc.tmp
+ $grep fprintf libc.tmp > libc.ptf
+ if com="$sed -n -e 's/^.* [ADTSIW] *_[_.]*//p' -e 's/^.* [ADTSIW] //p'";\
+ eval $xscan; $contains '^fprintf$' libc.list >/dev/null 2>&1
+ then
+ nm_opt='-p'
+ eval $xrun
+ else
+ echo " "
+ echo "nm didn't seem to work right. Trying ar instead..." >&4
+ com=''
+ if ar t $libc > libc.tmp; then
+ for thisname in $libnames; do
+ ar t $thisname >>libc.tmp
+ done
+ $sed -e "s/\\$_o\$//" < libc.tmp > libc.list
+ echo "Ok." >&4
+ else
+ echo "ar didn't seem to work right." >&4
+ echo "Maybe this is a Cray...trying bld instead..." >&4
+ if bld t $libc | $sed -e 's/.*\///' -e "s/\\$_o:.*\$//" > libc.list
+ then
+ for thisname in $libnames; do
+ bld t $libnames | \
+ $sed -e 's/.*\///' -e "s/\\$_o:.*\$//" >>libc.list
+ ar t $thisname >>libc.tmp
+ done
+ echo "Ok." >&4
+ else
+ echo "That didn't work either. Giving up." >&4
+ exit 1
+ fi
+ fi
+ fi
+fi
+nm_extract="$com"
+if $test -f /lib/syscalls.exp; then
+ echo " "
+ echo "Also extracting names from /lib/syscalls.exp for good ole AIX..." >&4
+ $sed -n 's/^\([^ ]*\)[ ]*syscall$/\1/p' /lib/syscalls.exp >>libc.list
+fi
+;;
+esac
+$rm -f libnames libpath
+
+: is a C symbol defined?
+csym='tlook=$1;
+case "$3" in
+-v) tf=libc.tmp; tc=""; tdc="";;
+-a) tf=libc.tmp; tc="[0]"; tdc="[]";;
+*) tlook="^$1\$"; tf=libc.list; tc="()"; tdc="()";;
+esac;
+tx=yes;
+case "$reuseval-$4" in
+true-) ;;
+true-*) tx=no; eval "tval=\$$4"; case "$tval" in "") tx=yes;; esac;;
+esac;
+case "$tx" in
+yes)
+ case "$runnm" in
+ true)
+ if $contains $tlook $tf >/dev/null 2>&1;
+ then tval=true;
+ else tval=false;
+ fi;;
+ *)
+ echo "main() { extern short $1$tdc; printf(\"%hd\", $1$tc); }" > t.c;
+ if $cc $ccflags $ldflags -o t t.c $libs >/dev/null 2>&1;
+ then tval=true;
+ else tval=false;
+ fi;
+ $rm -f t t.c;;
+ esac;;
+*)
+ case "$tval" in
+ $define) tval=true;;
+ *) tval=false;;
+ esac;;
+esac;
+eval "$2=$tval"'
+
+: define an is-in-libc? function
+inlibc='echo " "; td=$define; tu=$undef;
+sym=$1; var=$2; eval "was=\$$2";
+tx=yes;
+case "$reuseval$was" in
+true) ;;
+true*) tx=no;;
+esac;
+case "$tx" in
+yes)
+ set $sym tres -f;
+ eval $csym;
+ case "$tres" in
+ true)
+ echo "$sym() found." >&4;
+ case "$was" in $undef) . ./whoa; esac; eval "$var=\$td";;
+ *)
+ echo "$sym() NOT found." >&4;
+ case "$was" in $define) . ./whoa; esac; eval "$var=\$tu";;
+ esac;;
+*)
+ case "$was" in
+ $define) echo "$sym() found." >&4;;
+ *) echo "$sym() NOT found." >&4;;
+ esac;;
+esac'
+
+: determine filename position in cpp output
+echo " "
+echo "Computing filename position in cpp output for #include directives..." >&4
+echo '#include <stdio.h>' > foo.c
+$cat >fieldn <<EOF
+$startsh
+$cppstdin $cppflags $cppminus <foo.c 2>/dev/null | \
+$grep '^[ ]*#.*stdio\.h' | \
+while read cline; do
+ pos=1
+ set \$cline
+ while $test \$# -gt 0; do
+ if $test -r \`echo \$1 | $tr -d '"'\`; then
+ echo "\$pos"
+ exit 0
+ fi
+ shift
+ pos=\`expr \$pos + 1\`
+ done
+done
+EOF
+chmod +x fieldn
+fieldn=`./fieldn`
+$rm -f foo.c fieldn
+case $fieldn in
+'') pos='???';;
+1) pos=first;;
+2) pos=second;;
+3) pos=third;;
+*) pos="${fieldn}th";;
+esac
+echo "Your cpp writes the filename in the $pos field of the line."
+
+: locate header file
+$cat >findhdr <<EOF
+$startsh
+wanted=\$1
+name=''
+if test -f $usrinc/\$wanted; then
+ echo "$usrinc/\$wanted"
+ exit 0
+fi
+awkprg='{ print \$$fieldn }'
+echo "#include <\$wanted>" > foo\$\$.c
+$cppstdin $cppminus $cppflags < foo\$\$.c 2>/dev/null | \
+$grep "^[ ]*#.*\$wanted" | \
+while read cline; do
+ name=\`echo \$cline | $awk "\$awkprg" | $tr -d '"'\`
+ case "\$name" in
+ */\$wanted) echo "\$name"; exit 0;;
+ *) name='';;
+ esac;
+done;
+$rm -f foo\$\$.c;
+case "\$name" in
+'') exit 1;;
+esac
+EOF
+chmod +x findhdr
+
+: access call always available on UNIX
+set access d_access
+eval $inlibc
+
+: locate the flags for 'access()'
+case "$d_access" in
+"$define")
+ echo " "
+ $cat >access.c <<'EOCP'
+#include <sys/types.h>
+#ifdef I_FCNTL
+#include <fcntl.h>
+#endif
+#ifdef I_SYS_FILE
+#include <sys/file.h>
+#endif
+#ifdef I_UNISTD
+#include <unistd.h>
+#endif
+main() {
+ exit(R_OK);
+}
+EOCP
+ : check sys/file.h first, no particular reason here
+ if $test `./findhdr sys/file.h` && \
+ $cc $cppflags -DI_SYS_FILE access.c -o access >/dev/null 2>&1 ; then
+ h_sysfile=true;
+ echo "<sys/file.h> defines the *_OK access constants." >&4
+ elif $test `./findhdr fcntl.h` && \
+ $cc $cppflags -DI_FCNTL access.c -o access >/dev/null 2>&1 ; then
+ h_fcntl=true;
+ echo "<fcntl.h> defines the *_OK access constants." >&4
+ elif $test `./findhdr unistd.h` && \
+ $cc $cppflags -DI_UNISTD access.c -o access >/dev/null 2>&1 ; then
+ echo "<unistd.h> defines the *_OK access constants." >&4
+ else
+ echo "I can't find the four *_OK access constants--I'll use mine." >&4
+ fi
+ ;;
+esac
+$rm -f access*
+
+: Look for GNU-cc style attribute checking
+echo " "
+echo "Checking whether your compiler can handle __attribute__ ..." >&4
+$cat >attrib.c <<'EOCP'
+#include <stdio.h>
+void croak (char* pat,...) __attribute__((format(printf,1,2),noreturn));
+EOCP
+if $cc $ccflags -c attrib.c >attrib.out 2>&1 ; then
+ if $contains 'warning' attrib.out >/dev/null 2>&1; then
+ echo "Your C compiler doesn't fully support __attribute__."
+ val="$undef"
+ else
+ echo "Your C compiler supports __attribute__."
+ val="$define"
+ fi
+else
+ echo "Your C compiler doesn't seem to understand __attribute__ at all."
+ val="$undef"
+fi
+set d_attribut
+eval $setvar
+$rm -f attrib*
+
+: check for const keyword
+echo " "
+echo 'Checking to see if your C compiler knows about "const"...' >&4
+$cat >const.c <<'EOCP'
+typedef struct spug { int drokk; } spug;
+main()
+{
+ const char *foo;
+ const spug y;
+}
+EOCP
+if $cc -c $ccflags const.c >/dev/null 2>&1 ; then
+ val="$define"
+ echo "Yup, it does."
+else
+ val="$undef"
+ echo "Nope, it doesn't."
+fi
+set d_const
+eval $setvar
+
+: see how we invoke the C preprocessor
+$cat <<EOM
+
+$package needs to be able to preprocess its input files in a mode which
+preserves comments, which is often not the default behaviour. It should run
+the C preprocessor you will use when compiling your own source code, which
+should be ISO/ANSI C compliant if you want $package to handle the latest
+standard C. I will try to guess, but I might guess wrongly because it is not
+necessarily the same preprocessor used to build $package.
+
+EOM
+$cat <<'EOT' >testcpp.c
+#define ABC abc
+#define XYZ xyz
+ABC.XYZ
+/* comment */
+EOT
+:
+if $test "X$cppfilecom" != "X" && \
+ $cppfilecom testcpp.c </dev/null >testcpp.out 2>/dev/null && \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 && \
+ $contains comment testcpp.out >/dev/null 2>&1
+then
+ echo "You used to use $cppfilecom so we'll use that again."
+elif echo 'Maybe "'$cc' -E -C" will work...' && \
+ $cc -E -C testcpp.c </dev/null >testcpp.out 2>/dev/null && \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 && \
+ $contains comment testcpp.out >/dev/null 2>&1
+then
+ echo "It works!"
+ cppfilecom="$cc -E -C"
+elif echo 'Nope...maybe "'"$cc"' -P -C" will work...' && \
+ $cc -P -C testcpp.c </dev/null >testcpp.out 2>/dev/null && \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 && \
+ $contains comment testcpp.out >/dev/null 2>&1
+then
+ echo "Yup, that does."
+ cppfilecom="$cc -P -C"
+elif echo 'No such luck, maybe "'"$cpp"' -C" will work...' && \
+ $cpp -C testcpp.c </dev/null >testcpp.out 2>/dev/null && \
+ $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 && \
+ $contains comment testcpp.out >/dev/null 2>&1
+then
+ echo "Yup, it does."
+ cppfilecom="$cpp -C"
+else
+ cppfilecom=''
+ $cat <<'EOM'
+I can't find a C preprocessor that will preserve comments. Please name one.
+EOM
+fi
+:
+dflt="$cppfilecom"
+cont=true
+while $test "$cont" ; do
+ echo " "
+ rp="How should $package run your preprocessor preserving comments?"
+ . ./myread
+ cppfilecom="$ans"
+ $cppfilecom testcpp.c >testcpp.out 2>&1
+ if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 && \
+ $contains comment testcpp.out >/dev/null 2>&1
+ then
+ echo "OK, that will do."
+ cont=''
+ else
+ echo "Sorry, I can't get that to work."
+ fi
+done
+
+: Now see if it ignores header files.
+cp testcpp.c testcpp.h
+$cppfilecom testcpp.h >testcpp.out 2>&1
+if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 && \
+ $contains comment testcpp.out >/dev/null 2>&1
+then
+ echo "Terrific; it processes .h files passed on the command line too."
+ val="$undef"
+else
+ echo "It ignores .h files on the command line; pity."
+ val="$define"
+fi
+set d_cppignhdrs
+eval $setvar
+
+: Now see how to send stdin to it.
+echo " "
+cp testcpp.c testcpp.h
+$cppfilecom <testcpp.h >testcpp.out 2>&1
+if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 && \
+ $contains comment testcpp.out >/dev/null 2>&1
+then
+ echo "Great; and it will read stdin if passed no arguments."
+ val="$define"
+ cppstdinflags=''
+else
+ $cppfilecom - <testcpp.h >testcpp.out 2>&1
+ if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 && \
+ $contains comment testcpp.out >/dev/null 2>&1
+ then
+ echo "Great; and it can read stdin by passing it '-'."
+ val="$define"
+ cppstdinflags='-'
+ else
+ $cat <<FOO
+Unfortunately, I can't find an easy way to get that preprocessor to read from
+standard input. Do you know any flags I can pass it to get it to do so?
+If that preprocessor can't read directly form standard input, answer 'none'.
+
+FOO
+ val='dunno'
+ while $test "$val" = "dunno"; do
+ rp='Flags to get preprocessor to read stdin?'
+ dflt='none'
+ . ./myread
+ if $test $ans = 'none'; then
+ echo "Oh well, if $package wants it done, it will do it for itself."
+ val="$undef"
+ else
+ $cppfilecom $ans <testcpp.h >testcpp.out 2>&1
+ if $contains 'abc.*xyz' testcpp.out >/dev/null 2>&1 && \
+ $contains comment testcpp.out >/dev/null 2>&1
+ then
+ echo "Good; that works fine."
+ val="$define"
+ cppstdinflags="$ans"
+ else
+ echo "Sorry, I couldn't get that to work."
+ fi
+ fi
+ done
+ fi
+fi
+set d_cppcanstdin
+eval $setvar
+
+: cleanup cpp test files anyway
+$rm -f testcpp.*
+
+: see if we can have long filenames
+echo " "
+rmlist="$rmlist /tmp/cf$$"
+$test -d /tmp/cf$$ || mkdir /tmp/cf$$
+first=123456789abcdef
+second=/tmp/cf$$/$first
+$rm -f $first $second
+if (echo hi >$first) 2>/dev/null; then
+ if $test -f 123456789abcde; then
+ echo 'You cannot have filenames longer than 14 characters. Sigh.' >&4
+ val="$undef"
+ else
+ if (echo hi >$second) 2>/dev/null; then
+ if $test -f /tmp/cf$$/123456789abcde; then
+ $cat <<'EOM'
+That's peculiar... You can have filenames longer than 14 characters, but only
+on some of the filesystems. Maybe you are using NFS. Anyway, to avoid problems
+I shall consider your system cannot support long filenames at all.
+EOM
+ val="$undef"
+ else
+ echo 'You can have filenames longer than 14 characters.' >&4
+ val="$define"
+ fi
+ else
+ $cat <<'EOM'
+How confusing! Some of your filesystems are sane enough to allow filenames
+longer than 14 characters but some others like /tmp can't even think about them.
+So, for now on, I shall assume your kernel does not allow them at all.
+EOM
+ val="$undef"
+ fi
+ fi
+else
+ $cat <<'EOM'
+You can't have filenames longer than 14 chars. You can't even think about them!
+EOM
+ val="$undef"
+fi
+set d_flexfnam
+eval $setvar
+$rm -rf /tmp/cf$$ 123456789abcde*
+
+: see which of string.h or strings.h is needed
+echo " "
+strings=`./findhdr string.h`
+if $test "$strings" && $test -r "$strings"; then
+ echo "Using <string.h> instead of <strings.h>." >&4
+ val="$define"
+else
+ val="$undef"
+ strings=`./findhdr strings.h`
+ if $test "$strings" && $test -r "$strings"; then
+ echo "Using <strings.h> instead of <string.h>." >&4
+ else
+ echo "No string header found -- You'll surely have problems." >&4
+ fi
+fi
+set i_string
+eval $setvar
+case "$i_string" in
+"$undef") strings=`./findhdr strings.h`;;
+*) strings=`./findhdr string.h`;;
+esac
+
+: index or strchr
+echo " "
+if set index val -f; eval $csym; $val; then
+ if set strchr val -f d_strchr; eval $csym; $val; then
+ if $contains strchr "$strings" >/dev/null 2>&1 ; then
+ val="$define"
+ vali="$undef"
+ echo "strchr() found." >&4
+ else
+ val="$undef"
+ vali="$define"
+ echo "index() found." >&4
+ fi
+ else
+ val="$undef"
+ vali="$define"
+ echo "index() found." >&4
+ fi
+else
+ if set strchr val -f d_strchr; eval $csym; $val; then
+ val="$define"
+ vali="$undef"
+ echo "strchr() found." >&4
+ else
+ echo "No index() or strchr() found!" >&4
+ val="$undef"
+ vali="$undef"
+ fi
+fi
+set d_strchr; eval $setvar
+val="$vali"
+set d_index; eval $setvar
+
+: see if link exists
+set link d_link
+eval $inlibc
+
+: Locate the flags for 'open()'
+echo " "
+$cat >open3.c <<'EOCP'
+#include <sys/types.h>
+#ifdef I_FCNTL
+#include <fcntl.h>
+#endif
+#ifdef I_SYS_FILE
+#include <sys/file.h>
+#endif
+main() {
+ if(O_RDONLY);
+#ifdef O_TRUNC
+ exit(0);
+#else
+ exit(1);
+#endif
+}
+EOCP
+: check sys/file.h first to get FREAD on Sun
+if $test `./findhdr sys/file.h` && \
+ $cc $cppflags "-DI_SYS_FILE" open3.c -o open3 >/dev/null 2>&1 ; then
+ h_sysfile=true;
+ echo "<sys/file.h> defines the O_* constants..." >&4
+ if ./open3; then
+ echo "and you have the 3 argument form of open()." >&4
+ val="$define"
+ else
+ echo "but not the 3 argument form of open(). Oh, well." >&4
+ val="$undef"
+ fi
+elif $test `./findhdr fcntl.h` && \
+ $cc "-DI_FCNTL" open3.c -o open3 >/dev/null 2>&1 ; then
+ h_fcntl=true;
+ echo "<fcntl.h> defines the O_* constants..." >&4
+ if ./open3; then
+ echo "and you have the 3 argument form of open()." >&4
+ val="$define"
+ else
+ echo "but not the 3 argument form of open(). Oh, well." >&4
+ val="$undef"
+ fi
+else
+ val="$undef"
+ echo "I can't find the O_* constant definitions! You got problems." >&4
+fi
+set d_open3
+eval $setvar
+$rm -f open3*
+
+: see if strftime exists
+set strftime d_strftime
+eval $inlibc
+
+: see if strstr exists
+set strstr d_strstr
+eval $inlibc
+
+: see if symlink exists
+set symlink d_symlink
+eval $inlibc
+
+: check for volatile keyword
+echo " "
+echo 'Checking to see if your C compiler knows about "volatile"...' >&4
+$cat >try.c <<'EOCP'
+main()
+{
+ typedef struct _goo_struct goo_struct;
+ goo_struct * volatile goo = ((goo_struct *)0);
+ struct _goo_struct {
+ long long_int;
+ int reg_int;
+ char char_var;
+ };
+ typedef unsigned short foo_t;
+ char *volatile foo;
+ volatile int bar;
+ volatile foo_t blech;
+ foo = foo;
+}
+EOCP
+if $cc -c $ccflags try.c >/dev/null 2>&1 ; then
+ val="$define"
+ echo "Yup, it does."
+else
+ val="$undef"
+ echo "Nope, it doesn't."
+fi
+set d_volatile
+eval $setvar
+$rm -f try.*
+
+: preserve RCS keywords in files with variable substitution, grrr
+Id='$Id'
+
+: check for void type
+echo " "
+echo "Checking to see how well your C compiler groks the void type..." >&4
+echo " "
+$cat >&4 <<EOM
+ Support flag bits are:
+ 1: basic void declarations.
+ 2: arrays of pointers to functions returning void.
+ 4: operations between pointers to and addresses of void functions.
+ 8: generic void pointers.
+EOM
+echo " "
+case "$voidflags" in
+'')
+ $cat >try.c <<'EOCP'
+#if TRY & 1
+void sub() {
+#else
+sub() {
+#endif
+ extern void moo(); /* function returning void */
+ void (*goo)(); /* ptr to func returning void */
+#if TRY & 8
+ void *hue; /* generic ptr */
+#endif
+#if TRY & 2
+ void (*foo[10])();
+#endif
+
+#if TRY & 4
+ if(goo == moo) {
+ exit(0);
+ }
+#endif
+ exit(0);
+}
+main() { sub(); }
+EOCP
+ if $cc $ccflags -c -DTRY=$defvoidused try.c >.out 2>&1 ; then
+ voidflags=$defvoidused
+ echo "It appears to support void to the level $package wants ($defvoidused)."
+ if $contains warning .out >/dev/null 2>&1; then
+ echo "However, you might get some warnings that look like this:"
+ $cat .out
+ fi
+ else
+echo "Hmm, your compiler has some difficulty with void. Checking further..." >&4
+ if $cc $ccflags -c -DTRY=1 try.c >/dev/null 2>&1; then
+ echo "It supports 1..."
+ if $cc $ccflags -c -DTRY=3 try.c >/dev/null 2>&1; then
+ echo "It also supports 2..."
+ if $cc $ccflags -c -DTRY=7 try.c >/dev/null 2>&1; then
+ voidflags=7
+ echo "And it supports 4 but not 8 definitely."
+ else
+ echo "It doesn't support 4..."
+ if $cc $ccflags -c -DTRY=11 try.c >/dev/null 2>&1; then
+ voidflags=11
+ echo "But it supports 8."
+ else
+ voidflags=3
+ echo "Neither does it support 8."
+ fi
+ fi
+ else
+ echo "It does not support 2..."
+ if $cc $ccflags -c -DTRY=13 try.c >/dev/null 2>&1; then
+ voidflags=13
+ echo "But it supports 4 and 8."
+ else
+ if $cc $ccflags -c -DTRY=5 try.c >/dev/null 2>&1; then
+ voidflags=5
+ echo "And it supports 4 but has not heard about 8."
+ else
+ echo "However it supports 8 but not 4."
+ fi
+ fi
+ fi
+ else
+ echo "There is no support at all for void."
+ voidflags=0
+ fi
+ fi
+esac
+case "$voidflags" in
+"$defvoidused") ;;
+*)
+ dflt="$voidflags";
+ rp="Your void support flags add up to what?"
+ . ./myread
+ voidflags="$ans"
+ ;;
+esac
+$rm -f try.* .out
+
+: determine lexical analyser generator
+case "$lex" in
+'')
+ dflt=lex;;
+*)
+ dflt="$lex";;
+esac
+echo " "
+if $test -f "$flex"; then
+ rp='Which lexical analyser generator (lex or flex) shall I use?'
+else
+ rp='Which lexical analyser generator shall I use?'
+fi
+. ./myread
+lex="$ans"
+
+: if using lex this will normally be useless, but flex frequently takes args
+echo " "
+case "$lexflags" in
+'') dflt='none';;
+*) dflt="$lexflags";;
+esac
+rp="What flags should be given to $lex?"
+. ./myread
+case "$ans" in
+none) lexflags='';;
+*) lexflags="$ans";;
+esac
+
+: determine compiler compiler
+case "$yacc" in
+'')
+ dflt=yacc;;
+*)
+ dflt="$yacc";;
+esac
+echo " "
+comp='yacc'
+if $test -f "$byacc"; then
+ dflt="$byacc"
+ comp="byacc or $comp"
+fi
+if $test -f "$bison"; then
+ comp="$comp or bison -y"
+fi
+rp="Which compiler compiler ($comp) shall I use?"
+. ./myread
+yacc="$ans"
+case "$yacc" in
+*bis*)
+ case "$yacc" in
+ *-y*) ;;
+ *)
+ yacc="$yacc -y"
+ echo "(Adding -y option to bison to get yacc-compatible behaviour.)"
+ ;;
+ esac
+ ;;
+esac
+
+: see if we need extra yacc flags
+dflt="$yaccflags"
+case "$dflt" in
+'') dflt=none;;
+esac
+$cat <<EOH
+
+Your yacc program may need extra flags to normally process the parser sources.
+Do NOT specify any -d or -v flags here, since those are explicitely known
+by the various Makefiles. However, if your machine has strange/undocumented
+options (like -Sr# on SCO to specify the maximum number of grammar rules), then
+please add them here. To use no flags, specify the word "none".
+
+EOH
+rp="Any additional yacc flags?"
+. ./myread
+case "$ans" in
+none) yaccflags='';;
+*) yaccflags="$ans";;
+esac
+
+: see if we should include -ly
+echo " "
+case "$yacc" in
+*byacc*)
+ echo "You are using byacc, so I won't look for a yacc library." >&4
+ libyacc=''
+ ;;
+*yacc)
+ xxx=`./loc liby$_a x $libpth`
+ case "$xxx" in
+ x)
+ echo "No yacc library found." >&4
+ libyacc=''
+ ;;
+ *)
+ echo "yacc library found in $xxx." >&4
+ libyacc="$xxx"
+ ;;
+ esac
+ ;;
+*bison*)
+ echo "You are using bison, so I won't look for a yacc library." >&4
+ libyacc=''
+ ;;
+*)
+echo "You don't seem to have yacc, so I won't look for the yacc library." >&4
+ libyacc=''
+ ;;
+esac
+
+: find out how to generate dependencies
+echo " "
+echo "Checking how to generate makefile dependencies on your machine..." >&4
+toplev=`cd ..;pwd`
+$cat >dep.c <<'EOCP'
+#include "dep.h"
+EOCP
+$cat >dep.h <<'EOCP'
+
+EOCP
+takeflags='flags=""
+case "$@" in
+*--*)
+ for arg
+ do
+ shift
+ case "$arg" in
+ --) break;;
+ *) flags="$flags $arg";;
+ esac
+ done;;
+esac'
+case "$mkdep" in
+'')
+ ;;
+*)
+ if test -x "$mkdep" &&
+ $mkdep dep.c >dep.out 2>/dev/null &&
+ $contains "dep$_o:.*dep\.h" dep.out >/dev/null 2>&1
+ then
+ echo "$mkdep works."
+ else
+ mkdep=
+ fi
+esac
+
+case "$mkdep" in
+'')
+ $spitshell > ../mkdep <<EOM
+$startsh
+$takeflags
+for srcfile
+do
+ $cpp -M -I. $cppflags \$flags \$srcfile 2>/dev/null
+done
+exit 0
+EOM
+ mkdep=$toplev/mkdep
+ chmod +x $mkdep
+ $eunicefix $mkdep
+ if $mkdep dep.c >dep.out 2>/dev/null &&
+ $contains "dep$_o:.*dep\.h" dep.out >/dev/null 2>&1
+ then
+ echo "Looks like we can use $cpp -M."
+ else
+ mkdep=
+ fi
+ ;;
+esac
+
+case "$mkdep" in
+'')
+ $spitshell > ../mkdep <<EOM
+$startsh
+$takeflags
+for srcfile
+do
+ $cc -MM -I. $cppflags \$flags \$srcfile 2>/dev/null
+done
+exit 0
+EOM
+ mkdep=$toplev/mkdep
+ chmod +x $mkdep
+ $eunicefix $mkdep
+ if $mkdep dep.c >dep.out 2>/dev/null &&
+ $contains "dep$_o: dep.h" dep.out >/dev/null 2>&1
+ then
+ echo "Looks like we can use $cc -MM."
+ else
+ mkdep=
+ fi
+ ;;
+esac
+
+case "$mkdep" in
+'')
+ $spitshell >../mkdep <<EOS
+$startsh
+$takeflags
+for srcfile
+do
+ case "\$srcfile" in
+ *.c) c='.c';;
+ *.y) c='.y';;
+ *.l) c='.l';;
+ esac
+ filebase=\`basename \$srcfile \$c\`
+ <\$srcfile $cpp $cppminus $cppflags -I. \$flags 2>/dev/null | \\
+ $sed -e '/^# *[0-9]/!d' \\
+ -e 's/^.*"\(.*\)".*\$/'\$filebase'$_o: \1/' \\
+ -e 's|: \./|: |' \\
+ -e 's|: *$|: '\$srcfile'|' | \\
+ $grep -v '^#' | $sort | $uniq
+done
+exit 0
+EOS
+ mkdep=$toplev/mkdep
+ chmod +x $mkdep
+ $eunicefix $mkdep
+ if $mkdep dep.c >dep.out 2>/dev/null &&
+ $contains "dep$_o:.*dep\.h" dep.out >/dev/null 2>&1
+ then
+ echo "A shell script using $cpp does the trick."
+ else
+ echo "$cpp doesn't seem to be any use at all."
+ $spitshell >../mkdep <<EOS
+$startsh
+$takeflags
+files="\$@"
+set X \$flags
+shift
+inc='.'
+while test \$# -gt 0
+do
+ case "\$1" in
+ -I)
+ shift
+ inc="\$inc:\$1"
+ ;;
+ -I*)
+ dir=\`echo \$1 | sed -e 's/^-I//'\`
+ inc="\$inc:\$dir"
+ ;;
+ esac
+ shift
+done
+set X \$files
+shift
+trap "$rm -f /tmp/mkdep\$\$; exit 1" 1 2 3 15
+for srcfile
+do
+ case "\$srcfile" in
+ *.c) c='.c';;
+ *.y) c='.y';;
+ *.l) c='.l';;
+ esac
+ filebase=\`basename \$srcfile \$c\`
+ echo \$filebase$_o: \$srcfile
+ $grep '^#[ ]*include' \$srcfile /dev/null | \
+ $sed -n -e 's/#[ ]*include[ ]*//' \\
+ -e '/<\(.*\)>/ d' \\
+ -e 's/:[^"]*"\([^"]*\)".*/: \1/' \\
+ -e "s/\\.c:/$_o:/p" > /tmp/mkdep\$\$
+ IFS=': '
+ while read file dep; do
+ for dir in \$inc; do
+ if $test -f "\$dir/\$dep"; then
+ dep="\$dir/\$dep"
+ break
+ fi
+ done
+ echo "\$file: \$dep" | $sed -e 's,: \./,: ,'
+ done </tmp/mkdep\$\$
+ IFS=' '
+ $rm -f /tmp/mkdep\$\$
+done
+exit 0
+EOS
+ mkdep=$toplev/mkdep
+ chmod +x $mkdep
+ $eunicefix $mkdep
+ if $mkdep dep.c >dep.out 2>/dev/null &&
+ $contains "dep$_o:.*dep\.h" dep.out >/dev/null 2>&1
+ then
+ cat << EOM
+
+I can use a script with grep instead, but it will make some incorrect
+dependencies, since it doesn't understand about conditional compilation.
+Moreover, some dependencies may be missing, because scanning won't be
+a recursive process.
+If you have a program which generates makefile dependencies, you may want
+to use it. If not, you can use the script and edit the Makefile by hand
+if you need to.
+EOM
+ else
+ mkdep=
+ cat << EOM
+
+I can't seem to generate makefile dependencies at all! Perhaps you have a
+program that does? If you don't, you might look at the mkdep script to
+see if you can create one which works.
+EOM
+ fi
+ fi
+esac
+dflt="$mkdep"
+fn=f~/
+rp="Name of program to make makefile dependencies?"
+. ./getfile
+mkdep="$ans"
+$rm -f dep.c dep.h dep$_o dep.out
+
+: Cruising for prototypes
+echo " "
+echo "Checking out function prototypes..." >&4
+$cat >prototype.c <<'EOCP'
+main(int argc, char *argv[]) {
+ exit(0);}
+EOCP
+if $cc $ccflags -c prototype.c >prototype.out 2>&1 ; then
+ echo "Your C compiler appears to support function prototypes."
+ val="$define"
+else
+ echo "Your C compiler doesn't seem to understand function prototypes."
+ val="$undef"
+fi
+set prototype
+eval $setvar
+$rm -f prototype*
+
+: see if signal is declared as pointer to function returning int or void
+echo " "
+xxx=`./findhdr signal.h`
+$test "$xxx" && $cppstdin $cppminus $cppflags < $xxx >$$.tmp 2>/dev/null
+if $contains 'int.*\*[ ]*signal' $$.tmp >/dev/null 2>&1 ; then
+ echo "You have int (*signal())() instead of void." >&4
+ val="$undef"
+elif $contains 'void.*\*[ ]*signal' $$.tmp >/dev/null 2>&1 ; then
+ echo "You have void (*signal())() instead of int." >&4
+ val="$define"
+elif $contains 'extern[ ]*[(\*]*signal' $$.tmp >/dev/null 2>&1 ; then
+ echo "You have int (*signal())() instead of void." >&4
+ val="$undef"
+else
+ case "$d_voidsig" in
+ '')
+ echo "I can't determine whether signal handler returns void or int..." >&4
+ dflt=void
+ rp="What type does your signal handler return?"
+ . ./myread
+ case "$ans" in
+ v*) val="$define";;
+ *) val="$undef";;
+ esac;;
+ "$define")
+ echo "As you already told me, signal handler returns void." >&4;;
+ *)
+ echo "As you already told me, signal handler returns int." >&4;;
+ esac
+fi
+set d_voidsig
+eval $setvar
+case "$d_voidsig" in
+"$define") signal_t="void";;
+*) signal_t="int";;
+esac
+$rm -f $$.tmp
+
+: define an is-a-typedef? function
+typedef='type=$1; var=$2; def=$3; shift; shift; shift; inclist=$@;
+case "$inclist" in
+"") inclist="sys/types.h";;
+esac;
+eval "varval=\$$var";
+case "$varval" in
+"")
+ $rm -f temp.c;
+ for inc in $inclist; do
+ echo "#include <$inc>" >>temp.c;
+ done;
+ $cppstdin $cppflags $cppminus < temp.c >temp.E 2>/dev/null;
+ if $contains $type temp.E >/dev/null 2>&1; then
+ eval "$var=\$type";
+ else
+ eval "$var=\$def";
+ fi;
+ $rm -f temp.?;;
+*) eval "$var=\$varval";;
+esac'
+
+: see if time exists
+echo " "
+if set time val -f d_time; eval $csym; $val; then
+ echo 'time() found.' >&4
+ val="$define"
+ set time_t timetype long stdio.h sys/types.h
+ eval $typedef
+ dflt="$timetype"
+ echo " "
+ rp="What type is returned by time() on this system?"
+ . ./myread
+ timetype="$ans"
+else
+ echo 'time() not found, hope that will do.' >&4
+ val="$undef"
+ timetype='int';
+fi
+set d_time
+eval $setvar
+
+: see if stdarg is available
+echo " "
+if $test `./findhdr stdarg.h`; then
+ echo "<stdarg.h> found." >&4
+ valstd="$define"
+else
+ echo "<stdarg.h> NOT found." >&4
+ valstd="$undef"
+fi
+
+: see if varags is available
+echo " "
+if $test `./findhdr varargs.h`; then
+ echo "<varargs.h> found." >&4
+else
+ echo "<varargs.h> NOT found, but that's ok (I hope)." >&4
+fi
+
+: set up the varargs testing programs
+$cat > varargs.c <<EOP
+#ifdef I_STDARG
+#include <stdarg.h>
+#endif
+#ifdef I_VARARGS
+#include <varargs.h>
+#endif
+
+#ifdef I_STDARG
+int f(char *p, ...)
+#else
+int f(va_alist)
+va_dcl
+#endif
+{
+ va_list ap;
+#ifndef I_STDARG
+ char *p;
+#endif
+#ifdef I_STDARG
+ va_start(ap,p);
+#else
+ va_start(ap);
+ p = va_arg(ap, char *);
+#endif
+ va_end(ap);
+}
+EOP
+$cat > varargs <<EOP
+$startsh
+if $cc -c $ccflags -D\$1 varargs.c >/dev/null 2>&1; then
+ echo "true"
+else
+ echo "false"
+fi
+$rm -f varargs$_o
+EOP
+chmod +x varargs
+
+: now check which varargs header should be included
+echo " "
+i_varhdr=''
+case "$valstd" in
+"$define")
+ if `./varargs I_STDARG`; then
+ val='stdarg.h'
+ elif `./varargs I_VARARGS`; then
+ val='varargs.h'
+ fi
+ ;;
+*)
+ if `./varargs I_VARARGS`; then
+ val='varargs.h'
+ fi
+ ;;
+esac
+case "$val" in
+'')
+echo "I could not find the definition for va_dcl... You have problems..." >&4
+ val="$undef"; set i_stdarg; eval $setvar
+ val="$undef"; set i_varargs; eval $setvar
+ ;;
+*)
+ set i_varhdr
+ eval $setvar
+ case "$i_varhdr" in
+ stdarg.h)
+ val="$define"; set i_stdarg; eval $setvar
+ val="$undef"; set i_varargs; eval $setvar
+ ;;
+ varargs.h)
+ val="$undef"; set i_stdarg; eval $setvar
+ val="$define"; set i_varargs; eval $setvar
+ ;;
+ esac
+ echo "We'll include <$i_varhdr> to get va_dcl definition." >&4;;
+esac
+$rm -f varargs*
+
+: see if prototypes support variable argument declarations
+echo " "
+case "$prototype$i_stdarg" in
+$define$define)
+ echo "It appears we'll be able to prototype varargs functions." >&4
+ val="$define"
+ ;;
+*)
+ echo "Too bad... We won't be using prototyped varargs functions..." >&4
+ val="$undef"
+ ;;
+esac
+set vaproto
+eval $setvar
+
+$cat <<EOH
+
+You may wish to compile with extra compiler warnings enabled.
+Note that doing so enhances your chance of receiving your free set of steak
+knives, particularly if you find any bugs and report them.
+If you don't want extra warnings, answer "none".
+
+EOH
+case "$warnflags" in
+'') case "$cc" in
+ *gcc*)
+ dflt="-Wall -Wno-comment"
+ if $contains 'fprintf' `./findhdr stdio.h` >/dev/null 2>&1; then
+ :
+ else
+ dflt="$dflt -Wno-implicit"
+ fi
+ ;;
+ *) dflt="none";;
+ esac
+ ;;
+' ') dflt="none";;
+*) dflt="$warnflags";;
+esac
+
+rp="Any $cc flags to enable warnings?"
+. ./myread
+case "$ans" in
+none) warnflags=' ';;
+*) warnflags="$ans";;
+esac
+
+: define an alternate in-header-list? function
+inhdr='echo " "; td=$define; tu=$undef; yyy=$@;
+cont=true; xxf="echo \"<\$1> found.\" >&4";
+case $# in 2) xxnf="echo \"<\$1> NOT found.\" >&4";;
+*) xxnf="echo \"<\$1> NOT found, ...\" >&4";;
+esac;
+case $# in 4) instead=instead;; *) instead="at last";; esac;
+while $test "$cont"; do
+ xxx=`./findhdr $1`
+ var=$2; eval "was=\$$2";
+ if $test "$xxx" && $test -r "$xxx";
+ then eval $xxf;
+ eval "case \"\$$var\" in $undef) . ./whoa; esac"; eval "$var=\$td";
+ cont="";
+ else eval $xxnf;
+ eval "case \"\$$var\" in $define) . ./whoa; esac"; eval "$var=\$tu"; fi;
+ set $yyy; shift; shift; yyy=$@;
+ case $# in 0) cont="";;
+ 2) xxf="echo \"but I found <\$1> $instead.\" >&4";
+ xxnf="echo \"and I did not find <\$1> either.\" >&4";;
+ *) xxf="echo \"but I found <\$1\> instead.\" >&4";
+ xxnf="echo \"there is no <\$1>, ...\" >&4";;
+ esac;
+done;
+while $test "$yyy";
+do set $yyy; var=$2; eval "was=\$$2";
+ eval "case \"\$$var\" in $define) . ./whoa; esac"; eval "$var=\$tu";
+ set $yyy; shift; shift; yyy=$@;
+done'
+
+: see if this is a sys/file.h system
+val=''
+set sys/file.h val
+eval $inhdr
+
+: do we need to include sys/file.h ?
+case "$val" in
+"$define")
+ echo " "
+ if $h_sysfile; then
+ val="$define"
+ echo "We'll be including <sys/file.h>." >&4
+ else
+ val="$undef"
+ echo "We won't be including <sys/file.h>." >&4
+ fi
+ ;;
+*)
+ h_sysfile=false
+ ;;
+esac
+set i_sysfile
+eval $setvar
+
+: see if fcntl.h is there
+val=''
+set fcntl.h val
+eval $inhdr
+
+: see if we can include fcntl.h
+case "$val" in
+"$define")
+ echo " "
+ if $h_fcntl; then
+ val="$define"
+ echo "We'll be including <fcntl.h>." >&4
+ else
+ val="$undef"
+ if $h_sysfile; then
+ echo "We don't need to include <fcntl.h> if we include <sys/file.h>." >&4
+ else
+ echo "We won't be including <fcntl.h>." >&4
+ fi
+ fi
+ ;;
+*)
+ h_fcntl=false
+ val="$undef"
+ ;;
+esac
+set i_fcntl
+eval $setvar
+
+: see if stddef is available
+set stddef.h i_stddef
+eval $inhdr
+
+: see if stdlib is available
+set stdlib.h i_stdlib
+eval $inhdr
+
+: see if we should include time.h, sys/time.h, or both
+echo " "
+echo "Testing to see if we should include <time.h>, <sys/time.h> or both." >&4
+$echo $n "I'm now running the test program...$c"
+$cat >try.c <<'EOCP'
+#include <sys/types.h>
+#ifdef I_TIME
+#include <time.h>
+#endif
+#ifdef I_SYSTIME
+#ifdef SYSTIMEKERNEL
+#define KERNEL
+#endif
+#include <sys/time.h>
+#endif
+#ifdef I_SYSSELECT
+#include <sys/select.h>
+#endif
+main()
+{
+ struct tm foo;
+#ifdef S_TIMEVAL
+ struct timeval bar;
+#endif
+#ifdef S_TIMEZONE
+ struct timezone tzp;
+#endif
+ if (foo.tm_sec == foo.tm_sec)
+ exit(0);
+#ifdef S_TIMEVAL
+ if (bar.tv_sec == bar.tv_sec)
+ exit(0);
+#endif
+ exit(1);
+}
+EOCP
+flags=''
+s_timezone=''
+sysselect=''
+for s_timeval in '-DS_TIMEVAL' ''; do
+for i_systimek in '' '-DSYSTIMEKERNEL'; do
+for i_time in '' '-DI_TIME'; do
+for i_systime in '-DI_SYSTIME' ''; do
+ case "$flags" in
+ '') $echo $n ".$c"
+ if $cc $ccflags \
+ $i_time $i_systime $i_systimek $sysselect $s_timeval $s_timezone \
+ try.c -o try >/dev/null 2>&1 ; then
+ set X $i_time $i_systime $i_systimek $sysselect $s_timeval
+ shift
+ flags="$*"
+ echo " "
+ $echo $n "Succeeded with $flags$c"
+ fi
+ ;;
+ esac
+done
+done
+done
+done
+timeincl=''
+echo " "
+case "$flags" in
+*SYSTIMEKERNEL*) i_systimek="$define"
+ timeincl=`./findhdr sys/time.h`
+ echo "We'll include <sys/time.h> with KERNEL defined." >&4;;
+*) i_systimek="$undef";;
+esac
+case "$flags" in
+*I_TIME*) i_time="$define"
+ timeincl=`./findhdr time.h`" $timeincl"
+ echo "We'll include <time.h>." >&4;;
+*) i_time="$undef";;
+esac
+case "$flags" in
+*I_SYSTIME*) i_systime="$define"
+ timeincl=`./findhdr sys/time.h`" $timeincl"
+ echo "We'll include <sys/time.h>." >&4;;
+*) i_systime="$undef";;
+esac
+$rm -f try.c try
+
+: see if sys/types.h has to be included
+set sys/types.h i_systypes
+eval $inhdr
+
+: see if this is a unistd.h system
+set unistd.h i_unistd
+eval $inhdr
+
+: end of configuration questions
+echo " "
+echo "End of configuration questions."
+echo " "
+
+: back to where it started
+if test -d ../UU; then
+ cd ..
+fi
+
+: configuration may be patched via a 'config.over' file
+if $test -f config.over; then
+ echo " "
+ dflt=y
+ rp='I see a config.over file. Do you wish to load it?'
+ . UU/myread
+ case "$ans" in
+ n*) echo "OK, I'll ignore it.";;
+ *) . ./config.over
+ echo "Configuration override changes have been loaded."
+ ;;
+ esac
+fi
+
+: in case they want portability, strip down executable paths
+case "$d_portable" in
+"$define")
+ echo " "
+ echo "Stripping down executable paths..." >&4
+ for file in $loclist $trylist; do
+ eval $file="\$file"
+ done
+ ;;
+esac
+
+: create config.sh file
+echo " "
+echo "Creating config.sh..." >&4
+$spitshell <<EOT >config.sh
+$startsh
+#
+# This file was produced by running the Configure script. It holds all the
+# definitions figured out by Configure. Should you modify one of these values,
+# do not forget to propagate your changes by running "Configure -der". You may
+# instead choose to run each of the .SH files by yourself, or "Configure -S".
+#
+
+# Package name : $package
+# Source directory : $src
+# Configuration time: $cf_time
+# Configured by : $cf_by
+# Target system : $myuname
+
+Author='$Author'
+Date='$Date'
+Header='$Header'
+Id='$Id'
+Locker='$Locker'
+Log='$Log'
+Mcc='$Mcc'
+RCSfile='$RCSfile'
+Revision='$Revision'
+Source='$Source'
+State='$State'
+afs='$afs'
+ar='$ar'
+archobjs='$archobjs'
+awk='$awk'
+bash='$bash'
+bin='$bin'
+binexp='$binexp'
+bison='$bison'
+byacc='$byacc'
+c='$c'
+cat='$cat'
+cc='$cc'
+ccflags='$ccflags'
+cf_by='$cf_by'
+cf_time='$cf_time'
+chgrp='$chgrp'
+chmod='$chmod'
+chown='$chown'
+comm='$comm'
+compress='$compress'
+contains='$contains'
+cp='$cp'
+cpio='$cpio'
+cpp='$cpp'
+cppfilecom='$cppfilecom'
+cppflags='$cppflags'
+cpplast='$cpplast'
+cppminus='$cppminus'
+cpprun='$cpprun'
+cppstdin='$cppstdin'
+cppstdinflags='$cppstdinflags'
+csh='$csh'
+d_access='$d_access'
+d_attribut='$d_attribut'
+d_bsd='$d_bsd'
+d_const='$d_const'
+d_cppcanstdin='$d_cppcanstdin'
+d_cppignhdrs='$d_cppignhdrs'
+d_eunice='$d_eunice'
+d_flexfnam='$d_flexfnam'
+d_gnulibc='$d_gnulibc'
+d_index='$d_index'
+d_link='$d_link'
+d_open3='$d_open3'
+d_portable='$d_portable'
+d_strchr='$d_strchr'
+d_strftime='$d_strftime'
+d_strstr='$d_strstr'
+d_symlink='$d_symlink'
+d_time='$d_time'
+d_voidsig='$d_voidsig'
+d_volatile='$d_volatile'
+d_xenix='$d_xenix'
+date='$date'
+defvoidused='$defvoidused'
+echo='$echo'
+egrep='$egrep'
+emacs='$emacs'
+eunicefix='$eunicefix'
+expr='$expr'
+find='$find'
+firstmakefile='$firstmakefile'
+flex='$flex'
+gcc='$gcc'
+gccversion='$gccversion'
+glibpth='$glibpth'
+grep='$grep'
+gzip='$gzip'
+h_fcntl='$h_fcntl'
+h_sysfile='$h_sysfile'
+hint='$hint'
+i_fcntl='$i_fcntl'
+i_stdarg='$i_stdarg'
+i_stddef='$i_stddef'
+i_stdlib='$i_stdlib'
+i_string='$i_string'
+i_sysfile='$i_sysfile'
+i_systime='$i_systime'
+i_systimek='$i_systimek'
+i_systypes='$i_systypes'
+i_time='$i_time'
+i_unistd='$i_unistd'
+i_varargs='$i_varargs'
+i_varhdr='$i_varhdr'
+incpath='$incpath'
+inews='$inews'
+installbin='$installbin'
+installmansrc='$installmansrc'
+installprivlib='$installprivlib'
+ksh='$ksh'
+ldflags='$ldflags'
+less='$less'
+lex='$lex'
+lexflags='$lexflags'
+libc='$libc'
+libpth='$libpth'
+libs='$libs'
+libyacc='$libyacc'
+line='$line'
+lint='$lint'
+lkflags='$lkflags'
+ln='$ln'
+lns='$lns'
+locincpth='$locincpth'
+loclibpth='$loclibpth'
+lp='$lp'
+lpr='$lpr'
+ls='$ls'
+mail='$mail'
+mailx='$mailx'
+make='$make'
+manext='$manext'
+mansrc='$mansrc'
+mansrcexp='$mansrcexp'
+mips='$mips'
+mips_type='$mips_type'
+mkdep='$mkdep'
+mkdir='$mkdir'
+more='$more'
+mv='$mv'
+myuname='$myuname'
+n='$n'
+nm_opt='$nm_opt'
+nm_so_opt='$nm_so_opt'
+nroff='$nroff'
+optimize='$optimize'
+osname='$osname'
+osvers='$osvers'
+package='$package'
+perl='$perl'
+pg='$pg'
+plibpth='$plibpth'
+pmake='$pmake'
+pr='$pr'
+prefix='$prefix'
+prefixexp='$prefixexp'
+privlib='$privlib'
+privlibexp='$privlibexp'
+prototype='$prototype'
+rm='$rm'
+rmail='$rmail'
+runnm='$runnm'
+sed='$sed'
+sendmail='$sendmail'
+sh='$sh'
+shar='$shar'
+sharpbang='$sharpbang'
+shsharp='$shsharp'
+signal_t='$signal_t'
+sleep='$sleep'
+smail='$smail'
+so='$so'
+sort='$sort'
+spackage='$spackage'
+spitshell='$spitshell'
+src='$src'
+startsh='$startsh'
+strings='$strings'
+submit='$submit'
+sysman='$sysman'
+tail='$tail'
+tar='$tar'
+tbl='$tbl'
+test='$test'
+timeincl='$timeincl'
+timetype='$timetype'
+touch='$touch'
+tr='$tr'
+troff='$troff'
+uname='$uname'
+uniq='$uniq'
+usenm='$usenm'
+usrinc='$usrinc'
+uuname='$uuname'
+vaproto='$vaproto'
+vi='$vi'
+voidflags='$voidflags'
+warnflags='$warnflags'
+xlibpth='$xlibpth'
+yacc='$yacc'
+yaccflags='$yaccflags'
+zcat='$zcat'
+zip='$zip'
+EOT
+
+: add special variables
+$test -f $src/patchlevel.h && \
+awk '/^#define/ {printf "%s=%s\n",$2,$3}' $src/patchlevel.h >>config.sh
+echo "CONFIG=true" >>config.sh
+
+: propagate old symbols
+if $test -f UU/config.sh; then
+ <UU/config.sh sort | uniq >UU/oldconfig.sh
+ sed -n 's/^\([a-zA-Z_0-9]*\)=.*/\1/p' config.sh config.sh UU/oldconfig.sh |\
+ sort | uniq -u >UU/oldsyms
+ set X `cat UU/oldsyms`
+ shift
+ case $# in
+ 0) ;;
+ *)
+ cat <<EOM
+Hmm...You had some extra variables I don't know about...I'll try to keep 'em...
+EOM
+ echo "# Variables propagated from previous config.sh file." >>config.sh
+ for sym in `cat UU/oldsyms`; do
+ echo " Propagating $hint variable "'$'"$sym..."
+ eval 'tmp="$'"${sym}"'"'
+ echo "$tmp" | \
+ sed -e "s/'/'\"'\"'/g" -e "s/^/$sym='/" -e "s/$/'/" >>config.sh
+ done
+ ;;
+ esac
+fi
+
+: Finish up by extracting the .SH files
+case "$alldone" in
+exit)
+ $rm -rf UU
+ echo "Done."
+ exit 0
+ ;;
+cont)
+ ;;
+'')
+ dflt=''
+ nostick=true
+ $cat <<EOM
+
+If you'd like to make any changes to the config.sh file before I begin
+to configure things, do it as a shell escape now (e.g. !vi config.sh).
+
+EOM
+ rp="Press return or use a shell escape to edit config.sh:"
+ . UU/myread
+ nostick=''
+ case "$ans" in
+ '') ;;
+ *) : in case they cannot read
+ sh 1>&4 -c "$ans";;
+ esac
+ ;;
+esac
+
+: if this fails, just run all the .SH files by hand
+. ./config.sh
+
+echo " "
+exec 1>&4
+. ./UU/extract
+
+if $contains '^depend:' [Mm]akefile >/dev/null 2>&1; then
+ dflt=y
+ case "$silent" in
+ true) ;;
+ *)
+ $cat <<EOM
+
+Now you need to generate make dependencies by running "make depend".
+You might prefer to run it in background: "make depend > makedepend.out &"
+It can take a while, so you might not want to run it right now.
+
+EOM
+ ;;
+ esac
+ rp="Run make depend now?"
+ . UU/myread
+ case "$ans" in
+ y*)
+ make depend && echo "Now you must run a make."
+ ;;
+ *)
+ echo "You must run 'make depend' then 'make'."
+ ;;
+ esac
+elif test -f [Mm]akefile; then
+ echo " "
+ echo "Now you must run a make."
+else
+ echo "Done."
+fi
+
+$rm -f kit*isdone ark*isdone
+$rm -rf UU
+
+: End of Configure
+
diff --git a/FAQ b/FAQ
new file mode 100644
index 0000000..8abf1d3
--- /dev/null
+++ b/FAQ
@@ -0,0 +1,204 @@
+Frequently Asked Questions about c2man
+--------------------------------------
+By Graham Stoney (greyham@research.canon.com.au)
+Last-modified: $Date: 2004-05-03 05:17:49 $
+
+Q. Where can I get an up-to-date already patched copy of c2man?
+
+A. You can usually get the latest version via ftp:
+ ftp /pub/Unix/Util/c2man-2.0.*.tar.gz from dnpap.et.tudelft.nl
+
+ Many thanks to Richard Kooijman <R.Kooijman@et.tudelft.nl> for providing
+ the ftp site, and keeping it up to date. The very latest version probably
+ won't be available until a short time after each patch is issued, since
+ we're relying on Richard's kindness to apply the patches and keep the tar
+ file up to date manually.
+
+ You can also retrieve the latest version via the author's mail server, by
+ mailing to greyham@research.canon.com.au with a message like:
+
+ Subject: Command
+ @PACK shar
+ @SH maildist - c2man 2.0
+
+ In reply, you can expect on the order of 9 or so mail messages, each around
+ 55 K long. You'll also have the extra hassle of unpacking it. Detailed
+ instructions on using the mail server can be obtained by mailing to the
+ same with address a message like:
+
+ Subject: Command
+ @SH mailhelp -
+
+ It should also be available in your local comp.sources.misc archive. The
+ versions in the alt.sources and comp.sources.reviewed archives are
+ obsolete. One day soon I'll be able to put it up for ftp here directly.
+
+
+Q. How do I remove myself from the c2man discussion list?
+
+A. You should have received instructions on how to do this when you joined the
+ list. It's always wise to save a copy of the instructions you receive when
+ you join a mailing list, so that you can refer to them in future when you
+ wish to leave.
+
+ To remove yourself from the c2man discussion list, send E-mail to:
+ listserv@research.canon.com.au
+
+ With the message:
+ Subject:
+ unsubscribe c2man
+
+ You should also be able to unsubscribe be running Configure again, and
+ asking it to unsubscribe you when it asks if you wish to subscribe to, or
+ unsubscribe from the mailing list.
+
+ Note that the discussion list and the automatic patch notification/update
+ list are completely independant.
+
+
+Q. How do I remove myself from the c2man automatic patch notification/update
+ list?
+
+A. If you don't wish to receive future notification or mailing of new patches,
+ you need to send a message to the author's personal mail server. In other
+ words, you send E-mail to:
+ greyham@research.canon.com.au
+
+ With the message:
+ Subject: Command
+ @SH package - c2man
+
+ You can also achieve the same effect by running Configure and asking that
+ future patches not be sent to you. You may also alter your notification
+ vs update preference via Configure.
+
+
+Q. Can c2man handle C++? Is anyone working on a version that can?
+
+A. No, it can't handle C++, although there are other tools that do a similar
+ job for C++. A few people have expressed interest, but I don't know of
+ anyone who is actively working on it. If you look in the file C++autodoc in
+ the distribution, you'll get all the gory details. This file is always kept
+ up-to-date with the current state of play.
+
+
+Q. How do I apply the official patches to c2man?
+
+A. You need the patch program, by Larry Wall. Chances are that it's already
+ installed on your system; if not, you could ask your system administrator
+ about getting it, or search for it using archie if you know how. Once
+ you've got it, follow the instructions in each of the patch headers. For
+ example, patch 10 says:
+
+ Fix: From rn, say "| patch -p -N -d DIR", where DIR is your c2man source
+ directory. Outside of rn, say "cd DIR; patch -p -N <thisarticle".
+ If you don't have the patch program, apply the following by hand,
+ or get patch (version 2.0, latest patchlevel).
+
+ In other words, 'cd' to your c2man directory and type:
+ patch -p -N < patch10
+
+ That should feed the patch into the patch program, which will apply it. You
+ also need to take care to follow the "After Patching" instructions in each
+ patch, and repeat this procedure for each patch. In general, you can apply
+ all the patches without having to re-run Configure after every patch set,
+ although you must run Configure after patch30, because it renames a few
+ files. You can apply patches 10 through 30 without having to run Configure
+ though. The "After patching" instructions assume that you apply patches as
+ they are issued; you don't generally have to do them multiple times if
+ you're applying a whole group of patch sets.
+
+
+Q. Can c2man document structure fields automatically, like it does for enums?
+
+A. In short, No.
+
+ This is a very logical extension; so much so in fact that I'd say it's
+ absence in the current version is a real deficiency. I'm not sure if you
+ always want the structure contents listed in the manual page for the
+ functions that use the type though, since some interfaces use "opaque"
+ types, where the structure contents is deliberately hidden from the user;
+ eg: the stdio FILE type. My thoughts were to generate a separate manual
+ page for each struct or type definition, with perhaps an option to include
+ the info in all the functional manual pages using that type, as now happens
+ with enum types now.
+
+ Adding struct support to the current grammar should be fairly easy; mainly
+ by copying what it does with enum's; and it would certainly be very
+ worthwhile. I'd encourage anyone who'd like to see greater functionality in
+ c2man to feel free to add it in, and send me the diffs.
+
+ Sorry, this doesn't work at present. It's probably the most serious
+ omission from the program; lots of people have asked about this. At
+ present, I don't know when it's likely to be fixed. I might suddenly get
+ really keen one day and do it -- otherwise, someone else will have to
+ implement it and send me the diffs. It shouldn't be too hard, but it's a
+ matter of making it a priority and getting around to actually doing it...
+
+
+Q. Why do my functions using ``FILE *'' get documented with this weird
+ ``struct _iobuf'' type?
+
+A. Unfortunately, many systems use a #define for ``FILE'' in stdio.h to rename
+ it to ``struct _iobuf'', rather than using a typedef. Since c2man sees the
+ output of the pre-processor, ``FILE'' is long gone before it reads the
+ code, and so the documentation that it generates is misleading.
+
+ Some stdio.h's perform this #define conditionally, so it may be possible to
+ pass certain -D flags to c2man which will cause stdio.h to use a typedef
+ instead, although this will be very system-dependant.
+
+ I don't know of a really good solution to this problem, but I'd be
+ interested to hear if anyone has one.
+
+
+Q. How can I get c2man recognise and document #defines?
+
+A. c2man doesn't recognise #defines at all, but you can rewrite it as an enum.
+ You do need to be able to change the type passed to an enum though, to get
+ c2man to recognise that it's what's being passed. C is very loose with its
+ enums, so it's still just as flexible as the #define case, and the types
+ look more self-documenting in the code too:
+
+ enum Bits
+ {
+ BIT0 = 1, /* The first bit */
+ BIT1 = 2, /* The next bit */
+ BIT2 = 4 /* The last bit */
+ };
+
+ /* set the bits! */
+ void set_bits( enum Bits bits );
+
+ Gives you:
+
+ set_bits(3) UNIX Programmer's Manual set_bits(3)
+
+ NAME
+ set_bits - set the bits!
+
+ SYNOPSIS
+ #include <set_bits.h>
+
+ void set_bits(enum Bits bits);
+
+ PARAMETERS
+ enum Bits bits
+ Possible values for an enum Bits are as follows:
+ BIT0 The first bit.
+ BIT1 The next bit.
+ BIT2 The last bit.
+
+ DESCRIPTION
+ Set the bits!.
+
+
+Q. But what if my function returns an errno-like code which can take many
+ values, but I'd like the documentation to list only those that the function
+ in question can actually generate?
+
+A. c2man makes a crude attempt at identifying token/value lists in the RETURNS
+ section from the comment describing the function. If the first thing on a
+ line in the RETURNS section is a single token followed a ':' or TAB
+ character, c2man interprets it as a token list and attempts to format it
+ accordingly. Have a look at the file "eg/reterrno.h" for an exmple.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..3f4622a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,74 @@
+INSTALLING c2man:
+
+1. For OS/2 and MSDOS, see the README.pc file in the pc directory.
+
+ For all flavours of Unix, run Configure and answer the questions.
+ Most of the time the default answers should do the trick, but here's some
+ tips; If you're using...
+
+ANSI-C: Don't put the compiler in strict ISO/ANSI mode, since c2man uses a few
+ UNIX-isms that may disappear from your header files if you do that
+ (eg: popen). Don't use -ansi on gcc for example.
+
+gcc: Do yourself a favour and use the latest version of gcc (>= 2.3.3).
+ If you use -Wall, also use -Wno-implicit if your system header files
+ don't declare basic stuff like fprintf in stdio.h (SunOS Release 4.1.2
+ for example!).
+
+bison: If you get link errors reporting `alloca' as undefined, try specifying
+ -lPW when Configure asks `Any additional libraries?'.
+
+flex: You may need to specify -lfl when asked `Any additional libraries?'.
+ Flex versions 2.3 and older will cause c2man to hang if it encounters
+ an 8 bit character in the input file. If you require 8-bit character
+ support, use the flex flag '-8' (this is the default for flex 2.4).
+
+Sun: Sun yacc outputs old prototypes for malloc and free (says they return
+ char * instead of void *), which conflict with the correct ones flex 2.3
+ generates if you use gcc. To make matters worse, gcc 2.2 errors on the
+ old prototypes even if you don't use flex. Use bison instead, or just
+ delete the incorrect prototypes on the first line of y.tab.c when the
+ make errors. If you use gcc 2.2, just upgrade your gcc.
+
+HPUX: When using cc, don't specify -Aa. Adding -D_HPUX_SOURCE may help too.
+ If you use the optional c89 compiler instead of standard cc, specify
+ -D_INCLUDE_POSIX_SOURCE -D_INCLUDE_XOPEN_SOURCE as your compiler flags.
+
+dbmalloc:
+ Specify a compiler flag of -DDBMALLOC (and optimization -g if you like)
+ and a library of -ldbmalloc for maximum checking. Don't use dbmalloc
+ with gcc and flex, or y.tab.c will fail to build; just use lex instead.
+ Don't use the shared version of your C library (eg: -lc_s), as
+ Configure will by default, lest you get multiply defined symbols.
+
+Interactive Unix 2.2:
+ If you use gcc (which requires -posix) ignore the warnings about
+ popen/pclose not being defined - apparently they aren't in POSIX.
+
+NeXT: In NeXTstep 3.1 and greater, `cc -C -E' is broken; tell Configure to
+ run the preprocessor as `/lib/cpp -C' or `cc -C -E -traditional-cpp'.
+ On NeXTstep 3.2, don't link with -lposix. It's busted. Sigh.
+
+Otherwise, If you get any errors or warnings, please report them to me (with
+fixes if possible!). Don't worry too much about warnings from y.tab.c or
+lex.yy.c though, since they're generally at the mercy of your yacc & lex.
+
+2. run make depend, if you didn't do it at the end of Configure.
+
+3. run make
+
+4. format (and read) the manual page in c2man.1.
+ The examples in it are automatically generated, so check that it looks OK.
+
+5. Optionally, run "make test > /dev/null" if you don't want to wade though
+ heaps of output, or "make test | nroff -man | more" if you do. This runs
+ c2man over the examples, and on its own source. The test is assumed to pass
+ if it doesn't error or dump core.
+
+ If the preprocessor you told Configure that c2man is to use is different to
+ the one used to when compiling c2man itself, the test may fail because the
+ definitions in config.h may not match the preprocessor c2man will run
+ during the test and in normal use.
+
+6. As root, do "make install". This will install the c2man binary, the example
+ files and the manual page.
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..cb3907e
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,64 @@
+README Start here.
+ChangeLog Log of recent changes.
+INSTALL How to install it.
+FAQ Frequently Asked Questions about c2man, with Answers.
+C++autodoc An article describing how C++ support could be added.
+MANIFEST This list of all files in the package.
+Configure Automated installation script.
+c2man.man Source for the manual pages; needs flattening.
+Makefile.SH Produces Makefile.
+catalog Free Compilers Catalog entry for c2man.
+example.h First example header file for the manual page.
+ctype_ex.h Second example header file for the manual page.
+flatten.SH Produces sed script to flatten c2man.1 for installation.
+fixexamp.in Commented sed script to format man page examples.
+lex.l Lexical analyser.
+grammar.y Parser.
+config_h.SH Produces config.h, the portability header.
+patchlevel.h The current patch level.
+confmagic.h Further portability magic brought to you by metaconfig.
+c2man.h Source code...
+semantic.h
+symbol.h
+strconcat.h
+manpage.h
+enum.h
+c2man.c
+semantic.c
+string.c
+symbol.c
+strconcat.c
+manpage.c
+enum.c
+strappend.c
+strappend.h
+output.h Format-independant interface to backends.
+nroff.c Backend for nroff output.
+texinfo.c Backend for texinfo output.
+latex.c Backend for LaTeX output.
+html.c Backend for HTML output.
+autodoc.c Backend for AutoDoc output.
+libc/README.libc Info about library routines which may help.
+libc/COPYING GPL to cover the GNU-derived library routines.
+libc/getopt.c getopt support for OS/2, MSDOS & VMS.
+libc/getopt.h ...
+libc/getopt1.c ...
+libc/alloca.c Portable alloca() routine.
+eg/boxcomment.c Example input files...
+eg/ccomment.h
+eg/commentaft.c
+eg/cppcomment.h
+eg/dash.h
+eg/ellipsis.c
+eg/grouped.c
+eg/multidecl.c
+eg/namedash.h
+eg/oldstyle.c
+eg/returnerr.h
+eg/returnlist.h
+eg/sections.c
+eg/simplesect.c
+eg/surround.c
+eg/underscore.h
+eg/variable.c
+eg/retdecl.c
diff --git a/Makefile.SH b/Makefile.SH
new file mode 100755
index 0000000..5f427cd
--- /dev/null
+++ b/Makefile.SH
@@ -0,0 +1,172 @@
+case $CONFIG in
+'')
+ if test ! -f config.sh; then
+ ln ../config.sh . || \
+ ln ../../config.sh . || \
+ ln ../../../config.sh . || \
+ (echo "Can't find config.sh."; exit 1)
+ fi 2>/dev/null
+ . ./config.sh
+ ;;
+esac
+: This forces SH files to create target in same directory as SH file.
+: This is so that make depend always knows where to find SH derivatives.
+case "$0" in
+*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
+esac
+echo "Extracting Makefile (with variable substitutions)"
+: This section of the file will have variable substitutions done on it.
+: Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!.
+: Protect any dollar signs and backticks that you do not want interpreted
+: by putting a backslash in front. You may delete these comments.
+$spitshell >Makefile <<!GROK!THIS!
+# $Id: Makefile.SH,v 1.1 2004-05-03 05:17:48 behdad Exp $
+#
+# UNIX makefile for manual page generator
+# Note: any changes made here will be lost next time Configure is run!.
+
+CC=$cc $optimize
+YACC=$yacc $yaccflags
+LEX=$lex $lexflags
+SED=$sed
+CAT=$cat
+RM=$rm
+MV=$mv
+CP=$cp
+ECHO=$echo
+MKDEP=$mkdep
+
+# where we get installed
+bin=$binexp
+privlib=$installprivlib
+
+mansrc=$mansrc
+manext=$manext
+CFLAGS=$ccflags
+WARNFLAGS=$warnflags
+LDFLAGS=$ldflags
+LIBS=$libs $liblex $libyacc
+!GROK!THIS!
+
+: In the following dollars and backticks do not need the extra backslash.
+$spitshell >>Makefile <<'!NO!SUBS!'
+
+# As Larry said, "Grrrr"
+SHELL=/bin/sh
+
+OSOURCES = config.h c2man.h semantic.h symbol.h strconcat.h \
+ strappend.h manpage.h enum.h output.h lex.l grammar.y
+DCSOURCES = c2man.c semantic.c string.c symbol.c strconcat.c \
+ strappend.c manpage.c enum.c nroff.c texinfo.c latex.c html.c \
+ autodoc.c
+SOURCES = $(OSOURCES) $(DCSOURCES)
+CSOURCES = $(DCSOURCES) y.tab.c
+OBJECTS = c2man.o semantic.o string.o symbol.o y.tab.o strconcat.o \
+ strappend.o manpage.o enum.o nroff.o texinfo.o latex.o html.o \
+ autodoc.o
+GENERATED = c2man example.inc ctype_ex.inc y.tab.c lex.yy.c y.output \
+ fixexamp.sed flatten.sed
+
+
+all: c2man c2man.1
+
+install: all
+ $(CP) c2man $(bin)
+ $(CP) c2man.1 $(mansrc)/c2man.$(manext)
+ -mkdir $(privlib)
+ chmod 755 $(privlib)
+ -mkdir $(privlib)/eg
+ chmod 755 $(privlib)/eg
+ $(CP) eg/*.[chly] $(privlib)/eg
+ chmod 755 $(privlib)/eg/*
+
+uninstall:
+ $(RM) -f $(bin)/c2man $(mansrc)/c2man.$(manext)
+ $(RM) -f $(privlib)/eg/*
+ rmdir $(privlib)/eg
+ rmdir $(privlib)
+
+c2man: $(OBJECTS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
+
+c2man.1: c2man.man c2man example.inc ctype_ex.inc flatten.sed
+ $(SED) -f flatten.sed < c2man.man > c2man.1
+
+.c.o:
+ $(CC) $(CFLAGS) $(WARNFLAGS) -c $<
+
+y.tab.c: grammar.y
+ @$(ECHO) Expect 61 shift/reduce conflicts.
+ $(YACC) grammar.y
+
+# don't compile y.tab.c with all warnings; yacc/bison are not up to it.
+y.tab.o: y.tab.c lex.yy.c
+ $(CC) $(CFLAGS) -c y.tab.c
+
+lex.yy.c: lex.l
+ $(LEX) -n lex.l
+
+example.inc: c2man example.h fixexamp.sed
+ ./c2man -o- example.h | $(SED) -f fixexamp.sed >example.inc
+
+ctype_ex.inc: c2man ctype_ex.h fixexamp.sed
+ ./c2man -o- -g ctype_ex.h | $(SED) -f fixexamp.sed >ctype_ex.inc
+
+fixexamp.sed: fixexamp.in
+ $(SED) -e '/^#/d' fixexamp.in > fixexamp.sed
+
+flatten.sed: flatten.SH config.sh
+ sh flatten.SH
+
+Makefile: Makefile.SH config.sh
+ sh Makefile.SH
+
+config.h: config_h.SH config.sh
+ sh config_h.SH
+
+TAGS: $(SOURCES)
+ etags -t $(SOURCES)
+
+clean:
+ $(RM) -f *.o *.s *.bak *~ *.log $(GENERATED) core
+
+distclean realclean: clean
+ $(RM) -f Makefile config.sh mkdep c2man.kit?
+
+lint:
+ lint -b $(CFLAGS) $(CSOURCES)
+
+print:
+ cpr $(SOURCES) | lpr -J'c2man'
+
+test: c2man
+ @echo "Running c2man over the examples..." 1>&2
+ @for file in eg/*.[chly]; do ./c2man -v -o- $$file; done
+ @echo "Running c2man over its own source code..." 1>&2
+ @for file in $(DCSOURCES); do ./c2man -v -o- $$file; done
+ @echo "Hmmm, test seemed to go OK." 1>&2
+
+depend:
+ $(SED) -e '1,/^# DO NOT/!d' < Makefile > Makefile.new
+ $(MKDEP) $(DCSOURCES) >> Makefile.new
+ - test ! -f y.tab.c -o ! -f lex.yy.c || $(MKDEP) y.tab.c >> Makefile.new
+ $(MV) -f Makefile.new Makefile
+
+# y.tab.c dependancies updated manually since it won't exist yet when make
+# depend is first run.
+y.tab.o: c2man.h
+y.tab.o: config.h
+y.tab.o: confmagic.h
+y.tab.o: enum.h
+y.tab.o: manpage.h
+y.tab.o: semantic.h
+y.tab.o: strappend.h
+y.tab.o: strconcat.h
+y.tab.o: symbol.h
+
+# DO NOT DELETE THIS LINE! make depend DEPENDS ON IT!
+c2man.o:
+ @echo "You must run a make depend first."; exit 1
+!NO!SUBS!
+chmod 755 Makefile
+$eunicefix Makefile
diff --git a/README b/README
new file mode 100644
index 0000000..a42e054
--- /dev/null
+++ b/README
@@ -0,0 +1,112 @@
+
+ c2man, Version 2
+ by Graham Stoney
+
+ Copyright (c) 1992-1996
+ Canon Information Systems Research Australia
+ All rights reserved.
+
+C2man is an automatic documentation tool that extracts comments from C source
+code to generate functional interface documentation in the same format as
+sections 2 & 3 of the Unix Programmer's Manual. It requires minimal effort from
+the programmer by looking for comments in the usual places near the objects
+they document, rather than imposing a rigid function-comment syntax or
+requiring that the programmer learn and use a typesetting language. Acceptable
+documentation can often be generated from existing code with no modifications.
+
+The program can generate nroff/troff -man, TeXinfo, LaTeX or HTML output
+directly, and should run on virtually any Unix-like system, OS/2, VMS, MSDOS or
+Amiga systems.
+
+You will need lex or flex, plus yacc or bison, and a C compiler (traditional
+K&R 1 or ISO/ANSI will do) to build the program. You'll also need a text
+formatter to format its output.
+
+This version of c2man is copyright, but may be freely redistributed and modified
+so long as:
+
+1. The names of all contributing authors remain on the documentation,
+2. All derivative works are clearly documented as such,
+3. All derivative works remain freely redistributable under the same conditions.
+
+As such, there is no warranty.
+
+The manual page includes some automatically generated examples, which will be
+missing if you try to read it before doing a make. Running make will generate
+the complete manual page, which you can then copy around freely.
+
+c2man does not currently support C++, but if you think this would be worth
+while, look in the file "C++autodoc" for information on how I envisage C++
+support could be added, and get ready to volunteer. Note that this isn't
+related to the Commodore Amiga AutoDoc backend; the name's just a coincidence.
+
+The file "FAQ" in the c2man distribution contains answers to a number of
+Frequently Asked Questions about c2man.
+
+By popular demand, there are a few trivial examples of different comment
+styles in the "eg" directory. I'm open to submissions from users too.
+
+
+There is a mailing list for c2man users; it is very low volume and has a very
+low noise content. This is the preferred place to ask questions about the
+program and discuss modifications and additions with the author and other
+users, but please check in the file "FAQ" first before asking questions on the
+list, in case I've already answered it. You are encouraged to join by sending
+mail with no Subject: line to <listserv@research.canon.com.au> containing:
+
+ SUBSCRIBE c2man Your name
+
+Where `Your name' should be replaced with your real name.
+Messages for distribution to everyone on the list should be sent to:
+<c2man@research.canon.com.au>.
+
+
+The time I have available for c2man support is rather limited, but if it lacks
+any features you require, feel free to Email me (preferably to the mailing list
+address above) asking about it. Unless you request otherwise, I will probably
+cc: to the list replies to any questions that I get mailed, to save me
+answering them again for other people. I encourage you to go ahead and make
+any changes you like and send me the diffs for inclusion in the next patch, but
+it's a good idea to ask first in case someone already has the feature you want
+in the works. In order for me to integrate your changes, they need to be
+reasonably "clean", and you'll need to update manual page as appropriate.
+
+Please try to remember to include the c2man version number in any bug reports.
+You can find it by running: c2man -V /dev/null
+
+If you'd like to be notified automatically about new releases and patches,
+answer yes to the Configure question about sending mail to the author.
+
+
+Special thanks for their direct and indirect contributions to c2man go to:
+ Larry Wall, Raphael Manfredi, Harlan Stenn and the "dist" team, for writing
+ various bits of metaconfig, which generated the Configure script.
+
+ Darrel Hankerson for the OS/2 and MSDOS ports.
+ Rick Flower for the VMS port.
+ Stefan Ruppert for the Amiga port, and AutoDoc backend.
+
+ Richard Kooijman for the LaTeX backend, and for fixing the TeXinfo backend.
+ Diab Jerius too, for more work on the TeXinfo backend.
+ Frank P.J. Ooms for the HTML backend.
+
+ Vern Paxson for his suggestions on how to handle comment lexing better.
+
+Thanks to the following people for suggestions & bug fixes is long overdue:
+ Peter (P.) Barszczewski, Carlo Tarantola, Dennis Allison,
+ Philip Yzarn de Louraille, Jerry Lieberthal, Mats Ohrman, Stefan Zimmermann,
+ Dolf Grunbauer, Lele Gaifax, Carl R. Crawford, Jhon Honce, Chris Borchert,
+ Jerry E. Dunmire, Marty Leisner, Dan Forrest, Ken Weinert, Ken Poppleton,
+ Michael Hamilton, Thomas E. Dickey, Marco Nijdam.
+
+Finally, c2man owes a huge debt to the public domain program cproto, by
+Chin Huang, from which the original code was derived.
+
+(Hmmm. This is beginning to sound like an Academy Awards night...)
+
+
+See the file "INSTALL" for Unix installation instructions.
+
+
+Graham Stoney greyham@research.canon.com.au
+Mailing List for general c2man Questions & Answers c2man@research.canon.com.au
diff --git a/autodoc.c b/autodoc.c
new file mode 100644
index 0000000..0291fc2
--- /dev/null
+++ b/autodoc.c
@@ -0,0 +1,554 @@
+/*
+** $PROJECT:
+**
+** $VER: autodoc.c 2.2 (25.01.95)
+**
+** by
+**
+** Stefan Ruppert , Windthorststra_e 5 , 65439 Flvrsheim , GERMANY
+**
+** (C) Copyright 1995
+** All Rights Reserved !
+**
+** $HISTORY:
+**
+** 25.01.95 : 002.002 : changed to patchlevel 33
+** 22.01.95 : 000.001 : initial
+*/
+
+#include "c2man.h"
+#include "manpage.h"
+#include "output.h"
+#include <ctype.h>
+
+#ifdef DEBUG
+#define D(x) x
+#else
+#define D(x)
+#endif
+
+#define MAX_TAG 10
+
+static const int linelength = 79;
+static const int tablength = 4;
+static const int indentlength = 4;
+
+static int indent = 4;
+static int list_indent = 0;
+static int column = 0;
+static int newline = FALSE;
+static int breakline = FALSE;
+static int see_also = FALSE;
+static int fileend = FALSE;
+static int acttable = -1;
+static int tablemaxtag[MAX_TAG];
+
+void autodoc_format(text)
+const char *text;
+{
+ if(see_also)
+ {
+ if(column + ((text) ? strlen(text) + 2 : 1) > linelength)
+ {
+ putchar('\n');
+ newline = TRUE;
+ }
+ }
+
+ if(newline)
+ {
+ int i;
+ column = i = indent + list_indent;
+ for(; i ; i--)
+ putchar(' ');
+ newline = FALSE;
+ }
+}
+
+void autodoc_text(text)
+const char *text;
+{
+ int br = 1;
+ autodoc_format(text);
+
+ if(!see_also || (br = strcmp(text,",\n")))
+ {
+ if(see_also < 2)
+ {
+ put_string(text);
+ column += strlen(text);
+ }
+ } else if(!br)
+ {
+ column += 2;
+ put_string(", ");
+ }
+}
+
+void autodoc_char(c)
+const int c;
+{
+ if(c != '\f')
+ {
+ autodoc_format(NULL);
+
+ if(c == '\t')
+ {
+ int i = tablength - (column % tablength);
+ column += i;
+ for(; i ; i--)
+ putchar(' ');
+ } else
+ {
+ if(see_also)
+ {
+ if(c == '(')
+ see_also++;
+ else if(c == ')')
+ see_also--;
+ }
+
+ putchar(c);
+ column++;
+ }
+
+ if((newline = (c == '\n')))
+ column = 0;
+ }
+}
+
+void autodoc_comment() { }
+
+void autodoc_header(firstpage, input_files, grouped, name, terse, section)
+ManualPage *firstpage;
+int input_files;
+boolean grouped;
+const char *name;
+const char *terse;
+const char *section;
+{
+ const char *basename = strrchr(firstpage->sourcefile, '/');
+ int len;
+ int spc;
+
+ fileend = FALSE;
+
+ if(basename && *basename == '/')
+ basename++;
+
+ len = ((basename) ? strlen(basename) + 1 : 0) + strlen(name);
+ spc = linelength - 2 * len;
+
+ see_also = FALSE;
+
+ if(basename)
+ {
+ autodoc_text(basename);
+ autodoc_char('/');
+ }
+ autodoc_text(name);
+
+ if(spc > 0)
+ {
+ while(spc)
+ {
+ autodoc_char(' ');
+ spc--;
+ }
+ if(basename)
+ {
+ autodoc_text(basename);
+ autodoc_char('/');
+ }
+ autodoc_text(name);
+ } else
+ {
+ const char *ptr = name;
+ len = linelength - 1 - len;
+
+ while(len)
+ {
+ if(basename && *basename)
+ {
+ autodoc_char(*basename);
+ basename++;
+ } else
+ {
+ if(ptr == name && basename)
+ autodoc_char('/');
+ else
+ {
+ autodoc_char(*ptr);
+ ptr++;
+ }
+ }
+ len--;
+ }
+ }
+
+ put_string("\n");
+}
+
+void autodoc_dash() { put_string("-"); }
+
+void autodoc_section(name)
+const char *name;
+{
+ D((fprintf(stderr,"section : %s\n",name)));
+ newline = FALSE;
+ see_also = FALSE;
+ put_string("\n");
+ if(!strcmp(name,"DESCRIPTION"))
+ name = "FUNCTION";
+ else if(!strcmp(name,"PARAMETERS"))
+ name = "INPUTS";
+ else if(!strcmp(name,"RETURNS"))
+ name = "RESULT";
+ else if(!strcmp(name,"SEE ALSO"))
+ see_also = TRUE;
+
+ put_string(" ");
+ autodoc_text(name);
+ indent = 8;
+ list_indent = 0;
+ autodoc_char('\n');
+}
+
+void autodoc_sub_section(name)
+const char *name;
+{
+ autodoc_text(name);
+ indent = 12;
+}
+
+void autodoc_break_line()
+{
+ breakline = TRUE;
+}
+
+void autodoc_blank_line()
+{
+ autodoc_char('\n');
+}
+
+void autodoc_code_start() { }
+void autodoc_code_end() { }
+
+void autodoc_code(text)
+const char *text;
+{
+ autodoc_text(text);
+}
+
+void autodoc_tag_entry_start()
+{
+ if(list_indent > 0)
+ {
+ autodoc_char('\n');
+ list_indent -= indentlength;
+ }
+}
+void autodoc_tag_entry_start_extra()
+{
+ if(list_indent > 0)
+ {
+ autodoc_char('\n');
+ list_indent -= indentlength;
+ }
+}
+void autodoc_tag_entry_end()
+{
+ list_indent += indentlength;
+ autodoc_char('\n');
+}
+void autodoc_tag_entry_end_extra(text)
+const char *text;
+{
+ put_string("\" \"\t(");
+ autodoc_text(text);
+ put_string(")\"\n");
+ list_indent += indentlength;
+}
+
+void autodoc_table_start(longestag)
+const char *longestag;
+{
+ if(acttable < MAX_TAG - 1)
+ {
+ acttable++;
+ tablemaxtag[acttable] = strlen(longestag);
+ }
+
+ indent += indentlength;
+ newline = TRUE;
+}
+
+void autodoc_table_entry(name, description)
+const char *name;
+const char *description;
+{
+ int i = tablemaxtag[acttable] - strlen(name) + 1;
+
+ autodoc_code(name);
+ while(i > 0)
+ {
+ putchar(' ');
+ i--;
+ }
+ putchar('-');
+ putchar(' ');
+
+ if (description)
+ output_comment(description);
+ else
+ autodoc_char('\n');
+}
+
+void autodoc_table_end()
+{
+ if(acttable > -1)
+ acttable--;
+
+ autodoc_char('\n');
+ indent -= indentlength;
+ if(list_indent > 0)
+ list_indent -= indentlength;
+}
+
+void autodoc_indent()
+{
+ int i;
+ for(i = indent + list_indent; i ; i--)
+ autodoc_char(' ');
+}
+
+void autodoc_list_start()
+{
+ indent += indentlength;
+ newline = TRUE;
+}
+
+void autodoc_list_entry(name)
+const char *name;
+{
+ autodoc_code(name);
+}
+
+void autodoc_list_separator() { put_string(" ,"); }
+void autodoc_list_end() { autodoc_char('\n'); autodoc_table_end(); }
+
+void autodoc_include(filename)
+const char *filename;
+{
+
+}
+
+void autodoc_terse_sep()
+{
+ autodoc_char(' ');
+ autodoc_dash();
+ autodoc_char(' ');
+}
+
+void autodoc_name(name)
+const char *name;
+{
+ if(name)
+ autodoc_text(name);
+ else
+ autodoc_section("NAME");
+}
+
+void autodoc_file_end()
+{
+ if(!fileend)
+ putchar('\f');
+ fileend = TRUE;
+ newline = FALSE;
+}
+
+/* ideally, this should be made aware of embedded autodoc commands */
+void autodoc_description(text)
+const char *text;
+{
+ enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
+ boolean new_line = TRUE;
+
+ /* correct punctuation a bit as it goes out */
+ for (;*text;text++)
+ {
+ int c = *text;
+
+ if (new_line && (c == '-' || c == '*'))
+ {
+ output->break_line();
+ state = CAPITALISE;
+ }
+ else if (c == '.')
+ state = PERIOD;
+ else if (isspace(c) && state == PERIOD)
+ state = CAPITALISE;
+ else if (isalnum(c))
+ {
+ if (islower(c) && state == CAPITALISE) c = toupper(c);
+ state = TEXT;
+ }
+
+ output->character(c);
+ new_line = c == '\n';
+ }
+
+ /* do a full stop if there wasn't one */
+ if (state == TEXT) output->character('.');
+}
+
+/* ideally, this should be made aware of embedded autodoc commands */
+void
+autodoc_returns(comment)
+const char *comment;
+{
+ enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
+ char lastchar = '\n';
+ boolean tag_list_started = FALSE;
+
+ /* for each line... */
+ while (*comment)
+ {
+ boolean tagged = FALSE;
+
+ {
+ const char *c = comment;
+
+ /* search along until the end of a word */
+ while (*c && *c != ':' && !isspace(*c))
+ c++;
+
+ /* skip all spaces or tabs after the first word */
+ while (*c && *c != '\n')
+ {
+ if (*c == '\t' || *c == ':')
+ {
+ tagged = TRUE;
+ break;
+ }
+ else if (!isspace(*c))
+ break;
+
+ c++;
+ }
+ }
+
+ /* is it tagged?; explicitly reject dot commands */
+ if (tagged)
+ {
+ /* output lingering newline if necessary */
+ if (lastchar != '\n')
+ {
+ if (state == TEXT && !ispunct(lastchar)) output->character('.');
+ output->character(lastchar = '\n');
+ }
+
+ if (!tag_list_started)
+ {
+ output->tag_list_start();
+ tag_list_started = TRUE;
+ }
+
+ /* output the taggy bit */
+ output->tag_entry_start();
+ while (*comment && *comment != ':' && !isspace(*comment))
+ output->character(*comment++);
+ output->tag_entry_end();
+
+ /* skip any extra tabs or spaces */
+ while (*comment == ':' || (isspace(*comment) && *comment != '\n'))
+ comment++;
+
+ state = CAPITALISE;
+ }
+
+ /* terminate the previous line if necessary */
+ if (lastchar != '\n') output->character(lastchar = '\n');
+
+ /* correct punctuation a bit as the line goes out */
+ for (;*comment && *comment != '\n'; comment++)
+ {
+ char c = *comment;
+
+ if (c == '.')
+ state = PERIOD;
+ else if (isspace(c) && state == PERIOD)
+ state = CAPITALISE;
+ else if (isalnum(c))
+ {
+ if (islower(c) && state == CAPITALISE && fixup_comments)
+ c = toupper(c);
+ state = TEXT;
+ }
+
+ output->character(lastchar = c);
+ }
+
+ /* if it ended in punctuation, just output the nl straight away. */
+ if (ispunct(lastchar))
+ {
+ if (lastchar == '.') state = CAPITALISE;
+ output->character(lastchar = '\n');
+ }
+
+ if (*comment) comment++;
+ }
+
+ /* output lingering newline if necessary */
+ if (lastchar != '\n')
+ {
+ if (state == TEXT && !ispunct(lastchar) && fixup_comments)
+ output->character('.');
+ output->character('\n');
+ }
+
+ if (tag_list_started)
+ output->tag_list_end();
+}
+
+
+struct Output autodoc_output =
+{
+ autodoc_comment,
+ autodoc_header,
+ autodoc_dash,
+ autodoc_section,
+ autodoc_sub_section,
+ autodoc_break_line,
+ autodoc_blank_line,
+ autodoc_code_start,
+ autodoc_code_end,
+ autodoc_code,
+ dummy, /* autodoc_tag_list_start */
+ dummy, /* autodoc_tag_list_end */
+ autodoc_tag_entry_start,
+ autodoc_tag_entry_start_extra,
+ autodoc_tag_entry_end,
+ autodoc_tag_entry_end_extra,
+ autodoc_table_start,
+ autodoc_table_entry,
+ autodoc_table_end,
+ autodoc_indent,
+ autodoc_list_start,
+ autodoc_code, /* autodoc_list_entry */
+ autodoc_list_separator,
+ autodoc_list_end,
+ autodoc_include,
+ autodoc_file_end, /* autodoc_file_end */
+ autodoc_text,
+ autodoc_char,
+ NULL, /* autodoc_parse_option */
+ dummy, /* autodoc_print_options */
+ autodoc_name,
+ autodoc_terse_sep,
+ autodoc_text, /* autodoc_reference */
+ autodoc_text, /* autodoc_emphasized */
+ autodoc_description,
+ autodoc_returns
+};
+
diff --git a/c2man.c b/c2man.c
new file mode 100644
index 0000000..0250d11
--- /dev/null
+++ b/c2man.c
@@ -0,0 +1,928 @@
+/* $Id: c2man.c,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ *
+ * C Manual page generator.
+ * Reads C source code and outputs manual pages.
+ */
+#include <ctype.h>
+#include <errno.h>
+
+#include "c2man.h"
+#include "enum.h"
+#include "strconcat.h"
+#include "strappend.h"
+#include "manpage.h"
+#include "output.h"
+#include "patchlevel.h"
+
+#ifdef I_FCNTL
+#include <fcntl.h>
+#endif
+
+#ifdef I_SYS_FILE
+#include <sys/file.h>
+#endif
+
+#include <sys/stat.h>
+#include <signal.h>
+
+/* getopt declarations */
+extern int getopt();
+extern char *optarg;
+extern int optind;
+
+/* lex declarations */
+extern FILE *yyin; /* lex input stream */
+
+/* Name of the program */
+const char *progname = "c2man";
+
+/* Program options */
+
+/* TRUE if static declarations are also output. */
+boolean static_out = FALSE;
+
+/* TRUE if variable declarations are output. */
+boolean variables_out = FALSE;
+
+/* TRUE if formal parameter promotion is enabled. */
+boolean promote_param = TRUE;
+
+/* String output before prototype declaration specifiers */
+const char *decl_spec_prefix = "";
+
+/* String output before prototype declarator */
+const char *declarator_prefix = " ";
+
+/* String output after prototype declarator */
+const char *declarator_suffix = "\n";
+
+/* String output before the first parameter in a function prototype */
+const char *first_param_prefix = "\n\t";
+
+/* String output before each subsequent parameter in a function prototype */
+const char *middle_param_prefix = "\n\t";
+
+/* String output after the last parameter in a function prototype */
+const char *last_param_suffix = "\n";
+
+/* Directory to write output files in */
+char *output_dir = NULL;
+
+/* Name of the manual */
+char *manual_name = NULL;
+
+/* Section for manual page */
+const char *manual_section = NULL;
+
+/* prefix for generated #include lines */
+char *header_prefix = NULL;
+
+/* list of include file specified by user */
+IncludeFile *first_include;
+static IncludeFile **last_next_include = &first_include;
+
+/* list of excluded sections specified by user */
+ExcludeSection *first_excluded_section;
+static ExcludeSection **last_next_excluded_section = &first_excluded_section;
+
+/* TRUE if c2man should attempt to fixup comment sections */
+boolean fixup_comments = TRUE;
+
+/* do we group related stuff into one file? */
+boolean group_together;
+
+/* was terse description read from file or command line option? */
+boolean terse_specified;
+
+/* terse description when grouped together */
+char *group_terse = NULL;
+
+/* should we always document parameters, even if it's only "Not Documented" */
+boolean always_document_params = TRUE;
+
+/* look for a function def comment at the start of the function body */
+boolean look_at_body_start = FALSE;
+
+/* only look for a function def comment at the start of the function body */
+boolean body_start_only = FALSE;
+
+/* default output info for each object type */
+struct Output_Object_Info output_object[_OBJECT_NUM] =
+{
+#if 0
+ {'c', "class"},
+ {'s', "struct"},
+ {'e', "enum"},
+ {'t', "typedef"},
+#endif
+ {'f', "function"},
+ {'v', "variable"},
+ {'F', "static function"},
+ {'V', "static variable"}
+};
+
+/* Include file directories */
+#ifdef MSDOS
+int num_inc_dir = 1;
+const char *inc_dir[MAX_INC_DIR] = { ".\\" };
+#else
+#ifdef AMIGA
+int num_inc_dir = 1;
+const char *inc_dir[MAX_INC_DIR] = { "include:" };
+#else
+int num_inc_dir = 2;
+const char *inc_dir[MAX_INC_DIR] = { "./", "/usr/include/" };
+#endif
+#endif
+
+/* total number of errors encountered */
+int errors;
+
+/* name of the base file being processed; NULL = stdin */
+const char *basefile;
+Time_t basetime; /* modification time of base file */
+boolean inbasefile; /* are we parsing in that base file? */
+
+/* is the base file a header file? */
+boolean header_file;
+
+#ifdef AMIGA
+struct Output *output = &autodoc_output;
+const char *default_section = "doc";
+#else
+/* use nroff output by default */
+struct Output *output = &nroff_output;
+const char *default_section = "3";
+#endif
+
+/* should we generate the output file named after the input file? */
+boolean use_input_name = FALSE;
+
+/* should we generate embeddable files? */
+boolean make_embeddable = FALSE;
+
+#define USE_CPP
+#ifdef USE_CPP
+const char *cpp_cmd = CPP_FILE_COM;
+#if defined(MSDOS)
+#include "popen.h"
+#define popen(c,m) os_popen(c,m)
+#define pclose(f) os_pclose(f)
+#else
+#if defined (_MSC_VER)
+#define popen(c,m) _popen(c,m)
+#define pclose(f) _pclose(f)
+#endif
+#endif
+#endif
+
+boolean verbose = FALSE;
+
+/* can cpp read standard input? */
+static boolean cppcanstdin
+#ifdef CPP_CAN_STDIN
+ = 1
+#endif
+;
+/* does cpp ignore header files */
+static boolean cppignhdrs
+#ifdef CPP_IGN_HDRS
+ = 1
+#endif
+;
+
+/* nifty little function for handling I/O errors */
+void my_perror(action, filename)
+const char *action, *filename;
+{
+ int err = errno;
+ fprintf(stderr,"%s: %s ", progname, action);
+ errno = err;
+ perror(filename);
+}
+
+/* write the #include lines as specified by the user */
+void print_includes(f)
+FILE *f;
+{
+ IncludeFile *incfile;
+
+ for (incfile = first_include; incfile; incfile=incfile->next)
+ {
+ char *name = incfile->name;
+ boolean surrounded = *name == '"' || *name == '<';
+
+ fputs("#include ", f);
+ if (!surrounded) fputc('<',f);
+ fputs(name, f);
+ if (!surrounded) fputc('>',f);
+ fputc('\n',f);
+ }
+}
+
+void outmem()
+{
+ fprintf(stderr,"%s: Out of memory!\n", progname);
+ exit(1);
+}
+
+#ifndef DBMALLOC
+void *safe_malloc(size)
+size_t size;
+{
+ void *mem;
+
+ if ((mem = (void *)malloc(size)) == NULL)
+ outmem();
+
+ return mem;
+}
+#endif
+
+/* Replace any character escape sequences in a string with the actual
+ * characters. Return a pointer to malloc'ed memory containing the result.
+ * This function knows only a few escape sequences.
+ */
+static char *
+escape_string (src)
+char *src;
+{
+ char *result, *get, *put;
+
+ result = strduplicate(src);
+ put = result;
+ get = src;
+ while (*get != '\0') {
+ if (*get == '\\') {
+ switch (*(++get)) {
+ case 'n':
+ *put++ = '\n';
+ ++get;
+ break;
+ case 't':
+ *put++ = '\t';
+ ++get;
+ break;
+ default:
+ if (*get != '\0')
+ *put++ = *get++;
+ }
+ } else {
+ *put++ = *get++;
+ }
+ }
+ *put = *get;
+ return result;
+}
+
+/* Output usage message and exit.
+ */
+static void
+usage ()
+{
+ int i;
+
+ fprintf(stderr, "usage: %s [ option ... ] [ file ... ]\n", progname);
+ fputs(" -o directory\twrite output files in directory\n",stderr);
+ fputs(" -p\t\tdisable prototype promotion\n", stderr);
+ fputs(" -s\t\toutput static declarations\n", stderr);
+ fputs(" -v\t\toutput variable declarations\n", stderr);
+ fputs(" -k\t\tdon't attempt to fixup comments\n", stderr);
+ fputs(" -b\t\tlook for descriptions at top of function bodies\n", stderr);
+ fputs(" -B\t\tonly look for descriptions by applying -b\n", stderr);
+ fputc('\n', stderr);
+ fputs(" -i incfile\n", stderr);
+ fputs(" -i \"incfile\"\n", stderr);
+ fputs(" -i <incfile>\tadd #include for incfile to SYNOPSIS\n",
+ stderr);
+ fputc('\n', stderr);
+ fputs(" -H prefix\tspecify prefix for #include in SYNOPSIS\n", stderr);
+ fputc('\n', stderr);
+ fputs(" -g\n", stderr);
+ fputs(" -G terse\tgroup info from each file into a single page\n",
+ stderr);
+ fputs(" -e\t\tmake embeddable files\n", stderr);
+ fputc('\n', stderr);
+ fputs(" -l ", stderr);
+#ifdef HAS_LINK
+ fputs("h|", stderr);
+#endif
+#ifdef HAS_SYMLINK
+ fputs("s|", stderr);
+#endif
+ fputs("f|n|r\t", stderr);
+ fputs("linking for grouped pages: ", stderr);
+#ifdef HAS_LINK
+ fputs("hard, ", stderr);
+#endif
+#ifdef HAS_SYMLINK
+ fputs("soft, ", stderr);
+#endif
+ fputs("file, none or remove\n", stderr);
+ fputs(" -n\t\tName output file after input source file\n", stderr);
+ fputs(" -L\t\tLazy: Be silent about undocumented parameters\n",
+ stderr);
+
+ fputs(" -T n|l|h|t|a[,options]\tselect typesetting output format: nroff, LaTeX, HTML ,TeXinfo or AutoDoc\n",
+ stderr);
+ nroff_output.print_options();
+ latex_output.print_options();
+ html_output.print_options();
+ texinfo_output.print_options();
+ autodoc_output.print_options();
+
+ fputs(" -M name\tset name of the manual in which the page goes\n",
+ stderr);
+ fputs(" -x section\texclude section from ouput\n", stderr);
+ fputc('\n', stderr);
+ fputs(" -D name[=value]\n", stderr);
+ fputs(" -U name\n", stderr);
+ fputs(" -I directory\tC preprocessor options\n", stderr);
+ fputc('\n', stderr);
+ fputs(" -F template\tset prototype template in the form ", stderr);
+ fputs("\"int f (a, b)\"\n",stderr);
+ fputs(" -P preprocessor\tAlternate C preprocessor ", stderr);
+ fputs("(e.g., \"gcc -E -C\")\n", stderr);
+ fputs(" -V\t\tbe verbose and print version information\n", stderr);
+ fputs(" -S section\tset the section for the manual page (default = 3)\n",
+ stderr);
+ fputs(" -O ", stderr);
+ for (i = 0; i < _OBJECT_NUM; i++)
+ fputc(output_object[i].flag, stderr);
+ fputs("[subdir][.ext]", stderr);
+ fputs("\tOutput control over different object types:\n\t\t", stderr);
+ for (i = 0; i < _OBJECT_NUM; i++)
+ {
+ fputs(output_object[i].name, stderr);
+ if (i <= _OBJECT_NUM - 2)
+ fprintf(stderr,i == _OBJECT_NUM-2 ? " or " : ", ");
+ }
+ fputs(".\n", stderr);
+ exit(1);
+}
+
+/* name of the temporary file; kept here so we can blast it if hit with ctrl-C
+ */
+static char temp_name[20];
+Signal_t (*old_interrupt_handler)();
+
+/* ctrl-C signal handler for use when we have a temporary file */
+static Signal_t interrupt_handler(sig)
+int sig;
+{
+ unlink(temp_name);
+ exit(128 + sig);
+}
+
+/* open a unique temporary file.
+ * To be universally accepted by cpp's, the file's name must end in .c; so we
+ * can't use mktemp, tmpnam or tmpfile.
+ * returns an open stream & sets ret_name to the name.
+ */
+FILE *open_temp_file()
+{
+ int fd;
+ long n = getpid();
+ FILE *tempf;
+ boolean remove_temp_file();
+
+ /* keep generating new names until we hit one that does not exist */
+ do
+ {
+ /* ideally we'd like to put the temporary file in /tmp, but it must go
+ * in the current directory because when cpp processes a #include, it
+ * looks in the same directory as the file doing the include; so if we
+ * use /tmp/blah.c to fake reading fred.h via `#include "fred.h"', cpp
+ * will look for /tmp/fred.h, and fail.
+ */
+ sprintf(temp_name,"c2man%ld.c",n++ % 1000000);
+ }
+ while((fd =
+#ifdef HAS_OPEN3
+ open(temp_name,O_WRONLY|O_CREAT|O_EXCL,0666)
+#else
+ creat(temp_name,O_EXCL|0666) /* do it the old way */
+#endif
+ ) == -1
+ && errno == EEXIST);
+
+ /* install interrupt handler to remove the temporary file */
+ old_interrupt_handler = signal(SIGINT, interrupt_handler);
+
+ /* convert it to a stream */
+ if ((fd == -1 && errno != EEXIST) || (tempf = fdopen(fd, "w")) == NULL)
+ {
+ my_perror("error fdopening temp file",temp_name);
+ remove_temp_file();
+ return NULL;
+ }
+
+ return tempf;
+}
+
+/* remove the temporary file & restore ctrl-C handler.
+ * returns FALSE in the event of failure.
+ */
+boolean remove_temp_file()
+{
+ int ok = unlink(temp_name) == 0; /* this should always succeed */
+ signal(SIGINT, old_interrupt_handler);
+ return ok;
+}
+
+/* process the specified source file through the pre-processor.
+ * This is a lower level routine called by both process_stdin and process_file
+ * to actually get the work done once any required temporary files have been
+ * generated.
+ */
+int process_file_directly(base_cpp_cmd, name)
+const char *base_cpp_cmd;
+const char *name;
+{
+ char *full_cpp_cmd;
+
+#ifdef DEBUG
+ fprintf(stderr,"process_file_directly: %s, %s\n", base_cpp_cmd, name);
+#endif
+
+#ifdef USE_CPP
+ full_cpp_cmd = strconcat(base_cpp_cmd, " ", name, NULLCP);
+ if (verbose)
+ fprintf(stderr,"%s: running `%s'\n", progname, full_cpp_cmd);
+
+ if ((yyin = popen(full_cpp_cmd, "r")) == NULL) {
+ my_perror("error running", base_cpp_cmd);
+ free(full_cpp_cmd);
+ return 0;
+ }
+#else
+ if (verbose) fprintf(stderr,"%s: reading %s\n", progname, name);
+ if (name && freopen(name, "r", yyin) == NULL)
+ {
+ my_perror("cannot open", name);
+ return 0;
+ }
+#endif
+
+ parse_file(name);
+
+#ifdef USE_CPP
+ free(full_cpp_cmd);
+ if (pclose(yyin) & 0xFF00)
+ return 0;
+#else
+ if (fclose(yyin))
+ {
+ my_perror("error closing", name);
+ return 0;
+ }
+#endif
+
+ return !errors;
+}
+
+/* process a specified file */
+int process_file(base_cpp_cmd, name)
+const char *base_cpp_cmd;
+const char *name;
+{
+ char *period;
+ struct stat statbuf;
+
+#ifdef DEBUG
+ fprintf(stderr,"process_file: %s, %s\n", base_cpp_cmd, name);
+#endif
+ basefile = name;
+ header_file = (period = strrchr(name,'.')) &&
+ (period[1] == 'h' || period[1] == 'H');
+
+ /* use the file's date as the date in the manual page */
+ if (stat(name,&statbuf) != 0)
+ {
+ my_perror("can't stat", name);
+ return 0;
+ }
+ basetime = statbuf.st_mtime;
+
+ /* should we do this via a temporary file?
+ * Only if it's a header file and either CPP ignores them, or the user
+ * has specified files to include.
+ *
+ * For HP/Apollo (SR10.3, CC 6.8), we must always use a temporary file,
+ * because its compiler recognizes the special macro "__attribute(p)",
+ * which we cannot redefine in the command line because it has parameters.
+ */
+#ifndef apollo
+ if (header_file && (cppignhdrs || first_include))
+#endif
+ {
+ FILE *tempf;
+ int ret;
+
+ if (verbose)
+ fprintf(stderr, "%s: preprocessing via temporary file\n", progname);
+
+ if ((tempf = open_temp_file()) == NULL)
+ return 0;
+
+ print_includes(tempf);
+ if (verbose) print_includes(stderr);
+
+#ifdef apollo
+ fprintf(tempf,"#define __attribute(p)\n", basefile);
+#endif
+ fprintf(tempf,"#include \"%s\"\n", basefile);
+ if (verbose) fprintf(stderr,"#include \"%s\"\n", basefile);
+
+ if (fclose(tempf) == EOF)
+ {
+ my_perror("error closing temp file", temp_name);
+ remove_temp_file();
+ return 0;
+ }
+
+ /* since we're using a temporary file, it's not the base file */
+ inbasefile = 0;
+ ret = process_file_directly(base_cpp_cmd, temp_name);
+ remove_temp_file();
+ return ret;
+ }
+
+ /* otherwise, process it directly */
+ inbasefile = 1;
+
+ return process_file_directly(base_cpp_cmd,name);
+}
+
+/* process the thing on the standard input */
+int process_stdin(base_cpp_cmd)
+const char *base_cpp_cmd;
+{
+ if (isatty(fileno(stdin)))
+ fprintf(stderr,"%s: reading standard input\n", progname);
+
+ header_file = 0; /* assume it's not since it's from stdin */
+ basefile = NULL;
+
+ /* use the current date in the man page */
+ basetime = time((Time_t *)NULL);
+
+ inbasefile = 1; /* reading stdin, we start in the base file */
+
+ /* always use a temp file if the preprocessor can't read stdin, otherwise
+ * only use one if the user specified files for inclusion.
+ */
+ if (!cppcanstdin || first_include) /* did user specify include files? */
+ {
+ FILE *tempf;
+ int c, ret;
+
+ if (verbose)
+ fprintf(stderr,"%s: reading stdin to a temporary file\n", progname);
+
+ if ((tempf = open_temp_file()) == NULL)
+ return 0;
+
+ print_includes(tempf);
+ if (verbose) print_includes(stderr);
+ fprintf(tempf,"#line 1 \"stdin\"\n");
+
+ while ((c = getchar()) != EOF)
+ putc(c,tempf);
+
+ if (fclose(tempf) == EOF)
+ {
+ my_perror("error closing temp file", temp_name);
+ remove_temp_file();
+ return 0;
+ }
+ ret = process_file_directly(base_cpp_cmd, temp_name);
+ remove_temp_file();
+ return ret;
+ }
+ else
+ {
+ char *full_cpp_cmd = strconcat(base_cpp_cmd," ", CPP_STDIN_FLAGS,
+ NULLCP);
+
+ if (verbose)
+ fprintf(stderr,"%s: running `%s'\n", progname, full_cpp_cmd);
+
+ if ((yyin = popen(full_cpp_cmd, "r")) == NULL) {
+ my_perror("error running", full_cpp_cmd);
+ return 0;
+ }
+
+ parse_file(basefile);
+
+ free(full_cpp_cmd);
+ if (pclose(yyin) & 0xFF00)
+ return 0;
+
+ return !errors;
+ }
+}
+
+int
+main (argc, argv)
+int argc;
+char **argv;
+{
+ int i, c, ok = 0;
+ char *s, cbuf[2];
+ const char *base_cpp_cmd;
+ IncludeFile *includefile;
+ ExcludeSection *excludesection;
+ char *cpp_opts;
+#ifdef HAS_LINK
+ enum LinkType link_type = LINK_HARD; /* for -g/G */
+#else
+ enum LinkType link_type = LINK_FILE;
+#endif
+
+#ifdef YYDEBUG
+ extern int yydebug;
+#endif
+
+ /* initialise CPP options with -D__C2MAN__ */
+ cbuf[0] = VERSION + '0';
+ cbuf[1] = '\0';
+#ifdef VMS
+ cpp_opts = strconcat("-\"D__C2MAN__=", cbuf, "\"",NULLCP);
+#else
+ cpp_opts = strconcat("-D__C2MAN__=", cbuf, NULLCP);
+#ifdef NeXT
+ cpp_opts = strappend(cpp_opts, " -D_NEXT_SOURCE", NULLCP);
+#endif /* !NeXT */
+#endif /* !VMS */
+
+ /* Scan command line options. */
+ while ((c = getopt(argc, argv, "P:D:F:I:psU:Vvo:eM:H:G:gi:x:S:l:LT:nO:kbB"))
+ != EOF)
+ {
+ switch (c) {
+ case 'I':
+ case 'D':
+ case 'U':
+ cbuf[0] = c; cbuf[1] = '\0';
+ if (cpp_opts)
+ cpp_opts = strappend(cpp_opts," -",cbuf,optarg,NULLCP);
+ else
+ cpp_opts = strconcat("-",cbuf,optarg,NULLCP);
+ break;
+ case 'P':
+ cpp_cmd = optarg;
+
+ /* with no better info to go on, we have to assume that this
+ * preprocessor is minimally capable.
+ */
+ cppcanstdin = 0;
+ cppignhdrs = 1;
+ break;
+ case 'G':
+ group_terse = optarg;
+ terse_specified = TRUE;
+ /* FALLTHROUGH */
+ case 'g':
+ group_together = TRUE;
+ break;
+ case 'F':
+ s = escape_string(optarg);
+
+ decl_spec_prefix = s;
+ while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
+ if (*s == '\0') usage();
+ *s++ = '\0';
+ while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
+ if (*s == '\0') usage();
+
+ declarator_prefix = s;
+ while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
+ if (*s == '\0') usage();
+ *s++ = '\0';
+ while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
+ if (*s == '\0') usage();
+
+ declarator_suffix = s;
+ while (*s != '\0' && *s != '(') ++s;
+ if (*s == '\0') usage();
+ *s++ = '\0';
+
+ first_param_prefix = s;
+ while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
+ if (*s == '\0') usage();
+ *s++ = '\0';
+ while (*s != '\0' && *s != ',') ++s;
+ if (*s == '\0') usage();
+
+ middle_param_prefix = ++s;
+ while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
+ if (*s == '\0') usage();
+ *s++ = '\0';
+ while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
+ if (*s == '\0') usage();
+
+ last_param_suffix = s;
+ while (*s != '\0' && *s != ')') ++s;
+ *s = '\0';
+
+ break;
+ case 'p':
+ promote_param = FALSE;
+ break;
+ case 's':
+ static_out = TRUE;
+ break;
+ case 'V':
+ verbose = TRUE;
+ fprintf(stderr, "%s: Version %d, Patchlevel %d\n",
+ progname, VERSION, PATCHLEVEL);
+ break;
+ case 'v':
+ variables_out = TRUE;
+ break;
+ case 'k':
+ fixup_comments = FALSE;
+ break;
+ case 'o':
+ output_dir = optarg;
+ break;
+ case 'M':
+ manual_name = optarg;
+ break;
+ case 'H':
+ header_prefix = optarg;
+ break;
+ case 'i':
+ *last_next_include = includefile =
+ (IncludeFile *)safe_malloc(sizeof *includefile);
+ includefile->name = optarg;
+ includefile->next = NULL;
+ last_next_include = &includefile->next;
+ break;
+ case 'x':
+ *last_next_excluded_section = excludesection =
+ (ExcludeSection *)safe_malloc(sizeof *excludesection);
+ excludesection->name = optarg;
+ excludesection->next = NULL;
+ last_next_excluded_section = &excludesection->next;
+ break;
+ case 'S':
+ manual_section = optarg;
+ break;
+ case 'l':
+ switch(optarg[0])
+ {
+#ifdef HAS_LINK
+ case 'h': link_type = LINK_HARD; break;
+#endif
+#ifdef HAS_SYMLINK
+ case 's': link_type = LINK_SOFT; break;
+#endif
+ case 'f': link_type = LINK_FILE; break;
+ case 'n': link_type = LINK_NONE; break;
+ case 'r': link_type = LINK_REMOVE;break;
+ default: usage();
+ }
+ break;
+ case 'e':
+ make_embeddable = TRUE;
+ break;
+ case 'n':
+ use_input_name = TRUE;
+ break;
+ case 'L':
+ always_document_params = FALSE;
+ break;
+ case 'T':
+ switch(optarg[0])
+ {
+ case 'n': output = &nroff_output; default_section = "3";
+ break;
+ case 'l': output = &latex_output; default_section = "tex";
+ break;
+ case 't': output = &texinfo_output; default_section = "texi";
+ break;
+ case 'h': output = &html_output; default_section = "html";
+ break;
+ case 'a': output = &autodoc_output; default_section = "doc";
+ break;
+ default: usage();
+ }
+ s = strtok(&optarg[1], ",");
+ if (s && *output->parse_option == NULL) usage();
+ while(s)
+ {
+ if (output->parse_option(s)) usage();
+ s = strtok(NULL, ",");
+ }
+ break;
+ case 'O':
+ for (i = 0; i < _OBJECT_NUM; i++)
+ if (output_object[i].flag == optarg[0])
+ break;
+
+ if (i == _OBJECT_NUM)
+ {
+ fprintf(stderr,"%s: -O option must specify one of:\n\t",
+ progname);
+ for (i = 0; i < _OBJECT_NUM; i++)
+ {
+ fprintf(stderr,"%c (%s)", output_object[i].flag,
+ output_object[i].name);
+ if (i <= _OBJECT_NUM - 2)
+ fprintf(stderr,i == _OBJECT_NUM-2 ? " or " : ", ");
+ }
+ fprintf(stderr, ".\n");
+ exit(1);
+ }
+
+ if ((s = strchr(++optarg,'.'))) /* look for an extension */
+ {
+ output_object[i].subdir = alloc_string(optarg, s);
+ output_object[i].extension = strduplicate(s+1);
+ }
+ else
+ output_object[i].subdir = strduplicate(optarg);
+
+ break;
+ case 'b':
+ look_at_body_start = TRUE;
+ break;
+ case 'B':
+ body_start_only = TRUE;
+ look_at_body_start = TRUE;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+
+ /* make sure we have a manual section */
+ if (manual_section == NULL) manual_section = default_section;
+
+#ifdef MALLOC_DEBUG
+ getchar(); /* wait so we can start up NeXT MallocDebug tool */
+#endif
+#ifdef YYDEBUG
+ yydebug = 1;
+#endif
+
+ if (cpp_opts)
+ {
+ base_cpp_cmd = strconcat(cpp_cmd, " ", cpp_opts, NULLCP);
+ free(cpp_opts);
+ }
+ else
+ base_cpp_cmd = cpp_cmd;
+
+ if (optind == argc) {
+ if (use_input_name)
+ {
+ fprintf(stderr,"%s: %s\n", progname,
+ "cannot name output after input file if there isn't one!");
+ usage();
+ }
+ ok = process_stdin(base_cpp_cmd);
+ }
+ else
+ for (i = optind; i < argc; ++i)
+ if (!(ok = process_file(base_cpp_cmd,argv[i]))) break;
+
+ if (ok && firstpage)
+ output_manual_pages(firstpage,argc - optind, link_type);
+ free_manual_pages(firstpage);
+ destroy_enum_lists();
+
+ if (cpp_opts) free((char *)base_cpp_cmd);
+
+ for (includefile = first_include; includefile;)
+ {
+ IncludeFile *next = includefile->next;
+ free(includefile);
+ includefile = next;
+ }
+
+ for (excludesection = first_excluded_section; excludesection;)
+ {
+ ExcludeSection *next = excludesection->next;
+ free(excludesection);
+ excludesection = next;
+ }
+
+ for (i = 0; i < _OBJECT_NUM; i++)
+ {
+ safe_free(output_object[i].subdir);
+ safe_free(output_object[i].extension);
+ }
+
+#ifdef DBMALLOC
+ malloc_dump(2);
+ malloc_chain_check(1);
+#endif
+#ifdef MALLOC_DEBUG
+ sleep(1000000);
+#endif
+ return !ok;
+}
diff --git a/c2man.h b/c2man.h
new file mode 100644
index 0000000..d26ec71
--- /dev/null
+++ b/c2man.h
@@ -0,0 +1,284 @@
+/* $Id: c2man.h,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ *
+ * Definitions for C language manual page generator
+ */
+#ifndef _C2MAN_H
+#define _C2MAN_H
+
+#include "config.h"
+#include "symbol.h"
+
+#ifdef I_SYS_TYPES
+#include <sys/types.h>
+#endif
+
+#ifdef I_STDLIB
+#include <stdlib.h>
+#endif
+
+#ifdef I_STRING
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef I_UNISTD
+#include <unistd.h>
+#endif
+
+#ifdef I_STDDEF
+#include <stddef.h>
+#endif
+
+#ifdef I_TIME
+#include <time.h>
+#endif
+#ifdef I_SYS_TIME
+#include <sys/time.h>
+#endif
+
+#ifdef NeXT
+#include <libc.h>
+#undef ECHO /* lex generates ECHO */
+#endif
+
+#ifdef DBMALLOC
+#include </usr/local/debug_include/malloc.h>
+#endif
+
+#include "confmagic.h"
+
+/* number of spaces in a tab */
+#define NUM_TAB_SPACES 4
+
+/* maximum include file nesting */
+#define MAX_INC_DEPTH 15
+
+/* maximum number of include directories */
+#define MAX_INC_DIR 15
+
+/* maximum number of characters in a text buffer */
+#define MAX_TEXT_LENGTH 256
+
+/* Boolean type */
+typedef int boolean;
+#ifndef TRUE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+/* NULL char *, useful for passing NULL to functions wanting a char * */
+#define NULLCP ((char *)0)
+
+/* This is a list of function parameters. */
+typedef struct _parameter_list {
+ struct _parameter *first; /* pointer to first parameter in list */
+ struct _parameter *last; /* pointer to last parameter in list */
+} ParameterList;
+
+/* Declaration specifier flags */
+#define DS_NONE 0 /* default */
+#define DS_EXTERN 1 /* contains "extern" specifier */
+#define DS_STATIC 2 /* contains "static" specifier */
+#define DS_CHAR 4 /* contains "char" type specifier */
+#define DS_SHORT 8 /* contains "short" type specifier */
+#define DS_FLOAT 16 /* contains "float" type specifier */
+#define DS_JUNK 32 /* we're not interested in this declaration */
+#define DS_INLINE 64 /* makes static look interesting */
+
+/* This structure stores information about a declaration specifier. */
+typedef struct _decl_spec {
+ unsigned short flags; /* flags defined above */
+ char *text; /* source text */
+ struct _enumerator_list *enum_list; /* associated enum (if any) */
+} DeclSpec;
+
+/* Styles of declaration/definition */
+typedef enum {
+ DECL_SIMPLE, /* simple declaration */
+ DECL_COMPOUND, /* compound declaration */
+ DECL_FUNCTION, /* function declaration (prototype) */
+ DECL_FUNCDEF /* an actual function definition */
+} DeclType;
+
+/* This structure stores information about a declarator. */
+typedef struct _declarator {
+ char *name; /* name of variable or function */
+ char *text; /* source text */
+ DeclType type; /* style of function declaration */
+ ParameterList params; /* function parameters */
+ char *comment; /* description of param or variable */
+ char *retcomment; /* description of return value */
+ struct _declarator *head; /* head function declarator */
+ struct _declarator *func_stack; /* stack of function declarators */
+ struct _declarator *next; /* next declarator in list */
+} Declarator;
+
+/* This is a list of declarators. */
+typedef struct _declarator_list {
+ Declarator *first; /* pointer to first declarator in list */
+ Declarator *last; /* pointer to last declarator in list */
+} DeclaratorList;
+
+/* This structure stores information about a declaration. */
+typedef struct _declaration {
+ DeclSpec decl_spec;
+ DeclaratorList decl_list;
+} Declaration;
+
+/* this structure store information about an enumerator */
+typedef struct _enumerator {
+ char *name; /* name of enum entry */
+ char *comment; /* description of entry */
+ char *group_comment; /* general descr. for next few enums in list */
+ struct _enumerator *next; /* next enumerator in list */
+} Enumerator;
+
+/* This is a list of enumerators. */
+typedef struct _enumerator_list {
+ Enumerator *first; /* pointer to first enumerator in list */
+ Enumerator *last; /* pointer to last enumerator in list */
+ struct _enumerator_list *next; /* next list in a list-of-lists */
+} EnumeratorList;
+
+
+/* This structure stores information about a function parameter. */
+typedef struct _parameter {
+ DeclSpec decl_spec;
+ Declarator *declarator;
+ boolean suppress; /* don't print in grouped page */
+ boolean duplicate; /* mention fn in grouped page */
+ struct _parameter *next; /* next parameter in list */
+} Parameter;
+
+/* this is an identifier, with surrounding comments (if any) */
+typedef struct _identifier {
+ char *name;
+ char *comment_before, *comment_after;
+} Identifier;
+
+/* parser stack entry type */
+typedef union {
+ char *text;
+ DeclSpec decl_spec;
+ Parameter parameter;
+ ParameterList param_list;
+ Declarator *declarator;
+ DeclaratorList decl_list;
+ Declaration declaration;
+ Enumerator enumerator;
+ EnumeratorList *enum_list;
+ Identifier identifier;
+ boolean boolean;
+} yystype;
+
+/* include files specified by user */
+typedef struct _includefile
+{
+ char *name;
+ struct _includefile *next;
+} IncludeFile;
+
+/* output object types */
+enum Output_Object
+{
+#if 0 /* C++ stuff */
+ OBJECT_CLASS,
+ OBJECT_STRUCT,
+ OBJECT_ENUM,
+ OBJECT_TYPEDEF,
+#endif
+ OBJECT_FUNCTION,
+ OBJECT_VARIABLE,
+ OBJECT_STATIC_FUNCTION,
+ OBJECT_STATIC_VARIABLE,
+ _OBJECT_NUM
+};
+
+struct Output_Object_Info
+{
+ char flag; /* -O flag used to set it */
+ char *name; /* descriptive name for usage() */
+ char *extension; /* file extension */
+ char *subdir; /* subdirectory */
+};
+
+/* list of sections to exclude */
+typedef struct ExcludeSection
+{
+ char *name;
+ struct ExcludeSection *next;
+} ExcludeSection;
+
+#define YYSTYPE yystype
+
+/* Program options */
+extern boolean static_out;
+extern boolean variables_out;
+extern boolean promote_param;
+extern boolean look_at_body_start;
+extern boolean body_start_only;
+extern const char *decl_spec_prefix, *declarator_prefix, *declarator_suffix;
+extern const char *first_param_prefix, *middle_param_prefix, *last_param_suffix;
+extern int num_inc_dir;
+extern const char *inc_dir[];
+extern char *manual_name;
+extern const char *progname;
+extern char *header_prefix;
+extern IncludeFile *first_include;
+extern ExcludeSection *first_excluded_section;
+
+extern boolean fixup_comments;
+
+extern char *group_terse;
+extern boolean group_together;
+extern boolean terse_specified;
+extern boolean always_document_params;
+
+extern char *output_dir;
+
+/* Global declarations */
+extern int line_num;
+extern const char *basefile;
+extern Time_t basetime;
+extern boolean inbasefile;
+extern boolean header_file;
+extern SymbolTable *typedef_names;
+extern void output_error();
+extern void parse_file _((const char *start_file));
+extern int errors;
+extern const char *manual_section;
+extern boolean use_input_name;
+extern boolean make_embeddable;
+extern struct Output_Object_Info output_object[_OBJECT_NUM];
+
+
+
+/* Output a string to standard output. */
+#define put_string(s) fputs(s, stdout)
+
+/* a malloc that handles errors, and a free that handles NULL */
+#ifndef DBMALLOC
+void *safe_malloc _((size_t size));
+#else
+/* use macro so dbmalloc tells us where safe_malloc is called from */
+#define safe_malloc(s) malloc(s)
+#endif
+#define safe_free(p) do { if (p) free(p); p = NULL; } while(0)
+
+void outmem();
+void print_includes _((FILE *f));/* write #include lines */
+
+void yyerror _V((const char *fmt, ...));
+
+char *strduplicate _((const char *s));
+int strncmpi _((const char *s1, const char *s2, size_t n));
+char *strtoupper _((char *s));
+
+void my_perror _((const char *action, const char *filename));
+
+char *alloc_string _((const char *start, const char *end));
+
+#endif
diff --git a/c2man.man b/c2man.man
new file mode 100644
index 0000000..ad0d20e
--- /dev/null
+++ b/c2man.man
@@ -0,0 +1,906 @@
+.\" $Id: c2man.man,v 1.1 2004-05-03 05:17:49 behdad Exp $
+.de EX \"Begin example
+.br
+.if \\$1 .ne \\$1
+.if !"\\$2"" \{
+.if n .sp 1
+.if t .sp .5
+\\$2
+\}
+.if n .sp 1
+.if t .sp .5
+.nf
+.cs R 24
+.vs \n(.vu-2p
+.in +.5i
+..
+.de EE \"End example
+.br
+.vs \n(.vu+2p
+.cs R
+.fi
+.in -.5i
+.if n .sp 1
+.if t .sp .5
+..
+.de CS \"Begin shell command
+.br
+.if n .sp 1
+.if t .sp .5
+.in +.5i
+%
+.ft B
+..
+.de CE \"End shell command
+.br
+.ft R
+.in -.5i
+.if n .sp 1
+.if t .sp .5
+..
+.de CD \"Shell command
+.CS
+\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.CE
+..
+.\" The IF & IE macros cannot be combined due to flatten.sed
+.de IF \"Begin Include a source file
+.br
+.if n .sp 1
+.if t .sp .5
+.ne 10
+.nf
+.cs R 24
+.vs \n(.vu-2p
+.RS 0.25in
+..
+.de IE \"End Include a source file
+.br
+.RE
+.if n .sp 1
+.if t .sp .5
+.vs \n(.vu+2p
+.cs R
+.fi
+..
+.\" The OF & OE macros cannot be combined due to flatten.sed
+.de OF \"Begin Include a fixed nroff output file
+.br
+.if n .sp 1
+.if t .sp .5
+.ne 10
+.nf
+.RS 0.25in
+..
+.de OE \"End Include a fixed nroff output file
+.br
+.RE
+.if n .sp 1
+.if t .sp .5
+.fi
+..
+.de NA \"Begin name and Email address stuff
+.br
+.if \\$1 .ne \\$1
+.if !"\\$2"" \{
+.if n .sp 1
+.if t .sp .5
+\\$2
+\}
+.if n .sp 1
+.if t .sp .5
+.nf
+.in +.5i
+..
+.de NE \"End name
+.fi
+.in -.5i
+.if n .sp 1
+.if t .sp .5
+..
+.TH C2MAN 1 "March 2, 1995"
+.BY "CISRA"
+.SH NAME
+c2man \- generate manual pages from C source code
+.SH SYNOPSIS
+.B c2man
+[
+.I option \fP...\fI
+] [
+.I file \fP...\fI
+]
+.SH DESCRIPTION
+.B c2man
+reads C source code files in which comments have been strategically placed,
+and outputs manual page(s) documenting each function defined or declared (via
+a prototype), and optionally each variable with global scope.
+Function definitions and declarations may be in the old style or ISO/ANSI style.
+If no
+.I file
+argument is given,
+.B c2man
+takes its input from the standard input.
+.PP
+If a
+.B .h
+file is written as a formal interface description when preparing an
+interface spec,
+.B c2man
+can generate all the manual pages required for the spec at one fell swoop,
+and then keep them up to date automatically as the interface changes.
+.PP
+Since
+.B c2man
+will accept either function definitions or prototypes, it can be used on
+either
+.B .c
+or
+.B .h
+files.
+If the input is a
+.B header
+file, any files specified by
+.B \-i
+options are
+assumed to be prerequisites, and get parsed before the input file.
+(Any file whose extension begins with
+.RB `` h '',
+matched case-insensitively,
+is considered a
+.B header
+file.)
+.PP
+This is potentially a huge win for most programmers that just love documenting
+their functions, and updating the documentation every time it changes.
+Here's an example, named example.h:
+.IF
+.so example.h
+.IE
+.PP
+When:
+.CD c2man example.h
+is run,
+this produces a file named
+.B dowork.3
+which can be processed by man(1) or used as:
+.CD "nroff -man dowork.3"
+to produce:
+.OF
+.ne 34
+.so example.inc
+.OE
+.SS "Output Generation"
+By default, a separate output file is generated for each global identifier
+(i.e. function or variable) documented by c2man.
+.PP
+Much of
+.BR c2man 's
+information is extracted from the comment placed immediately before the
+declaration/definition of the identifier being documented; this comment
+is taken to describe the identifier and
+.B must
+be present, or the identifier will be ignored entirely.
+In the case of a variable declaration/definition, this comment may instead be
+placed after it starting on the same line.
+.PP
+Global variables are not documented, unless the
+.B \-v
+option is used.
+.PP
+Identifiers declared
+.B static
+are ignored by default unless the file is a
+.B header
+file (which is most useful with
+.B inline
+functions) or the
+.B -s
+option is used.
+.PP
+Declarations with the
+.B extern
+keyword are ignored unless they appear in a
+.B header
+file; note that this does not include function definitions.
+.SS "Sections Generated Automatically"
+Each manual page starts with a
+.B NAME
+section, listing the name(s) of the identifier(s) documented, along with a
+terse description.
+By default, this description is the first line or sentence of the
+comment describing the identifier.
+With the
+.B \-g
+option, it is found after the first dash
+.RB ( \- )
+in the first comment of the file, and the
+.B \-G
+option specifies it explicitly.
+.PP
+The
+.B SYNOPSIS
+section
+begins with an
+.B #include
+line
+if the source file is a
+.BR header .
+After this is an external declaration for the
+identifier(s) being documented.
+.PP
+Information in the
+.B PARAMETERS
+section is gleaned from the comments immediately before or after each
+parameter declaration. A comment after a parameter can follow the comma that
+separates that parameter from the next, if the comment starts on the same line
+and is the only remaining thing on that line. Leading underscores in a
+parameter name are stripped when printed in the manual page.
+.PP
+If the manual page is for a group of functions (ie:
+.B \-g
+or
+.B \-G
+options),
+identical parameters (in both name and type) common to more than one function
+are described only once if only one has a comment (as in the ctype Xexample below).
+.PP
+If a parameter is an
+.B enumerated
+.BR type ,
+all the possible values it can take are output, along with their descriptions.
+These descriptions are gleaned from the comments surrounding the
+.B enum
+identifiers where the type was defined.
+Comments describing
+.B enum
+identifiers are placed in a similar manner to those that describe function
+parameters.
+.B enum
+identifiers that begin with an underscore are ignored, which is useful for
+padding or
+.I _NUMBER_OF_...
+values which aren't normally used by someone calling
+the function.
+If none of the identifiers in an enumerated type has a comment,
+.B c2man
+will bunch them together to save space.
+.PP
+The
+.B DESCRIPTION
+section contains everything
+after the first line or sentence
+of the comment describing the identifier,
+up until the word
+.RB `` returns ''
+at the start of a line, matched case-insensitively and optionally followed by
+a colon
+.RB ( : ).
+In the case of a variable of
+.B enumerated
+.BR type ,
+it will also list all the values it can hold.
+.PP
+The
+.B RETURNS
+section contains anything after that. Any of these lines that begin with a
+single word followed by a colon or a tab generate tagged paragraphs so that
+lists of possible return values and error codes look neat.
+If the function is void, don't put anything like "Returns: nothing" in
+the comment, since it's a waste of space. If the identifier is a function
+returning an
+.B enumerated
+.BR type ,
+its possible values will be listed here.
+.PP
+The
+.B RETURNS
+section is also added if there is a comment after the function return type.
+.EX 5 "For example:"
+/* Sample function */
+char * /* NULL if failed string otherwise */
+sample_function()
+{
+}
+.EE
+The
+.B RETURNS
+section will contain the full contents of the comment (stripping the optional
+leading asterisk). It is not possible to use both methods to specify a
+description for the return value. In that case the comment after the
+return type supersedes whatever was specified for the return value in
+the comment above the function.
+.PP
+Finally, a
+.B "SEE ALSO"
+section is generated, referencing all the other manual pages generated, if any.
+.PP
+The
+.BR RETURNS ,
+.B PARAMETERS
+and
+.B "SEE ALSO"
+sections are omitted entirely if they aren't needed.
+.SS "Comment Style and Placement"
+Both
+.B C
+and
+.B C++
+style comments are recognized,
+with seperate consecutive single-line comments coalesced into a single block.
+When looking at comments,
+.B c2man
+ignores everything before the first alpha-numeric character. After that, it
+ignores leading white-space, leading asterisks and leading slashes
+on all subsequent
+lines, and ignores all trailing lines thus rendered blank. If that leaves
+nothing, the comment is ignored entirely.
+This makes it very flexible in supporting popular comment boxing.
+.PP
+Comments can be placed with considerable flexibility so that most commenting
+styles are supported.
+.EX 13 "The following variations of the enum definition in the \fBdowork.h\fR\
+ example are all equivalent:"
+/* commas after the comments. */
+enum Place
+{
+ HOME /* Home, Sweet Home */,
+ WORK /* where I spend lots of time */,
+ MOVIES /* Saturday nights mainly */,
+ CITY /* New York, New York */,
+ COUNTRY /* Bob's Country Bunker */
+};
+.EE
+.EX 16
+/* the comment needn't go on the same line,
+ * if the comma goes after the comment.
+ */
+enum Place
+{
+ HOME
+ /* Home, Sweet Home */,
+ WORK
+ /* where I spend lots of time */,
+ MOVIES
+ /* Saturday nights mainly */,
+ CITY
+ /* New York, New York */,
+ COUNTRY
+ /* Bob's Country Bunker */
+};
+.EE
+.EX 14
+/* the comment can go before it too. */
+enum Place
+{
+ /* Home, Sweet Home */
+ HOME,
+ /* where I spend lots of time */
+ WORK,
+ /* Saturday nights mainly */
+ MOVIES,
+ /* New York, New York */
+ CITY,
+ /* Bob's Country Bunker */
+ COUNTRY
+};
+.EE
+But the following example is
+.B NOT
+equivalent because the commas are between the identifier and the its
+associated comment, and the comment is on a different line.
+Each comment actually applies to the wrong identifier, so this will result in
+very misleading output.
+.EX 16 "Don't do this:"
+enum Place
+{
+ HOME,
+ /* Home, Sweet Home */
+ WORK,
+ /* where I spend lots of time */
+ MOVIES,
+ /* Saturday nights mainly */
+ CITY,
+ /* New York, New York */
+ COUNTRY
+ /* Bob's Country Bunker */
+};
+.EE
+.PP
+Since enum identifiers sometimes fall into logical groups, a comment before
+such an identifier will be taken to apply to the next few in the list,
+provided that the comments describing each individual identifier
+are placed after them. Also, there must be a blank line separating the comment
+describing the next logical group and the comment at the end of the previous
+line, or the two will be coalesced and incorrectly treated as a single comment
+for the previous enumerator.
+.EX 17 "In other words, you can go:"
+/* include logical grouping comments. */
+enum Place
+{
+ /* These take up most of the week */
+ HOME, /* Home, Sweet Home */
+ WORK, /* where I spend lots of time */
+
+ /* More for special occasions */
+ MOVIES, /* Saturday nights mainly */
+ CITY, /* New York, New York */
+
+ /* The real favourite */
+ COUNTRY /* Bob's Country Bunker */
+};
+.EE
+.PP
+That may all sound a bit complex, but the upshot is that
+.B c2man
+will usually know which identifier a comment is associated with, unless you do
+something truly bizarre.
+.SS "Processing of Comment Contents"
+Basic punctuation and capitalisation corrections are made in each section for
+neatness, and the typesetting program used to process the output will generally
+reformat line breaks according to the width of the output device. Blank lines
+in a comment will be preserved, and lines starting with a dash
+.RB ( \- ),
+an asterisk
+.RB ( * ),
+or a numbered point
+.RB ( (n) ,
+.B n)
+.RB or\ n. ),
+will cause a line break, allowing simple bulleted or numbered lists.
+.PP
+Typesetter specific commands may be included for more complex processing,
+although this isn't recommended since it ties you to a particular typesetter.
+.SS "Grouped Manual Pages"
+Simple, closely related objects can be grouped together onto a single page with the
+.B \-g
+or
+.B \-G
+options. By default, this results in a single output file with multiple links
+so that it can be accessed by the name of the input file, or of any identifier
+documented.
+For example, if ctype.h contains:
+.IF
+.so ctype_ex.h
+.IE
+.PP
+then using:
+.CD c2man -g ctype.h
+yields:
+.OF
+.so ctype_ex.inc
+.OE
+.SS "Extra Sections"
+Additional sections not otherwise recognized by
+.B c2man
+can be included in the manual page by including them in the comment
+describing the identifier.
+A section heading is preceded in the comment by an empty line (after
+removal of leading asterisks), and is the only word on it's line, or is
+a word followed by a colon
+.RB ( : ),
+or is a line ending with a colon, so section names with spaces are allowed,
+like "Return value:".
+.P
+Section heading names are capitalized, and the names
+.BR DESCRIPTION ,
+.B RETURNS
+and
+.B NAME
+are recognized specially so you can name them explicitly if you like.
+.BR FUNCTION ,
+.B PROCEDURE
+and
+.B ROUTINE
+are also recognised, and treated identically to
+.BR NAME .
+.EX 9 "For example:"
+/*
+ * Have a quick puff.
+ *
+ * Warning: Smoking causes lung cancer
+ */
+void go_for_a_smoke();
+.EE
+Generates a manual page with a
+.B WARNING
+section.
+.EE
+.SH OPTIONS
+.TP
+.BI \-o dir
+Write generated files into directory
+.B dir
+rather than the current directory.
+If
+.B dir
+is specified as
+.BR \- ,
+generated pages are written to the standard output, separated by form-feeds.
+.TP
+.B \-v
+Also output declarations for variables defined in the file.
+.TP
+.B \-s
+Output manual pages for all
+.B static
+identifiers.
+.TP
+.B \-g
+Group all the info generated together into a single
+page (ala ctype(3)), reading the single-line terse description for the
+.B NAME
+section from the line of the first comment in the file.
+If this first line contains a dash
+.RB ( \- )
+surrounded by whitespace, the terse description is taken starting after the
+dash.
+If multiple files are specified,
+the first such suitable comment encountered is used. A link to
+the output file is made for each identifier documented, according to the
+.B \-l
+option.
+.TP
+.BI \-G terse
+Like
+.BR \-g ,
+but using the specified terse description rather than reading it from the
+file.
+.TP
+.B \-k
+Don't attempt to fix up capitalization and punctuation.
+.TP
+.B \-b
+If a function lacks a preceding comment, look for one immediately following
+the curly-brace at the top of the function body.
+The comment must appear before anything else.
+.TP
+.B \-B
+Apply
+.B \-b
+strictly. Only look for the description of a function at
+the top of its body.
+.TP
+.B \-l h|s|f|n|r
+Select how the output for a grouped manual page is linked to files named after
+all identifiers documented on the page.
+Hard link
+.RB ( h )
+is the default, as it uses the least space.
+Soft link
+.RB ( s ),
+where supported, allows a
+.BR find (1)
+command with
+.RB `` "\-type f" ''
+to easily skip the duplicated pages.
+Separate file
+.RB ( f )
+containing a file include
+directive is the traditional
+.SM UNIX
+method.
+No link
+.RB ( n )
+is useful for generating printed documentation without duplicated pages; only
+a single file, named according to the
+.B \-n
+option, is generated.
+Remove
+.RB ( r )
+is like No link, but also removes any previously generated links/files named
+after the identifiers documented. Useful for cleaning up after accidents with
+the other link options.
+.sp
+In all cases, any existing links will be removed before being rewritten.
+.TP
+.B \-n
+Name the documentation output file after the input file.
+When generating grouped manual pages, this will be the file to which others
+are linked.
+For non-grouped manual pages, if documentation for more than one
+identifier is generated, information about the last identifier will overwrite
+information about all the previous ones.
+.PP
+.BI \-i file
+.PP
+\fB\-i\fI\{"file"\}
+.TP
+.BI \-i <file>
+Insert a
+.B #include
+line referencing the specified file in the
+.B SYNOPSIS
+section, using the ``<file>'' form by default.
+Any number of
+.B \-i
+options may be specified to build up a list of prerequisites.
+If using the second form, you may need to quote the quotation marks, lest they
+get removed by the shell.
+.TP
+.BI \-x sectionname
+Exclude
+.I sectionname
+from the generated manpages. This option may be repeated to exclude a number
+of sections.
+.TP
+.BI \-H header-path
+Prepend
+.B header-path
+to the name of the
+.B header
+file when an
+.B #include
+line is automatically generated in the
+.B SYNOPSIS
+section.
+.TP
+.BI \-L
+Lazy option: Only list parameters in the
+.B PARAMETERS
+section if they are documented by a comment in the source. By default,
+parameters with no comment are described as ``Not Documented.'', to encourage
+the programmer to comment them.
+.TP
+.BI \-Tn|l|t|h|a[, options ]
+Set the output typesetting language as well as language specific
+options.
+.I options
+is a comma delimited list of options.
+.B Nroff
+.RB ( n )
+is the default,
+.B LaTeX
+.RB ( l )
+,
+.B Texinfo
+.RB ( t )
+,
+.B HTML
+.RB ( h )
+, or
+.B AutoDoc
+.RB ( a ).
+.B Texinfo
+specific options are
+.BR s ,
+.BR t ,
+.BR n ,
+and
+.BR C .
+
+In
+.B Texinfo
+mode, each section is normally coded as a ``heading'' rather than a
+``section''. This prevents the section name from appearing in the
+table of contents. If the option
+.B t
+is given, the name of the manpage is used for the title of the
+.B NAME
+section, and is encoded as a ``section'', placing it in
+the table of contents. Subsequent sections are encoded as ``headings''.
+.B Texinfo
+supports multiple levels of headings; the desired level may be
+specified via the
+.BI s n
+option, where
+.I n
+starts at 0 for the ``chapter level'' and works down. A
+top level node is created for the manpage, except when in embedded
+mode
+(the
+.B c2man \-e
+option). If the
+.B n
+option is specified, a node is created in embedded mode, but
+without Up, Previous, or Next pointers; these must be filled in
+.BR ( Texinfo
+mode in
+.B emacs
+does a good job of it). The
+.B C
+option capitalizes the section titles. Usually they are printed
+as specified (which is usually upper case).
+.TP
+.BI \-e
+Prepares the output so it can be embedded in texts of the output typesetting
+language.
+.TP
+.BI \-M name
+Set the name of the manual in which the page will go.
+.TP
+.BI \-S section
+Set the default manual section, used as the extension on the output files.
+.I section
+defaults to ``3'' for
+.BR nroff ,
+``texi'' for
+.B Texinfo ,
+``html'' for
+.B HTML
+and ``tex'' for
+.B LaTeX
+output, as specified via the
+.B \-T
+option.
+This setting can be overridden by the
+.BI \-O? .ext
+options for finer control.
+.TP
+.BI \-Of|v|F|V[ subdir ][. ext ]
+Provides for finer control of the output files, allowing a different output
+subdirectory and extension to be specified for these different classes of
+objects:
+functions
+.RB ( f ),
+variables
+.RB ( v ),
+static functions
+.RB ( F )
+and static variables
+.RB ( V ).
+.sp
+If
+.I subdir
+is specified, the selected class of output will be written in that
+subdirectory under the directory given by the
+.B \-o
+option if specified, otherwise under the current directory.
+.sp
+If
+.I .ext
+is specified, it will be used as the extension on the output files of the
+selected class, instead of the default based on the
+.B \-S
+option (if specified), or the typesetting output format specified by the
+.B \-T
+option.
+.sp
+For example, the following command will generate
+.BR nroff (1)
+style output under the /usr/local/man hierarchy, documenting functions in
+section 3 (/usr/local/man/man3/*.3), global variables in section 3v
+(/usr/local/man/man3/*.3v), static functions in section 9
+(/usr/local/man/man9/*.9) and
+static variables in section 9v (/usr/local/man/man9/*.9v):
+.CD c2man -o/usr/local/man -v -s -Ofman3.3 -Ovman3.3v -OFman9.9 -OVman9.9v input.c
+The
+.B \-O
+options will have no effect if
+.B \-o-
+is used to write to standard output, and
+.BR \-Ov ,
+.B \-OF
+and
+.B \-OV
+will have no effect unless their classes of output are enabled via the
+appropriate
+.B \-v
+and
+.B \-s
+options.
+.TP
+.BI \-F template
+Set the format used to output the prototype for functions with more than 1
+parameter
+in each manual page;
+functions with zero or 1 parameters are always output as one line.
+The format is specified by a template in the form
+.EX
+" int f ( a, b )"
+.EE
+but you may replace each space in this string with any number of
+whitespace characters.
+For example, the option
+.EX
+-F"int f(\\n\\ta,\\n\\tb\\n\\t)"
+.EE
+.EX 5 "will produce:"
+int main(
+ int argc,
+ char *argv[]
+ )
+.EE
+.EX 5 "The default output format is:"
+int main
+(
+ int argc,
+ char *argv[]
+);
+.EE
+.TP
+.BI \-P preprocessor
+Run a different C preprocessor than normal (use
+.B \-V
+to determine the configured default).
+You must include any options required to prevent it from stripping comments,
+which is normally the default preprocessor behaviour.
+For example, to use
+.BR gcc 's
+cpp instead:
+.CD c2man -P \{"gcc -E -C"\}
+.TP
+.BI \-D name[=value]
+This option is passed through to the preprocessor and is used to define
+symbols for use with conditionals such as
+.I #ifdef.
+.TP
+.BI \-U name
+This option is passed through to the preprocessor and is used to remove
+any definitions of this symbol.
+.TP
+.BI \-I directory
+This option is passed through to the preprocessor and is used to specify
+a directory to search for files that are referenced with
+.I #include.
+.TP
+.B \-V
+Print version information and cpp parameters.
+.SH FILES
+.TP
+$(privlib)/eg/*.[ch]
+A few example input files, showing different commenting styles.
+.SH "SEE ALSO"
+man(1),
+apropos(1),
+catman(8),
+cproto(1),
+cc(1),
+cpp(1)
+.SH DIAGNOSTICS
+.BR c2man 's
+error messages are not very helpful, so make sure your code compiles before
+trying
+.BR c2man .
+If the code compiles OK but
+.B c2man
+rejects it, it may be because a comment is in a position
+.B c2man
+does not accept, or you are using a compiler extension not strictly conforming
+to standard C.
+.B c2man
+defines the preprocessor symbol
+.B __C2MAN__
+with its major version number
+to allow you to work around such problems by surrounding them with
+.BR "#ifndef __C2MAN__" .
+.PP
+An error at the very end of a function may indicate that the comments at the
+beginning are badly placed.
+.SH HISTORY
+.B c2man
+was originally written by:
+.NA 4
+Graham Stoney
+Canon Information Systems Research Australia
+greyham@research.canon.com.au
+(please send bug reports here)
+.NE
+Many thanks are due to the many other Internet contributors since then, and to
+Chin Huang, the author of
+.B cproto
+from which it was originally derived.
+.SH BUGS
+The
+.B \-F
+option only interprets the following
+character escape sequences:
+.EX 2
+\\n newline
+\\t tab
+.EE
+.PP
+A comment before a preprocessor directive will be considered to apply
+to the identifier that immediately follows, if it has no
+comment of its own.
+This is because the preprocessor directive gets removed by cpp before
+c2man looks at it.
+.PP
+Comments aren't legal in some of the more obscure places that they are in C.
+.PP
+Heavy use of
+.B #define
+in a program may yield somewhat obscure manual pages.
+.PP
+.BR c2man 's
+output backends may not be entirely consistent, but then users of
+different formatters tend to have different tastes.
diff --git a/catalog b/catalog
new file mode 100644
index 0000000..42ec395
--- /dev/null
+++ b/catalog
@@ -0,0 +1,44 @@
+language: C, nroff, texinfo, latex, html, autodoc
+package: c2man
+version: 2.0 patchlevel 40
+parts: documentation generator (C -> nroff -man, -> texinfo, -> latex,
+ -> html, -> autodoc)
+author: Graham Stoney <greyham@research.canon.com.au>
+location: ftp from any comp.sources.misc archive, in volume42
+ (the version in the comp.sources.reviewed archive is obsolete)
+ ftp /pub/Unix/Util/c2man-2.0.*.tar.gz from dnpap.et.tudelft.nl
+ Australia: ftp /usenet/comp.sources.misc/volume42/c2man-2.0/*
+ from archie.au
+ N.America: ftp /usenet/comp.sources.misc/volume42/c2man-2.0/*
+ from ftp.wustl.edu
+ Europe: ftp /News/comp.sources.misc/volume42/c2man-2.0/*
+ from ftp.irisa.fr
+ Japan: ftp /pub/NetNews/comp.sources.misc/volume42/c2man-2.0/*
+ from ftp.iij.ad.jp
+ Patches: ftp pub/netnews/sources.bugs/volume93/sep/c2man* from lth.se
+description: c2man is an automatic documentation tool that extracts comments
+ from C source code to generate functional interface
+ documentation in the same format as sections 2 & 3 of the Unix
+ Programmer's Manual. It requires minimal effort from the
+ programmer by looking for comments in the usual places near the
+ objects they document, rather than imposing a rigid
+ function-comment syntax or requiring that the programmer learn
+ and use a typesetting language. Acceptable documentation can
+ often be generated from existing code with no modifications.
+conformance: supports both K&R and ISO/ANSI C coding styles
+features: + generates output in nroff -man, TeXinfo, LaTeX or HTML format
+ + handles comments as part of the language grammar
+ + automagically documents enum parameter & return values
+ + handles C (/* */) and C++ (//) style comments
+ - doesn't handle C++ grammar (yet)
+requires: yacc/byacc/bison, lex/flex, and nroff/groff/texinfo/LaTeX.
+ports: Unix, OS/2, MSDOS, VMS, Amiga.
+portability: very high for unix, via Configure
+status: actively developed; contributions by users are encouraged.
+discussion: via a mailing list: send "subscribe c2man <Your Name>" (in the
+ message body) to listserv@research.canon.com.au
+help: from the author and other users on the mailing list:
+ c2man@research.canon.com.au
+announcements: patches appear first in comp.sources.bugs, and then in
+ comp.sources.misc.
+updated: 1996/03/21
diff --git a/config_h.SH b/config_h.SH
new file mode 100644
index 0000000..cf2fa77
--- /dev/null
+++ b/config_h.SH
@@ -0,0 +1,353 @@
+case $CONFIG in
+'')
+ if test -f config.sh; then TOP=.;
+ elif test -f ../config.sh; then TOP=..;
+ elif test -f ../../config.sh; then TOP=../..;
+ elif test -f ../../../config.sh; then TOP=../../..;
+ elif test -f ../../../../config.sh; then TOP=../../../..;
+ else
+ echo "Can't find config.sh."; exit 1
+ fi
+ . $TOP/config.sh
+ ;;
+esac
+case "$0" in
+*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
+esac
+echo "Extracting config.h (with variable substitutions)"
+sed <<!GROK!THIS! >config.h -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un-def!#undef!'
+/*
+ * This file was produced by running the config_h.SH script, which
+ * gets its values from config.sh, which is generally produced by
+ * running Configure.
+ *
+ * Feel free to modify any of this as the need arises. Note, however,
+ * that running config_h.SH again will wipe out any changes you've made.
+ * For a more permanent change edit config.sh and rerun config_h.SH.
+ *
+ * \$Id: config_h.SH,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ */
+
+/*
+ * Package name : $package
+ * Source directory : $src
+ * Configuration time: $cf_time
+ * Configured by : $cf_by
+ * Target system : $myuname
+ */
+
+#ifndef _config_h_
+#define _config_h_
+
+/* VMS:
+ * This symbol, if defined, indicates that the program is running under
+ * VMS. It is currently only set in conjunction with the EUNICE symbol.
+ */
+/* BSD:
+ * This symbol, if defined, indicates that the program is running under
+ * a BSD system.
+ */
+#$d_eunice VMS /**/
+#$d_bsd BSD /**/
+
+/* CPP_FILE_COM:
+ * This symbol contains the first part of the string which will invoke
+ * the C preprocessor a file and produce to standard output, preserving
+ * comments. Typical value of "cc -E -C" or "/lib/cpp -C".
+ */
+/* CPP_STDIN_FLAGS:
+ * This variable contains any flags necessary to get CPP_FILE_COM to
+ * read from the standard input.
+ */
+/* CPP_IGN_HDRS:
+ * This symbol is defined if CPP_FILE_COM ignores *.h files.
+ */
+/* CPP_CAN_STDIN:
+ * This symbol is defined if CPP_FILE_COM can read standard input
+ * directly.
+ */
+#define CPP_FILE_COM "$cppfilecom"
+#define CPP_STDIN_FLAGS "$cppstdinflags"
+#$d_cppignhdrs CPP_IGN_HDRS /* does CPP ignore .h files? */
+#$d_cppcanstdin CPP_CAN_STDIN /* can CPP read stdin directly? */
+
+/* HAS_ACCESS:
+ * This manifest constant lets the C program know that the access()
+ * system call is available to check for accessibility using real UID/GID.
+ * (always present on UNIX.)
+ */
+#$d_access HAS_ACCESS /**/
+
+/* HASATTRIBUTE:
+ * This symbol indicates the C compiler can check for function attributes,
+ * such as printf formats. This is normally only supported by GNU cc.
+ */
+#$d_attribut HASATTRIBUTE /**/
+#ifndef HASATTRIBUTE
+#define __attribute__(_arg_)
+#endif
+
+/* HASCONST:
+ * This symbol, if defined, indicates that this C compiler knows about
+ * the const type. There is no need to actually test for that symbol
+ * within your programs. The mere use of the "const" keyword will
+ * trigger the necessary tests.
+ */
+#$d_const HASCONST /**/
+#ifndef HASCONST
+#define const
+#endif
+
+/* FLEXFILENAMES:
+ * This symbol, if defined, indicates that the system supports filenames
+ * longer than 14 characters.
+ */
+#$d_flexfnam FLEXFILENAMES /**/
+
+/* HAS_LINK:
+ * This symbol, if defined, indicates that the link routine is
+ * available to create hard links.
+ */
+#$d_link HAS_LINK /**/
+
+/* HAS_OPEN3:
+ * This manifest constant lets the C program know that the three
+ * argument form of open(2) is available.
+ */
+#$d_open3 HAS_OPEN3 /**/
+
+/* HAS_STRCHR:
+ * This symbol is defined to indicate that the strchr()/strrchr()
+ * functions are available for string searching. If not, try the
+ * index()/rindex() pair.
+ */
+/* HAS_INDEX:
+ * This symbol is defined to indicate that the index()/rindex()
+ * functions are available for string searching.
+ */
+#$d_strchr HAS_STRCHR /**/
+#$d_index HAS_INDEX /**/
+
+/* HAS_STRFTIME:
+ * This symbol, if defined, indicates that the strftime routine is
+ * available to format locale-specific times.
+ */
+#$d_strftime HAS_STRFTIME /**/
+
+/* HAS_STRSTR:
+ * This symbol, if defined, indicates that the strstr routine is
+ * available to find substrings.
+ */
+#$d_strstr HAS_STRSTR /**/
+
+/* HAS_SYMLINK:
+ * This symbol, if defined, indicates that the symlink routine is available
+ * to create symbolic links.
+ */
+#$d_symlink HAS_SYMLINK /**/
+
+/* Time_t:
+ * This symbol holds the type returned by time(). It can be long,
+ * or time_t on BSD sites (in which case <sys/types.h> should be
+ * included).
+ */
+#define Time_t $timetype /* Time type */
+
+/* Signal_t:
+ * This symbol's value is either "void" or "int", corresponding to the
+ * appropriate return type of a signal handler. Thus, you can declare
+ * a signal handler using "Signal_t (*handler)()", and define the
+ * handler using "Signal_t handler(sig)".
+ */
+#define Signal_t $signal_t /* Signal handler's return type */
+
+/* HASVOLATILE:
+ * This symbol, if defined, indicates that this C compiler knows about
+ * the volatile declaration.
+ */
+#$d_volatile HASVOLATILE /**/
+#ifndef HASVOLATILE
+#define volatile
+#endif
+
+/* I_FCNTL:
+ * This manifest constant tells the C program to include <fcntl.h>.
+ */
+#$i_fcntl I_FCNTL /**/
+
+/* I_STDDEF:
+ * This symbol, if defined, indicates that <stddef.h> exists and should
+ * be included.
+ */
+#$i_stddef I_STDDEF /**/
+
+/* I_STDLIB:
+ * This symbol, if defined, indicates that <stdlib.h> exists and should
+ * be included.
+ */
+#$i_stdlib I_STDLIB /**/
+
+/* I_STRING:
+ * This symbol, if defined, indicates to the C program that it should
+ * include <string.h> (USG systems) instead of <strings.h> (BSD systems).
+ */
+#$i_string I_STRING /**/
+
+/* I_SYS_FILE:
+ * This symbol, if defined, indicates to the C program that it should
+ * include <sys/file.h> to get definition of R_OK and friends.
+ */
+#$i_sysfile I_SYS_FILE /**/
+
+/* I_SYS_TYPES:
+ * This symbol, if defined, indicates to the C program that it should
+ * include <sys/types.h>.
+ */
+#$i_systypes I_SYS_TYPES /**/
+
+/* I_TIME:
+ * This symbol, if defined, indicates to the C program that it should
+ * include <time.h>.
+ */
+/* I_SYS_TIME:
+ * This symbol, if defined, indicates to the C program that it should
+ * include <sys/time.h>.
+ */
+#$i_time I_TIME /**/
+#$i_systime I_SYS_TIME /**/
+
+/* I_UNISTD:
+ * This symbol, if defined, indicates to the C program that it should
+ * include <unistd.h>.
+ */
+#$i_unistd I_UNISTD /**/
+
+/* I_STDARG:
+ * This symbol, if defined, indicates that <stdarg.h> exists and should
+ * be included.
+ */
+/* I_VARARGS:
+ * This symbol, if defined, indicates to the C program that it should
+ * include <varargs.h>.
+ */
+#$i_stdarg I_STDARG /**/
+#$i_varargs I_VARARGS /**/
+
+/* CAN_PROTOTYPE:
+ * If defined, this macro indicates that the C compiler can handle
+ * function prototypes.
+ */
+/* DOTS:
+ * This macro is used to specify the ... in function prototypes which
+ * have arbitrary additional arguments.
+ */
+/* NXT_ARG:
+ * This macro is used to separate arguments in the declared argument list.
+ */
+/* P_FUNC:
+ * This macro is used to declare "private" (static) functions.
+ * It takes three arguments: the function type and name, a parenthesized
+ * traditional (comma separated) argument list, and the declared argument
+ * list (in which arguments are separated with NXT_ARG, and additional
+ * arbitrary arguments are specified with DOTS). For example:
+ *
+ * P_FUNC(int foo, (bar, baz), int bar NXT_ARG char *baz[])
+ */
+/* P_FUNC_VOID:
+ * This macro is used to declare "private" (static) functions that have
+ * no arguments. The macro takes one argument: the function type and name.
+ * For example:
+ *
+ * P_FUNC_VOID(int subr)
+ */
+/* V_FUNC:
+ * This macro is used to declare "public" (non-static) functions.
+ * It takes three arguments: the function type and name, a parenthesized
+ * traditional (comma separated) argument list, and the declared argument
+ * list (in which arguments are separated with NXT_ARG, and additional
+ * arbitrary arguments are specified with DOTS). For example:
+ *
+ * V_FUNC(int main, (argc, argv), int argc NXT_ARG char *argv[])
+ */
+/* V_FUNC_VOID:
+ * This macro is used to declare "public" (non-static) functions that have
+ * no arguments. The macro takes one argument: the function type and name.
+ * For example:
+ *
+ * V_FUNC_VOID(int fork)
+ */
+/* _:
+ * This macro is used to declare function parameters for folks who want
+ * to make declarations with prototypes using a different style than
+ * the above macros. Use double parentheses. For example:
+ *
+ * int main _((int argc, char *argv[]));
+ */
+#$prototype CAN_PROTOTYPE /**/
+#ifdef CAN_PROTOTYPE
+#define NXT_ARG ,
+#define DOTS , ...
+#define V_FUNC(name, arglist, args)name(args)
+#define P_FUNC(name, arglist, args)static name(args)
+#define V_FUNC_VOID(name)name(void)
+#define P_FUNC_VOID(name)static name(void)
+#define _(args) args
+#else
+#define NXT_ARG ;
+#define DOTS
+#define V_FUNC(name, arglist, args)name arglist args;
+#define P_FUNC(name, arglist, args)static name arglist args;
+#define V_FUNC_VOID(name)name()
+#define P_FUNC_VOID(name)static name()
+#define _(args) ()
+#endif
+
+/* CAN_VAPROTO:
+ * This variable is defined on systems supporting prototype declaration
+ * of functions with a variable number of arguments.
+ */
+/* _V:
+ * This macro is used to declare function parameters in prototypes for
+ * functions with a variable number of parameters. Use double parentheses.
+ * For example:
+ *
+ * int printf _V((char *fmt, ...));
+ *
+ * Remember to use the plain simple _() macro when declaring a function
+ * with no variable number of arguments, since it might be possible to
+ * have a non-effect _V() macro and still get prototypes via _().
+ */
+#$vaproto CAN_VAPROTO /**/
+#ifdef CAN_VAPROTO
+#define _V(args) args
+#else
+#define _V(args) ()
+#endif
+
+/* VOIDFLAGS:
+ * This symbol indicates how much support of the void type is given by this
+ * compiler. What various bits mean:
+ *
+ * 1 = supports declaration of void
+ * 2 = supports arrays of pointers to functions returning void
+ * 4 = supports comparisons between pointers to void functions and
+ * addresses of void functions
+ * 8 = suports declaration of generic void pointers
+ *
+ * The package designer should define VOIDUSED to indicate the requirements
+ * of the package. This can be done either by #defining VOIDUSED before
+ * including config.h, or by defining defvoidused in Myinit.U. If the
+ * latter approach is taken, only those flags will be tested. If the
+ * level of void support necessary is not present, defines void to int.
+ */
+#ifndef VOIDUSED
+#define VOIDUSED $defvoidused
+#endif
+#define VOIDFLAGS $voidflags
+#if (VOIDFLAGS & VOIDUSED) != VOIDUSED
+#define void int /* is void to be avoided? */
+#define M_VOID /* Xenix strikes again */
+#endif
+
+#endif
+!GROK!THIS!
diff --git a/confmagic.h b/confmagic.h
new file mode 100644
index 0000000..5cf0a4a
--- /dev/null
+++ b/confmagic.h
@@ -0,0 +1,27 @@
+/*
+ * This file was produced by running metaconfig and is intended to be included
+ * after config.h and after all the other needed includes have been dealt with.
+ *
+ * This file may be empty, and should not be edited. Rerun metaconfig instead.
+ * If you wish to get rid of this magic, remove this file and rerun metaconfig
+ * without the -M option.
+ *
+ * $Id: confmagic.h,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ */
+
+#ifndef _confmagic_h_
+#define _confmagic_h_
+
+#ifndef HAS_INDEX
+#ifndef index
+#define index strchr
+#endif
+#endif
+
+#ifndef HAS_INDEX
+#ifndef rindex
+#define rindex strrchr
+#endif
+#endif
+
+#endif
diff --git a/ctype_ex.h b/ctype_ex.h
new file mode 100644
index 0000000..5719a7f
--- /dev/null
+++ b/ctype_ex.h
@@ -0,0 +1,38 @@
+/* ctype.h - character classification functions */
+
+/* character is alphanumeric
+ * returns 0 if the character doesn't fit the
+ * classification; non-zero (but not necessarily 1)
+ * if it does.
+ */
+inline int isalnum(int c /* the character to classify */);
+
+/* character is a letter */
+inline int isalpha(int c);
+
+/* character is a control character */
+inline int iscntrl(int c);
+
+/* character is a digit */
+inline int isdigit(int c);
+
+/* character is a graphic */
+inline int isgraph(int c);
+
+/* character is a lower case letter */
+inline int islower(int c);
+
+/* character is printable */
+inline int isprint(int c);
+
+/* character is punctuation */
+inline int ispunct(int c);
+
+/* character is a a form of whitespace */
+inline int isspace(int c);
+
+/* character is an upper case letter */
+inline int isupper(int c);
+
+/* character is a hexadecimal digit */
+inline int isxdigit(int c);
diff --git a/eg/boxcomment.c b/eg/boxcomment.c
new file mode 100644
index 0000000..f5f0379
--- /dev/null
+++ b/eg/boxcomment.c
@@ -0,0 +1,41 @@
+/***************************************************************************
+ * C style box comment.
+ *
+ * This function has a very pretty C style box comment.
+ ***************************************************************************/
+void boxcomm_c1(void);
+
+/***************************************************************************
+/ Fancier C style box comment.
+/
+/ This function has a very pretty C style box comment.
+/***************************************************************************/
+void boxcomm_c2(void);
+
+/***************************************************************************
+/*** Even Fancier C style box comment.
+/***
+/*** This function has a very pretty C style box comment.
+/***************************************************************************/
+void boxcomm_c3(void);
+
+/*-------------------------------------------------------------------------
+ * C style box comment.
+ *
+ * This function has a dashed C style box comment.
+ *-------------------------------------------------------------------------*/
+void boxcomm_c4(void);
+
+////////////////////////////////////////////////////////////////////////////
+// C++ style box comment.
+//
+// This function has a very pretty C++ style box comment.
+////////////////////////////////////////////////////////////////////////////
+void boxcomm_cpp1(void);
+
+////////////////////////////////////////////////////////////////////////////
+//// Fancier C++ style box comment.
+////
+//// This function has a very pretty C++ style box comment.
+////////////////////////////////////////////////////////////////////////////
+void boxcomm_cpp2(void);
diff --git a/eg/ccomment.h b/eg/ccomment.h
new file mode 100644
index 0000000..86bb7cd
--- /dev/null
+++ b/eg/ccomment.h
@@ -0,0 +1,41 @@
+/*
+** function starting with a C comment
+*/
+void ccomment(
+ /* single line before */
+ int single_before,
+
+ /*
+ * multiple
+ * lines before
+ */
+ int multiple_before,
+
+ int end_of_line, /* end of the line */
+
+ int multiple_eol, /*
+ * multiple lines
+ * starting at
+ * the EOL
+ */
+
+ int single_eol_before_comma /* end of line, but before comma */,
+
+ int multiple_eol_before_comma /*
+ * multiple lines after, at the EOL and
+ * before comma.
+ * can't imagine anyone coding this.
+ */,
+
+ int single_after
+ /* single line after */
+ ,
+
+ int multiple_after
+ /*
+ * multiple lines
+ * after.
+ * can't imagine anyone coding like this.
+ */
+);
+
diff --git a/eg/commentaft.c b/eg/commentaft.c
new file mode 100644
index 0000000..29e86d8
--- /dev/null
+++ b/eg/commentaft.c
@@ -0,0 +1 @@
+int commentafter; /* you'll need -v to get this documented */
diff --git a/eg/cppcomment.h b/eg/cppcomment.h
new file mode 100644
index 0000000..2f4ff90
--- /dev/null
+++ b/eg/cppcomment.h
@@ -0,0 +1,32 @@
+//
+// function starting with a C++ comment
+//
+void cppcomment(
+ // single line before
+ int single_before,
+
+ //
+ // multiple
+ // lines before
+ //
+ int multiple_before,
+
+ int end_of_line, // end of the line
+
+ int multiple_eol, //
+ // multiple lines
+ // starting at
+ // the EOL
+ //
+
+ int single_after
+ // single line after
+ ,
+ int multiple_after
+ //
+ // multiple lines
+ // after.
+ // cant imagine anyone coding like this.
+ //
+);
+
diff --git a/eg/dash.h b/eg/dash.h
new file mode 100644
index 0000000..bc3502b
--- /dev/null
+++ b/eg/dash.h
@@ -0,0 +1,2 @@
+/* dash - comment with a dash. */
+int dash(int x);
diff --git a/eg/ellipsis.c b/eg/ellipsis.c
new file mode 100644
index 0000000..0842f6a
--- /dev/null
+++ b/eg/ellipsis.c
@@ -0,0 +1,15 @@
+int pr(int,...);
+
+void main(void)
+{
+ pr(3, 'a', 'b', 'c');
+}
+
+/* ellipsis test function */
+int pr(
+ int nitems, /* number of items */
+ ... /* items */
+)
+{
+ /* blah, blah, blah, blah, blah! */
+}
diff --git a/eg/grouped.c b/eg/grouped.c
new file mode 100644
index 0000000..05f3a27
--- /dev/null
+++ b/eg/grouped.c
@@ -0,0 +1,23 @@
+/*
+ * grouped functions
+ *
+ */
+
+/* my grouped1 does something weird */
+grouped1(a,b)
+int a; /* the a parameter */
+char b; /* the b parameter */
+{
+
+ /* do nothing */
+ return(1);
+}
+/* my grouped2 does also something weird */
+grouped2(a,b)
+int a; /* the a parameter */
+char *b;/* the b parameter */
+{
+
+ /* do nothing */
+ return(1);
+}
diff --git a/eg/multidecl.c b/eg/multidecl.c
new file mode 100644
index 0000000..70ffa3f
--- /dev/null
+++ b/eg/multidecl.c
@@ -0,0 +1,3 @@
+int multidecl1, /* the first one */
+ multidecl2, /* the second one */
+ multidecl3; /* the last one */
diff --git a/eg/namedash.h b/eg/namedash.h
new file mode 100644
index 0000000..6d05848
--- /dev/null
+++ b/eg/namedash.h
@@ -0,0 +1,9 @@
+/*
+ * NAME
+ * namedash - name section with dash.
+ *
+ * DESCRIPTION
+ * This function goes way over the top and includes a NAME section that
+ * has a dash in it.
+ */
+int namedash();
diff --git a/eg/oldstyle.c b/eg/oldstyle.c
new file mode 100644
index 0000000..ec4bb8b
--- /dev/null
+++ b/eg/oldstyle.c
@@ -0,0 +1,24 @@
+/*
+** old-style function starting with a C comment
+*/
+void oldstyle(single_before, multiple_before, end_of_line, multiple_eol)
+
+/* single line before */
+int single_before;
+
+/*
+ * multiple
+ * lines before
+ */
+int multiple_before;
+
+int end_of_line; /* end of the line */
+
+int multiple_eol; /*
+ * multiple lines
+ * starting at
+ * the EOL
+ */
+{
+ /* blah, blah, blah, blah, blah! */
+}
diff --git a/eg/retdecl.c b/eg/retdecl.c
new file mode 100644
index 0000000..6675c8d
--- /dev/null
+++ b/eg/retdecl.c
@@ -0,0 +1,10 @@
+/* return near the declarator
+ * This is an example of embedding the `returns' information in near the
+ * declarator in a function declaration.
+ */
+char * /* a string, or NULL if it failed */
+retdecl()
+{
+ /* reference implementation that barely meets the interface spec */
+ return NULL;
+}
diff --git a/eg/returnerr.h b/eg/returnerr.h
new file mode 100644
index 0000000..2292585
--- /dev/null
+++ b/eg/returnerr.h
@@ -0,0 +1,16 @@
+/*
+ * Do an operating system operation
+ * This is an example of a function which performs some sort of operating
+ * system operation, returning an errno-like indication of its success or
+ * failure. We'd like the documentation to list all the possible failure
+ * indications that this function can return, which is only a tiny subset of
+ * all the possible errno values. Hence, we don't define it as returning an
+ * enum of some sort, since that would cause c2man to list every possible value
+ * that type can have.
+ * Returns an indication of success or failure, as follows:
+ * EOK: Success
+ * EIO: I/O error
+ * ENOMEM: Out of memory
+ * EIEIO: Old Macdonald error
+ */
+int reterrno();
diff --git a/eg/returnlist.h b/eg/returnlist.h
new file mode 100644
index 0000000..819f652
--- /dev/null
+++ b/eg/returnlist.h
@@ -0,0 +1,16 @@
+/* generate a lot of silly values
+ * Returns: Quite a number of things, as follows:
+ * 0 nothing
+ * 1 something small
+ * 2 a little larger
+ * 3 done in triplicate
+ * 4 getting larger
+ * 5 quintuplets
+ * 6 that'll do now, although I think this one is going to get
+ * very long and even cover multiple lines. let's just hope that
+ * it gets it right, including the capitalisation. maybe this is
+ * not a super thorough test, so including some
+ * .B bold
+ * stuff might help
+ */
+int returnlist();
diff --git a/eg/sections.c b/eg/sections.c
new file mode 100644
index 0000000..8a84a00
--- /dev/null
+++ b/eg/sections.c
@@ -0,0 +1,17 @@
+/*
+ * NAME
+ * sections - multisection function comment.
+ *
+ * DESCRIPTION
+ * Only a mental cripple would be as verbose as this.
+ *
+ * WARNING
+ * Now here's a legitimate excuse for it.
+ */
+int sections(
+ int fred, /* Mary's boyfriend */
+ int world /* real crazy */
+)
+{
+ what the heck, all this stuff just gets ignored
+}
diff --git a/eg/simplesect.c b/eg/simplesect.c
new file mode 100644
index 0000000..8d6f4ed
--- /dev/null
+++ b/eg/simplesect.c
@@ -0,0 +1,13 @@
+/*
+ * calculate some sections.
+ * Note: this becomes the description.
+ *
+ * Warning: This becomes a section.
+ */
+int simplesect(
+ int fred, /* Mary's boyfriend */
+ int world /* real crazy */
+)
+{
+ what the heck, all this stuff just gets ignored
+}
diff --git a/eg/surround.c b/eg/surround.c
new file mode 100644
index 0000000..e050056
--- /dev/null
+++ b/eg/surround.c
@@ -0,0 +1,6 @@
+/* surrounded by comments.
+ * this is the first one, and only it should be output.
+ *
+ * note: you'll need -v to get output from this.
+ */
+int surround; /* this should NOT be output. */
diff --git a/eg/underscore.h b/eg/underscore.h
new file mode 100644
index 0000000..e57e6d5
--- /dev/null
+++ b/eg/underscore.h
@@ -0,0 +1,21 @@
+/* parameter names have underscores
+ * the underscores get removed in the documentation
+ */
+void underscore(
+ /* an int */
+ int __x,
+
+ /* a pointer to an int */
+ int *__y,
+
+ /* another pointer to an int, funnily enough */
+ int _z[],
+
+ /* a char, with a strange bit legal name */
+ char _,
+
+ /* an anonymous double */
+ double,
+
+ /* pointer to a function */
+ float (*__funcptr)(int *__a1, char __a2[]));
diff --git a/eg/variable.c b/eg/variable.c
new file mode 100644
index 0000000..a788e82
--- /dev/null
+++ b/eg/variable.c
@@ -0,0 +1,5 @@
+/* a variable, not a function.
+ *
+ * Note: you'll need to use -v to get this to work.
+ */
+int variable;
diff --git a/enum.c b/enum.c
new file mode 100644
index 0000000..fd6c1ac
--- /dev/null
+++ b/enum.c
@@ -0,0 +1,179 @@
+/* $Id: enum.c,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ * enumerator operations
+ */
+#include "c2man.h"
+#include "strconcat.h"
+#include "enum.h"
+#include "manpage.h"
+
+SymbolTable *enum_table; /* enum symbol table */
+
+/* we have to keep a list of EnumeratorLists because:
+ * - unnamed EnumeratorLists can't go in the symbol table.
+ * - a single EnumeratorList can be typedef'ed or enum'ed to more than one
+ * symbol, in which case it is referenced from the typedef_table or
+ * enum_table repectively more than once.
+ */
+EnumeratorList *first_list = NULL, **last_next_list = &first_list;
+
+/* Initialize a list of enumerators.*/
+EnumeratorList *
+new_enumerator_list (enumerator)
+ Enumerator *enumerator;
+{
+ Enumerator *p;
+ EnumeratorList *list;
+
+ list = (EnumeratorList *)safe_malloc(sizeof *list);
+ *last_next_list = list;
+ last_next_list = &list->next;
+ list->next = NULL;
+
+ p = (Enumerator *)safe_malloc(sizeof(Enumerator));
+ *p = *enumerator;
+
+ list->first = list->last = p;
+ p->next = NULL;
+ return list;
+}
+
+/* Add the enumerator to the list. */
+void
+add_enumerator_list (list, enumerator)
+ EnumeratorList *list;
+ Enumerator *enumerator;
+{
+ Enumerator *p;
+
+ p = (Enumerator *)safe_malloc((unsigned)sizeof(Enumerator));
+ *p = *enumerator;
+
+ list->last->next = p;
+ list->last = p;
+ p->next = NULL;
+}
+
+/* Free storage used by the elements in the enumerator list. */
+void
+free_enumerator_list (enumerator_list)
+ EnumeratorList *enumerator_list;
+{
+ Enumerator *p, *next;
+
+ p = enumerator_list->first;
+ while (p != NULL) {
+ next = p->next;
+ free_enumerator(p);
+ free(p);
+ p = next;
+ }
+}
+
+
+void
+new_enumerator(e, name, comment_before, comment_after)
+ Enumerator *e;
+ char *name;
+ char *comment_before;
+ char *comment_after;
+{
+ e-> name = name;
+ e-> comment = comment_after ? comment_after : comment_before;
+ e-> group_comment = comment_before && comment_after ? comment_before : NULL;
+}
+
+/* Free the storage used by the enumerator.*/
+void
+free_enumerator (param)
+ Enumerator *param;
+{
+ free(param->name);
+ safe_free(param->comment);
+ safe_free(param->group_comment);
+}
+
+/* add a comment to the last enumerator in the list */
+int
+comment_last_enumerator(list, comment)
+ EnumeratorList *list;
+ char *comment;
+{
+ if (list->last->comment)
+ {
+ if (list->last->group_comment)
+ {
+ enumerator_error(list->last->name);
+ free(comment);
+ return 0;
+ }
+
+ list->last->group_comment = list->last->comment;
+ }
+
+ list->last->comment = comment;
+ return 1;
+}
+
+/* enum namespace management */
+void add_enum_symbol(name, enum_list)
+ char *name;
+ EnumeratorList *enum_list;
+{
+ Symbol *entry = new_symbol(enum_table, name, DS_NONE);
+
+ if (entry)
+ {
+ entry->value.enum_list = enum_list;
+ entry->valtype = SYMVAL_ENUM;
+ }
+}
+
+/* look for the Enumerator list associated with the symbol */
+EnumeratorList *find_enum_symbol(name)
+ char *name;
+{
+ Symbol *entry = find_symbol(enum_table, name);
+
+ if (entry)
+ return entry->value.enum_list;
+ else
+ return NULL;
+}
+
+void destroy_enum_lists()
+{
+ EnumeratorList *list, *next;
+
+ /* free all the enumerator lists */
+ for (list = first_list; list; list = next)
+ {
+ next = list->next;
+ free_enumerator_list(list);
+ free(list);
+ }
+}
+
+/* create new typedef symbols */
+void new_typedef_symbols(decl_spec, decl_list)
+ DeclSpec *decl_spec;
+ DeclaratorList *decl_list;
+{
+ Declarator *d;
+
+ for (d = decl_list->first; d; d = d-> next)
+ {
+ Symbol *s = new_symbol(typedef_names, d->name, DS_NONE);
+
+ if (s && decl_spec->enum_list)
+ {
+ s->value.enum_list = decl_spec->enum_list;
+ s->valtype = SYMVAL_ENUM;
+ }
+ }
+}
+
+void enumerator_error(name)
+ char *name;
+{
+ yyerror("enumerator '%s' has multiple comments", name);
+}
diff --git a/enum.h b/enum.h
new file mode 100644
index 0000000..3e6606e
--- /dev/null
+++ b/enum.h
@@ -0,0 +1,41 @@
+/* $Id: enum.h,v 1.1 2004-05-03 05:17:48 behdad Exp $ */
+#include "config.h"
+
+extern SymbolTable *enum_table; /* enum symbol table */
+
+/* Initialize a list of enumerators.*/
+EnumeratorList *
+new_enumerator_list _((Enumerator *enumerator));
+
+/* Add the enumerator to the list. */
+void
+add_enumerator_list _((EnumeratorList *list, Enumerator *enumerator));
+
+/* Free storage used by the elements in the enumerator list. */
+void
+free_enumerator_list _((EnumeratorList *enumerator_list));
+
+void
+new_enumerator _((Enumerator *e, char *name,
+ char *comment_before, char *comment_after));
+
+/* Free the storage used by the enumerator.*/
+void
+free_enumerator _((Enumerator *param));
+
+/* add a comment to the last enumeralor in the list */
+int
+comment_last_enumerator _((EnumeratorList *enum_list, char *comment));
+
+/* enum namespace management */
+void add_enum_symbol _((char *name, EnumeratorList *first_enum));
+
+/* look for the first enumerator associated with the symbol */
+EnumeratorList *find_enum_symbol _((char *name));
+
+void destroy_enum_lists();
+
+/* create new typedef symbols */
+void new_typedef_symbols _((DeclSpec *decl_spec, DeclaratorList *decl_list));
+
+void enumerator_error _((char *name));
diff --git a/example.h b/example.h
new file mode 100644
index 0000000..61ac8d5
--- /dev/null
+++ b/example.h
@@ -0,0 +1,18 @@
+enum Place
+{
+ HOME, /* Home, Sweet Home */
+ WORK, /* where I spend lots of time */
+ MOVIES, /* Saturday nights mainly */
+ CITY, /* New York, New York */
+ COUNTRY /* Bob's Country Bunker */
+};
+
+/*
+ * do some useful work for a change.
+ * This function will actually get some productive
+ * work done, if you are really lucky.
+ * returns the number of milliseconds in a second.
+ */
+int dowork(int count, /* how much work to do */
+ enum Place where, /* where to do the work */
+ long fiveoclock /* when to knock off */);
diff --git a/fixexamp.in b/fixexamp.in
new file mode 100644
index 0000000..7131705
--- /dev/null
+++ b/fixexamp.in
@@ -0,0 +1,60 @@
+# $Id: fixexamp.in,v 1.1 2004-05-03 05:17:49 behdad Exp $
+# Fix up c2man output for inclusion of examples in the c2man manual page.
+# This file gets processed to remove comments because some sed's can't handle
+# them. Can you believe it?.
+
+# The double backslashes in variable interpolations are because sed consumes
+# one, not because we're defining macros here (we aren't).
+
+# special hack: rename ctype_ex to ctype just to make that example neat.
+s/ctype_ex/ctype/
+
+# replace the .TH line with a title line.
+# we only alter the title length just as the title line is output so an example
+# that goes over a page break doesn't damage the real manual page's header.
+# Also, calculate and remember the shortened line length: groff doesn't reset
+# .ll in .SH & .TP macros, so we use an absolute value later rather than
+# relative changes.
+/^\.TH /{
+s/^\.TH "\([^"]*\)" \([^ ]*\) .*/.ds [H \1\\|(\\|\2\\|)/
+a\
+.ds [D UNIX Programmer's Manual\
+.po +1i\
+.lt -1.5i\
+.tl @\\*([H@\\*([D@\\*([H@\
+.lt +1.5i\
+.po -1i\
+.RS +1i\
+.nr CL \\n(.l-0.5i
+}
+
+# surround all the .SH and .SS lines with page offset indents
+# the .ne line will force a page break before the .po is evaluated, in the case
+# where a .SH in an example is at the very bottom of the page. Otherwise the .SH
+# could cause the break, resulting in the wrong .po setting for the new page's
+# title line.
+/^\.S[SH] /{
+i\
+.br\
+.ne 3\
+.RE\
+.po +1i
+a\
+.po -1i\
+.RS +1i\
+.ll \\n(CLu
+}
+
+# handle tagged paragraphs; .TP retains .RS setting, but resets .ll
+# since the parameter to .TP is on the next line, we read the next line in first
+/^.TP/{
+n
+a\
+.ll \\n(CLu
+}
+
+# up the line length again at the end of the example file
+$a\
+.ll \\n(CLu+0.5i\
+.RE
+
diff --git a/flatten.SH b/flatten.SH
new file mode 100644
index 0000000..4dafdc3
--- /dev/null
+++ b/flatten.SH
@@ -0,0 +1,51 @@
+case $CONFIG in
+'')
+ if test -f config.sh; then TOP=.;
+ elif test -f ../config.sh; then TOP=..;
+ elif test -f ../../config.sh; then TOP=../..;
+ elif test -f ../../../config.sh; then TOP=../../..;
+ elif test -f ../../../../config.sh; then TOP=../../../..;
+ else
+ echo "Can't find config.sh."; exit 1
+ fi
+ . $TOP/config.sh
+ ;;
+esac
+: This forces SH files to create target in same directory as SH file.
+: This is so that make depend always knows where to find SH derivatives.
+case "$0" in
+*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
+esac
+echo "Extracting flatten.sed (with variable substitutions)"
+: This section of the file will have variable substitutions done on it.
+: Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!.
+: Protect any dollar signs and backticks that you do not want interpreted
+: by putting a backslash in front. You may delete these comments.
+$spitshell >flatten.sed <<!GROK!THIS!
+s!\$(privlib)!$privlib!
+!GROK!THIS!
+
+: In the following dollars and backticks do not need the extra backslash.
+$spitshell >>flatten.sed <<'!NO!SUBS!'
+/^.so *example.h$/{
+r example.h
+d
+}
+
+/^.so *example.inc$/{
+r example.inc
+d
+}
+
+/^.so *ctype_ex.h$/{
+r ctype_ex.h
+d
+}
+
+/^.so *ctype_ex.inc$/{
+r ctype_ex.inc
+d
+}
+!NO!SUBS!
+chmod 755 flatten.sed
+$eunicefix flatten.sed
diff --git a/grammar.y b/grammar.y
new file mode 100644
index 0000000..9721dbe
--- /dev/null
+++ b/grammar.y
@@ -0,0 +1,947 @@
+/* $Id: grammar.y,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ *
+ * yacc grammar for C manual page generator
+ * This was derived from the grammar given in Appendix A of
+ * "The C Programming Language" by Kernighan and Ritchie.
+ */
+
+/* identifiers that are not reserved words */
+%token T_IDENTIFIER T_TYPEDEF_NAME
+
+/* storage class */
+%token T_AUTO T_EXTERN T_REGISTER T_STATIC T_TYPEDEF
+/* This keyword included for compatibility with C++. */
+%token T_INLINE
+
+/* type specifiers */
+%token T_CHAR T_DOUBLE T_FLOAT T_INT T_VOID
+%token T_LONG T_SHORT T_SIGNED T_UNSIGNED
+%token T_ENUM T_STRUCT T_UNION
+
+/* type qualifiers */
+%token T_CONST T_VOLATILE
+/* These keywords included for compatibility with MSDOS C compilers. */
+%token T_CDECL T_FAR T_HUGE T_INTERRUPT T_NEAR T_PASCAL
+
+/* paired braces and everything between them: { ... } */
+%token T_BRACES
+
+/* paired square brackets and everything between them: [ ... ] */
+%token T_BRACKETS
+
+/* three periods */
+%token T_ELLIPSIS
+
+/* equal sign followed by constant expression or stuff between braces */
+%token T_INITIALIZER
+
+/* string literal */
+%token T_STRING_LITERAL
+
+/* text inside a regular comment, and one at the end of a non-empty line */
+%token T_COMMENT T_EOLCOMMENT
+
+%type <declaration> declaration
+%type <parameter> function_definition
+%type <decl_spec> declaration_specifiers declaration_specifier
+%type <decl_spec> storage_class type_specifier type_qualifier
+%type <decl_spec> struct_or_union_specifier enum_specifier
+%type <decl_list> declarator_list init_declarator_list
+%type <declarator> init_declarator declarator direct_declarator
+%type <declarator> parameter_declarator abstract_parameter_declarator
+%type <declarator> abstract_declarator direct_abstract_declarator
+%type <param_list> parameter_type_list parameter_list
+%type <parameter> parameter_declaration
+%type <param_list> opt_identifier_list identifier_list
+%type <enumerator> enumerator
+%type <enum_list> enumerator_list
+%type <identifier> identifier
+%type <text> struct_or_union
+%type <text> pointer type_qualifier_list
+%type <text> opt_comment opt_eolcomment
+%type <text> any_id T_IDENTIFIER T_TYPEDEF_NAME
+%type <text> T_BRACKETS
+%type <text> T_COMMENT T_EOLCOMMENT T_STRING_LITERAL
+
+%{
+#include "c2man.h"
+#include "semantic.h"
+#include "strconcat.h"
+#include "strappend.h"
+#include "manpage.h"
+#include "enum.h"
+
+#ifdef I_STDARG
+#include <stdarg.h>
+#endif
+#ifdef I_VARARGS
+#include <varargs.h>
+#endif
+
+int yylex();
+
+#define YYMAXDEPTH 150
+
+/* where are we up to scanning through an enum? */
+static enum { NOENUM, KEYWORD, BRACES } enum_state = NOENUM;
+
+/* Pointer to parameter list for the current function definition. */
+static ParameterList *func_params;
+
+/* Table of typedef names */
+SymbolTable *typedef_names;
+
+boolean first_comment; /* are we still looking for the first comment? */
+static char *body_comment = NULL;/* last comment found at start of func body */
+%}
+%%
+
+program
+ : /* empty */
+ | translation_unit
+ ;
+
+translation_unit
+ : external_declaration
+ | translation_unit external_declaration
+ ;
+
+external_declaration
+ : declaration opt_eolcomment
+ {
+ remember_declarations(NULL, &$1.decl_spec, &$1.decl_list, $2);
+ }
+ | T_COMMENT declaration opt_eolcomment
+ {
+ remember_declarations($1, &$2.decl_spec, &$2.decl_list, $3);
+ }
+ | function_definition opt_eolcomment
+ {
+ if (look_at_body_start && body_comment) {
+ /* Use the body comment */
+ new_manual_page(body_comment,&$1.decl_spec,$1.declarator);
+ body_comment = NULL; /* Prevent it being free'ed */
+ } else {
+ free_declarator($1.declarator);
+ free_decl_spec(&$1.decl_spec);
+ }
+ }
+ | T_COMMENT function_definition opt_eolcomment
+ {
+ if (body_start_only) {
+ if (body_comment) {
+ new_manual_page(body_comment,&$2.decl_spec,$2.declarator);
+ body_comment = NULL; /* Prevent it being free'ed */
+ } else {
+ free_declarator($2.declarator);
+ free_decl_spec(&$2.decl_spec);
+ safe_free($1);
+ }
+ } else {
+ new_manual_page($1,&$2.decl_spec,$2.declarator);
+ }
+ safe_free($3);
+ }
+ | function_definition ';' opt_eolcomment
+ {
+ if (look_at_body_start && body_comment) {
+ new_manual_page(body_comment,&$1.decl_spec,$1.declarator);
+ body_comment = NULL; /* Prevent it being free'ed */
+ } else {
+ free_declarator($1.declarator);
+ free_decl_spec(&$1.decl_spec);
+ }
+ safe_free($3);
+ }
+ | T_COMMENT function_definition ';' opt_eolcomment
+ {
+ if (body_start_only) {
+ if (body_comment) {
+ new_manual_page(body_comment,&$2.decl_spec,$2.declarator);
+ body_comment = NULL; /* Prevent it being free'ed */
+ } else {
+ free_declarator($2.declarator);
+ free_decl_spec(&$2.decl_spec);
+ safe_free($1);
+ }
+ } else {
+ new_manual_page($1,&$2.decl_spec,$2.declarator);
+ }
+ safe_free($4);
+ }
+ | linkage_specification
+ | T_COMMENT T_EOLCOMMENT
+ {
+ free($1);
+ free($2);
+ }
+ | T_COMMENT
+ {
+ if (inbasefile && first_comment)
+ {
+ remember_terse($1);
+ first_comment = FALSE;
+ }
+ free($1);
+ }
+ | T_EOLCOMMENT
+ {
+ free($1);
+ }
+ | error ';'
+ {
+ yyerrok;
+ }
+ ;
+
+linkage_specification
+ : T_EXTERN T_STRING_LITERAL T_BRACES
+ {
+ /* Provide an empty action here so bison will not complain about
+ * incompatible types in the default action it normally would
+ * have generated.
+ */
+ }
+ | T_EXTERN T_STRING_LITERAL declaration
+ {
+ /* empty */
+ }
+ ;
+
+function_definition
+ : declaration_specifiers declarator opt_eolcomment
+ {
+ if ($2->type != DECL_FUNCTION) {
+ yyerror("syntax error");
+ YYERROR;
+ }
+ func_params = &($2->head->params);
+ if ($3) comment_last_parameter(&$2->head->params, $3);
+ }
+ opt_declaration_list T_BRACES
+ {
+ func_params = NULL;
+ $2->type = DECL_FUNCDEF;
+
+ $$.decl_spec = $1;
+ $$.declarator = $2;
+ }
+ | declarator opt_eolcomment
+ {
+ if ($1->type != DECL_FUNCTION) {
+ yyerror("syntax error");
+ YYERROR;
+ }
+ func_params = &($1->head->params);
+ if ($2) comment_last_parameter(&$1->head->params, $2);
+ }
+ opt_declaration_list T_BRACES
+ {
+ DeclSpec decl_spec;
+
+ func_params = NULL;
+ $1->type = DECL_FUNCDEF;
+
+ new_decl_spec(&$$.decl_spec, "int", DS_NONE);
+ $$.declarator = $1;
+ }
+ ;
+
+declaration
+ : declaration_specifiers ';'
+ {
+ $$.decl_spec = $1;
+ $$.decl_list.first = NULL;
+ }
+ | declaration_specifiers init_declarator_list ';'
+ {
+ $$.decl_spec = $1;
+ $$.decl_list = $2;
+ }
+ | T_TYPEDEF declaration_specifiers declarator_list ';'
+ {
+ new_typedef_symbols(&$2,&$3);
+ $$.decl_spec = $2;
+ $$.decl_list = $3;
+ }
+ ;
+
+declarator_list
+ : declarator
+ {
+ new_decl_list(&$$, $1);
+ }
+ | declarator_list ',' opt_eolcomment declarator
+ {
+ if ($3) comment_last_decl(&$1, $3);
+ add_decl_list(&$$, &$1, $4);
+ }
+ | declarator_list opt_eolcomment
+ {
+ $$ = $1;
+ if ($2) comment_last_decl(&$1, $2);
+ }
+ ;
+
+opt_declaration_list
+ : /* empty */
+ | declaration_list
+ | declaration_list T_ELLIPSIS
+ ;
+
+declaration_list
+ : opt_comment declaration opt_eolcomment
+ {
+ set_param_types(func_params, &$2.decl_spec, &$2.decl_list, $1, $3);
+ }
+ | declaration_list opt_comment declaration opt_eolcomment
+ {
+ set_param_types(func_params, &$3.decl_spec, &$3.decl_list, $2, $4);
+ }
+ ;
+
+declaration_specifiers
+ : declaration_specifier
+ | declaration_specifiers declaration_specifier
+ {
+ join_decl_specs(&$$, &$1, &$2);
+ }
+ ;
+
+declaration_specifier
+ : storage_class
+ | type_specifier
+ | type_qualifier
+ ;
+
+storage_class
+ : T_AUTO
+ {
+ new_decl_spec(&$$, "auto", DS_NONE);
+ }
+ | T_EXTERN
+ {
+ new_decl_spec(&$$, "extern", DS_EXTERN);
+ }
+ | T_REGISTER
+ {
+ new_decl_spec(&$$, "register", DS_NONE);
+ }
+ | T_STATIC
+ {
+ new_decl_spec(&$$, "static", DS_STATIC);
+ }
+ | T_INLINE
+ {
+ new_decl_spec(&$$, "inline", DS_INLINE);
+ }
+ ;
+
+type_specifier
+ : T_CHAR
+ {
+ new_decl_spec(&$$, "char", DS_CHAR);
+ }
+ | T_DOUBLE
+ {
+ new_decl_spec(&$$, "double", DS_NONE);
+ }
+ | T_FLOAT
+ {
+ new_decl_spec(&$$, "float", DS_FLOAT);
+ }
+ | T_INT
+ {
+ new_decl_spec(&$$, "int", DS_NONE);
+ }
+ | T_LONG
+ {
+ new_decl_spec(&$$, "long", DS_NONE);
+ }
+ | T_SHORT
+ {
+ new_decl_spec(&$$, "short", DS_SHORT);
+ }
+ | T_SIGNED
+ {
+ new_decl_spec(&$$, "signed", DS_NONE);
+ }
+ | T_UNSIGNED
+ {
+ new_decl_spec(&$$, "unsigned", DS_NONE);
+ }
+ | T_VOID
+ {
+ new_decl_spec(&$$, "void", DS_NONE);
+ }
+ | struct_or_union_specifier
+ | enum_specifier
+ | T_TYPEDEF_NAME
+ {
+ Symbol *s = find_symbol(typedef_names, $1);
+
+ new_enum_decl_spec(&$$, $1, s->flags,
+ s->valtype == SYMVAL_ENUM ? s->value.enum_list
+ : (EnumeratorList *)NULL);
+ }
+ ;
+
+type_qualifier
+ : T_CONST
+ {
+ new_decl_spec(&$$, "const", DS_NONE);
+ }
+ | T_VOLATILE
+ {
+ new_decl_spec(&$$, "volatile", DS_NONE);
+ }
+ | T_CDECL
+ {
+ new_decl_spec(&$$, "cdecl", DS_NONE);
+ }
+ | T_INTERRUPT
+ {
+ new_decl_spec(&$$, "interrupt", DS_NONE);
+ }
+ | T_FAR
+ {
+ new_decl_spec(&$$, "far", DS_NONE);
+ }
+ | T_HUGE
+ {
+ new_decl_spec(&$$, "huge", DS_NONE);
+ }
+ | T_NEAR
+ {
+ new_decl_spec(&$$, "near", DS_NONE);
+ }
+ | T_PASCAL
+ {
+ new_decl_spec(&$$, "pascal", DS_NONE);
+ }
+ ;
+
+struct_or_union_specifier
+ : struct_or_union any_id T_BRACES
+ {
+ dyn_decl_spec(&$$, strconcat($1, " ",$2," {}",NULLCP), DS_NONE);
+ free($2);
+ }
+ | struct_or_union T_BRACES
+ {
+ dyn_decl_spec(&$$, strconcat($1," {}",NULLCP), DS_NONE);
+ }
+ | struct_or_union any_id
+ {
+ dyn_decl_spec(&$$, strconcat($1, " ",$2,NULLCP), DS_NONE);
+ free($2);
+ }
+ ;
+
+struct_or_union
+ : T_STRUCT
+ {
+ $$ = "struct";
+ }
+ | T_UNION
+ {
+ $$ = "union";
+ }
+ ;
+
+init_declarator_list
+ : init_declarator
+ {
+ new_decl_list(&$$, $1);
+ }
+ | init_declarator_list ',' opt_eolcomment init_declarator
+ {
+ if ($3) comment_last_decl(&$1, $3);
+ add_decl_list(&$$, &$1, $4);
+ }
+ | init_declarator_list opt_eolcomment
+ {
+ $$ = $1;
+ if ($2) comment_last_decl(&$1, $2);
+ }
+ ;
+
+init_declarator
+ : declarator
+ | declarator T_INITIALIZER
+ ;
+
+enum_specifier
+ : T_ENUM any_id '{' opt_eolcomment enumerator_list '}'
+ {
+ add_enum_symbol($2, $5);
+ new_enum_decl_spec(&$$, strconcat("enum ",$2," {}",NULLCP),
+ DS_NONE, $5);
+ free($2);
+ safe_free($4);
+ enum_state = NOENUM;
+ }
+ | T_ENUM '{' opt_eolcomment enumerator_list '}'
+ {
+ new_enum_decl_spec(&$$, strduplicate("enum {}"), DS_NONE, $4);
+ safe_free($3);
+ enum_state = NOENUM;
+ }
+ | T_ENUM any_id
+ {
+ new_enum_decl_spec(&$$, strconcat("enum ",$2,NULLCP), DS_NONE,
+ find_enum_symbol($2));
+ free($2);
+ enum_state = NOENUM;
+ }
+ ;
+
+enumerator_list
+ : enumerator
+ {
+ $$ = new_enumerator_list(&$1);
+ }
+ | enumerator_list ',' opt_eolcomment enumerator
+ {
+ $$ = $1;
+ if ($3) comment_last_enumerator($$, $3);
+ add_enumerator_list($$, &$4);
+ }
+ | enumerator_list opt_eolcomment
+ {
+ $$ = $1;
+ if ($2) comment_last_enumerator($$, $2);
+ }
+ | enumerator_list ',' opt_eolcomment
+ {
+ $$ = $1;
+ if ($3) comment_last_enumerator($$, $3);
+ }
+ ;
+
+enumerator
+ : identifier
+ {
+ new_enumerator(&$$,$1.name,$1.comment_before,$1.comment_after);
+ }
+ ;
+
+any_id
+ : T_IDENTIFIER
+ | T_TYPEDEF_NAME
+ | any_id T_COMMENT
+ {
+ $$ = $1;
+ free($2);
+ }
+ | any_id T_EOLCOMMENT
+ {
+ $$ = $1;
+ free($2);
+ }
+ ;
+
+declarator
+ : pointer T_EOLCOMMENT direct_declarator
+ {
+ char *newtext = strappend($1,$3->text,NULLCP);
+ free($3->text);
+ $$ = $3;
+ $$->text = newtext;
+ if ($$->type == DECL_SIMPLE)
+ $$->type = DECL_COMPOUND;
+ $$->retcomment = $2;
+ }
+ | pointer direct_declarator
+ {
+ char *newtext = strappend($1,$2->text,NULLCP);
+ free($2->text);
+ $$ = $2;
+ $$->text = newtext;
+ if ($$->type == DECL_SIMPLE)
+ $$->type = DECL_COMPOUND;
+ }
+ | T_EOLCOMMENT direct_declarator
+ {
+ $$ = $2;
+ $$->retcomment = $1;
+ }
+ | direct_declarator
+ {
+ $$ = $1;
+ }
+ ;
+
+parameter_declarator
+ : pointer direct_declarator
+ {
+ char *newtext = strappend($1,$2->text,NULLCP);
+ free($2->text);
+ $$ = $2;
+ $$->text = newtext;
+ if ($$->type == DECL_SIMPLE)
+ $$->type = DECL_COMPOUND;
+ }
+ | direct_declarator
+ {
+ $$ = $1;
+ }
+ ;
+
+direct_declarator
+ : T_IDENTIFIER
+ {
+ $$ = new_declarator($1, strduplicate($1));
+ }
+ | '(' declarator ')'
+ {
+ char *newtext = strconcat("(",$2->text,")",NULLCP);
+ free($2->text);
+ $$ = $2;
+ $$->text = newtext;
+ }
+ | direct_declarator T_BRACKETS
+ {
+ $$ = $1;
+ $$->text = strappend($1->text,$2,NULLCP);
+ free($2);
+ }
+ | direct_declarator '(' parameter_type_list ')'
+ {
+ $$ = new_declarator(strduplicate("%s()"), strduplicate($1->name));
+ $$->params = $3;
+ $$->func_stack = $1;
+ $$->head = ($1->func_stack == NULL) ? $$ : $1->head;
+ $$->type = ($1->type == DECL_SIMPLE) ? DECL_FUNCTION : $1->type;
+ }
+ | direct_declarator '(' opt_identifier_list ')'
+ {
+ $$ = new_declarator(strduplicate("%s()"), strduplicate($1->name));
+ $$->params = $3;
+ $$->func_stack = $1;
+ $$->head = ($1->func_stack == NULL) ? $$ : $1->head;
+ $$->type = ($1->type == DECL_SIMPLE) ? DECL_FUNCTION : $1->type;
+ }
+ ;
+
+pointer
+ : '*' type_qualifier_list
+ {
+ $$ = strconcat("*",$2, NULLCP);
+ safe_free($2);
+ }
+ | '*' type_qualifier_list pointer
+ {
+ $$ = $2 ? strconcat("*",$2, $3, NULLCP)
+ : strconcat("*", $3, NULLCP);
+ safe_free($2);
+ free($3);
+ }
+ ;
+
+type_qualifier_list
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | type_qualifier_list type_qualifier
+ {
+ $$ = $1 ? strconcat($1," ",$2.text," ",NULLCP)
+ : strconcat($2.text," ",NULLCP);
+ safe_free($1);
+ free_decl_spec(&$2);
+ }
+ ;
+
+parameter_type_list
+ : parameter_list opt_eolcomment
+ {
+ $$ = $1;
+ if ($2) comment_last_parameter(&$1, $2);
+ }
+ | parameter_list ',' opt_eolcomment
+ opt_comment T_ELLIPSIS opt_comment opt_eolcomment
+ {
+ Identifier ellipsis;
+
+ if ($3) comment_last_parameter(&$1, $3);
+ ellipsis.name = strduplicate("...");
+
+ if ($4 && $6 && $7)
+ {
+ yyerror("ellipsis parameter has multiple comments");
+ free($7);
+ free($6);
+ free($4);
+ ellipsis.comment_before = ellipsis.comment_after = NULL;
+ }
+ else
+ {
+ ellipsis.comment_before = $4;
+ ellipsis.comment_after = $6 ? $6 : $7;
+ }
+
+ add_ident_list(&$$, &$1, &ellipsis);
+ }
+ ;
+
+parameter_list
+ : parameter_declaration
+ {
+ new_param_list(&$$, &$1);
+ }
+ | parameter_list ',' opt_eolcomment parameter_declaration
+ {
+ if ($3) comment_last_parameter(&$1, $3);
+ add_param_list(&$$, &$1, &$4);
+ }
+ ;
+
+parameter_declaration
+ : opt_comment declaration_specifiers parameter_declarator opt_comment
+ {
+ new_parameter(&$$, &$2, $3, $1, $4);
+ }
+ | opt_comment declaration_specifiers abstract_parameter_declarator opt_comment
+ {
+ new_parameter(&$$, &$2, $3, $1, $4);
+ }
+ | opt_comment declaration_specifiers opt_comment
+ {
+ new_parameter(&$$, &$2, (Declarator *)NULL, $1, $3);
+ }
+ ;
+
+opt_identifier_list
+ : /* empty */
+ {
+ new_ident_list(&$$);
+ }
+ | identifier_list opt_eolcomment
+ {
+ $$ = $1;
+ if ($2) comment_last_parameter(&$1, $2);
+ }
+ ;
+
+identifier_list
+ : identifier
+ {
+ new_ident_list(&$$);
+ add_ident_list(&$$, &$$, &$1);
+ }
+ | identifier_list ',' opt_eolcomment identifier
+ {
+ if ($3) comment_last_parameter(&$1, $3);
+ add_ident_list(&$$, &$1, &$4);
+ }
+ ;
+
+identifier
+ : opt_comment T_IDENTIFIER opt_comment
+ {
+ $$.comment_before = $1;
+ $$.comment_after = $3;
+ $$.name = $2;
+ }
+
+abstract_declarator
+ : pointer
+ {
+ $$ = new_declarator($1, NULLCP);
+ }
+ | pointer T_EOLCOMMENT direct_abstract_declarator
+ {
+ char *newtext = strappend($1,$3->text,NULLCP);
+ free($3->text);
+ $$ = $3;
+ $$->text = newtext;
+ if ($$->type == DECL_SIMPLE)
+ $$->type = DECL_COMPOUND;
+ $$->retcomment = $2;
+ }
+ | pointer direct_abstract_declarator
+ {
+ char *newtext = strappend($1,$2->text,NULLCP);
+ free($2->text);
+ $$ = $2;
+ $$->text = newtext;
+ if ($$->type == DECL_SIMPLE)
+ $$->type = DECL_COMPOUND;
+ }
+ | T_EOLCOMMENT direct_abstract_declarator
+ {
+ $$ = $2;
+ $$->retcomment = $1;
+ }
+ | direct_abstract_declarator
+ {
+ $$ = $1;
+ }
+ ;
+
+abstract_parameter_declarator
+ : pointer
+ {
+ $$ = new_declarator($1, NULLCP);
+ }
+ | pointer direct_abstract_declarator
+ {
+ char *newtext = strappend($1,$2->text,NULLCP);
+ free($2->text);
+ $$ = $2;
+ $$->text = newtext;
+ if ($$->type == DECL_SIMPLE)
+ $$->type = DECL_COMPOUND;
+ }
+ | direct_abstract_declarator
+ {
+ $$ = $1;
+ }
+ ;
+
+direct_abstract_declarator
+ : '(' abstract_declarator ')'
+ {
+ char *newtext = strconcat("(",$2->text,")",NULLCP);
+ free($2->text);
+ $$ = $2;
+ $$->text = newtext;
+ }
+ | direct_abstract_declarator T_BRACKETS
+ {
+ $$ = $1;
+ $$->text = strappend($1->text,$2,NULLCP);
+ free($2);
+ }
+ | T_BRACKETS
+ {
+ $$ = new_declarator($1, NULLCP);
+ }
+ | direct_abstract_declarator '(' parameter_type_list ')'
+ {
+ $$ = new_declarator(strduplicate("%s()"), NULLCP);
+ $$->params = $3;
+ $$->func_stack = $1;
+ $$->head = ($1->func_stack == NULL) ? $$ : $1->head;
+ $$->type = ($1->type == DECL_SIMPLE) ? DECL_FUNCTION : $1->type;
+ }
+ | direct_abstract_declarator '(' ')'
+ {
+ $$ = new_declarator(strduplicate("%s()"), NULLCP);
+ $$->func_stack = $1;
+ $$->head = ($1->func_stack == NULL) ? $$ : $1->head;
+ $$->type = ($1->type == DECL_SIMPLE) ? DECL_FUNCTION : $1->type;
+ }
+ | '(' parameter_type_list ')'
+ {
+ Declarator *d;
+
+ d = new_declarator(NULL, NULL);
+ $$ = new_declarator(strduplicate("%s()"), NULLCP);
+ $$->params = $2;
+ $$->func_stack = d;
+ $$->head = $$;
+ }
+ | '(' ')'
+ {
+ Declarator *d;
+
+ d = new_declarator(NULL, NULL);
+ $$ = new_declarator(strduplicate("%s()"), NULLCP);
+ $$->func_stack = d;
+ $$->head = $$;
+ }
+ ;
+
+opt_comment
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | T_COMMENT
+ ;
+
+opt_eolcomment
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | T_EOLCOMMENT
+ ;
+
+%%
+#ifdef MSDOS
+#include "lex_yy.c"
+#else
+#ifdef VMS
+#include "lexyy.c"
+#else
+#include "lex.yy.c"
+#endif /* !VMS */
+#endif /* !MSDOS */
+
+#ifdef I_STDARG
+void yyerror(const char *format, ...)
+#else
+void yyerror(va_alist)
+ va_dcl
+#endif
+{
+#ifndef I_STDARG
+ const char *format;
+#endif
+ va_list args;
+
+ output_error();
+
+#ifdef I_STDARG
+ va_start(args, format);
+#else
+ va_start(args);
+ format = va_arg(args, char *);
+#endif
+
+ vfprintf(stderr, format, args);
+ va_end(args);
+ putc('.',stderr);
+ putc('\n',stderr);
+}
+
+void
+parse_file (start_file)
+const char *start_file;
+{
+ const char *s;
+#ifdef FLEX_SCANNER
+ static boolean restart = FALSE;
+#endif
+
+ cur_file = start_file ? strduplicate(start_file) : NULL;
+
+ if (basefile && strlen(basefile) > 2) {
+ s = basefile + strlen(basefile) - 2;
+ if (strcmp(s, ".l") == 0 || strcmp(s, ".y") == 0)
+ BEGIN LEXYACC;
+ }
+
+ typedef_names = create_symbol_table();
+ enum_table = create_symbol_table();
+
+ line_num = 1;
+ ly_count = 0;
+ first_comment = group_together && !terse_specified;
+
+ /* flex needs a yyrestart before every file but the first */
+#ifdef FLEX_SCANNER
+ if (restart) yyrestart(yyin);
+ restart = TRUE;
+#endif
+
+ yyparse();
+
+ destroy_symbol_table(enum_table);
+ destroy_symbol_table(typedef_names);
+
+ safe_free(cur_file);
+}
diff --git a/html.c b/html.c
new file mode 100644
index 0000000..4fc4112
--- /dev/null
+++ b/html.c
@@ -0,0 +1,453 @@
+/* $Id: html.c,v 1.1 2004-05-03 05:17:49 behdad Exp $
+ * functions for html style output.
+ */
+#include "c2man.h"
+#include "manpage.h"
+#include "output.h"
+#include <ctype.h>
+
+static int html_in_code = 0;
+
+void html_terse_sep();
+void html_description _((const char *text));
+
+void html_char(c)
+const int c;
+{
+ switch (c)
+ {
+ case '<':
+ put_string("&lt;");
+ break;
+ case '>':
+ put_string("&gt;");
+ break;
+ case '&':
+ put_string("&amp;");
+ break;
+ case '"':
+ put_string("&quot;");
+ break;
+ default:
+ putchar(c);
+ break;
+ }
+}
+
+void html_text(text)
+const char *text;
+{
+ while(*text)
+ {
+ html_char(*text++);
+ }
+}
+
+
+void html_comment()
+{
+ put_string("<!");
+}
+
+void html_header(firstpage, input_files, grouped, name, terse, section)
+ ManualPage *firstpage;
+ int input_files;
+ boolean grouped;
+ const char *name;
+ const char *terse;
+ const char *section;
+{
+
+ output_warning();
+ put_string("<header>\n");
+ put_string("<title>");
+ html_text(name);
+ html_terse_sep();
+ html_text(terse);
+ put_string("</title>\n");
+ put_string("</header>\n");
+ put_string("<body>\n");
+}
+
+void html_file_end()
+{
+ put_string("\n</body>\n");
+}
+
+void html_dash()
+{
+ put_string("-");
+}
+
+void html_section(name)
+const char *name;
+{
+ put_string("<h1>");
+ html_text(name);
+ put_string("</h1>\n");
+}
+
+void html_sub_section(name)
+const char *name;
+{
+ put_string("<h2>");
+ html_text(name);
+ put_string("</h2>");
+}
+
+void html_break_line()
+{
+ if (!html_in_code)
+ {
+ put_string("<br>\n");
+ }
+}
+
+void html_blank_line()
+{
+ if (!html_in_code)
+ {
+ put_string("<p>\n");
+ }
+ else
+ {
+ putchar('\n');
+ }
+}
+
+void html_code_start()
+{
+ put_string("<pre>");
+ html_in_code = 1;
+}
+
+void html_code_end()
+{
+ put_string("</pre>\n");
+ html_in_code = 0;
+}
+
+void html_code(text)
+const char *text;
+{
+ html_code_start();
+ html_text(text);
+ html_code_end();
+}
+
+void html_tag_list_start()
+{
+ put_string("<dl>");
+}
+
+void html_tag_list_end()
+{
+ put_string("</dl>\n");
+}
+
+void html_tag_entry_start()
+{
+ put_string("<dt>\n");
+}
+
+void html_tag_entry_start_extra()
+{
+ put_string("<dt>\n");
+}
+
+void html_tag_entry_end()
+{
+ put_string("<dd>\n");
+}
+
+void html_tag_entry_end_extra(text)
+const char *text;
+{
+ put_string(" <em>");
+ put_string(text);
+ put_string("</em>)");
+ put_string("<dd>\n");
+}
+
+void html_table_start(longestag)
+const char *longestag;
+{
+ put_string("<ul>");
+}
+
+void html_table_entry(name, description)
+const char *name;
+const char *description;
+{
+ put_string("<li>");
+ html_text(name);
+ if (description)
+ {
+ html_terse_sep();
+ html_description(description);
+ }
+ put_string("<p>\n");
+}
+
+void html_table_end()
+{
+ put_string("</ul>");
+}
+
+void html_indent()
+{
+ put_string("\t");
+}
+
+void html_list_start()
+{
+ put_string("<ul>");
+}
+
+
+void html_list_end()
+{
+ put_string("</ul>");
+}
+
+void html_list_entry(name)
+const char *name;
+{
+ put_string("<li>");
+ put_string(name);
+ put_string("\n");
+}
+
+void html_list_separator()
+{
+ put_string(",\n");
+}
+
+void html_include(filename)
+const char *filename;
+{
+ printf(".so %s\n", filename);
+}
+
+void html_name(name)
+const char *name;
+{
+ if (name)
+ html_text(name);
+ else
+ html_section("NAME");
+}
+
+void html_terse_sep()
+{
+ html_char(' ');
+ html_dash();
+ html_char(' ');
+}
+
+void html_reference(name)
+const char *name;
+{
+ put_string("<a href=");
+ put_string(name);
+ put_string(".html>");
+ put_string(name);
+ put_string("</a>\n");
+}
+
+void html_emphasized(text)
+const char *text;
+{
+ put_string("<em>");
+ put_string(text);
+ put_string("</em>");
+}
+
+/* ideally, this should be made aware of embedded html commands */
+void html_description(text)
+const char *text;
+{
+ enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
+ boolean new_line = TRUE;
+
+ /* correct punctuation a bit as it goes out */
+ for (;*text;text++)
+ {
+ int c = *text;
+
+ if (new_line && (c == '-' || c == '*' || c == '\n' ||
+ is_numbered(text)))
+ {
+ output->break_line();
+ state = CAPITALISE;
+ }
+ else if (new_line && c == '\n') { /* Two newlines - Paragraph break */
+ output->blank_line();
+ }
+ else if (c == '.')
+ state = PERIOD;
+ else if (isspace(c) && state == PERIOD)
+ state = CAPITALISE;
+ else if (isalnum(c))
+ {
+ if (islower(c) && state == CAPITALISE) c = toupper(c);
+ state = TEXT;
+ }
+
+ output->character(c);
+ new_line = c == '\n';
+ }
+
+ /* do a full stop if there wasn't one */
+ if (state == TEXT) output->character('.');
+}
+
+/* ideally, this should be made aware of embedded html commands */
+void
+html_returns(comment)
+const char *comment;
+{
+ enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
+ char lastchar = '\n';
+ boolean tag_list_started = FALSE;
+
+ /* for each line... */
+ while (*comment)
+ {
+ boolean tagged = FALSE;
+
+ {
+ const char *c = comment;
+
+ /* search along until the end of a word */
+ while (*c && *c != ':' && !isspace(*c))
+ c++;
+
+ /* skip all spaces or tabs after the first word */
+ while (*c && *c != '\n')
+ {
+ if (*c == '\t' || *c == ':')
+ {
+ tagged = TRUE;
+ break;
+ }
+ else if (!isspace(*c))
+ break;
+
+ c++;
+ }
+ }
+
+ /* is it tagged?; explicitly reject dot commands */
+ if (tagged)
+ {
+ /* output lingering newline if necessary */
+ if (lastchar != '\n')
+ {
+ if (state == TEXT && !ispunct(lastchar)) output->character('.');
+ output->character(lastchar = '\n');
+ }
+
+ if (!tag_list_started)
+ {
+ output->tag_list_start();
+ tag_list_started = TRUE;
+ }
+
+ /* output the taggy bit */
+ output->tag_entry_start();
+ while (*comment && *comment != ':' && !isspace(*comment))
+ output->character(*comment++);
+ output->tag_entry_end();
+
+ /* skip any extra tabs or spaces */
+ while (*comment == ':' || (isspace(*comment) && *comment != '\n'))
+ comment++;
+
+ state = CAPITALISE;
+ }
+
+ /* terminate the previous line if necessary */
+ if (lastchar != '\n') output->character(lastchar = '\n');
+
+ /* correct punctuation a bit as the line goes out */
+ for (;*comment && *comment != '\n'; comment++)
+ {
+ char c = *comment;
+
+ if (c == '.')
+ state = PERIOD;
+ else if (isspace(c) && state == PERIOD)
+ state = CAPITALISE;
+ else if (isalnum(c))
+ {
+ if (islower(c) && state == CAPITALISE && fixup_comments)
+ c = toupper(c);
+ state = TEXT;
+ }
+
+ output->character(lastchar = c);
+ }
+
+ /* if it ended in punctuation, just output the nl straight away. */
+ if (ispunct(lastchar))
+ {
+ if (lastchar == '.') state = CAPITALISE;
+ output->character(lastchar = '\n');
+ }
+
+ if (*comment) comment++;
+ }
+
+ /* output lingering newline if necessary */
+ if (lastchar != '\n')
+ {
+ if (state == TEXT && !ispunct(lastchar) && fixup_comments)
+ output->character('.');
+ output->character('\n');
+ }
+
+ if (tag_list_started)
+ output->tag_list_end();
+}
+
+
+struct Output html_output =
+{
+ html_comment,
+ html_header,
+ html_dash,
+ html_section,
+ html_sub_section,
+ html_break_line,
+ html_blank_line,
+ html_code_start,
+ html_code_end,
+ html_code,
+ html_tag_list_start,
+ html_tag_list_end,
+ html_tag_entry_start,
+ html_tag_entry_start_extra,
+ html_tag_entry_end,
+ html_tag_entry_end_extra,
+ html_table_start,
+ html_table_entry,
+ html_table_end,
+ html_indent,
+ html_list_start,
+ html_list_entry,
+ html_list_separator,
+ html_list_end,
+ html_include,
+ html_file_end,
+ html_text,
+ html_char,
+ NULL, /* html_parse_option */
+ dummy, /* html_print_options */
+ html_name,
+ html_terse_sep,
+ html_reference,
+ html_emphasized,
+ html_description,
+ html_returns
+ };
diff --git a/latex.c b/latex.c
new file mode 100644
index 0000000..ace199c
--- /dev/null
+++ b/latex.c
@@ -0,0 +1,356 @@
+/* $Id: latex.c,v 1.1 2004-05-03 05:17:49 behdad Exp $
+ * functions for LaTeX style output.
+ */
+#include "c2man.h"
+#include "manpage.h"
+#include "output.h"
+#include <ctype.h>
+
+static boolean verbatim = FALSE; /* skip quoting in verbatim section */
+
+void latex_char(c)
+const int c;
+{
+ int i;
+
+ switch (c)
+ {
+ case '$':
+ case '#':
+ case '&':
+ case '^':
+ case '_':
+ if (!verbatim)
+ putchar('\\');
+ putchar(c);
+ break;
+ case '>':
+ case '<':
+ if (!verbatim)
+ putchar('$');
+ putchar(c);
+ if (!verbatim)
+ putchar('$');
+ break;
+ case '\t':
+ for (i = 0; i < NUM_TAB_SPACES; i++)
+ putchar(' ');
+ break;
+ default:
+ putchar(c);
+ break;
+ }
+}
+
+void latex_text(text)
+const char *text;
+{
+ while(*text)
+ latex_char(*text++);
+}
+
+void latex_comment() { put_string("% "); }
+
+void latex_header(firstpage, input_files, grouped, name, terse, section)
+ManualPage *firstpage;
+int input_files;
+boolean grouped;
+const char *name;
+const char *terse;
+const char *section;
+{
+ if (make_embeddable) return;
+
+ put_string("\\documentstyle{article}\n");
+ output_warning();
+ put_string("\\begin{document}\n");
+}
+
+void latex_dash() { put_string("---"); }
+
+void latex_section(name)
+const char *name;
+{
+ put_string("\\section*{");
+ latex_text(name);
+ put_string("}\n");
+}
+
+void latex_sub_section(name)
+const char *name;
+{
+ put_string("\\subsection*{");
+ latex_text(name);
+ put_string("}\n");
+}
+
+void latex_break_line() { /* put_string("\\newline\n"); */ }
+void latex_blank_line() { put_string("\n"); }
+
+void latex_code_start() { put_string("\\begin{verbatim}\n"); verbatim = TRUE; }
+void latex_code_end() { put_string("\\end{verbatim}\n"); verbatim = FALSE; }
+
+void latex_code(text)
+const char *text;
+{
+ put_string("\\verb`");
+ put_string(text);
+ put_string("`");
+}
+
+void latex_tag_list_start() { put_string("\\begin{description}\n"); }
+void latex_tag_entry_start() { put_string("\\item["); }
+void latex_tag_entry_end() { put_string("]\\hfill\\newline\n"); }
+void latex_tag_entry_end_extra(text)
+const char *text;
+{
+ put_string("(");
+ latex_text(text);
+ put_string(")");
+ latex_tag_entry_end();
+}
+void latex_tag_list_end() { put_string("\\end{description}\n"); }
+
+void latex_table_start(longestag)
+const char *longestag;
+{ put_string("\\begin{description}\n"); }
+
+void latex_table_entry(name, description)
+const char *name;
+const char *description;
+{
+ put_string("\\item[");
+ latex_text(name);
+ put_string("]\n");
+ if (description)
+ output_comment(description);
+ else
+ latex_char('\n');
+}
+
+void latex_table_end() { put_string("\\end{description}\n"); }
+
+void latex_list_entry(text)
+const char *text;
+{
+ latex_text(text);
+}
+void latex_list_separator() { put_string(",\n"); }
+void latex_list_end() { latex_char('\n'); }
+
+void latex_include(filename)
+const char *filename;
+{
+ put_string("\\include{");
+ latex_text(filename);
+ put_string("}\n");
+}
+
+void latex_file_end() { put_string("\\end{document}\n"); }
+
+void latex_name(name)
+const char *name;
+{
+ if (name) latex_text(name);
+ else latex_section("NAME");
+}
+
+void latex_terse_sep()
+{
+ latex_char(' ');
+ latex_dash();
+ latex_char(' ');
+}
+
+void latex_reference(text)
+const char *text;
+{
+ latex_text(text);
+ latex_char('(');
+ latex_text(manual_section);
+ latex_char(')');
+}
+
+/* ideally, this should be made aware of embedded latex commands */
+void latex_description(text)
+const char *text;
+{
+ enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
+ boolean new_line = TRUE;
+
+ /* correct punctuation a bit as it goes out */
+ for (;*text;text++)
+ {
+ int c = *text;
+
+ if (new_line && (c == '-' || c == '*'))
+ {
+ output->break_line();
+ state = CAPITALISE;
+ }
+ else if (c == '.')
+ state = PERIOD;
+ else if (isspace(c) && state == PERIOD)
+ state = CAPITALISE;
+ else if (isalnum(c))
+ {
+ if (islower(c) && state == CAPITALISE) c = toupper(c);
+ state = TEXT;
+ }
+
+ output->character(c);
+ new_line = c == '\n';
+ }
+
+ /* do a full stop if there wasn't one */
+ if (state == TEXT) output->character('.');
+}
+
+/* ideally, this should be made aware of embedded latex commands */
+void
+latex_returns(comment)
+const char *comment;
+{
+ enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
+ char lastchar = '\n';
+ boolean tag_list_started = FALSE;
+
+ /* for each line... */
+ while (*comment)
+ {
+ boolean tagged = FALSE;
+
+ {
+ const char *c = comment;
+
+ /* search along until the end of a word */
+ while (*c && *c != ':' && !isspace(*c))
+ c++;
+
+ /* skip all spaces or tabs after the first word */
+ while (*c && *c != '\n')
+ {
+ if (*c == '\t' || *c == ':')
+ {
+ tagged = TRUE;
+ break;
+ }
+ else if (!isspace(*c))
+ break;
+
+ c++;
+ }
+ }
+
+ /* is it tagged?; explicitly reject dot commands */
+ if (tagged)
+ {
+ /* output lingering newline if necessary */
+ if (lastchar != '\n')
+ {
+ if (state == TEXT && !ispunct(lastchar)) output->character('.');
+ output->character(lastchar = '\n');
+ }
+
+ if (!tag_list_started)
+ {
+ output->tag_list_start();
+ tag_list_started = TRUE;
+ }
+
+ /* output the taggy bit */
+ output->tag_entry_start();
+ while (*comment && *comment != ':' && !isspace(*comment))
+ output->character(*comment++);
+ output->tag_entry_end();
+
+ /* skip any extra tabs or spaces */
+ while (*comment == ':' || (isspace(*comment) && *comment != '\n'))
+ comment++;
+
+ state = CAPITALISE;
+ }
+
+ /* terminate the previous line if necessary */
+ if (lastchar != '\n') output->character(lastchar = '\n');
+
+ /* correct punctuation a bit as the line goes out */
+ for (;*comment && *comment != '\n'; comment++)
+ {
+ char c = *comment;
+
+ if (c == '.')
+ state = PERIOD;
+ else if (isspace(c) && state == PERIOD)
+ state = CAPITALISE;
+ else if (isalnum(c))
+ {
+ if (islower(c) && state == CAPITALISE && fixup_comments)
+ c = toupper(c);
+ state = TEXT;
+ }
+
+ output->character(lastchar = c);
+ }
+
+ /* if it ended in punctuation, just output the nl straight away. */
+ if (ispunct(lastchar))
+ {
+ if (lastchar == '.') state = CAPITALISE;
+ output->character(lastchar = '\n');
+ }
+
+ if (*comment) comment++;
+ }
+
+ /* output lingering newline if necessary */
+ if (lastchar != '\n')
+ {
+ if (state == TEXT && !ispunct(lastchar) && fixup_comments)
+ output->character('.');
+ output->character('\n');
+ }
+
+ if (tag_list_started)
+ output->tag_list_end();
+}
+
+struct Output latex_output =
+{
+ latex_comment,
+ latex_header,
+ latex_dash,
+ latex_section,
+ latex_sub_section,
+ latex_break_line,
+ latex_blank_line,
+ latex_code_start,
+ latex_code_end,
+ latex_code,
+ latex_tag_list_start,
+ latex_tag_list_end,
+ latex_tag_entry_start,
+ latex_tag_entry_start, /* entry_start_extra */
+ latex_tag_entry_end,
+ latex_tag_entry_end_extra,
+ latex_table_start,
+ latex_table_entry,
+ latex_table_end,
+ dummy, /* latex_indent */
+ dummy, /* latex_list_start */
+ latex_list_entry,
+ latex_list_separator,
+ latex_list_end,
+ latex_include,
+ latex_file_end,
+ latex_text,
+ latex_char,
+ NULL, /* latex_parse_option */
+ dummy, /* latex_print_option */
+ latex_name,
+ latex_terse_sep,
+ latex_reference,
+ latex_text,
+ latex_description,
+ latex_returns
+};
diff --git a/lex.l b/lex.l
new file mode 100644
index 0000000..ec99c22
--- /dev/null
+++ b/lex.l
@@ -0,0 +1,621 @@
+%{
+/* $Id: lex.l,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ *
+ * C manual page generator
+ * Lexical analyzer specification
+ */
+
+#include <ctype.h>
+
+extern boolean inbasefile; /* Steven Haehn Mar 19, 1996 */
+
+static char *cur_file; /* current file name (malloced) */
+int line_num = 1; /* current line number in file */
+static int curly = 0; /* number of curly brace nesting levels */
+static int square = 0; /* number of square bracket nesting levels */
+static int ly_count = 0; /* number of occurrences of %% */
+static int embedded = 0; /* flag for embedded compiler directives */
+
+/* temporary string buffer */
+static char buf[MAX_TEXT_LENGTH];
+
+#define DYNBUF_ALLOC 240 /* size of increment of dynamic buf */
+static char *dynbuf; /* start of dynamic buf */
+static int dynbuf_size; /* number of bytes allocated */
+static int dynbuf_current; /* current end of buffer */
+
+static boolean comment_ateol; /* does comment start & end at end of a line? */
+static boolean comment_remember;/* remember contents of current comment? */
+static boolean comment_caller; /* state we were in before */
+static boolean body_start = FALSE; /* At the start of a function body */
+
+typedef struct {
+#ifdef FLEX_SCANNER
+ YY_BUFFER_STATE buffer;
+#else
+ FILE *fp;
+#endif
+ char *file;
+ int line_num;
+} IncludeStack;
+
+static int inc_depth = 0; /* include nesting level */
+static IncludeStack inc_stack[MAX_INC_DEPTH]; /* stack of included files */
+
+static void update_line_num _((void));
+static void do_include _((char *filename, int sysinc));
+static void new_dynbuf();
+static void add_dynbuf _((int c));
+static char *return_dynbuf();
+static void get_cpp_directive();
+static boolean process_line_directive _((const char *new_file));
+
+/*
+ * The initial comment processing is done primarily by the rather complex lex
+ * rules in the various comment start states, the main functions being removal
+ * of leading *'s, /'s and whitespace on a line, the removal of trailing
+ * whitespace on a line, and the coalescing of separate comments on adjacent
+ * lines. The remaining bits of textual content are collected by the following
+ * functions, which simply strip leading and trailing blank lines.
+ */
+void start_comment _((boolean ateol));
+int end_comment _((boolean ateol));
+void add_comment _((const char *s));
+void newline_comment _((void));
+
+static int comment_newlines; /* number of newlines hit in comment */
+static boolean comment_started; /* have preceding empty lines been skipped */
+
+#ifdef FLEX_SCANNER /* flex uses YY_START instead of YYSTATE */
+#define YYSTATE YY_START
+#ifndef YY_START /* flex 2.3.8 & before didn't support it at all */
+#define YY_START ((yy_start - 1) / 2)
+#endif
+#endif
+
+#undef yywrap /* for flex */
+
+/* SKIP skipping value assignment in an enum */
+%}
+
+WS [ \t]
+WLF [ \t\n\f]*
+LETTER [A-Za-z_]
+DIGIT [0-9]
+ID {LETTER}({LETTER}|{DIGIT})*
+STRING \"(\\.|\\\n|[^"\\])*\"
+QUOTED ({STRING}|\'(\\\'|[^'\n])*\'|\\.)
+
+%p 5000
+%e 2000
+%s CPP1 INIT1 INIT2 CURLY SQUARE LEXYACC SKIP COMMENT COMMLINE CPPCOMMENT EMBEDDED
+%%
+
+
+<LEXYACC>^"%%" {
+ if (++ly_count >= 2)
+ BEGIN INITIAL;
+ }
+<LEXYACC>^"%{" BEGIN INITIAL;
+<LEXYACC>{QUOTED} update_line_num();
+<LEXYACC>. ;
+<INITIAL>^"%}" BEGIN LEXYACC;
+
+<INITIAL>^{WS}*#{WS}* BEGIN CPP1;
+
+<CPP1>define{WS}+{ID} {
+ sscanf(yytext, "define %s", buf);
+ get_cpp_directive();
+ new_symbol(typedef_names, buf, DS_EXTERN);
+ }
+
+<CPP1>include{WS}*\"[^"]+\" {
+ sscanf(yytext, "include \"%[^\"]\"", buf);
+ get_cpp_directive();
+ do_include(buf, FALSE);
+ }
+<CPP1>include{WS}*\<[^>]+\> {
+ sscanf(yytext, "include <%[^>]>", buf);
+ get_cpp_directive();
+ do_include(buf, TRUE);
+ }
+
+<CPP1>line{WS}+[0-9]+{WS}+\".*$ {
+ sscanf(yytext, "line %d \"%[^\"]\"",
+ &line_num, buf);
+ --line_num;
+ BEGIN INITIAL;
+
+ if (process_line_directive(buf))
+ inbasefile = yylval.boolean;
+ }
+<CPP1>[0-9]+{WS}+\".*$ {
+ sscanf(yytext, "%d \"%[^\"]\"", &line_num, buf);
+ --line_num;
+ BEGIN INITIAL;
+
+ if (process_line_directive(buf))
+ inbasefile = yylval.boolean;
+ }
+<CPP1>[0-9]+.*$ {
+ sscanf(yytext, "%d ", &line_num);
+ --line_num;
+ BEGIN INITIAL;
+ }
+
+<CPP1>. get_cpp_directive();
+
+<INITIAL>"(" return '(';
+<INITIAL>")" return ')';
+<INITIAL>"*" return '*';
+<INITIAL,SKIP>"," {
+ BEGIN INITIAL; /* stop skipping */
+ return ',';
+ }
+<INITIAL>";" return ';';
+<INITIAL>"..." return T_ELLIPSIS;
+<INITIAL>{STRING} { update_line_num(); return T_STRING_LITERAL; }
+
+<INITIAL>auto return T_AUTO;
+<INITIAL>extern return T_EXTERN;
+<INITIAL>register return T_REGISTER;
+<INITIAL>static return T_STATIC;
+<INITIAL>typedef return T_TYPEDEF;
+<INITIAL>char return T_CHAR;
+<INITIAL>double return T_DOUBLE;
+<INITIAL>float return T_FLOAT;
+<INITIAL>int return T_INT;
+<INITIAL>void return T_VOID;
+<INITIAL>long return T_LONG;
+<INITIAL>short return T_SHORT;
+<INITIAL>signed return T_SIGNED;
+<INITIAL>__signed__ return T_SIGNED;
+<INITIAL>__signed return T_SIGNED;
+<INITIAL>unsigned return T_UNSIGNED;
+<INITIAL>enum { enum_state = KEYWORD; return T_ENUM; }
+<INITIAL>struct return T_STRUCT;
+<INITIAL>union return T_UNION;
+<INITIAL>const return T_CONST;
+<INITIAL>__const__ return T_CONST;
+<INITIAL>__const return T_CONST;
+<INITIAL>volatile return T_VOLATILE;
+<INITIAL>__volatile__ return T_VOLATILE;
+<INITIAL>__volatile return T_VOLATILE;
+<INITIAL>inline return T_INLINE;
+<INITIAL>__inline__ return T_INLINE;
+<INITIAL>__inline return T_INLINE;
+<INITIAL>cdecl return T_CDECL;
+<INITIAL>far return T_FAR;
+<INITIAL>huge return T_HUGE;
+<INITIAL>interrupt return T_INTERRUPT;
+<INITIAL>near return T_NEAR;
+<INITIAL>pascal return T_PASCAL;
+<INITIAL>__extension__ ;
+
+<INITIAL>__attribute__ {
+ BEGIN EMBEDDED;
+ }
+<EMBEDDED>"(" ++embedded;
+<EMBEDDED>")" {
+ if (--embedded == 0)
+ BEGIN INITIAL;
+ }
+<EMBEDDED>{ID}|","|{DIGIT}+|{WS} ;
+<EMBEDDED>{QUOTED} update_line_num();
+
+<INITIAL>{ID} {
+ if (enum_state == BRACES) BEGIN SKIP;
+ yylval.text = strduplicate(yytext);
+ if (is_typedef_name(yytext))
+ return T_TYPEDEF_NAME;
+ else
+ return T_IDENTIFIER;
+ }
+
+<INITIAL>"=" BEGIN INIT1;
+<INIT1>"{" { curly = 1; BEGIN INIT2; }
+<INIT1>[,;] {
+ unput(yytext[yyleng-1]);
+ BEGIN INITIAL;
+ return T_INITIALIZER;
+ }
+<INIT1>{QUOTED} update_line_num();
+<INIT1>. ;
+
+<INIT2>"{" ++curly;
+<INIT2>"}" {
+ if (--curly == 0) {
+ BEGIN INITIAL;
+ return T_INITIALIZER;
+ }
+ }
+<INIT2>{QUOTED} update_line_num();
+<INIT2>. ;
+
+<INITIAL,SKIP>"{" {
+ if (enum_state == KEYWORD)
+ {
+ enum_state = BRACES;
+ return '{';
+ }
+ else
+ {
+ curly = 1;
+ BEGIN CURLY;
+ body_start = TRUE; /* Look for first comment
+ * in the func body.
+ */
+ safe_free(body_comment);
+ body_comment = NULL;
+ }
+ }
+<INITIAL,SKIP>"}" {
+ BEGIN INITIAL; /* stop skipping */
+ return '}';
+ }
+
+<CURLY>"{" ++curly;
+<CURLY>"}" {
+ if (--curly == 0) {
+ BEGIN INITIAL;
+ return T_BRACES;
+ }
+ }
+<CURLY,SKIP>{QUOTED} update_line_num();
+<CURLY,SKIP>. body_start = FALSE;
+
+<INITIAL>"[" {
+ new_dynbuf(); add_dynbuf(yytext[0]);
+ square = 1; BEGIN SQUARE;
+ }
+<SQUARE>"[" { ++square; add_dynbuf(yytext[0]); }
+<SQUARE>"]" {
+ add_dynbuf(yytext[0]);
+ if (--square == 0) {
+ BEGIN INITIAL;
+ yylval.text = return_dynbuf();
+ return T_BRACKETS;
+ }
+ }
+<SQUARE>{QUOTED}|. {
+ int i;
+ for (i = 0; i < yyleng; ++i)
+ {
+ if (yytext[i] == '\n') ++line_num;
+ add_dynbuf(yytext[i]);
+ }
+ }
+
+<INITIAL,INIT1,INIT2,CURLY,SQUARE,LEXYACC,SKIP,EMBEDDED>^{WS}*"/*"[*=-]*{WS}+ {
+ comment_caller = YYSTATE;
+ start_comment(FALSE);
+ BEGIN COMMENT; }
+<INITIAL,INIT1,INIT2,CURLY,SQUARE,LEXYACC,SKIP,EMBEDDED>^{WS}*"/*"[*=-]*[^/] {
+ yyless(yyleng-1);
+ comment_caller = YYSTATE;
+ start_comment(FALSE);
+ BEGIN COMMENT; }
+<INITIAL,INIT1,INIT2,CURLY,SQUARE,LEXYACC,SKIP,EMBEDDED>"/*"[*=-]*{WS}+ {
+ comment_caller = YYSTATE;
+ start_comment(TRUE);
+ BEGIN COMMENT; }
+<INITIAL,INIT1,INIT2,CURLY,SQUARE,LEXYACC,SKIP,EMBEDDED>"/*"[*=-]*[^/] {
+ yyless(yyleng-1);
+ comment_caller = YYSTATE;
+ start_comment(TRUE);
+ BEGIN COMMENT; }
+<COMMLINE>^{WS}*"/"+{WS}* |
+<COMMLINE>^{WS}*"/"*"*"*{WS}+ BEGIN COMMENT;
+<COMMLINE>^{WS}*"/"*"*"*[^/] { yyless(yyleng-1); BEGIN COMMENT; }
+<COMMLINE>. { yyless(0); BEGIN COMMENT; }
+<COMMLINE>\n newline_comment();
+<COMMENT>{WS}*"*"+"/"{WS}*\n{WS}*"/*""*"*{WS}+ newline_comment();
+<COMMENT>{WS}*"*"+"/"{WS}*\n{WS}*"/*""*"*[^/] {
+ yyless(yyleng-1); newline_comment(); }
+<COMMENT>{WS}*[*=-]*"*/"{WS}*$ { int ret = end_comment(TRUE);
+ BEGIN comment_caller;
+ if (ret) return ret; }
+<COMMENT>{WS}*[*=-]*"*/" { int ret = end_comment(FALSE);
+ BEGIN comment_caller;
+ if (ret) return ret; }
+<COMMENT>[^*\n \t]* |
+<COMMENT>{WS}* |
+<COMMENT>"*"+[^*/\n]* add_comment(yytext);
+<COMMENT>{WS}*\n { newline_comment(); BEGIN COMMLINE; }
+
+<INITIAL,INIT1,INIT2,CURLY,SQUARE,LEXYACC,SKIP,EMBEDDED>^{WS}*"//"[/*=-]*{WS}* {
+ comment_caller = YYSTATE;
+ start_comment(FALSE);
+ BEGIN CPPCOMMENT; }
+<INITIAL,INIT1,INIT2,CURLY,SQUARE,LEXYACC,SKIP,EMBEDDED>"//"[/*=-]*{WS}* {
+ comment_caller = YYSTATE;
+ start_comment(TRUE);
+ BEGIN CPPCOMMENT; }
+<CPPCOMMENT>.* add_comment(yytext);
+<CPPCOMMENT>\n{WS}*"//"[/*=-]*{WS}* newline_comment();
+<CPPCOMMENT>\n { int ret = end_comment(TRUE);
+ ++line_num;
+ BEGIN comment_caller;
+ if (ret) return ret; }
+
+[ \t\f]+ ;
+\n ++line_num;
+
+. {
+ output_error();
+ fprintf(stderr, "bad character '%c'\n", yytext[0]);
+ }
+%%
+
+/* If the matched text contains any new line characters, then update the
+ * current line number.
+ */
+static void
+update_line_num ()
+{
+ const char *p = (const char *)yytext;
+ while (*p != '\0') {
+ if (*p++ == '\n')
+ line_num++;
+ }
+}
+
+void start_comment(ateol)
+boolean ateol; /* does comment start at end of an existing line? */
+{
+ comment_remember = (look_at_body_start && body_start) ||
+ ((comment_caller == INITIAL || comment_caller == SKIP) &&
+ (inbasefile || enum_state == BRACES));
+
+ if (comment_remember)
+ {
+ comment_ateol = ateol;
+ comment_newlines = 0;
+ comment_started = FALSE;
+ new_dynbuf();
+ }
+}
+
+int end_comment(ateol)
+boolean ateol; /* does comment end at end of line? */
+{
+ if (comment_remember)
+ {
+ if (!ateol) comment_ateol = FALSE;
+ yylval.text = return_dynbuf();
+ if (yylval.text[0] == '\0' ||
+ /* ignore lint directives entirely */
+ strcmp("EMPTY", yylval.text) == 0 ||
+ strcmp("FALLTHROUGH", yylval.text) == 0 ||
+ strcmp("FALLTHRU", yylval.text) == 0 ||
+ strcmp("LINTED", yylval.text) == 0 ||
+ strcmp("LINTLIBRARY", yylval.text) == 0 ||
+ strcmp("LINTSTDLIB", yylval.text) == 0 ||
+ strcmp("NOTDEFINED", yylval.text) == 0 ||
+ strcmp("NOTREACHED", yylval.text) == 0 ||
+ strcmp("NOTUSED", yylval.text) == 0 ||
+ strncmp("ARGSUSED", yylval.text, 8) == 0 ||
+ strncmp("PRINTFLIKE", yylval.text, 10) == 0 ||
+ strncmp("SCANFLIKE", yylval.text, 9) == 0 ||
+ strncmp("VARARGS", yylval.text, 7) == 0)
+ {
+ free(yylval.text);
+ return 0;
+ }
+ if (body_start) { /* first comment at start of func body */
+ safe_free(body_comment);
+ body_comment = yylval.text;
+ body_start = FALSE;
+ return 0;
+ }
+#ifdef DEBUG
+ fprintf(stderr,"`%s'\n", yylval.text);
+#endif
+ return comment_ateol ? T_EOLCOMMENT : T_COMMENT;
+ }
+ return 0;
+}
+
+/* add a newline to the comment, deferring to remove trailing ones */
+void newline_comment()
+{
+ ++line_num;
+
+ if (!comment_remember || !comment_started) return;
+
+ comment_newlines++;
+}
+
+/* add some true text to the comment */
+void add_comment(s)
+const char *s;
+{
+#ifdef DEBUG
+ fprintf(stderr,"`%s'\n", s);
+#endif
+ if (!comment_remember) return;
+
+ comment_started = TRUE;
+
+ while (comment_newlines)
+ {
+ add_dynbuf('\n');
+ comment_newlines--;
+ }
+
+ while(*s)
+ add_dynbuf(*s++);
+}
+
+/* Scan rest of preprocessor statement.
+ */
+static void
+get_cpp_directive ()
+{
+ int c, lastc = '\0';
+
+ while ((c = input()) > 0) {
+ switch (c) {
+ case '\n':
+ if (lastc != '\\') {
+ unput(c);
+ BEGIN INITIAL;
+ return;
+ }
+ line_num++;
+ break;
+ case '*':
+ if (lastc == '/')
+ {
+ /* might be able to attach comments to #defines one day */
+ comment_caller = YYSTATE;
+ start_comment(TRUE);
+ BEGIN COMMENT;
+ }
+ break;
+ case '/':
+ if (lastc == '/')
+ {
+ /* might be able to attach comments to #defines one day */
+ comment_caller = YYSTATE;
+ start_comment(TRUE);
+ BEGIN CPPCOMMENT;
+ }
+ break;
+ }
+ lastc = c;
+ }
+}
+
+/* Process include directive.
+ */
+static void
+do_include (filename, sysinc)
+char *filename; /* file name */
+int sysinc; /* 1 = do not search current directory */
+{
+ char path[MAX_TEXT_LENGTH];
+ int i;
+ FILE *fp;
+ IncludeStack *sp;
+
+ if (inc_depth >= MAX_INC_DEPTH) {
+ output_error();
+ fprintf(stderr, "includes too deeply nested\n");
+ return;
+ }
+
+ for (i = sysinc != 0; i < num_inc_dir; ++i) {
+ strcpy(path, inc_dir[i]);
+ strcat(path, filename);
+ if ((fp = fopen(path, "r")) != NULL) {
+ sp = inc_stack + inc_depth;
+ sp->file = cur_file;
+ sp->line_num = line_num;
+#ifdef FLEX_SCANNER
+ sp->buffer = YY_CURRENT_BUFFER;
+ yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
+#else
+ sp->fp = yyin;
+ yyin = fp;
+#endif
+ ++inc_depth;
+ cur_file = strduplicate(filename);
+ line_num = 0;
+ return;
+ }
+ }
+}
+
+/* returns TRUE if the basefile status has changed */
+static boolean process_line_directive(new_file)
+const char *new_file;
+{
+ boolean new_stdin;
+
+ /* strip leading ./ that Sun acc prepends */
+ if (!strncmp(new_file,"./",2))
+ new_file += 2;
+
+ new_stdin = new_file[0] == '\0' || !strcmp(new_file,"stdin");
+
+ /* return BASEFILE token only when file changes */
+ if ((cur_file == NULL && !new_stdin) ||
+ (cur_file != NULL &&strcmp(cur_file, new_file)))
+ {
+ safe_free(cur_file);
+ cur_file = new_stdin ? NULL : strduplicate(new_file);
+ yylval.boolean = basefile ? !strcmp(cur_file,basefile) :
+ cur_file == basefile;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* When the end of the current input file is reached, pop any
+ * nested includes.
+ */
+int
+yywrap ()
+{
+ IncludeStack *sp;
+
+ if (inc_depth > 0) {
+ --inc_depth;
+ sp = inc_stack + inc_depth;
+ fclose(yyin);
+#ifdef FLEX_SCANNER
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(sp->buffer);
+#else
+ yyin = sp->fp;
+#endif
+ safe_free(cur_file);
+ cur_file = sp->file;
+ line_num = sp->line_num + 1;
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+
+static void new_dynbuf()
+{
+ if ((dynbuf = malloc(dynbuf_size = DYNBUF_ALLOC)) == 0)
+ outmem();
+
+ dynbuf_current = 0;
+}
+
+static void add_dynbuf(c)
+int c;
+{
+ if (dynbuf_current == dynbuf_size &&
+ ((dynbuf = realloc(dynbuf,dynbuf_size += DYNBUF_ALLOC)) == 0))
+ outmem();
+
+ dynbuf[dynbuf_current++] = c;
+}
+
+static char *return_dynbuf()
+{
+ add_dynbuf('\0');
+
+ /* chop it back to size */
+ if ((dynbuf = realloc(dynbuf,dynbuf_current)) == 0)
+ outmem();
+
+ return dynbuf;
+}
+
+/* Output an error message along with the current line number in the
+ * source file.
+ */
+void
+output_error ()
+{
+ errors++;
+ fprintf(stderr, "%s:%d: ", cur_file ? cur_file : "stdin", line_num);
+ fprintf(stderr, "\n(%s) ", yytext);
+}
diff --git a/libc/COPYING b/libc/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/libc/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/libc/README.libc b/libc/README.libc
new file mode 100644
index 0000000..0f0260d
--- /dev/null
+++ b/libc/README.libc
@@ -0,0 +1,10 @@
+This directory contains sources for library routines which some users have
+found to be missing on their machines.
+
+Since some of this code is covered by the GNU General Public License, a copy
+is included in the file COPYING. Note that only those files in the c2man
+distribution which explicitly state that they fall under the terms of this
+license actually do so.
+
+The getopt routines (needed for MSC on the PC, and for VMS) are adapted from
+the GNU versions.
diff --git a/libc/alloca.c b/libc/alloca.c
new file mode 100644
index 0000000..9e6a3a2
--- /dev/null
+++ b/libc/alloca.c
@@ -0,0 +1,186 @@
+/*
+ alloca -- (mostly) portable public-domain implementation -- D A Gwyn
+
+ This implementation of the PWB library alloca() function,
+ which is used to allocate space off the run-time stack so
+ that it is automatically reclaimed upon procedure exit,
+ was inspired by discussions with J. Q. Johnson of Cornell.
+
+ It should work under any C implementation that uses an
+ actual procedure stack (as opposed to a linked list of
+ frames). There are some preprocessor constants that can
+ be defined when compiling for your specific system, for
+ improved efficiency; however, the defaults should be okay.
+
+ The general concept of this implementation is to keep
+ track of all alloca()-allocated blocks, and reclaim any
+ that are found to be deeper in the stack than the current
+ invocation. This heuristic does not reclaim storage as
+ soon as it becomes invalid, but it will do so eventually.
+
+ As a special case, alloca(0) reclaims storage without
+ allocating any. It is a good idea to use alloca(0) in
+ your main control loop, etc. to force garbage collection.
+*/
+#ifndef lint
+static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */
+#endif
+
+#ifdef emacs
+#include "config.h"
+#ifdef static
+/* actually, only want this if static is defined as ""
+ -- this is for usg, in which emacs must undefine static
+ in order to make unexec workable
+ */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif static
+#endif emacs
+
+#ifdef X3J11
+typedef void *pointer; /* generic pointer type */
+#else
+typedef char *pointer; /* generic pointer type */
+#endif
+
+#define NULL 0 /* null pointer constant */
+
+extern void free();
+extern pointer malloc();
+
+/*
+ Define STACK_DIRECTION if you know the direction of stack
+ growth for your system; otherwise it will be automatically
+ deduced at run-time.
+
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+*/
+
+#ifndef STACK_DIRECTION
+#define STACK_DIRECTION 0 /* direction unknown */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define STACK_DIR STACK_DIRECTION /* known at compile-time */
+
+#else /* STACK_DIRECTION == 0; need run-time code */
+
+static int stack_dir; /* 1 or -1 once known */
+#define STACK_DIR stack_dir
+
+static void
+find_stack_direction (/* void */)
+{
+ static char *addr = NULL; /* address of first
+ `dummy', once known */
+ auto char dummy; /* to get stack address */
+
+ if (addr == NULL)
+ { /* initial entry */
+ addr = &dummy;
+
+ find_stack_direction (); /* recurse once */
+ }
+ else /* second entry */
+ if (&dummy > addr)
+ stack_dir = 1; /* stack grew upward */
+ else
+ stack_dir = -1; /* stack grew downward */
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/*
+ An "alloca header" is used to:
+ (a) chain together all alloca()ed blocks;
+ (b) keep track of stack depth.
+
+ It is very important that sizeof(header) agree with malloc()
+ alignment chunk size. The following default should work okay.
+*/
+
+#ifndef ALIGN_SIZE
+#define ALIGN_SIZE sizeof(double)
+#endif
+
+typedef union hdr
+{
+ char align[ALIGN_SIZE]; /* to force sizeof(header) */
+ struct
+ {
+ union hdr *next; /* for chaining headers */
+ char *deep; /* for stack depth measure */
+ } h;
+} header;
+
+/*
+ alloca( size ) returns a pointer to at least `size' bytes of
+ storage which will be automatically reclaimed upon exit from
+ the procedure that called alloca(). Originally, this space
+ was supposed to be taken from the current stack frame of the
+ caller, but that method cannot be made to work for some
+ implementations of C, for example under Gould's UTX/32.
+*/
+
+static header *last_alloca_header = NULL; /* -> last alloca header */
+
+pointer
+alloca (size) /* returns pointer to storage */
+ unsigned size; /* # bytes to allocate */
+{
+ auto char probe; /* probes stack depth: */
+ register char *depth = &probe;
+
+#if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* unknown growth direction */
+ find_stack_direction ();
+#endif
+
+ /* Reclaim garbage, defined as all alloca()ed storage that
+ was allocated from deeper in the stack than currently. */
+
+ {
+ register header *hp; /* traverses linked list */
+
+ for (hp = last_alloca_header; hp != NULL;)
+ if (STACK_DIR > 0 && hp->h.deep > depth
+ || STACK_DIR < 0 && hp->h.deep < depth)
+ {
+ register header *np = hp->h.next;
+
+ free ((pointer) hp); /* collect garbage */
+
+ hp = np; /* -> next header */
+ }
+ else
+ break; /* rest are not deeper */
+
+ last_alloca_header = hp; /* -> last valid storage */
+ }
+
+ if (size == 0)
+ return NULL; /* no allocation required */
+
+ /* Allocate combined header + user data storage. */
+
+ {
+ register pointer new = malloc (sizeof (header) + size);
+ /* address of header */
+
+ ((header *)new)->h.next = last_alloca_header;
+ ((header *)new)->h.deep = depth;
+
+ last_alloca_header = (header *)new;
+
+ /* User storage begins just after header. */
+
+ return (pointer)((char *)new + sizeof(header));
+ }
+}
diff --git a/libc/getopt.c b/libc/getopt.c
new file mode 100644
index 0000000..479d4cc
--- /dev/null
+++ b/libc/getopt.c
@@ -0,0 +1,735 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* NOTE!!! AIX requires this to be the first thing in the file.
+ Do not put ANYTHING before it! */
+#if !defined (__GNUC__) && defined (_AIX)
+ #pragma alloca
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
+#include <alloca.h>
+#else
+#ifdef _MSC_VER
+#include <malloc.h>
+#else
+#ifndef _AIX
+char *alloca ();
+#endif
+#endif
+#endif /* alloca.h */
+#endif /* not __GNUC__ */
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#undef alloca
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#else /* Not GNU C library. */
+#define __alloca alloca
+#endif /* GNU C library. */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+ long-named option. Because this is not POSIX.2 compliant, it is
+ being phased out. */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+static void
+my_bcopy (from, to, size)
+ const char *from;
+ char *to;
+ int size;
+{
+ int i;
+ for (i = 0; i < size; i++)
+ to[i] = from[i];
+}
+#endif /* GNU C library. */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
+ char **temp = (char **) __alloca (nonopts_size);
+
+ /* Interchange the two blocks of data in ARGV. */
+
+ my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
+ my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
+ (optind - last_nonopt) * sizeof (char *));
+ my_bcopy ((char *) temp,
+ (char *) &argv[first_nonopt + optind - last_nonopt],
+ nonopts_size);
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ int option_index;
+
+ optarg = 0;
+
+ /* Initialize the internal data when the first call is made.
+ Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ if (optind == 0)
+ {
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (getenv ("POSIXLY_CORRECT") != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Now skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ if (longopts != NULL
+ && ((argv[optind][0] == '-'
+ && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ ))
+ {
+ const struct option *p;
+ char *s = nextchar;
+ int exact = 0;
+ int ambig = 0;
+ const struct option *pfound = NULL;
+ int indfound;
+
+ while (*s && *s != '=')
+ s++;
+
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name;
+ p++, option_index++)
+ if (!strncmp (p->name, nextchar, s - nextchar))
+ {
+ if (s - nextchar == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*s)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = s + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+#if 0
+ if (c < 040 || c >= 0177)
+ fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+ argv[0], c);
+ else
+ fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+ }
+ optopt = c;
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = 0;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+#if 0
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/libc/getopt.h b/libc/getopt.h
new file mode 100644
index 0000000..45541f5
--- /dev/null
+++ b/libc/getopt.h
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/libc/getopt1.c b/libc/getopt1.c
new file mode 100644
index 0000000..a32615c
--- /dev/null
+++ b/libc/getopt1.c
@@ -0,0 +1,176 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "getopt.h"
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/manpage.c b/manpage.c
new file mode 100644
index 0000000..8f6c047
--- /dev/null
+++ b/manpage.c
@@ -0,0 +1,1347 @@
+/* $Id: manpage.c,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ * stuff to do with manual page outputing
+ */
+
+/*
+ * This file has been modified by Manoj Srivastava <srivasta@debian.org>
+ * to incorporate a patch that was also submitted to the author. The change
+ * shall be incorporated upstream in due course.
+ */
+
+#include "c2man.h"
+
+#include <errno.h>
+#include <ctype.h>
+
+#include "manpage.h"
+#include "strconcat.h"
+#include "strappend.h"
+#include "semantic.h"
+#include "output.h"
+
+#ifdef I_SYS_FILE
+#include <sys/file.h>
+#endif
+
+/* list of manual pages */
+ManualPage *firstpage = NULL;
+ManualPage **lastpagenext = &firstpage;
+
+void dummy() {}
+
+void
+new_manual_page(comment, decl_spec, declarator)
+ char *comment;
+ DeclSpec *decl_spec;
+ Declarator *declarator;
+{
+ ManualPage *newpage;
+
+ /* check that we really want a man page for this */
+ if ((!comment) ||
+ !inbasefile ||
+ (!variables_out && !is_function_declarator(declarator)) ||
+ (decl_spec->flags & DS_JUNK) ||
+ (!static_out && (decl_spec->flags & DS_STATIC) && !header_file) ||
+
+ /* only document extern stuff if it's in a header file, or includes a
+ * function definition.
+ */
+ ((decl_spec->flags & DS_EXTERN) && !header_file &&
+ declarator->type != DECL_FUNCDEF))
+ {
+ free_decl_spec(decl_spec);
+ free_declarator(declarator);
+ safe_free(comment);
+ return;
+ }
+
+ declarator->comment = comment;
+
+ newpage = (ManualPage *)safe_malloc(sizeof *newpage);
+ newpage->decl_spec = (DeclSpec *)safe_malloc(sizeof *newpage->decl_spec);
+ newpage->declarator = declarator;
+
+ *newpage->decl_spec = *decl_spec;
+ newpage->sourcefile = strduplicate(basefile);
+ newpage->sourcetime = basetime;
+
+ *lastpagenext = newpage;
+ newpage->next = NULL;
+ lastpagenext = &newpage->next;
+}
+
+void free_manual_page(page)
+ ManualPage *page;
+{
+ free_decl_spec(page->decl_spec);
+ free(page->decl_spec);
+ free_declarator(page->declarator);
+ safe_free(page->sourcefile);
+}
+
+/* free the list of manual pages */
+void free_manual_pages(first)
+ ManualPage *first;
+{
+ ManualPage *page, *next;
+
+ /* free any terse description read from the file */
+ if (group_terse && !terse_specified)
+ {
+ free(group_terse);
+ group_terse = NULL;
+ }
+
+ for (page = first;page;page = next)
+ {
+ next = page->next;
+ free_manual_page(page);
+ free(page);
+ }
+}
+
+/* allocate a substring starting at start, ending at end (NOT including *end) */
+char *alloc_string(start, end)
+ const char *start;
+ const char *end;
+{
+ int len = end - start;
+ char *ret;
+ if (len == 0) return NULL;
+
+ ret = (char *)safe_malloc((size_t)len+1);
+
+ strncpy(ret,start,len);
+ ret[len] = '\0';
+
+ return ret;
+}
+
+/* remember the terse description from the first comment in a file */
+void remember_terse(comment)
+ char *comment;
+{
+ char *c, *d;
+
+ enum { STUFF, LEADSPACE, DASH, TRAILSPACE, FOUND } state = STUFF;
+
+ /* if we've found a terse comment in a previous file, or one was
+ * specified on the command line, forget it.
+ */
+ if (group_terse) return;
+
+ /* look for a whitespace surrounded sequence of dashes to skip */
+ for (c = comment;*c && state != FOUND;c++)
+ {
+ switch (state)
+ {
+ case STUFF: if (isspace(*c)) state = LEADSPACE;
+ break;
+ case LEADSPACE: if (*c == '-') state = DASH;
+ else if (!isspace(*c)) state = STUFF;
+ break;
+ case DASH: if (isspace(*c)) state = TRAILSPACE;
+ else if (*c != '-') state = STUFF;
+ break;
+ case TRAILSPACE:if (!isspace(*c)) { c--; state = FOUND; }
+ break;
+ case FOUND: break;
+ }
+ }
+
+ /* if no dashes were found, go back to the start */
+ if (state != FOUND) c = comment;
+
+ d = c + 1;
+
+ while (*d && *d != '\n')
+ d++;
+
+ group_terse = alloc_string(c,d);
+}
+
+/* output a comment in man page form, followed by a newline */
+void
+output_comment(comment)
+const char *comment;
+{
+ if (!comment || !comment[0])
+ output->text("Not Documented.");
+ else if (fixup_comments)
+ output->description(comment);
+ else
+ output->text(comment);
+
+ output->character('\n');
+}
+
+/* output the phrase "a[n] <type name>" */
+void output_conjunction(text)
+char *text;
+{
+ output->character('a');
+ if (strchr("aAeEiIoOuU",text[0])) output->character('n');
+ output->character(' ');
+ output->code(text);
+}
+
+/* output the description for an identifier; be it return value or param */
+static void output_identifier_description(comment, outfunc,
+ decl_spec, declarator)
+ const char *comment; /* comment for this identifier */
+ void (*outfunc) _((const char *)); /* function to output comment */
+ const DeclSpec *decl_spec;
+ const Declarator *declarator;
+{
+ /* one day, this may document the contents of structures too */
+
+ /* output list of possible enum values, if any */
+ if (decl_spec->enum_list)
+ {
+ int maxtaglen = 0;
+ char *longestag = NULL;
+ int descriptions = 0;
+ int entries = 0;
+ Enumerator *e;
+ int is_first = 1;
+ boolean started = FALSE;
+
+ /* don't output the "Not Doc." message for enums */
+ if (comment)
+ {
+ (*outfunc)(comment);
+ output->blank_line();
+ }
+
+ /* see if any have descriptions */
+ for (e = decl_spec->enum_list->first; e; e = e->next)
+ if (e->name[0] != '_')
+ {
+ int taglen = strlen(e->name);
+ if (taglen > maxtaglen)
+ {
+ maxtaglen = taglen;
+ longestag = e->name;
+ }
+ if (e->comment) descriptions = 1;
+ entries++;
+ }
+
+ /* if there are a lot of them, the list may be automatically generated,
+ * and probably isn't wanted in every manual page.
+ */
+ if (entries > 20)
+ {
+ char entries_s[15];
+ sprintf(entries_s, "%d", entries);
+ output->text("Since there are ");
+ output->text(entries_s);
+ output->text(" possible values for ");
+ output_conjunction(decl_spec->text);
+ output->text(", they are not all listed here.\n");
+ }
+ else if (entries > 0) /* skip the pathological case */
+ {
+ /* the number of possibilities is reasonable; list them all */
+ output->text("Possible values for ");
+ output_conjunction(decl_spec->text);
+ output->text(" are as follows:\n");
+
+ for (e = decl_spec->enum_list->first; e; e = e->next)
+ {
+ /* don't print names with a leading underscore! */
+ if (e->name[0] == '_') continue;
+
+ if (e->group_comment)
+ {
+ /* break out of table mode for the group comment */
+ if (started)
+ {
+ if (descriptions)
+ output->table_end();
+ else
+ output->list_end();
+ started = FALSE;
+ }
+ output->indent();
+ output_comment(e->group_comment);
+ }
+
+ if (!started)
+ {
+ if (descriptions)
+ output->table_start(longestag);
+ else
+ output->list_start();
+ started = TRUE;
+ }
+
+ if (descriptions)
+ output->table_entry(e->name, e->comment);
+ else
+ {
+ if (!is_first)
+ output->list_separator();
+ is_first = 0;
+ output->list_entry(e->name);
+ }
+ }
+
+ if (started)
+ {
+ if (descriptions)
+ output->table_end();
+ else
+ output->list_end();
+ }
+ }
+ }
+ else
+ (*outfunc)(comment);
+}
+
+/* is there automatic documentation here? */
+static boolean auto_documented(page)
+const ManualPage *page;
+{
+ /* one day we may handle structs too */
+ return
+ page->decl_spec->enum_list != NULL; /* enums are self-documenting. */
+}
+
+/* decide if a manual page needs a RETURNS section.
+ * If this is true, then output_identifier_description must be able to generate
+ * sensible output for it.
+ */
+static boolean needs_returns_section(page)
+const ManualPage *page;
+{
+ return
+ (page->returns && page->returns[0]) ||
+ (auto_documented(page) && is_function_declarator(page->declarator));
+}
+
+/* does this declarator have documented parameters? */
+boolean has_documented_parameters(d)
+const Declarator *d;
+{
+ if (has_parameters(d))
+ {
+ Parameter *p;
+
+ for (p = d->head->params.first; p != NULL; p = p->next)
+ if (p->declarator->comment || always_document_params)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* Output the list of function parameter descriptions.
+ */
+void
+output_parameter_descriptions (params, function)
+ParameterList *params;
+char *function;
+{
+ Parameter *p;
+ boolean tag_list_started = FALSE;
+
+ for (p = params->first; p != NULL; p = p->next)
+ {
+ if (p->suppress ||
+ (!always_document_params && p->declarator->comment == NULL))
+ continue;
+
+ if (!tag_list_started)
+ {
+ output->tag_list_start();
+ tag_list_started = TRUE;
+ }
+
+ if (p->duplicate)
+ output->tag_entry_start_extra();
+ else
+ output->tag_entry_start();
+
+ output_parameter(p);
+
+ /* include function name if it's a duplicate */
+ if (p->duplicate)
+ output->tag_entry_end_extra(function);
+ else
+ output->tag_entry_end();
+
+ output_identifier_description(p->declarator->comment, output_comment,
+ &p->decl_spec, p->declarator);
+ }
+
+ if (tag_list_started)
+ output->tag_list_end();
+}
+
+/* split out the 'Returns:' section of a function comment */
+boolean
+split_returns_comment(comment, description, returns)
+ char *comment;
+ char **description;
+ char **returns;
+{
+ char *retstart;
+
+ for (retstart = comment;
+ retstart;
+ retstart = strchr(retstart,'\n'))
+ {
+ if (*retstart == '\n') retstart++; /* skip the newline */
+
+ if (!strncmpi(retstart, "returns",(size_t)7))
+ {
+ char *descend = retstart - 2; /* back before newline */
+
+ /* go back to the end of the description in case there were
+ * linefeeds before the returns.
+ */
+ while (descend > comment && isspace(*descend))
+ descend--;
+
+ *description =
+ descend > comment ? alloc_string(comment,descend+1) : NULL;
+
+ retstart += 7;
+
+ while (*retstart == ':' || isspace(*retstart))
+ retstart++;
+
+ if (*retstart)
+ *returns = strduplicate(retstart);
+ else
+ *returns = NULL;
+ return TRUE;
+ }
+ }
+
+ *description = comment;
+ *returns = NULL;
+ return FALSE;
+}
+
+/* skip to past the dash on the first line, if there is one
+ * The dash must be surrounded by whitespace, so hyphens are not skipped.
+ */
+const char *skipdash(c)
+const char *c;
+{
+ const char *d;
+
+ /* ignore anything on the first line, up to a dash (if any) */
+ for (d = c + 1; *d && *d != '\n' && *d != '-'; d++)
+ ;
+
+ if (isspace(d[-1]) && d[0] == '-' && isspace(d[1]))
+ {
+ do
+ d++;
+ while (*d && *d != '\n' && isspace(*d));
+
+ if (*d && *d != '\n') c = d;
+ }
+ return c;
+}
+
+/* split the function comment into manual page format.
+ * returns TRUE if the DESCRIPTION field was explicit.
+ */
+boolean
+split_function_comment(comment, identifier_name,
+ terse, description, returns, extra_sections)
+ const char *comment;
+ const char *identifier_name;
+ char **terse;
+ char **description;
+ char **returns;
+ Section **extra_sections;
+{
+ const char *c, *start_text = NULL, *end_text = NULL;
+ char **put_ptr = NULL;
+ Section *first_section, **lastnextsection = &first_section;
+ boolean explicit_description = FALSE;
+ boolean lastblank = TRUE;
+ boolean skip_dash = FALSE;
+
+ *description = *returns = NULL;
+ if (terse) *terse = NULL;
+
+ /* for each line... */
+ for (c = comment; *c;)
+ {
+ const char *start_line = c;
+ boolean section_heading;
+ /* remember if it's a blank line */
+ if (*c == '\n')
+ {
+ lastblank = TRUE;
+ c++;
+ continue;
+ }
+
+ /* if the last one was blank, perhaps this one is a section heading
+ */
+ if (lastblank)
+ {
+ boolean need_colon = FALSE;
+
+ /* see if we've found the start of a SECTION */
+ while (isalnum(*c) || *c == ' ' || *c == '/')
+ {
+ if (isspace(*c)) need_colon = TRUE;
+ c++;
+ }
+
+ section_heading = (!need_colon && *c == '\n') ||
+ (*c == ':' && (!need_colon || *(c+1) == '\n')) ||
+ (!need_colon && *c == '\0' && start_line == comment);
+ }
+ else
+ section_heading = FALSE;
+
+ lastblank = FALSE; /* this one's not blank; for next time */
+
+ if (section_heading)
+ {
+ size_t section_len = c - start_line; /* length of section name */
+
+ /* yes, we've found a SECTION; store the previous one (if any) */
+ if (put_ptr && start_text)
+ {
+ if (skip_dash) start_text = skipdash(start_text);
+ *put_ptr = alloc_string(start_text,end_text);
+ }
+
+ skip_dash = FALSE;
+
+ /* check for comments that start with the name of the identifier */
+ if (start_line == comment &&
+ !strncmp(start_line, identifier_name, section_len))
+ {
+ put_ptr = description;
+ }
+
+ /* only accept NAME if not grouped */
+ else if (terse &&
+ (!strncmpi(start_line,"NAME", section_len) ||
+ !strncmpi(start_line,"FUNCTION", section_len) ||
+ !strncmpi(start_line,"PROCEDURE", section_len) ||
+ !strncmpi(start_line,"ROUTINE", section_len))
+ )
+
+ {
+ put_ptr = terse;
+ skip_dash = TRUE;
+ }
+ else if (!strncmpi(start_line,"DESCRIPTION", section_len))
+ {
+ explicit_description = TRUE;
+ put_ptr = description;
+ }
+ else if (!strncmpi(start_line,"RETURNS", section_len))
+ {
+ put_ptr = returns;
+ }
+ else
+ {
+ /* allocate a new section */
+ Section *new_section =
+ (Section *)safe_malloc(sizeof *new_section);
+
+ *lastnextsection = new_section;
+ lastnextsection = &new_section->next;
+
+ new_section->name = alloc_string(start_line,c);
+ strtoupper(new_section->name);
+ new_section->text = NULL;
+ new_section->been_output = FALSE; /* not been output yet */
+ put_ptr = &new_section->text;
+ }
+
+ /* defer decision about where text starts till we find some */
+ start_text = NULL;
+
+ if (*c == ':') /* skip the terminating : */
+ {
+ c++;
+
+ /* skip forward to the start of the text */
+ while (*c && *c != '\n' && isspace(*c))
+ c++;
+
+ /* if we find the text here, then we've got it */
+ if (*c && *c != '\n')
+ start_text = c;
+ }
+ }
+ else
+ {
+ /* are we looking at the top of the function comment? */
+ if (start_line == comment)
+ {
+ /* only look for terse comment if not grouped together */
+ if (terse)
+ {
+ const char *endterse, *afterdash = skipdash(start_line);
+
+ /* find the end of the terse comment */
+ while (*c && *c != '\n')
+ {
+ c++;
+ /* '.' ends terse description only if it ends sentence */
+ if (*(c-1)=='.' && *c && isspace(*c))
+ break;
+ }
+
+ endterse = c;
+ *terse = alloc_string(
+ afterdash < endterse ? afterdash : start_line,
+ endterse);
+
+ /* skip it if it's a ., and any trailing spaces */
+ if (*c == '.')
+ do c++; while (*c && *c != '\n' && isspace(*c));
+
+ start_text = NULL; /* look for it */
+
+ if (*c && *c != '\n')
+ /* actually, it's a description, starting here */
+ start_text = c;
+ }
+ /* must be a description starting at the beginning of the line.
+ */
+ else
+ start_text = start_line;
+
+ put_ptr = description;
+ }
+ else
+ /* have we just located the first real text in a section? */
+ if (put_ptr && !start_text) start_text = start_line;
+ }
+
+ /* skip the line */
+ if (*c && *c != '\n')
+ while (*c && *c != '\n') c++;
+
+ end_text = c; /* so far, the text ends at the end of this line */
+ if (*c) c++;
+ }
+
+ /* store the last one */
+ if (put_ptr && start_text)
+ {
+ if (skip_dash) start_text = skipdash(start_text);
+ *put_ptr = alloc_string(start_text,end_text);
+ }
+
+ /* terminate (or nuke) section list */
+ *lastnextsection = NULL;
+
+ *extra_sections = first_section;
+
+ return explicit_description;
+}
+
+/* see if two parameters are declared identically */
+boolean params_identical(first, second)
+ Parameter *first;
+ Parameter *second;
+{
+ return
+ first->decl_spec.flags == second->decl_spec.flags &&
+
+ /* there may be no decl_spec.text if it's an ellipsis arg */
+ ((!first->decl_spec.text && !second->decl_spec.text) ||
+ (first->decl_spec.text && second->decl_spec.text &&
+ !strcmp(first->decl_spec.text, second->decl_spec.text))) &&
+
+ ((!first->declarator->text && !second->declarator->text) ||
+ (first->declarator->text && second->declarator->text &&
+ !strcmp(first->declarator->text, second->declarator->text)));
+}
+
+/* search all the parameters in this grouped manual page for redundancies */
+boolean mark_duplicate_parameters(firstpage)
+ ManualPage *firstpage;
+{
+ Parameter *param;
+ boolean any = FALSE;
+ ManualPage *page;
+
+ for (page = firstpage; page; page = page->next)
+ {
+ if (has_parameters(page->declarator))
+ for (param = page->declarator->head->params.first; param;
+ param = param->next)
+ {
+ ManualPage *otherpage;
+ Parameter *otherparam;
+
+ if (always_document_params || param->declarator->comment)
+ any = TRUE;
+
+ for (otherpage = page->next; otherpage;
+ otherpage = otherpage->next)
+ {
+ if (has_parameters(otherpage->declarator))
+ for (otherparam = otherpage->declarator->head->params.first;
+ otherparam;
+ otherparam = otherparam->next)
+ {
+ /* do these two look the same? */
+ if (params_identical(param, otherparam))
+ {
+ /* order is important for bit positions */
+ enum { NEITHER, US, THEM, BOTH } has_comm = NEITHER;
+
+ /* work out who has the comment */
+ if (param->declarator->comment) has_comm |= US;
+ if (otherparam->declarator->comment) has_comm |= THEM;
+
+ switch(has_comm)
+ {
+ case NEITHER:
+ case US:
+ otherparam->suppress = TRUE;
+ break;
+ case THEM:
+ param->suppress = TRUE;
+ break;
+ case BOTH:
+ if (!strcmp(param->declarator->comment,
+ otherparam->declarator->comment))
+ otherparam->suppress = TRUE;
+ else
+ {
+ param->duplicate = TRUE;
+ otherparam->duplicate = TRUE;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return any;
+}
+
+/* output a formatting string so that it works with filling on */
+void output_format_string(fmt)
+const char *fmt;
+{
+ while (*fmt)
+ {
+ output->character(*fmt);
+
+ if (*fmt++ == '\n')
+ output->break_line(); /* break the line */
+ }
+}
+
+/* write the warning for the header */
+void output_warning()
+{
+ output->comment();
+ output->text("WARNING! THIS FILE WAS GENERATED AUTOMATICALLY BY ");
+ output->text(progname);
+ output->text("!\n");
+ output->comment();
+ output->text("DO NOT EDIT! CHANGES MADE TO THIS FILE WILL BE LOST!\n");
+}
+
+void output_includes()
+{
+ IncludeFile *incfile;
+
+ for (incfile = first_include; incfile; incfile=incfile->next)
+ {
+ char *name = incfile->name;
+ boolean surrounded = *name == '"' || *name == '<';
+
+ output->text("#include ");
+ if (!surrounded) output->character('<');
+ output->text(name);
+ if (!surrounded) output->character('>');
+ output->text("\n");
+ output->break_line();
+ }
+}
+
+int exclude_section(section)
+const char *section;
+{
+ ExcludeSection *exclude;
+
+ for (exclude = first_excluded_section ; exclude ; exclude = exclude->next)
+ if (!strcmp(section, exclude->name)) return 1;
+
+ return 0;
+}
+
+
+/* Writes the entire contents of the manual page specified by basepage. */
+void
+output_manpage(firstpage, basepage, input_files, title, section)
+ /* the first page in the list of all manual pages. This is used to build
+ * the SEE ALSO section of related pages when group_together is false.
+ */
+ ManualPage *firstpage;
+
+ /* the base page from which the output manual page will be generated. if
+ * group_together indicates that the user wanted grouped pages, basepage
+ * will always be the same as firstpage, and all the ManualPage's in the
+ * list will be grouped together into the one output page.
+ */
+ ManualPage *basepage;
+
+ int input_files;
+ const char *title;
+ const char *section;
+{
+ ManualPage *page;
+ boolean need_returns;
+ char *terseout, *terse = NULL;
+ boolean exclude_description = exclude_section("DESCRIPTION");
+
+ /* check if there's more than one page in the group */
+ boolean grouped = group_together && firstpage->next;
+
+ /* split up all the function comments for this page */
+ for (page = basepage; page; page = page->next)
+ {
+ boolean explicit_description =
+ split_function_comment(page->declarator->comment,
+ page->declarator->name,
+ group_together ? (char **)NULL : &terse,
+ &page->description,&page->returns,&page->first_section);
+
+ /* we may need to look harder if RETURNS wasn't easy to find in the
+ * function comment.
+ */
+ if (page->returns == NULL)
+ {
+ /* if there was a retcomment supplied by the declarator, use it if
+ * we couldn't split anything from the function comment.
+ */
+ if (page->declarator->retcomment)
+ {
+ page->returns = page->declarator->retcomment;
+
+ /* page->returns now owns the string */
+ page->declarator->retcomment = NULL;
+ }
+ else
+ /* if there wasn't a RETURNS section, and the DESCRIPTION field
+ * was not explicit, see if we can split one out of the
+ * description field.
+ */
+ if (!explicit_description)
+ {
+ char *newdesc;
+ if (split_returns_comment(page->description, &newdesc,
+ &page->returns))
+ {
+ free(page->description);
+ page->description = newdesc;
+ }
+ }
+ }
+
+ if (!group_together) break;
+ }
+
+ /* work out what we'll actually print as a terse description */
+ terseout = group_terse ? group_terse : (terse ? terse : "Not Described");
+
+ output->header(basepage, input_files, grouped,
+ title ? title : basepage->declarator->name, terseout, section);
+
+ output->name(NULL);
+ /* output the names of all the stuff documented on this page */
+ for (page = basepage; page; page = page->next)
+ {
+ output->name(page->declarator->name);
+
+ if (!group_together) break;
+
+ if (page->next) output->text(",\n");
+ }
+
+ output->terse_sep();
+ output->text(terseout);
+ output->character('\n');
+
+ if (!exclude_section("SYNOPSIS"))
+ {
+ output->section("SYNOPSIS");
+
+ output->code_start();
+
+ /* list the include files the user asked us to */
+ output_includes();
+
+ /* if it's a header file, say to #include it */
+ if (header_file)
+ {
+ output->text("#include <");
+ if (header_prefix)
+ {
+ output->text(header_prefix);
+ output->character('/');
+ }
+ output->text(basefile);
+ output->text(">\n");
+ }
+
+ /* can't just use .PP; that may reset our font */
+ if (first_include || header_file) output->blank_line();
+
+ for (page = basepage; page; page = page->next)
+ {
+ output_format_string(decl_spec_prefix);
+
+ /* make sure variables are prefixed extern */
+ if (!(page->decl_spec->flags & DS_STATIC) &&
+ !is_function_declarator(page->declarator) &&
+ !strstr(page->decl_spec->text, "extern"))
+ output->text("extern ");
+
+ output_decl_spec(page->decl_spec);
+ output_format_string(declarator_prefix);
+
+ /* format it nicely if there's more than one parameter */
+ output_declarator(page->declarator,
+ page->declarator->head->params.first !=
+ page->declarator->head->params.last);
+
+ output->text(";\n");
+
+ if (!grouped) break;
+ if (page->next) output->blank_line();
+ }
+
+ output->code_end();
+ }
+
+ /* only output paramaters if there actually are some,
+ * not including merely (void)
+ */
+ if (!exclude_section("PARAMETERS") &&
+ ((grouped && mark_duplicate_parameters(basepage)) ||
+ (!grouped && has_documented_parameters(basepage->declarator))))
+ {
+ output->section("PARAMETERS");
+
+ for (page = basepage; page; page = page->next)
+ {
+ if (has_parameters(page->declarator))
+ output_parameter_descriptions(&page->declarator->head->params,
+ page->declarator->name);
+ if (!grouped) break; /* only do first page */
+ }
+ }
+
+ if (!exclude_description)
+ output->section("DESCRIPTION");
+
+ if (grouped)
+ {
+ need_returns = FALSE;
+ for (page = basepage; page; page = page->next)
+ {
+ if (needs_returns_section(page)) need_returns = TRUE;
+
+ if (!exclude_description)
+ {
+ /* enum variables are documented in DESCRIPTION */
+ if (auto_documented(page) &&
+ !is_function_declarator(page->declarator))
+ {
+ output->sub_section(page->declarator->name);
+ output_identifier_description(page->description,
+ output_comment, page->decl_spec, page->declarator);
+ }
+ else if (page->description)
+ {
+ output->sub_section(page->declarator->name);
+ output_comment(page->description);
+ }
+ }
+
+ safe_free(page->description);
+ }
+ }
+ else
+ {
+ need_returns = needs_returns_section(basepage);
+
+ if (!exclude_description)
+ {
+ const char *descr = basepage->description
+ ? basepage->description : terseout;
+
+ if (auto_documented(page) &&
+ !is_function_declarator(page->declarator))
+ output_identifier_description(descr, output_comment,
+ page->decl_spec, page->declarator);
+ else
+ output_comment(descr);
+ }
+
+ safe_free(basepage->description);
+ }
+
+ /* terse can now never be a static string */
+ safe_free(terse);
+
+ if (need_returns && !exclude_section("RETURNS"))
+ {
+ output->section("RETURNS");
+
+ for (page = basepage; page; page = page->next)
+ {
+ if (needs_returns_section(page))
+ {
+ if (grouped) output->sub_section(page->declarator->name);
+
+ output_identifier_description(page->returns, output->returns,
+ page->decl_spec, page->declarator);
+ safe_free(page->returns);
+ }
+
+ if (!grouped) break;
+ }
+ }
+
+ /* output any other sections */
+ for (page = basepage; page; page = page->next)
+ {
+ Section *section, *next;
+
+ for (section = page->first_section; section; section = next)
+ {
+ next = section->next;
+
+ if (!section->been_output && section->text &&
+ strncmpi(section->text,"none",4) &&
+ !exclude_section(section->name))
+ {
+ output->section(section->name);
+ if (grouped) output->sub_section(page->declarator->name);
+ output_comment(section->text);
+ section->been_output = TRUE;
+
+ if (grouped && page->next)
+ {
+ ManualPage *other_page = page->next;
+
+ /* look through all the other pages for matching sections */
+ for (; other_page; other_page = other_page->next)
+ {
+ Section *other_section = other_page->first_section;
+ for (;other_section; other_section =
+ other_section->next)
+ {
+ if (other_section->been_output ||
+ strcmp(other_section->name, section->name))
+ continue;
+
+ output->sub_section(other_page->declarator->name);
+ output_comment(other_section->text);
+ other_section->been_output = TRUE;
+ }
+ }
+ }
+ }
+
+
+ /* free this section */
+ free(section->name);
+ safe_free(section->text);
+ free(section);
+ }
+
+ if (!grouped) break;
+ }
+
+ /* only output SEE ALSO if not grouped */
+ if (!group_together)
+ {
+ ManualPage *also;
+
+ /* add the SEE ALSO section */
+ /* look for any other functions to refer to */
+ for (also = firstpage; also && also == basepage; also = also->next)
+ ;
+
+ if (also && !exclude_section("SEE ALSO")) /* did we find at least one? */
+ {
+ int isfirst = 1;
+
+ output->section("SEE ALSO");
+
+ for (also = firstpage; also; also = also->next)
+ {
+ if (also == basepage) continue;
+
+ if (!isfirst)
+ output->text(",\n");
+ else
+ isfirst = 0;
+
+ output->reference(also->declarator->name);
+ }
+
+ output->character('\n');
+ }
+ }
+
+ if (!make_embeddable)
+ output->file_end();
+}
+
+
+/* generate output filename based on a string */
+char *page_file_name(based_on, object_type, extension)
+ /* string to base the name on; this will be the name of an identifier or
+ * the base of the input file name.
+ */
+ const char *based_on;
+ enum Output_Object object_type; /* class of object documented */
+ const char *extension; /* file extension to use */
+{
+ char *filename;
+ const char *subdir = output_object[object_type].subdir;
+
+#ifndef FLEXFILENAMES
+ char *basename;
+ int chopoff = 14 - strlen(extension) - 1;
+
+ basename = strduplicate(based_on);
+ if (strlen(basename) > chopoff)
+ basename[chopoff] = '\0';
+#else
+ const char *basename = based_on;
+#endif
+
+ filename = strduplicate(output_dir);
+
+ if (subdir)
+ {
+ if (filename) filename = strappend(filename, "/", NULLCP);
+ filename = strappend(filename, subdir, NULLCP);
+ }
+
+ if (filename) filename = strappend(filename, "/", NULLCP);
+ filename = strappend(filename, basename,".",extension, NULLCP);
+
+#ifndef FLEXFILENAMES
+ free(basename);
+#endif
+ return filename;
+}
+
+/* determine the output page type from a declaration */
+enum Output_Object page_output_type(decl_spec, declarator)
+const DeclSpec *decl_spec;
+const Declarator *declarator;
+{
+ boolean is_static = decl_spec->flags & DS_STATIC;
+ return is_function_declarator(declarator)
+ ? (is_static ? OBJECT_STATIC_FUNCTION : OBJECT_FUNCTION)
+ : (is_static ? OBJECT_STATIC_VARIABLE : OBJECT_VARIABLE);
+}
+
+/* determine the extension/section from an output type */
+const char *page_manual_section(output_type)
+enum Output_Object output_type;
+{
+ return output_object[output_type].extension ?
+ output_object[output_type].extension : manual_section;
+}
+
+/* remove an existing file, if it exists & we have write permission to it */
+int remove_old_file(name)
+const char *name;
+{
+#ifdef HAS_ACCESS
+ /* check that we have write premission before blasting it */
+ if (access(name,W_OK) == -1)
+ {
+ if (errno != ENOENT)
+ {
+ my_perror("can't access output file", name);
+ return FALSE;
+ }
+ }
+ else
+#endif
+ {
+ /* if it exists, blast it */
+ if (unlink(name) == -1 && errno != ENOENT)
+ {
+ my_perror("error unlinking old link file", name);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/* output all the manual pages in a list */
+void output_manual_pages(first, input_files, link_type)
+ ManualPage *first;
+ int input_files; /* number of different input files */
+ enum LinkType link_type; /* how grouped pages will be linked */
+{
+ ManualPage *page;
+ int tostdout = output_dir && !strcmp(output_dir,"-");
+
+ char *filename = NULL;
+
+ /* output each page, in turn */
+ for (page = first; page; page = page->next)
+ {
+ char *input_file_base = NULL;
+ enum Output_Object output_type =
+ page_output_type(page->decl_spec, page->declarator);
+
+ /* the manual name is used as the output file extension, and also in
+ * the nroff output header.
+ */
+ const char *section = page_manual_section(output_type);
+
+ /* work out the base name of the file this was generated from */
+ if (page->sourcefile)
+ {
+ const char *base = strrchr(firstpage->sourcefile, '/');
+ const char *last;
+
+ /* use the file name as the manual page title */
+ if (base == NULL)
+ base = firstpage->sourcefile;
+ else
+ base++;
+ last = strrchr(base, '.');
+ if (last == NULL)
+ last = base + strlen(base);
+
+ input_file_base = alloc_string(base, last);
+ }
+
+ if (!tostdout)
+ {
+ safe_free(filename); /* free previous, if any */
+ filename = page_file_name(
+ use_input_name && input_file_base
+ ? input_file_base : page->declarator->name,
+ output_type, section);
+ fprintf(stderr,"generating: %s\n",filename);
+
+ /* a previous run may have left links, so nuke old file first */
+ if (!remove_old_file(filename)) exit(1);
+
+ if (freopen(filename, "w", stdout) == NULL)
+ {
+ my_perror("error opening output file", filename);
+ free(filename);
+ exit(1);
+ }
+ }
+
+ /* do the page itself */
+ output_manpage(first, page, input_files,
+ group_together && input_file_base ? input_file_base
+ : page->declarator->name,
+ group_together ? manual_section : section);
+
+ safe_free(input_file_base);
+
+ /* don't continue if grouped, because all info went into this page */
+ if (group_together) break;
+
+ if (tostdout && page->next) output->character('\f');
+ }
+
+ /* close the last output file if there was one */
+ if (!tostdout && fclose(stdout) == EOF)
+ {
+ my_perror("error linking closing file", filename);
+ exit(1);
+ }
+
+ /* if pages are grouped, just link the rest to the first */
+ if (group_together && !tostdout && link_type != LINK_NONE)
+ {
+ for (page=use_input_name && first->sourcefile ? first : first->next;
+ page; page = page->next)
+ {
+ enum Output_Object output_type =
+ page_output_type(page->decl_spec, page->declarator);
+ const char *extension = page_manual_section(output_type);
+ char *linkname = page_file_name(page->declarator->name,
+ output_type, extension);
+ int result = 0;
+
+ /* we may have a function with the same name as the sourcefile */
+ if (!strcmp(filename, linkname))
+ {
+ free(linkname);
+ continue;
+ }
+
+ fprintf(stderr,"%s: %s\n",
+ link_type == LINK_REMOVE ? "removing" : "linking", linkname);
+
+ /* always nuke old output file, since it may be linked to the one
+ * we've just generated, so LINK_FILE may trash it.
+ */
+ if (!remove_old_file(linkname)) exit(1);
+
+ switch(link_type)
+ {
+#ifdef HAS_LINK
+ case LINK_HARD:
+ result = link(filename, linkname);
+ break;
+#endif
+#ifdef HAS_SYMLINK
+ case LINK_SOFT:
+ result = symlink(filename, linkname);
+ break;
+#endif
+ case LINK_FILE:
+ if (freopen(linkname, "w", stdout) == NULL)
+ {
+ result = -1;
+ break;
+ }
+ output_warning();
+ output->include(filename);
+ if (fclose(stdout) == EOF)
+ result = -1;
+ break;
+ case LINK_NONE:
+ case LINK_REMOVE:
+ break;
+ }
+
+ /* check it went OK */
+ if (result == -1)
+ {
+ my_perror("error linking output file", linkname);
+ exit(1);
+ }
+ free(linkname);
+ }
+ }
+
+ safe_free(filename);
+}
diff --git a/manpage.h b/manpage.h
new file mode 100644
index 0000000..8fdcb09
--- /dev/null
+++ b/manpage.h
@@ -0,0 +1,64 @@
+/* $Id: manpage.h,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ * stuff to do with manual page outputing
+ */
+#ifndef MANPAGE_H
+#define MANPAGE_H
+
+#include "c2man.h"
+
+typedef struct Section Section;
+struct Section
+{
+ Section *next;
+ char *name;
+ char *text;
+ boolean been_output;
+};
+
+typedef struct ManualPage ManualPage;
+struct ManualPage
+{
+ DeclSpec *decl_spec;
+ Declarator *declarator;
+ ManualPage *next;
+ Section *first_section;
+ char *description;
+ char *returns;
+ char *sourcefile;
+ Time_t sourcetime;
+};
+
+enum LinkType
+{
+#ifdef HAS_LINK
+ LINK_HARD, /* filesystem hard link */
+#endif
+#ifdef HAS_SYMLINK
+ LINK_SOFT, /* filesystem soft link */
+#endif
+ LINK_FILE, /* nroff file with .so directive */
+ LINK_NONE, /* don't create extra links for it */
+ LINK_REMOVE /* don't create extra links & remove existing ones */
+};
+
+/* list of manual pages */
+extern ManualPage *firstpage;
+
+void
+new_manual_page _((char *comment, DeclSpec *decl_spec, Declarator *declarator));
+
+/* remember the terse description from the first comment in a file */
+void remember_terse _((char *comment));
+
+void output_manual_pages _((ManualPage *first, int num_input_files,
+ enum LinkType link_type));
+
+void free_manual_pages _((ManualPage *first));
+
+void output_format_string _((const char *fmt));
+
+void output_warning _((void));
+
+void output_comment _((const char *comment));
+
+#endif
diff --git a/nroff.c b/nroff.c
new file mode 100644
index 0000000..174d8b4
--- /dev/null
+++ b/nroff.c
@@ -0,0 +1,424 @@
+/* $Id: nroff.c,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ * functions for nroff style output.
+ */
+#include "c2man.h"
+#include "manpage.h"
+#include "output.h"
+#include "semantic.h"
+#include <ctype.h>
+
+void nroff_text(text)
+const char *text;
+{
+ put_string(text);
+}
+
+void nroff_char(c)
+const int c;
+{
+ putchar(c);
+}
+
+void nroff_comment() { put_string(".\\\" "); }
+
+void nroff_header(firstpage, input_files, grouped, name, terse, section)
+ManualPage *firstpage;
+int input_files;
+boolean grouped;
+const char *name;
+const char *terse;
+const char *section;
+{
+#ifdef HAS_STRFTIME
+ char month[20];
+#else
+ char *month;
+ static char *month_list[] =
+ { "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December" };
+#endif
+ Time_t raw_time;
+ struct tm *filetime;
+
+ if (make_embeddable) return;
+
+ output_warning();
+ put_string(".TH \"");
+
+ /* if lots of files contributed, use the current time; otherwise use the
+ * time of the source file they came from.
+ */
+ raw_time = (grouped && input_files > 1) ? time((Time_t *)NULL)
+ : firstpage->sourcetime;
+
+ filetime = localtime(&raw_time);
+
+#ifdef HAS_STRFTIME
+ /* generate the date format string */
+ strftime(month, sizeof month,"%B",filetime);
+#else
+ month = month_list[filetime->tm_mon];
+#endif
+
+ nroff_text(name);
+
+ printf("\" %s \"%d %s %d\"",
+ section,filetime->tm_mday,month,filetime->tm_year+1900);
+
+/* I have conflicting info about how the .TH macro works.... */
+#ifdef HENRYS_TH /* As per Henry Spencer's "How to write a manual page" */
+ if (manual_name) printf(" \"%s\"", manual_name);
+ put_string("\n.BY");
+#endif
+ printf(" \"%s",progname);
+ if ((input_files <= 1 || !grouped) && firstpage->sourcefile)
+ {
+ const char *basename = strrchr(firstpage->sourcefile, '/');
+ if (basename == NULL)
+ basename = firstpage->sourcefile;
+ else
+ basename++;
+ printf(" %s", basename);
+ }
+#ifndef HENRYS_TH
+ if (manual_name) printf("\" \"%s", manual_name);
+#endif
+ put_string("\"\n");
+
+#ifdef NeXT
+ /* define our own .SS on packages (such as NeXT's) where it doesn't move
+ * left a little. Sorry, awf doesn't support .SS.
+ */
+ put_string(".de SS\n.}X .25i \"\" \"\"\n.nr )E 2\n");
+ put_string("\\&\\\\$1\n.br\n..\n");
+#endif
+}
+
+void nroff_dash() { put_string("\\-"); }
+
+void nroff_section(name)
+const char *name;
+{
+ put_string(".SH \"");
+ nroff_text(name);
+ put_string("\"\n");
+}
+
+void nroff_sub_section(name)
+const char *name;
+{
+ put_string(".SS \"");
+ nroff_text(name);
+ put_string("\"\n");
+}
+
+void nroff_break_line() { put_string(".br\n"); }
+void nroff_blank_line() { put_string(".sp\n"); }
+
+void nroff_code_start() { put_string(".ft B\n"); }
+void nroff_code_end() { put_string(".ft R\n"); }
+
+void nroff_code(text)
+const char *text;
+{
+ put_string("\\fB");
+ nroff_text(text);
+ put_string("\\fR");
+}
+
+void nroff_tag_entry_start() { put_string(".TP\n.B \""); }
+void nroff_tag_entry_start_extra() { put_string(".TP\n.BR \""); }
+void nroff_tag_entry_end() { put_string("\"\n"); }
+void nroff_tag_entry_end_extra(text)
+const char *text;
+{
+ put_string("\" \"\t(");
+ nroff_text(text);
+ put_string(")\"\n");
+}
+
+void nroff_table_start(longestag)
+const char *longestag;
+{
+ void nroff_list_start();
+ nroff_list_start();
+
+ /* We measure the length of the longest tag in the table by changing to the
+ * code font, taking it's width with \w'string' and adding a little for
+ * the space between the tag and description. This gets stored in the TL
+ * number register, where the nroff_table_entry can find it.
+ * This isn't foolproof, because a shorter tag may be longer if it contains
+ * wider characters, but the extra space gives a little head room anyway.
+ */
+ nroff_code_start();
+ printf(".nr TL \\w'%s'u+0.2i\n", longestag);
+ nroff_code_end();
+}
+
+void nroff_table_entry(name, description)
+const char *name;
+const char *description;
+{
+ put_string(".TP \\n(TLu\n");
+
+ nroff_code(name);
+ nroff_char('\n');
+ if (description)
+ output_comment(description);
+ else
+ nroff_char('\n');
+}
+
+void nroff_table_end() { put_string(".RE\n.PD\n"); }
+
+void nroff_indent() { put_string(".IP\n"); }
+
+void nroff_list_start() { put_string(".RS 0.75in\n.PD 0\n"); }
+
+void nroff_list_entry(name)
+const char *name;
+{
+ nroff_code(name);
+}
+
+void nroff_list_separator() { put_string(",\n"); }
+void nroff_list_end() { nroff_char('\n'); nroff_table_end(); }
+
+void nroff_include(filename)
+const char *filename;
+{
+ printf(".so %s\n", filename);
+}
+
+void nroff_name(name)
+const char *name;
+{
+ if (name) nroff_text(name);
+ else nroff_section("NAME");
+}
+
+void nroff_terse_sep()
+{
+ nroff_char(' ');
+ nroff_dash();
+ nroff_char(' ');
+}
+
+void nroff_emphasized(text)
+const char *text;
+{
+ put_string("\\fI");
+ nroff_text(text);
+ put_string("\\fR");
+}
+
+void nroff_reference(text)
+const char *text;
+{
+ nroff_text(text);
+ nroff_char('(');
+ nroff_text(manual_section);
+ nroff_char(')');
+}
+
+void nroff_description(text)
+const char *text;
+{
+ enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
+ boolean new_line = TRUE;
+ boolean dot_command = FALSE;
+
+ /* correct punctuation a bit as it goes out */
+ for (;*text;text++)
+ {
+ int c = *text;
+
+ if (dot_command)
+ {
+ if (c == '\n') dot_command = FALSE;
+ }
+ else if (new_line && c == '.')
+ dot_command = TRUE;
+ else if (new_line && (c == '-' || c == '*' || is_numbered(text)))
+ {
+ output->break_line();
+ state = CAPITALISE;
+ }
+ else if (c == '.')
+ state = PERIOD;
+ else if (isspace(c) && state == PERIOD)
+ state = CAPITALISE;
+ else if (isalnum(c))
+ {
+ if (islower(c) && state == CAPITALISE) c = toupper(c);
+ state = TEXT;
+ }
+
+ output->character(c);
+ new_line = c == '\n';
+ }
+
+ /* do a full stop if there wasn't one */
+ if (!dot_command && state == TEXT) output->character('.');
+}
+
+void
+nroff_returns(comment)
+const char *comment;
+{
+ enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
+ char lastchar = '\n';
+ boolean tag_list_started = FALSE;
+
+ /* for each line... */
+ while (*comment)
+ {
+ boolean tagged = FALSE;
+
+ /* explicitly reject dot commands */
+ if (*comment && *comment != '.')
+ {
+ const char *c = comment;
+
+ /* search along until the end of a word */
+ while (*c && *c != ':' && !isspace(*c))
+ c++;
+
+ /* skip all spaces or tabs after the first word */
+ while (*c && *c != '\n')
+ {
+ if (*c == '\t' || *c == ':')
+ {
+ tagged = TRUE;
+ break;
+ }
+ else if (!isspace(*c))
+ break;
+
+ c++;
+ }
+ }
+
+ /* is it tagged?; explicitly reject dot commands */
+ if (tagged)
+ {
+ /* output lingering newline if necessary */
+ if (lastchar != '\n')
+ {
+ if (state == TEXT && !ispunct(lastchar)) output->character('.');
+ output->character(lastchar = '\n');
+ }
+
+ if (!tag_list_started)
+ {
+ output->tag_list_start();
+ tag_list_started = TRUE;
+ }
+
+ /* output the taggy bit */
+ output->tag_entry_start();
+ while (*comment && *comment != ':' && !isspace(*comment))
+ output->character(*comment++);
+ output->tag_entry_end();
+
+ /* skip any extra tabs or spaces */
+ while (*comment == ':' || (isspace(*comment) && *comment != '\n'))
+ comment++;
+
+ state = CAPITALISE;
+ }
+
+ /* terminate the previous line if necessary */
+ if (lastchar != '\n') output->character(lastchar = '\n');
+
+ /* dot commands go out unaltered */
+ if (*comment == '.')
+ {
+ for (;*comment && *comment != '\n'; comment++)
+ output->character(*comment);
+ output->character('\n');
+ }
+ else
+ {
+ /* correct punctuation a bit as the line goes out */
+ for (;*comment && *comment != '\n'; comment++)
+ {
+ char c = *comment;
+
+ if (c == '.')
+ state = PERIOD;
+ else if (isspace(c) && state == PERIOD)
+ state = CAPITALISE;
+ else if (isalnum(c))
+ {
+ if (islower(c) && state == CAPITALISE && fixup_comments)
+ c = toupper(c);
+ state = TEXT;
+ }
+
+ output->character(lastchar = c);
+ }
+
+ /* if it ended in punctuation, just output the nl straight away. */
+ if (ispunct(lastchar))
+ {
+ if (lastchar == '.') state = CAPITALISE;
+ output->character(lastchar = '\n');
+ }
+ }
+
+ if (*comment) comment++;
+ }
+
+ /* output lingering newline if necessary */
+ if (lastchar != '\n')
+ {
+ if (state == TEXT && !ispunct(lastchar) && fixup_comments)
+ output->character('.');
+ output->character('\n');
+ }
+
+ if (tag_list_started)
+ output->tag_list_end();
+}
+
+
+struct Output nroff_output =
+{
+ nroff_comment,
+ nroff_header,
+ nroff_dash,
+ nroff_section,
+ nroff_sub_section,
+ nroff_break_line,
+ nroff_blank_line,
+ nroff_code_start,
+ nroff_code_end,
+ nroff_code,
+ dummy, /* nroff_tag_list_start */
+ dummy, /* nroff_tag_list_end */
+ nroff_tag_entry_start,
+ nroff_tag_entry_start_extra,
+ nroff_tag_entry_end,
+ nroff_tag_entry_end_extra,
+ nroff_table_start,
+ nroff_table_entry,
+ nroff_table_end,
+ nroff_indent,
+ nroff_list_start,
+ nroff_code, /* nroff_list_entry */
+ nroff_list_separator,
+ nroff_list_end,
+ nroff_include,
+ dummy, /* nroff_file_end */
+ nroff_text,
+ nroff_char,
+ NULL, /* nroff_parse_option */
+ dummy, /* nroff_print_options */
+ nroff_name,
+ nroff_terse_sep,
+ nroff_reference,
+ nroff_emphasized,
+ nroff_description,
+ nroff_returns
+};
diff --git a/output.h b/output.h
new file mode 100644
index 0000000..a968401
--- /dev/null
+++ b/output.h
@@ -0,0 +1,149 @@
+/* $Id: output.h,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ * format-independant output interface.
+ */
+#ifndef OUTPUT_H
+#define OUTPUT_H
+
+/* To add a new output format:
+ * 1. Add the new -Tx suboption to the manual page.
+ * 2. Add handling for the new suboption to c2man.c, including the default
+ * output file extension.
+ * 3. Copy nroff.c to xxx.c and change the xxx_... output functions and the
+ * pointers in the xxx_output structure so the new xxx_output object
+ * generates the correct output constructs. Try to do this without modifying
+ * manpage.c if possible; add new output functions only if necessary.
+ * 4. Add the new xxx_output structure to the declaration of output structures
+ * at the end of this file.
+ */
+
+/* Output object defines what type of output is being generated.
+ * This contains pointers to functions that generate each type of output
+ * construct.
+ */
+struct Output
+{
+ /* comment until the end of the line */
+ void (*comment) _((void));
+
+ /* header and introduction to the file */
+ void (*header) _((ManualPage *firstpage, int input_files, boolean grouped,
+ const char *name, const char *terse, const char *section));
+
+ /* a dash */
+ void (*dash) _((void));
+
+ /* start of a main section */
+ void (*section) _((const char *name));
+
+ /* start of a sub section */
+ void (*sub_section) _((const char * name));
+
+ /* break the current line here */
+ void (*break_line) _((void));
+
+ /* a blank line */
+ void (*blank_line) _((void));
+
+ /* switch into the mode to include declarations like in program code */
+ void (*code_start) _((void));
+
+ /* switch back from code mode to normal */
+ void (*code_end) _((void));
+
+ /* output a single string in code font */
+ void (*code) _((const char *text));
+
+ /* start a list of tagged paragraphs */
+ void (*tag_list_start) _((void));
+
+ /* end a list of tagged paragraph */
+ void (*tag_list_end) _((void));
+
+ /* start a tagged paragraph: the tag should go straight after this */
+ void (*tag_entry_start) _((void));
+
+ /* start a tagged paragraph that has an extra non-code bit at the end
+ * of the tag: the tag should go straight after this
+ */
+ void (*tag_entry_start_extra) _((void));
+
+ /* end the tag on a tagged paragraph */
+ void (*tag_entry_end) _((void));
+
+ /* end the tag on a tagged paragraph with an extra non-code bit at the end
+ * of the tag.
+ */
+ void (*tag_entry_end_extra) _((const char *text));
+
+ /* start a name/value pair table */
+ void (*table_start) _((const char *longestag));
+
+ /* an entry in the name/value pair table */
+ void (*table_entry) _((const char *name, const char * description));
+
+ /* end the name/value pair table */
+ void (*table_end) _((void));
+
+ /* an indented paragraph */
+ void (*indent) _((void));
+
+ /* start a list */
+ void (*list_start) _((void));
+
+ /* an entry in the list */
+ void (*list_entry) _((const char *name));
+
+ /* the seperator between one entry in a list and the next */
+ void (*list_separator) _((void));
+
+ /* end the list */
+ void (*list_end) _((void));
+
+ /* include another file in the output */
+ void (*include) _((const char *filename));
+
+ /* end the file */
+ void (*file_end) _((void));
+
+ /* output string, quoted to protect against formatter controls */
+ void (*text) _((const char *text));
+
+ /* output char, quoted to protect against formatter controls */
+ void (*character) _((const int c));
+
+ /* parse formatter specific option. set to NULL if not available */
+ int (*parse_option) _((const char *option));
+
+ /* print formatter specific options to stderr. */
+ void (*print_options) _((void));
+
+ /* output NAME section header and section names */
+ void (*name) _((const char *name));
+
+ /* output separators between section name and terse description */
+ void (*terse_sep) _((void));
+
+ /* output string, making it a hypertext reference */
+ void (*reference) _((const char *text));
+
+ /* output string, displaying it emphasized (usually italic) */
+ void (*emphasized) _((const char *text));
+
+ /* output description, fixing punctuation but leaving formatter commands */
+ void (*description) _((const char *text));
+
+ /* output returns text, fixing punct. but leaving formatter commands */
+ void (*returns) _((const char *text));
+};
+
+/* pointer to the relevant output structure */
+extern struct Output *output;
+
+/* output structures for all formats we support */
+extern struct Output nroff_output, texinfo_output, latex_output, html_output,
+ autodoc_output;
+
+/* dummy routine which does nothing */
+void dummy _((void));
+
+#endif
diff --git a/patchlevel.h b/patchlevel.h
new file mode 100644
index 0000000..2d23afc
--- /dev/null
+++ b/patchlevel.h
@@ -0,0 +1,2 @@
+#define VERSION 2
+#define PATCHLEVEL 41
diff --git a/semantic.c b/semantic.c
new file mode 100644
index 0000000..1dac9b5
--- /dev/null
+++ b/semantic.c
@@ -0,0 +1,732 @@
+/* $Id: semantic.c,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ *
+ * C manual page generator
+ * These routines implement the semantic actions executed by the yacc parser.
+ */
+#include "c2man.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include "semantic.h"
+#include "enum.h"
+#include "manpage.h"
+#include "strconcat.h"
+#include "output.h"
+
+/* Return TRUE if the given identifier is really a typedef name.
+ * Search the symbol table for the identifier.
+ */
+boolean
+is_typedef_name (name)
+char *name;
+{
+ return (boolean)(find_symbol(typedef_names, name) != NULL);
+}
+
+/* Initialize a new declaration specifier part.
+ */
+void
+new_decl_spec (decl_spec, text, flags)
+DeclSpec *decl_spec;
+char *text;
+int flags;
+{
+ decl_spec->text = text ? strduplicate(text) : NULL;
+ decl_spec->flags = flags;
+ decl_spec->enum_list = NULL;
+}
+
+/* Free storage used by a declaration specifier part.
+ */
+void
+free_decl_spec (decl_spec)
+DeclSpec *decl_spec;
+{
+ safe_free(decl_spec->text); /* could be an ellipsis you know */
+}
+
+/* Initialize a new declaration specifier part, including an enum part.
+ */
+void
+new_enum_decl_spec (decl_spec, text, flags, enum_list)
+DeclSpec *decl_spec;
+char *text;
+int flags;
+EnumeratorList *enum_list;
+{
+ decl_spec->text = text;
+ decl_spec->flags = flags;
+ decl_spec->enum_list = enum_list;
+}
+
+/* Initialize a new declaration specifier part, but don't strdup the text. */
+void
+dyn_decl_spec (decl_spec, text, flags)
+DeclSpec *decl_spec;
+char *text;
+unsigned int flags;
+{
+ decl_spec->text = text;
+ decl_spec->flags = flags;
+ decl_spec->enum_list = NULL;
+}
+
+/* Append two declaration specifier parts together.
+ */
+void
+join_decl_specs (result, a, b)
+DeclSpec *result, *a, *b;
+{
+ if (a->text)
+ {
+ if (b->text)
+ {
+ result->text = strconcat(a->text, " ", b->text, NULLCP);
+ free(a->text);
+ free(b->text);
+ }
+ else
+ result->text = a->text;
+ }
+ else
+ result->text = b->text;
+
+ result->flags = a->flags | b->flags;
+
+ /* only one of the decl specs should have an enum list! */
+ result->enum_list = a->enum_list ? a->enum_list : b->enum_list;
+}
+
+/* Allocate and initialize a declarator. */
+Declarator *
+new_declarator (text, name)
+char *name, *text;
+{
+ Declarator *d;
+
+ d = (Declarator *)safe_malloc(sizeof(Declarator));
+ d->text = text;
+ d->name = name;
+ d->type = DECL_SIMPLE;
+ d->comment = NULL;
+ d->retcomment = NULL;
+ new_ident_list(&d->params);
+ d->head = d;
+ d->func_stack = NULL;
+ return d;
+}
+
+/* Free storage used by a declarator.
+ */
+void
+free_declarator (d)
+Declarator *d;
+{
+#ifdef DEBUG
+ fprintf(stderr,"free_declarator: decl = %lx, name = %s, text = %s\n",
+ (long)d, d->name?d->name:"NULL", d->text?d->text:"NULL");
+#endif
+ safe_free(d->name); /* could be an ellipsis (ie: no name) */
+ safe_free(d->text); /* ellipsis is marked by no text too */
+ safe_free(d->comment);
+ safe_free(d->retcomment);
+ free_param_list(&(d->params));
+ if (d->func_stack != NULL)
+ free_declarator(d->func_stack);
+ free(d);
+}
+
+/* add a comment to the last declarator in the list */
+int
+comment_last_decl(list, comment)
+DeclaratorList *list;
+char *comment;
+{
+ if (list->last->comment)
+ {
+ declarator_error(list->last);
+ free(comment);
+ return 0;
+ }
+ else
+ list->last->comment = comment;
+ return 1;
+}
+
+/* Initialize a declarator list and add the given declarator to it.
+ */
+void
+new_decl_list (decl_list, declarator)
+DeclaratorList *decl_list;
+Declarator *declarator;
+{
+ decl_list->first = decl_list->last = declarator;
+ declarator->next = NULL;
+}
+
+/* Free storage used by the declarators in the declarator list.
+ */
+void
+free_decl_list (decl_list)
+DeclaratorList *decl_list;
+{
+ Declarator *d, *next;
+#ifdef DEBUG
+ fprintf(stderr,"free_decl_list: decl_list = %lx, first = %lx\n",
+ (long)decl_list, (long)decl_list->first);
+#endif
+ d = decl_list->first;
+ while (d != NULL) {
+ next = d->next;
+ free_declarator(d);
+ d = next;
+ }
+}
+
+/* Add the declarator to the declarator list.
+ */
+void
+add_decl_list (to, from, declarator)
+DeclaratorList *to, *from;
+Declarator *declarator;
+{
+ to->first = from->first;
+ from->last->next = declarator;
+ to->last = declarator;
+ to->last->next = NULL;
+}
+
+/* Initialize the parameter structure.
+ */
+void
+new_parameter (param, decl_spec, declarator, comment_before, comment_after)
+Parameter *param; /* pointer to structure to be initialized */
+DeclSpec *decl_spec; /* declaration specifier structure */
+Declarator *declarator; /* declarator structure */
+char *comment_before; /* comment before the param */
+char *comment_after; /* comment after the param */
+{
+
+ if (decl_spec == NULL) {
+ new_decl_spec(&(param->decl_spec), NULLCP, DS_JUNK);
+ } else {
+ param->decl_spec = *decl_spec;
+ }
+
+ if (declarator == NULL) {
+ declarator = new_declarator(NULLCP, NULLCP);
+ }
+ param->declarator = declarator;
+
+ if (comment_before && comment_after)
+ {
+ parameter_error(param);
+ free(comment_after); /* comment_before will go in Parameter */
+ }
+
+ param->declarator->comment =
+ comment_before ? comment_before : comment_after;
+ param->suppress = FALSE;
+ param->duplicate = FALSE;
+}
+
+/* Free the storage used by the parameter.
+ */
+void
+free_parameter (param)
+Parameter *param;
+{
+ free_decl_spec(&(param->decl_spec));
+ free_declarator(param->declarator);
+}
+
+/* add a comment to the last parameter in the list */
+int
+comment_last_parameter(list, comment)
+ParameterList *list;
+char *comment;
+{
+ if (list->last == NULL)
+ {
+ yyerror("comment '%s' applies to non-existent parameter", comment);
+ free(comment);
+ return 0;
+ }
+
+ if (list->last->declarator->comment)
+ {
+ parameter_error(list->last);
+ free(comment);
+ return 0;
+ }
+ else
+ list->last->declarator->comment = comment;
+ return 1;
+}
+
+/* Initialize a list of function parameters.
+ */
+void
+new_param_list (param_list, param)
+ParameterList *param_list;
+Parameter *param;
+{
+ Parameter *p;
+
+ p = (Parameter *)safe_malloc((unsigned)sizeof(Parameter));
+ *p = *param;
+
+ param_list->first = param_list->last = p;
+ p->next = NULL;
+}
+
+/* Free storage used by the elements in the function parameter list.
+ */
+void
+free_param_list (param_list)
+ParameterList *param_list;
+{
+ Parameter *p, *next;
+
+ p = param_list->first;
+ while (p != NULL) {
+ next = p->next;
+ free_parameter(p);
+ free(p);
+ p = next;
+ }
+}
+
+/* Add the function parameter declaration to the list.
+ */
+void
+add_param_list (to, from, param)
+ParameterList *to, *from;
+Parameter *param;
+{
+ Parameter *p;
+
+ p = (Parameter *)safe_malloc((unsigned)sizeof(Parameter));
+ *p = *param;
+
+ to->first = from->first;
+ from->last->next = p;
+ to->last = p;
+ p->next = NULL;
+}
+
+/* Initialize an empty list of function parameter names.
+ */
+void
+new_ident_list (param_list)
+ParameterList *param_list;
+{
+ param_list->first = param_list->last = NULL;
+}
+
+/* Add an item to the list of function parameter declarations but set only
+ * the parameter name field and the comments.
+ */
+void
+add_ident_list (to, from, ident)
+ParameterList *to, *from;
+Identifier *ident;
+{
+ Parameter *p;
+ Declarator *declarator;
+
+ p = (Parameter *)safe_malloc(sizeof(Parameter));
+ declarator = new_declarator(ident->name, strduplicate(ident->name));
+ new_parameter(p, (DeclSpec *)NULL, declarator, ident->comment_before,
+ ident->comment_after);
+
+ to->first = from->first;
+ if (to->first == NULL) {
+ to->first = p;
+ } else {
+ from->last->next = p;
+ }
+ to->last = p;
+ p->next = NULL;
+}
+
+/* Search the list of parameters for a matching parameter name.
+ * Return a pointer to the matching parameter or NULL if not found.
+ */
+static Parameter *
+search_parameter_list (params, name)
+ParameterList *params;
+char *name;
+{
+ Parameter *p;
+
+ for (p = params->first; p != NULL; p = p->next) {
+ if (p->declarator->name && strcmp(p->declarator->name, name) == 0)
+ return p;
+ }
+ return (Parameter *)NULL;
+}
+
+/* This routine is called to generate function prototypes from traditional
+ * style function definitions. For each parameter name in the declarator
+ * list, find the matching parameter name in the parameter list and set
+ * that parameter's declaration specifier.
+ * This is also where we promote formal parameters. Parameters of type
+ * "char", "unsigned char", "short", or "unsigned short" get promoted to
+ * "int". Parameters of type "float" are promoted to "double".
+ */
+void
+set_param_types (params, decl_spec, declarators, comment, eolcomment)
+ParameterList *params;
+DeclSpec *decl_spec;
+DeclaratorList *declarators;
+char *comment;
+char *eolcomment;
+{
+ Declarator *d;
+ Parameter *p;
+
+ if (comment && eolcomment)
+ {
+ yyerror("parameter declaration has multiple comments");
+ return;
+ }
+
+ if (!comment) comment = eolcomment;
+
+ for (d = declarators->first; d != NULL; d = d->next) {
+ /* Search the parameter list for a matching name. */
+ if ((p = search_parameter_list(params, d->name)) == NULL) {
+ output_error();
+ fprintf(stderr, "declared argument \"%s\" is missing\n", d->name);
+ } else {
+ char *decl_spec_text = decl_spec->text;
+ if (promote_param && strcmp(d->text, d->name) == 0) {
+ if (decl_spec->flags & (DS_CHAR | DS_SHORT))
+ decl_spec_text = "int";
+ else if (decl_spec->flags & DS_FLOAT)
+ decl_spec_text = "double";
+ }
+ safe_free(p->decl_spec.text); /* there shouldn't be one, but...*/
+ p->decl_spec.text = strduplicate(decl_spec_text);
+ if (p->decl_spec.flags != decl_spec->flags)
+ {
+ if (p->decl_spec.flags & DS_JUNK)
+ p->decl_spec.flags = decl_spec->flags;
+ else
+ parameter_error(p);
+ }
+ if (p->decl_spec.enum_list != decl_spec->enum_list)
+ {
+ if (p->decl_spec.enum_list == NULL)
+ p->decl_spec.enum_list = decl_spec->enum_list;
+ else
+ parameter_error(p);
+ }
+
+ free_declarator(p->declarator);
+ p->declarator = d;
+
+ if (comment)
+ {
+ if (p->declarator->comment)
+ parameter_error(p);
+ else
+ p->declarator->comment = strduplicate(comment);
+ }
+ }
+ }
+
+ free_decl_spec(decl_spec);
+ safe_free(comment);
+}
+
+/* Output a declaration specifier for an external declaration.
+ */
+void
+output_decl_spec (decl_spec)
+DeclSpec *decl_spec;
+{
+ output->text(decl_spec->text);
+}
+
+static void
+output_parameters _((Declarator *d, boolean format));
+
+/* does a function have any parameters?
+ * This accounts for both fn() and fn(void)
+ */
+boolean has_parameters(d)
+const Declarator *d;
+{
+ Parameter *first = d->head->params.first;
+
+ return (first != NULL &&
+ (first->declarator->text != NULL ||
+ strcmp(first->decl_spec.text, "void")));
+}
+
+/* output a declarator name, stripping leading underscores if necessary */
+void output_decl_text(text, keep_underscores)
+char *text;
+boolean keep_underscores;
+{
+ if (!keep_underscores)
+ {
+ /* skip leading stuff before the actual name */
+ while (*text && *text != '_' && !isalnum(*text))
+ output->character(*text++);
+ while (text[0] == '_' && text[1]) text++;
+ }
+ output->text(text);
+}
+
+/* Output a function declarator.
+ */
+static void
+output_func_declarator (declarator, format)
+Declarator *declarator;
+boolean format;
+{
+ char *s, *t, *decl_text;
+
+ /* Output declarator text before function declarator place holder. */
+ if ((s = strstr(declarator->text, "%s")) == NULL)
+ return;
+ *s = '\0';
+ output->text(declarator->text);
+
+ /* Substitute place holder with function declarator. */
+ if (!is_function_declarator(declarator->func_stack)) {
+
+ decl_text = declarator->func_stack->text;
+ if (declarator->name == NULL || declarator->name[0] == '\0') {
+ output->text(decl_text);
+ } else {
+
+ /* Output the declarator text before the declarator name. */
+ if ((t = strstr(decl_text, declarator->name)) == NULL)
+ return;
+ *t = '\0';
+ output->text(decl_text);
+ *t = declarator->name[0];
+
+ if (format && strcmp(declarator_prefix, " ") != 0)
+ output_format_string(declarator_prefix);
+
+ /* Output the declarator name. */
+ output_decl_text(declarator->name, format);
+
+ /* Output the remaining declarator text. */
+ output->text(t + strlen(declarator->name));
+
+ /* Output the declarator suffix. */
+ if (format) output_format_string(declarator_suffix);
+ }
+ } else {
+ output_func_declarator(declarator->func_stack,format);
+ }
+ *s = '%';
+ s += 2;
+
+ /* Output declarator text up to but before parameters place holder. */
+ if ((t = strstr(s, "()")) == NULL)
+ return;
+ *t = '\0';
+ output->text(s);
+
+ /* Substitute place holder with function parameters. */
+ output->character(*t++ = '(');
+ output_parameters(declarator, format);
+ output->text(t);
+}
+
+/* Output a declarator.
+ */
+void
+output_declarator (d, format)
+Declarator *d;
+boolean format;
+{
+ if (d->func_stack) {
+ output_func_declarator(d, format);
+ } else {
+ output_decl_text(d->text, format);
+ }
+}
+
+/* Output a function parameter.
+ */
+void
+output_parameter (p)
+Parameter *p;
+{
+ if (p->decl_spec.text)
+ output->text(p->decl_spec.text);
+ else
+ /* Check for parameter names with no declaration specifiers. This
+ * happens when a parameter name appears in the identifier list of a
+ * function definition but does not appear in the parameter declaration
+ * part. The default type in this cause is "int".
+ */
+ if (p->declarator->text && strcmp(p->declarator->text, "...") != 0)
+ output->text("int ");
+
+ /* not all parameters must have declarators: might be a prototype */
+ if (p->declarator->text) {
+ if (p->decl_spec.text)
+ output->character(' ');
+ /* don't format parameters; keep it all on one line */
+ output_declarator(p->declarator, FALSE);
+ }
+}
+
+/* Output the list of function parameters.
+ */
+static void
+output_parameters (d, format)
+Declarator *d;
+boolean format;
+{
+ if (has_parameters(d)) {
+ Parameter *p = d->params.first;
+ if (format) output_format_string(first_param_prefix);
+ output_parameter(p);
+ p = p->next;
+ while (p != NULL) {
+ output->character(',');
+ if (format) output_format_string(middle_param_prefix);
+ output_parameter(p);
+ p = p->next;
+ }
+ if (format) output_format_string(last_param_suffix);
+ }
+ else
+ output->text("void");
+}
+
+/* remember variable and function declarations. */
+int
+remember_declarations (comment, decl_spec, decl_list, eolcomment)
+char *comment; /* comment before */
+DeclSpec *decl_spec; /* declaration specifier */
+DeclaratorList *decl_list; /* list of declared variables */
+char *eolcomment; /* eol comment after */
+{
+ Declarator *d, *next;
+ int ret = 1;
+
+ /* attach EOL comment to last one in list */
+ if (eolcomment)
+ {
+ Declarator *attach;
+
+ /* if it's a function, attach it to the last parameter */
+ if (is_function_declarator(decl_list->last) &&
+ decl_list->last->head->params.last)
+ attach = decl_list->last->head->params.last->declarator;
+ else
+ attach = decl_list->last;
+
+ if (attach->comment)
+ {
+ declarator_error(attach);
+ free(eolcomment);
+ ret = 0;
+ }
+ else
+ attach->comment = eolcomment;
+ }
+
+ /* special case of a single declarator handled efficiently */
+ if (decl_list->first && decl_list->first->next == NULL)
+ {
+ d = decl_list->first;
+ /* free the declarator comment if it isn't going to get used */
+ if (comment)
+ safe_free(d->comment);
+ else
+ comment = d->comment;
+
+ /* and nuke it from the declarator so free_declarator won't free it
+ * (since safe_free will do that) if new_manual_page decides to throw
+ * it away.
+ */
+ d->comment = NULL;
+
+ new_manual_page(comment, decl_spec, d);
+ }
+ else
+ {
+ for (d = decl_list->first; d != NULL; d = next)
+ {
+ DeclSpec spec_copy;
+ char *comment_copy;
+
+ next = d->next;
+#ifdef DEBUG
+ fprintf(stderr,
+ "remember_declarations: text=%s name=%s\ncomment: %s\n",
+ d->text,d->name, comment ? comment : "NULL");
+#endif
+ spec_copy = *decl_spec;
+ spec_copy.text = strduplicate(decl_spec->text);
+ comment_copy = d->comment ? d->comment :
+ (comment ? strduplicate(comment) : NULL);
+ d->comment = NULL;
+ new_manual_page(comment_copy, &spec_copy,d);
+ }
+
+ /* free 'em up */
+ free_decl_spec(decl_spec);
+ safe_free(comment);
+ }
+
+ return ret;
+}
+
+void parameter_error(param)
+Parameter *param;
+{
+ yyerror("parameter '%s' has multiple comments", param->declarator->name);
+}
+
+void declarator_error(decl)
+Declarator *decl;
+{
+ yyerror("declarator '%s' has multiple comments", decl->name);
+}
+
+/* is a declarator for a function? (as opposed to a variable) */
+boolean is_function_declarator(decl)
+const Declarator *decl;
+{
+ return decl->type == DECL_FUNCTION || decl->type == DECL_FUNCDEF;
+}
+
+/* is a comment a start of a numbered list item */
+boolean is_numbered(text)
+const char *text;
+{
+ char *next = NULL;
+
+ if (*text == '(') {
+ ++text;
+ errno = 0;
+ strtol(text, &next, 0);
+ if (errno)
+ return FALSE;
+ if (*next == ')')
+ return TRUE;
+ }
+ else {
+ errno = 0;
+ strtol(text, &next, 0);
+ if (errno)
+ return FALSE;
+ if (*next == '.' || *next == ')')
+ return TRUE;
+ }
+ return FALSE ;
+}
+
diff --git a/semantic.h b/semantic.h
new file mode 100644
index 0000000..6518dd4
--- /dev/null
+++ b/semantic.h
@@ -0,0 +1,121 @@
+/* $Id: semantic.h,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ *
+ * Declarations for semantic action routines
+ */
+#include "config.h"
+
+extern boolean is_typedef_name _((
+ char *name
+ ));
+void
+new_decl_spec _((
+DeclSpec *decl_spec,
+char *text,
+int flags));
+
+extern void join_decl_specs _((
+ DeclSpec *result,
+ DeclSpec *a,
+ DeclSpec *b
+ ));
+extern void free_decl_spec _((
+ DeclSpec *decl_spec
+ ));
+void
+new_parameter _((
+Parameter *param, /* pointer to structure to be initialized */
+DeclSpec *decl_spec, /* declaration specifier structure */
+Declarator *declarator, /* declarator structure */
+char *comment_before, /* comment before the param */
+char *comment_after)); /* comment after the param */
+
+extern void free_parameter _((
+ Parameter *param
+ ));
+
+/* add a comment to the last parameter in the list */
+int
+comment_last_parameter _((ParameterList *list, char *comment));
+
+extern void new_param_list _((
+ ParameterList *param_list,
+ Parameter *param
+ ));
+
+extern void add_param_list _((
+ ParameterList *to,
+ ParameterList *from,
+ Parameter *param
+ ));
+extern void free_param_list _((
+ ParameterList *param_list
+ ));
+extern void new_ident_list _((
+ ParameterList *param_list
+ ));
+extern void add_ident_list _((
+ ParameterList *to,
+ ParameterList *from,
+ Identifier *ident
+ ));
+extern Declarator * new_declarator _((
+ char *text,
+ char *name
+ ));
+extern void free_declarator _((
+ Declarator *d
+ ));
+extern void new_decl_list _((
+ DeclaratorList *decl_list,
+ Declarator *declarator
+ ));
+extern void add_decl_list _((
+ DeclaratorList *to,
+ DeclaratorList *from,
+ Declarator *declarator
+ ));
+extern void free_decl_list _((
+ DeclaratorList *decl_list
+ ));
+extern void set_param_types _((
+ ParameterList *params,
+ DeclSpec *decl_spec,
+ DeclaratorList *declarators,
+ char *comment,
+ char *eolcomment
+ ));
+
+/* Output a function parameter.*/
+void output_parameter _((Parameter *p));
+
+int
+remember_declarations _((
+char *comment, /* comment associated */
+DeclSpec *decl_spec, /* declaration specifier */
+DeclaratorList *decl_list, /* list of declared variables */
+char *eolcomment)); /* eol comment after */
+
+void
+dyn_decl_spec _((
+DeclSpec *decl_spec,
+char *text,
+unsigned int flags));
+
+void
+new_enum_decl_spec _((
+DeclSpec *decl_spec,
+char *text,
+int flags,
+EnumeratorList *enum_list));
+
+void
+output_decl_spec _((DeclSpec *decl_spec));
+
+void
+output_declarator _((Declarator *d, boolean format));
+
+void parameter_error _((Parameter *param));
+void declarator_error _((Declarator *decl));
+
+boolean has_parameters _((const Declarator *d));
+boolean is_function_declarator _((const Declarator *d));
diff --git a/strappend.c b/strappend.c
new file mode 100644
index 0000000..c8cc997
--- /dev/null
+++ b/strappend.c
@@ -0,0 +1,64 @@
+/* $Id: strappend.c,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ */
+#include "c2man.h"
+#include "strappend.h"
+
+#ifdef I_STDARG
+#include <stdarg.h>
+#endif
+#ifdef I_VARARGS
+#include <varargs.h>
+#endif
+
+extern void outmem();
+
+/*
+ * append a list of strings to another, storing them in a malloc'ed region.
+ * The first string may be NULL, in which case the rest are simply concatenated.
+ */
+#ifdef I_STDARG
+char *strappend(char *first, ...)
+#else
+char *strappend(va_alist)
+ va_dcl
+#endif
+{
+ size_t totallen;
+ va_list argp;
+ char *s, *retstring;
+#ifndef I_STDARG
+ char *first;
+#endif
+ /* add up the total length */
+#ifdef I_STDARG
+ va_start(argp,first);
+#else
+ va_start(argp);
+ first = va_arg(argp, char *);
+#endif
+ totallen = first ? strlen(first) : 0;
+ while ((s = va_arg(argp,char *)) != NULL)
+ totallen += strlen(s);
+ va_end(argp);
+
+ /* malloc the memory */
+ totallen++; /* add space for the nul terminator */
+ if ((retstring = first ? realloc(first,totallen) : malloc(totallen)) == 0)
+ outmem();
+
+ if (first == NULL) *retstring = '\0';
+
+#ifdef I_STDARG
+ va_start(argp,first);
+#else
+ va_start(argp);
+ first = va_arg(argp, char *); /* skip the first arg */
+#endif
+
+ while ((s = va_arg(argp,char *)) != NULL)
+ strcat(retstring,s);
+
+ va_end(argp);
+
+ return retstring;
+}
diff --git a/strappend.h b/strappend.h
new file mode 100644
index 0000000..585df68
--- /dev/null
+++ b/strappend.h
@@ -0,0 +1,6 @@
+/* $Id: strappend.h,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ * concatenate a list of strings, storing them in a malloc'ed region
+ */
+#include "config.h"
+
+char *strappend _V((char *first, ...));
diff --git a/strconcat.c b/strconcat.c
new file mode 100644
index 0000000..c9caff6
--- /dev/null
+++ b/strconcat.c
@@ -0,0 +1,74 @@
+/* $Id: strconcat.c,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ * concatenate a list of strings, storing them in a malloc'ed region
+ */
+#include "c2man.h"
+#include "strconcat.h"
+
+#ifdef I_STDARG
+#include <stdarg.h>
+#endif
+#ifdef I_VARARGS
+#include <varargs.h>
+#endif
+
+extern void outmem();
+
+#ifdef I_STDARG
+char *strconcat(const char *first, ...)
+#else
+char *strconcat(va_alist)
+ va_dcl
+#endif
+{
+ size_t totallen;
+ va_list argp;
+ char *s, *retstring;
+#ifndef I_STDARG
+ char *first;
+#endif
+ /* add up the total length */
+#ifdef I_STDARG
+ va_start(argp,first);
+#else
+ va_start(argp);
+ first = va_arg(argp, char *);
+#endif
+#ifdef DEBUG
+ fprintf(stderr,"strconcat: \"%s\"",first);
+#endif
+ totallen = strlen(first);
+ while ((s = va_arg(argp,char *)) != NULL)
+ {
+ totallen += strlen(s);
+#ifdef DEBUG
+ fprintf(stderr,",\"%s\"",s);
+#endif
+ }
+#ifdef DEBUG
+ fprintf(stderr,"\nstrlen = %ld\n",(long)totallen);
+#endif
+ va_end(argp);
+
+ /* malloc the memory */
+ if ((retstring = malloc(totallen + 1)) == 0)
+ outmem();
+
+#ifdef I_STDARG
+ va_start(argp,first);
+#else
+ va_start(argp);
+ first = va_arg(argp, char *);
+#endif
+ /* copy the stuff in */
+ strcpy(retstring,first);
+
+ while ((s = va_arg(argp,char *)) != NULL)
+ strcat(retstring,s);
+
+ va_end(argp);
+
+#ifdef DEBUG
+ fprintf(stderr,"strconcat returns \"%s\"\n",retstring);
+#endif
+ return retstring;
+}
diff --git a/strconcat.h b/strconcat.h
new file mode 100644
index 0000000..021d451
--- /dev/null
+++ b/strconcat.h
@@ -0,0 +1,6 @@
+/* $Id: strconcat.h,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ * concatenate a list of strings, storing them in a malloc'ed region
+ */
+#include "config.h"
+
+char *strconcat _V((const char *first, ...));
diff --git a/string.c b/string.c
new file mode 100644
index 0000000..5af082b
--- /dev/null
+++ b/string.c
@@ -0,0 +1,82 @@
+/* $Id: string.c,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ *
+ * Some string handling routines
+ */
+#include "c2man.h"
+#include <ctype.h>
+
+/* Copy the string into an allocated memory block.
+ * Return a pointer to the copy.
+ */
+char *
+strduplicate (s)
+const char *s; /* The string to copy. May be NULL */
+{
+ char *dest;
+
+ if (!s) return NULL;
+
+ if ((dest = malloc((unsigned)(strlen(s)+1))) == NULL)
+ outmem();
+
+ strcpy(dest, s);
+ return dest;
+}
+
+#ifndef HAS_STRSTR
+
+/* Return a pointer to the first occurence of the substring
+ * within the string, or NULL if not found.
+ */
+char *
+strstr (src, key)
+const char *src, *key;
+{
+ char *s;
+ int keylen;
+
+ keylen = strlen(key);
+ s = strchr(src, *key);
+ while (s != NULL) {
+ if (strncmp(s, key, keylen) == 0)
+ return s;
+ s = strchr(s+1, *key);
+ }
+ return NULL;
+}
+
+#endif
+
+/* compare two strings case insensitively, for up to n chars */
+int strncmpi(s1, s2, n)
+const char *s1, *s2;
+size_t n;
+{
+ while(n--)
+ {
+ char c1 = *s1, c2 = *s2;
+
+ if (c1 == '\0' && c2 == '\0') break;
+
+ if (isalpha(c1) && isupper(c1)) c1 = tolower(c1);
+ if (isalpha(c2) && isupper(c2)) c2 = tolower(c2);
+
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ s1++; s2++;
+ }
+ return 0;
+}
+
+/* convert string to upper case */
+char *strtoupper(in)
+char *in;
+{
+ char *s;
+
+ for (s = in; *s; s++)
+ {
+ if (islower(*s)) *s = toupper(*s);
+ }
+ return in;
+}
diff --git a/symbol.c b/symbol.c
new file mode 100644
index 0000000..85be039
--- /dev/null
+++ b/symbol.c
@@ -0,0 +1,119 @@
+/* $Id: symbol.c,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ *
+ * Symbol table maintenance. Implements an abstract data type called
+ * the symbol table.
+ */
+#include "c2man.h"
+#include "symbol.h"
+
+/* Create a symbol table.
+ * Return a pointer to the symbol table or NULL if an error occurs.
+ */
+SymbolTable *
+create_symbol_table ()
+{
+ SymbolTable *symtab;
+ int i;
+
+ symtab = (SymbolTable *)safe_malloc(sizeof(SymbolTable));
+
+ for (i = 0; i < SYM_MAX_HASH; ++i)
+ symtab->bucket[i] = NULL;
+
+ return symtab;
+}
+
+
+/* Free the memory allocated to the symbol table.
+ */
+void
+destroy_symbol_table (symtab)
+SymbolTable *symtab;
+{
+ int i;
+ Symbol *sym, *next;
+
+ for (i = 0; i < SYM_MAX_HASH; ++i) {
+ sym = symtab->bucket[i];
+ while (sym != NULL) {
+ next = sym->next;
+ free(sym->name);
+ free(sym);
+ sym = next;
+ }
+ }
+ free(symtab);
+}
+
+
+/* This is a simple hash function mapping a symbol name to a hash bucket. */
+
+static unsigned int
+hash (name)
+char *name;
+{
+ char *s;
+ unsigned int h;
+
+ h = 0;
+ s = name;
+ while (*s != '\0')
+ h = (h << 1) ^ *s++;
+ return h % SYM_MAX_HASH;
+}
+
+
+/* Search the list of symbols <list> for the symbol <name>.
+ * Return a pointer to the symbol or NULL if not found.
+ */
+static Symbol *
+search_symbol_list (list, name)
+Symbol *list;
+char *name;
+{
+ Symbol *sym;
+
+ for (sym = list; sym != NULL; sym = sym->next) {
+ if (strcmp(sym->name, name) == 0)
+ return sym;
+ }
+ return NULL;
+}
+
+
+/* Look for symbol <name> in symbol table <symtab>.
+ * Return a pointer to the symbol or NULL if not found.
+ */
+Symbol *
+find_symbol (symtab, name)
+SymbolTable *symtab;
+char *name;
+{
+ return search_symbol_list(symtab->bucket[hash(name)], name);
+}
+
+
+/* If the symbol <name> does not already exist in symbol table <symtab>,
+ * then add the symbol to the symbol table.
+ * Return a pointer to the symbol or NULL on an error.
+ */
+Symbol *
+new_symbol (symtab, name, flags)
+SymbolTable *symtab; /* symbol table */
+char *name; /* symbol name */
+int flags; /* symbol attributes */
+{
+ Symbol *sym;
+ int i;
+
+ if ((sym = find_symbol(symtab, name)) == NULL) {
+ sym = (Symbol *)safe_malloc(sizeof(Symbol));
+ sym->name = strduplicate(name);
+ sym->flags = flags;
+ sym->valtype = SYMVAL_NONE;
+ i = hash(name);
+ sym->next = symtab->bucket[i];
+ symtab->bucket[i] = sym;
+ }
+ return sym;
+}
diff --git a/symbol.h b/symbol.h
new file mode 100644
index 0000000..2ce0f5f
--- /dev/null
+++ b/symbol.h
@@ -0,0 +1,41 @@
+/* $Id: symbol.h,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ *
+ * Definitions for a symbol table
+ */
+#include "config.h"
+
+#ifndef _SYMBOL_H
+#define _SYMBOL_H
+
+typedef struct _symbol {
+ struct _symbol *next; /* next symbol in list */
+ char *name; /* name of symbol */
+ unsigned short flags; /* symbol attributes */
+
+ enum { SYMVAL_NONE, SYMVAL_ENUM } valtype;
+
+ union {
+ struct _enumerator_list *enum_list;
+ } value;
+} Symbol;
+
+/* The hash table length should be a prime number. */
+#define SYM_MAX_HASH 251
+
+typedef struct _symbol_table {
+ Symbol *bucket[SYM_MAX_HASH]; /* hash buckets */
+} SymbolTable;
+
+/* Create symbol table */
+extern SymbolTable *create_symbol_table();
+
+/* destroy symbol table */
+extern void destroy_symbol_table _((SymbolTable *symtab));
+
+/* Lookup symbol name */
+extern Symbol *find_symbol _((SymbolTable *symtab, char *name));
+
+/* Define new symbol */
+extern Symbol *new_symbol _((SymbolTable *symtab, char *name, int flags));
+
+#endif
diff --git a/texinfo.c b/texinfo.c
new file mode 100644
index 0000000..1b464b6
--- /dev/null
+++ b/texinfo.c
@@ -0,0 +1,465 @@
+/* $Id: texinfo.c,v 1.1 2004-05-03 05:17:48 behdad Exp $
+ * functions for texinfo style output.
+ */
+#include "c2man.h"
+#include "manpage.h"
+#include "output.h"
+#include <ctype.h>
+
+static char *heading_not_in_contents[] =
+ {"@chapheading ", "@heading ", "@subheading ", "@subsubheading "};
+static char *heading_in_contents[] =
+ {"@chapter ", "@section ", "@subsection ", "@subsubsection "};
+
+#define n_levels (sizeof(heading_not_in_contents) / sizeof(char *))
+
+#define level(n) ((n) >= n_levels ? n_levels - 1 : (n))
+
+/* section level for man page entry */
+static int top_level = 1;
+
+/* always output node for manpage, even if embedded */
+static int embed_node_info = 0;
+
+/* use title as name of section, rather than "NAME" */
+static int title_name = 0;
+
+/* the section title, filled in by texinfo_header */
+static const char *title = "INTERNAL ERROR, BOGUS TITLE DUDE!";
+
+/* do section titles get capitalized? */
+static int capitalize_sections = 0;
+
+void texinfo_char(c)
+const int c;
+{
+ int i;
+
+ switch(c)
+ {
+ case '\t':
+ for (i = 0; i < NUM_TAB_SPACES; i++)
+ putchar(' ');
+ break;
+ default:
+ putchar(c);
+ break;
+ }
+}
+
+void texinfo_text(text)
+const char *text;
+{
+ while (*text)
+ texinfo_char(*text++);
+}
+
+void put_section(text)
+const char *text;
+{
+
+ if (capitalize_sections)
+ {
+ int first_letter = 1;
+
+ for ( ; *text ; text++)
+ {
+ texinfo_char(first_letter ? toupper(*text) : tolower(*text));
+ first_letter = isspace(*text);
+ }
+ }
+ else
+ texinfo_text(text);
+}
+
+void texinfo_comment() { put_string("@c "); }
+
+void texinfo_header(firstpage, input_files, grouped, name, terse, section)
+ManualPage *firstpage;
+int input_files;
+boolean grouped;
+const char *name;
+const char *terse;
+const char *section;
+{
+ if (! make_embeddable)
+ {
+ put_string("\\input texinfo @c -*-texinfo-*-\n");
+ output_warning();
+ put_string("@c %**start of header\n");
+ put_string("@setfilename ");
+ texinfo_text(name);
+ put_string(".info\n@settitle ");
+ texinfo_text(name);
+ putchar('\n');
+ put_string("@c %**end of header\n");
+
+ put_string("@node Top, ");
+ texinfo_text(name);
+ put_string(", (dir), (dir)\n");
+ }
+
+ if (! make_embeddable || embed_node_info)
+ {
+ put_string("@node ");
+ texinfo_text(name);
+ put_string(", (dir), Top, (dir)\n");
+ }
+
+ title = name;
+}
+
+void texinfo_dash() { put_string("---"); }
+
+void texinfo_section(name)
+const char *name;
+{
+ put_string(heading_not_in_contents[level(top_level)]);
+ put_section(name);
+ putchar('\n');
+ put_string("@noindent\n");
+}
+
+void texinfo_section_in_contents(name)
+const char *name;
+{
+ put_string(heading_in_contents[level(top_level)]);
+ put_section(name);
+ putchar('\n');
+ put_string("@noindent\n");
+}
+
+void texinfo_sub_section(name)
+const char *name;
+{
+ put_string(heading_not_in_contents[level(top_level+1)]);
+ put_section(name);
+ putchar('\n');
+ put_string("@noindent\n");
+}
+
+void texinfo_break_line() { /* put_string("@*\n"); */ }
+void texinfo_blank_line() { put_string("@sp 1\n"); }
+
+void texinfo_code_start() { put_string("@example\n"); }
+void texinfo_code_end() { put_string("@end example\n"); }
+
+void texinfo_code(text)
+const char *text;
+{
+ put_string("@code{");
+ texinfo_text(text);
+ put_string("}");
+}
+
+void texinfo_tag_list_start() { put_string("@quotation\n@table @code\n"); }
+void texinfo_tag_entry_start() { put_string("@item "); }
+void texinfo_tag_entry_end() { putchar('\n'); }
+
+void texinfo_tag_entry_end_extra(text)
+const char *text;
+{
+ putchar('(');
+ texinfo_text(text);
+ putchar(')');
+ texinfo_tag_entry_end();
+}
+void texinfo_tag_list_end() { put_string("@end table\n@end quotation\n"); }
+
+void texinfo_table_start(longestag)
+const char *longestag;
+{ put_string("@quotation\n@table @code\n"); }
+
+void texinfo_table_entry(name, description)
+const char *name;
+const char *description;
+{
+ put_string("@item ");
+ texinfo_text(name);
+ putchar('\n');
+ if (description)
+ output_comment(description);
+ else
+ putchar('\n');
+}
+
+void texinfo_table_end() { put_string("@end table\n@end quotation\n"); }
+
+void texinfo_list_start() { }
+void texinfo_list_entry(text)
+const char *text;
+{
+ texinfo_code(text);
+}
+void texinfo_list_separator() { put_string(",\n"); }
+void texinfo_list_end() { putchar('\n'); }
+
+void texinfo_include(filename)
+const char *filename;
+{
+ put_string("@include ");
+ texinfo_text(filename);
+ put_string("\n");
+}
+
+void texinfo_file_end() { put_string("@bye\n"); }
+
+static first_name = 1;
+void texinfo_name(name)
+const char *name;
+{
+ if (name)
+ {
+ if (!first_name || !title_name || strcmp(title,name))
+ texinfo_text(name);
+ first_name = 0;
+ }
+ else
+ {
+ first_name = 1;
+ if (title_name)
+ {
+ /* don't muck around with capitalization of title */
+ int capitalize_sections_save = capitalize_sections;
+ capitalize_sections = 0;
+
+ texinfo_section_in_contents(title);
+ capitalize_sections = capitalize_sections_save;
+ }
+ else
+ texinfo_section("NAME");
+ }
+}
+
+void texinfo_terse_sep()
+{
+ if (!title_name || group_together)
+ {
+ texinfo_char(' ');
+ texinfo_dash();
+ texinfo_char(' ');
+ }
+}
+
+void texinfo_reference(text)
+const char *text;
+{
+ texinfo_text(text);
+ texinfo_char('(');
+ texinfo_text(manual_section);
+ texinfo_char(')');
+}
+
+/* ideally, this should be made aware of embedded texinfo commands */
+void texinfo_description(text)
+const char *text;
+{
+ enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
+ boolean new_line = TRUE;
+
+ /* correct punctuation a bit as it goes out */
+ for (;*text;text++)
+ {
+ int c = *text;
+
+ if (new_line && (c == '-' || c == '*' || is_numbered(text)))
+ {
+ output->break_line();
+ state = CAPITALISE;
+ }
+ else if (c == '.')
+ state = PERIOD;
+ else if (isspace(c) && state == PERIOD)
+ state = CAPITALISE;
+ else if (isalnum(c))
+ {
+ if (islower(c) && state == CAPITALISE) c = toupper(c);
+ state = TEXT;
+ }
+
+ output->character(c);
+ new_line = c == '\n';
+ }
+
+ /* do a full stop if there wasn't one */
+ if (state == TEXT) output->character('.');
+}
+
+/* ideally, this should be made aware of embedded texinfo commands */
+void
+texinfo_returns(comment)
+const char *comment;
+{
+ enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
+ char lastchar = '\n';
+ boolean tag_list_started = FALSE;
+
+ /* for each line... */
+ while (*comment)
+ {
+ boolean tagged = FALSE;
+
+ {
+ const char *c = comment;
+
+ /* search along until the end of a word */
+ while (*c && *c != ':' && !isspace(*c))
+ c++;
+
+ /* skip all spaces or tabs after the first word */
+ while (*c && *c != '\n')
+ {
+ if (*c == '\t' || *c == ':')
+ {
+ tagged = TRUE;
+ break;
+ }
+ else if (!isspace(*c))
+ break;
+
+ c++;
+ }
+ }
+
+ /* is it tagged?; explicitly reject dot commands */
+ if (tagged)
+ {
+ /* output lingering newline if necessary */
+ if (lastchar != '\n')
+ {
+ if (state == TEXT && !ispunct(lastchar)) output->character('.');
+ output->character(lastchar = '\n');
+ }
+
+ if (!tag_list_started)
+ {
+ output->tag_list_start();
+ tag_list_started = TRUE;
+ }
+
+ /* output the taggy bit */
+ output->tag_entry_start();
+ while (*comment && *comment != ':' && !isspace(*comment))
+ output->character(*comment++);
+ output->tag_entry_end();
+
+ /* skip any extra tabs or spaces */
+ while (*comment == ':' || (isspace(*comment) && *comment != '\n'))
+ comment++;
+
+ state = CAPITALISE;
+ }
+
+ /* terminate the previous line if necessary */
+ if (lastchar != '\n') output->character(lastchar = '\n');
+
+ /* correct punctuation a bit as the line goes out */
+ for (;*comment && *comment != '\n'; comment++)
+ {
+ char c = *comment;
+
+ if (c == '.')
+ state = PERIOD;
+ else if (isspace(c) && state == PERIOD)
+ state = CAPITALISE;
+ else if (isalnum(c))
+ {
+ if (islower(c) && state == CAPITALISE && fixup_comments)
+ c = toupper(c);
+ state = TEXT;
+ }
+
+ output->character(lastchar = c);
+ }
+
+ /* if it ended in punctuation, just output the nl straight away. */
+ if (ispunct(lastchar))
+ {
+ if (lastchar == '.') state = CAPITALISE;
+ output->character(lastchar = '\n');
+ }
+
+ if (*comment) comment++;
+ }
+
+ /* output lingering newline if necessary */
+ if (lastchar != '\n')
+ {
+ if (state == TEXT && !ispunct(lastchar) && fixup_comments)
+ output->character('.');
+ output->character('\n');
+ }
+
+ if (tag_list_started)
+ output->tag_list_end();
+}
+
+
+int texinfo_parse_option(option)
+const char *option;
+{
+ if (option[0] == 't')
+ title_name = 1;
+ else if (option[0] == 'n')
+ embed_node_info = 1;
+ else if (option[0] == 's')
+ {
+ top_level = atoi(&option[1]);
+ if (top_level < 0) return 1;
+ }
+ else if (option[0] == 'C')
+ capitalize_sections = 1;
+ else return 1;
+
+ return 0;
+}
+
+void texinfo_print_options()
+{
+ fputs("\ttexinfo options:\n", stderr);
+ fputs("\tt\tuse manpage title as NAME title\n", stderr);
+ fputs("\tn\toutput node info if embedded output\n", stderr);
+ fputs("\ts<n>\tset top heading level to <n>\n", stderr);
+ fputs("\tC\tcaptialize section titles\n", stderr);
+}
+
+
+struct Output texinfo_output =
+{
+ texinfo_comment,
+ texinfo_header,
+ texinfo_dash,
+ texinfo_section,
+ texinfo_sub_section,
+ texinfo_break_line,
+ texinfo_blank_line,
+ texinfo_code_start,
+ texinfo_code_end,
+ texinfo_code,
+ texinfo_tag_list_start,
+ texinfo_tag_list_end,
+ texinfo_tag_entry_start,
+ texinfo_tag_entry_start, /* entry_start_extra */
+ texinfo_tag_entry_end,
+ texinfo_tag_entry_end_extra,
+ texinfo_table_start,
+ texinfo_table_entry,
+ texinfo_table_end,
+ dummy, /* texinfo_indent */
+ texinfo_list_start,
+ texinfo_list_entry,
+ texinfo_list_separator,
+ texinfo_list_end,
+ texinfo_include,
+ texinfo_file_end,
+ texinfo_text,
+ texinfo_char,
+ texinfo_parse_option,
+ texinfo_print_options,
+ texinfo_name,
+ texinfo_terse_sep,
+ texinfo_reference,
+ texinfo_text,
+ texinfo_description,
+ texinfo_returns
+};