home *** CD-ROM | disk | FTP | other *** search
- MODULE ProcCheck;
-
- (* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * ProcCheck is public domain. Use it any way you see fit, but please *
- * leave my name and E-Mail address in both the source code and *
- * executables throughout all revisions. If you make any enhancements, *
- * I would appreciate hearing about it. Thank you. *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * *
- * ProcCheck.mod V1.0 (12-Sept-1989) by David Czaya *
- * V1.1 (15-Feb-1990) cleaned up a bit and tried *
- * to make the code semi-generic *
- * for portability. *
- * *
- * E-mail: CIS 73445,407 *
- * PeopleLink -Dave- *
- * GEnie DCzaya *
- * *
- * Originally written in "Benchmark Modula 2" for the Amiga! I tried *
- * to use standard Modula 2 procedures (with certain exceptions) so *
- * that this code could be easily ported to other implementations and *
- * machines. Machine specifics are marked. *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * *
- * ProcCheck (PROCEDURE CHECK) is a PRE-COMPILE utility which *
- * scans through Modula 2 source code and attempts to pick out all *
- * the procedures that have been referenced. It then divides the *
- * procedures into the following categories: *
- * *
- * 1) Undeclared Procedures - very useful before compiling. Tells *
- * you which procedures have been used, but not IMPORTed or *
- * defined. *
- * *
- * 2) Unused Procedures - shows procedures which have been IMPORTed *
- * or defined, but never called. Excellent for cleaning up the *
- * code. *
- * *
- * 3) Standard Identifiers, Internal procedures and IMPORTed *
- * procedures are all identified and the number of calls made to *
- * each is recorded. This is handy for optimizing your code. You can *
- * tell at a glance whether certain procedures are being overworked, *
- * etc. *
- * *
- * One of these days, I might make it parse out variables, constants, *
- * enumerations, etc. Let me know if you're interested. *
- * *
- * Oh, and it timestamps the report file, of course. *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * *
- * Caveats: ProcCheck is not the greatest code parser in the world. *
- * It's not too difficult to confuse it into picking up or *
- * missing information depending on your style of writing. *
- * Nevertheless, it's output is not critical and it should *
- * be somewhat useful. *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *)
-
-
- FROM AmigaDOS IMPORT DateStamp, DateStampRecord;
- FROM InOut IMPORT WriteString, WriteLn, ReadString, Read, Done, Echo,
- OpenOutputFile, CloseOutput, Write, WriteInt;
- FROM LongInOut IMPORT WriteLongInt;
- FROM Strings IMPORT CompareString, Relation, CopyString, ConcatString,
- StringLength, LocateSubString, ConvStringToUpperCase;
- FROM FileSystem IMPORT File, Response, Close, Lookup, SetPos,
- GetPos, ReadChar;
- FROM Memory IMPORT AllocMem, FreeMem, MemReqSet, MemPublic, MemClear;
-
- TYPE
- ProcRecPtr = POINTER TO ProcRec;
- ProcRec = RECORD
- prFileName : ARRAY [0..30] OF CHAR;
- prProcName : ARRAY [0..255] OF CHAR;
- prCount : INTEGER;
- prDeclared : BOOLEAN;
- prTag : BOOLEAN;
- next : ProcRecPtr;
- END;
-
- Control = (off,on);
-
- CONST
- ProgName = 'ProcCheck';
- BadInput = 'Invalid input.\n';
- ColumnWidth = 55;
- Separator = '*';
- ColorReset = '\x9Bm';
- Color = '\x9B33m'; (* Color 3 *)
- CursorOff = '\x9B0 p';
- CursorOn = '\x9B p';
-
- VAR
- inFile : File;
- str,
- moduleName : ARRAY [0..128] OF CHAR;
- nextChar : CHAR;
- memHead,
- memLast : ProcRecPtr;
- ansi : Control;
-
-
- PROCEDURE ColorOn(); (* Amiga specific *)
- BEGIN
- IF ansi = on THEN
- WriteString(Color);
- END;
- END ColorOn;
-
-
- PROCEDURE ColorOff(); (* Amiga specific *)
- BEGIN
- IF ansi = on THEN
- WriteString(ColorReset);
- END;
- END ColorOff;
-
-
- PROCEDURE GetDate(); (* Amiga specific *)
- VAR
- dsRec : DateStampRecord;
- n,
- m, d, y,
- hrs, min, sec : CARDINAL;
-
- AmPm : ARRAY[0..4] OF CHAR;
-
- PROCEDURE Spacer(VAR in : CARDINAL);
- BEGIN
- IF in < 10 THEN
- Write(60C);
- WriteInt(in,1);
- ELSE
- WriteInt(in,2);
- END;
- END Spacer;
-
- BEGIN
- DateStamp(dsRec);
- n := dsRec.dsDays - 2251D;
- y := (4 * n + 3) DIV 1461;
- n := n - ((1461 * y) DIV 4);
- y := y + 1984;
- m := ((5 * n + 2) DIV 153);
- d := (n) - (153 * m + 2) DIV 5 + 1;
- m := m + 3;
- IF m > 12 THEN
- INC(y);
- DEC(m,12);
- END;
-
- AmPm := " am\t\t";
- hrs := 0;
- min := dsRec.dsMinute;
- sec := dsRec.dsTick DIV 50D;
-
- IF min > 59 THEN
- hrs := min DIV 60;
- min := min MOD 60;
- END;
-
- IF hrs > 11 THEN
- AmPm := " pm\t\t";
- END;
-
- IF hrs > 12 THEN DEC(hrs,12) END;
- IF hrs = 0 THEN INC(hrs,12) END;
-
- WriteInt(m,0); Write('/');
- WriteInt(d,0); Write('/');
- WriteInt(y-1900,0); Write('\n');
-
- WriteInt(hrs,2); (* Write formatted hour *)
- Write(72C);
- Spacer(min);
- Write(72C);
- Spacer(sec);
- WriteString(AmPm); (* Write am/pm msg. *)
- END GetDate;
-
-
- PROCEDURE AlphaNum(c: CHAR): BOOLEAN;
- BEGIN
- RETURN(((c >= 'A') AND (c <= 'Z')) OR
- ((c >= 'a') AND (c <= 'z')) OR
- ((c >= '0') AND (c <= '9')));
- END AlphaNum;
-
-
- PROCEDURE DrawCharLine(c: CHAR; len: CARDINAL);
- BEGIN
- WHILE len > 0 DO
- Write(c);
- DEC(len);
- END;
- END DrawCharLine;
-
-
- PROCEDURE WriteInfo();
- CONST
- Undeclared = 'Undeclared Procedures\n\n';
- Unused = 'Unused Procedures (IMPORTed variables, constants, etc.)\n\n';
- Idents = 'Standard Identifiers';
- Internal = 'Internal Procedures';
- Imports = 'IMPORTed Procedures (variables, constants, etc.)';
- VAR
- tempStr : ARRAY [0..255] OF CHAR;
-
- BEGIN
- IF ansi = on THEN
- WriteString(CursorOff);
- END;
-
- DrawCharLine(Separator,ColumnWidth); WriteLn;
- ColorOn();
- WriteString(Undeclared);
- ColorOff();
-
- memLast := memHead;
- WHILE memLast # NIL DO
- WITH memLast^ DO
- IF (NOT prDeclared) THEN
- prTag := TRUE;
- CopyString(tempStr,prFileName);
- ConcatString(tempStr,'.');
- ConcatString(tempStr,prProcName);
- WriteString(tempStr);
- WriteLn;
- END;
- END;
- memLast := memLast^.next;
- END;
-
- DrawCharLine(Separator,ColumnWidth); WriteLn;
- ColorOn();
- WriteString(Unused);
- ColorOff();
-
- memLast := memHead;
- WHILE memLast # NIL DO
- WITH memLast^ DO
- IF (prCount <= 0) THEN
- prTag := TRUE;
- CopyString(tempStr,prFileName);
- ConcatString(tempStr,'.');
- ConcatString(tempStr,prProcName);
- WriteString(tempStr);
- WriteLn;
- END;
- END;
- memLast := memLast^.next;
- END;
-
- DrawCharLine(Separator,ColumnWidth); WriteLn;
- ColorOn();
- WriteString(Idents);
- DrawCharLine(' ',ColumnWidth - StringLength(Idents) - 5);
- WriteString('Calls\n\n');
- ColorOff();
-
- memLast := memHead;
- WHILE memLast # NIL DO
- WITH memLast^ DO
- IF (CompareString('Std',prFileName) = equal) THEN
- prTag := TRUE;
- WriteString(prProcName);
- DrawCharLine('.',ColumnWidth-StringLength(prProcName)-4);
- WriteInt(prCount,4);
- WriteLn;
- END;
- END;
- memLast := memLast^.next;
- END;
-
- DrawCharLine(Separator,ColumnWidth); WriteLn;
- ColorOn();
- WriteString(Internal);
- DrawCharLine(' ',ColumnWidth - StringLength(Internal) - 5);
- WriteString('Calls\n\n');
- ColorOff();
-
- memLast := memHead;
- WHILE memLast # NIL DO
- WITH memLast^ DO
- IF (CompareString(prFileName,'Internal') = equal) THEN
- prTag := TRUE;
- WriteString(prProcName);
- DrawCharLine('.',ColumnWidth - StringLength(prProcName) - 4);
- WriteInt(prCount,4);
- WriteLn;
- END;
- END;
- memLast := memLast^.next;
- END;
-
- DrawCharLine(Separator,ColumnWidth); WriteLn;
- ColorOn();
- WriteString(Imports);
- DrawCharLine(' ',ColumnWidth - StringLength(Imports) - 5);
- WriteString('Calls\n\n');
- ColorOff();
-
- memLast := memHead;
- WHILE memLast # NIL DO
- WITH memLast^ DO
- IF (NOT prTag) THEN
- CopyString(tempStr,prFileName);
- ConcatString(tempStr,'.');
- ConcatString(tempStr,prProcName);
- WriteString(tempStr);
- DrawCharLine('.',ColumnWidth - StringLength(tempStr) - 4);
- WriteInt(prCount,4);
- WriteLn;
- END;
- END;
- memLast := memLast^.next;
- END;
- DrawCharLine(Separator,ColumnWidth); WriteLn;
-
- IF ansi = on THEN
- WriteString(CursorOn);
- END;
- END WriteInfo;
-
-
- PROCEDURE Cleanup(err: ARRAY OF CHAR);
- VAR
- last : ProcRecPtr;
- BEGIN
- IF err[0] = 0C THEN
- WriteInfo();
- ELSE
- WriteString(err);
- END;
-
- CloseOutput();
-
- IF inFile.handle # NIL THEN
- Close(inFile);
- IF (inFile.err # 0D) THEN (* Amiga specific *)
- WriteString('Error '); WriteLongInt(inFile.err,0);
- WriteString(' occurred while closing source file!\n');
- END;
- END;
-
- memLast := memHead;
- WHILE memLast # NIL DO
- last := memLast;
- memLast := memLast^.next;
- FreeMem(last,SIZE(last^));
- END;
-
- HALT;
- END Cleanup;
-
-
- PROCEDURE GetNextWord(VAR nextWord: ARRAY OF CHAR; VAR nextChar: CHAR);
- VAR
- currPos : LONGCARD;
- charPos : CARDINAL;
- lastChar : CHAR;
- BEGIN
- GetPos(inFile,currPos);
-
- charPos := 0;
- lastChar := 0C;
-
- LOOP
- ReadChar(inFile,nextChar);
- nextWord[charPos] := nextChar;
-
- INC(currPos);
- INC(charPos);
- SetPos(inFile,currPos);
- IF (inFile.eof) THEN Cleanup('') END;
-
- IF (nextChar = '(') AND
- AlphaNum(lastChar) THEN
- ReadChar(inFile,nextChar);
- IF (nextChar # '*') THEN
- nextChar := '(';
- nextWord[charPos] := 0C;
- DEC(currPos);
- SetPos(inFile,currPos);
- RETURN;
- END;
- END;
- IF (NOT AlphaNum(nextChar)) THEN
- IF (charPos > 1) THEN
- nextWord[charPos-1] := 0C;
- RETURN;
- ELSE
- charPos := 0;
- END;
- END;
- lastChar := nextChar;
- END;
- END GetNextWord;
-
-
- PROCEDURE AddToList(filename,procname: ARRAY OF CHAR;
- sureProc,declared: BOOLEAN; count: INTEGER);
- VAR
- last : ProcRecPtr;
- BEGIN
- memLast := memHead;
- WHILE memLast # NIL DO
- IF (CompareString(procname,memLast^.prProcName) = equal) THEN
- INC(memLast^.prCount);
- IF declared THEN
- memLast^.prDeclared := declared;
- END;
- RETURN;
- END;
- last := memLast;
- memLast := memLast^.next;
- END;
- (* Amiga specific - just use *)
- (* ALLOCATE, DEALLOCATE or new *)
- IF sureProc THEN
- memLast := AllocMem(SIZE(memLast^),MemReqSet{MemPublic,MemClear});
- IF memLast = NIL THEN
- Cleanup('Memory disorder...\n');
- END;
-
- IF memHead = NIL THEN
- memHead := memLast;
- END;
-
- CopyString(memLast^.prFileName,filename);
- CopyString(memLast^.prProcName,procname);
- memLast^.prCount := count;
- memLast^.prDeclared := declared;
-
- last^.next := memLast;
- memLast := NIL;
- END;
- END AddToList;
-
-
- PROCEDURE GetImports(str: ARRAY OF CHAR);
- VAR
- importName,
- tempName,
- procName : ARRAY [0..128] OF CHAR;
- currPos : LONGCARD;
- charPos : CARDINAL;
- myChar : CHAR;
- BEGIN
- IF (CompareString(str,'FROM') = equal) THEN (* FROM *)
- GetNextWord(importName,myChar);
- GetNextWord(tempName,myChar);
- IF (CompareString(tempName,'IMPORT') = equal) THEN
- LOOP
- GetNextWord(procName,myChar);
- AddToList(importName,procName,TRUE,TRUE,0);
- IF (myChar = ';') THEN
- RETURN;
- END;
- END;
- END;
- END;
- END GetImports;
-
-
- PROCEDURE ProcessFile(VAR nextWord: ARRAY OF CHAR);
- CONST
-
- (* BITSET,FLOAT,INC and some others are in here somewhere. *)
- (* Line continuation is compiler specific - may have to *)
- (* extend this on one long line. *)
-
- StdIdent =
- 'ABSBOOLEANCAPCARDINALCHARCHRDECDISPOSE\
- EXCLFALSEFLOATDHALTHIGHINCLINLINEINTEGER\
- LONGBITSETLONGCARDLONGINTLONGREALMAXMIN\
- NEWODDORDPROCRETURNREALSIZETRUETRUNCDVAL';
-
- VAR
- nextChar : CHAR;
- currPos : LONGCARD;
- bof : LONGINT;
- charPos : CARDINAL;
- procTag : BOOLEAN;
- declared : BOOLEAN;
- BEGIN
- LOOP
- declared := FALSE;
- GetNextWord(nextWord,nextChar);
- GetImports(nextWord);
- IF (CompareString(nextWord,'PROCEDURE') = equal) THEN
- GetNextWord(nextWord,nextChar);
- declared := TRUE;
- END;
-
- AddToList('',nextWord,FALSE,FALSE,1);
- nextWord[StringLength(str)-1] := 0C;
- IF (nextChar = '(') THEN
- IF (LocateSubString(StdIdent,nextWord,0,
- StringLength(StdIdent)) # -1) THEN
- AddToList('Std',nextWord,TRUE,TRUE,1);
- ELSE
- AddToList('Internal',nextWord,TRUE,declared,-1);
- END;
- END;
- END;
- END ProcessFile;
-
-
- PROCEDURE Startup();
- CONST
-
- ReportStr =
- 'Send report to: (\x9B33mS\x9Bmcreen/\x9B33mF\x9Bmile) ';
- AnsiStr =
- 'Do you want \x9B33mANSI\x9Bm color codes in this file? (Y/N) ';
-
- VAR
- fileName,
- reportName : ARRAY [0..128] OF CHAR;
- chances : CARDINAL;
- kbChar : CHAR;
- BEGIN
- ColorOn();
- WriteString(ProgName);
- ColorOff();
- WriteString(' - lists PROCEDURE usage in a Modula 2 source file.\n');
- WriteString('Public domain by David Czaya (CIS 73445,407) (1989/1990) V1.1\n\n');
-
- Echo := FALSE;
- chances := 3;
- LOOP
- ColorOn(); (* ANSI screen controls *)
- WriteString('Source');
- ColorOff();
- WriteString(' file: ');
- ReadString(fileName); WriteLn;
- Lookup(inFile,fileName,FALSE);
- IF (inFile.res = done) THEN EXIT END;
- DEC(chances);
- IF (chances = 0) THEN
- WriteString(BadInput);
- HALT;
- END;
- END;
-
- chances := 3;
- LOOP
- WriteString(ReportStr);
- Read(kbChar);
- IF (CAP(kbChar) = 'S') OR
- (CAP(kbChar) = 'F') THEN
- EXIT;
- END;
- DEC(chances);
- IF (chances = 0) THEN Cleanup(BadInput) END;
- END;
-
- IF (CAP(kbChar) = 'F') THEN
- Read(kbChar); (* flush <RETURN> *)
- chances := 3;
- LOOP
- WriteString(AnsiStr);
- Read(kbChar);
- IF (CAP(kbChar) = 'N') OR
- (CAP(kbChar) = 'Y') THEN
- EXIT;
- END;
- DEC(chances);
- IF (chances = 0) THEN Cleanup(BadInput) END;
- END;
-
- chances := 3;
- LOOP
- ColorOn();
- WriteString('Report');
- ColorOff();
- WriteString(' file: ');
- ReadString(reportName); WriteLn;
- OpenOutputFile(reportName);
- DEC(chances);
- IF (chances = 0) THEN Cleanup(BadInput) END;
- IF Done THEN EXIT END;
- END;
-
- IF (CAP(kbChar) = 'N') THEN
- ansi := off;
- END;
- ELSE
- Read(kbChar); (* flush <RETURN> *)
- END;
-
- GetDate();
- ConvStringToUpperCase(fileName);
- WriteString(fileName);
- WriteString('\n\n');
- END Startup;
-
-
- BEGIN
- ansi := on;
- Startup();
- ProcessFile(str);
- END ProcCheck.
-
-
-