home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD1.bin / useful / dev / obero / oberon-a / source / ol / ol.mod < prev    next >
Encoding:
Text File  |  1994-09-03  |  16.9 KB  |  564 lines

  1. (***************************************************************************
  2.  
  3.      $RCSfile: OL.mod $
  4.   Description: Recursively scans the symbol files referenced by a module and
  5.                creates a WITH file to be input to a linker.
  6.  
  7.    Created by: fjc (Frank Copeland)
  8.     $Revision: 2.3 $
  9.       $Author: fjc $
  10.         $Date: 1994/09/03 16:30:49 $
  11.  
  12.   Copyright © 1993-1994, Frank Copeland
  13.   This module forms part of the OL program
  14.   See OL.doc for conditions of use and distribution
  15.  
  16.   Log entries are at the end of the file.
  17.  
  18. ***************************************************************************)
  19.  
  20. MODULE OL;
  21.  
  22. (*
  23. ** $C= CaseChk       $I= IndexChk  $L= LongAdr   $N= NilChk
  24. ** $P- PortableCode  $R= RangeChk  $S= StackChk  $T= TypeChk
  25. ** $V= OvflChk       $Z= ZeroVars
  26. *)
  27.  
  28. IMPORT
  29.   OLRev, Errors, E := Exec, D := Dos, DU := DosUtil, Str := Strings,
  30.   F := Files, IO := StdIO, Args, SYS := SYSTEM, L := Lists;
  31.  
  32. CONST
  33.   CopyrightStr = "Copyright © 1993-1994 Frank Copeland\n";
  34.   UsageStr = "See OL.doc for conditions of use\n";
  35.  
  36.   maxPaths = 32;
  37.   maxName  = 255;
  38.   maxPath  = 255;
  39.  
  40.   SymTag = 53594D07H; (* Symbol file tag : "SYM" + version # *)
  41.  
  42.   (* terminal symbols for symbol file elements *)
  43.   eUndef = 0; eCon = 1; eTypE = 2; eTyp = 3; eVar = 4; eXProc = 5;
  44.   eLibCall = 6; ePointer = 7; eProcTyp = 8; eArray = 9; eDynArr = 10;
  45.   eRecord = 11; eParList = 12; eValPar = 13; eVarPar = 14; eValRegPar = 15;
  46.   eVarRegPar = 16; eFldList = 17; eFld = 18; eHPtr = 19; eHProc = 20;
  47.   eFixup = 21; eMod = 22; eBPointer = 23; eCPointer = 24; eMod0 = 25;
  48.  
  49.   noLinker = 0;
  50.   aLink = 1;
  51.   bLink = 2;
  52.   dLink = 3;
  53.  
  54. TYPE
  55.   NameStr = ARRAY maxName + 1 OF CHAR;
  56.   PathStr = ARRAY maxPath + 1 OF CHAR;
  57.  
  58.   ModulePtr = POINTER TO Module;
  59.   Module = RECORD (L.ExtNode)
  60.     path : PathStr;
  61.   END; (* Module *)
  62.  
  63. VAR
  64.   searchPath : ARRAY maxPaths OF E.STRPTR;
  65.   pathx      : INTEGER;
  66.   moduleName : NameStr;
  67.   moduleList : L.List;
  68.   linker : SHORTINT;
  69.   doLink : BOOLEAN;
  70.   outputPath, linkerPath, linkOptions : ARRAY 256 OF CHAR;
  71.   withName : PathStr;
  72.  
  73. (*------------------------------------*)
  74. PROCEDURE Greetings ();
  75.  
  76. BEGIN (* Greetings *)
  77.   IO.WriteStr (OLRev.vString);
  78.   IO.WriteStr (CopyrightStr);
  79.   IO.WriteStr (UsageStr);
  80.   IO.WriteLn ();
  81. END Greetings;
  82.  
  83. PROCEDURE Init ();
  84.  
  85.   (*------------------------------------*)
  86.   PROCEDURE WbInit ();
  87.  
  88.   BEGIN (* WbInit *)
  89.     IO.WriteStr ("Sorry, no support for Workbench yet :-(\n");
  90.     HALT (10);
  91.   END WbInit;
  92.  
  93.   (*------------------------------------*)
  94.   PROCEDURE Usage ();
  95.  
  96.   BEGIN (* Usage *)
  97.     IO.WriteStr ("Usage   : OL {option} <module>\n");
  98.     IO.WriteStr ("Options : SRC | SOURCE <directory>\n");
  99.     IO.WriteStr ("          DST | DESTINATION <directory>\n");
  100.     IO.WriteStr ("          ALINK | BLINK | DLINK\n");
  101.     IO.WriteStr ("          LINK\n");
  102.     IO.WriteStr ("          LINKER <path>\n");
  103.     IO.WriteStr ("          OPT | OPTIONS <linker options>\n");
  104.     IO.WriteStr ("see OL.doc for details\n\n");
  105.     HALT (20)
  106.   END Usage;
  107.  
  108.   (*------------------------------------*)
  109.   PROCEDURE CliInit ();
  110.  
  111.     CONST
  112.       OnlyOneLinker = " !! More than one linker specified\n\n";
  113.       RepeatArg = " !! Argument given more than once\n\n";
  114.  
  115.     VAR arg : INTEGER; argStr : ARRAY 256 OF CHAR;
  116.  
  117.   BEGIN (* CliInit *)
  118.     arg := 1; moduleName := ""; linker := noLinker; doLink := FALSE;
  119.     linkerPath := ""; linkOptions := "";
  120.     LOOP
  121.       IF arg >= Args.argc THEN
  122.         IF moduleName = "" THEN Usage () ELSE EXIT END;
  123.       END;
  124.       COPY (Args.argv [arg]^, argStr); Str.ToUpper (argStr);
  125.       IF (argStr = "SRC") OR (argStr = "SOURCE") THEN
  126.         INC (arg); IF arg >= Args.argc THEN Usage () END;
  127.         IF pathx >= maxPaths THEN
  128.           IO.WriteStr (" !! Too many search paths\n\n"); HALT (20)
  129.         ELSE
  130.           searchPath [pathx] := Args.argv [arg];
  131.           INC (pathx); searchPath [pathx] := NIL
  132.         END
  133.       ELSIF (argStr = "DST") OR (argStr = "DESTINATION") THEN
  134.         IF outputPath = "" THEN
  135.           INC (arg); IF arg >= Args.argc THEN Usage () END;
  136.           COPY (Args.argv [arg]^, outputPath )
  137.         ELSE
  138.           IO.WriteStr (RepeatArg); Usage ()
  139.         END;
  140.       ELSIF argStr = "ALINK" THEN
  141.         IF linker = noLinker THEN linker := aLink
  142.         ELSE
  143.           IO.WriteStr (OnlyOneLinker); Usage ()
  144.         END;
  145.       ELSIF argStr = "BLINK" THEN
  146.         IF linker = noLinker THEN linker := bLink
  147.         ELSE
  148.           IO.WriteStr (OnlyOneLinker); Usage ()
  149.         END;
  150.       ELSIF argStr = "DLINK" THEN
  151.         IF linker = noLinker THEN linker := dLink
  152.         ELSE
  153.           IO.WriteStr (OnlyOneLinker); Usage ()
  154.         END;
  155.       ELSIF argStr = "LINK" THEN
  156.         IF ~doLink THEN doLink := TRUE
  157.         ELSE IO.WriteStr (RepeatArg); Usage ()
  158.         END
  159.       ELSIF argStr = "LINKER" THEN
  160.         IF linkerPath = "" THEN
  161.           INC (arg); IF arg >= Args.argc THEN Usage () END;
  162.           COPY (Args.argv [arg]^, linkerPath)
  163.         ELSE
  164.           IO.WriteStr (RepeatArg); Usage ()
  165.         END
  166.       ELSIF (argStr = "OPT") OR (argStr = "OPTIONS") THEN
  167.         IF linkOptions = "" THEN
  168.           INC (arg); IF arg >= Args.argc THEN Usage () END;
  169.           COPY (Args.argv [arg]^, linkOptions)
  170.         ELSE
  171.           IO.WriteStr (RepeatArg); Usage ()
  172.         END
  173.       ELSIF moduleName = "" THEN
  174.         COPY (Args.argv [arg]^, moduleName)
  175.       ELSE
  176.         Usage ()
  177.       END;
  178.       INC (arg);
  179.     END; (* LOOP *)
  180.     IF linker = noLinker THEN linker := bLink END;
  181.     IF pathx >= maxPaths THEN
  182.       IO.WriteStr (" !! Too many search paths\n\n"); HALT (20)
  183.     ELSIF linker # dLink THEN
  184.       searchPath [pathx] := SYS.ADR ("OLIB:");
  185.       INC (pathx); searchPath [pathx] := NIL
  186.     END;
  187.  
  188.     IO.WriteF1 ("Program : %s\n", SYS.ADR (moduleName));
  189.     IO.WriteStr ("Linker  : ");
  190.     IF linkerPath # "" THEN IO.WriteStr (linkerPath); IO.Write (" ")
  191.     ELSIF linker = aLink THEN IO.WriteStr ("ALink ")
  192.     ELSIF linker = bLink THEN IO.WriteStr ("BLink ")
  193.     ELSE IO.WriteStr ("dlink ")
  194.     END;
  195.     IF doLink THEN IO.WriteStr (linkOptions) END;
  196.     IO.WriteLn (); IO.WriteLn ()
  197.   END CliInit;
  198.  
  199. BEGIN (* Init *)
  200.   searchPath [0] := NIL; pathx := 0; outputPath := "";
  201.   L.NewList (moduleList);
  202.   IF Args.argc = 0 THEN   (* Program run from Workbench *)
  203.     WbInit ()
  204.   ELSE                      (* Program run from CLI *)
  205.     CliInit ()
  206.   END; (* ELSE *)
  207. END Init;
  208.  
  209. PROCEDURE Main ();
  210.  
  211.   VAR error : BOOLEAN;
  212.  
  213.   (*------------------------------------*)
  214.   PROCEDURE Process (modName : ARRAY OF CHAR; key : LONGINT);
  215.  
  216.     VAR
  217.       fileName, name : NameStr; symPath, objPath : PathStr;
  218.       node : L.NodePtr; module : ModulePtr; symFile : F.File; r : F.Rider;
  219.       s : SHORTINT; i : INTEGER; l, modKey : LONGINT; ch : CHAR;
  220.  
  221.     (*------------------------------------*)
  222.     PROCEDURE ReadModAnchor (
  223.       VAR k : LONGINT; VAR n : ARRAY OF CHAR)
  224.       : BOOLEAN;
  225.  
  226.       VAR s : SHORTINT; ch : CHAR;
  227.  
  228.     BEGIN (* ReadModAnchor *)
  229.       F.Read (r, s); (* modAnchor *)
  230.       IF (s = eMod) OR (s = eMod0) THEN
  231.         F.ReadBytes (r, k, 4); (* key *)
  232.         s := 0;
  233.         LOOP
  234.           F.Read (r, ch); n [s] := ch;
  235.           IF ch = 0X THEN EXIT END;
  236.           INC (s);
  237.           IF s > maxName THEN
  238.             n [maxName] := 0X;
  239.             IO.WriteF1
  240.               ( "\x9B\x4B !! Module name too long in symbol file %s\n\n",
  241.                 SYS.ADR (symPath));
  242.             RETURN FALSE
  243.           END; (* IF *)
  244.         END; (* LOOP *)
  245.         RETURN TRUE
  246.       END; (* IF *)
  247.       RETURN FALSE
  248.     END ReadModAnchor;
  249.  
  250.   (* $D- disable copying of open arrays *)
  251.   BEGIN (* Process *)
  252.     node := L.FindName (moduleList, modName);
  253.     IF node = NIL THEN
  254.       COPY (modName, fileName); Str.Append (fileName, ".Sym");
  255.       IF DU.Search (searchPath, fileName, symPath) THEN
  256.         COPY (modName, fileName); Str.Append (fileName, ".Obj");
  257.         IF DU.Search (searchPath, fileName, objPath) THEN
  258.           NEW (module);
  259.           IF module # NIL THEN
  260.             L.AttachName (module^, modName);
  261.             module.path := objPath; module.key := key;
  262.             L.AddTail (moduleList, module);
  263.             symFile := F.Old (symPath);
  264.             IF symFile # NIL THEN
  265.               IO.WriteF1 ("\x9B\x4B << %s\r", SYS.ADR (symPath));
  266.               F.Set (r, symFile, 0);
  267.               F.ReadBytes (r, l, 4); (* Symbol file tag *)
  268.               IF l = SymTag THEN
  269.                 IF ReadModAnchor (modKey, name) THEN
  270.                   IF (key = 0) OR (key = modKey) THEN
  271.                     IF Str.CompareCAP (modName, name) = 0 THEN
  272.                       WHILE ~error & ReadModAnchor (modKey, name) DO
  273.                         Process (name, modKey)
  274.                       END
  275.                     ELSE
  276.                       IO.WriteF1 (
  277.                         "\x9B\x4B !! Bad name in symbol file %s\n\n",
  278.                         SYS.ADR (symPath));
  279.                       error := TRUE
  280.                     END; (* ELSE *)
  281.                   ELSE
  282.                     IO.WriteF1 (
  283.                       "\x9B\x4B !! Bad key in symbol file %s\n\n",
  284.                       SYS.ADR (symPath));
  285.                     error := TRUE
  286.                   END; (* ELSE *)
  287.                 ELSE
  288.                   IO.WriteF1 (
  289.                     "\x9B\x4B !! Bad modAnchor in symbol file %s\n\n",
  290.                     SYS.ADR (symPath));
  291.                   error := TRUE
  292.                 END; (* ELSE *)
  293.               ELSE
  294.                 IO.WriteF1 (
  295.                   "\x9B\x4B !! Bad tag in symbol file %s\n\n",
  296.                   SYS.ADR (symPath));
  297.                 error := TRUE
  298.               END; (* ELSE *)
  299.               F.Close (symFile)
  300.             ELSE
  301.               IO.WriteF1 (
  302.                 "\x9B\x4B !! Could not open %s\n\n", SYS.ADR (symPath));
  303.               error := TRUE
  304.             END; (* IF *)
  305.           ELSE
  306.             IO.WriteStr ("\x9B\x4B !! Out of memory\n\n");
  307.             error := TRUE
  308.           END; (* ELSE *)
  309.         ELSIF linker # dLink THEN
  310.           IO.WriteF1 (
  311.             "\x9B\x4B !! Could not find object file %s\n\n", SYS.ADR (fileName));
  312.           error := TRUE
  313.         END
  314.       ELSIF linker # dLink THEN
  315.         IO.WriteF1 (
  316.           "\x9B\x4B !! Could not find symbol file %s\n\n", SYS.ADR (fileName));
  317.         error := TRUE
  318.       END; (* IF *)
  319.     ELSE
  320.       IF node (ModulePtr).key # key THEN
  321.         IO.WriteF1 (
  322.           "\x9B\x4B !! Bad key in module %s\n\n", SYS.ADR (modName));
  323.         error := TRUE
  324.       (*
  325.       ELSE
  326.         IO.WriteF1 (
  327.           "\x9B\x4B    Module %s already processed\r", SYS.ADR (modName));
  328.       *)
  329.       END; (* IF *)
  330.     END; (* IF *)
  331.   END Process;
  332.  
  333.   (*------------------------------------*)
  334.   PROCEDURE OberonLib ();
  335.  
  336.     VAR libPath : PathStr; module : ModulePtr;
  337.  
  338.   BEGIN (* OberonLib *)
  339.     IF linker = dLink THEN
  340.       IF pathx >= maxPaths THEN
  341.         IO.WriteStr (" !! Too many search paths\n\n"); HALT (20)
  342.       ELSE
  343.         searchPath [pathx] := SYS.ADR ("OLIB:");
  344.         INC (pathx); searchPath [pathx] := NIL
  345.       END;
  346.       IF DU.Search (searchPath, "OLib.lib", libPath) THEN
  347.         NEW (module);
  348.         IF module # NIL THEN
  349.           module.path := libPath; L.AddTail (moduleList, module);
  350.         ELSE
  351.           IO.WriteStr ("\x9B\x4B !! Out of memory\n\n");
  352.           error := TRUE
  353.         END
  354.       ELSE
  355.         IO.WriteStr ("\x9B\x4B !! Could not find OLib.lib\n\n");
  356.         error := TRUE
  357.       END
  358.     END;
  359.     IF DU.Search (searchPath, "OberonSys.lib", libPath) THEN
  360.       NEW (module);
  361.       IF module # NIL THEN
  362.         module.path := libPath; L.AddTail (moduleList, module);
  363.       ELSE
  364.         IO.WriteStr ("\x9B\x4B !! Out of memory\n\n");
  365.         error := TRUE
  366.       END; (* ELSE *)
  367.     ELSE
  368.       IO.WriteStr ("\x9B\x4B !! Could not find OberonSys.lib\n\n");
  369.       error := TRUE
  370.     END; (* IF *)
  371.   END OberonLib;
  372.  
  373.   (*------------------------------------*)
  374.   (*
  375.     Produces a .with file with the format:
  376.  
  377.     FROM <moduleName>.obj
  378.     LIBRARY <first imported module>*
  379.       <other imported modules>*
  380.       ...
  381.       OberonSys.lib
  382.     TO <moduleName>
  383.  
  384.   *)
  385.   PROCEDURE Output ();
  386.  
  387.     VAR
  388.       withFile : F.File; w : F.Rider; module : L.NodePtr; ch : CHAR;
  389.  
  390.     (*------------------------------------*)
  391.     PROCEDURE Indent ();
  392.     BEGIN (* Indent *)
  393.       F.Write (w, " "); F.Write (w, " ")
  394.     END Indent;
  395.  
  396.     (*------------------------------------*)
  397.     PROCEDURE WriteStr (str : ARRAY OF CHAR);
  398.     (* $D- disable copying of open arrays *)
  399.     BEGIN (* WriteStr *)
  400.       F.WriteBytes (w, str, Str.Length (str))
  401.     END WriteStr;
  402.  
  403.     (*------------------------------------*)
  404.     PROCEDURE OutputALink ();
  405.  
  406.     BEGIN (* OutputALink *)
  407.       F.Set (w, withFile, 0);
  408.       module := moduleList.head;
  409.       WriteStr ("FROM ");
  410.       WriteStr (module (ModulePtr).path); F.Write (w, "\n");
  411.       module := module.succ;
  412.       WriteStr ("LIBRARY "); WriteStr (module (ModulePtr).path);
  413.       module := module.succ;
  414.       WHILE module # NIL DO
  415.         F.Write (w, "*"); F.Write (w, "\n");
  416.         Indent (); WriteStr (module (ModulePtr).path);
  417.         module := module.succ
  418.       END;
  419.       F.Write (w, "\n"); WriteStr ("TO ");
  420.       WriteStr (moduleName); F.Write (w, "\n");
  421.     END OutputALink;
  422.  
  423.     (*------------------------------------*)
  424.     PROCEDURE OutputBLink ();
  425.  
  426.     BEGIN (* OutputBLink *)
  427.       F.Set (w, withFile, 0);
  428.       module := moduleList.head;
  429.       WriteStr ("FROM\n");
  430.       Indent (); WriteStr (module (ModulePtr).path); F.Write (w, "\n");
  431.       module := module.succ;
  432.       WriteStr ("LIBRARY\n");
  433.       WHILE module # NIL DO
  434.         Indent (); WriteStr (module (ModulePtr).path); F.Write (w, "\n");
  435.         module := module.succ
  436.       END;
  437.       WriteStr ("TO\n");
  438.       Indent (); WriteStr (moduleName); F.Write (w, "\n");
  439.     END OutputBLink;
  440.  
  441.     (*------------------------------------*)
  442.     PROCEDURE OutputDLink ();
  443.  
  444.     BEGIN (* OutputDLink *)
  445.       F.Set (w, withFile, 0);
  446.       module := moduleList.head;
  447.       WHILE module # NIL DO
  448.         WriteStr (module (ModulePtr).path); F.Write (w, "\n");
  449.         module := module.succ
  450.       END;
  451.     END OutputDLink;
  452.  
  453.   BEGIN (* Output *)
  454.     IF outputPath # "" THEN
  455.       COPY (outputPath, withName);
  456.       ch := withName [Str.Length(withName)-1];
  457.       IF (ch # ":") & (ch # "/") THEN Str.Append (withName, "/") END
  458.     ELSE
  459.       withName [0] := 0X
  460.     END;
  461.     Str.Append (withName, moduleName); Str.Append (withName, ".with");
  462.     withFile := F.New (withName);
  463.     IF withFile # NIL THEN
  464.       IF linker = aLink THEN OutputALink ()
  465.       ELSIF linker = bLink THEN OutputBLink ()
  466.       ELSE OutputDLink ()
  467.       END;
  468.       F.Register (withFile);
  469.       IF withFile.dosError # 0 THEN
  470.         IO.WriteF1 ("\x9B\x4B !! Error closing %s\n", SYS.ADR (withName))
  471.       ELSE
  472.         IO.WriteF1 ("\x9B\x4B >> %s\n\n", SYS.ADR (withName))
  473.       END;
  474.     ELSE
  475.       IO.WriteF1 (
  476.         "\x9B\x4B !! Could not create %s\n", SYS.ADR (withName));
  477.     END; (* ELSE *)
  478.   END Output;
  479.  
  480.   (*------------------------------------*)
  481.   PROCEDURE DoLink ();
  482.  
  483.     VAR
  484.       command : ARRAY 256 OF CHAR; success : BOOLEAN;
  485.  
  486.   BEGIN (* DoLink *)
  487.     IF linkerPath # "" THEN COPY (linkerPath, command)
  488.     ELSIF linker = aLink THEN command := "ALink"
  489.     ELSIF linker = bLink THEN command := "BLink"
  490.     ELSE (* linker = dLink *) command := "dlink"
  491.     END;
  492.     IF linker = dLink THEN Str.Append (command, " @")
  493.     ELSE Str.Append (command, " WITH ")
  494.     END;
  495.     Str.Append (command, withName);
  496.     IF linkOptions # "" THEN
  497.       Str.Append (command, " "); Str.Append (command, linkOptions)
  498.     END;
  499.     IF D.base.version >= 37 THEN
  500.       success := (D.base.SystemTags (command, 0) # -1)
  501.     ELSE
  502.       success := D.base.Execute (command, NIL, NIL)
  503.     END;
  504.     IF ~success THEN
  505.       IO.WriteF1 (" !! Error calling '%s'\n", SYS.ADR (command))
  506.     END
  507.   END DoLink;
  508.  
  509. BEGIN (* Main *)
  510.   error := FALSE;
  511.   Process (moduleName, 0);
  512.   IF ~error THEN OberonLib () END;
  513.   IF ~error THEN Output () END;
  514.   IF ~error & doLink THEN DoLink () END
  515. END Main;
  516.  
  517. BEGIN (* OL *)
  518.   Greetings ();
  519.   Init ();
  520.   Main ()
  521. END OL.
  522.  
  523. (***************************************************************************
  524.  
  525.   $Log: OL.mod $
  526.   Revision 2.3  1994/09/03  16:30:49  fjc
  527.   - Gets version string from OLRev.
  528.  
  529.   Revision 2.2  1994/08/08  16:37:42  fjc
  530.   Release 1.4
  531.  
  532.   Revision 2.1  1994/07/03  14:59:27  fjc
  533.   - Added option to call linker direct from OL.
  534.  
  535.   Revision 1.6  1994/06/17  18:07:52  fjc
  536.   - Added specific support for ALink and dlink.
  537.  
  538.   Revision 1.5  1994/06/05  00:02:02  fjc
  539.   - Changed to use new Amiga interface
  540.  
  541.   Revision 1.4  1994/05/19  23:26:57  fjc
  542.   - Fixed case-sensitivity of module parameter.
  543.   - Command line arguments slightly changed.
  544.   - Changed format of .with file to suit Commodore's ALink.
  545.   - OLIB: is now the default symbol file search path.
  546.  
  547.   Revision 1.3  1994/05/11  23:42:09  fjc
  548.   - Added copyright notice to file header
  549.   - Changed greeting
  550.  
  551.   Revision 1.2  1994/01/25  09:58:30  fjc
  552.   - Updated greeting
  553.  
  554.   Revision 1.1  1994/01/15  19:00:05  fjc
  555.   - Start of revision control
  556.  
  557.   v0.3  (02-01-94)  Recognises new symbol file tags.
  558.   v0.2  (06-09-93)  First public release.
  559.   v0.1  (23-07-93)  Initial conversion from Modula 2 to Oberon.
  560.   v0.0  (28-05-93)  Initial version, written in Modula 2.
  561.  
  562. ***************************************************************************)
  563.  
  564.