Thread View: alt.sources.patches
1 messages
1 total messages
Started by Graham Stoney
Tue, 28 Jul 1992 06:45
c2man: generate man pages from C comments; patch v1.2 -> v1.3
Author: Graham Stoney
Date: Tue, 28 Jul 1992 06:45
Date: Tue, 28 Jul 1992 06:45
1762 lines
46576 bytes
46576 bytes
Archive-name: c2man/patch.1.2-1.3
Submitted-by: greyham@research.canon.oz.au
This official patch brings c2man v1.2 up to v1.3.
This patch introduces the most significant changes yet to prevent errors
reading included files, plus a few other odds and ends. If you were about to
give up because c2man couldn't read programs using basic header files on your
system, this patch is for you. See the CHANGES file for details.
As before, any feedback, comments or tips are greatly appreciated.
Graham
*** 1.2 1992/07/17 06:41:33
--- CHANGES 1992/07/28 06:35:19
***************
*** 3,10 ****
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.
--- 3,10 ----
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.
***************
*** 11,23 ****
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.
--- 11,41 ----
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.
*** 1.3 1992/07/17 06:41:33
--- README 1992/07/28 06:35:19
***************
*** 1,12 ****
! This is c2man (Version 1.2), a program for generating Unix style manual pages
! in nroff -man format directly from ordinary comments embedded in C source code.
! It owes a huge debt to the public domain program cproto, by Chin Huang, from
! which much of the code is derived.
- Please send me some Email if you find c2man useful; the more people I know are
- using it, the more time I am likely to spend on bug fixes and enhancements.
- Also, I can let you know about new releases if you wish.
-
This version of c2man is copyright 1992 by Canon Information Systems Research
Australia. It may be freely redistributed and modified so long as:
--- 1,13 ----
! This is c2man (Version 1.3), a program for generating Unix style manual pages
! in nroff/troff -man format directly from ordinary comments embedded in C source
! code. It owes a huge debt to the public domain program cproto, by Chin Huang,
! from which much of the code is derived.
!
! Even if you don't have nroff or troff, you can still use c2man by grabbing
! Henry Spencer's Amazingly Workable Formatter (awf) program; it's written in
! AWK, and can format c2man output (it's v23i027 in your local comp.sources.unix
! archive).
This version of c2man is copyright 1992 by Canon Information Systems Research
Australia. It may be freely redistributed and modified so long as:
***************
*** 22,29 ****
you can't just cp it into place. As a further consequence, the example will be
missing from the manual page if you try to read it before doing a make.
! Comments and bug reports (especially those with patches :-) are welcome,
! and make sure you include the c2man version number (go: c2man -V).
If anyone wants to volunteer to write c++2man, please drop me a line! Such a
tool would be incredibly useful, and shouldn't be too hard to add to c2man.
--- 23,34 ----
you can't just cp it into place. As a further consequence, the example will be
missing from the manual page if you try to read it before doing a make.
! Please send me some Email if you find c2man useful; the more people I know are
! using it, the more time I am likely to spend on bug fixes and enhancements;
! plus I can let you know about new releases if you wish. Comments and bug
! reports (especially those with patches :-) are welcome, but make sure you
! include the c2man version number (go: c2man -V).
!
If anyone wants to volunteer to write c++2man, please drop me a line! Such a
tool would be incredibly useful, and shouldn't be too hard to add to c2man.
***************
*** 33,57 ****
INSTALLATION:
1. You will need a C compiler that can handle ANSI constructs (prototypes,
! string concatenation, free(NULL), etc), or an ANSI to K&R converter.
! Don't put the compiler in strict ANSI mode though, 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.
!
! Don't use -Wall with gcc unless your system header files have basic
! stuff like fprintf in stdio.h (SunOS Release 4.1.2 for example!).
!
! Sun yacc outputs incorrect prototypes for malloc and free (says they
! return char * instead of void *), which gcc 2.2 or later errors on; use
! bison instead, or just delete the incorrect prototypes on the first
! line of y.tab.c when the make errors.
! 2. Look at the Makefile, and check that YACC, CC, WARN, SYSV and DEFINES are
! set correctly.
3. Type "make"
4. Look at the manual page. The example in it is automatically generated, so
! check that it looks OK.
5. As root, do "make install"
--- 38,64 ----
INSTALLATION:
1. You will need a C compiler that can handle ANSI constructs (prototypes,
! string concatenation, free(NULL), etc), or an ANSI to K&R converter.
! Don't put the compiler in strict ANSI mode though, 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.
!
! Don't use -Wall with gcc unless your system header files have basic stuff
! like fprintf in stdio.h (SunOS Release 4.1.2 for example!).
!
! Sun yacc outputs incorrect prototypes for malloc and free (says they return
! char * instead of void *), which gcc 2.2 or later errors on; use bison
! instead, or just delete the incorrect prototypes on the first line of
! y.tab.c when the make errors.
!
! If using gcc on a Sun, you may need GNU libc to get stdarg.h
! 2. Look at the Makefile, and check that CC, DEFINES, WARN, LIBS and BSD are
! set if necessary. Optionally, set LEX and YACC too.
3. Type "make"
4. Look at the manual page. The example in it is automatically generated, so
! check that it looks OK.
5. As root, do "make install"
*** 1.4 1992/07/17 06:41:33
--- Makefile 1992/07/28 06:35:19
***************
*** 1,36 ****
! # $Id: Makefile,v 1.4 1992/07/17 06:41:33 greyham Exp $
#
# UNIX makefile for manual page generator
#
! # Pick if you want yacc or bison. (use the first one)
! #YACC = bison -y
! #YACC = bison -y -v -t
! # Pick the ANSI-C compiler you use.
#CC=gcc
! #CC=../tmp/gcc-2.2.2/gcc -B../tmp/gcc-2.2.2/
#CC=/usr/local/lang/acc
! # Define SYSV for System V, otherwise BSD is assumed.
! #SYSV = -DSYSV
# Pick what extra warnings you'd like.
! WARN=-Wall
# Pick whatever other compiler defines are needed.
! DEFINES= -O
! # -g
# -DYYDEBUG
# -DDEBUG
# Want to use flex?
#LEX=flex
! # be lenient on y.tab.c, but harsh on the rest
! NOWARN=$(SYSV) $(DEFINES)
! CFLAGS = $(WARN) $(NOWARN)
! # -DMALLOC_DEBUG
DIST1 = README CHANGES c2man.1 Makefile example.h example.sed \
flatten.sed $(OSOURCES)
--- 1,63 ----
! # $Id: Makefile,v 1.5 1992/07/28 06:34:30 greyham Exp $
#
# UNIX makefile for manual page generator
#
! # Choose one of the pre-packaged configurations here, or customize your own
! # down below. To pick one here, uncomment only ONE of these sets of lines.
! # NeXT:
! DEFINES=-O
! WARN=-Wall
!
! # Sun with gcc:
#CC=gcc
! #DEFINES=-O
! #WARN=
!
! # Sun with acc:
#CC=/usr/local/lang/acc
+ #DEFINES=-O
+ #WARN=
+ #BSD=-DBSD
+
+ # HPUX:
+ #DEFINES= -Aa -D_INCLUDE_POSIX_SOURCE -D_INCLUDE_XOPEN_SOURCE \
+ -D_INCLUDE_HPUX_SOURCE
+ #WARN=
+
+ # Interactive UNIX with gcc:
+ #CC=gcc -nostdinc -I/usr/include
+ #DEFINES=-O -D_POSIX_SOURCE
+ #WARN=-Wall
+ #LIBS=-lcposix
+
+ # End of pre-packaged configurations.
+
+ # Pick the ANSI-C compiler you use.
+ #CC=gcc
! # Define BSD if your library doesn't have ANSI string functions.
! #BSD = -DBSD
# Pick what extra warnings you'd like.
! #WARN=-Wall
# Pick whatever other compiler defines are needed.
! #DEFINES= -g
# -DYYDEBUG
# -DDEBUG
+ # Pick if you want yacc or bison. (use the first one)
+ #YACC = bison -y
+ #YACC = bison -y -v -t
+
# Want to use flex?
#LEX=flex
! # For MallocDebug on the NeXT:
! #LIBS=-lMallocDebug -lsys_s
! #DEFINES=-g -DMALLOC_DEBUG
DIST1 = README CHANGES c2man.1 Makefile example.h example.sed \
flatten.sed $(OSOURCES)
***************
*** 48,53 ****
--- 75,84 ----
GENERATED = c2man c2man.man example.inc y.tab.c lex.yy.c \
c2man.sh1 c2man.sh2 dowork.3 y.output
+ # be lenient on y.tab.c, but harsh on the rest
+ NOWARN=$(BSD) $(DEFINES)
+ CFLAGS = $(WARN) $(NOWARN)
+
MAKE=make
all: c2man c2man.man
***************
*** 57,64 ****
sed -f flatten.sed < c2man.1 > /usr/local/man/man1/c2man.1
c2man: $(OBJECTS)
! $(CC) $(CFLAGS) -o $@ $(OBJECTS)
! # -lMallocDebug -lsys_s
y.tab.c: grammar.y
@echo Expect 28 shift/reduce conflicts.
--- 88,94 ----
sed -f flatten.sed < c2man.1 > /usr/local/man/man1/c2man.1
c2man: $(OBJECTS)
! $(CC) $(CFLAGS) -o $@ $(OBJECTS) $(LIBS)
y.tab.c: grammar.y
@echo Expect 28 shift/reduce conflicts.
*** 1.3 1992/07/17 06:41:33
--- c2man.1 1992/07/28 06:35:19
***************
*** 1,4 ****
! .\" $Id: c2man.1,v 1.3 1992/07/17 06:41:33 greyham Exp $
.de EX \"Begin example
.ne 5
.if n .sp 1
--- 1,4 ----
! .\" $Id: c2man.1,v 1.5 1992/07/28 06:34:30 greyham Exp $
.de EX \"Begin example
.ne 5
.if n .sp 1
***************
*** 96,103 ****
parameters.
.B enum
identifiers that begin with an underscore are ignored, which is useful for
! padding or NUM_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.
--- 96,103 ----
parameters.
.B enum
identifiers that begin with an underscore are ignored, which is useful for
! padding or 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.
***************
*** 108,119 ****
after the first line or sentence
of the comment immediately before the declaration/definition,
up until the word
! .RB `` returns ''
! (or
! .RB `` return ''
! followed by a non-alphanumeric)
! at the start of a line and matched case-insensitively
! (if any of that exists).
.LP
The
.B RETURNS
--- 108,116 ----
after the first line or sentence
of the comment immediately before the declaration/definition,
up until the word
! .RB `` return[s] ''
! at the start of a line, matched case-insensitively and optionally followed by
! some non-alphanumerics.
.LP
The
.B RETURNS
***************
*** 126,144 ****
section is generated, referencing all the other manual pages generated from
the same source file, if any.
.LP
! .B c2man
! will omit the
.BR RETURNS ,
.B PARAMETERS
! or
.B "SEE ALSO"
! sections entirely if it doesn't seem to need them.
.LP
When looking at comments,
.B c2man
strips the comment delimiters,
ignores both leading whitespace and leading asterisks on a
! line, and ignores all surrounding thus rendered ``blank''.
This makes it very flexible in supporting popular comment boxing.
.LP
The following variations of the enum definition in the
--- 123,148 ----
section is generated, referencing all the other manual pages generated from
the same source file, if any.
.LP
! The
.BR RETURNS ,
.B PARAMETERS
! and
.B "SEE ALSO"
! sections are omitted entirely if they aren't needed.
.LP
+ Both
+ .B C
+ and
+ .B C++
+ style comments are recognized,
+ with consecutive lines of
+ .B C++
+ comments are treated as a single block.
When looking at comments,
.B c2man
strips the comment delimiters,
ignores both leading whitespace and leading asterisks on a
! line, and ignores all surrounding lines thus rendered blank.
This makes it very flexible in supporting popular comment boxing.
.LP
The following variations of the enum definition in the
***************
*** 156,163 ****
};
.EE
.EX
! /* the comment needn't go on the same line, */
! /* if the comma goes after the comment. */
enum Place
{
HOME
--- 160,168 ----
};
.EE
.EX
! /* the comment needn't go on the same line,
! * if the comma goes after the comment.
! */
enum Place
{
HOME
***************
*** 236,241 ****
--- 241,251 ----
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.
.ig
.TP
.B \-p
*** 1.2 1992/07/17 06:41:33
--- c2man.c 1992/07/28 06:35:20
***************
*** 1,10 ****
! /* $Id: c2man.c,v 1.2 1992/07/17 06:41:33 greyham Exp $
*
* C Manual page.
* Reads C source code and outputs manual pages.
*/
#ifndef lint
! static char *rcsid = "$Id: c2man.c,v 1.2 1992/07/17 06:41:33 greyham Exp $";
#endif
#include <stdio.h>
#include <ctype.h>
--- 1,10 ----
! /* $Id: c2man.c,v 1.3 1992/07/28 06:34:30 greyham Exp $
*
* C Manual page.
* Reads C source code and outputs manual pages.
*/
#ifndef lint
! static char *rcsid = "$Id: c2man.c,v 1.3 1992/07/28 06:34:30 greyham Exp $";
#endif
#include <stdio.h>
#include <ctype.h>
***************
*** 81,86 ****
--- 81,88 ----
/* total number of errors encountered */
int errors;
+ char *cpp_cmd;
+
/* Output an error message along with the current line number in the
* source file.
*/
***************
*** 152,157 ****
--- 154,187 ----
exit(1);
}
+ int process_file(char *name)
+ {
+ char *cmd = name ? strconcat(cpp_cmd, " ", name, NULL) : cpp_cmd;
+
+ #ifdef NO_CPP
+ if (name && freopen(name, "r", yyin) == NULL)
+ {
+ fprintf(stderr, "%s: cannot open file %s\n", progname, argv[i]);
+ return 0;
+ }
+ #else
+ if ((yyin = popen(cmd, "r")) == NULL) {
+ fprintf(stderr, "%s: error running %s\n", progname, cmd);
+ return 0;
+ }
+ #endif
+ strcpy(cur_file, name ? name : "stdin");
+
+ parse_file();
+ #ifdef NO_CPP
+ fclose(yyin);
+ #else
+ pclose(yyin);
+ if (name) free(cmd);
+ #endif
+ return !errors;
+ }
+
int
main (argc, argv)
int argc;
***************
*** 158,164 ****
char **argv;
{
int i, c;
! char *s, *cpp_cmd, *new_cmd, cbuf[2];
#ifdef YYDEBUG
extern int yydebug;
#endif
--- 188,194 ----
char **argv;
{
int i, c;
! char *s, *new_cmd, cbuf[2];
#ifdef YYDEBUG
extern int yydebug;
#endif
***************
*** 251,289 ****
yydebug = 1;
#endif
! if (optind == argc) {
! strcpy(cur_file, "stdin");
! parse_file();
! } else {
! for (i = optind; i < argc; ++i) {
! #ifdef NO_CPP
! if (freopen(argv[i], "r", yyin) == NULL) {
! fprintf(stderr, "%s: cannot open file %s\n", progname, argv[i]);
! continue;
! }
! #else
! new_cmd = strconcat(cpp_cmd, " ", argv[i], NULL);
! if ((yyin = popen(new_cmd, "r")) == NULL) {
! fprintf(stderr, "%s: error running cpp\n", progname);
! continue;
! }
! #endif
! strcpy(cur_file, argv[i]);
! parse_file();
! #ifdef NO_CPP
! fclose(yyin);
! #else
! pclose(yyin);
! free(new_cmd);
! #endif
! if (errors) break;
! }
! }
free(cpp_cmd);
#ifdef MALLOC_DEBUG
! sleep(100000);
#endif
return errors;
}
--- 281,297 ----
yydebug = 1;
#endif
! if (optind == argc)
! process_file(NULL);
! else
! for (i = optind; i < argc; ++i)
! if (!process_file(argv[i])) break;
+ fclose(stdout); /* close last output file */
free(cpp_cmd);
#ifdef MALLOC_DEBUG
! wait(NULL);
#endif
return errors;
}
*** 1.1 1992/07/07 09:24:32
--- config.h 1992/07/28 06:35:20
***************
*** 1,6 ****
! /* $Id: config.h,v 1.1 1992/07/07 09:24:32 greyham Exp $
*
! * cproto configuration and system dependencies
*/
/* maximum include file nesting */
--- 1,6 ----
! /* $Id: config.h,v 1.3 1992/07/28 06:34:30 greyham Exp $
*
! * c2man configuration and system dependencies
*/
/* maximum include file nesting */
***************
*** 23,34 ****
#include <malloc.h>
#endif
! #if defined(SYSV) || defined(MSDOS)
#include <string.h>
- #define index strchr
- #define rindex strrchr
#else
#include <strings.h>
#endif
#ifndef MSDOS
--- 23,34 ----
#include <malloc.h>
#endif
! #ifndef BSD
#include <string.h>
#else
#include <strings.h>
+ #define strchr index
+ #define strrchr rindex
#endif
#ifndef MSDOS
*** 1.2 1992/07/17 06:41:33
--- lex.l 1992/07/28 06:35:22
***************
*** 1,5 ****
%{
! /* $Id: lex.l,v 1.2 1992/07/17 06:41:33 greyham Exp $
*
* C manual page generator
* Lexical analyzer specification
--- 1,5 ----
%{
! /* $Id: lex.l,v 1.5 1992/07/28 06:34:30 greyham Exp $
*
* C manual page generator
* Lexical analyzer specification
***************
*** 38,52 ****
static int inc_depth = 0; /* include nesting level */
static IncludeStack inc_stack[MAX_INC_DEPTH]; /* stack of included files */
static void do_include();
! void new_dynbuf(void);
! void add_dynbuf(char c);
#undef yywrap /* for flex */
%}
! %s CPP1 CPP2 INIT1 INIT2 CURLY COMMENT LEXYACC SKIP EOLCOMMENT ENDEOLCOMM
! %s CPPCOMM CPPEOLCOMM
%%
--- 38,56 ----
static int inc_depth = 0; /* include nesting level */
static IncludeStack inc_stack[MAX_INC_DEPTH]; /* stack of included files */
+
static void do_include();
! static void new_dynbuf(void);
! static void add_dynbuf(char c);
! static int get_comment(boolean ateol, boolean cpp);
! static void get_cpp_directive();
#undef yywrap /* for flex */
+
+ /* SKIP skipping value assignment in an enum */
%}
! %s CPP1 INIT1 INIT2 CURLY LEXYACC SKIP
%%
***************
*** 59,92 ****
<INITIAL>^"%}" BEGIN LEXYACC;
<INITIAL>^{WS}*#{WS}* BEGIN CPP1;
! <CPP1>define{WS}+{ID}.*\\$ {
! sscanf(yytext, "define %s", buf);
! new_symbol(typedef_names, buf);
! BEGIN CPP2;
! }
! <CPP1>define{WS}+{ID}.*$ {
sscanf(yytext, "define %s", buf);
new_symbol(typedef_names, buf);
- BEGIN INITIAL;
}
- <CPP2>.*\\$ ;
- <CPP2>.*$ BEGIN INITIAL;
! <CPP1>include{WS}+\"[^"]+\".*$ {
sscanf(yytext, "include \"%[^\"]\"", buf);
! do_include(buf, 0);
! BEGIN INITIAL;
}
! <CPP1>include{WS}+\<[^>]+\>.*$ {
sscanf(yytext, "include <%[^>]>", buf);
! do_include(buf, 1);
! BEGIN INITIAL;
}
<CPP1>[0-9]+{WS}+\".*$ {
char new_file[MAX_TEXT_LENGTH];
sscanf(yytext, "%d \"%[^\"]\"", &line_num,
! new_file);
--line_num;
BEGIN INITIAL;
--- 63,96 ----
<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);
}
! <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, cur_file);
+ line_num--;
+ BEGIN INITIAL;
+ }
<CPP1>[0-9]+{WS}+\".*$ {
char new_file[MAX_TEXT_LENGTH];
sscanf(yytext, "%d \"%[^\"]\"", &line_num,
! new_file);
--line_num;
BEGIN INITIAL;
***************
*** 94,100 ****
if (strcmp(cur_file, new_file))
{
strcpy(cur_file, new_file);
! yylval.boolean = !strcmp(cur_file,basefile);
return T_BASEFILE;
}
}
--- 98,106 ----
if (strcmp(cur_file, new_file))
{
strcpy(cur_file, new_file);
! yylval.boolean =
! new_file[0] == '\0' /* stdin */
! || !strcmp(cur_file,basefile);
return T_BASEFILE;
}
}
***************
*** 104,110 ****
BEGIN INITIAL;
}
! <CPP1>.*$ BEGIN INITIAL;
<INITIAL>"(" return '(';
<INITIAL>")" return ')';
--- 110,116 ----
BEGIN INITIAL;
}
! <CPP1>. get_cpp_directive();
<INITIAL>"(" return '(';
<INITIAL>")" return ')';
***************
*** 210,259 ****
}
<CURLY,SKIP>{QUOTED}|. ;
! <INITIAL,SKIP>^{WS}*"/*" { new_dynbuf(); BEGIN COMMENT; }
! <INITIAL,SKIP>^{WS}*"//" { new_dynbuf(); BEGIN CPPCOMM; };
! <INITIAL,SKIP>"/*" { new_dynbuf(); BEGIN EOLCOMMENT; }
! <INITIAL,SKIP>"//" { new_dynbuf(); BEGIN CPPEOLCOMM; };
!
! <COMMENT>"*/" {
! add_dynbuf('\0');
! yylval.text = dynbuf;
! BEGIN INITIAL;
! return T_COMMENT;
! }
!
! <EOLCOMMENT>"*/" {
! add_dynbuf('\0');
! yylval.text = dynbuf;
! BEGIN ENDEOLCOMM;
! }
! <CPPCOMM>^{WS}*"//" { add_dynbuf('\n'); }
! <CPPCOMM>^. {
! unput(yytext[0]);
! add_dynbuf('\0');
! yylval.text = dynbuf;
! BEGIN INITIAL;
! return T_COMMENT;
! }
! <CPPEOLCOMM>\n {
! ++line_num;
! add_dynbuf('\0');
! yylval.text = dynbuf;
! BEGIN INITIAL;
! return T_EOLCOMMENT;
}
- <EOLCOMMENT,COMMENT>\n { ++line_num; add_dynbuf('\n'); }
- <EOLCOMMENT,COMMENT,CPPEOLCOMM,CPPCOMM>. add_dynbuf(yytext[0]);
-
- <ENDEOLCOMM>\n { ++line_num; BEGIN INITIAL; return T_EOLCOMMENT; }
-
-
[ \t\f]+ ;
\n ++line_num;
- <ENDEOLCOMM>. { unput(yytext[0]); BEGIN INITIAL; return T_COMMENT; }
-
. {
output_error();
fprintf(stderr, "bad character '%c'\n", yytext[0]);
--- 216,241 ----
}
<CURLY,SKIP>{QUOTED}|. ;
! <INITIAL,SKIP>^{WS}*"/*" {
! int ret;
! if (ret = get_comment(FALSE,FALSE)) return ret;
! }
! <INITIAL,SKIP>^{WS}*"//" {
! int ret;
! if (ret = get_comment(FALSE,TRUE)) return ret;
! }
! <INITIAL,SKIP>"/*" {
! int ret;
! if (ret = get_comment(TRUE, FALSE)) return ret;
! }
! <INITIAL,SKIP>"//" {
! int ret;
! if (ret = get_comment(TRUE, TRUE)) return ret;
}
[ \t\f]+ ;
\n ++line_num;
. {
output_error();
fprintf(stderr, "bad character '%c'\n", yytext[0]);
***************
*** 261,266 ****
--- 243,408 ----
%%
#include <stdlib.h>
+ /* this horrid mess parses a C or a C++ comment, extracts the interesting text,
+ * and determines if the comment is at the end of the line or not.
+ */
+ static int
+ get_comment(boolean ateol, boolean cpp)
+ {
+ int c, lastc = '\0';
+ int end = 0;
+ boolean remember = inbasefile || enum_state == BRACES;
+ enum
+ {
+ START, /* looking for the start of text */
+ FIRSLASH, /* looking for first / of C++ comment */
+ SECSLASH, /* looking for 2nd / of C++ comment */
+ STARTLINE, /* looking for start of next text line */
+ TEXT, /* in text */
+ ASTER, /* found an asterix */
+ END /* after end of C comment, looking for EOL */
+ } laststate, state = START;
+
+ if (remember)
+ new_dynbuf();
+
+ while ((c = input()) != 0)
+ {
+ switch (state)
+ {
+ case FIRSLASH:
+ if (c != '/' && !isspace(c)) { unput(c); goto leave; }
+ state = SECSLASH;
+ continue;
+ case SECSLASH:
+ if (c != '/') { unput(c); unput('/'); goto leave; }
+ state = laststate;
+ continue;
+ }
+
+ switch (c)
+ {
+ case '\n':
+ line_num++;
+ if (cpp && ateol) goto leave;
+
+ switch (state)
+ {
+ case ASTER: if ((state = laststate) == TEXT)
+ { if (remember) add_dynbuf('*'); }
+ else if (state == START)
+ break; /* don't add if at the start */
+ /* FALLTHROUGH if now in TEXT */
+ case STARTLINE:
+ case TEXT: if (remember) add_dynbuf(c);
+ state = STARTLINE; break;
+ case END: goto leave;
+ default: break; /* don't add it in START */
+ }
+
+ if (cpp) { laststate = state; state = FIRSLASH; }
+ break;
+
+ case '*':
+ switch (state)
+ {
+ case ASTER: if (laststate == TEXT && remember) add_dynbuf('*');
+ break;
+ case END: unput(c); ateol = 0; goto leave;
+ default: laststate = state; state = ASTER;
+ }
+ break;
+
+ case '/':
+ switch (state)
+ {
+ case ASTER: if (!ateol) goto leave;
+ state = END; continue;
+ case TEXT: break;
+ case END: unput(c); ateol = 0; goto leave;
+ default: continue;
+ }
+ /* FALLTHROUGH if state == TEXT */
+
+ normal:
+ default:
+ switch (state)
+ {
+ case ASTER:
+ if ((state = laststate) == TEXT && remember)
+ add_dynbuf('*');
+ else
+ break;
+ /* FALLTHROUGH if just became TEXT */
+ case TEXT:
+ if (remember)
+ {
+ add_dynbuf(c);
+ if (!isspace(c)) end = dynbuf_current;
+ }
+ break;
+ default:
+ if (!isspace(c))
+ {
+ state = TEXT;
+ if (remember) { add_dynbuf(c); end = dynbuf_current; }
+ }
+ break;
+ case END: unput(c); ateol = 0; goto leave;
+ }
+ break;
+ }
+ }
+
+ leave:
+ if (remember)
+ {
+ if (end == 0)
+ free(dynbuf);
+ else
+ {
+ dynbuf[end] = '\0';
+ yylval.text = dynbuf;
+ #ifdef DEBUG
+ fprintf(stderr,"ateol %d, comment '%s'\n",ateol,dynbuf);
+ #endif
+ return ateol ? T_EOLCOMMENT : T_COMMENT;
+ }
+ }
+ return 0;
+ }
+
+
+ /* 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 */
+ if (get_comment(TRUE,FALSE))
+ free(dynbuf);
+ }
+ break;
+ }
+ lastc = c;
+ }
+ }
+
/* Process include directive.
*/
static void
***************
*** 319,325 ****
}
! void new_dynbuf(void)
{
if ((dynbuf = malloc(dynbuf_size = DYNBUF_ALLOC)) == 0)
outmem();
--- 461,467 ----
}
! static void new_dynbuf(void)
{
if ((dynbuf = malloc(dynbuf_size = DYNBUF_ALLOC)) == 0)
outmem();
***************
*** 327,333 ****
dynbuf_current = 0;
}
! void add_dynbuf(char c)
{
if (dynbuf_current == dynbuf_size &&
((dynbuf = realloc(dynbuf,dynbuf_size += DYNBUF_ALLOC)) == 0))
--- 469,475 ----
dynbuf_current = 0;
}
! static void add_dynbuf(char c)
{
if (dynbuf_current == dynbuf_size &&
((dynbuf = realloc(dynbuf,dynbuf_size += DYNBUF_ALLOC)) == 0))
*** 1.4 1992/07/17 06:41:33
--- manpage.c 1992/07/28 06:35:22
***************
*** 1,4 ****
! /* $Id: manpage.c,v 1.4 1992/07/17 06:41:33 greyham Exp $
* stuff to do with manual page outputing
*/
--- 1,4 ----
! /* $Id: manpage.c,v 1.7 1992/07/28 06:34:30 greyham Exp $
* stuff to do with manual page outputing
*/
***************
*** 40,46 ****
{
char *period;
! return ((period = rindex(cur_file,'.')) && (!strcmp(period+1,"h")));
}
void
--- 40,46 ----
{
char *period;
! return ((period = strrchr(cur_file,'.')) && (!strcmp(period+1,"h")));
}
void
***************
*** 106,178 ****
output_comment(comment)
char *comment;
{
! enum { START, TEXT, NEWLINE, BLANKLINE, SPACING } state = START;
! char c, last = '.';
! if (comment == NULL)
{
put_string("Not Documented.");
return;
}
-
- while (c = *comment++)
- {
- switch(state)
- {
- case START:
- if (!isspace(c) && c != '*')
- {
- if (islower(c)) c = toupper(c);
- putchar(last = c);
- state = TEXT;
- }
- break;
- case TEXT:
- if (c == '\n')
- state = NEWLINE;
- else if (isspace(c))
- state = SPACING;
- else
- putchar(last = c);
- break;
- case SPACING:
- if (c == '\n')
- state = NEWLINE;
- else if (!isspace(c))
- {
- putchar(' ');
- state = TEXT;
- putchar(last = c);
- }
- break;
- case NEWLINE:
- if (c == '\n') /* got a blank line? */
- {
- state = BLANKLINE;
- break;
- }
-
- if (c == '*' || isspace(c))
- break;
! putchar('\n');
! putchar(last = c);
! state = TEXT;
! break;
! case BLANKLINE:
! if (c == '*' || isspace(c))
! break;
! putchar('\n');
! putchar('\n');
! putchar(last = c);
! state = TEXT;
! break;
! }
}
/* do a full stop if there wasn't one */
! if (last != '.') putchar('.');
}
/* Output the list of function parameter descriptions.
--- 106,132 ----
output_comment(comment)
char *comment;
{
! char lastchar = '.';
! if (!comment || !comment[0])
{
put_string("Not Documented.");
return;
}
! /* correct punctuation as it goes out */
! for (;*comment;comment++)
! {
! if (lastchar == '.' && islower(*comment))
! lastchar = toupper(*comment);
! else
! lastchar = *comment;
! putchar(lastchar);
}
/* do a full stop if there wasn't one */
! if (lastchar != '.') putchar('.');
}
/* Output the list of function parameter descriptions.
***************
*** 197,202 ****
--- 151,157 ----
/* output list of possible enum values, if any */
if (p->decl_spec.enum_list)
{
+ int maxtaglen = 0;
int descriptions = 0;
Enumerator *e;
int is_first = 1;
***************
*** 210,218 ****
/* see if any have descriptions */
for (e = p->decl_spec.enum_list->first; e; e = e->next)
! if (e->name[0] != '_' && e->comment)
! descriptions = 1;
!
printf("Possible values for a\n.B \"%s\"\nare:\n",
p->decl_spec.text);
--- 165,177 ----
/* see if any have descriptions */
for (e = p->decl_spec.enum_list->first; e; e = e->next)
! if (e->name[0] != '_')
! {
! int taglen = strlen(e->name);
! if (taglen > maxtaglen) maxtaglen = taglen;
! if (e->comment) descriptions = 1;
! }
!
printf("Possible values for a\n.B \"%s\"\nare:\n",
p->decl_spec.text);
***************
*** 226,232 ****
if (descriptions)
{
put_string(".TP");
! if (is_first) put_string(" 1.5in");
putchar('\n');
}
else if (!is_first)
--- 185,191 ----
if (descriptions)
{
put_string(".TP");
! if (is_first) printf(" %dm", maxtaglen + 2);
putchar('\n');
}
else if (!is_first)
***************
*** 234,240 ****
--- 193,201 ----
is_first = 0;
+ put_string("\\fB");
put_string(e->name);
+ put_string("\\fR");
if (descriptions)
{
***************
*** 257,264 ****
}
}
! char *alloc_string(char *start,int len)
{
char *ret;
if (len == 0) return NULL;
--- 218,226 ----
}
}
! char *alloc_string(char *start,char *end)
{
+ int len = end - start + 1;
char *ret;
if (len == 0) return NULL;
***************
*** 297,426 ****
char **terse, /* terse one-liner. */
char **description,/* full description */
char **returns /* return value */)
! {
! static char *wordreturn = "return";
! enum { FINDFIRST, /* looking for start of first line */
! FIRSTLN, /* scanning down the first line */
! FIRSTDESC, /* look for start of first description line */
! FINDDESC, /* looking for start of a description line */
! DESCLN, /* at the start of a line in the description */
! DESC, /* scanning down the description */
! CHECKRETURNS,/* seeing if Return is followed by non-alphanum */
! CHECKRETURN_,/* seeing ig Returns is followed by a space */
! CHECKRETURN, /* seeing if Return is followed by non-alphanum */
! FINDRETURN, /* looking for start of text after Return */
! RETURN /* the Returns: bit */
! } state = FINDFIRST;
! int firstlen = 0, desclen = 0, retlen = 0;
! char *firststart = NULL, *descstart = NULL, *retstart = NULL;
! char *c;
! int retmatch = 0;
!
! if (comment == NULL)
{
! *terse = NULL;
*description = NULL;
*returns = NULL;
return;
! }
!
! for (c = comment; *c; c++)
{
! switch(state)
! {
! case FINDFIRST:
! if (!isspace(*c) && *c != '*')
! {
! firststart = c;
! firstlen = 1;
! state = FIRSTLN;
! }
! break;
! case FIRSTLN:
! if (*c == '\n' || *c == '.')
! state = FIRSTDESC;
! else
! firstlen++;
! break;
! case FIRSTDESC:
! if (isspace(*c) || *c == '*')
! break;
!
! descstart = c;
! desclen = 0;
! retmatch = 0;
! state = FINDDESC;
! /* FALLTHROUGH */
! case FINDDESC:
! if (isspace(*c) || *c == '*')
! {
! desclen++;
! break;
! }
!
! state = DESCLN;
! /* FALLTHROUGH */
! case DESCLN:
! if ((islower(*c) && *c == wordreturn[retmatch]) ||
! (isupper(*c) && tolower(*c) == wordreturn[retmatch]))
! {
! /* complete match? */
! if (wordreturn[++retmatch] == '\0')
! state = CHECKRETURNS;
! break;
! }
! else
! state = DESC;
! /* FALLTHROUGH */
! case DESC:
! desclen += retmatch + 1;
! retmatch = 0;
! if (*c == '\n')
! state = FINDDESC;
! break;
! case CHECKRETURNS:
! retmatch++;
! if (*c == 's' || *c == 'S')
! state = CHECKRETURN_; /* make sure it's followed by space */
! else
! state = DESC;
! break;
! case CHECKRETURN_:
! if (isspace(*c) || !isalnum(*c))
! state = FINDRETURN;
! else
! {
! retmatch++; /* accept this one too */
! state = DESC;
! }
! break;
! case CHECKRETURN:
! if (isspace(*c))
! retmatch++;
! else if (!isalnum(*c))
! state = FINDRETURN;
else
! {
! retmatch++; /* accept this one too */
! state = DESC;
! }
! break;
! case FINDRETURN:
! if (!isalnum(*c))
! break;
! retstart = c;
! retlen = 0;
! state = RETURN;
! /* fallthrough */
! case RETURN:
! retlen++;
! break;
}
}
! *terse = alloc_string(firststart,firstlen);
! *description = alloc_string(descstart,desclen);
! *returns = alloc_string(retstart,retlen);
return;
}
--- 259,334 ----
char **terse, /* terse one-liner. */
char **description,/* full description */
char **returns /* return value */)
! {
! char *firstdot, *firsteol, *retstart, *descstart;
!
! /* find the end of the terse comment */
! firstdot = strchr(comment,'.');
! firsteol = strchr(comment,'\n');
!
! if (firstdot && firsteol)
! descstart = firstdot < firsteol ? firstdot : firsteol - 1;
! else if (firstdot)
! descstart = firstdot;
! else if (firsteol)
! descstart = firsteol;
! else
{
! *terse = strdup(comment);
*description = NULL;
*returns = NULL;
return;
! }
!
! *terse = alloc_string(comment,descstart++);
!
! /* spin to next line */
! while (*descstart && isspace(*descstart))
! descstart++;
!
! /* leave others out if not included */
! if (!descstart)
{
! *description = NULL;
! *returns = NULL;
! return;
! }
!
! for (retstart = strchr(descstart,'\n');
! retstart;
! retstart = strchr(retstart,'\n'))
! {
! retstart++; /* skip the newline */
! if (!strncmp(retstart, "return",6) || !strncmp(retstart, "Return",6) ||
! !strncmp(retstart, "RETURN",6))
! {
! 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 > descstart && isspace(*descend))
! descend--;
!
! *description = alloc_string(descstart,descend);
!
! retstart += 6;
! if (*retstart == 's' || *retstart == 'S')
! retstart++;
!
! while (*retstart == ':' || isspace(*retstart))
! retstart++;
!
! if (*retstart)
! *returns = strdup(retstart);
else
! *returns = NULL;
! return;
}
}
! *description = strdup(descstart);
! *returns = NULL;
return;
}
***************
*** 455,469 ****
&terse,&description,&returns);
/* stat the file to check the relevant date */
! if (stat(cur_file,&statbuf) == 0)
! {
! filetime = localtime(&statbuf.st_mtime);
! }
! else
{
perror(cur_file);
exit(-1);
}
/* generate the date format string */
strftime(month, sizeof month,"%B",filetime);
--- 363,375 ----
&terse,&description,&returns);
/* stat the file to check the relevant date */
! if (stat(cur_file,&statbuf) != 0)
{
perror(cur_file);
exit(-1);
}
+
+ filetime = localtime(&statbuf.st_mtime);
/* generate the date format string */
strftime(month, sizeof month,"%B",filetime);
***************
*** 484,490 ****
putchar('\n');
#endif
! printf(".SH NAME\n%s \\- ",declarator->name);
#if 0
for (s = declarator->text; *s && *s != '(';s++)
--- 390,396 ----
putchar('\n');
#endif
! printf(".SH NAME\n.B %s\n\\- ",declarator->name);
#if 0
for (s = declarator->text; *s && *s != '(';s++)
***************
*** 495,501 ****
printf(".SH SYNOPSIS\n");
! put_string(".nf\n");
/* if it's a header file, say to #include it */
if (header_file())
--- 401,407 ----
printf(".SH SYNOPSIS\n");
! put_string(".nf\n\\fB");
/* if it's a header file, say to #include it */
if (header_file())
***************
*** 516,522 ****
output_decl_spec(decl_spec);
put_string(declarator_prefix);
output_declarator(declarator, TRUE); /* format it nicely */
! put_string(";\n.fi\n");
/* only output paramaters if there actually are some,
* not including merely (void)
--- 422,428 ----
output_decl_spec(decl_spec);
put_string(declarator_prefix);
output_declarator(declarator, TRUE); /* format it nicely */
! put_string(";\\fR\n.fi\n");
/* only output paramaters if there actually are some,
* not including merely (void)
***************
*** 550,577 ****
{
ManualPage *page;
extern char *output_dir;
!
/* output each page, in turn */
for (page = first; page; page = page->next)
{
ManualPage *also;
! char *filename;
! /* open the output file */
! if (output_dir)
! filename = strconcat(output_dir,"/",
page->declarator->name,".",section,NULL);
! else
! filename = strconcat(page->declarator->name,".",section,NULL);
! fprintf(stderr,"generating: %s\n",filename);
! if (freopen(filename, "w", stdout) == NULL)
! {
! free(filename);
! perror(filename);
! exit(1);
}
!
/* do the page itself */
output_manpage(page->decl_spec,page->declarator);
--- 456,487 ----
{
ManualPage *page;
extern char *output_dir;
! int tostdout = output_dir && !strcmp(output_dir,"-");
!
/* output each page, in turn */
for (page = first; page; page = page->next)
{
ManualPage *also;
! char *filename = NULL;
! if (!tostdout)
! {
! /* open the output file */
! if (output_dir)
! filename = strconcat(output_dir,"/",
page->declarator->name,".",section,NULL);
! else
! filename = strconcat(page->declarator->name,".",section,NULL);
! fprintf(stderr,"generating: %s\n",filename);
! if (freopen(filename, "w", stdout) == NULL)
! {
! free(filename);
! perror(filename);
! exit(1);
! }
}
!
/* do the page itself */
output_manpage(page->decl_spec,page->declarator);
***************
*** 599,605 ****
putchar('\n');
}
! free(filename);
}
- fclose(stdout);
}
--- 509,520 ----
putchar('\n');
}
!
! if (tostdout)
! {
! if (page->next) putchar('\f');
! }
! else
! free(filename);
}
}
*** 1.2 1992/07/17 06:41:33
--- semantic.c 1992/07/28 06:35:23
***************
*** 1,4 ****
! /* $Id: semantic.c,v 1.2 1992/07/17 06:41:33 greyham Exp $
*
* C manual page generator
* These routines implement the semantic actions executed by the yacc parser.
--- 1,4 ----
! /* $Id: semantic.c,v 1.3 1992/07/21 11:47:42 greyham Exp $
*
* C manual page generator
* These routines implement the semantic actions executed by the yacc parser.
***************
*** 387,393 ****
decl_spec_text = decl_spec->text;
if (promote_param && strcmp(d->text, d->name) == 0) {
! s = rindex(decl_spec_text, ' ');
s = (s != NULL) ? s+1 : decl_spec_text;
if (strcmp(s, "char") == 0 || strcmp(s, "short") == 0)
decl_spec_text = "int";
--- 387,393 ----
decl_spec_text = decl_spec->text;
if (promote_param && strcmp(d->text, d->name) == 0) {
! s = strrchr(decl_spec_text, ' ');
s = (s != NULL) ? s+1 : decl_spec_text;
if (strcmp(s, "char") == 0 || strcmp(s, "short") == 0)
decl_spec_text = "int";
*** 1.3 1992/07/17 06:41:33
--- string.c 1992/07/28 06:35:24
***************
*** 1,4 ****
! /* $Id: string.c,v 1.3 1992/07/17 06:41:33 greyham Exp $
*
* Some string handling routines
*/
--- 1,4 ----
! /* $Id: string.c,v 1.4 1992/07/21 11:47:42 greyham Exp $
*
* Some string handling routines
*/
***************
*** 34,44 ****
int keylen;
keylen = strlen(key);
! s = index(src, *key);
while (s != NULL) {
if (strncmp(s, key, keylen) == 0)
return s;
! s = index(s+1, *key);
}
return NULL;
}
--- 34,44 ----
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;
}
--
Graham Stoney | "a Perl script is correct if it's halfway
Flip Dibner fan club, "Hi Flip!" | readable and gets the job done before your
Ph: +61 2 805-2909 Fax: -2929 | boss fires you." L. Wall & R. Schwartz
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads