home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
reviewed
/
volume01
/
cextract
/
part03
< prev
next >
Wrap
Internet Message Format
|
1991-07-08
|
56KB
From: adb@cs.bu.edu (Adam Bryant)
Subject: C prototyper / header file generator
#!/bin/sh
# This is part 03 of a multipart archive
# ============= parse.c ==============
if test -f 'parse.c' -a X"$1" != X"-c"; then
echo 'x - skipping parse.c (File already exists)'
else
echo 'x - extracting parse.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parse.c' &&
/*
X *
X * main parsing routines for the cextract/cextdoc programs.
X * Also includes a number of generic routines applicable to both.
X *
X * These routines provide the methods used to extract comments,
X * prototypes and function names from C source files.
X *
X * Copyright (c) 1990, 1991 by Adam Bryant
X *
X * The only restrictions on the use of these routines is that they not
X * be used for monetary gain, and that this copyright notice be left
X * intact.
X *
X * Note: These programs may be freely used to extract code and/or
X * documentation at proprietary/corporate sites, as long as the
X * actual source code is not used within any proprietary code.
X */
/*
X * Version history:
X *
X * Changes for Version 0.40 of both cextract and cextdoc:
X * - implemented new out_char() interface.
X * - first comments will not be shown if no functions exist.
X * - implemented concatenation of comments.
X * - implemented troff output for cextdoc portion.
X *
X * Changes for Version 0.41 of both cextract and cextdoc:
X * - switched the NO_SETBUFFER to SETBUFFER, making non-use standard.
X * - added in the DO_VARARGS code to automatically account for the
X * the variable argument setup in parsing.
X *
X * Changes for Version 0.42 of both:
X * - made the DO_VARARGS code the default. (removed #ifdefs)
X *
X * Changes for Version 0.50 (1/18/91) of both:
X * - added the configuration file code.
X * - removed much of the DEBUG print statements from stable code.
X * - made the bad syntax encounters exit the program.
X *
X * Changes for Version 0.51 (1/21/91) of both:
X * - implemented code to allow compilation on VAX VMS systems.
X *
X * Changes for Version 0.60 (4/15/91) of both:
X * - more VMS stuff, and addition of files: patchlevel.h,
X * README, and INSTALL.
X * - removed all other DEBUG statements.
X * - left the SETBUFFER code in place, but removed mention
X * of it from the Makefile, since there was no noticable
X * speed enhancement through its use.
X * - upgraded to version 6.0 for release to comp.sources.reviewed.
X *
X * Changes for Version 1.0 (4/17/91-5/3/91) of both:
X * - removed most system definitions from cproto.h and replaced
X * with more includes of system header files. But, there are
X * still a number of system functions which are not in the header
X * files on at least Sun systems.
X * - now use the "is_switch()" function to parse the command line
X * arguments. This allowed me to use both '-' and '/' on VMS
X * systems to avoid confusion in the manual pages.
X * - simplified the Makefile, especially for the "make install".
X * - fixed various mispellings/misphrasings in error messages.
X * - checked the argument in calls to free() within pop_proto().
X * - configuration files will be checked for in the following order:
X * system file, home directory, current directory.
X * any encountered will be read in. This will allow overriding
X * of customization options in a logical order.
X * - implemented switch to control how the config files are read in.
X * - redid the manual pages and split out the customization section
X * into its own manual page.
X * - adjusted the comment capturing code to assure that it doesn't
X * misassign comments to the wrong functions.
X * - fixed one minor memory leak.
X * - adjust system configuration file locations.
X * - redid VMS popen() and pclose() to assure unique temporary file.
X * - added in an "err_msg()" routine to call perror() if it exits.
X * - made sure to check return value of all calls to fputs().
X * - merged "cextdoc" into "cextract".
X * - added verbose command line options with same format as the
X * configuration commands.
X * - now use the "+" and "-" switches to indicate on and off.
X * - added a number of new options to support the new merged
X * programs and to allow displaying of settings.
X * - added a -Hstring to indicate replacement of the sequence:
X *
X * #ifndef __CEXTRACT__
X * ... output ...
X * #endif
X *
X * with:
X *
X * #ifndef string
X * #define string
X * ... output ...
X * #endif
X *
X * - wrote up a VMS help file for cextract.
X *
X * Version 1.1: Okay, so there were still more changes needed. :-)
X * - fixed more occurances of proceed instead of precede.
X * - fixed typos of "it's" instead of "its".
X * - removed empty targets from Makefile
X * - add sed facility to Makefile to properly configure man pages.
X * - wrote a ".so" implementation for cextdoc manual instead of
X * prior hard link method.
X * - added a MANDIR variable to the Makefile.
X * - tweaked the documentation in a few places.
X * - allow the "!" or "no-" (Non-VMS) or "no" (VMS) prefix to
X * command line options.
X * - use "sys$login:" as HOME directory on VMS systems, if HOME
X * environment variable is not defined.
X * - changed the "sys$system:" to "sys$library".
X * - fixed typo of "fclose(*stream)" in the VMS pclose.
X * - adjusted the VMS qualifier building to build /define=(a,b,c), etc.
X * - added in a "remove-names" option to eliminate variable names
X * from the parameter list output.
X * - fixed strncmp() bug in the check for the "replace" option.
X * - fixed a number of calls to cfg_err() to pass cmd_line parameter.
X * - implemented better check for empty or "void" parameter lists.
X * - merged the void check and style determination into one routine
X * and called it diverge_style().
X * - changed a number of routines to use char* math instead of
X * array stepping using counters.
X * - added a configuration file section to the VMS help file.
X * - tweaked the cextract.1 and cextrc.5 manual pages a bit more.
X * - edited the README, INSTALL, and INSTALL.VMS files.
X * - implemented checks to be sure that the files to be parsed are
X * accessible before calling the C preprocessor.
X * - renamed the files as:
X * cproto.c => parse.c
X * cproto.h => xtract.h
X * cextract.c => main.c
X * this was done to avoid some of the conflict with files
X * beginning with the same string of characters.
X * - made sure that "make test" tested the version in the current
X * directory.
X *
X * Version 1.2: yet another pre-submission fix section.
X * - fixed a typo in the comments.
X * - separated the INSTALL definition in the Makefile into INSTBIN
X * and INSTMAN command to allow those systems without "install"
X * to perform installations properly.
X * - added "/exe=cextract" to the build.com link operation.
X * - fixed the character count in the copy_str() function.
X * [This fixes the misread on the "replace" operation].
X * - fixed up the "method" description in the README.
X * - added ${CEXTRACT} to the "test" (ala "make test") dependency.
X * - removed the "make links" and appended it to "make install"
X * - changed the "skip-config" command to "read-config".
X * - had one more go at the cextrc.5 manual page.
X * - tweaked the cextract.1 manual page as well.
X * - added check for declaration of array of function pointers.
X * - added code to parse structure declarations within funciton
X * parameter lists. [why anyone would program like this is
X * beyond me, but hey, I like to support valid C.]
X * - made sure to only test for functions where a brace was
X * preceded by a semi-colon or a paranthesis.
X * - make sure to clear out the "code_info" array more often.
X * - increased the array sizes to allow for larger buffer space.
X * [temporary until implement dynamic memory routines.]
X * - created a TODO file and removed those items from the bottom
X * of the README file.
X * - shortened the BUGS section of the cextract.1 manual page.
X * - changed the program name check to strncmp() so VMS sites work.
X * - created a newbuild.com file and mentioned it in INSTALL.VMS.
X * - fixed errors in the newbuild.com file.
X * - added a mentioning of the '/' character for VMS options.
X * - cleaned up the README, INSTALL and other docs.
X *
X */
#include "xtract.h"
#ifndef VAXC
#include <pwd.h>
#ifdef cyber
extern struct passwd *getpwuid();
#endif /* cyber */
#endif /* VAXC */
X
/* storage elements */
P_PROTO proto_list = NULL, proto_next = NULL;
P_MACRO macro_list = NULL, last_macro = NULL;
P_SUBST subst_list = NULL;
FILE *fpin = NULL;
char code_info[MAX_SIZE+1], cfg_file[MID_SIZE];
char dummy_str[MID_SIZE], file_name[MID_SIZE];
int total_out = 0, files_parsed = 0, arg_ch_count = 0;
int out_file_flag = 0, comment_len = 0, dont_space = TRUE;
char start_comment[MAX_SIZE];
char prog_name[FNAME_SIZE];
char tmp_str[FNAME_SIZE];
static char last_comment[MAX_SIZE];
X
/* options for the parsing routines */
int yank_comments = FALSE, first_comment = FALSE, single_comments = TRUE;
int doc_extract = DOC_NONE, prepend_filename = FALSE;
int use_extern = TRUE, no_statics = TRUE, start_block = FALSE;
X
/* some cextract global option flags */
int show_anyway = TRUE;
int use_stdc = FALSE;
int use_both = FALSE;
int sort_mode = SORT_NONE;
int noshow_names = FALSE;
int tab_width = 0;
int cfg_switch = 7;
X
/* default font values */
char ft_title[3] = "C";
char ft_comment[3] = "CO";
char ft_name[3] = "B";
char ft_plist[3] = "R";
X
/* routine to send a system error message */
void
err_msg(estr)
X char *estr;
{
#ifdef NO_PERROR
X fprintf(stderr, "%s: %s\n", prog_name, estr);
#else
X fprintf(stderr, "%s\n", estr);
X perror(prog_name);
#endif /* NO_PERROR */
}
X
/* routine to check routine value of fputs */
void
fput_string (outstr, filep)
X char *outstr;
X FILE *filep;
{
X /* check the output of fputs */
X if (fputs(outstr, filep) == EOF) {
X err_msg("unable to write to file");
X exit(1);
X }
}
X
/* quickie function to distinquish proper switches */
int
is_switch (ch)
X int ch;
{
X if (ch == '-') return(TRUE);
X if (ch == '+') return(TRUE);
#ifdef VMS
X if (ch == '/') return(TRUE);
#endif /* VMS */
X return(FALSE);
}
X
/* call the external routine out_char() and send out all characters */
void
out_str(omode, str)
X int omode;
X char *str;
{
X /* simple function */
X while (*str != '\0') {
X out_char(omode, *str);
X str++;
X }
}
X
/* add a new substitution macro to the substitution list */
void
add_subst(type, f_str, t_str)
X int type;
X char *f_str, *t_str;
{
X P_SUBST subst_tmp;
X
X /* allocate the memory space */
X if ((subst_tmp = (P_SUBST) malloc(sizeof(S_SUBST))) == NULL) {
X fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
X exit(1);
X }
X if ((subst_tmp->from_str =
X (char *) malloc(sizeof(char) * (1 + strlen(f_str)))) == NULL) {
X fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
X exit(1);
X }
X if ((subst_tmp->to_str =
X (char *) malloc(sizeof(char) * (1 + strlen(t_str)))) == NULL) {
X fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
X exit(1);
X }
X
X /* now record the information */
X subst_tmp->submode = type;
X strcpy(subst_tmp->from_str, f_str);
X strcpy(subst_tmp->to_str, t_str);
X
X /* place it in the chain */
X subst_tmp->next = subst_list;
X subst_list = subst_tmp;
}
X
/* add a new macro to the macro list */
void
add_macro(str)
X char *str;
{
X P_MACRO macro_tmp;
X
X /* allocate the space */
X if ((macro_tmp = (P_MACRO) malloc(sizeof(S_MACRO))) == NULL) {
X fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
X exit(1);
X }
X if (macro_list == NULL) {
X macro_list = macro_tmp;
X }
X if ((macro_tmp->m_str =
X (char *) malloc(sizeof(char) * (strlen(str) + 1))) == NULL) {
X fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
X exit(1);
X }
X strcpy(macro_tmp->m_str, str);
X macro_tmp->next = NULL;
X if (last_macro != NULL) {
X last_macro->next = macro_tmp;
X }
X last_macro = macro_tmp;
}
X
/* return TRUE if the macro definition is in the string */
static int
macro_match(macro, str)
X char *macro, *str;
{
X int i, len, hold = FALSE;
X
X /* check it */
X if (macro[1] == 'D') {
X len = strlen(str);
X for (i = 0; i < len; i++) {
X if (macro[2 + i] != str[i]) break;
X }
X if (i == len &&
X (macro[i + 2] == '=' || macro[i + 2] == '\0')) {
X hold = TRUE;
X }
X }
X
X return(hold);
}
X
/* if the matching definition is in the list, remove it */
int
removed_macro(str)
X char *str;
{
X P_MACRO macro_ptr, macro_tmp;
X int hold = FALSE;
X
X /* go through the list */
X if ((macro_ptr = macro_list) != NULL) {
X
X /* check the beginning element */
X if (macro_match(macro_ptr->m_str, str)) {
X macro_list = macro_list->next;
X macro_ptr->next = NULL;
X free(macro_ptr->m_str);
X free(macro_ptr);
X hold = TRUE;
X }
X
X /* check the rest */
X macro_tmp = macro_ptr->next;
X while (hold == FALSE && macro_tmp != NULL) {
X if (macro_match(macro_tmp->m_str, str)) {
X macro_ptr->next = macro_tmp->next;
X macro_tmp->next = NULL;
X free(macro_tmp->m_str);
X free(macro_tmp);
X hold = TRUE;
X }
X /* onto the next */
X macro_ptr = macro_tmp;
X macro_tmp = macro_tmp->next;
X }
X }
X
X /* now assign the last_macro value and get back to work */
X if (hold == TRUE) {
X for (last_macro = macro_list;
X (last_macro != NULL) &&
X (last_macro->next != NULL);
X last_macro = last_macro->next) ;
X }
X return(hold);
}
X
/* compare two strings considering cases the same */
int
str_test (s1, s2)
X char *s1, *s2;
{
X int ch1, ch2;
X
X for (; *s1 != '\0'; s1++, s2++) {
X ch1 = (islower(*s1) ? toupper(*s1) : *s1);
X ch2 = (islower(*s2) ? toupper(*s2) : *s2);
X if (ch1 != ch2) return(ch1 - ch2);
X }
X return(*s1 - *s2);
}
X
/* sort the list of functions and their prototypes */
void
sort_proto()
{
X P_PROTO p2_ptr;
X int done = FALSE;
X
X /* all done? */
X if ((proto_list == NULL) || (proto_list->next == NULL)) return;
X
X /* go until done sorting */
X while (done == FALSE) {
X
X /* initialize */
X proto_next = proto_list;
X done = TRUE;
X
X /* test for initial swap */
X if ( str_test( proto_next->name, (proto_next->next)->name ) > 0) {
X proto_list = proto_next->next;
X proto_next->next = proto_list->next;
X proto_list->next = proto_next;
X proto_next = proto_list;
X }
X
X /* sort remaining linked list */
X for (; (proto_next->next)->next != NULL; proto_next = proto_next->next) {
X p2_ptr = (proto_next->next)->next;
X if ( str_test( (proto_next->next)->name, p2_ptr->name ) > 0) {
X
X /* swap locations in list */
X (proto_next->next)->next = p2_ptr->next;
X p2_ptr->next = proto_next->next;
X proto_next->next = p2_ptr;
X
X /* continue sort */
X done = FALSE;
X }
X }
X
X }
}
X
/* remove the top item on the stack */
void
pop_proto()
{
X P_PROTO tmp_proto = proto_list;
X
X /* done? */
X if (proto_list == NULL) {
X proto_next = NULL;
X return;
X }
X if (proto_list == proto_next) {
X proto_next = NULL;
X }
X
X /* now do it */
X proto_list = proto_list->next;
X tmp_proto->next = NULL;
X if (tmp_proto->name != NULL) free(tmp_proto->name);
X if (tmp_proto->ftype != NULL) free(tmp_proto->ftype);
X if (tmp_proto->fname != NULL) free(tmp_proto->fname);
X if (tmp_proto->plist != NULL) free(tmp_proto->plist);
X if (tmp_proto->comment != NULL) free(tmp_proto->comment);
X free(tmp_proto);
}
X
/* initialize the page for troff output, if needed */
void
init_roff(omode)
X int omode;
{
X static int init_done = FALSE;
X
X /* perform the initialization */
X if (init_done == FALSE) {
X out_str(omode, ".sp 0.5i\n");
X out_str(omode, ".ps 10\n");
X out_str(omode, ".vs 12\n");
X out_str(omode, ".fp 1 ");
X out_str(omode, ft_title);
X out_str(omode, "\n.fp 2 ");
X out_str(omode, ft_comment);
X out_str(omode, "\n.fp 3 ");
X out_str(omode, ft_name);
X out_str(omode, "\n.fp 4 ");
X out_str(omode, ft_plist);
X out_char(omode, '\n');
X init_done = TRUE;
X }
}
X
/* output the given function prototype */
void
out_proto(omode, f_ptr, mode, do_comments)
X int omode;
X P_PROTO f_ptr;
X int mode, do_comments;
{
X char *ch_out, tempstr[MID_SIZE];
X int did_leader = FALSE;
X
X /* check for stupidity */
X if (f_ptr == NULL) return;
X
X /* check for initial comment output */
X if (first_comment && (start_comment[0] != '\0')) {
X
X /* send out the first comment if so desired */
X strcpy(tempstr, "/*");
X if (prepend_filename) {
X strcat(tempstr, " ");
X strcat(tempstr, file_name);
X strcat(tempstr, ":");
X }
X send_first_comment(tempstr);
X did_leader = TRUE;
X
X /* it has been parsed */
X start_comment[0] = '\0';
X }
X
X /* is there a preamble? */
X if (doc_extract != DOC_NONE) {
X if (dont_space == FALSE) {
X if (doc_extract != DOC_ROFF) {
X out_char(omode, '\n');
X out_char(omode, '\n');
X } else {
X out_str(omode, ".sp 2\n");
X }
X } else if (doc_extract == DOC_ROFF) {
X init_roff(omode);
X }
X dont_space = FALSE;
X if (doc_extract != DOC_ROFF) {
X out_str(omode, "Function: ");
X out_str(omode, f_ptr->name);
X out_str(omode, "\nFile: ");
X } else {
X if (start_block == FALSE) {
X out_str(omode, ".KS\n");
X } else {
X start_block = FALSE;
X }
X out_str(omode, ".nf\n");
X out_str(omode, "\\f1Function: \\f3");
X out_str(omode, f_ptr->name);
X out_str(omode, "\n\\f1File: \\f3");
X }
X out_str(omode, f_ptr->fname);
X out_char(omode, '\n');
X }
X
X /* show the preceeding comment? */
X if (do_comments) {
X if (doc_extract != DOC_ROFF) {
X out_char(omode, '\n');
X if (f_ptr->comment != NULL) {
X out_str(omode, f_ptr->comment);
X out_char(omode, '\n');
X }
X } else {
X out_str(omode, ".sp\n\\f2");
X out_str(omode, f_ptr->comment);
X out_char(omode, '\n');
X }
X } else if ((doc_extract != DOC_NONE) ||
X (total_out == 0) ||
X did_leader) {
X out_char(omode, '\n');
X }
X
X /* turn on fill mode for troff style documentation */
X if (doc_extract == DOC_ROFF) {
X out_str(omode, ".fi\n");
X out_str(omode, ".in +0.5i\n");
X out_str(omode, ".ti -0.5i\n");
X }
X
X /* show the full function name and type */
X
X /* check for spacing and font selection */
X if (doc_extract == DOC_ROFF) {
X out_str(omode, "\\f3");
X out_str(omode, f_ptr->ftype);
X out_str(omode, " ( \\c\n\\f4");
X } else {
X out_str(omode, f_ptr->ftype);
X out_str(omode, " (");
X }
X
X if (mode != MODE_OLDC) {
X
X /* beginning comment? */
X if (mode == MODE_COMMENT) {
X out_str(omode, "/*");
X }
X
X /* show the prototype list */
X if (doc_extract != DOC_ROFF) {
X out_char(omode, ' ');
X out_str(omode, f_ptr->plist);
X out_char(omode, ' ');
X } else {
X
X /* break at each variable */
X for (ch_out = f_ptr->plist;
X *ch_out != '\0';
X ch_out++) {
X
X /* send out the list; breaking for ','s */
X out_char(omode, *ch_out);
X if (*ch_out == ',') {
X out_str(omode, "\\c\n");
X }
X }
X
X }
X
X /* check for end comments */
X if (mode == MODE_COMMENT) {
X out_str(omode, "*/");
X }
X
X }
X
X /* close up this output */
X if (doc_extract == DOC_ROFF) {
X out_str(omode, "\\f3 );\n");
X } else {
X out_str(omode, ");\n");
X }
X
X /* turn off fill mode for troff style documentation */
X if (doc_extract == DOC_ROFF) {
X out_str(omode, ".nf\n");
X out_str(omode, ".in -0.5i\n");
X out_str(omode, ".KE\n");
X }
}
X
/* read and store all characters prior to end comment indicator */
static void
get_comment(tagon, head_str, cmt_str)
X int tagon;
X char head_str[], cmt_str[];
{
X int curr_ch;
X int prev_ch = ' ';
X
X /* keep going until scan is complete */
X if (tagon == TRUE) {
X if (head_str[0] == '\0') {
X /* catenate side by side comments */
X comment_len -= 2;
X } else {
X /* insert intermediary white space and comment */
X for (curr_ch = 0;
X head_str[curr_ch] != '\0';
X curr_ch++) {
X cmt_str[comment_len++] = head_str[curr_ch];
X }
X cmt_str[comment_len++] = '/';
X cmt_str[comment_len++] = '*';
X }
X } else {
X comment_len = 0;
X }
X while ((curr_ch = getc(fpin)) != EOF) {
X
X /* test for end of comment */
X if ((curr_ch == '/') && (prev_ch == '*')) {
X cmt_str[comment_len++] = '/';
X break;
X }
X
X /* store it */
X cmt_str[comment_len++] = prev_ch = curr_ch;
X }
X
X /* close storage */
X cmt_str[comment_len] = '\0';
}
X
/* structure to hold definitions */
typedef struct s_param {
X char *name; /* the name of the variable */
X char *desc; /* description string */
X struct s_param *next; /* pointer to the next element */
} S_PARAM, *P_PARAM;
P_PARAM param_list;
X
/* take all of the variables between the parenthesis and break them down */
static int
fill_param(str)
X char *str;
{
X int paren_loc, count, i, in_word = 1, len = strlen(str);
X P_PARAM last_param = NULL, param_tmp;
X char tempc[MID_SIZE];
X
X /* initialize the list */
X param_list = NULL;
X paren_loc = 0;
X count = 0;
X tempc[0] = '\0';
X for (i = 1; i < len; i++) {
X
X /* check for the end */
X if (str[i] == ')') {
X paren_loc = i;
X break;
X }
X
X /* find a variable name; check for separators */
X if (str[i] == ',') {
X
X /* check current information */
X if (in_word == 1) {
X fprintf(stderr, "Empty variable list in file %s\n", file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X }
X in_word = 1;
X
X /* store the name */
X tempc[count] = '\0';
X count = 0;
X if ((param_tmp = (P_PARAM) malloc(sizeof(S_PARAM))) == NULL) {
X fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
X exit(1);
X }
X if ((param_tmp->name =
X (char *) malloc(sizeof(char) * (strlen(tempc) + 1))) == NULL) {
X fprintf(stderr, "Serious Error: Out of memory\n");
X exit(1);
X }
X strcpy(param_tmp->name, tempc);
X param_tmp->next = NULL;
X param_tmp->desc = NULL;
X if (param_list == NULL) {
X param_list = param_tmp;
X last_param = param_list;
X } else {
X last_param->next = param_tmp;
X last_param = param_tmp;
X }
X
X } else if (str[i] == ' ') {
X if (in_word == 2) {
X in_word = 0;
X }
X } else if (id_char(str[i])) {
X if (in_word == 0) {
X fprintf(stderr, "Invalid parameter list in %s?\n", file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X }
X in_word = 2;
X tempc[count++] = str[i];
X } else {
X fprintf(stderr, "Ack! Invalid C in file %s?\n", file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X }
X
X }
X
X /* now store the last name if any was found */
X if (count != 0) {
X
X /* store the name */
X tempc[count] = '\0';
X if ((param_tmp = (P_PARAM) malloc(sizeof(S_PARAM))) == NULL) {
X fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
X exit(1);
X }
X if ((param_tmp->name =
X (char *) malloc(sizeof(char) * (strlen(tempc) + 1))) == NULL) {
X fprintf(stderr, "Serious Error: Out of memory\n");
X exit(1);
X }
X strcpy(param_tmp->name, tempc);
X param_tmp->desc = NULL;
X param_tmp->next = NULL;
X if (param_list == NULL) {
X param_list = param_tmp;
X last_param = param_list;
X } else {
X last_param->next = param_tmp;
X last_param = param_tmp;
X }
X }
X return(paren_loc);
}
X
/* remove any preceding and trailing spaces */
void
trim_str(str)
X char *str;
{
X register int i = 0, j = 0;
X int last_space = -1;
X
X /* trim leading spaces */
X while (isspace(str[i])) i++;
X
X /* shift string */
X while (1) {
X if ((str[j] = str[i++]) == '\0') {
X break;
X } else if (isspace(str[j])) {
X last_space = j;
X } else {
X last_space = -1;
X }
X j++;
X }
X
X /* now remove any trailing spaces */
X if (last_space != -1) {
X str[last_space] = '\0';
X }
}
X
/* just go through and send out the entire parameter list */
static int
oldc_output()
{
X int count = 0, lcount = 0;
X P_PARAM param_tmp;
X
X /* first test for the simple case */
X if (param_list == NULL) {
X strcpy(dummy_str, "void");
X return(4);
X }
X dummy_str[0] = '\0';
X
X /* go through the list */
X while (param_list != NULL) {
X
X /* add in separators */
X if (count++ > 0) {
X
X strcat(dummy_str, ", ");
X lcount += 2;
X
X }
X
X /* check the type */
X if (param_list->desc != NULL) {
X trim_str(param_list->desc);
X strcat(dummy_str, param_list->desc);
X lcount += strlen(param_list->desc);
X free(param_list->desc);
X } else {
X if (noshow_names) {
X strcat(dummy_str, "int");
X lcount += 3;
X } else {
X strcat(dummy_str, "int ");
X strcat(dummy_str, param_list->name);
X lcount += 4 + strlen(param_list->name);
X }
X }
X free(param_list->name);
X
X /* clean up storage */
X param_tmp = param_list;
X param_list = param_list->next;
X param_tmp->next = NULL;
X free(param_tmp);
X
X }
X
X /* finish it up */
X return(lcount);
}
X
/* return the proper element */
static P_PARAM
var_match(str)
X char *str;
{
X int i, len, len2;
X P_PARAM p_hold;
X
X /* go through all of the items and find a match */
X len2 = strlen(str);
X p_hold = param_list;
X while (p_hold != NULL) {
X
X /* check for a match */
X len = strlen(p_hold->name);
X for (i = 0; i < len2 - len + 1; i++) {
X /* check for the match */
X if (strncmp(str + i, p_hold->name, len) == 0) {
X /* found a match */
X if (!id_char(str[i + len])) {
X return(p_hold);
X }
X } else if (id_char(str[i])) {
X /* definite non-match */
X i = len2 - len + 1;
X }
X }
X
X /* go to the next element */
X p_hold = p_hold->next;
X }
X
X return(p_hold);
}
X
/* remove the variable name from the given type and variable combo */
static void
kill_variable(str)
X char *str;
{
X register int i;
X
X /* no need to breakdown this baby */
X if (strcmp(str, "...") == 0) return;
X
X /* search for the variable name */
X for (i = strlen(str) - 1; i >= 0; i--) {
X
X /* found it */
X if (id_char(str[i])) {
X
X /* clean it up */
X while ((i >= 0) &&
X id_char(str[i])) {
X str[i--] = ' ';
X }
X i++;
X trim_str(str + i);
X if (i == 0) {
X strcpy(str, "int");
X } else {
X trim_str(str);
X }
X break;
X
X }
X
X }
}
X
/* separate and rebuild the ANSI format list */
static int
newc_parse (i_str)
X char *i_str;
{
X char hold_str[MID_SIZE], hold2_str[MID_SIZE];
X P_SUBST sub_tmp;
X int depth, cnt = 0, len;
X
X /* start the process */
X dummy_str[0] = '\0';
X do {
X
X /* move along the input string */
X switch (*i_str) {
X case ',':
X case '\0':
X /* finish off this item */
X if (cnt == 0) break;
X hold_str[cnt] = '\0';
X
X /* search for matches among the replacement code */
X for (sub_tmp = subst_list;
X sub_tmp != NULL;
X sub_tmp = sub_tmp->next) {
X /* check it */
X len = strlen(sub_tmp->from_str);
X switch (sub_tmp->submode) {
X case SUBST_FULL:
X /* the full string needs replacing? */
X if (strcmp(hold_str, sub_tmp->from_str) == 0) {
X strcpy(hold_str, sub_tmp->to_str);
X }
X break;
X case SUBST_TYPE:
X /* the type only needs replacing? */
X if (strncmp(hold_str, sub_tmp->from_str, len) == 0) {
X strcpy(hold2_str, hold_str + len);
X strcpy(hold_str, sub_tmp->to_str);
X strcat(hold_str, hold2_str);
X }
X break;
X case SUBST_NAME:
X /* the variable only needs replacing? WHY!? */
X if ((cnt > len) &&
X (strcmp(hold_str + cnt - len, sub_tmp->from_str) == 0)) {
X hold_str[cnt - len] = '\0';
X strcat(hold_str, sub_tmp->to_str);
X }
X break;
X }
X }
X
X /* do we clean it? */
X if (noshow_names) {
X kill_variable(hold_str);
X } else {
X trim_str(hold_str);
X }
X
X /* append to output */
X if (dummy_str[0] != '\0') {
X strcat(dummy_str, ", ");
X }
X strcat(dummy_str, hold_str);
X cnt = 0;
X break;
X case '{':
X /* collect up all of the type declaration */
X depth = -1;
X do {
X hold_str[cnt++] = *i_str;
X switch (*i_str) {
X case '\0':
X fprintf(stderr, "Unexpected end of parameters in file %s\n",
X file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X case '{':
X depth++;
X break;
X case '}':
X depth--;
X break;
X default:
X /* ignore me */
X break;
X }
X i_str++;
X } while ((depth > 0) ||
X (*i_str != '}'));
X hold_str[cnt++] = *i_str;
X break;
X case ' ':
X if (cnt == 0) break;
X default:
X /* just copy it */
X hold_str[cnt++] = *i_str;
X }
X
X } while (*(i_str++) != '\0');
X
X /* give back the length */
X return(strlen(dummy_str));
}
X
/* extract all of the parameters using old style format */
static int
oldc_parse(str)
X char *str;
{
X int depth = 0, last_char = ')';
X int start, count2, in_var;
X P_PARAM p_tmp;
X P_SUBST sub_tmp;
X
X char type_name[MID_SIZE], var_name[MID_SIZE], tempc[MID_SIZE];
X
X /* build the parameter list */
X if (str[start = fill_param(str)] != ')') {
X strcpy(dummy_str, "void");
X return(4);
X }
X
X /* begin with non-space character */
X for (str += start + 1; *str == ' '; str++) ;
X count2 = 0;
X in_var = FALSE;
X type_name[0] = '\0';
X
X /* now go through the entire structure */
X for (; *str != '\0'; str++) {
X
X switch (*str) {
X case ' ':
X /* add on to variable or append to type definition */
X if (in_var == TRUE) {
X var_name[count2++] = ' ';
X break;
X }
X break;
X case '{':
X /* must be a struct declaration */
X if ((depth != 0) ||
X (in_var == TRUE)) {
X fprintf(stderr, "Unexpected left brace in file %s\n", file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X }
X depth = -1;
X if (var_name[count2] != ' ') {
X var_name[count2++] = ' ';
X }
X do {
X var_name[count2++] = *str;
X switch (*str) {
X case '\0':
X fprintf(stderr, "Invalid C in file %s?\n", file_name);
X fprintf(stderr, "Decl: %s Name: %s\n",
X type_name, var_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X case '{':
X depth++;
X break;
X case '}':
X depth--;
X break;
X default:
X /* ignore me */
X break;
X }
X str++;
X } while ((depth > 0) ||
X (*str != '}'));
X goto saw_space;
X break;
X case ',':
X /* just add on if between parenthesis */
X if (depth != 0) {
X var_name[count2++] = ',';
X break;
X }
X case ';':
X /* found end of declaration? */
X var_name[count2] = '\0';
X if ((depth != 0) || (type_name[0] == '\0')) {
X fprintf(stderr, "Invalid C in file %s?\n", file_name);
X fprintf(stderr, "Decl: %s Name: %s\n",
X type_name, var_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X }
X if (var_name[0] == '\0') {
X fprintf(stderr, "Invalid C in file %s?\n", file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X }
X
X /* build the proper string */
X trim_str(type_name);
X strcpy(tempc, type_name);
X strcat(tempc, " ");
X trim_str(var_name);
X strcat(tempc, var_name);
X
X /* search for matches among the replacement code */
X for (sub_tmp = subst_list;
X sub_tmp != NULL;
X sub_tmp = sub_tmp->next) {
X /* check it */
X switch (sub_tmp->submode) {
X case SUBST_FULL:
X /* the full string needs replacing? */
X if (strcmp(tempc, sub_tmp->from_str) == 0) {
X strcpy(tempc, sub_tmp->to_str);
X }
X break;
X case SUBST_TYPE:
X /* the type only needs replacing? */
X if (strcmp(type_name, sub_tmp->from_str) == 0) {
X strcpy(tempc, sub_tmp->to_str);
X strcat(tempc, " ");
X strcat(tempc, var_name);
X }
X break;
X case SUBST_NAME:
X /* the variable only needs replacing? WHY!? */
X if (strcmp(var_name, sub_tmp->from_str) == 0) {
X strcpy(tempc, type_name);
X strcat(tempc, " ");
X strcat(tempc, sub_tmp->to_str);
X }
X break;
X }
X }
X
X /* now find the proper variable name */
X if ((p_tmp = var_match(var_name)) == NULL) {
X fprintf(stderr, "Could not place variable %s properly in file %s\n",
X var_name, file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X }
X
X /* now check for variable name removal */
X if (noshow_names) {
X kill_variable(tempc);
X }
X
X /* set aside space */
X if ((p_tmp->desc =
X (char *) malloc(sizeof(char) * (strlen(tempc) + 1))) == NULL) {
X fprintf(stderr, "Serious Memory Allocation Error\n");
X exit(1);
X }
X
X /* now stow it */
X strcpy(p_tmp->desc, tempc);
X
X /* reset properly */
X count2 = 0;
X var_name[0] = '\0';
X if (*str == ';') {
X in_var = FALSE;
X type_name[0] = '\0';
X }
X break;
X case '*':
X /* just append on, must now be in variable */
X if ((last_char == ' ') && (in_var == FALSE)) {
X in_var = TRUE;
X goto saw_space;
X } else if (in_var == FALSE) {
X /* must push out type properly */
X var_name[count2] = '\0';
X count2 = 0;
X if ((type_name[0] != '\0') &&
X (type_name[strlen(type_name) - 1] != ' ')) {
X strcat(type_name, " ");
X }
X strcat(type_name, var_name);
X var_name[0] = '\0';
X }
X in_var = TRUE;
X var_name[count2++] = '*';
X break;
X case '(':
X case '[':
X /* count depth, assume balanced for both */
X depth++;
X if ((last_char == ' ') &&
X (in_var == FALSE)) {
X in_var = TRUE;
X goto saw_space;
X }
X in_var = TRUE;
X var_name[count2++] = *str;
X break;
X case ')':
X case ']':
X /* check depth */
X depth--;
X if (depth < 0) {
X fprintf(stderr, "Misbalanced parens in file %s\n", file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X }
X if (last_char == ' ') goto saw_space;
X var_name[count2++] = *str;
X break;
X default:
X if (!id_char(*str)) {
X fprintf(stderr, "Just found '%c' in variable in file %s\n",
X *str, file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X }
X /* check for just seeing space */
X if (last_char == ' ' && in_var == FALSE) {
X
X saw_space:
X var_name[count2] = '\0';
X count2 = 0;
X if ((type_name[0] != '\0') &&
X (type_name[strlen(type_name) - 1] != ' ')) {
X strcat(type_name, " ");
X }
X strcat(type_name, var_name);
X var_name[0] = '\0';
X
X }
X var_name[count2++] = *str;
X break;
X }
X
X /* save the last character */
X last_char = *str;
X }
X
X /* now send everything out */
X return(oldc_output());
}
X
/* function to determine if the parameter list is K&R, ANSI or empty */
static int
diverge_style(str, len)
X char *str;
X int len;
{
X int void_fnd = FALSE, nspc_fnd = FALSE, in_word = 1;
X
X /* perform the first simple test */
X if (str[len - 1] == ';') return(2);
X
X /* should have a right parenthesis now */
X if (str[len - 1] != ')') {
X fprintf(stderr, "Expecting right paren in file %s\n", file_name);
X return(1);
X }
X
X /* now check to see if it only lists all variables */
X for (str++; *str != '\0'; str++) {
X
X /* check for separators */
X switch (*str) {
X case ',':
X /* variable separator */
X if (in_word == 1) {
X fprintf(stderr, "Empty variable list in file %s", file_name);
X return(1);
X }
X nspc_fnd = TRUE;
X in_word = 1;
X break;
X case ' ':
X /* word separator */
X if (in_word == 2) {
X in_word = 0;
X }
X break;
X case ')':
X if (*(str + 1) != '\0') {
X return(1);
X }
X break;
X default:
X /* check for variable name */
X if ((void_fnd == FALSE) &&
X (strncmp(str, "void", 4) == 0)) {
X void_fnd = TRUE;
X str += 3;
X in_word = 2;
X } else if (id_char(*str)) {
X if (in_word == 0) {
X return(1);
X }
X in_word = 2;
X nspc_fnd = TRUE;
X } else {
X return(1);
X }
X break;
X }
X }
X return((nspc_fnd == TRUE)? 2 : 0);
}
X
/* return length of function name... and store it in space provide */
static int
find_name(out_name, in_desc, desc_len)
X char *out_name, *in_desc;
X int desc_len;
{
X int pos, count = 0;
X
X /* find the end of the name */
X for (pos = desc_len; pos > 0; pos--) {
X if (id_char(in_desc[pos])) break;
X }
X
X /* find the length of the name */
X while ((pos > 0) &&
X (id_char(in_desc[pos]))) {
X count++;
X pos--;
X }
X
X /* copy it */
X if (!id_char(in_desc[pos])) {
X pos++;
X } else {
X count++;
X }
X strncpy(out_name, in_desc + pos, count);
X out_name[count] = '\0';
X return(count);
}
X
/* function to extract the function prototype from preceding characters */
static void
parse_func()
{
X P_PROTO tmp_proto;
X int count, valid = TRUE, depth = 0, done = FALSE;
X int sep_point = 0, len, dummy_len = 0;
X char *func_declare, *func_list, name_space[MID_SIZE];
X
X /* clean up the input string */
X trim_str(code_info);
X len = strlen(code_info);
X
X /* now go backwards and find the first occurance */
X /* of a right parenthesis without a '[', ',' or ';' after */
X for (count = len - 1; done == FALSE && count > 0; count--) {
X
X /* check for a select group of characters */
X switch (code_info[count]) {
X case ' ':
X /* don't change validity for spaces */
X break;
X case ')':
X /* check if it is a good match */
X depth++;
X if (depth == 1 && valid == TRUE) {
X done = TRUE;
X }
X break;
X case '(':
X /* keep proper track of depth */
X depth--;
X if (depth < 0) {
X fprintf(stderr, "Too many left parens in file %s\n",
X file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X }
X
X /* watch for function pointers */
X valid = FALSE;
X break;
X case '[':
X case ';':
X case ',':
X /* any paranthesis before this is invalid */
X valid = FALSE;
X break;
X case '=':
X /* there should be no equal signs anywhere around this */
X valid = FALSE;
X count = 0;
X break;
X default:
X /* it can now be a valid parenthesis */
X valid = TRUE;
X break;
X }
X }
X
X /* exit if no function type was found */
X if (done != TRUE) return;
X
X /* now find the separation point for the function */
X done = FALSE;
X for (; done == FALSE && count > 0; count--) {
X valid = code_info[count];
X switch (valid) {
X case ' ':
X break;
X case ')':
X /* go deeper */
X depth++;
X break;
X case '(':
X /* rise higher */
X depth--;
X if (depth == 0) {
X sep_point = count;
X done = TRUE;
X }
X break;
X default:
X break;
X }
X }
X
X /* confirm separation point */
X if (done == FALSE) {
X fprintf(stderr, "Too many right parens in file %s\n",
X file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X }
X
X /* now find the start of the function declaration */
X for (; count > 0; count--) {
X if ((code_info[count] == ';') ||
X (code_info[count] == '}')) break;
X }
X if ((code_info[count] == ';') ||
X (code_info[count] == '}')) count++;
X
X /* gain space */
X if ((func_list = (char *) malloc(sizeof(char) * (len - sep_point + 1)))
X == NULL) {
X fprintf(stderr, "Serious Error: Malloc failed\n");
X exit(1);
X }
X if ((func_declare =
X (char *) malloc(sizeof(char) * (sep_point - count + 1))) == NULL) {
X fprintf(stderr, "Serious Error: Malloc failed\n");
X exit(1);
X }
X
X /* now assign the locations */
X strcpy(func_list, &(code_info[sep_point]));
X strncpy(func_declare, &(code_info[count]), sep_point - count);
X func_declare[sep_point - count] = '\0';
X trim_str(func_list);
X trim_str(func_declare);
X
X /* find just the function name */
X len = strlen(func_declare);
X count = find_name(name_space, func_declare, len);
X
X /* just leave if there is no function */
X if (count == 0) {
X free(func_list);
X free(func_declare);
X return;
X }
X
X /* check for statics which shouldn't be shown */
X if (no_statics) {
X if (strncmp(func_declare, "static ", 7) == 0) {
X last_comment[0] = '\0';
X comment_len = 0;
X free(func_list);
X free(func_declare);
X return;
X }
X }
X
X /* declare storage space for the function */
X if ((tmp_proto = (P_PROTO) malloc(sizeof(S_PROTO))) == NULL) {
X fprintf(stderr, "Memory allocation failure\n");
X exit(1);
X }
X tmp_proto->next = NULL;
X
X /* place it in the list */
X if ((proto_next == NULL) || (proto_list == NULL)) {
X proto_next = proto_list = tmp_proto;
X } else {
X proto_next->next = tmp_proto;
X proto_next = tmp_proto;
X }
X if ((proto_next->fname =
X (char *) malloc(sizeof(char) * (strlen(file_name) + 2))) == NULL) {
X fprintf(stderr, "Memory allocation error\n");
X exit(1);
X }
X strcpy(proto_next->fname, file_name);
X
X /* now copy any preceding comments if desired */
X if ((yank_comments) &&
X (last_comment[0] != '\0')) {
X if ((proto_next->comment =
X (char *) malloc(sizeof(char) * (comment_len + 5))) == NULL) {
X fprintf(stderr, "Memory allocation error\n");
X exit(1);
X }
X strcpy(proto_next->comment, "/*");
X strcat(proto_next->comment, last_comment);
X last_comment[0] = '\0';
X comment_len = 0;
X } else {
X proto_next->comment = NULL;
X }
X
X /* output extern if desired */
X if (use_extern && strncmp("extern ", func_declare, 7) != 0) {
X strcpy(dummy_str, "extern ");
X dummy_len = 7;
X } else {
X dummy_str[0] = '\0';
X dummy_len = 0;
X }
X
X /* now check if the function type is an integer */
X if (count == len) {
X strcat(dummy_str, "int ");
X strcat(dummy_str, func_declare);
X dummy_len += 4 + len;
X } else {
X strcat(dummy_str, func_declare);
X dummy_len += len;
X }
X
X /* store the function header */
X if ((proto_next->ftype =
X (char *) malloc(sizeof(char) * (dummy_len + 2))) == NULL) {
X fprintf(stderr, "Memory allocation error\n");
X exit(1);
X }
X strcpy(proto_next->ftype, dummy_str);
X
X /* the function string */
X if ((proto_next->name =
X (char *) malloc(sizeof(char) * (count + 2))) == NULL) {
X fprintf(stderr, "Memory allocation error\n");
X exit(1);
X }
X strcpy(proto_next->name, name_space);
X
X /* now output empty list amount */
X len = strlen(func_list);
X switch (diverge_style(func_list, len)) {
X case 0:
X /* empty or "void" parameter list */
X strcpy(dummy_str, "void");
X dummy_len = 4;
X break;
X case 1:
X /* ANSI C format! -- remove trailing parenthesis */
X func_list[--len] = '\0';
X dummy_len = newc_parse(func_list + 1);
X break;
X default:
X /* K&R C format */
X dummy_len = oldc_parse(func_list);
X break;
X }
X
X /* store it */
X if ((proto_next->plist =
X (char *) malloc(sizeof(char) * (dummy_len + 2))) == NULL) {
X fprintf(stderr, "Memory allocation error\n");
X exit(1);
X }
X strcpy(proto_next->plist, dummy_str);
X
X /* replace space */
X free(func_list);
X free(func_declare);
}
X
/* go through the file extracting functions */
void
parse_file()
{
X int curr_char, count = 0, was_comment = FALSE, may_flush = FALSE;
X int depth = 0, num_comment = 0, temp_count = 0, temp_lines = 0;
X char temp_list[MID_SIZE];
X int prev_char = '\n', prev_real = ' ';
X
X /* go to it */
X start_comment[0] = '\0';
X last_comment[0] = '\0';
X temp_list[0] = '\0';
X while ((curr_char = getc(fpin)) != EOF) {
X
X /* check depth first */
X if (depth == 0) {
X
X /* process the characters */
X if (curr_char == '#' && prev_char == '\n') {
X
X /* nuke any preprocessor statements */
X was_comment = FALSE;
X do {
X prev_char = curr_char;
X } while (((curr_char = getc(fpin)) != '\n') &&
X !feof(fpin));
X
X } else if (curr_char == '"') {
X
X /* nuke string quotes -- must be on same line */
X prev_char = curr_char;
X count = 0;
X while (!feof(fpin)) {
X if ((curr_char = getc(fpin)) == '"') {
X break;
X } else if (curr_char == '\n') {
X fprintf(stderr, "Unexpected newline in string in file %s\n",
X file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X } else if (curr_char == '\\') {
X prev_char = curr_char;
X curr_char = getc(fpin);
X }
X prev_char = curr_char;
X }
X
X } else if (curr_char == '\'') {
X
X /* nuke character quotes -- must be on same line */
X count = 0;
X prev_char = curr_char;
X while (!feof(fpin)) {
X if ((curr_char = getc(fpin)) == '\'') {
X break;
X } else if (curr_char == '\n') {
X fprintf(stderr,
X "Unexpected newline in character constant in file %s\n",
X file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X } else if (curr_char == '\\') {
X prev_char = curr_char;
X curr_char = getc(fpin);
X }
X prev_char = curr_char;
X }
X
X } else if (curr_char == '*' && prev_char == '/') {
X
X /* clear out commments; treat as spaces */
X if (count > 0) count--;
X if (was_comment == FALSE) {
X num_comment++;
X temp_count = 0;
X } else {
X temp_count--;
X if ((single_comments == TRUE) &&
X (temp_count > 0)) {
X num_comment++;
X was_comment = FALSE;
X temp_count = 0;
X }
X }
X temp_list[temp_count] = '\0';
X curr_char = ' ';
X if (yank_comments ||
X ((num_comment == 1) && first_comment)) {
X
X /* process it */
X if (num_comment == 1) {
X get_comment(was_comment, temp_list, start_comment);
X } else {
X get_comment(was_comment, temp_list, last_comment);
X }
X was_comment = TRUE;
X temp_lines = 0;
X temp_count = (-1);
X
X } else {
X
X while ((curr_char = getc(fpin)) != EOF) {
X
X /* test for end of comment */
X if ((curr_char == '/') && (prev_char == '*')) {
X break;
X }
X prev_char = curr_char;
X }
X curr_char = ' ';
X
X }
X
X } else if (curr_char == '{') {
X
X /* reset recording process */
X was_comment = FALSE;
X may_flush = FALSE;
X depth++;
X
X /* now check if it is a function */
X if ((prev_real == ';') ||
X (prev_real == ')')) {
X
X /* found end of function, struct, or union definition */
X code_info[count] = '\0';
X parse_func();
X code_info[count = 0] = '\0';
X
X } else {
X code_info[count++] = '{';
X }
X
X } else if (curr_char == '}') {
X
X fprintf(stderr, "Extra right brace in file %s\n", file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X
X }
X
X /* tag onto the list */
X if (depth == 0) {
X
X /* store the characters for later use */
X if (isspace(curr_char) &&
X (count != 0 && code_info[count - 1] != ' ')) {
X
X /* combine any white space into a single space character */
X code_info[count++] = ' ';
X
X } else if (!isspace(curr_char)) {
X
X /* store any other type directly */
X if (curr_char != '/') {
X was_comment = FALSE;
X temp_count = 0;
X temp_lines = 0;
X }
X code_info[count++] = curr_char;
X prev_real = curr_char;
X
X }
X
X /* count the lead in */
X if (was_comment == TRUE) {
X
X /* no multiple newlines */
X if (curr_char == '\n') {
X if (temp_lines == 0) {
X temp_lines = 1;
X } else {
X temp_lines = 0;
X temp_count = -1;
X was_comment = FALSE;
X }
X }
X
X /* check beginning */
X if (temp_count >= 0) {
X temp_list[temp_count] = curr_char;
X }
X temp_count++;
X
X }
X
X /* now note what was last encountered */
X prev_char = curr_char;
X
X }
X
X } else {
X
X /* keep track of depth and got through code otherwise */
X if (curr_char == '#' && prev_char == '\n') {
X
X /* nuke any preprocessor statements */
X do {
X prev_char = curr_char;
X } while (((curr_char = getc(fpin)) != '\n') &&
X !feof(fpin));
X
X } else if (curr_char == '"') {
X
X /* nuke string quotes -- must be on same line */
X may_flush = TRUE;
X while (!feof(fpin)) {
X prev_char = curr_char;
X if ((curr_char = getc(fpin)) == '\n') {
X fprintf(stderr, "Unexpected newline in string in file %s\n",
X file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X } else if (curr_char == '\\') {
X prev_char = curr_char;
X curr_char = getc(fpin);
X continue;
X } else if (curr_char == '"') {
X break;
X }
X };
X
X } else if (curr_char == '\'') {
X
X /* nuke character quotes -- must be on same line */
X may_flush = TRUE;
X while (!feof(fpin)) {
X prev_char = curr_char;
X if ((curr_char = getc(fpin)) == '\n') {
X fprintf(stderr, "Unexpected newline in constant in file %s\n",
X file_name);
X fprintf(stderr, "Bailing out...\n");
X exit(1);
X } else if (curr_char == '\\') {
X prev_char = curr_char;
X curr_char = getc(fpin);
X } else if (curr_char == '\'') {
X break;
X }
X }
X
X } else if (curr_char == '*' && prev_char == '/') {
X
X /* nuke comments */
X num_comment++;
X while ((curr_char = getc(fpin)) != EOF) {
X
X /* test for end of comment */
X if ((curr_char == '/') && (prev_char == '*')) {
X break;
X }
X prev_char = curr_char;
X
X }
X curr_char = ' ';
X
X } else if (curr_char == '{') {
X
X depth++;
X code_info[count++] = curr_char;
X
X } else if (curr_char == '}') {
X
X --depth;
X if (count > 0) code_info[count++] = curr_char;
X if (may_flush) {
X if (depth == 0) may_flush = FALSE;
X code_info[count = 0] = '\0';
X }
X
X } else {
X /* just copy on the off chance */
X code_info[count++] = curr_char;
X }
X
X /* now note what was last encountered */
X prev_char = curr_char;
X
X }
X
X }
}
X
/* This function will create the temporary source file
X * needed to detect the varargs prototypes.
X */
static void
bld_testfile(fname)
X char *fname;
{
X FILE *fp;
X
X /* simply create a file of the given name with the test information */
X if ((fp = fopen(fname, "w")) == NULL) {
X sprintf(tmp_str, "Error opening initialization file <%s>", fname);
X err_msg(tmp_str);
X exit(1);
X }
X
X /* now fill the file */
X fput_string("#include <stdio.h>\n", fp);
X fput_string("#include <varargs.h>\n", fp);
X fput_string("int function1(va_alist)\nva_dcl\n", fp);
X fput_string("{ /* empty function */ }\n", fp);
X fput_string("int function2(fstrct)\nFILE fstrct;\n", fp);
X fput_string("{ /* empty function */ }\n", fp);
X
X /* all done */
X if (fclose(fp) == EOF) {
X sprintf(tmp_str, "Error closing initialization file <%s>", fname);
X err_msg(tmp_str);
X exit(1);
X }
}
X
/* function to search for the expanded value of the varargs setup */
int
vargs_init ()
{
X char sys_cmd[MID_SIZE], tmpfname[MID_SIZE];
X char t_instr[MID_SIZE], t_outstr[MID_SIZE];
X int type_select = 0;
X
X /* first build the temporary file name */
X sprintf(tmpfname, TMPFILE_FMT, getpid());
X
X /* generate the temporary file */
X bld_testfile(tmpfname);
X
X /* now launch a CPP process */
X sprintf(sys_cmd, "%s %s", CPP, tmpfname);
X if ((fpin = popen(sys_cmd, "r")) == NULL) {
X sprintf(tmp_str, "unable to open CPP pipe to file <%s>",
X tmpfname);
X err_msg(tmp_str);
X exit(1);
X }
X
X /* now analyze it to capture the var args info */
X parse_file();
X pclose(fpin);
X unlink(tmpfname);
X fpin = NULL;
X
X /* now go and retrieve the info */
X while (proto_list != NULL) {
X
X /* get the proper function */
X if (strcmp(proto_list->name, "function1") == 0) {
X /* this is the varargs part */
X strcpy(t_instr, proto_list->plist);
X strcpy(t_outstr, "...");
X type_select = SUBST_FULL;
X } else if (strcmp(proto_list->name, "function2") == 0) {
X /* this is the FILE structure type */
X for (type_select = strlen(proto_list->plist) - 1;
X type_select > 0;
X type_select--) {
X /* cut off the variable name */
X if (proto_list->plist[type_select] == ' ') {
X proto_list->plist[type_select] = '\0';
X break;
X }
X }
X strcpy(t_instr, proto_list->plist);
X strcpy(t_outstr, "FILE");
X type_select = SUBST_TYPE;
X } else {
X /* this isn't right */
X fprintf(stderr, "Warning: error in parsing initialization functions\n");
X goto skip_it;
X }
X
X /* now copy the information in properly */
X add_subst(type_select, t_instr, t_outstr);
X
X /* get rid of it */
X skip_it:
X pop_proto();
X }
X
X /* get out */
X return(1);
}
X
/* set path to home configuration file and indicate success */
static int
set_home_config()
{
#ifndef VAXC
X struct passwd *pwtemp = NULL;
#endif /* VAXC */
X char home_file[MID_SIZE];
X
X /* locate the home directory */
X if (getenv("HOME") != NULL) {
X
X /* the simple method */
X strcpy(home_file, getenv("HOME"));
X
#ifndef VAXC
X } else if ((pwtemp = getpwuid(getuid())) != NULL) {
X
X /* get the home directory from the password entry */
X strcpy(home_file, pwtemp->pw_dir);
X
#endif /* VAXC */
X } else {
#ifdef VMS
X strcpy(home_file, "sys$login:");
#else
X /* nothing, go home */
X return(FALSE);
#endif /* VMS */
X }
X
X /* now build the file */
X strcat(home_file, DIR_SEPARATOR);
X strcat(home_file, CONFIG_FILE);
X
X /* record it */
X strcpy(tmp_str, home_file);
X return(TRUE);
}
X
/* function to read in any configuration files */
void
do_config ()
{
X /* try to parse the system configuration file */
X if (cfg_switch & 1) {
X parse_config(SYS_CONFIG);
X }
X
X /* now parse the personal configuration file */
X if (cfg_switch & 2) {
X if (set_home_config()) {
X parse_config(tmp_str);
X }
X }
X
X /* now check the current directory */
X if (cfg_switch & 4) {
X parse_config(CONFIG_FILE);
X }
X
X /* lastly, check any random file */
X if (cfg_file[0] != '\0') {
X parse_config(cfg_file);
X }
}
X
/* return a pointer to a string containing the date */
char *
mach_time ()
{
X long timeval;
X
X /* first get the time */
X timeval = time(0);
X
X /* now find the string using ctime */
X return(ctime(&timeval));
}
X
#ifdef VMS
#ifdef NO_POPEN
/* quickie implementation on VAX VMS systems */
#define VMSTMP_FMT "sys$scratch:cexttmp.%d"
char newcommand[FNAME_SIZE];
char vmstmpfile[FNAME_SIZE];
X
/* All of these routines were written by John Carr (jrcarr@iup.bitnet) */
FILE *
popen(command, type)
X char *command, *type;
{
X static int tmpnameset = FALSE;
X
X /* build the file name */
X if (tmpnameset == FALSE) {
X sprintf(vmstmpfile, VMSTMP_FMT, getpid());
X tmpnameset = TRUE;
X }
X
X /* this "popen()" hack is only useful for reading from the "CPP" output */
X sprintf(newcommand, "%s /preprocess=%s", command, vmstmpfile);
X system(newcommand);
X return(fopen(vmstmpfile, "r"));
}
X
/* close up the "pipe" */
int
pclose (stream)
X FILE *stream;
{
X if (fclose(stream) == EOF) return(-1);
X return(unlink(vmstmpfile));
}
#endif /* NO_POPEN */
#endif /* VAXC */
SHAR_EOF
chmod 0644 parse.c ||
echo 'restore of parse.c failed'
Wc_c="`wc -c < 'parse.c'`"
test 53393 -eq "$Wc_c" ||
echo 'parse.c: original size 53393, current size' "$Wc_c"
fi
# ============= patchlevel.h ==============
if test -f 'patchlevel.h' -a X"$1" != X"-c"; then
echo 'x - skipping patchlevel.h (File already exists)'
else
echo 'x - extracting patchlevel.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'patchlevel.h' &&
#define PATCHLEVEL 2
SHAR_EOF
chmod 0644 patchlevel.h ||
echo 'restore of patchlevel.h failed'
Wc_c="`wc -c < 'patchlevel.h'`"
test 21 -eq "$Wc_c" ||
echo 'patchlevel.h: original size 21, current size' "$Wc_c"
fi
true || echo 'restore of proto.h failed'
echo End of part 3, continue with part 4
exit 0