home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / program / kr2ansi / kr2ansi.c < prev    next >
C/C++ Source or Header  |  1993-10-23  |  26KB  |  669 lines

  1. /* ------------------------------------------------------------------------ *
  2.  *                            K R 2 A N S I . C                             *
  3.  * ------------------------------------------------------------------------ *
  4.  *                                                                    9/23/91
  5.  *  Author:   Harry Karayiannis
  6.  *            ______________________E-MAIL:_____________________
  7.  *            INTERnet:                | BITnet:
  8.  *               harryk@bucsf.bu.edu   |   cscrzcc@buacca.bu.edu
  9.  *            --------------------------------------------------
  10.  *
  11.  *  Purpose:  Read a C-code source file written in Kernighan-Ritchie's
  12.  *            programming style, and produce ANSI prototypes for all
  13.  *            functions. (Hint: using output redirection you can create
  14.  *            a file with prototypes of all the functions in your K&R C 
  15.  *            source-file. The program is automagically putting the word
  16.  *            "extern" in front of the prototype-line, so you can #include
  17.  *            the file in you current source code and compile it with an
  18.  *            ANSI compiler).
  19.  *
  20.  *  Usage:    kr2ansi [-p] [ [-r file1] | [usr_def1 ... usr_defn] ] file2
  21.  *               -p       : show parameters
  22.  *               -r file1 : read user-defined types from 'file1'
  23.  *                usr_def1 ... usr_defn :
  24.  *                          user-defined types present in 'file2'
  25.  *                file2   : the file to read C-code from
  26.  *
  27.  *  Notes:    This program is useful for people (like myself) who like
  28.  *            K&R programming style, but want to take advantage of the
  29.  *            parameter-cheking, during compilation, typically done by
  30.  *            ANSI compilers (e.g. gcc, Turbo-C, Prospero-C, etc).
  31.  *            Others simply want their K&R code to compile under an ANSI
  32.  *            compiler without watching all those "irritating" warnings
  33.  *            saying: "Function call without prototyping".
  34.  *              For either case, kr2ansi can prove very handy.....
  35.  *
  36.  *  Caveats:  The program is not bug-free. I tried to make it work with
  37.  *            files that follow the programming style presented in
  38.  *            "The C Programming Language (1st Edition)", by Kernighan
  39.  *            and Ritchie.
  40.  *            In other words, it expects K&R function declarations to
  41.  *            be in the following form:
  42.  *            (NOTE: I write comments with backslashes '\' cause
  43.  *                   MWC does not parse nested comments)
  44.  *
  45.  *              FUNCTION-TYPE FUNCTION-NAME(P1,P2,...,PN) \* comments *\
  46.  *              \* also you can have ... *\
  47.  *              \* ...more comments here *\
  48.  *                  PARAMETER-TYPE  P1,P2;      \* comments *\
  49.  *              \* ... or here *\
  50.  *                  PARAMETER-TYPE  P3;         \* more comments *\
  51.  *                  PARAMETER-TYPE  P4,...,PN;  \* yet more comments *\
  52.  *              {                       \* ... or even here *\
  53.  *                function-body
  54.  *              }
  55.  *
  56.  *            The program gets confused when it finds 1) comments inside the
  57.  *            parameter list, 2) semicolons placed after comments, 3) comments
  58.  *            that open in one line and close in a different one, 4) curly
  59.  *            braces '{' that do not appear as the first char in a separate
  60.  *            line, and perhaps in some more case I've not figured out yet.
  61.  *            But you shouldn't use such a bad programming style anyways 8*)
  62.  *            (Hint: I think that unix-like preprocessors (like "cpp" in
  63.  *                   MWc, gcc, etc) take a flag that causes comments to be
  64.  *                   removed from the source-file...check it out)
  65.  *
  66.  *            However, it is almost guaranteed to work with files that follow
  67.  *            K & R, or Rochkind's programming style (except in one case...)
  68.  *
  69.  *
  70.  *  Bugs:     kr2ansi fails to find integer functions that do not include
  71.  *            the data-type in the beginning of the function-declaration:
  72.  *            e.g.
  73.  *                  main(argc,argv)
  74.  *                      int   argc;
  75.  *                      char  *argv[];
  76.  *                  {
  77.  *                    ...
  78.  *                  }
  79.  *
  80.  *            The reason is that the program identifies a K&R function header
  81.  *            by checking the first word of the line, which *must* be a valid
  82.  *            data-type (standard or user-defined). If you come up with a bet-
  83.  *            ter algorithm please let me know. (Please don't tell me to write
  84.  *            a complete C parser, cause I won't)
  85.  */
  86.  
  87.  
  88.  
  89. #include <stdio.h>              /* don't tell me you don't know this one */
  90. #include "kr2ansi.h"            /* constants, macros & user-defined types */
  91.  
  92. char  *progname;                    /* the name of the program */
  93. char *data_types[]={ DATA_TYPES };  /* array of valid data-types */
  94. unsigned options = NONE;            /* bit map with command-line options */
  95.  
  96. /* ======================================================================== *
  97.  *                                main
  98.  * ======================================================================== */
  99.  
  100. int main(argc, argv)
  101.     int   argc;
  102.     char  *argv[];
  103. {
  104.   char  fname_in[MAXNAME];                  /* name of input file */
  105.   GLOBAL char *data_types[];                /* array of valid data-types */
  106.  
  107.   void    kr2ansi();
  108.   BOOLEAN parse();        /* return FALSE on command_line error */
  109.   extern void usage();    /* in file: ERROR.C */
  110.  
  111.  
  112.  
  113.   progname = argv[0];     /* set the program's name */
  114.   if ( !parse(argc, argv, data_types, fname_in) )
  115.     usage("[-p] [ [-r file1] | [usr_def1 ... usr_def10] ] file2");
  116.   else
  117.     kr2ansi(fname_in);
  118.  
  119.   return(0);
  120. }
  121.  
  122.  
  123. /* ======================================================================== *
  124.  *                                parse
  125.  * ======================================================================== */
  126.  
  127. BOOLEAN parse(argc, argv, data_types, fname_in)
  128.     int   argc;               /* number of args in command-line */
  129.     char  *argv[];            /* the arguments themselves */
  130.     char  *data_types[];      /* array of valid data-types */
  131.     char  *fname_in;          /* name of the input file */
  132. {
  133. /* Check the validity of the command line,
  134.  * make valid specified user-defined data-types,
  135.  * and assign the specified filename to : fname_in
  136.  */
  137.  
  138.   register int i,u;           /* integer counters */
  139.   void set_dtypes();          /* read user-def. types from a file */
  140.   GLOBAL unsigned options;    /* bit map with command-line options */
  141.   STD_CLIB char *strcpy();    /* part of the standard C-library */
  142.  
  143.  
  144.   if (argc < 2)                       /* too few arguments */
  145.     return(FALSE);
  146.  
  147.   i=1;             /* you can add your own options in this loop */
  148.   while ( argv[i][0] == '-' )
  149.   {
  150.     if ( !strcmp(argv[i],"-p") )      /* option -p: */
  151.     {                                   /* show parameters */
  152.       if (i == argc-1)
  153.         return(FALSE);
  154.       options |= SHOW_PARA;
  155.     }
  156.     else if ( !strcmp(argv[i],"-r") ) /* option -r: */
  157.     {                                   /* read user-defined types from file */
  158.       if (i != argc-3)
  159.         return(FALSE);
  160.       options |= RD_TYPES;
  161.       set_dtypes(argv[i+1], data_types);
  162.     }
  163.     else if ( !strcmp(argv[i],"") )
  164.       options |= UNUSED4;               /* unused slot */
  165.     else if ( !strcmp(argv[i],"") )
  166.       options |= UNUSED5;               /* unused slot */
  167.     else if ( !strcmp(argv[i],"") )
  168.       options |= UNUSED6;               /* unused slot */
  169.     else if ( !strcmp(argv[i],"") )
  170.       options |= UNUSED7;               /* unused slot */
  171.     else if ( !strcmp(argv[i],"") )
  172.       options |= UNUSED8;               /* unused slot */
  173.     else                              /* invalid option */
  174.       return(FALSE);                    /* return FALSE */
  175.     i++;
  176.   }
  177.  
  178.   if ( !(options & RD_TYPES) )      /* get user-def types from command-line */
  179.     for (u=i; (u<=N_DT_USR  &&  u<argc-1); u++)
  180.       strcpy(data_types[DT_USR1+u-i], argv[u]);
  181.  
  182.   strcpy(fname_in, argv[argc-1]);   /* get name of the input-file */
  183.  
  184.   return(TRUE);
  185. }
  186.  
  187.  
  188.  
  189. /* ======================================================================== *
  190.  *                                kr2ansi
  191.  * ======================================================================== */
  192.  
  193. void kr2ansi(fname)
  194.     char  *fname;             /* name of the input file */
  195. {
  196. /* This function opens the input file, and reads all
  197.  * the lines, one at a time. If a line is a valid K&R
  198.  * function decleration (header) it calls make_ansi()
  199.  * to convert the line into an ANSI function decleration
  200.  */
  201.  
  202.   FILE  *fp_in;               /* used for reading the file: fname */
  203.   char  ln[MAXLINE];          /* next line in the file: fname */
  204.  
  205.   BOOLEAN is_KR_header();     /* TRUE if ln is a valid K&R function header */
  206.   void  make_ansi();          /* make ln an ANSI function header */
  207.   extern void fatal();        /* in file: ERROR.C */
  208.   STD_CLIB char *fgets();     /* part of the standard C-library  */
  209.  
  210.  
  211.  
  212.   fp_in = fopen(fname, "r");
  213.   demand(fp_in != NULL, "file2 does not exist");
  214.   while (fgets(ln, MAXLINE, fp_in) != NULL)
  215.   {
  216.     if ( is_KR_header(ln) )
  217.     {
  218.       make_ansi(fp_in, ln);
  219.       printf("%s",ln);
  220.     }
  221.   }
  222.   fclose(fp_in);
  223. }
  224.  
  225.  
  226.  
  227. /* ======================================================================== *
  228.  *                              set_dtypes()
  229.  * ======================================================================== */
  230.  
  231. void set_dtypes(fname, data_types)
  232.     char  *fname;         /* name of the file to read user-def types from */
  233.     char  *data_types[];  /* array with valid data-types */
  234. {
  235. /*
  236.  * set_dtypes() reads up to N_DT_USR words from file 'fname' and assigns
  237.  * them to the array 'data_types[]'. Each word can be up to DT_MAXWORD
  238.  * characters long (words longer than DT_MAXWORD are truncated).
  239.  */
  240.  
  241.   FILE  *fp;              /* used for reading the file: fname */
  242.   int  c;
  243.   BOOLEAN onword;         /* TRUE if we are on a word */
  244.   register int ccount;    /* counter for word's letters (up to DT_MAXWORD) */
  245.   register int wcount;    /* counter for words (up to N_DT_USR) */
  246.   extern void fatal();    /* in file: ERROR.C */
  247.   STD_CLIB int fgetc();   /* part of the standard C-library */
  248.  
  249.  
  250.   fp = fopen(fname, "r");
  251.   demand( fp != NULL, "file1 does not exist");
  252.   while ((c=fgetc(fp)) != EOF  && IS_BLANK(c)); /* skip leading blanks */
  253.   if (c == EOF)                                 /* if file is empty, exit */
  254.   {
  255.     fclose(fp);
  256.     fatal("file1 is empty");
  257.   }
  258.  
  259.   /*
  260.    * IMPORTANT:
  261.    *    at this point we know for a fact that 'c' is
  262.    *    the first letter of the first word in the file
  263.    */
  264.  
  265.   wcount = DT_USR1;                   /* the first slot for user-def types */
  266.   ccount = 0;                         /* initialize char-counter */
  267.   data_types[wcount][ccount++] = c;   /* set the first character */
  268.   onword = TRUE;                      /* we are on the first word */
  269.   while ( wcount < DT_USR1+N_DT_USR  &&  (c=fgetc(fp)) != EOF )
  270.   {
  271.     if ( IS_BLANK(c) )                /* we are on a blank character */
  272.     {
  273.       if (onword)                       /* if it immediately follows a word */
  274.       {                                 /* we should take care of some stuff */
  275.         onword = FALSE;                     /* we're not on a word anymore */
  276.         data_types[wcount][ccount] = '\0';  /* terminate previous word */
  277.         wcount++;                           /* increase word-counter */
  278.         ccount = 0;                         /* reset char-counter */
  279.       }
  280.     }
  281.     else                              /* we are on a letter... */
  282.     {
  283.       onword = TRUE;                    /* ..thus we are on a word */
  284.       if (ccount < DT_MAXWORD-1)        /* no more DT_MAXWORD chars allowed */
  285.         data_types[wcount][ccount++] = c;   /* append 'c' in current data-type */
  286.     }
  287.   }
  288.   fclose(fp);
  289. }
  290.  
  291.  
  292. /* ======================================================================== *
  293.  *                              is_KR_header
  294.  * ======================================================================== */
  295.  
  296. BOOLEAN is_KR_header(header)
  297.     char  *header;            /* potential K&R func. header */
  298. {
  299. /* This function recognises a "valid" K&R func. header line
  300.  * by testing three basic conditions (the order is significant):
  301.  *
  302.  *  1. the first word _must_ be a valid data-type.
  303.  *
  304.  *  2. the line _must not_ contain a semicolon.
  305.  *     (BUG: we screw up if line contains ';' inside a comment)
  306.  *
  307.  *  3. a) after we remove potentially commented characters,
  308.  *     b) the last non-blank character _must_ be a closing parenthesis: ')'
  309.  *
  310.  * If any of the above conditions fail then the function returns FALSE,
  311.  * otherwise the line is considered to be valid, it is modified a little
  312.  * (see below), and the function returns TRUE.
  313.  *
  314.  * If the function concludes that the line is a valid K&R func-header
  315.  * it modifies the line in order to bring it in the form expected by
  316.  * the function make_ansi(): a) removes any white spaces and potential
  317.  * comments after the closing parenthesis, and b) appends a semicolon
  318.  * and a newline character.
  319.  * (Actually potential comments are _always_ removed)
  320.  */
  321.  
  322.   char  word[MAXWORD];        /* the first word of the line */
  323.   char  *get_1st_word();      /* returns the 1st word in a string */
  324.   register int i;             /* just a counter */
  325.   BOOLEAN valid();            /* TRUE if the 1st param. is a valid data-type */
  326.   STD_CLIB int strlen();      /* part of the standard C-library */ 
  327.   STD_CLIB char *strcpy();    /* part of the standard C-library */
  328.  
  329.  
  330.  
  331.   strcpy(word,get_1st_word(header));/* C o n d i t i o n   # 1: */
  332.   if ( !valid(word) )               /*  1st word must be a valid data-type */
  333.     return(FALSE);
  334.  
  335.   i = strlen(header);               /* C o n d i t i o n   # 2: */
  336.   while (i > 0){                    /*  no ';' allowed in the header */
  337.     if ( header[i] == ';' )
  338.       return(FALSE);
  339.     i--;
  340.   }
  341.                                     /* C o n d i t i o n   # 3: */
  342.   i = 0;                            /*  a. remove potential comments */
  343.   while (header[i] != '\0' && header[i] != '/') i++;
  344.   header[i] = '\0';
  345.   i = strlen(header)-1;             /*  b. last non-blank char must be ')' */
  346.   while ( IS_BLANK(header[i]) && i>0 ) i--;
  347.   if ( header[i] != ')' )
  348.     return(FALSE);
  349.                                     /* M o d i f y  L i n e: */
  350.   header[++i] = ';';                /* append a semicolon, and */
  351.   header[++i] = '\n';               /* a newline character     */
  352.   header[++i] = '\0';
  353.  
  354.   return(TRUE);
  355. }
  356.  
  357.  
  358.  
  359. /* ======================================================================== *
  360.  *                             get_1st_word
  361.  * ======================================================================== */
  362.  
  363. char *get_1st_word(line)
  364.     char  *line;
  365. {
  366. /* Return the first word in the parameter string
  367.  *  If the word is longer than MAXWORD,
  368.  *  the function returns W_TOO_LONG
  369.  *  NOTE:
  370.  *    W_TOO_LONG should contain _at most_ MAXWORD chars in the quotes
  371.  */
  372.  
  373.   char  word[MAXLINE];      /* reserve space for MAXLINE chars (see below) */
  374.   register int i;           /* just a counter */
  375.   STD_CLIB char *strcpy();  /* part of the standard C-library */
  376.  
  377.  
  378.  
  379.   i=0;                            /* skip leading blanks and... */
  380.   while (line[i] != '\0' && IS_BLANK(line[i]))
  381.     i++;
  382.   strcpy(word, &line[i]);         /* ...put result in: 'word' */
  383.                                   /* NOTE: 'word' has room for MAXLINE chars */
  384.  
  385.   i=0;                            /* keep only the 1st word */
  386.   while (word[i] != '\0' && !IS_BLANK(word[i]))
  387.     i++;
  388.   word[i] = '\0';
  389.                                   /* return 'word' (or W_TOO_LONG) */
  390.   return( (strlen(word) > MAXWORD) ? W_TOO_LONG : word );
  391. }
  392.  
  393.  
  394.  
  395.  
  396. /* ======================================================================== *
  397.  *                                valid
  398.  * ======================================================================== */
  399.  
  400. BOOLEAN valid(word)
  401.     char  *word;
  402. {
  403. /* Compare the string 'word' against all
  404.  * strings listed in the array 'data_types'.
  405.  * Return TRUE on the first match, or FALSE
  406.  * if 'word' is not listed in 'data_types'.
  407.  */
  408.  
  409.   register int i;             /* just a counter */
  410.   GLOBAL char *data_types[];  /* array with valid data-types */
  411.   STD_CLIB int strcmp();      /* part of the standard C-library */
  412.  
  413.  
  414.   for (i=DT_STD1; i<=(LAST_DT_STD+N_DT_USR); i++)
  415.     if ( !strcmp(word, data_types[i]) )
  416.       return(TRUE);
  417.  
  418.   return(FALSE);
  419. }
  420.  
  421.  
  422.  
  423.  
  424.  
  425. /* ======================================================================== *
  426.  *                              make_ansi
  427.  * ======================================================================== */
  428.  
  429.  
  430. void make_ansi(fp, proto)
  431.     FILE  *fp;                    /* pointer to file: fname_in */
  432.     char  *proto;                 /* ANSI-prototyping to be produced */
  433. {
  434. /* This function takes the string 'proto' and converts it to
  435.  * a valid ANSI function prototype:
  436.  *
  437.  *   First it inserts the word "extern" into the string 'line',
  438.  * just in front of the function's data-type.
  439.  *   Then it checks if the parameter-list is empty, via the
  440.  * function: has_param(), and removes all the chars after the
  441.  * opening parenthesis (i.e. 'proto' becomes:
  442.  *                            "extern fn_type fn_name(" ).
  443.  *   Now, if the parameter list was empty, the string: "void);\n"
  444.  * is appended to 'proto' and the function returns. Otherwise it
  445.  * is expecting to find the parameter-declarations between the
  446.  * function-declaration and the first '{' character. For each
  447.  * such line, it removes potential comments and checks the first
  448.  * word (parameter-type) against all valid data-types.
  449.  *   If everything is ok, the parameter-type along with the
  450.  * parameter itself are appended to 'proto' (via the function:
  451.  * append_param() ). Otherwise the parameter-type is "assumed"
  452.  * to be invalid and the string constant: UNDEFINED_DATA_TYPE
  453.  * is used instead.
  454.  * BUG: The above algorithm fails when a comment is opened in
  455.  *      one line and is closed in a different line.
  456.  *      The result is that in the output line commented words
  457.  *      will appear as a parameters of type UNDEFINED_DATA_TYPE.
  458.  */
  459.  
  460.  
  461.   char  *cp;
  462.   char  par_decl[MAXLINE];    /* parameter-declaration line */
  463.   char  par_type[MAXWORD];    /* parameter's data-type */
  464.   char  *get_1st_word();
  465.   BOOLEAN no_err = TRUE;
  466.   BOOLEAN append_param();     /* see below */
  467.   BOOLEAN has_params();       /* see below */
  468.   BOOLEAN valid();
  469.   STD_CLIB int  strlen();     /* part of the standard C-library */
  470.   STD_CLIB char *strcpy();    /* part of the standard C-library */
  471.   STD_CLIB char *strcat();    /* part of the standard C-library */
  472.   STD_CLIB char *strchr();    /* part of the standard C-library */
  473.  
  474.  
  475.  
  476.   strcpy(par_decl, "extern ");     /* put "extern" in the front */
  477.   strcat(par_decl, proto);         /* (note: here we use 'par_decl' */
  478.   strcpy(proto, par_decl);         /*  as temporary string storage) */
  479.  
  480.   if ( !has_params(proto) )        /* check & remove parameter-list */
  481.   {
  482.     strcat(proto, "void);\n");
  483.     return;
  484.   }
  485.                                               /* get next 'par_decl' */
  486.   while ( fgets(par_decl, MAXLINE, fp) != NULL  &&  no_err)
  487.   {
  488.     char  *ptr;
  489.  
  490.     if ( ptr = strchr(par_decl,'/') )         /* remove potential comments */
  491.       *ptr = '\0';
  492.  
  493.     strcpy(par_type, get_1st_word(par_decl)); /* get the parameter-type */
  494.  
  495.     if (par_type[0] == '{')                   /* if we hit a '{' we stop */
  496.       break;
  497.  
  498.     if ( !valid(par_type) )                   /* check for valid 'par_type' */
  499.       strcpy(par_type, UNDEFINED_DATA_TYPE);
  500.                                               /* append ANSI parameter-list */
  501.     no_err = append_param(proto, par_type, par_decl);
  502.   }
  503.  
  504.  
  505.   /* The function append_param() converts 'proto' to the following form: */
  506.   /*    "extern fn_type fn_name(ptype p1, ptype p2, ..., ptype pn, "    */
  507.   /*  So we need to fix 'proto''s tail by  1. erasing the last two chars */
  508.   /*  (namely ' ' and ',')  and  2. appending the string: ");\n"  */
  509.  
  510.   cp = proto + (strlen(proto)-2);  /* go two chars back */
  511.   *cp = ')';
  512.   *(cp+1) = ';';
  513.   *(cp+2) = '\n';
  514.   *(cp+3) = '\0';
  515. }
  516.  
  517.  
  518. /* ======================================================================== *
  519.  *                              has_params
  520.  * ======================================================================== */
  521.  
  522. BOOLEAN has_params(header)
  523.     char  *header;        /* the function-header line */
  524. {
  525. /* This function checks if the parameter-list is empty,
  526.  * and removes all chars after the opening parenthesis.
  527.  * Its task is to modify 'header' and to return TRUE if
  528.  * the parameter-list was empty.
  529.  * NOTICE that the parameter-list is considered empty
  530.  * when either the char ')' comes right after char '('
  531.  *          or it consists of white(BLANK) characters.
  532.  */
  533.  
  534.   char    *cp1, *cp2;           /* temporary pointers */
  535.   BOOLEAN param_yes = FALSE;    /* what the function returns */
  536.   STD_CLIB char *strchr();      /* part of the standard C-library */
  537.  
  538.  
  539.  
  540.   cp1 = cp2 = strchr(header,'('); /* save the start of param-list in cp2 */
  541.  
  542.   if ( *(cp1+1) == ')' )          /* if ')' comes right after '('  */
  543.   {                               /*   Remove all charactes coming */
  544.     *(cp1+1) = '\0';              /*   right after '(', and...     */
  545.     return(FALSE);                /*   ...return FALSE             */
  546.   }
  547.  
  548.                                   /* check for BLANK parameter-list */
  549.   while ( *cp2 != '\0'  &&  IS_BLANK(*cp2) )
  550.     cp2++;
  551.   if (*cp2 != ')')
  552.     param_yes = TRUE;
  553.  
  554.   *(cp1+1) = '\0';
  555.  
  556.   return(param_yes);
  557. }
  558.  
  559.  
  560.  
  561. /* ======================================================================== *
  562.  *                              append_param
  563.  * ======================================================================== */
  564.  
  565. BOOLEAN append_param(proto, par_type, par_decl)
  566.     char  *proto;                 /* the output ANSI-prototype */
  567.     char  *par_type;              /* the data-type of the parameter */
  568.     char  *par_decl;              /* the parameter-declaration line */
  569. {
  570. /* Get a parameter-declaration line, construct the appropriate
  571.  * ANSI-prototyped-declaration string, and append it to the ANSI 
  572.  * prototype.
  573.  *                  *** I m p o r t a n t ***
  574.  *  'par_decl' has been ensured (by function make_ansi()), to be
  575.  *  valid (i.e. the 1st word is a valid data-type). So the string
  576.  *  coming after the 1st word(='par_type') should be a list of
  577.  *  parameters. BUT if 'par_type' is one of the strings "unsigned",
  578.  *  short" or "long", then the 2nd word might be "int" (which should
  579.  *  not be treated as a parameter, but as part of the parameters'
  580.  *  data-type). Furthermore, 'par_type' may be "register", in which
  581.  *  case we only the 2nd word only (or the string "register" if the
  582.  *  2nd word is not a valid data-type).
  583.  */
  584.  
  585.   char  *s, *param;
  586.   char  _str[MAXWORD];
  587.   register int i;
  588.  
  589.   void construct_ANSI_declaration();
  590.   BOOLEAN valid();
  591.   STD_CLIB int  *strcmp();
  592.   STD_CLIB char *strcat(), *strtok();
  593.  
  594.  
  595.  
  596.   i = 0;                      /* skip the first word of 'par_decl' */
  597.   while (par_decl[i] != '\0' &&  IS_BLANK(par_decl[i])) i++;
  598.   while (par_decl[i] != '\0' && !IS_BLANK(par_decl[i])) i++;
  599.   s = &par_decl[i];
  600.                               /* check for: register data-type,*
  601.                                * or unsigned/short/long int    */
  602.   strcpy(_str, get_1st_word(s));
  603.   if ( valid(_str) )
  604.   {
  605.     if ( !strcmp(par_type,"register") )         /* handle "register" cases */
  606.       strcpy(par_type, _str);
  607.     else                                        /* handle unsigned/long/short */
  608.     {
  609.       strcat(par_type, " ");                      /* cat " int" in 'par_type'*/ 
  610.       strcat(par_type, _str);
  611.     }
  612.     while( *s != '\0'  &&   IS_BLANK(*s) ) s++; /* skip the 2nd word: "int" */
  613.     while( *s != '\0'  &&  !IS_BLANK(*s) ) s++;
  614.   }
  615.                               /* append ANSI param-declaration to 'proto' */
  616.   while ( (param = strtok(s, ",; \t\n")) != NULL )
  617.   {
  618.     if ( strlen(proto) >= MAXLINE-strlen(par_type)-strlen(param)-4 )
  619.     {                         /* error-check for "output line too long" */
  620.       strcat(proto, "<...>, ");
  621.       return(FALSE);
  622.     }
  623.     construct_ANSI_declaration(proto, par_type, param);
  624.     s = (char *)NULL;
  625.   }
  626.  
  627.   return(TRUE);
  628. }
  629.  
  630.  
  631. /* ======================================================================== *
  632.  *                      construct_ANSI_declaration
  633.  * ======================================================================== */
  634.  
  635. void construct_ANSI_declaration(proto, par_type, param)
  636.     char  *proto;         /* the functin prototype */
  637.     char  *par_type;      /* parameter's data-type */
  638.     char  *param;         /* the parameter itself */
  639. {
  640. /* Construct the ANSI parameter-declaration,
  641.  * so it can be appended in the parameter-list
  642.  * (if DONT_SHOW_PARAMETERS is not defined, the
  643.  *  parameter itself is also included)
  644.  */
  645.  
  646.   register int i;           /* just a counter */
  647.   GLOBAL unsigned options;  /* bit map with command-line options */
  648.   STD_CLIB int  strlen();   /* part of the standard C-library */
  649.   STD_CLIB char *strcat();  /* part of the standard C-library */
  650.  
  651.  
  652.   strcat(proto, par_type);        /* append the parameter's data-type */
  653.   strcat(proto, " ");
  654.  
  655.   if (options & SHOW_PARA)        /* include parameter in parameter-list */
  656.     strcat(proto, param);
  657.   else                            /* exclude parameter from parameter-list */
  658.   {
  659.     for (i=0; param[i] != '\0'; i++)    /* look for any pointers */
  660.       if (param[i] == '['  ||  param[i] == '*')
  661.         strcat(proto, "*");
  662.   }
  663.  
  664.   i = strlen(proto)-1;            /* separate parameters with ", " */
  665.   if ( proto[i] == ' ' )
  666.     proto[i] = '\0';
  667.   strcat(proto, ", ");
  668. }
  669.