home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
351.lha
/
ProcCheck_v1.1
/
ProcCheck.mod
< prev
next >
Wrap
Text File
|
1990-03-09
|
18KB
|
605 lines
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.