Article View: comp.sources.reviewed
Article #10v02i041: cextract - (Ver. 1.7) C prototyper/header file generator, Part03/05
From: Adam Bryant
Date: Tue, 03 Nov 1992 22:11
Date: Tue, 03 Nov 1992 22:11
939 lines
28365 bytes
28365 bytes
Submitted-by: Adam Bryant <adb@cs.bu.edu>
Posting-number: Volume 2, Issue 41
Archive-name: cextract/part03
Supersedes: cextract: Volume 1, Issue 4-8
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 3 (of 5)."
# Contents: main.c
# Wrapped by adb@csa on Fri Oct 30 16:20:36 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'main.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'main.c'\"
else
echo shar: Extracting \"'main.c'\" \(24410 characters\)
sed "s/^X//" >'main.c' <<'END_OF_FILE'
X/*
X *
X * The purpose of this program is to extract the function descriptions
X * (prototypes) from C source code. It also provides for the creation
X * of documentation based on those prototypes.
X *
X * The specific reason for the creation of this program was to
X * provide a method for automatically creating header files to
X * describe all of the functions to be used within a multi-file
X * program.
X *
X * This file makes use of code in the companion files parse.c and io.c.
X *
X * Copyright (c) 1990, 1991, 1992 by Adam Bryant
X *
X * See Copyright notice in the file parse.c or in the manual page.
X *
X */
X/*
X * Version history:
X *
X * For Version 0.30: file parse functions were separated out into a
X * separate file so that other programs could make use of them. The
X * functions descriptions are now stored in dynamic memory and
X * functions are provided to allow the manipulation of those
X * descriptions.
X * Version 0.31: Only a few minor adjustments were made to cextract...
X * only as much as was needed to build the cextdoc program using the
X * cproto.[ch] files.
X * Version 0.40: Totally rewrote the parsing code so that the use of
X * temporary files is unnecessary. Instead, two dynamic storage
X * elements have been created. Besides being much faster, this
X * method is also much more elegant than the prior method.
X * Version 0.41: Switched the NOSETBUFFER to a SETBUFFER flag.
X * Added in the ability to handle the vararg system to convert it
X * to the "..." for ANSI C.
X *
X * ... change notes for later versions in parse.c
X *
X * Note on Version 1.0: merged the cextract and cextdoc into one
X * program, with differential being made based on the command line
X * or in the program name. Version sent to comp.sources.reviewed.
X *
X */
X#include "xtract.h"
X#ifndef VMS
X#include <sys/types.h>
X#include <sys/stat.h>
X#else
X#include <types.h>
X#include <stat.h>
X#endif /* VMS */
X
X/* definition strings to be set when the C preprocessor runs */
X#ifndef VAXC
X#define CPP_GIVEN "-D__CEXTRACT__"
X#define CPP_GIVEN2 "-D__CEXTDOC__"
X#else
X#define CPP_GIVEN "/define=__CEXTRACT__"
X#define CPP_GIVEN2 "/define=__CEXTDOC__"
X#endif /* VAXC */
X
X/* output filter from the parsing routines */
Xvoid
Xout_char(type, outch)
X int type, outch;
X{
X /* to keep track of where the output list is */
X int tab_width = get_option(OPT_TABWIDTH);
X static P_BUFDATA curbuf[2] = { NULL, NULL };
X static int curpos[2] = { 0, 0 };
X static int tab_count = 0;
X
X /* split output properly */
X switch (type) {
X case 0:
X /* documentation mode should never get this */
X if (doc_extract != DOC_NONE) {
X fprintf(stderr, "Serious Internal Error: bad out_char() data\n");
X exit(1);
X }
X case 1:
X /* give it to the first one */
X if (tempbuf[type] == NULL) {
X
X /* start the list */
X if ((tempbuf[type] = (P_BUFDATA) malloc(sizeof(S_BUFDATA))) == NULL) {
X fprintf(stderr, "Memory Allocation Error\n");
X exit(1);
X }
X tempbuf[type]->next = NULL;
X curbuf[type] = tempbuf[type];
X }
X
X /* have we got enough in this one? */
X if (curpos[type] == MID_SIZE) {
X
X /* finish it off */
X build_memory:
X curbuf[type]->data[MID_SIZE] = '\0';
X curpos[type] = 0;
X
X /* start the next one */
X if ((curbuf[type]->next =
X (P_BUFDATA) malloc(sizeof(S_BUFDATA))) == NULL) {
X fprintf(stderr, "Memory Allocation Error\n");
X exit(1);
X }
X curbuf[type] = curbuf[type]->next;
X curbuf[type]->next = NULL;
X
X }
X
X /* special output filter for the documentation mode */
X if (doc_extract != DOC_NONE) {
X
X /* tab expansion? */
X if (tab_width > 0) {
X if (outch == '\t') {
X /* fill out tabs properly */
X while (tab_count++ < tab_width) {
X
X /* check that it will fit */
X if (curpos[type] == MID_SIZE) {
X tab_count--;
X goto build_memory;
X }
X
X /* put out the space */
X curbuf[type]->data[(curpos[type])++] = ' ';
X
X }
X tab_count = 0;
X break;
X } else if (outch == '\\') {
X /* account for font changes */
X tab_count -= 2;
X } else if (outch == '\n') {
X /* now on a new line */
X tab_count = 0;
X } else {
X /* just count */
X if (++tab_count == tab_width) {
X tab_count = 0;
X }
X }
X }
X
X }
X
X /* now store it */
X curbuf[type]->data[(curpos[type])++] = outch;
X break;
X case -1:
X /* close everything up */
X if (curbuf[0] != NULL) {
X curbuf[0]->data[curpos[0]] = '\0';
X }
X if (curbuf[1] != NULL) {
X curbuf[1]->data[curpos[1]] = '\0';
X }
X break;
X default:
X /* ain't one of mine */
X fprintf(stderr, "Serious Internal Error: bad data to out_char()\n");
X break;
X }
X
X}
X
X/* show the version of the program */
Xvoid
Xshow_version ()
X{
X fprintf(stderr, "%s: version %d.%d, Copyright 1992 by Adam Bryant\n",
X prog_name, VERSION, PATCHLEVEL);
X}
X
X/* quickly show a sting and indicate if it is on or off */
Xstatic void
Xquick_show (str, mode)
X char *str;
X int mode;
X{
X fprintf(stderr, "\t%s is %s.\n", str, mode ? "on":"off");
X}
X
X/* show all of the settings */
Xvoid
Xshow_settings ()
X{
X P_MACRO macro_temp;
X P_SUBST sub_tmp;
X
X /* give the version info and current settings */
X show_version();
X fprintf(stderr, "\n List of current settings:\n");
X fprintf(stderr, "\tC preprocessor in use: %s\n", cpp_prog);
X switch (doc_extract) {
X case DOC_NONE:
X fprintf(stderr, "\tfunction prototype extraction mode.\n");
X if (output_file[0][0] != '\0') {
X fprintf(stderr, "\tthe output file is \"%s\".\n", output_file[0]);
X }
X if (header_string[0] != '\0') {
X fprintf(stderr, "\tthe header string is \"%s\".\n", header_string);
X }
X quick_show("merged ANSI and K&R C output", get_option(OPT_COMPACT));
X if (!get_option(OPT_COMPACT)) {
X quick_show("showing both ANSI and K&R C", get_option(OPT_BOTHUSE));
X if (!get_option(OPT_BOTHUSE)) {
X quick_show("ANSI C output format", get_option(OPT_STDCUSE));
X }
X }
X quick_show("showing prototypes at all times", get_option(OPT_SHOWANYWAY));
X break;
X case DOC_NORMAL:
X fprintf(stderr, "\ttext documentation mode.\n");
X if (output_file[1][0] != '\0') {
X fprintf(stderr, "\tthe output file is \"%s\".\n", output_file[1]);
X }
X break;
X case DOC_ROFF:
X fprintf(stderr, "\ttroff documentation mode.\n");
X if (output_file[1][0] != '\0') {
X fprintf(stderr, "\tthe output file is \"%s\".\n", output_file[1]);
X }
X break;
X default:
X fprintf(stderr, "\tError, unknown mode.\n\n");
X exit(1);
X break;
X }
X if (get_option(OPT_SORTMODE) == SORT_ALL) {
X quick_show("sorting for all functions", TRUE);
X } else if (get_option(OPT_SORTMODE) == SORT_FILE) {
X quick_show("sorting for each file", TRUE);
X } else {
X quick_show("sorting", FALSE);
X }
X if (get_option(OPT_WRAPPOINT) > 0) {
X fprintf(stderr, "\tlong prototype lists wrap at column %d.\n",
X get_option(OPT_WRAPPOINT));
X } else {
X quick_show("wrapping of long prototypes", FALSE);
X }
X quick_show("separating function name and type", get_option(OPT_TYPEWRAP));
X quick_show("showing first comment in each file",
X get_option(OPT_FIRSTCOMMENT));
X quick_show("sending file name with first comment",
X get_option(OPT_PREPEND));
X quick_show("comment capturing", get_option(OPT_COMMENTS));
X if (get_option(OPT_STATICMODE) == ONLY_STATICS) {
X quick_show("only static functions are searched for", TRUE);
X } else {
X quick_show("including static functions in search",
X get_option(OPT_STATICMODE) == ANY_STATICS);
X }
X quick_show("prepending extern to function declarations",
X get_option(OPT_EXTERNS));
X quick_show("testing for multi-line comments",
X !get_option(OPT_SINGLECOMMENTS));
X
X /* now show all of the macro definitions */
X if (macro_list != NULL) {
X fprintf(stderr, "\n List of preprocessor definitions:\n");
X for (macro_temp = macro_list;
X macro_temp != NULL;
X macro_temp = macro_temp->next) {
X /* use? */
X if ((macro_temp->usewhen != 2) &&
X (macro_temp->usewhen != (doc_extract != DOC_NONE))) continue;
X fprintf(stderr, "\t%s\n", macro_temp->m_str);
X }
X }
X
X /* now check the substitutions */
X if (subst_list != NULL) {
X fprintf(stderr, "\n List of prototype substitutions:\n");
X for (sub_tmp = subst_list;
X sub_tmp != NULL;
X sub_tmp = sub_tmp->next) {
X /* used? */
X if ((sub_tmp->usewhen != 2) &&
X (sub_tmp->usewhen != (doc_extract != DOC_NONE))) continue;
X
X /* check it */
X switch (sub_tmp->submode) {
X case SUBST_FULL:
X /* the full string needs replacing? */
X fprintf(stderr, "\treplace all \"%s\" with \"%s\"\n",
X sub_tmp->from_str, sub_tmp->to_str);
X break;
X case SUBST_TYPE:
X /* the type only needs replacing? */
X fprintf(stderr, "\treplace type \"%s\" with \"%s\"\n",
X sub_tmp->from_str, sub_tmp->to_str);
X break;
X case SUBST_NAME:
X /* the variable only needs replacing? WHY!? */
X fprintf(stderr, "\treplace name \"%s\" with \"%s\"\n",
X sub_tmp->from_str, sub_tmp->to_str);
X break;
X }
X }
X }
X
X /* all done */
X fprintf(stderr, "\n");
X exit(0);
X}
X
X/* quick function to copy a "string" */
Xint
Xcopy_str (o_str, in_str)
X char *o_str, *in_str;
X{
X int ch, count = 0, ch_read = 0;
X
X /* find the beginning of the string */
X while ((*in_str != '"') &&
X (*in_str != '\0')) {
X ch_read++;
X in_str++;
X }
X
X /* now was a string found? */
X if (*in_str == '\0') {
X return(-1);
X }
X ch_read++;
X in_str++;
X
X /* copy all of the string */
X while (((ch = *(in_str)) != '\0') &&
X (ch != '"')) {
X /* copy it */
X o_str[count++] = ch;
X ch_read++;
X in_str++;
X }
X if (ch == '"') ch_read++;
X
X /* finish up and get out */
X o_str[count] = '\0';
X return(ch_read);
X}
X
X/* show the usage for the program */
Xvoid
Xshow_usage()
X{
X#ifndef VMS
X fprintf(stderr,
X "Usage: %s [-Q#] [+AaBbPpNnVvxZ -Hstr -Yprg -o ofile] [[-opts] file ... ]\n",
X prog_name);
X fprintf(stderr, "\t+A alphabetically sort all functions [incompatable with +C]\n");
X fprintf(stderr, "\t+a alphabetically sort functions within each file [default off]\n");
X fprintf(stderr, "\t-B build a system configuration file based on settings\n");
X fprintf(stderr, "\t-b build a configuration file in the current directory\n");
X fprintf(stderr, "\t+C include first comment from each file\n");
X fprintf(stderr, "\t+c include comments immediately preceding functions\n");
X fprintf(stderr, "\t-Dexpr send a macro definition to the C preprocessor\n");
X fprintf(stderr, "\t+E add a preceding 'extern' to each function definition\n");
X fprintf(stderr, "\t+F toggle prepending of file name to first comment [need +C]\n");
X fprintf(stderr, "\t-f#cc in troff doc-mode set various font styles\n");
X fprintf(stderr, "\t-Hstring build header file with read test on string\n");
X fprintf(stderr, "\t-Idir add directory to search list for include files\n");
X fprintf(stderr, "\t-o file send output to a file instead of standard output\n");
X fprintf(stderr, "\t [take first non-flag as filename for output]\n");
X fprintf(stderr, "\t+m allow multi-line comments when parsing comments\n");
X fprintf(stderr, "\t-N do documentation output in troff ms format\n");
X fprintf(stderr, "\t-n do documentation output in normal text\n");
X fprintf(stderr, "\t+P create output in both ANSI and non-ANSI prototypes\n");
X fprintf(stderr, "\t+p create output in ANSI C prototype format\n");
X fprintf(stderr, "\t-Q# do not read in config files, or only those specified\n");
X fprintf(stderr, "\t-qfile read in a specified configuration file\n");
X fprintf(stderr, "\t+r remove variable names prior to output\n");
X fprintf(stderr, "\t+S show parameters for non-ANSI portion of output\n");
X fprintf(stderr, "\t+s include static function definitions\n");
X fprintf(stderr, "\t-s=only capture only static function definitions\n");
X fprintf(stderr, "\t-s=none exclude static function definitions\n");
X fprintf(stderr, "\t-s=any include static function definitions\n");
X fprintf(stderr, "\t-TN set tab width in doc-mode to N characters [0 = off]\n");
X fprintf(stderr, "\t-Uname undefine the given macro name\n");
X fprintf(stderr, "\t-V display the program settings then exit\n");
X fprintf(stderr, "\t-v display version information then exit\n");
X fprintf(stderr, "\t+W place function type on a separate line.\n");
X fprintf(stderr, "\t+w# wrap long parameter output [dflt length 72]\n");
X fprintf(stderr, "\t-x run program in extraction mode\n");
X fprintf(stderr, "\t-Yprog specify program to use as a C preprocessor\n");
X fprintf(stderr, "\t+Z create the output as a compact, merged list\n");
X#else /* VMS */
X fprintf(stderr, "USAGE: %s [/READ-CONFIG=#] [/OUTPUT=outfile] [[/OPTS] FILE ... ]\n",
X prog_name);
X#endif /* VMS */
X exit(1);
X}
X
X/* set the value of a global option */
Xvoid
Xset_option(which, how, value)
X Optype which;
X int how, value;
X{
X#ifdef CHECK_INPUTS
X /* check input values */
X if ((which < 0) ||
X (which >= OPT_NUMBER)) {
X fprintf(stderr, "SERIOUS ERROR: Internal option value out of range %d\n",
X which);
X exit(1);
X }
X if ((how < 0) ||
X (how > 2)) {
X fprintf(stderr, "SERIOUS ERROR: Internal option method out of range %d\n",
X how);
X exit(1);
X }
X#endif /* CHECK_INPUTS */
X
X /* now set properly */
X if (how == 2) {
X global_opts[0][which] = value;
X global_opts[1][which] = value;
X } else {
X global_opts[how][which] = value;
X }
X}
X
X/* retrieve the value of a global option */
Xint
Xget_option(which)
X Optype which;
X{
X#ifdef CHECK_INPUTS
X /* check input values */
X if ((which < 0) ||
X (which >= OPT_NUMBER)) {
X fprintf(stderr, "SERIOUS ERROR: Internal option value out of range %d\n",
X which);
X exit(1);
X }
X#endif /* CHECK_INPUTS */
X
X /* return whichever setting is needed */
X if (doc_extract == DOC_NONE) {
X return(global_opts[0][which]);
X }
X return(global_opts[1][which]);
X}
X
X/* set configuration settings based on the initial name */
Xstatic void
Xcext_init()
X{
X /* enter the proper mode */
X if (strncmp(CEXTDOC_NAME, prog_name, strlen(prog_name)) == 0) {
X doc_extract = DOC_NORMAL;
X } else {
X doc_extract = DOC_NONE;
X }
X
X /* set documentation mode options properly */
X set_option(OPT_COMMENTS, 1, TRUE);
X set_option(OPT_STATICMODE, 1, ANY_STATICS);
X set_option(OPT_EXTERNS, 1, FALSE);
X set_option(OPT_STDCUSE, 1, TRUE);
X set_option(OPT_SORTMODE, 1, SORT_FILE);
X
X /* set extraction mode options now */
X set_option(OPT_COMMENTS, 0, FALSE);
X set_option(OPT_STATICMODE, 0, NO_STATICS);
X set_option(OPT_EXTERNS, 0, TRUE);
X set_option(OPT_STDCUSE, 0, FALSE);
X set_option(OPT_SORTMODE, 0, SORT_NONE);
X
X /* now set common options */
X set_option(OPT_NONAMES, 2, FALSE);
X set_option(OPT_COMPACT, 2, FALSE);
X set_option(OPT_TYPEWRAP, 2, FALSE);
X set_option(OPT_WRAPPOINT, 2, 0);
X set_option(OPT_BOTHUSE, 2, TRUE);
X set_option(OPT_SINGLECOMMENTS, 2, TRUE);
X set_option(OPT_FIRSTCOMMENT, 2, FALSE);
X set_option(OPT_SHOWANYWAY, 2, TRUE);
X set_option(OPT_PREPEND, 2, FALSE);
X set_option(OPT_TABWIDTH, 2, 8);
X}
X
X/* return FALSE if character is not a normal part of a filename */
Xint
Xfname_char(ch)
X int ch;
X{
X switch (ch) {
X#ifdef MS_DOS
X case '\\':
X#endif /* MS_DOS */
X#ifdef VMS
X case ']':
X case ':':
X#endif /* VMS */
X case '/':
X /* nope */
X return(FALSE);
X }
X return(TRUE);
X}
X
X/* routine to build the macros onto the prototype line */
Xstatic void
Xappend_macros(str_out)
X char *str_out;
X{
X P_MACRO macro_temp;
X
X#ifndef VAXC
X for (macro_temp = macro_list;
X macro_temp != NULL;
X macro_temp = macro_temp->next) {
X
X /* check for use */
X if ((macro_temp->usewhen != 2) &&
X (macro_temp->usewhen != (doc_extract != DOC_NONE))) continue;
X
X /* use it */
X strcat(str_out, macro_temp->m_str);
X strcat(str_out, " ");
X
X }
X#else
X char und_str[MID_SIZE], def_str[MID_SIZE], inc_str[MID_SIZE];
X int und_uses = 0, def_uses = 0, inc_uses = 0;
X int und_len = strlen(UNDEF_LEADER);
X int inc_len = strlen(UNDEF_LEADER);
X int def_len = strlen(DEF_LEADER);
X
X /* initialize */
X und_str[0] = '\0';
X def_str[0] = '\0';
X inc_str[0] = '\0';
X
X /* properly build the command line for the C compiler */
X for (macro_temp = macro_list;
X macro_temp != NULL;
X macro_temp = macro_temp->next) {
X
X /* check for use */
X if ((macro_temp->usewhen != 2) &&
X (macro_temp->usewhen != (doc_extract != DOC_NONE))) continue;
X
X /* check for the definition statement */
X if (strncmp(DEF_LEADER, macro_temp->m_str, def_len) == 0) {
X if (def_uses++ > 0) {
X strcat(def_str, ",");
X }
X if (macro_temp->m_str[def_len] == '(') {
X strcat(def_str, macro_temp->m_str + def_len + 1);
X def_str[strlen(def_str) - 1] = '\0';
X def_uses++;
X } else {
X strcat(def_str, macro_temp->m_str + def_len);
X }
X } else if (strncmp(UNDEF_LEADER, macro_temp->m_str, und_len) == 0) {
X if (und_uses++ > 0) {
X strcat(und_str, ",");
X }
X if (macro_temp->m_str[und_len] == '(') {
X strcat(und_str, macro_temp->m_str + und_len + 1);
X und_str[strlen(und_str) - 1] = '\0';
X def_uses++;
X } else {
X strcat(und_str, macro_temp->m_str + und_len);
X }
X } else if (strncmp(INC_LEADER, macro_temp->m_str, inc_len) == 0) {
X if (inc_uses++ > 0) {
X strcat(inc_str, ",");
X }
X if (macro_temp->m_str[inc_len] == '(') {
X strcat(inc_str, macro_temp->m_str + inc_len + 1);
X und_str[strlen(inc_str) - 1] = '\0';
X def_uses++;
X } else {
X strcat(inc_str, macro_temp->m_str + inc_len);
X }
X } else {
X strcat(str_out, macro_temp->m_str);
X }
X
X }
X
X /* now finish everything off */
X if (def_uses > 0) {
X strcat(str_out, DEF_LEADER);
X if (def_uses > 1) strcat(str_out, "(");
X strcat(str_out, def_str);
X if (def_uses > 1) strcat(str_out, ")");
X }
X if (und_uses > 0) {
X strcat(str_out, UNDEF_LEADER);
X if (und_uses > 1) strcat(str_out, "(");
X strcat(str_out, und_str);
X if (und_uses > 1) strcat(str_out, ")");
X }
X if (inc_uses > 0) {
X strcat(str_out, INC_LEADER);
X if (inc_uses > 1) strcat(str_out, "(");
X strcat(str_out, inc_str);
X if (inc_uses > 1) strcat(str_out, ")");
X }
X strcat(str_out, " ");
X#endif /* VAXC */
X}
X
X/* control program flow and command line options */
Xint
Xmain (argc, argv)
X int argc;
X char **argv;
X{
X char cur_argstr[MID_SIZE], sysl_out[MID_SIZE];
X extern int getpid();
X struct stat fst;
X int count, j, len;
X
X /* initialize some things */
X fpout = stdout;
X len = strlen(argv[0]);
X for (j = len - 1; j > 0; j--) {
X if (fname_char(argv[0][j]) == FALSE) {
X j++;
X break;
X }
X }
X strcpy(prog_name, &(argv[0][j]));
X out_filenum = 0;
X start_comment[0] = '\0';
X header_string[0] = '\0';
X cur_cfg_file[0] = '\0';
X output_file[0][0] = '\0';
X output_file[1][0] = '\0';
X cfg_file[0] = '\0';
X sprintf(cpp_prog, "%s %s", CPP, CPP_COMMENTS);
X macro_list = last_macro = NULL;
X cext_init();
X
X /* check for config file flags */
X count = 1;
X if ((count < argc) &&
X is_switch(argv[count][0])) {
X
X#ifndef VMS
X /* are we skipping config files? */
X if (argv[count][1] == 'Q') {
X
X /* check the type */
X if (isdigit(argv[count][2])) {
X cfg_switch = argv[count][2] - '0';
X if ((cfg_switch < 0) ||
X (cfg_switch > 7) ||
X (argv[count][3] != '\0')) {
X fprintf(stderr, "Invalid value for -Q flag\n");
X show_usage();
X }
X } else if (argv[count][2] != '\0') {
X fprintf(stderr, "Invalid data following the -Q flag\n");
X show_usage();
X } else {
X cfg_switch = 0;
X }
X
X /* processed this one */
X count++;
X } else {
X#endif /* VMS */
X
X /* now test for full length string */
X if (minmatch_str(&(argv[count][1]), "read-config", 4)) {
X len = strlen(argv[count]);
X for (j = 4; j < len; j++) {
X if ((argv[count][j] == ':') ||
X (argv[count][j] == '=')) {
X j++;
X break;
X }
X }
X if (j == len) {
X cfg_switch = 0;
X } else if (isdigit(argv[count][j])) {
X cfg_switch = argv[count][j] - '0';
X if ((cfg_switch < 0) ||
X (cfg_switch > 7) ||
X (argv[count][j + 1] != '\0')) {
X fprintf(stderr, "Invalid value for -read-config flag\n");
X show_usage();
X }
X } else {
X fprintf(stderr, "Invalid data following the -read-config flag\n");
X show_usage();
X }
X count++;
X }
X
X#ifndef VMS
X }
X#endif /* VMS */
X }
X
X /* now do the configurations */
X add_macro(2, CPP_GIVEN);
X add_macro(1, CPP_GIVEN2);
X do_config();
X
X /* go through the entire argument list */
X while (count < argc) {
X
X /* check for any switches */
X if (is_switch(argv[count][0])) {
X
X /* call the routine for command line parsing */
X if (argv[count][0] == '-') {
X j = FALSE;
X } else {
X j = TRUE;
X }
X strcpy(cur_argstr, &(argv[count][1]));
X parse_cmd(cur_argstr, j, TRUE);
X
X } else {
X
X /* treat it as a file name */
X if (out_filenum == 1) {
X
X /* store the output file name */
X strcpy(output_file[0], argv[count]);
X strcpy(output_file[1], argv[count]);
X out_filenum = 2;
X
X } else {
X
X /* check if both C and A are on */
X if (get_option(OPT_FIRSTCOMMENT) &&
X (get_option(OPT_SORTMODE) == SORT_ALL)) {
X fprintf(stderr, "Sorting all functions and displaying file names does not mix\n");
X show_usage();
X }
X
X /* yes, a file has been parsed */
X out_filenum = 3;
X
X /* process the file for input */
X strcpy(file_name, argv[count]);
X strcpy(errout_filename, file_name);
X line_count = 1;
X
X /* check if the file exits */
X if (stat( file_name, &fst ) != 0) {
X sprintf(cur_argstr, "error: could not access file <%s>",
X file_name);
X err_msg(cur_argstr);
X exit(1);
X } else if ((fpin = fopen(file_name, "r")) == NULL) {
X sprintf(cur_argstr, "error: could not read file <%s>",
X file_name);
X err_msg(cur_argstr);
X exit(1);
X }
X fclose(fpin);
X
X /* build /lib/cpp line */
X sprintf(sysl_out, "%s ", cpp_prog);
X append_macros(sysl_out);
X strcat(sysl_out, file_name);
X
X /* open it */
X if ((fpin = open_input(sysl_out, "r")) == NULL) {
X sprintf(tmp_str, "unable to open CPP \"pipe\" to file <%s>",
X file_name);
X err_msg(tmp_str);
X exit(1);
X }
X
X#ifdef SETBUFFER
X /* now set the buffer */
X setbuffer(fpin, inbuffer, BUFFER_SIZE);
X#endif /* SETBUFFER */
X
X /* now do it */
X parse_file();
X files_parsed++;
X if (get_option(OPT_SORTMODE) != SORT_ALL) {
X send_file();
X }
X close_input(fpin);
X
X }
X
X }
X
X /* now go to the next argument */
X count++;
X }
X
X /* check if -o flag is unprocessed */
X if (out_filenum == 1) {
X fprintf(stderr, "No output file specified\n");
X show_usage();
X }
X if ((out_filenum == 2) || (out_filenum == 0)) {
X fprintf(stderr, "No files for parsing specified\n");
X show_usage();
X }
X
X /* send out everything, if it hasn't been done */
X if (get_option(OPT_SORTMODE) == SORT_ALL) {
X send_file();
X }
X
X /* now close things up and combine if needed */
X cxt_close();
X exit(0);
X return(0);
X}
X
X/* transmit the currently stored comment to the output file */
Xvoid
Xsend_first_comment(begin_str)
X char *begin_str;
X{
X int mode;
X
X /* check for last comment */
X if (start_comment[0] != '\0') {
X
X /* check the mode */
X if (doc_extract == DOC_NONE) {
X mode = 0;
X } else {
X mode = 1;
X }
X
X /* give the header for troff output */
X dont_space = FALSE;
X if (doc_extract == DOC_ROFF) {
X start_block = TRUE;
X init_roff(1);
X if (total_out > 0) {
X out_str(1, ".bp\n");
X out_str(1, ".sp 0.5i\n");
X }
X out_str(1, ".KS\n");
X out_str(1, ".nf\n");
X out_str(1, ".ft 2\n");
X } else {
X out_char(mode, '\n');
X }
X
X /* duplicate if needed */
X if (!get_option(OPT_COMPACT) &&
X (doc_extract == DOC_NONE) &&
X (get_option(OPT_SHOWANYWAY) &&
X get_option(OPT_BOTHUSE))) {
X out_char(1, '\n');
X out_str(0, begin_str);
X out_str(1, begin_str);
X out_str(0, start_comment);
X out_str(1, start_comment);
X out_char(0, '\n');
X out_char(1, '\n');
X } else {
X out_str(mode, begin_str);
X out_str(mode, start_comment);
X out_char(mode, '\n');
X }
X
X }
X}
X
X#ifdef TEST
X/* dummy function that will never be used but makes a nice test */
Xchar (*(*test_it())[])(same_foo, x, y, fpfoo, z, fpp2)
X int *x, z;
X FILE* fpfoo, fpp2;
X char (*(*same_foo())[])();
X int *y;
X{
X /* As scary a bit of code as I could think of. Is it valid? */
X}
X#endif /*TEST*/
END_OF_FILE
if test 24410 -ne `wc -c <'main.c'`; then
echo shar: \"'main.c'\" unpacked with wrong size!
fi
# end of 'main.c'
fi
echo shar: End of archive 3 \(of 5\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 5 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
exit 0 # Just in case...
--
Andrew Patrick acting as Comp.Sources.Reviewed Moderator
Department of Communications, Ottawa, CANADA
csr@calvin.dgbt.doc.CA
Technical Details
Message-ID:
<1992Nov3.221136.16892@rick.dgbt.doc.ca>Path:
arc1-ca.pugleaf.net!sparky!uunet!utcsri!torn!cunews!dgbt!rick.dgbt.doc.ca!calvin.dgbt.doc.ca!csrShow Full Headers
Complete Article Headers
Newsgroups: comp.sources.reviewed Path: arc1-ca.pugleaf.net!sparky!uunet!utcsri!torn!cunews!dgbt!rick.dgbt.doc.ca!calvin.dgbt.doc.ca!csr From: Adam Bryant <adb@cs.bu.edu> Subject: v02i041: cextract - (Ver. 1.7) C prototyper/header file generator, Part03/05 Message-ID: <1992Nov3.221136.16892@rick.dgbt.doc.ca> Originator: csr@calvin.dgbt.doc.ca Sender: news@rick.dgbt.doc.ca Nntp-Posting-Host: calvin.dgbt.doc.ca Organization: Communications Research Centre, Ottawa Date: Tue, 3 Nov 1992 22:11:36 GMT Approved: csr@calvin.dgbt.doc.ca Lines: 939