/* TurboText AREXX Macro for M2Sprint Modula-2 Linker */
/* Version 1.0, 4 April 95 by J. E. Gilpin */
/*
$VER: TTX_M2S_Link 1.0 (04.04.95)
*/

/*************************************************************************/
/* Tell ARexx to request a results string from external commands.        */
/*-----------------------------------------------------------------------*/
OPTIONS RESULTS

/*************************************************************************/
/* Set up a prompt for the ARexx console window. Requesting user input   */
/* at the end of this ARexx macro allows the linker output to be         */
/* examined before closing the console window.                           */
/*-----------------------------------------------------------------------*/
OPTIONS PROMPT "Press <CTRL \> or <RETURN> to exit:>"

/*************************************************************************/
/* Define BOOLEAN constants & control characters for program readability.*/
/*-----------------------------------------------------------------------*/
TRUE = 1; FALSE = 0; LF = '0A'x; CR = '0D'x; Space = '20'x; Tab = '09'x

/*************************************************************************/
/* Use the TurboText Command "GetFilePath" to get the complete file path */
/* and name of the program currently loaded in the editor.               */
/*-----------------------------------------------------------------------*/
GetFilePath
Name=RESULT

/*************************************************************************/
/* Extract the path portion of the filename to use as the destination    */
/* directory for the Linker.                                             */
/*-----------------------------------------------------------------------*/
dir=LASTPOS('/',Name)        /* Check for a directory delimiter.         */
device=LASTPOS(':',Name)     /* Check for a device or volume delimiter.  */
IF dir>0 THEN
 DO
  Path=LEFT(Name,dir-1)      /* Path is a directory.  */
  PathType="dir"
 END
ELSE IF device>0 THEN
 DO
  Path=LEFT(Name,device)     /* Path is device or vol.*/
  PathType="dev"
 END
ELSE DO
  SAY "Can't get File Path"  /* No path found, so this macro won't work. */
  SIGNAL Depart              /* Exit the macro. */
END

/*************************************************************************/
/* Switch to TurboText's second view before executing any commands which */
/* might move the cursor to another location in the program. Executing   */
/* TurboText Command "SwitchView" at the end of this macro will switch   */
/* back to the original view and cursor position. This step isn't        */
/* necessary, but it eliminates confusion caused by unexpected cursor    */
/* movement. If you are using TurboText's second view for another        */
/* purpose, you can eliminate this step.                                 */
/*-----------------------------------------------------------------------*/
SwitchView

/*************************************************************************/
/* The M2S Compiler output filename consists of the "MODULE name" with   */
/* the file extension ".lnk". Locate the MODULE name in the program, add */
/* ".lnk" to the name and invoke the M2S Linker "M2L" with the resulting */
/* filename. Check for the correct MODULE type before linking.           */
/*-----------------------------------------------------------------------*/

GetPrefs FreeForm                   /* Get line wrap setting.            */
Form=RESULT                         /* Save as variable "Form".          */
SetPrefs FreeForm OFF               /* Enables word wrap at EOL.         */
Type="MOD"
MoveSOF                             /* Move cursor to start of program.  */
DO WHILE RC=0                       /* Exit loop if past end of text.    */
  IF ~FindWord() THEN LEAVE         /* "FindWord" skips M2 comments etc. */
  GetWord; Word=RESULT              /* Get word & assign to variable.    */
  SELECT
   WHEN Word = "MODULE" THEN        /* If the word is MODULE exit loop.  */
    DO
     MoveRight 6                    /* Move cursor past word MODULE.     */
     IF ~FindWord() THEN LEAVE      /* "FindWord" skips M2 comments etc. */
     CALL LinkFile                  /* "LinkFile" calls the M2S linker.  */
     SIGNAL Done                    /* Exit from this ARexx Script.      */
    END
   WHEN Word = "DEFINITION" THEN    /* IF word is DEFINITION skip it.    */
    DO
     Type="DEF"                     /* Set program type flag.            */
     MoveRight 10                   /* Move cursor past word & continue. */
    END
   WHEN Word="IMPLEMENTATION" THEN  /* If word is IMPLEMENTATION skip it.*/
    DO
     Type="IMP"                     /* Set program type flag.            */
     MoveRight 14                   /* Move cursor past word & continue. */
    END
   OTHERWISE LEAVE                  /* Word MODULE not found. Exit loop  */
  END
END
SAY "MODULE Name not found"         /* Write error message.              */

Done:
SetPrefs FreeForm Form              /* Restore original FreeForm setting.*/
SwitchView                          /* Restore original TurboText View.  */
Depart:
PULL CmdString
Exit                                /* Macro finished, exit to editor.   */


LinkFile:
/*************************************************************************/
/* Check the "Type" flag, set by the calling procedure, to assure that   */
/* the Module to be linked is the correct type. If it isn't, issue an    */
/* error message and return to the calling procedure.                    */
/*-----------------------------------------------------------------------*/

IF Type="DEF" THEN                  /* Check for correct Module type     */
 DO                                 /* before invoking the linker.       */
  SAY "Cannot Link a DEFINITION symbol file." /* Write error message.    */
  RETURN                            /* Incorrect Module type, so return  */
 END                                /* without invoking the linker.      */
GetWord                             /* Get word following "MODULE".      */
ModuleName=RESULT                   /* Assign module name to a variable. */
IF PathType="dir" THEN              /* If the destination path is a      */
 DO                                 /* directory; concatenate the path,  */
  Name=Path||"/"||ModuleName||".lnk"/* a "/", and the module name.       */
 END                                /* If the path is a device or volume */
ELSE Name=Path||ModuleName||".lnk"  /* concatenate path & module name.   */

/***  Run the M2Sprint linker "M2L" and return to the main procedure.  ***/
ADDRESS COMMAND "M2Sprint:M2L "||'"'Name'"'||" TO "||'"'Path'"'
RETURN


FindWord:
/*************************************************************************/
/* M2Sprint (like most Modula-2 compilers) allows comments to precede    */
/* the module name. The Modula-2 keyword "MODULE" could be present       */
/* within a comment and result in a filename misidentification if a word */
/* search is performed. Therefore, a character search is performed       */
/* instead. This procedure returns a BOOLEAN value "TRUE" when the first */
/* uncommented word is found; otherwise it returns "FALSE".              */
/*-----------------------------------------------------------------------*/

DO WHILE RC=0                       /* Repeat until end of text.         */
  Skip=TRUE                         /* Initialize BOOLEAN flag for loop. */
  DO WHILE Skip                     /* Start text analysis loop.         */
    GetChar; Char=RESULT            /* Get a character to check.         */
    SELECT                          /* Skip spaces, line feeds etc.      */
      WHEN Char=CR    THEN Skip=TRUE
      WHEN Char=LF    THEN Skip=TRUE
      WHEN Char=Tab   THEN Skip=TRUE
      WHEN Char=Space THEN Skip=TRUE
      OTHERWISE Skip=FALSE          /* Text, so set flag to exit loop.   */
    END
    IF Skip THEN MoveRight          /* Move cursor to next character.    */
    IF RC~=0 THEN RETURN FALSE      /* If error indicates EOF, return F. */
  END
  IF Char="(" THEN DO               /* Check for start of M2 comment.    */
    MoveRight;GetChar;Char=RESULT   /* Get next character.               */
    IF Char~="*" THEN RETURN FALSE  /* If not comment, return FALSE.     */
    DO UNTIL Char=")"               /* Loop until end comment found.     */
      DO UNTIL Char="*"             /* Loop until asterisk found.        */
        MoveRight                   /* Move cursor to next character.    */
        IF RC~=0 THEN RETURN FALSE  /* If error indicates EOF, return F. */
        GetChar; Char=RESULT        /* Get a character to check.         */
      END
      MoveRight                     /* Move cursor to next character.    */
      IF RC~=0 THEN RETURN FALSE    /* If error indicates EOF, return F. */
      GetChar; Char=RESULT          /* Get a character to check.         */
    END
    MoveRight                       /* Must have found end of comment to */
    ITERATE                         /* get here, so move cursor and skip */
  END                               /* to next iteration of outer loop.  */
  RETURN TRUE                       /* Skipped legal comments & chars so */
END                                 /* return TRUE.                      */
RETURN FALSE                        /* No legal M2 word found, return F. */

/*-----------------------------------------------------------------------*/
