(* M2Preprocess.mod provides a mechanism to invoke the C preprocessor. Copyright (C) 2001-2023 Free Software Foundation, Inc. Contributed by Gaius Mulley . 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 . *) IMPLEMENTATION MODULE M2Preprocess ; FROM SYSTEM IMPORT WORD ; FROM DynamicStrings IMPORT string, InitString, Mark, KillString, EqualArray, InitStringCharStar, Dup, ConCat, ConCatChar, RIndex, Slice, Length ; FROM choosetemp IMPORT make_temp_file ; FROM pexecute IMPORT pexecute ; FROM libc IMPORT system, exit, unlink, printf, atexit ; FROM Lists IMPORT List, InitList, KillList, IncludeItemIntoList, ForeachItemInListDo ; FROM FIO IMPORT StdErr, StdOut ; FROM M2Printf IMPORT fprintf1 ; FROM M2Options IMPORT Verbose, PPonly, GetObj, GetMD, GetMMD, GetMQ, CppCommandLine, SaveTemps, GetSaveTempsDir, GetDumpDir ; FROM NameKey IMPORT Name, MakeKey, KeyToCharStar, makekey ; VAR ListOfFiles: List ; (* OnExitDelete - *) PROCEDURE OnExitDelete (filename: String) : String ; BEGIN IncludeItemIntoList (ListOfFiles, makekey (filename)) ; RETURN filename END OnExitDelete ; (* RemoveFile - removes a single file, s. *) PROCEDURE RemoveFile (w: WORD) ; VAR n: Name ; BEGIN n := w ; IF unlink (KeyToCharStar (n)) # 0 THEN END END RemoveFile ; (* RemoveFiles - *) PROCEDURE RemoveFiles () : INTEGER ; BEGIN ForeachItemInListDo (ListOfFiles, RemoveFile) ; RETURN 0 END RemoveFiles ; (* Return the filename with no path. *) PROCEDURE GetFileName (Path: String) : String ; VAR fstart: INTEGER ; BEGIN fstart := RIndex(Path, '/', 0) ; IF fstart=-1 THEN fstart := 0 ELSE fstart := fstart + 1 END ; RETURN Dup (Slice(Path, fstart, Length (Path))) END GetFileName ; (* Return basename. *) (* PROCEDURE BaseName (Path: String) : String ; VAR ext, basename: INTEGER ; BEGIN basename := RIndex(Path, '/', 0) ; IF basename=-1 THEN basename := 0 ELSE basename := basename + 1 END ; ext := RIndex(Path, '.', 0) ; IF ext=-1 THEN ext := 0 END ; RETURN Dup (Slice(Path, basename, ext)) END BaseName ; *) (* MakeSaveTempsFileName - return a temporary file like "./filename.{def,mod}.m2i" in the CWD unless SaveTempsDir = obj, when we put it in the dumpdir if that is specified (or fallback to '.' if not). We have to keep the original extension because that disambiguates .def and .mod files (otherwise, we'd need two 'preprocessed' extensions). *) PROCEDURE MakeSaveTempsFileName (filename: String) : String ; VAR NewName, DumpDir, NewDir : String ; BEGIN NewName := ConCat (GetFileName (filename), InitString ('.m2i')) ; NewDir := GetSaveTempsDir () ; DumpDir := GetDumpDir () ; (* IF Verbose THEN fprintf1 (StdOut, "newname: %s", NewName) ; fprintf1 (StdOut, " NewDir: %s", NewDir) ; fprintf1 (StdOut, " DumpDir: %s\n", DumpDir) END ; *) IF (NewDir#NIL) AND EqualArray (NewDir, 'obj') AND (DumpDir#NIL) THEN RETURN Dup (ConCat (DumpDir, NewName)) ELSE RETURN Dup (ConCat (InitString ('./'), NewName)) END ; END MakeSaveTempsFileName ; (* PreprocessModule - preprocess a file, filename, returning the new filename of the preprocessed file. Preprocessing will only occur if requested by the user. If no preprocessing was requested then filename is returned. If preprocessing occurs then a temporary file is created and its name is returned. All temporary files will be deleted when the compiler exits. *) PROCEDURE PreprocessModule (filename: String; isMain: BOOLEAN) : String ; VAR tempfile, command, commandLine: String ; BEGIN command := CppCommandLine () ; IF (command = NIL) OR EqualArray (command, '') THEN RETURN Dup (filename) ELSE commandLine := Dup (command) ; tempfile := NIL ; (* We support MD and MMD for the main file only, at present. *) IF isMain OR PPonly THEN IF GetMD () # NIL THEN tempfile := ConCat( Mark (InitString(' -MD ')), InitStringCharStar (GetMD ())) ELSIF GetMMD () # NIL THEN tempfile := ConCat( Mark (InitString(' -MMD ')), InitStringCharStar (GetMMD ())) END ; IF tempfile#NIL THEN commandLine := ConCat (Dup (commandLine), Dup (tempfile)) ; (* We can only add MQ if we already have an MD/MMD. *) IF GetMQ () # NIL THEN tempfile := ConCat( Mark (InitString(' -MQ ')), InitStringCharStar (GetMQ ())) ; commandLine := ConCat (Dup (commandLine), Dup (tempfile)) END ; END ; END ; (* The output file depends on whether we are in stand-alone PP mode, and if an output file is specified. *) tempfile := NIL ; IF PPonly THEN IF GetObj () # NIL THEN tempfile := InitStringCharStar (GetObj ()) END ; ELSIF SaveTemps THEN tempfile := MakeSaveTempsFileName (filename) ELSE tempfile := InitStringCharStar (make_temp_file (KeyToCharStar (MakeKey('.m2i')))) END ; commandLine := ConCat (ConCatChar (Dup (commandLine), ' '), filename) ; IF tempfile # NIL THEN commandLine := ConCat (ConCat (Dup (commandLine), Mark (InitString(' -o '))), tempfile) ; END ; (* use pexecute in the future res := pexecute(string(Slice(commandLine, 0, Index(commandLine, ' ', 0))), etc etc ); *) (* for now we'll use system *) IF Verbose THEN fprintf1 (StdOut, "preprocess: %s\n", commandLine) END ; IF system (string (commandLine)) # 0 THEN fprintf1 (StdErr, 'C preprocessor failed when preprocessing %s\n', filename) ; exit (1) END ; commandLine := KillString (commandLine) ; IF SaveTemps THEN RETURN tempfile ELSE RETURN OnExitDelete (tempfile) END END END PreprocessModule ; BEGIN InitList (ListOfFiles) ; IF atexit (RemoveFiles) # 0 THEN HALT END END M2Preprocess.