/*************************************************************************/ /* */ /* flow.c - A program to analyse Fortran77 programs */ /* */ /* --------------------------------------------------------------------- */ /* Copyright (c) 1996 by Dirk Geschke, */ /*************************************************************************/ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /*************************************************************************/ #include #include #include #include #define VERSION 0.12 #define NO_SUB 1000 #define NO_PROG 1 #define NO_CALL 5000 /* declaration of functions */ void RoutineCheck(char *Line); void Upcase(char *Line); void Routine_name(char *Line,char *R_Name); void help(char *PROG); void Output_Result(); void SUB_find(char *Name); /* new type declaration*/ struct Fort_Element { char Name [60]; int Call; }; /* G L O B A L variables */ struct Fort_Element Subroutine[NO_SUB+1]; /* storages subroutine names */ struct Fort_Element Program; /* storages program name */ struct Fort_Element Call[NO_CALL]; /* storages CALL names */ int s_call=0; /* counts CALL statements */ int subrout=0; /* counts SUBROUTINE statements */ int if_count=0; /* counts IF statements */ long int Comment=0; /* counts COMMENT lines */ int Prog_Anf=-1; /* storages number of first CALL of SUBROUTINE from PROGRAM */ int Prog_Ende=0; /* storages number of last CALL of SUBROUTINE from PROGRAM */ int Level=1; long int ActLine=0; char Dat_Name [81]; /* name of actual file */ FILE *CallFile=NULL; FILE *SubFile=NULL; FILE *OUTFILE=NULL; char S_OUT[]="FLOW.SUBS"; /* file name where to print subroutines */ char C_OUT[]="FLOW.CALL"; /* file name where to print call's */ int No_Main=0; /* Optionkeys */ int O_SUBROUTINE=0; int O_CALL=0; int O_InFile=0; int O_FIND=0; int O_FICALL=0; int O_FISUB=0; int O_OutFile=0; int O_RECURS=0; int O_WARN72=0; int O_NEWSTART=0; /* begin of main */ int main(int argc, char *argv[]) { int k,d,i; char Line [81]; char firstChar; char Option; FILE *InFile=NULL; long int Count_Lines=0; char PRG_Name[60]; OUTFILE=stdout; for (k=0; k73) { while (Line[i-2]==32) i--; /* only empty spaces at the end? */ /* -1 for EOL sign and -1 because */ /* of beginning at Line[0] => i-2 */ if (i>73) fprintf(stderr,"Warning: Line %ld in file %s \ consists of %d characters!\n",ActLine,Dat_Name,i-1); } } RoutineCheck(&Line[6]); } } /* if there is no definition of a SUBROUTINE in the same file after the PROGRAM routine, use EOF as end of PROGRAM statement */ if (Program.Call==1) { Program.Call=0; Prog_Ende=s_call-1; } fclose(InFile); } if (O_FISUB) fclose(SubFile); if (O_FICALL) fclose(CallFile); if (InFile==NULL) help(PRG_Name); if (strlen(Program.Name)==0) { fprintf(stderr,"\n\nError: No starting point found!\n\n"); No_Main=1; } if (O_OutFile) { strcpy(Dat_Name,Program.Name); strcat(Dat_Name,".FLOW"); if ((OUTFILE=fopen(Dat_Name,"w")) == NULL) { fprintf(stderr,"\nError: Can't open file %s!\n\n",Dat_Name); exit(2); } } if (O_NEWSTART==1) /* new starting point */ { fprintf(OUTFILE,"\n\n Results of subroutine %s:\n",Program.Name); fprintf(OUTFILE," ======================="); } else { fprintf(OUTFILE,"\n\n Results of program %s:\n",Program.Name); fprintf(OUTFILE," ===================="); } for (k=0; k1) { fprintf(stderr,"\n\aToo many definitions of SUBROUTINE %s!\n",\ Subroutine[0].Name); exit(2); } Program.Call=1; strcpy(Program.Name,Subroutine[0].Name); /* starting point found */ } else { if (O_SUBROUTINE) printf(" %s \n",Subroutine[subrout].Name); if (O_FISUB) fprintf(SubFile,"%-20s %-20s line %6ld\n", Subroutine[subrout].Name,Dat_Name,ActLine); } return; } /* PROGRAM? If starting point is a Subroutine skip this step */ if (O_NEWSTART==0) { strncpy(Sign,ptr,8); Sign[8]='\0'; if (strcmp(PROG,Sign)==0) { p++; strcpy(Line,&Line[i+8]); if (p>1) { fprintf(stderr,"\n\aToo many definitions of PROGRAM!\n"); exit(2); } Routine_name(Line,Program.Name); strcpy(Subroutine[0].Name,Program.Name); Program.Call=1; return; } } /* IF line? If true then find out if there is a CALL in it. */ if ((Line[i]=='I')&& (Line[i+1]=='F')) if ((Line[i+2]==' ')||(Line[i+2]=='(')) /* IF line found */ { if_count++; for (j=i+2; j0) /* IF line */ { i=j; ptr=&Line[i]; while (Line[i]==32) i++; /* removing leading spaces! */ ptr=&Line[i]; /* Check for 'IF (...) THEN' structure */ strncpy(Sign,ptr,4); if(strcmp(THEN,Sign)==0) { i+=4; while (Line[i]==32) i++; /* removing leading spaces! */ ptr=&Line[i]; } } /* Check for CALL statement */ strncpy(Sign,ptr,5); Sign[5]='\0'; /* append end-of-string sign */ if (strcmp(CALL,Sign)==0) { s_call++; if (s_call==NO_CALL) { fprintf(stderr,"Too many CALL statements\n"); fprintf(stderr,"Increase parameter NO_CALL!\n"); exit(2); } strcpy(Line,&Line[i+5]); Routine_name(Line,Call[s_call-1].Name); Call[s_call-1].Call=subrout; if (Program.Call==1) { if (Call[s_call-1].Call==subrout) /* 1. Call from Program */ { if (Prog_Anf==-1) { Prog_Anf=s_call-1; if (s_call==0) Prog_Anf=s_call; Call[s_call-1].Call=0; } } } if (O_CALL) printf("CALL %s \n",Call[s_call-1].Name); if (O_FISUB) fprintf(CallFile,"%-20s %-20s line %6ld\n",Call[s_call-1].Name, Dat_Name,ActLine); } } /************************************************************** * * * This function is used to extract the name of called * * or defined procedure. * * * **************************************************************/ void Routine_name(char *Line, char *R_Name) { int i=0; int offset=0; /* removing of leading spaces */ while (Line[offset]==32) offset++; /* space, opened parenthese or EOL are a sign for end of routine name */ while ((Line[i+offset] !=' ' ) && (Line[i+offset] != '(' ) && (Line[i+offset] !='\n')) { R_Name[i]= Line[i+offset]; i++; } R_Name[i]='\0'; /* append end of string! */ } /******************************************************************** * * * Printing if error with input or option -h * * * ********************************************************************/ void help(char *PROG) { printf("\n\nUsage: %s [-hCcFSsV] file [files... ] \n\n",PROG); printf(" -h: Printing of this message \n"); printf(" -C: Printing of each found CALL during the input\n"); printf(" -c: Each found CALL statement is reported \n"); printf(" in a file named %s with the name of the\n", C_OUT); printf(" file where it was found and the line number\n"); printf(" -F: Print name of file actually on work \n"); printf(" -f: The output is written to a file with the name \n"); printf(" of the .FLOW\n"); printf(" -U: Printing of unknown SUBROUTINE calls\n"); printf(" -r : Set a new starting point. Start with the \n"); printf(" SUBROUTINE instead of PROGRAM line\n"); printf(" -R: Omit following recursive calls\n"); printf(" -S: Printing of each found SUBROUTINE during the input\n"); printf(" -s: Each found SUBROUTINE is reported in a file \n"); printf(" named %s with the name of the\n", S_OUT); printf(" file where it was found and the line number\n"); printf(" -V: Number of version\n"); printf(" -W: A warning is given if a code line exceeds the\n"); printf(" length of 72 characters\n"); printf("\nFor further information see manual page flow(1).\n\n"); exit(2); } /******************************************************************** * * * Printing of SUBROUTINE calls out of main PROGRAM * * * ********************************************************************/ void Output_Result() { int i,k; for (i=Prog_Anf; i