/*************************************************************************** Program: ansi File: ansi.c Version: V1.0 Date: 16.12.91 Function: Convert C source to and from ANSI form. Copyright: SciTech Software 1991 Author: Andrew C. R. Martin Address: SciTech Software 23, Stag Leys, Ashtead, Surrey, KT21 2TD. Phone: +44 (0372) 275775 EMail: UUCP: cbmuk!cbmuka!scitec!amartin JANET: andrew@uk.ac.ox.biop **************************************************************************** This program is not in the public domain, but it may be freely copied and distributed for no charge providing this header is included. The code may be modified as required, but any modifications must be documented so that the person responsible can be identified. If someone else breaks this code, I don't want to be blamed for code that does not work! The code may not be sold commercially without prior permission from the author, although it may be given away free with commercial products, providing it is made clear that this program is free and that the source code is provided with the program. **************************************************************************** Description: ============ This program alters function definitions to convert non-ANSI C code to ANSI form. The -k and -p flags allow conversion from ANSI to K&R and generation of prototypes respectively. There are two *minor* problems: 1. In generation of prototypes. If a function has been defined with no explicit type it defaults to being int. Strictly the prototype should explicitly state this is int, but doesn't. 2. If a conversion actually occurs (either to or from ANSI) any comments which were in the definition will be lost. The only restriction (that I can think of!) on the code being processed is that a function definition must be the first thing on a line. i.e. if a comment is placed on the same line as the definition but before it, the program will think the whole line is a comment. **************************************************************************** Usage: ====== ansi [-k -p] -k generates K&R form code from ANSI -p generates a set of prototypes **************************************************************************** Revision History: ================= V1.0 17.12.91 Added support for prototype and K&R code generation. Also reorganised some code. ***************************************************************************/ /* System includes */ #include #include #ifdef AMIGA #include #else /* Not an Amiga */ typedef short BOOL; #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #endif /**************************************************************************/ #define MAXBUFF 200 /* Max chars in a line */ #define MAXLINES 50 /* Max lines in a function definition */ #define DIC 34 /* Double inverted commas */ #define SIC 39 /* Single inverted commas */ #define LF 10 /* Line feed */ #define CR 13 /* Carriage return */ #define MakeANSI 1 /* K&R-->ANSI */ #define MakeKR 2 /* ANSI-->K&R */ #define MakeProtos 3 /* Make prototypes */ #define toggle(x) (x) = abs((x)-1) /**************************************************************************/ /* Prototypes */ int main(int argc, char **argv); int GetVarName(char *buffer, char *strparam); void process_file(FILE *fp_in, FILE *fp_out, int mode); int isInteresting(char *buffer); void Ansify(FILE *fp, char funcdef[MAXLINES][MAXBUFF], int ndef, int mode); void WriteANSI(FILE *fp, char *varname, char *definitions); char *FindString(char *buffer, char *string); int isFunc(char funcdef[MAXLINES][MAXBUFF], int ndef); void terminate(char *string); void DeAnsify(FILE *fp_out, char funcdef[MAXLINES][MAXBUFF], int ndef); void WriteKR(FILE *fp, char *varname, char *definitions); /**************************************************************************/ main(int argc, char **argv) { int mode = MakeANSI; BOOL noisy = TRUE; FILE *fp_in = NULL, *fp_out = NULL; if(argc < 3) { printf("\nUsage: ansi [-k -p -q] \n"); printf(" Converts a K&R style C file to ANSI or vice versa\n"); printf(" -k generates K&R form code from ANSI\n"); printf(" -p generates a set of prototypes\n"); printf(" -q quiet mode\n\n"); exit(0); } /* Parse the command line */ argv++; while(--argc > 2) { if(argv[0][0] == '-') { switch(argv[0][1]) { case 'k': case 'K': mode = MakeKR; break; case 'p': case 'P': mode = MakeProtos; break; case 'q': case 'Q': noisy = FALSE; break; default: printf("Unknown switch %s\n",argv[0]); exit(0); } } else { printf("Invalid switch %s\n",argv[0]); exit(0); } argv++; } /* Open files */ if((fp_in = fopen(argv[0],"r")) == NULL) { printf("Unable to open input file %s\n",argv[0]); exit(1); } if((fp_out = fopen(argv[1],"w")) == NULL) { printf("Unable to open output file %s\n",argv[1]); exit(1); } /* Give a message */ if(noisy) { printf("SciTech Software ansi C converter\n"); printf("Copyright (C) 1991 SciTech Software. All Rights Reserved.\n"); printf("This program is freely distributable providing no profit is made in so doing.\n\n"); switch(mode) { case MakeANSI: printf("Converting file %s to ANSI\n",argv[0]); break; case MakeKR: printf("Converting file %s to Kernighan and Ritchie\n",argv[0]); break; case MakeProtos: printf("Generating prototypes for file %s\n",argv[0]); break; default: break; } } /* Now process the files as required by the flags */ process_file(fp_in, fp_out, mode); return(0); } /************************************************************************ GetVarName(buffer, strparam) ---------------------------- Input: char *buffer A character string Output: char *strparam Returned character string Returns: int Number of characters pulled out of the buffer string This routine returns the first , or ) delimited group of characters from character string `buffer' *************************************************************************/ int GetVarName(char *buffer, char *strparam) { int i, j = 0; for(i=0;buffer[i];i++) { /* Break out if we've got a , or ) */ if(buffer[i]==',' || buffer[i]==')') break; /* Otherwise copy the character */ strparam[j++] = buffer[i]; } strparam[j]='\0'; /* Strip any trailing spaces */ for(j=strlen(strparam) - 1 ; j >= 0 && (strparam[j] == ' ' || strparam[j] == '\t'); j--) strparam[j] = '\0'; return(i); } /*************************************************************************** process_file(fp_in, fp_out, mode) --------------------------------- Input: FILE *fp_in File to be processed FILE *fp_out Output file being created int mode Processing mode. MakeANSI: Create ANSI MakeKR: Create K&R MakeProtos: Create prototypes Returns: void Does the work of processing the file ***************************************************************************/ void process_file(FILE *fp_in, FILE *fp_out, int mode) { /* These are static so they're not placed on the stack. This lets us run with the default stack size on the Amiga */ static char buffer[MAXBUFF], funcdef[MAXLINES][MAXBUFF]; int i, ndef; while(fgets(buffer,MAXBUFF,fp_in)) { terminate(buffer); /* See if this line is possibly a function definition */ if(isInteresting(buffer)) { /* It's one of: (a) A function definition (b) A prototype (c) An external To be a function, it must contain a (, though this could be a prototype. */ if(strchr(buffer,'(') != NULL) { /* It's a function or a prototype. Copy it into funcdef assembling additional strings up to the first ; or { */ strcpy(funcdef[0], buffer); ndef=0; while(strchr(funcdef[ndef],';') == NULL && strchr(funcdef[ndef],'{') == NULL) { if(!fgets(funcdef[++ndef],MAXBUFF,fp_in)) break; if(ndef >= MAXLINES) { printf("Too many lines in function definition\n"); exit(1); } terminate(funcdef[ndef]); /* Pass the string to isInteresting() to update internal count of comments, brackets, etc. We don't care about the return value. */ isInteresting(funcdef[ndef]); } if(isFunc(funcdef,ndef)) { /* It's actually a function. If it was terminated by a ; we must assemble up to a { */ if(strchr(funcdef[ndef],';') != NULL && strchr(funcdef[ndef],'{') == NULL) { while(strchr(funcdef[ndef],'{') == NULL) { if(!fgets(funcdef[++ndef],MAXBUFF,fp_in)) break; if(ndef >= MAXLINES) { printf("Too many lines in function definition\n"); exit(1); } terminate(funcdef[ndef]); /* Pass the string to isInteresting() to update internal count of comments, brackets, etc. We don't care about the return value. */ isInteresting(funcdef[ndef]); } } /* Now actually ANSIfy, deANSIfy, or generate prototypes. Output to fp_out */ switch(mode) { case MakeKR: DeAnsify(fp_out, funcdef, ndef); break; case MakeANSI: case MakeProtos: Ansify(fp_out, funcdef, ndef, mode); break; default: printf("Internal confusion!!!\n"); break; } } else { /* It's a prototype, so copy each line out */ if(mode != MakeProtos) { for(i=0; i<=ndef; i++) fprintf(fp_out,"%s\n",funcdef[i]); } } } else { /* It's an extern, so just copy it */ if(mode != MakeProtos) fprintf(fp_out,"%s\n",buffer); } } else { /* We're in a #, comment, string, function or blank line. Simply copy the line to the output file. */ if(mode != MakeProtos) fprintf(fp_out,"%s\n",buffer); } } } /*************************************************************************** isInteresting(buffer) --------------------- Input: char *buffer Line from file Returns: int 1: Line is interesting-may be a function 0: Line not interesting Tries to determine whether a line is possibly a function definition. ***************************************************************************/ int isInteresting(char *buffer) { static int comment_count = 0, bra_count = 0, inSIC = 0, inDIC = 0; int i, retval = 0, isBlank = TRUE; /* Not interested if it's a #define, etc. */ if(buffer[0] == '#') return(0); /* If all of these are unset when we enter, we're interested */ if(!bra_count && !inDIC && !inSIC && !comment_count) retval = 1; /* If the first thing in this string was a comment we're no longer interested. */ for(i=0; buffer[i] && (buffer[i] == ' ' || buffer[i] == '\t'); i++); if(buffer[i] == '/' && buffer[i+1] == '*') retval = 0; /* Step along the line */ for(i=0; i definitions && *start != ';' && *start != '/') start--; if(*start == ';' || *start == '/') start++; /* Kill any leading spaces */ while(*start && (*start == ' ' || *start == '\t')) start++; /* If there are any commas between start and stop, move stop back to the first comma */ for(ptr=start; ptr<=stop; ptr++) { if(*ptr == ',') { stop = ptr; break; } } /* Step stop on to the first , or ; */ while(*stop && *stop != ',' && *stop != ';') stop++; /* Now step back over any spaces */ stop--; while(stop > start && (*stop == ' ' || *stop == '\t')) stop--; /* Now step back over the first variable name */ while(stop > start && *stop != ' ' && *stop != '\t') stop--; /* and over the spaces preceeding it */ while(stop > start && (*stop == ' ' || *stop == '\t')) stop--; /* Now copy the string delimited by start and stop */ for(i=0; i definitions && (*start == ' ' || *start == '\t')) start--; while(*(start--) == '*') fprintf(fp,"*"); fprintf(fp,"%s",varname); /*** Finally see if it's a [] array ***/ /* Set these to the position of varname in the definitions list */ start = stop = FindString(definitions, varname); /* Step stop on to the first , or ; */ while(*stop && *stop != ',' && *stop != ';') stop++; /* Now step back over any spaces */ stop--; while(stop > start && (*stop == ' ' || *stop == '\t')) stop--; /* See if there is a [ between start and stop */ while(start= funcdef[line] && (*termchar == ' ' || *termchar == '\t')) termchar--; /* If we stepped back beyond the start of the line, go to the previous line */ if(termchar < funcdef[line]) { line--; if(line < 0) break; termchar = funcdef[line] + strlen(funcdef[line]); } else { break; } } /* OK, see if the character was a ) */ if(*termchar == ')') retval = 0; else retval = 1; return(retval); } /************************************************************************* terminate(string) ----------------- I/O: char *string A character string Returns: void Terminates a string at the first \n *************************************************************************/ void terminate(char *string) { int i; for(i=0;string[i];i++) { if(string[i] == '\n') { string[i] = '\0'; break; } } } /************************************************************************* DeAnsify(fp, funcdef, ndef) --------------------------- Input: FILE *fp File being written char funcdef[][] Function definition array int ndef Number of definition lines Returns: void Writes a K&R function definition from the ANSI (or K&R) form in funcdef. *************************************************************************/ void DeAnsify(FILE *fp, char funcdef[MAXLINES][MAXBUFF], int ndef) { int i, j, nparam, isKR = FALSE, bufflen = 0, last = FALSE; char *buffer = NULL, *bufptr, *funptr, *ptr, *start, *stop, temp[MAXBUFF], func[MAXBUFF], varname[80]; ndef++; /* If any of the lines contains a ;, it's already KR */ for(i=0; ibufptr && (*stop==' ' || *stop=='\t')) stop--; /* Step back to the start of the variable name */ start = stop; while(start>=bufptr && *start!=' ' && *start!='\t' && *start != '*') start--; start++; /* Copy the variable name into our function buffer adding a , and space or ) as appropriate. */ for(j=0; start<=stop; start++, j++) temp[j] = *start; temp[j] = '\0'; if((ptr = strchr(temp,'[')) != NULL) *ptr = '\0'; if(last) strcat(temp,")"); else strcat(temp,", "); strcat(func, temp); funptr++; } /* We can now echo the parameter list to the output file */ fprintf(fp,"%s\n",func); /* Work through the parameter list writing the parameter definition lines */ funptr = func; while(*funptr && *funptr != ')') { /* Kill spaces */ for( ; funptr && (*funptr == ' ' || *funptr == '\t'); funptr++) ; /* Get a parameter */ funptr += GetVarName(funptr, varname) + 1; /* Write the K&R version */ WriteKR(fp, varname, bufptr); } fprintf(fp,"{\n"); /* Free memory */ free(buffer); } } /*************************************************************************** WriteKR(fp, varname, definitions) --------------------------------- Input: FILE *fp File being written char *varname Variable being processed char *definitions ANSI style definitions Returns: void Writes a variable definition in K&R form by extracting information from the ANSI definition. ***************************************************************************/ void WriteKR(FILE *fp, char *varname, char *definitions) { char *start, *stop, temp[MAXBUFF]; int i; /* Find the variable name in the definitions */ start = stop = FindString(definitions,varname); /* Step start back to the preceeding , / or (, then forward over any spaces */ while(start >= definitions && *start != '(' && *start != ',' && *start != '/') start--; start++; while(start