Article View: comp.sources.reviewed
Article #12v02i043: cextract - (Ver. 1.7) C prototyper/header file generator, Part05/05
From: Adam Bryant
Date: Tue, 03 Nov 1992 22:12
Date: Tue, 03 Nov 1992 22:12
2076 lines
60616 bytes
60616 bytes
Submitted-by: Adam Bryant <adb@cs.bu.edu>
Posting-number: Volume 2, Issue 43
Archive-name: cextract/part05
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 5 (of 5)."
# Contents: parse.c
# Wrapped by adb@csa on Fri Oct 30 16:20:37 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'parse.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'parse.c'\"
else
echo shar: Extracting \"'parse.c'\" \(54378 characters\)
sed "s/^X//" >'parse.c' <<'END_OF_FILE'
X/*
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, 1992 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 * The generated output (header) files are distributable in any
X * manner desired as they are based on the scanned source code,
X * not my program.
X */
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 function
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 * Version 1.3: first patch after comp.sources.reviewed
X * - fixed bug where comments within parameter list could cause a
X * function to be skipped.
X * - added both the CPP and CPP_COMMENTS flags to the Makefile.
X * - added patch from Martin Fouts (fouts@bozeman.clipper.ingr.com)
X * to provide simple changes to allow port to the CLIX OS.
X * - fixed stupid bug which caused the "-U" flag to not get parsed.
X * - changed the "#ifdef __STDC__" to the proper "#if __STDC__".
X * - wrote a new command and flag "build-config" to generate the system
X * configuration file automatically. [-B or -b for build]
X * - made sure the replace macros do not contain duplicates.
X * - prevented the creation of duplicate '-D','-I', or '-U' entries.
X * - fixed the "macro_match()" function for all systems. [VMS?]
X * - reversed the definitions of CFLAGS and COPTS in the Makefile.
X * - made sure to test if substitution already took place in vargs_find().
X * - fixed the 'Q' flag so that it properly reads in any numeric.
X * - added a dependency for the system configuration file to the
X * "install" target, so that it can be automatically generated.
X * - fixed the INSTALL, INSTALL.VMS and documentation files to
X * properly cover the new configuration file building mechanism.
X * - implemented a better method for the NO_OPEN option. This should
X * now work for all systems, not just VMS.
X * - fixed bug that the type of the function was not checked for
X * replacement.
X * - made sure that the subst macros where ordered as they came in.
X * - fixed bug with parameters for function pointers getting int
X * tagged on unnecessarily.
X *
X * Version 1.4: [2/25/92-4/20/92] Another iteration of fixes.
X * - allow any sort of text inside of brackets and parenthesis
X * in the variable declarations.
X * - fixed the fprintf formats in the font error messages.
X * - made sure to remove the use of register in prototype types.
X * - added the +Z option to allow for the compression of the output
X * using a macro. [Also under the "merge-output" option.]
X * - separated functions into a third file [io.c] to reduce the
X * size of the other files.
X *
X * Version 1.5: [4/29/92-5/18/92] Second submission fixes.
X * - added ability to exclude all but static functions from search
X * to allow for the creation of header files for single files.
X * - fixed the documentation to reflex the new "static" feature.
X * - fixed some errors in the manual pages.
X * - adjusted the Makefile: make echo, sed, nroff and install
X * configurable; had the "make test" command perform the diff
X * directly; enhanced the mkdir lines (is it portable?).
X * - fixed a bug in the out_str() function where it might have
X * accessed invalid data if the parameter str was NULL.
X * - for the SGI systems, added a "#define _POSIX_SOURCE" line.
X * - allow both "no-" and "no" for turning off options.
X * - implemented a "+W" ("+break-after-types") flag to separate
X * function type from the function name.
X * - implemented a "+w#" ("+wrap-parameters") flag to cause the
X * output of the parameter list to wrap after a given number of
X * characters.
X * - added the two new options to the documentation files.
X * - made use of minmatch_str's return value in io.c and cleaned up
X * some minor typos.
X * - fixed serious bug with the default settings for statics.
X * [Thanks to Jon Whellams for catching this. *sigh*]
X * - major rewrite of the options system:
X * + merged most of the options into a two dimensional array.
X * + used this two-dimensional array to distinguish between
X * options used in extract mode and doc mode.
X * + this makes it possible for the generated config files to
X * contain the proper "extract-only " or "doc-only "
X * prefixes.
X * - merged the two static flags into one flag with multiple
X * options, removing the confusing "-only-statics" flag.
X * - fixed the build_rc() routine to properly prefix "doc-only " or
X * "extract-only " to the output when appropriate.
X * - the mode ("extract", "doc", etc.) will no longer be written
X * when a configuration file is generated so "cextdoc" works.
X *
X * Version 1.6: [8/28/92] Third submission fixes.
X * - added line to set the permissions on the config file during install.
X * - regenerated the proto.h file to grab the main.c "parce.c" typo fix.
X * - fixed the documentation for the "-w#" flag. ["-w=#" --> "-w#"]
X * - for the INSTALL file, I now explicitly mention that installation
X * of the configuration file might need root permission.
X * - fixed outdated usages of pclose [pclose -> close_input].
X * - fixed the wrong usage of "command" in the "open_input" function.
X * - allow for alternative return values from system().
X * - make sure that multiple replacements can take place.
X * - fixed error with "replace" not recognizing "name" selection.
X * - made sure an error is printed if a bad "replace" format is seen.
X * - added support for // comments to begin future C++ support.
X * - provided a "strstr()" function for Xenix sites.
X * - expanded the "output-file" argument to support separate output
X * files for extraction and documentation modes.
X * - added the ability to select the C preprocessor at runtime.
X * - updated all of the documentation to reflect the above changes.
X * - preserve the doc/extract selection for macros and replace commands.
X *
X * Version 1.7: [10/30/92] Hopefully last enhancements before acceptance
X * - keep track of line numbers within the file being parsed.
X * - any syntax errors will be reported without aborting the file
X * parsing.
X * - syntax errors will be accurately reported by file and line number.
X * - added a check to test for too many left parenthesis.
X *
X */
X#include "xtract.h"
X
X/* storage elements */
XP_PROTO proto_list = NULL, proto_next = NULL;
XP_MACRO macro_list = NULL, last_macro = NULL;
XP_SUBST subst_list = NULL, last_subst = NULL;
XFILE *fpin = NULL;
Xchar code_info[MAX_SIZE+1], cfg_file[MID_SIZE];
Xchar dummy_str[MID_SIZE], file_name[MID_SIZE];
Xint arg_ch_count = 0;
Xint out_file_flag = 0, comment_len = 0, dont_space = TRUE;
Xchar start_comment[MAX_SIZE];
Xchar prog_name[FNAME_SIZE];
Xchar tmp_str[FNAME_SIZE];
Xint dont_stop = FALSE;
Xstatic char last_comment[MAX_SIZE];
X
X/* options for the different parsing methods */
Xint global_opts[2][OPT_NUMBER];
Xint doc_extract = DOC_NONE, cfg_switch = 7;
X
X/* variables for keeping track of things */
Xchar errout_filename[MID_SIZE];
Xint start_block = FALSE, files_parsed = 0, total_out = 0;
Xint line_count = 0;
X
X/* default font values */
Xchar ft_title[3] = "C";
Xchar ft_comment[3] = "CO";
Xchar ft_name[3] = "B";
Xchar ft_plist[3] = "R";
X
X/* add a new substitution macro to the substitution list */
Xvoid
Xadd_subst(type, select, f_str, t_str)
X int type, select;
X char *f_str, *t_str;
X{
X P_SUBST subst_tmp;
X
X /* check for duplicates */
X for (subst_tmp = subst_list;
X subst_tmp != NULL;
X subst_tmp = subst_tmp->next) {
X if ((subst_tmp->submode == type) &&
X (subst_tmp->usewhen == select) &&
X (strcmp(subst_tmp->from_str, f_str) == 0)) {
X
X /* can exit routine for complete matches */
X if (strcmp(subst_tmp->to_str, t_str) == 0) {
X return;
X }
X
X /* otherwise just adjust the replacement */
X free(subst_tmp->to_str);
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 strcpy(subst_tmp->to_str, t_str);
X return;
X
X }
X }
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_list == NULL) {
X subst_list = subst_tmp;
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 subst_tmp->usewhen = select;
X strcpy(subst_tmp->from_str, f_str);
X strcpy(subst_tmp->to_str, t_str);
X
X /* place the new link at the end of the chain */
X subst_tmp->next = NULL;
X if (last_subst != NULL) {
X last_subst->next = subst_tmp;
X }
X last_subst = subst_tmp;
X}
X
X/* add a new macro to the macro list */
Xvoid
Xadd_macro(select, str)
X int select;
X char *str;
X{
X P_MACRO macro_tmp;
X
X /* check for duplicate entries */
X for (macro_tmp = macro_list;
X macro_tmp != NULL;
X macro_tmp = macro_tmp->next) {
X /* no need to add something already there */
X if (strcmp(macro_tmp->m_str, str) == 0) {
X /* check for selection change */
X if (macro_tmp->usewhen != select) {
X macro_tmp->usewhen = 2;
X }
X return;
X }
X }
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->usewhen = select;
X macro_tmp->next = NULL;
X if (last_macro != NULL) {
X last_macro->next = macro_tmp;
X }
X last_macro = macro_tmp;
X}
X
X/* return TRUE if the macro definition is in the string */
Xstatic int
Xmacro_match(macro, str)
X char *macro, *str;
X{
X static int deflen = -1;
X int i, len, hold = FALSE;
X
X /* initialize */
X if (deflen == -1) {
X deflen = strlen(DEF_LEADER);
X }
X
X /* check it */
X if (strncmp(macro, DEF_LEADER, deflen) == 0) {
X len = strlen(str);
X for (i = 0; i < len; i++) {
X if (macro[i + deflen] != str[i]) break;
X }
X if ((i == len) &&
X ((macro[i + deflen] == '=') ||
X (macro[i + deflen] == '\0'))) {
X hold = TRUE;
X }
X }
X
X return(hold);
X}
X
X/* if the matching definition is in the list, remove it */
Xint
Xremoved_macro(select, str)
X int select;
X char *str;
X{
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 if (macro_ptr->usewhen != select) {
X /* just return */
X return(FALSE);
X } else {
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
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 if (macro_ptr->usewhen != select) {
X /* just return */
X return(FALSE);
X } else {
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 }
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}
X
X/* compare two strings considering cases the same */
Xint
Xstr_test (s1, s2)
X char *s1, *s2;
X{
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}
X
X/* sort the list of functions and their prototypes */
Xvoid
Xsort_proto()
X{
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}
X
X/* remove the top item on the stack */
Xvoid
Xpop_proto()
X{
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}
X
X/* initialize the page for troff output, if needed */
Xvoid
Xinit_roff(omode)
X int omode;
X{
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}
X
X/* check preprocessor statement for line numbering changes */
Xint
Xpreprocessor_check()
X{
X int curr_char = '#';
X int i, l, line_value;
X char temp_str[MID_SIZE], t2_str[MID_SIZE];
X
X /* get the whole line */
X if (fgets(temp_str, MID_SIZE, fpin) != NULL) {
X /* first handle the exit */
X l = strlen(temp_str);
X curr_char = temp_str[l - 1];
X
X /* now parse things */
X for (i = 0; i < l; i++) {
X if (isdigit(temp_str[i])) {
X if (sscanf(&(temp_str[i]), "%d %s", &line_value,
X t2_str) == 2) {
X line_count = line_value;
X l = strlen(t2_str);
X if (t2_str[l - 1] == '"') {
X t2_str[l - 1] = '\0';
X }
X if (t2_str[0] == '"') {
X i = 1;
X } else {
X i = 0;
X }
X strcpy(errout_filename, &(t2_str[i]));
X }
X break;
X } else if (!isspace(temp_str[i])) {
X if (strncmp(&(temp_str[i]), "line", 4) != 0) break;
X else {
X i += 3;
X }
X }
X }
X }
X return(curr_char);
X}
X
X/* read and store all characters prior to end comment indicator */
Xstatic void
Xget_comment(tagon, head_str, cmt_str)
X int tagon;
X char head_str[], cmt_str[];
X{
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 if (curr_ch == '\n') line_count++;
X }
X
X /* close storage */
X cmt_str[comment_len] = '\0';
X}
X
X/* structure to hold definitions */
Xtypedef 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 */
X} S_PARAM, *P_PARAM;
XP_PARAM param_list;
X
X/* take all of the variables between the parenthesis and break them down */
Xstatic int
Xfill_param(str)
X char *str;
X{
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 syntax_err("empty variable list encountered");
X return(-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 syntax_err("invalid parameter list encountered");
X return(-1);
X }
X in_word = 2;
X tempc[count++] = str[i];
X } else {
X syntax_err("unable to parse the complex C code");
X return(-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}
X
X/* remove any preceding and trailing spaces */
Xvoid
Xtrim_str(str)
X char *str;
X{
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}
X
X/* just go through and send out the entire parameter list */
Xstatic int
Xoldc_output()
X{
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 (get_option(OPT_NONAMES)) {
X strcat(dummy_str, "int");
X lcount += 3;
X } else if (strcmp("int", param_list->name)) {
X strcat(dummy_str, "int ");
X strcat(dummy_str, param_list->name);
X lcount += 4 + strlen(param_list->name);
X } else {
X strcat(dummy_str, param_list->name);
X lcount += 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}
X
X/* return the proper element */
Xstatic P_PARAM
Xvar_match(str)
X char *str;
X{
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}
X
X/* remove the variable name from the given type and variable combo */
Xstatic void
Xkill_variable(str)
X char *str;
X{
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 trim_str(str);
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}
X
X/* separate and rebuild the ANSI format list */
Xstatic int
Xnewc_parse (i_str)
X char *i_str;
X{
X char hold_str[MID_SIZE], hold2_str[MID_SIZE];
X P_SUBST sub_tmp;
X int depth, cnt = 0, len, i;
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
X /* check for usage */
X if ((sub_tmp->usewhen != 2) &&
X (sub_tmp->usewhen != (doc_extract != DOC_NONE))) continue;
X
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 /* check for removal of register type */
X if (strncmp(hold_str, "register ", 9) == 0) {
X for (i = 0; i < 9; i++) {
X hold_str[i] = ' ';
X }
X }
X
X /* do we clean it? */
X if (get_option(OPT_NONAMES)) {
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 syntax_err("unexpected end of parameters");
X return(-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}
X
X/* extract all of the parameters using old style format */
Xstatic int
Xoldc_parse(str)
X char *str;
X{
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];
X char oldvar_name[MID_SIZE], tempc[MID_SIZE];
X
X /* build the parameter list */
X if ((start = fill_param(str)) == -1) {
X /* clean up and exit on error */
X while (param_list != NULL) {
X p_tmp = param_list;
X param_list = param_list->next;
X p_tmp->next = NULL;
X free(p_tmp);
X }
X return(-1);
X }
X if (str[start] != ')') {
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 syntax_err("unexpected left brace encountered");
X return(-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 syntax_err("unable to parse the complex C structure");
X return(-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 syntax_err("unable to parse the complex C structure");
X return(-1);
X }
X if (var_name[0] == '\0') {
X syntax_err("unable to parse the complex C structure");
X return(-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 strcpy(oldvar_name, 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 strcpy(type_name, 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 strcpy(var_name, sub_tmp->to_str);
X }
X break;
X }
X }
X
X /* now find the proper variable name */
X if ((p_tmp = var_match(oldvar_name)) == NULL) {
X char temp_str[MID_SIZE];
X sprintf(temp_str, "could not place variable %s properly",
X oldvar_name);
X syntax_err(temp_str);
X return(-1);
X }
X
X /* now check for variable name removal */
X if (get_option(OPT_NONAMES)) {
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 if ((type_name[0] != '\0') ||
X (strcmp(var_name, "register") != 0)) {
X strcat(type_name, var_name);
X }
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 syntax_err("misbalanced parenthesis encountered");
X return(-1);
X }
X if (last_char == ' ') goto saw_space;
X var_name[count2++] = *str;
X break;
X default:
X if (!id_char(*str) && (depth == 0)) {
X syntax_err("unknown variable structure encountered");
X return(-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 if ((type_name[0] != '\0') ||
X (strcmp(var_name, "register") != 0)) {
X strcat(type_name, var_name);
X }
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}
X
X/* function to determine if the parameter list is K&R, ANSI or empty */
Xstatic int
Xdiverge_style(str, len)
X char *str;
X int len;
X{
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}
X
X/* return length of function name... and store it in space provide */
Xstatic int
Xfind_name(out_name, in_desc, desc_len)
X char *out_name, *in_desc;
X int desc_len;
X{
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}
X
X/* function to extract the function prototype from preceding characters */
Xstatic void
Xparse_func()
X{
X P_SUBST sub_tmp;
X P_PROTO tmp_proto;
X int count, valid = TRUE, depth = 0, done = FALSE;
X int sep_point = 0, typelen, cmpstt, 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 syntax_err("too many left parenthesis encountered");
X break;
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 /* get out 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 syntax_err("too many right parenthesis encountered");
X return;
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 if (code_info[count] == '(') {
X syntax_err("unexpected left parenthesis found while parsing parameters");
X return;
X }
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 (get_option(OPT_STATICMODE) != ANY_STATICS) {
X if (!strncmp(func_declare, "static ", 7) ==
X (get_option(OPT_STATICMODE) == NO_STATICS)) {
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 tmp_proto->name = NULL;
X tmp_proto->ftype = NULL;
X tmp_proto->fname = NULL;
X tmp_proto->plist = NULL;
X tmp_proto->comment = 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 (get_option(OPT_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 /* check for the conversion of the type declaration */
X if (count != len) {
X if (strncmp("extern ", func_declare, 7) == 0) {
X cmpstt = 7;
X } else {
X cmpstt = 0;
X }
X for (sub_tmp = subst_list;
X sub_tmp != NULL;
X sub_tmp = sub_tmp->next) {
X /* check it */
X if (sub_tmp->submode == SUBST_TYPE) {
X
X /* compare */
X typelen = strlen(sub_tmp->from_str);
X if (strncmp(func_declare + cmpstt, sub_tmp->from_str, typelen) == 0) {
X strcpy(tmp_str, sub_tmp->to_str);
X strcat(tmp_str, func_declare + cmpstt + typelen);
X strcpy(func_declare, tmp_str);
X len += (strlen(sub_tmp->to_str) - typelen - cmpstt);
X }
X
X }
X }
X }
X
X /* output extern if desired */
X if (get_option(OPT_EXTERNS) &&
X 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 if ((dummy_len = newc_parse(func_list + 1)) == -1) {
X free(func_list);
X free(func_declare);
X pop_proto();
X return;
X }
X break;
X default:
X /* K&R C format */
X if ((dummy_len = oldc_parse(func_list)) == -1) {
X free(func_list);
X free(func_declare);
X pop_proto();
X return;
X }
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}
X
X/* go through the file extracting functions */
Xvoid
Xparse_file()
X{
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', old_prev_real = ' ', 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 (curr_char == '\n') line_count++;
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 prev_char = '#';
X curr_char = preprocessor_check();
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 syntax_err("unexpected newline found in string");
X line_count++;
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 syntax_err("unexpected newline in character constant");
X line_count++;
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 ((get_option(OPT_SINGLECOMMENTS) == 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 (get_option(OPT_COMMENTS) ||
X ((num_comment == 1) &&
X get_option(OPT_FIRSTCOMMENT))) {
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 == '\n') line_count++;
X if ((curr_char == '/') && (prev_char == '*')) {
X break;
X }
X prev_char = curr_char;
X }
X curr_char = ' ';
X
X }
X prev_real = old_prev_real;
X
X } else if ((curr_char == '/') && (prev_char == '/')) {
X
X /* just yank out any C++ comments */
X if (count > 0) count--;
X while ((curr_char = getc(fpin)) != EOF) {
X
X /* test for end of comment */
X if (curr_char == '\n') {
X line_count++;
X break;
X }
X prev_char = curr_char;
X
X }
X curr_char = ' ';
X prev_real = old_prev_real;
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 syntax_err("extra right brace encountered");
X break;
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 old_prev_real = prev_real;
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 prev_char = '#';
X curr_char = preprocessor_check();
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 syntax_err("unexpected newline found in string");
X line_count++;
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 syntax_err("unexpected newline in character constant");
X line_count++;
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 == '\n') line_count++;
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 == '/' && prev_char == '/') {
X
X /* nuke C++ comments (don't count it) */
X while ((curr_char = getc(fpin)) != EOF) {
X
X /* test for end of comment */
X if (curr_char == '\n') {
X line_count++;
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}
X
END_OF_FILE
if test 54378 -ne `wc -c <'parse.c'`; then
echo shar: \"'parse.c'\" unpacked with wrong size!
fi
# end of 'parse.c'
fi
echo shar: End of archive 5 \(of 5\).
cp /dev/null ark5isdone
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.221258.17006@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: v02i043: cextract - (Ver. 1.7) C prototyper/header file generator, Part05/05 Message-ID: <1992Nov3.221258.17006@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:12:58 GMT Approved: csr@calvin.dgbt.doc.ca Lines: 2076