(* gm2lorder.mod ensure that underlying runtime modules are initialized. Copyright (C) 2008-2025 Free Software Foundation, Inc. Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>. This file is part of GNU Modula-2. GNU Modula-2 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 3, or (at your option) any later version. GNU Modula-2 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 GNU Modula-2; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. *) MODULE gm2lorder ; (* Author : Gaius Mulley Title : gm2lorder Date : Thu Sep 4 21:18:33 BST 2008 Description: Ensures that underlying runtime modules are initialized before all other modules. *) FROM libc IMPORT exit ; FROM ASCII IMPORT eof ; FROM SArgs IMPORT GetArg ; FROM StrLib IMPORT StrLen ; FROM DynamicStrings IMPORT String, InitString, KillString, Length, Equal, EqualArray, Slice, Mark ; FROM Indexing IMPORT Index, PutIndice, GetIndice, RemoveIndiceFromIndex, InitIndex, KillIndex, HighIndice ; FROM FIO IMPORT File, StdIn, StdOut, StdErr, WriteChar, WriteLine, Close, EOF, IsNoError, WriteString, FlushBuffer ; FROM SFIO IMPORT OpenToRead, OpenToWrite, ReadS, WriteS ; IMPORT DynamicStrings ; CONST Comment = '#' ; (* Comment identifier. *) DefaultRuntimeModules = 'Storage,SYSTEM,M2RTS,RTExceptions,IOLink' ; VAR fi, fo : File ; runTime : Index ; moduleList: Index ; (* InitRuntimeModules - initializes the list of critical runtime modules which must be initialized first and in a particular order. *) PROCEDURE InitRuntimeModules (s: String) ; VAR a : CARDINAL ; i, j: INTEGER ; BEGIN IF runTime # NIL THEN runTime := KillIndex (runTime) END ; runTime := InitIndex (0) ; i := 0 ; a := 0 ; REPEAT j := DynamicStrings.Index (s, ',', i) ; IF j = -1 THEN PutIndice (runTime, a, Slice (s, i, 0)) ELSE PutIndice (runTime, a, Slice (s, i, j)) ; i := j+1 END ; INC(a) UNTIL j=-1 ; s := KillString (s) END InitRuntimeModules ; (* Reorder - reorders the list of modules to ensure critical runtime modules are initialized first. It writes out the new ordered list. *) PROCEDURE Reorder ; VAR rh, mh, ri, mi: CARDINAL ; rs, ms: String ; BEGIN rh := HighIndice (runTime) ; mh := HighIndice (moduleList) ; ri := 0 ; WHILE ri <= rh DO mi := 0 ; rs := GetIndice (runTime, ri) ; WHILE mi <= mh DO ms := GetIndice (moduleList, mi) ; IF Equal (rs, ms) THEN rs := WriteS (fo, rs) ; WriteLine (fo) ; RemoveIndiceFromIndex (moduleList, ms) ; mh := HighIndice (moduleList) ELSE INC (mi) END END ; INC (ri) END ; mi := 0 ; WHILE mi <= mh DO ms := GetIndice (moduleList, mi) ; ms := WriteS (fo, ms) ; WriteLine (fo) ; INC (mi) END ; Close (fo) END Reorder ; (* ReadList - populates the moduleList with a list of module names. *) PROCEDURE ReadList ; VAR s: String ; i: CARDINAL ; BEGIN moduleList := InitIndex (0) ; i := 0 ; s := ReadS (fi) ; WHILE NOT EOF (fi) DO IF NOT EqualArray (s, '') THEN PutIndice (moduleList, i, s) ; INC (i) END ; s := ReadS (fi) END ; IF NOT EqualArray (s, '') THEN PutIndice (moduleList, i, s) END END ReadList ; (* OpenOutputFile - attempts to open an output file. *) PROCEDURE OpenOutputFile (s: String) ; BEGIN IF EqualArray(s, '-') THEN fo := StdOut ELSE fo := OpenToWrite(s) ; IF NOT IsNoError(fo) THEN WriteString(StdErr, 'cannot write to: ') ; s := WriteS(StdErr, s) ; WriteLine(StdErr) ; exit(1) END END END OpenOutputFile ; (* Usage - prints out a usage and exits with 0. *) PROCEDURE Usage ; BEGIN WriteString(StdOut, 'gm2lorder [-h] [-o outputfile] [-fruntime-modules=] inputfile') ; WriteLine(StdOut) ; WriteString(StdOut, ' inputfile is a file containing a list of modules, each module on a separate line') ; WriteLine(StdOut) ; WriteString(StdOut, ' the list of runtime modules can be specified as follows -fruntime-modules=module1,module2,module3') ; WriteLine(StdOut) ; WriteString(StdOut, ' the default for this flag is -fruntime-modules=') ; WriteString(StdOut, DefaultRuntimeModules) ; WriteLine(StdOut) ; WriteString(StdOut, ' Note that the list of runtime modules does not mean they will appear in the executable') ; WriteLine(StdOut) ; WriteString(StdOut, ' a runtime module is only included into the final executable if it is required,') ; WriteLine(StdOut) ; WriteString(StdOut, ' however gm2lorder will ensure the order of these modules.') ; WriteLine(StdOut) ; FlushBuffer(StdOut) ; exit(0) END Usage ; (* ScanArgs - scans arguments. *) PROCEDURE ScanArgs ; VAR i : CARDINAL ; s : String ; FoundFile: BOOLEAN ; BEGIN FoundFile := FALSE ; fi := StdIn ; fo := StdOut ; i := 1 ; WHILE GetArg(s, i) DO IF EqualArray(s, '-o') THEN s := KillString(s) ; INC(i) ; IF GetArg(s, i) THEN OpenOutputFile(s) ELSE WriteString(StdErr, 'missing filename option after -o') ; WriteLine(StdErr) ; exit(1) END ELSIF EqualArray(s, '-h') THEN Usage ELSIF EqualArray(Mark(Slice(s, 0, StrLen('-fruntime-modules='))), '-fruntime-modules=') THEN InitRuntimeModules(Slice(s, StrLen('-fruntime-modules='), 0)) ELSE IF FoundFile THEN WriteString(StdErr, 'already opened one file for reading') ; WriteLine(StdErr) ELSE FoundFile := TRUE ; fi := OpenToRead(s) ; IF NOT IsNoError(fi) THEN WriteString(StdErr, 'failed to open: ') ; s := WriteS(StdErr, s) ; WriteLine(StdErr) ; exit(1) END END END ; INC(i) END ; IF NOT FoundFile THEN WriteString(StdErr, 'a module file list must be specified on the command line') ; WriteLine(StdErr) ; exit(1) END END ScanArgs ; (* Init - *) PROCEDURE Init ; BEGIN runTime := NIL ; moduleList := NIL ; InitRuntimeModules(InitString(DefaultRuntimeModules)) ; ScanArgs ; ReadList ; Reorder END Init ; BEGIN Init END gm2lorder.