(* gm2lcc.mod generates the link command from a list of modules.
Copyright (C) 2001-2023 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 gm2lcc ;
(*
   Author     : Gaius Mulley
   Title      : gm2lcc
   Date       : Fri Jul 24 11:45:08 BST 1992
   Description: generates the link command from a list of modules.
*)
FROM libc IMPORT system, exit ;
FROM SYSTEM IMPORT ADR ;
FROM NameKey IMPORT Name, MakeKey, WriteKey, GetKey ;
FROM M2Search IMPORT FindSourceFile, PrependSearchPath ;
FROM M2FileName IMPORT CalculateFileName ;
FROM SArgs IMPORT GetArg ;
FROM StrLib IMPORT StrEqual, StrLen, StrCopy, StrConCat, StrRemoveWhitePrefix, IsSubString ;
FROM FIO IMPORT File, StdIn, StdErr, StdOut, Close, IsNoError, EOF, WriteString, WriteLine ;
FROM SFIO IMPORT OpenToRead, WriteS, ReadS ;
FROM ASCII IMPORT nul ;
FROM M2FileName IMPORT ExtractExtension ;
FROM DynamicStrings IMPORT String, InitString, KillString, ConCat, ConCatChar, Length, Slice, Equal, EqualArray, RemoveWhitePrefix, RemoveWhitePostfix, RemoveComment, string, Mark, InitStringChar, Dup, Mult, Assign, char ;
FROM FormatStrings IMPORT Sprintf0, Sprintf1, Sprintf2 ;
FROM M2Printf IMPORT fprintf0, fprintf1, fprintf2, fprintf3, fprintf4 ;
FROM ObjectFiles IMPORT FileObjects, InitFileObject, KillFileObject,
                        RegisterModuleObject, IsRegistered ;
FROM Indexing IMPORT Index, InitIndex, GetIndice,
                     HighIndice, LowIndice, IncludeIndiceIntoIndex,
                     ForeachIndiceInIndexDo ;
CONST
   Comment     =     '#' ;      (* Comment leader.                 *)
   MaxSpaces   =      20 ;      (* Maximum spaces after a module   *)
                                (* name.                           *)
   Debugging   =     FALSE ;
VAR
   DebugFound    : BOOLEAN ;
   CheckFound    : BOOLEAN ;
   VerboseFound  : BOOLEAN ;
   ProfileFound  : BOOLEAN ;
   LibrariesFound: BOOLEAN ;
   TargetFound   : BOOLEAN ;
   ExecCommand   : BOOLEAN ;    (* should we execute the final cmd *)
   UseAr         : BOOLEAN ;    (* use 'ar' and create archive     *)
   UseRanlib     : BOOLEAN ;    (* use 'ranlib' to index archive   *)
   IgnoreMain    : BOOLEAN ;    (* ignore main module when linking *)
   UseLibtool    : BOOLEAN ;    (* use libtool and suffixes?       *)
   Shared        : BOOLEAN ;    (* is a shared library required?   *)
   BOption,                  (* the full -B option and directory.  *)
   FOptions,
   CompilerDir,               (* contains the directory after -B.  *)
   RanlibProgram,
   ArProgram,
   Archives,
   Path,
   StartupFile,
   Libraries,
   MainModule,
   MainObject,
   Command,
   Target        : String ;
   CmdLine,
   objects       : FileObjects ;
   CmdLineObjects: Index ;
   fi, fo        : File ;       (* the input and output files      *)
(*
   FlushCommand - flush the command to the output file,
                  or execute the command.
*)
PROCEDURE FlushCommand () : INTEGER ;
BEGIN
   IF ExecCommand
   THEN
      IF VerboseFound
      THEN
         Command := WriteS (StdOut, Command) ;
         fprintf0 (StdOut, '\n')
      END ;
      RETURN system (string (Command))
   ELSE
      Command := WriteS (fo, Command)
   END ;
   RETURN 0
END FlushCommand ;
(*
   GenerateLinkCommand - generate the appropriate linkage command
                         with the correct options.
*)
PROCEDURE GenerateLinkCommand ;
BEGIN
   IF UseAr
   THEN
      Command := ConCat (ArProgram, InitString (' rc ')) ;
      IF TargetFound
      THEN
         Command := ConCat (Command, Target) ;
         Command := ConCatChar (Command, ' ')
      ELSE
         WriteString (StdErr, 'need target with ar') ; WriteLine (StdErr) ; Close (StdErr) ;
         exit (1)
      END
   ELSIF UseLibtool
   THEN
      Command := InitString ('libtool --tag=CC --mode=link gcc ') ;
      IF BOption # NIL
      THEN
         Command := ConCat (Command, Dup (BOption)) ;
         Command := ConCatChar (Command, ' ')
      END ;
      IF DebugFound
      THEN
         Command := ConCat (Command, Mark (InitString ('-g ')))
      END ;
      IF ProfileFound
      THEN
         Command := ConCat(Command, Mark(InitString ('-p ')))
      END ;
      Command := ConCat (Command, FOptions) ;
      IF Shared
      THEN
         Command := ConCat (Command, Mark (InitString ('-shared ')))
      END ;
      IF TargetFound
      THEN
         Command := ConCat (Command, Mark (InitString ('-o '))) ;
         Command := ConCat (Command, Target) ;
         Command := ConCatChar (Command, ' ')
      END ;
      IF ProfileFound
      THEN
         Command := ConCat (Command, Mark (InitString ('-lgmon ')))
      END
   END
END GenerateLinkCommand ;
(*
   GenerateRanlibCommand - generate the appropriate ranlib command.
*)
PROCEDURE GenerateRanlibCommand ;
BEGIN
   Command := ConCat (RanlibProgram, Mark (InitStringChar (' '))) ;
   IF TargetFound
   THEN
      Command := ConCat (Command, Target) ;
      Command := ConCatChar (Command, ' ')
   ELSE
      WriteString (StdErr, 'need target with ranlib') ; WriteLine (StdErr) ; Close (StdErr) ;
      exit (1)
   END
END GenerateRanlibCommand ;
(*
   RemoveLinkOnly - removes the <onlylink> prefix, if present.  This will occur
                    for a definition for "C" module where there is no
                    module constructor/destructor (_init and _finish pairs).
                    Otherwise, s, is returned.
*)
PROCEDURE RemoveLinkOnly (s: String) : String ;
VAR
   t: String ;
BEGIN
   t := InitString ('<onlylink>') ;
   IF Equal (Mark (Slice (s, 0, Length (t)-1)), t)
   THEN
      RETURN RemoveWhitePrefix (Slice (Mark (s), Length (t), 0))
   ELSE
      RETURN s
   END
END RemoveLinkOnly ;
(*
   ConCatStartupFile - check to see if the startup object file has not been added
                       to the command line and if so add it.
*)
PROCEDURE ConCatStartupFile ;
BEGIN
   IF RegisterModuleObject (objects, StartupFile)
   THEN
      IF UseLibtool
      THEN
         Command := ConCat (Command, Mark (Sprintf1 (Mark (InitString ('%s.lo')),
                                                     StartupFile)))
      ELSE
         Command := ConCat (Command, Mark (Sprintf1 (Mark (InitString ('%s.o')),
                                                     StartupFile)))
      END
   END
END ConCatStartupFile ;
(*
   GenObjectSuffix -
*)
PROCEDURE GenObjectSuffix () : String ;
BEGIN
   IF UseLibtool
   THEN
      RETURN InitString ('lo')
   ELSE
      RETURN InitString ('o')
   END
END GenObjectSuffix ;
(*
   GenArchiveSuffix -
*)
PROCEDURE GenArchiveSuffix () : String ;
BEGIN
   IF UseLibtool
   THEN
      RETURN InitString ('la')
   ELSE
      RETURN InitString ('a')
   END
END GenArchiveSuffix ;
(*
   LookupObjectFile - attempts to lookup the location of file name.extension
                      from using the -fobject-path path.  NIL is retured if
                      the object file is not found.  extension will be
                      marked and deleted.
*)
PROCEDURE LookupObjectFile (name, extension: String) : String ;
VAR
   location,
   filename: String ;
BEGIN
   filename := CalculateFileName (name, Mark (extension)) ;
   IF FindSourceFile (filename, location)
   THEN
      RETURN location
   ELSE
      RETURN NIL
   END
END LookupObjectFile ;
(*
   ConCatModuleObject - this object will be associated with a module, therefore
                        we remember it and make sure that it is not duplicated on the
                        command line by the user.
*)
PROCEDURE ConCatModuleObject (module: String) ;
VAR
   location: String ;
BEGIN
   location := LookupObjectFile (module, GenObjectSuffix ()) ;
   IF location = NIL
   THEN
      location := LookupObjectFile (module, GenArchiveSuffix ()) ;
      IF location # NIL
      THEN
         Archives := ConCatChar (ConCat (Archives, location), ' ')
      END
   ELSE
      IF RegisterModuleObject (objects, location)
      THEN
         Command := ConCat (ConCatChar (Command, ' '), location)
      END
   END
END ConCatModuleObject ;
(*
   FindModulesInFileList -
*)
PROCEDURE FindModulesInFileList ;
VAR
   text: String ;
BEGIN
   REPEAT
      text := RemoveComment (RemoveWhitePrefix( ReadS (fi)), Comment) ;
      IF (NOT EqualArray (text, '')) AND (NOT (IgnoreMain AND Equal (text, MainModule)))
      THEN
         text := RemoveLinkOnly (text) ;
         ConCatModuleObject (text)
      END
   UNTIL EOF (fi) ;
   IF (NOT EqualArray (MainObject, "")) AND RegisterModuleObject (objects, MainObject)
   THEN
      Command := ConCat (ConCatChar (Command, ' '), MainObject)
   END
END FindModulesInFileList ;
(*
   CollectObjects -
*)
PROCEDURE CollectObjects (Command: String) : String ;
VAR
   i, h: CARDINAL ;
   name: String ;
BEGIN
   i := 1 ;
   h := HighIndice (CmdLineObjects) ;
   WHILE i <= h DO
      name := GetIndice (CmdLineObjects, i) ;
      IF NOT IsRegistered (objects, name)
      THEN
         Command := ConCat (ConCatChar (Command, ' '), Dup (name))
      END ;
      INC (i)
   END ;
   IF Debugging
   THEN
      fprintf1 (StdErr, "objects on command line: %s\n", Command)
   END ;
   RETURN Command
END CollectObjects ;
(*
   CollectArchives -
*)
PROCEDURE CollectArchives (Command: String) : String ;
BEGIN
   IF LibrariesFound
   THEN
      Command := ConCat (ConCatChar (Command, ' '), Libraries)
   END ;
   RETURN Command
END CollectArchives ;
(*
   AddProgramModule - add the program module to the Command string, providing
                      that the user did not specify it on the command line.
*)
PROCEDURE AddProgramModule (Command: String) : String ;
BEGIN
   IF Debugging
   THEN
      fprintf1 (StdErr, "mainobject: %s\n", MainObject)
   END ;
   IF (NOT EqualArray (MainObject, "")) AND RegisterModuleObject (objects, MainObject)
   THEN
      IF Debugging
      THEN
         fprintf1 (StdErr, "first time: %s\n", MainObject)
      END ;
      Command := ConCat (ConCatChar (Command, ' '), MainObject)
   ELSE
      IF Debugging
      THEN
         fprintf0 (StdErr, "(ignored)\n")
      END
   END ;
   RETURN Command
END AddProgramModule ;
(*
   GenCC - writes out the linkage command for the C compiler.
*)
PROCEDURE GenCC ;
VAR
   Error: INTEGER ;
BEGIN
   GenerateLinkCommand ;
   ConCatStartupFile ;
   FindModulesInFileList ;
   Command := AddProgramModule (Command) ;
   Command := ConCat (Command, Archives) ;
   Command := CollectObjects (Command) ;
   Command := CollectArchives (Command) ;
   Error := FlushCommand () ;
   IF Error=0
   THEN
      IF UseRanlib
      THEN
         GenerateRanlibCommand ;
         Error := FlushCommand () ;
         IF Error#0
         THEN
            fprintf1 (StdErr, 'ranlib failed with exit code %d\n', Error) ;
            Close (StdErr) ;
            exit (Error)
         END
      END
   ELSE
      fprintf1 (StdErr, 'ar failed with exit code %d\n', Error) ;
      Close (StdErr) ;
      exit (Error)
   END
END GenCC ;
(*
   WriteModuleName - displays a module name, ModuleName, with formatted spaces
                     after the string.
*)
(*
PROCEDURE WriteModuleName (ModuleName: String) ;
BEGIN
   ModuleName := WriteS (fo, ModuleName) ;
   IF KillString (WriteS (fo, Mark (Mult (Mark (InitString (' ')), MaxSpaces-Length(ModuleName))))) = NIL
   THEN
   END
END WriteModuleName ;
*)
(*
   CheckCC - checks to see whether all the object files can be found
             for each module.
*)
PROCEDURE CheckCC ;
VAR
   s, t, u: String ;
   Error  : INTEGER ;
BEGIN
   Error := 0 ;
   REPEAT
      s := RemoveComment (RemoveWhitePrefix (ReadS (fi)), Comment) ;
      IF NOT EqualArray (s, '')
      THEN
         s := RemoveLinkOnly (s) ;
         t := Dup (s) ;
         t := CalculateFileName (s, Mark (GenObjectSuffix ())) ;
         IF FindSourceFile (t, u)
         THEN
            IF KillString (WriteS (fo, Mark (Sprintf2 (Mark (InitString ('%-20s : %s\n')), t, u)))) = NIL
            THEN
            END ;
            u := KillString (u)
         ELSE
            t := KillString (t) ;
            (* try finding .a archive *)
            t := CalculateFileName (s, Mark (GenArchiveSuffix ())) ;
            IF FindSourceFile (t, u)
            THEN
               IF KillString (WriteS (fo, Mark (Sprintf2 (Mark (InitString ('%-20s : %s\n')), t, u)))) = NIL
               THEN
               END ;
               u := KillString (u)
            ELSE
               IF KillString (WriteS (fo, Mark (Sprintf1 (InitString ('%-20s : distinct object or archive not found\n'), t)))) = NIL
               THEN
               END ;
               Error := 1
            END
         END
      END
   UNTIL EOF (fi) ;
   Close (fo) ;
   exit (Error)
END CheckCC ;
(*
   ProcessTarget - copies the specified target file into Target
                   and sets the boolean TargetFound.
*)
PROCEDURE ProcessTarget (i: CARDINAL) ;
BEGIN
   IF NOT GetArg (Target, i)
   THEN
      fprintf0 (StdErr, 'cannot get target argument after -o\n') ;
      Close (StdErr) ;
      exit (1)
   END ;
   TargetFound := TRUE
END ProcessTarget ;
(*
   StripModuleExtension - returns a String without an extension from, s.
                          It only considers '.obj', '.o' and '.lo' as
                          extensions.
*)
PROCEDURE StripModuleExtension (s: String) : String ;
VAR
   t: String ;
BEGIN
   t := ExtractExtension (s, Mark (InitString ('.lo'))) ;
   IF s=t
   THEN
      t := ExtractExtension (s, Mark (InitString ('.obj'))) ;
      IF s=t
      THEN
         RETURN ExtractExtension (s, Mark(InitString('.o')))
      END
   END ;
   RETURN t
END StripModuleExtension ;
(*
   ProcessStartupFile - copies the specified startup file name into StartupFile.
*)
PROCEDURE ProcessStartupFile (i: CARDINAL) ;
BEGIN
   IF GetArg (StartupFile, i)
   THEN
      StartupFile := StripModuleExtension (StartupFile)
   ELSE
      fprintf0 (StdErr, 'cannot get startup argument after --startup\n') ;
      Close (StdErr) ;
      exit (1)
   END
END ProcessStartupFile ;
(*
   IsALibrary - returns TRUE if, a, is a library. If TRUE we add it to the
                Libraries string.
*)
PROCEDURE IsALibrary (s: String) : BOOLEAN ;
BEGIN
   IF EqualArray (Mark (Slice (s, 0, 2)), '-l')
   THEN
      LibrariesFound := TRUE ;
      Libraries := ConCat (ConCatChar (Libraries, ' '), s) ;
      RETURN TRUE
   ELSE
      RETURN FALSE
   END
END IsALibrary ;
(*
   IsALibraryPath -
*)
PROCEDURE IsALibraryPath (s: String) : BOOLEAN ;
BEGIN
   IF EqualArray (Mark (Slice (s, 0, 2)), '-L')
   THEN
      IF UseLibtool
      THEN
         LibrariesFound := TRUE ;
         Libraries := ConCat (ConCatChar (Libraries, ' '), s)
      END ;
      RETURN TRUE
   ELSE
      RETURN FALSE
   END
END IsALibraryPath ;
(*
   AddCommandLineObject - adds, s, to a list of objects specified on the command line.
*)
PROCEDURE AddCommandLineObject (s: String) ;
BEGIN
   s := Dup (s) ;
   IncludeIndiceIntoIndex (CmdLineObjects, s) ;
   IF RegisterModuleObject (CmdLine, s)
   THEN
      IF Debugging
      THEN
         fprintf1 (StdErr, "object registered first time: %s\n", s)
      END
   ELSE
      IF Debugging
      THEN
         fprintf1 (StdErr, "  object ignored: %s\n", s)
      END
   END
END AddCommandLineObject ;
(*
   IsAnObject - returns TRUE if, a, is a library.
*)
PROCEDURE IsAnObject (s: String) : BOOLEAN ;
BEGIN
   IF ((Length (s) > 2) AND EqualArray (Mark (Slice (s, -2, 0)), '.o')) OR
      ((Length (s) > 4) AND EqualArray (Mark (Slice (s, -4, 0)), '.obj'))
   THEN
      RETURN TRUE
   ELSE
      RETURN FALSE
   END
END IsAnObject ;
(*
   AdditionalFOptions - add an -f option to the compiler.
*)
PROCEDURE AdditionalFOptions (s: String) ;
BEGIN
   FOptions := ConCat (FOptions, Mark (s)) ;
   FOptions := ConCatChar (FOptions, ' ')
END AdditionalFOptions ;
(*
   DisplayHelp -
*)
PROCEDURE DisplayHelp ;
BEGIN
   fprintf0 (StdErr, 'Usage: gm2lcc [-c][-g][-h][--help][--main mainmodule]\n');
   fprintf0 (StdErr, '              [--mainobject objectname][-Bdirectory][-p][--exec][-fshared]\n');
   fprintf0 (StdErr, '              [--ignoremain][--ar][-fobject-path=path][-ftarget-ar=arname]\n');
   fprintf0 (StdErr, '              [-ftarget-ranlib=ranlibname][-o outputname][--startup filename]\n') ;
   fprintf0 (StdErr, '              [-foption][-llibname][-Lpath] filename\n');
   exit (0)
END DisplayHelp ;
(*
   ScanArguments - scans arguments for flags: -fobject-path= -g and -B
*)
PROCEDURE ScanArguments ;
VAR
   filename,
   s        : String ;
   i        : CARDINAL ;
   FoundFile: BOOLEAN ;
BEGIN
   FoundFile := FALSE ;
   filename := NIL ;
   i := 1 ;
   WHILE GetArg (s, i) DO
      IF EqualArray (s, '-h') OR EqualArray (s, '--help')
      THEN
         DisplayHelp
      ELSIF EqualArray (s, '-g')
      THEN
         DebugFound := TRUE
      ELSIF EqualArray (s, '-c')
      THEN
         CheckFound := TRUE
      ELSIF EqualArray (s, '--main')
      THEN
         INC (i) ;
         IF NOT GetArg (MainModule, i)
         THEN
            fprintf0 (StdErr, 'expecting modulename after the --main option\n') ;
            Close (StdErr) ;
            exit (1)
         END
      ELSIF EqualArray (s, '--mainobject')
      THEN
         INC (i) ;
         IF GetArg (MainObject, i)
         THEN
            (* do nothing.  *)
         ELSE
            fprintf0 (StdErr, 'expecting an object file after the --mainobject option\n') ;
            Close (StdErr) ;
            exit (1)
         END
      ELSIF EqualArray (Mark (Slice (s, 0, 2)), '-B')
      THEN
         CompilerDir := KillString (CompilerDir) ;
         IF Length (s) = 2
         THEN
            INC(i) ;
            IF NOT GetArg (CompilerDir, i)
            THEN
               fprintf0 (StdErr, 'expecting path after -B option\n') ;
               Close (StdErr) ;
               exit (1)
            END
         ELSE
            CompilerDir := Slice (s, 2, 0)
         END ;
         BOption := Dup (s)
      ELSIF EqualArray (s, '-p')
      THEN
         ProfileFound := TRUE
      ELSIF EqualArray (s, '-v')
      THEN
         VerboseFound := TRUE
      ELSIF EqualArray (s, '--exec')
      THEN
         ExecCommand := TRUE
      ELSIF EqualArray (s, '-fshared')
      THEN
         Shared := TRUE
      ELSIF EqualArray (s, '--ignoremain')
      THEN
         IgnoreMain := TRUE
      ELSIF EqualArray (s, '--ar')
      THEN
         UseAr := TRUE ;
         UseRanlib := TRUE ;
         UseLibtool := FALSE
      ELSIF EqualArray (Mark (Slice (s, 0, 14)), '-fobject-path=')
      THEN
         PrependSearchPath (Slice (s, 14, 0))
      ELSIF EqualArray (Mark (Slice (s, 0, 12)), '-ftarget-ar=')
      THEN
         ArProgram := KillString (ArProgram) ;
         ArProgram := Slice (s, 12, 0)
      ELSIF EqualArray (Mark (Slice (s, 0, 16)), '-ftarget-ranlib=')
      THEN
         RanlibProgram := KillString (RanlibProgram) ;
         RanlibProgram := Slice (s, 16, 0)
      ELSIF EqualArray (s, '-o')
      THEN
         INC (i) ;                 (* Target found *)
         ProcessTarget (i)
      ELSIF EqualArray (s, '--startup')
      THEN
         INC (i) ;                 (* Target found.  *)
         ProcessStartupFile (i)
      ELSIF EqualArray (Mark (Slice (s, 0, 2)), '-f')
      THEN
         AdditionalFOptions (s)
      ELSIF IsALibrary (s) OR IsALibraryPath (s)
      THEN
      ELSIF IsAnObject (s)
      THEN
         AddCommandLineObject (s)
      ELSE
         IF FoundFile
         THEN
            fprintf2 (StdErr, 'already specified input filename (%s), unknown option (%s)\n', filename, s) ;
            Close (StdErr) ;
            exit (1)
         ELSE
            (* must be input filename.  *)
            Close (StdIn) ;
            fi := OpenToRead (s) ;
            IF NOT IsNoError (fi)
            THEN
               fprintf1 (StdErr, 'failed to open %s\n', s) ;
               Close (StdErr) ;
               exit (1)
            END ;
            FoundFile := TRUE ;
            filename := Dup (s)
         END
      END ;
      INC (i)
   END
END ScanArguments ;
(*
   Init - initializes the global variables.
*)
PROCEDURE Init ;
BEGIN
   DebugFound    := FALSE ;
   CheckFound    := FALSE ;
   TargetFound   := FALSE ;
   ProfileFound  := FALSE ;
   IgnoreMain    := FALSE ;
   UseAr         := FALSE ;
   UseLibtool    := FALSE ;
   UseRanlib     := FALSE ;
   VerboseFound  := FALSE ;
   Shared        := FALSE ;
   ArProgram     := InitString ('ar') ;
   RanlibProgram := InitString ('ranlib') ;
   MainModule    := InitString ('') ;
   StartupFile   := InitString ('mod_init') ;
   fi            := StdIn ;
   fo            := StdOut ;
   ExecCommand   := FALSE ;
   CompilerDir   := InitString ('') ;
   FOptions      := InitString ('') ;
   Archives      := NIL ;
   Path          := NIL ;
   LibrariesFound:= FALSE ;
   Libraries     := InitString ('') ;
   Command       := NIL ;
   Target        := NIL ;
   BOption       := NIL ;
   objects       := InitFileObject () ;
   CmdLine       := InitFileObject () ;
   CmdLineObjects:= InitIndex (1) ;
   MainObject    := InitString ('') ;
   ScanArguments ;
   IF CheckFound
   THEN
      CheckCC
   ELSE
      GenCC
   END ;
   Close (fo)
END Init ;
BEGIN
   Init
END gm2lcc.