home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 2
/
goldfish_vol2_cd1.bin
/
files
/
dev
/
obero
/
oberon-a
/
source
/
oru
/
oru.mod
< prev
next >
Wrap
Text File
|
1994-09-03
|
22KB
|
737 lines
(***************************************************************************
$RCSfile: ORU.mod $
Description: Generates a script file that will recompile modules dependant
on a given module.
Created by: fjc (Frank Copeland)
$Revision: 2.6 $
$Author: fjc $
$Date: 1994/09/03 16:32:01 $
Copyright © 1993-1994, Frank Copeland
This module forms part of the ORU program
See ORU.doc for conditions of use and distribution
Log entries are at the end of the file.
***************************************************************************)
MODULE ORU;
(*
** $C= CaseChk $I= IndexChk $L= LongAdr $N= NilChk
** $P- PortableCode $R= RangeChk $S= StackChk $T= TypeChk
** $V= OvflChk $Z= ZeroVars
*)
IMPORT
SYS := SYSTEM, ORURev, Errors, E := Exec, D := Dos, IU := IntuiUtil,
Args, IO := StdIO, Str := Strings, L := Lists, Files;
CONST
CopyrightStr = "Copyright © 1993-1994 Frank Copeland\n";
UsageStr = "See ORU.doc for conditions of use\n";
CONST
MaxPaths = 32; (* Maximum number of search paths. *)
SymExtension = ".Sym"; (* File extension for symbol files. *)
DefaultExtension = ".mod"; (* Default extension for source files. *)
DefaultPath = "OLIB:"; (* Default path for symbols *)
SymFileTag = 53594D07H; (* "SYM" + version # *)
eMod = 22; eMod0 = 25; (* Symbol file internal tags *)
(* Error messages *)
OutOfMem = " !! Out of memory\n";
OpenError = "\x9B\x4B !! Could not open %s\n";
VAR
NotCD : BOOLEAN; (* Don't search current directory if TRUE. *)
All : BOOLEAN; (* Process all modules in search directories. *)
Symbols : ARRAY MaxPaths + 1 OF E.STRPTR;
(* Search paths for symbol files. *)
NumSymbols : INTEGER; (* Number of paths specified. *)
Source : ARRAY MaxPaths + 1 OF E.STRPTR;
(* Search paths for source files. *)
NumSources : INTEGER; (* Number of paths specified. *)
Destination : E.STRPTR; (* Destination directory for batch file. *)
Extension : E.STRPTR; (* File extension for source files. *)
Module : E.STRPTR; (* Name of redefined module. *)
ModuleList : L.List; (* List of modules discovered. *)
Dependants : L.List; (* List of dependant modules. *)
CONST
MaxName = 31;
TYPE
ModName = ARRAY MaxName + 1 OF CHAR;
MNodePtr = POINTER TO MNode;
MNode = RECORD (L.ExtNode)
symbols : E.STRPTR;
imports : L.List;
path : E.STRPTR;
END; (* MNode *)
(*------------------------------------*)
PROCEDURE Init ();
(*
* Simply initialises global variables.
*)
BEGIN (* Init *)
Extension := SYS.ADR (DefaultExtension);
L.NewList (ModuleList);
L.NewList (Dependants);
END Init;
(*------------------------------------*)
PROCEDURE GetArgs ();
(*
* Parses the command line arguments.
*)
CONST DuplicateArg = " !! Argument duplicated\n\n";
PathMissing = " !! <path> missing\n\n";
ModAndAll = " !! both <module> and ALL specified\n\n";
TooManySyms = " !! Too many symbol file search paths\n";
TooManySrcs = " !! Too many source file search paths\n";
CmdMissing = " !! <command> missing\n\n";
ExtMissing = " !! <extension> missing\n\n";
WithMissing = " !! <file> missing\n\n";
ArgTooLong = " !! Argument in WITH file too long\n";
BadArg = " !! Unrecognised argument in WITH file\n";
VAR moduleFound, destFound, cmdFound, extFound : BOOLEAN; arg : INTEGER;
argStr : ARRAY 256 OF CHAR;
(*------------------------------------*)
PROCEDURE Greeting ();
BEGIN (* Greeting *)
IO.WriteStr (ORURev.vString);
IO.WriteStr (CopyrightStr);
IO.WriteStr (UsageStr);
IO.WriteLn ();
END Greeting;
(*------------------------------------*)
PROCEDURE Usage ();
BEGIN (* Usage *)
IO.WriteStr ("Usage: ORU {option} <module>|ALL\n\n");
IO.WriteStr ("Options: NOTCD {WITH <file>}\n");
IO.WriteStr (" {SYM | SYMBOLS <path>}\n");
IO.WriteStr (" {SRC | SOURCE} <path>}\n");
IO.WriteStr (" DST | DESTINATION <path>\n");
IO.WriteStr (" EXT | EXTENSION <extension>\n\n");
END Usage;
(*------------------------------------*)
PROCEDURE ParseWithFile (VAR fileName : ARRAY OF CHAR);
VAR file : Files.File; r : Files.Rider; argStr : ARRAY 256 OF CHAR;
(*------------------------------------*)
(* $D- disable copying of open arrays *)
PROCEDURE BailOut (msg : ARRAY OF CHAR);
BEGIN (* BailOut *)
IO.WriteStr (msg); Usage (); Files.Close (file); HALT (10)
END BailOut;
(*------------------------------------*)
(* $D- disable copying of open arrays *)
PROCEDURE BailOut2 (msg : ARRAY OF CHAR);
BEGIN (* BailOut2 *)
IO.WriteStr (msg); Files.Close (file); HALT (10)
END BailOut2;
(*------------------------------------*)
PROCEDURE GetNextArg ();
VAR i : LONGINT; ch : CHAR;
BEGIN (* GetNextArg *)
Files.Read (r, ch);
(* Skip white space *)
WHILE (ch <= " ") & ~r.eof DO Files.Read (r, ch) END;
IF r.eof THEN
RETURN
ELSIF ch = 22X THEN
(* Quoted argument *)
i := 0; Files.Read (r, ch);
WHILE (i < 255) & (ch # 22X) & ~r.eof DO
argStr [i] := ch; INC (i); Files.Read (r, ch)
END;
argStr [i] := 0X;
IF ch = 22X THEN Files.Read (r, ch)
ELSIF ~r.eof THEN BailOut2 (ArgTooLong)
END;
ELSE
i := 0;
WHILE (i < 255) & (ch > " ") & ~r.eof DO
argStr [i] := ch; INC (i); Files.Read (r, ch)
END;
argStr [i] := 0X;
IF (ch > " ") & ~r.eof THEN BailOut2 (ArgTooLong) END
END; (* ELSE *)
END GetNextArg;
(*------------------------------------*)
PROCEDURE CopyArg () : E.STRPTR;
VAR copy : E.STRPTR;
BEGIN (* CopyArg *)
SYS.NEW (copy, SYS.STRLEN (argStr) + 1);
COPY (argStr, copy^);
RETURN copy
END CopyArg;
BEGIN (* ParseWithFile *)
file := Files.Old (fileName);
IF file # NIL THEN
Files.Set (r, file, 0); GetNextArg ();
WHILE ~r.eof DO
Str.ToUpper (argStr);
IF argStr = "NOTCD" THEN
IF NotCD THEN BailOut (DuplicateArg) END;
NotCD := TRUE
ELSIF (argStr = "SYM") OR (argStr = "SYMBOLS") THEN
GetNextArg ();
IF r.eof THEN BailOut (PathMissing)
ELSIF NumSymbols >= MaxPaths THEN
BailOut2 (TooManySyms)
END;
Symbols [NumSymbols] := CopyArg ();
INC (NumSymbols); Symbols [NumSymbols] := NIL;
ELSIF (argStr = "SRC") OR (argStr = "SOURCE") THEN
GetNextArg ();
IF r.eof THEN BailOut (PathMissing)
ELSIF NumSources >= MaxPaths THEN BailOut2 (TooManySrcs)
END;
Source [NumSources] := CopyArg ();
INC (NumSources); Source [NumSources] := NIL;
ELSIF (argStr = "EXT") OR (argStr = "EXTENSION") THEN
GetNextArg ();
IF r.eof OR extFound THEN
IF extFound THEN BailOut (DuplicateArg)
ELSE BailOut (ExtMissing)
END;
END;
Extension := CopyArg (); extFound := TRUE
ELSE
BailOut (BadArg)
END; (* ELSE *)
GetNextArg ();
END; (* WHILE *)
Files.Close (file);
ELSE
IO.WriteF1 (" !! Could not open %s\n", SYS.ADR (fileName))
END; (* ELSE *)
END ParseWithFile;
(*------------------------------------*)
(* $D- disable copying of open arrays *)
PROCEDURE BailOut (msg : ARRAY OF CHAR);
BEGIN (* BailOut *)
IO.WriteStr (msg); Usage (); HALT (10)
END BailOut;
(*------------------------------------*)
(* $D- disable copying of open arrays *)
PROCEDURE BailOut2 (msg : ARRAY OF CHAR);
BEGIN (* BailOut2 *)
IO.WriteStr (msg); HALT (10)
END BailOut2;
BEGIN (* GetArgs *)
moduleFound := FALSE; destFound := FALSE; cmdFound := FALSE;
extFound := FALSE;
IF Args.IsCLI THEN
Greeting ();
IF Args.argc < 2 THEN
(* Minimum of one argument needed *)
BailOut (" !! Arguments missing\n\n")
END;
Symbols [0] := SYS.ADR (DefaultPath);
NumSymbols := 1; Symbols [1] := NIL;
arg := 1; (* first argument is the program name, so ignore it. *)
WHILE arg < Args.argc DO
COPY (Args.argv [arg]^, argStr); Str.ToUpper (argStr);
IF argStr = "NOTCD" THEN
IF NotCD THEN BailOut (DuplicateArg) END;
NotCD := TRUE
ELSIF (argStr = "SYM") OR (argStr = "SYMBOLS") THEN
INC (arg);
IF arg >= Args.argc THEN BailOut (PathMissing)
ELSIF NumSymbols >= MaxPaths THEN BailOut2 (TooManySyms)
END;
Symbols [NumSymbols] := Args.argv [arg];
INC (NumSymbols); Symbols [NumSymbols] := NIL;
ELSIF (argStr = "SRC") OR (argStr = "SOURCE") THEN
INC (arg);
IF arg >= Args.argc THEN BailOut (PathMissing)
ELSIF NumSources >= MaxPaths THEN BailOut2 (TooManySrcs)
END;
Source [NumSources] := Args.argv [arg];
INC (NumSources); Source [NumSources] := NIL;
ELSIF (argStr = "DST") OR (argStr = "DESTINATION") THEN
INC (arg);
IF (arg >= Args.argc) OR destFound THEN
IF destFound THEN BailOut (DuplicateArg)
ELSE BailOut (PathMissing)
END;
END;
Destination := Args.argv [arg]; destFound := TRUE
ELSIF (argStr = "EXT") OR (argStr = "EXTENSION") THEN
INC (arg);
IF (arg >= Args.argc) OR extFound THEN
IF extFound THEN BailOut (DuplicateArg)
ELSE BailOut (ExtMissing)
END;
END;
Extension := Args.argv [arg]; extFound := TRUE
ELSIF argStr = "ALL" THEN
IF All THEN BailOut (DuplicateArg)
ELSIF moduleFound THEN BailOut (ModAndAll)
END;
Module := SYS.ADR("All"); All := TRUE
ELSIF argStr = "WITH" THEN
INC (arg);
IF arg >= Args.argc THEN BailOut (WithMissing) END;
ParseWithFile (Args.argv [arg]^)
ELSE
IF moduleFound THEN BailOut (DuplicateArg)
ELSIF All THEN BailOut (ModAndAll)
END;
Module := Args.argv [arg]; moduleFound := TRUE
END; (* ELSE *)
INC (arg)
END; (* WHILE *)
IF ~moduleFound & ~All THEN BailOut (" !! <module> missing\n\n") END;
ELSE
IU.SimpleNotice
(NIL, SYS.ADR ("Sorry, no support for Workbench yet :-("));
HALT (10)
END; (* ELSE *)
END GetArgs;
(*------------------------------------*)
PROCEDURE SearchSymbolFile (directory : E.STRPTR; fileName : ARRAY OF CHAR);
CONST
NotSymFile = "\x9B\x4B !! %s is obsolete, or is not a symbol file\n";
VAR
F : Files.File; R : Files.Rider; tag : LONGINT; modName : ModName;
module : MNodePtr; import : L.ExtNodePtr;
(*------------------------------------*)
PROCEDURE ReadModAnchor (VAR n : ARRAY OF CHAR) : BOOLEAN;
CONST
BadName = "\x9B\x4B !! Bad name in symbol file %s\n";
VAR s : SHORTINT; ch : CHAR; key : LONGINT;
BEGIN (* ReadModAnchor *)
Files.Read (R, s); (* modAnchor *)
IF (s = eMod) OR (s = eMod0) THEN
Files.ReadBytes (R, key, 4); s := 0;
LOOP
Files.Read (R, ch); n [s] := ch;
IF ch = 0X THEN EXIT END;
INC (s);
IF s > MaxName THEN
n [MaxName] := 0X;
IO.WriteF1 (BadName, SYS.ADR (fileName));
WHILE ch # 0X DO Files.Read (R, ch) END;
RETURN FALSE
END; (* IF *)
END; (* LOOP *)
RETURN TRUE
END; (* IF *)
RETURN FALSE
END ReadModAnchor;
(* $D- disable copying of open arrays *)
BEGIN (* SearchSymbolFile *)
IO.WriteF1 ("\x9B\x4B << %s\r", SYS.ADR (fileName));
F := Files.Old (fileName);
IF F = NIL THEN IO.WriteF1 (OpenError, SYS.ADR (fileName))
ELSE
Files.Set (R, F, 0); Files.ReadBytes (R, tag, 4);
IF tag # SymFileTag THEN
IO.WriteF1 (NotSymFile, SYS.ADR (fileName))
ELSE
IF ReadModAnchor (modName) THEN
NEW (module);
L.AttachName (module^, modName); module.key := 0;
module.symbols := directory; L.NewList (module.imports);
L.AddTail (ModuleList, module);
WHILE ReadModAnchor (modName) DO
NEW (import);
L.AttachName (import^, modName);
L.AddTail (module.imports, import);
END;
END;
END;
Files.Close (F); SYS.DISPOSE (F)
END;
END SearchSymbolFile;
(*------------------------------------*)
PROCEDURE ScanForSymbols (directory : E.STRPTR);
CONST
LockError = " !! Failed to lock %s\n";
ExamineError = " !! Examine () failed\n";
NotDirectory = " !! %s is not a directory\n";
VAR
lock, oldLock : D.FileLockPtr; fib : D.FileInfoBlockPtr;
success : BOOLEAN; len : LONGINT; extension : ARRAY 5 OF CHAR;
BEGIN (* ScanForSymbols *)
IF directory = NIL THEN directory := SYS.ADR ("") END;
lock := D.base.Lock (directory^, D.sharedLock);
IF lock = NIL THEN IO.WriteF1 (LockError, directory); RETURN END;
NEW (fib);
oldLock := D.base.CurrentDir (lock);
success := D.base.Examine (lock, fib^);
IF ~success THEN IO.WriteStr (ExamineError)
ELSE
IF fib.dirEntryType <= 0 THEN IO.WriteF1 (NotDirectory, directory)
ELSE
WHILE D.base.ExNext (lock, fib^) DO
IF fib.dirEntryType < 0 THEN
len := Str.Length (fib.fileName);
IF (len > 3) & (fib.fileName [len - 4] = ".") THEN
Str.CopySubString (extension, fib.fileName, len - 4, 4);
IF extension = SymExtension THEN
SearchSymbolFile (directory, fib.fileName)
END;
END;
END;
END;
END;
END;
SYS.DISPOSE (fib);
oldLock := D.base.CurrentDir (oldLock);
D.base.UnLock (lock)
END ScanForSymbols;
(*------------------------------------*)
(* $D- disable copying of open arrays *)
PROCEDURE SearchForDependants (modName : ARRAY OF CHAR; level : LONGINT);
CONST ModuleMissing = " !! Module %s not found\n";
VAR node, module, import : L.NodePtr;
BEGIN (* SearchForDependants *)
module := L.FindNameNoCase (ModuleList, modName);
IF module = NIL THEN IO.WriteF1 (ModuleMissing, SYS.ADR (modName))
ELSE
IF module(MNodePtr).key > level THEN
module(MNodePtr).key := level;
node := ModuleList.head;
WHILE node # NIL DO
WITH node : MNodePtr DO
import := L.FindNameNoCase (node.imports, modName);
IF import # NIL THEN
SearchForDependants (node.name^, level - 1)
END;
END;
node := node.succ
END;
END;
END;
END SearchForDependants;
(*------------------------------------*)
PROCEDURE SearchForAll ();
VAR node, module, import : L.NodePtr;
BEGIN (* SearchForAll *)
module := ModuleList.head;
WHILE module # NIL DO
IF module(MNodePtr).key = 0 THEN
module(MNodePtr).key := -1;
node := ModuleList.head;
WHILE node # NIL DO
WITH node : MNodePtr DO
import := L.FindName (node.imports, module(L.ExtNodePtr).name^);
IF import # NIL THEN
SearchForDependants (node.name^, -2)
END;
END; (* WITH node *)
node := node.succ
END; (* WHILE *)
END;
module := module.succ;
END; (* WHILE *)
END SearchForAll;
(*------------------------------------*)
PROCEDURE SortDependants ();
VAR node : L.NodePtr;
BEGIN (* SortDependants *)
LOOP
node := L.RemHead (ModuleList);
IF node = NIL THEN EXIT END;
WITH node : MNodePtr DO
IF node.key < 0 THEN L.Enqueue (Dependants, node) END
END; (* WITH *)
END; (* LOOP *)
END SortDependants;
(*------------------------------------*)
(* $D- disable copying of open arrays *)
PROCEDURE FileExists (path : ARRAY OF CHAR) : BOOLEAN;
VAR lock : D.FileLockPtr; result : BOOLEAN;
BEGIN (* FileExists *)
result := FALSE;
lock := D.base.Lock (path, D.sharedLock);
IF lock # NIL THEN result := TRUE; D.base.UnLock (lock) END;
RETURN result
END FileExists;
(*------------------------------------*)
(* $D- disable copying of open arrays *)
PROCEDURE Search (file : ARRAY OF CHAR; VAR path : E.STRPTR) : BOOLEAN;
VAR
index : INTEGER; fullPath : ARRAY 256 OF CHAR;
len : LONGINT; ch : CHAR;
BEGIN (* Search *)
path := NIL;
IF NotCD THEN
IF Source [0] = NIL THEN RETURN FALSE END;
COPY (Source [0]^, fullPath); index := 0
ELSE
fullPath [0] := 0X; index := -1
END;
LOOP
len := Str.Length (fullPath);
IF len > 0 THEN
ch := fullPath [len - 1];
IF (ch # "/") & (ch # ":") THEN Str.Append (fullPath, "/") END
END;
Str.Append (fullPath, file); Str.Append (fullPath, Extension^);
IF FileExists (fullPath) THEN
IF index >= 0 THEN path := Source [index] END;
RETURN TRUE
END;
INC (index);
IF Source [index] = NIL THEN RETURN FALSE
ELSE COPY (Source [index]^, fullPath)
END
END
END Search;
(*------------------------------------*)
PROCEDURE SearchForSources ();
VAR node, succ : L.NodePtr;
BEGIN (* SearchForSources *)
node := Dependants.head;
WHILE node # NIL DO
succ := node.succ;
WITH node : MNodePtr DO
IF ~Search (node.name^, node.path) THEN
L.Remove (Dependants, node)
END
END;
node := succ
END;
END SearchForSources;
(*------------------------------------*)
(* $D- disable copying of open arrays *)
PROCEDURE OutputModules (batchFile : ARRAY OF CHAR);
VAR
F : Files.File; R : Files.Rider; module : L.NodePtr;
len : LONGINT; ch : CHAR;
BEGIN (* OutputModules *)
F := Files.New (batchFile);
IF F = NIL THEN IO.WriteF1 (OpenError, SYS.ADR (batchFile))
ELSE
Files.Set (R, F, 0);
module := Dependants.head;
WHILE module # NIL DO
WITH module : MNodePtr DO
IF module.path # NIL THEN
len := Str.Length (module.path^);
IF len > 0 THEN
Files.WriteBytes (R, module.path^, len);
ch := module.path^ [len - 1];
IF (ch # "/") & (ch # ":") THEN Files.Write (R, "/") END;
END
END;
Files.WriteBytes (R, module.name^, Str.Length (module.name^));
END;
Files.WriteBytes (R, Extension^, Str.Length (Extension^));
Files.Write (R, "\n");
module := module.succ
END;
Files.Register (F)
END;
END OutputModules;
(*------------------------------------*)
PROCEDURE Main ();
(*
* The main body of the program.
*
* The basic sequence is:
*
* * Scan the current directory and the Symbols list. With each symbol
* file found:
* * Add the module to the list of modules found.
* * Open the symbol file and create a list of the modules it
* imports.
* * Search the module list for modules that import the redefined module
* and add them to a list of dependant modules.
* * Search the current directory and the Sources list for the source
* files of the dependant modules.
* * Output the list to the script file using the command template.
*)
VAR index : INTEGER; batchFile : ARRAY 256 OF CHAR;
len : LONGINT; ch : CHAR;
BEGIN (* Main *)
IO.WriteStr (" !! Scanning for symbol files\n");
IF ~NotCD THEN
IO.WriteStr (" Scanning current directory\n"); ScanForSymbols (NIL)
END;
index := 0;
WHILE Symbols [index] # NIL DO
IO.WriteF1 ("\x9B\x4B Scanning %s\n", Symbols [index]);
ScanForSymbols (Symbols [index]); INC (index)
END;
IF All THEN
IO.WriteStr ("\x9B\x4B !! Searching for all dependant modules\n");
SearchForAll ()
ELSE
IO.WriteF1 ("\x9B\x4B !! Searching for dependants of %s\n", Module);
SearchForDependants (Module^, -1);
END; (* ELSE *)
IO.WriteStr ("\x9B\x4B !! Sorting dependant modules\n");
SortDependants ();
IO.WriteStr ("\x9B\x4B !! Searching for source files\n");
SearchForSources ();
(*
IO.WriteStr ("\nDependant modules:\n");
module := Dependants.head;
WHILE module # NIL DO
WITH module : MNodePtr DO
IO.WriteF3 (" %s %s : %ld\n", module.path, module.name, module.key);
END; (* WITH module *)
module := module.succ
END; (* WHILE *)
IO.WriteLn ();
*)
IF Destination = NIL THEN
batchFile := ""
ELSE
COPY (Destination^, batchFile); len := Str.Length (batchFile);
IF len > 0 THEN
ch := batchFile [len - 1];
IF (ch # "/") & (ch # ":") THEN Str.Append (batchFile, "/") END
END
END;
Str.Append (batchFile, Module^); Str.Append (batchFile, ".bat");
IO.WriteF1
("\x9B\x4B !! Creating batch file %s\n", SYS.ADR (batchFile));
OutputModules (batchFile)
END Main;
BEGIN (* ORU *)
Init ();
GetArgs ();
Main ();
END ORU.
(***************************************************************************
$Log: ORU.mod $
Revision 2.6 1994/09/03 16:32:01 fjc
- Gets version string from ORURev.
Revision 2.5 1994/08/08 16:38:47 fjc
Release 1.4
Revision 2.4 1994/06/17 18:09:17 fjc
- Updated for release
Revision 2.3 1994/06/05 00:11:07 fjc
- Updated symbol file tag to new version
- Changed to use new Amiga interface
Revision 2.2 1994/05/21 22:47:40 fjc
- Removed case-sensitivity of module parameter
- Appends "/" to paths not ending in "/" or ":"
Revision 2.1 1994/05/19 23:23:19 fjc
- Bumped version number.
- Changed to generate a batch file to be used with the BATCH
option of the compiler.
- OLIB: is now the default symbol file search path.
Revision 1.3 1994/05/11 23:40:54 fjc
- Added copyright notice to file header
- Changed greeting
Revision 1.2 1994/01/25 10:07:37 fjc
- Updated greeting
Revision 1.1 1994/01/15 19:02:30 fjc
- Start of revision control
0.4 (02-Jan-94) Recognises new symbol file tags.
0.3 (28-Dec-93) Increased MaxPaths.
0.2 (30-Sep-93) Add ALL and WITH options.
0.1 (06-Sep-93) First public release.
0.0 (27-Aug-93) Initial version.
***************************************************************************)