home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 375.lha / m2make_v1.02 / m2make.mod < prev    next >
Text File  |  1990-05-02  |  30KB  |  1,031 lines

  1. MODULE  M2Make;
  2. (*$D-*)
  3.  
  4. FROM    SYSTEM      IMPORT
  5.     ADR,                ADDRESS,        SHORT,              LONG,
  6.     TSIZE;
  7.  
  8. FROM    System      IMPORT
  9.     argc,               argv;
  10.  
  11. FROM    Conversions IMPORT
  12.     ConvStringToNumber, ConvNumberToString;
  13.  
  14. FROM    Strings     IMPORT
  15.     ConcatString,       CompareString,  CopyString,         ExtractSubString,
  16.     LocateSubString,    Relation,       CompareStringCAP,   LocateChar,
  17.     DeleteSubString,    StringLength;
  18.  
  19. FROM    AmigaDOS    IMPORT
  20.     FileHandle,         FileLock,       FileInfoBlock,      FileInfoBlockPtr,
  21.     DateStampRecord,    Open,           Close,              Lock,
  22.     UnLock,             Examine,        AccessRead,         ModeOldFile,
  23.     DateStampPtr,       Read,           ModeNewFile,        Execute;
  24.  
  25. FROM    Memory      IMPORT
  26.     AllocMem,           FreeMem,        MemReqSet,          MemChip,
  27.     MemClear,           MemPublic;
  28.  
  29. FROM    Tasks       IMPORT
  30.     TaskPtr,            FindTask,       SignalSet;
  31.  
  32. FROM    AmigaDOSProcess IMPORT
  33.     ProcessPtr;
  34.  
  35. IMPORT  TermInOut,
  36.         InOut;
  37.  
  38. CONST
  39.     FileNameSize        =25;
  40.     BufferSize          =500;
  41.     Null                =CHAR( 0 );
  42.     IndentSize          =6;
  43.  
  44. TYPE
  45.     ReadBuffer          =ARRAY[ 0..BufferSize ] OF CHAR;
  46.     ReadBufferPtr       =POINTER TO ReadBuffer;
  47.  
  48.     FileName            =ARRAY[ 0..FileNameSize ] OF CHAR;
  49.     FileNamePtr         =POINTER TO FileName;
  50.  
  51.     UserFile            =RECORD
  52.                             ufDate          :DateStampRecord;
  53.                             ufName          :FileName;
  54.                             ufHandle        :FileHandle;
  55.                             ufDef,
  56.                             ufFROM,
  57.                             ufIMPORT,
  58.                             ufScanned,
  59.                             ufStamped,
  60.                             ufMade,
  61.                             ufUpdated       :BOOLEAN;
  62.                             ufLinePtr,
  63.                             ufBufPtr        :INTEGER;
  64.                             ufLine,
  65.                             ufBuffer        :ReadBufferPtr;
  66.  
  67.                          END;
  68.     UserFilePtr         =POINTER TO UserFile;
  69.     UserFileArray       =ARRAY[ 0..0 ] OF UserFile;
  70.     UserFileArrayPtr    =POINTER TO UserFileArray;
  71.  
  72.     LibName             =FileName;
  73.     LibNamePtr          =POINTER TO LibName;
  74.     LibFileArray        =ARRAY[ 0..0 ] OF LibName;
  75.     LibFileArrayPtr     =POINTER TO LibFileArray;
  76.  
  77.     RunTypes            =(  Initial,
  78.                             Batch,
  79.                             Immediate,
  80.                             Xecute,
  81.                             Show
  82.                          );
  83.  
  84. VAR
  85.     IndentChar      :ARRAY[ 0..IndentSize ] OF CHAR;
  86.     ThisTask        :TaskPtr;
  87.     UserFiles       :UserFileArrayPtr;
  88.     LibFiles        :LibFileArrayPtr;
  89.     ModUpdated,
  90.     DefUpdated,
  91.     UserSize,
  92.     LibSize,
  93.     UserIndex,
  94.     LibIndex        :INTEGER;
  95.     FIB             :FileInfoBlockPtr;
  96.     IndentNum       :INTEGER;
  97.     LnkOutOfSync,
  98.     NewLineLast     :BOOLEAN;
  99.  
  100.     MsgLevel        :INTEGER;
  101.  
  102.     BatchFile,
  103.     ExecuteFile,
  104.     MainFile        :FileName;
  105.  
  106.     ModExt,
  107.     DefExt,
  108.     SymExt,
  109.     LnkExt          :ARRAY[ 0..6 ] OF CHAR;
  110.  
  111.     CompilerName,
  112.     LinkerName      :ARRAY[ 0..15 ] OF CHAR;
  113.  
  114.     RunType         :RunTypes;
  115.  
  116.     CompilerFlags,
  117.     LinkerFlags,
  118.     UpdateFlags     :ARRAY[ 0..8 ] OF CHAR;
  119.  
  120. PROCEDURE Indent;
  121. VAR
  122.     i:INTEGER;
  123. BEGIN
  124.     FOR i := 1 TO IndentNum DO
  125.         TermInOut.WriteString( IndentChar );
  126.     END;
  127. END Indent;
  128.  
  129. PROCEDURE Info ( Message   :ARRAY OF CHAR;
  130.                 NewLine   :BOOLEAN
  131.               );
  132. BEGIN
  133.     IF MsgLevel < 1 THEN
  134.         RETURN;
  135.     END;
  136.     IF ( NewLineLast ) AND ( MsgLevel > 1 ) THEN
  137.         Indent;
  138.         NewLineLast := FALSE;
  139.     END;
  140.     TermInOut.WriteString( Message );
  141.     IF NewLine THEN
  142.         TermInOut.WriteLn;
  143.         NewLineLast := TRUE;
  144.     END;
  145. END Info;
  146.  
  147. PROCEDURE Msg ( Message   :ARRAY OF CHAR;
  148.                 NewLine   :BOOLEAN
  149.               );
  150. BEGIN
  151.     IF MsgLevel < 2 THEN
  152.         RETURN;
  153.     END;
  154.     IF NewLineLast THEN
  155.         Indent;
  156.         NewLineLast := FALSE;
  157.     END;
  158.     TermInOut.WriteString( Message );
  159.     IF NewLine THEN
  160.         TermInOut.WriteLn;
  161.         NewLineLast := TRUE;
  162.     END;
  163. END Msg;
  164.  
  165. PROCEDURE DebugMsg ( Message   :ARRAY OF CHAR;
  166.                      NewLine   :BOOLEAN
  167.                    );
  168. BEGIN
  169.     IF MsgLevel < 3 THEN
  170.         RETURN;
  171.     END;
  172.     IF NewLineLast THEN
  173.         Indent;
  174.         NewLineLast := FALSE;
  175.     END;
  176.     TermInOut.WriteString( Message );
  177.     IF NewLine THEN
  178.         TermInOut.WriteLn;
  179.         NewLineLast := TRUE;
  180.     END;
  181. END DebugMsg;
  182.  
  183. PROCEDURE Free ( VAR Base    :ADDRESS;
  184.                      Size    :CARDINAL
  185.                );
  186. BEGIN
  187.     FreeMem( Base , LONG( Size ) );
  188.     Base := NIL;
  189. END Free;
  190.  
  191. PROCEDURE Stop ( Message:ARRAY OF CHAR );
  192. VAR
  193.     i   :INTEGER;
  194. BEGIN
  195.     InOut.CloseOutput;
  196.     IndentNum := 0;
  197.     TermInOut.WriteString( Message ); TermInOut.WriteLn;
  198.     IF FIB # NIL THEN
  199.         Free( FIB , TSIZE( FileInfoBlock ) );
  200.     END;
  201.     IF LibFiles # NIL THEN
  202.         DebugMsg( 'Library files found' , TRUE );
  203.         FOR i := 0 TO LibIndex DO
  204.             DebugMsg( LibFiles^[ i ] , TRUE );
  205.         END;
  206.         DebugMsg( '' , TRUE );
  207.         Free( LibFiles , TSIZE( LibFileArray )*LibSize*4 );
  208.     END;
  209.     IF UserFiles # NIL THEN
  210.         DebugMsg( 'User files found' , TRUE );
  211.         FOR i := 0 TO UserIndex DO
  212.             WITH UserFiles^[ i ] DO
  213.                 DebugMsg( ufName , TRUE );
  214.                 IF ufHandle # NIL THEN
  215.                     Close( ufHandle );
  216.                 END;
  217.                 IF ufLine # NIL THEN
  218.                     Free( ufLine , TSIZE( ReadBuffer ) );
  219.                 END;
  220.                 IF ufBuffer # NIL THEN
  221.                     Free( ufBuffer , TSIZE( ReadBuffer ) );
  222.                 END;
  223.             END;
  224.         END;
  225.         DebugMsg( '' , TRUE );
  226.         Free( UserFiles , TSIZE( UserFileArray )*UserSize*4 );
  227.     END;
  228.     HALT;
  229. END Stop;
  230.  
  231. PROCEDURE CheckAbort;
  232. BEGIN
  233.     WITH ThisTask^ DO
  234.         IF ( 12 IN tcSigRecvd ) THEN
  235.             Stop( 'M2Make - canceled' );
  236.         END;
  237.     END;
  238. END CheckAbort;
  239.  
  240. PROCEDURE Updating( Update:CHAR ):BOOLEAN;
  241. BEGIN
  242.     RETURN( LocateChar( UpdateFlags , Update , 0 , SIZE( UpdateFlags ) ) # -1 );
  243. END Updating;
  244.  
  245. PROCEDURE Alloc ( VAR Base    :ADDRESS;
  246.                       Size    :CARDINAL;
  247.                       Type    :CARDINAL
  248.                 );
  249. VAR
  250.     type    :MemReqSet;
  251. BEGIN
  252.     type     := MemReqSet{ MemClear };
  253.     INCL( type , Type );
  254.     Base     := AllocMem( LONG( Size ) , type );
  255.     IF Base = NIL THEN
  256.         Stop( 'Abort - Out of memory' );
  257.     END;
  258. END Alloc;
  259.  
  260. PROCEDURE FindUserFile( FileName:ARRAY OF CHAR ):INTEGER;
  261. VAR
  262.     i:INTEGER;
  263. BEGIN
  264.     IF UserIndex = -1 THEN
  265.         RETURN( -1 );
  266.     END;
  267.     FOR i := 0 TO UserIndex DO
  268.         WITH UserFiles^[ i ] DO
  269.             IF CompareString( FileName , ufName ) = equal THEN
  270.                 RETURN( i );
  271.             END;
  272.         END;
  273.     END;
  274.     RETURN( -1 );
  275. END FindUserFile;
  276.  
  277. PROCEDURE FindLibFile( FileName:ARRAY OF CHAR ):INTEGER;
  278. VAR
  279.     i:INTEGER;
  280. BEGIN
  281.     IF LibIndex = -1 THEN
  282.         RETURN( -1 );
  283.     END;
  284.     FOR i := 0 TO LibIndex DO
  285.         IF CompareString( FileName , LibFiles^[ i ] ) = equal THEN
  286.             RETURN( i );
  287.         END;
  288.     END;
  289.     RETURN( -1 );
  290. END FindLibFile;
  291.  
  292. PROCEDURE AddFile( FileName:ARRAY OF CHAR );
  293. BEGIN
  294.     INC( UserIndex );
  295.     IF UserIndex > UserSize*4 THEN
  296.         Stop( 'Abort - User file buffer overflow' );
  297.     END;
  298.     WITH UserFiles^[ UserIndex ] DO
  299.         CopyString( ufName , FileName );
  300.         ufDef     := FALSE;
  301.         ufStamped := FALSE;
  302.         ufScanned := FALSE;
  303.         ufUpdated := FALSE;
  304.         ufMade    := FALSE;
  305.         ufFROM    := FALSE;
  306.         ufIMPORT  := FALSE;
  307.         WITH ufDate DO
  308.             dsDays := 0D;
  309.         END;
  310.     END;
  311. END AddFile;
  312.  
  313. PROCEDURE AddLibFile( FileName:ARRAY OF CHAR );
  314. BEGIN
  315.     INC( LibIndex );
  316.     IF LibIndex > LibSize*4 THEN
  317.         Stop( 'Abort - Library file buffer overflow' );
  318.     END;
  319.     CopyString( LibFiles^[ LibIndex ] , FileName );
  320. END AddLibFile;
  321.  
  322. PROCEDURE GetStamp( FileName:ARRAY OF CHAR; Add:BOOLEAN ):DateStampPtr;
  323. VAR
  324.     i       :INTEGER;
  325.     lock    :FileLock;
  326. BEGIN
  327.     i := FindUserFile( FileName );
  328.     IF i # -1 THEN
  329.         WITH UserFiles^[ i ] DO
  330.             IF NOT ufStamped THEN
  331.                 lock := Lock( ADR( FileName ) , AccessRead );
  332.                 IF lock = NIL THEN
  333.                     ufStamped := TRUE;
  334.                     RETURN( DateStampPtr( ADR( ufDate ) ) );
  335.                 END;
  336.                 IF Examine( lock , FIB^ ) THEN
  337.                     ufStamped := TRUE;
  338.                     ufDate    := FIB^.fibDate;
  339.                     UnLock( lock );
  340.                     RETURN( DateStampPtr( ADR( ufDate ) ) );
  341.                 ELSE
  342.                     Info( FileName , TRUE );
  343.                     Stop( 'Abort - Examine failed ' );
  344.                 END;
  345.             ELSE
  346.                 RETURN( DateStampPtr( ADR( ufDate ) ) );
  347.             END;
  348.         END;
  349.     END;
  350.     IF Add THEN
  351.         AddFile( FileName );
  352.     END;
  353.     lock := Lock( ADR( FileName ) , AccessRead );
  354.     IF lock = NIL THEN
  355.         WITH UserFiles^[ UserIndex ] DO
  356.             ufStamped := TRUE;
  357.             RETURN( DateStampPtr( ADR( ufDate ) ) );
  358.         END;
  359.     END;
  360.     IF Examine( lock , FIB^ ) THEN
  361.         UnLock( lock );
  362.         IF Add THEN
  363.             WITH UserFiles^[ UserIndex ] DO
  364.                 ufStamped := TRUE;
  365.                 ufDate    := FIB^.fibDate;
  366.             END;
  367.         END;
  368.         RETURN( DateStampPtr( ADR( FIB^.fibDate ) ) );
  369.     ELSE
  370.         Info( FileName , TRUE );
  371.         Stop( 'Abort - Examine failed ' );
  372.     END;
  373. END GetStamp;
  374.  
  375. PROCEDURE FormFileName( Into,Name,Ext:ARRAY OF CHAR );
  376. BEGIN
  377.     CopyString( Into , Name );
  378.     ConcatString( Into , '.' );
  379.     ConcatString( Into , Ext );
  380. END FormFileName;
  381.  
  382. PROCEDURE OutOfSync( Name1,Name2:ARRAY OF CHAR; Add1,Add2:BOOLEAN ):BOOLEAN;
  383. VAR
  384.     date1,date2:DateStampPtr;
  385. BEGIN
  386.     Msg( '  Check sync: ' , FALSE );
  387.     Msg( Name1 , FALSE );Msg( ',',FALSE ); Msg( Name2 , FALSE );
  388.     date1 := GetStamp( Name1 , Add1 );
  389.     date2 := GetStamp( Name2 , Add2 );
  390.     IF ( date1^.dsDays > date2^.dsDays )
  391.        OR
  392.        ( ( date1^.dsDays = date2^.dsDays )
  393.          AND
  394.          ( date1^.dsMinute > date2^.dsMinute )
  395.        )
  396.        OR
  397.        ( ( date1^.dsDays = date2^.dsDays )
  398.          AND
  399.          ( date1^.dsMinute = date2^.dsMinute )
  400.          AND
  401.          ( date1^.dsTick > date2^.dsTick )
  402.        ) THEN
  403.         Msg( ' - Out of sync: ' , TRUE );
  404.         RETURN( TRUE );
  405.     ELSE
  406.         Msg( '' , TRUE );
  407.         RETURN( FALSE );
  408.     END;
  409. END OutOfSync;
  410.  
  411. PROCEDURE Whitespace( c:CHAR ):BOOLEAN;
  412. BEGIN
  413.     RETURN( c <= ' ' );
  414. END Whitespace;
  415.  
  416. PROCEDURE Terminator( c:CHAR ):BOOLEAN;
  417. BEGIN
  418.     RETURN( ( c <= ' ' ) OR ( c = ',' ) OR ( c = ';' ) OR ( c = '.' ) );
  419. END Terminator;
  420.  
  421. PROCEDURE GetNextChar( Index:INTEGER ):CHAR;
  422. VAR
  423.     c:CHAR;
  424. BEGIN
  425.     WITH UserFiles^[ Index ] DO
  426.         IF ufBufPtr = -1 THEN
  427.             IF Read( ufHandle , ufBuffer ,
  428.                      LONG( TSIZE( ReadBuffer ) ) ) = 0D THEN
  429.             END;
  430.         END;
  431.         INC( ufBufPtr );
  432.         c := ufBuffer^[ ufBufPtr ];
  433.         IF ufBufPtr = BufferSize THEN
  434.             ufBufPtr := -1;
  435.         END;
  436.     END;
  437.     RETURN( c );
  438. END GetNextChar;
  439.  
  440. PROCEDURE GetNextLine( Index:INTEGER );
  441. VAR
  442.     i:INTEGER;
  443.     char,last:CHAR;
  444.     comment:INTEGER;
  445.     done:BOOLEAN;
  446. BEGIN
  447.     WITH UserFiles^[ Index ] DO
  448.         i := 0;
  449.         char := ' ';
  450.         last := ' ';
  451.         comment := 0;
  452.         done := FALSE;
  453.         WHILE NOT ( done ) DO
  454.             CheckAbort;
  455.             ufLine^[ i ] := Null;
  456.             last := char;
  457.             char := GetNextChar( Index );
  458.             IF ( char = '*' ) AND ( last = '(' ) THEN
  459.                 INC( comment );
  460.             END;
  461.             IF ( char = ')' ) AND ( last = '*' ) THEN
  462.                 DEC( comment );
  463.                 IF comment = 0 THEN
  464.                     char := ' ';
  465.                     last := ' ';
  466.                     DEC( i );
  467.                     ufLine^[ i ] := ' ';
  468.                 END;
  469.             END;
  470.             ufLine^[ i ] := char;
  471.             IF ( comment = 0 ) AND ( ( char = ';' ) OR ( char = '.' ) ) THEN
  472.                 INC( i );
  473.                 done := TRUE;
  474.             ELSIF ( ( Whitespace( char ) ) AND ( Whitespace( last ) ) )
  475.                   OR
  476.                   ( comment > 0 ) THEN
  477.             ELSE
  478.                 INC( i );
  479.                 IF i > BufferSize THEN
  480.                     done := TRUE;
  481.                 END;
  482.             END;
  483.         END;
  484.         ufLine^[ i ] := Null;
  485.         ufLinePtr := 0;
  486.         DebugMsg('line=',FALSE);DebugMsg(ufLine^,TRUE);
  487.     END;
  488. END GetNextLine;
  489.  
  490. PROCEDURE GetNextWord( Index:INTEGER; NextWord:ARRAY OF CHAR ):BOOLEAN;
  491. VAR
  492.     c:CHAR;
  493.     i:INTEGER;
  494.     done:BOOLEAN;
  495. BEGIN
  496.     WITH UserFiles^[ Index ] DO
  497.         IF ufLinePtr = -1 THEN
  498.             GetNextLine( Index );
  499.         END;
  500.         i := -1;
  501.         WHILE Terminator( ufLine^[ ufLinePtr ] ) DO
  502.             INC( ufLinePtr );
  503.         END;
  504.         done := FALSE;
  505.         WHILE NOT ( done ) DO
  506.             CheckAbort;
  507.             c := ufLine^[ ufLinePtr ];
  508.             INC( ufLinePtr );
  509.             INC( i );
  510.             NextWord[ i ] := c;
  511.             done := Terminator( c );
  512.         END;
  513.         IF c = ';' THEN
  514.             ufLinePtr := -1;
  515.         END;
  516.         NextWord[ i ] := Null;
  517.     END;
  518.     RETURN( FALSE );
  519. END GetNextWord;
  520.  
  521. PROCEDURE LibraryFile( FileName:ARRAY OF CHAR ):BOOLEAN;
  522. VAR
  523.     lock:FileLock;
  524.     name:ARRAY[ 0..25 ] OF CHAR;
  525. BEGIN
  526.     DebugMsg(FileName,FALSE);
  527.     IF FindLibFile( FileName ) = -1 THEN
  528.         FormFileName( name , FileName , DefExt );
  529.         lock := Lock( ADR( name ) , AccessRead );
  530.         IF lock # NIL THEN
  531.             UnLock( lock );
  532.             DebugMsg(' user file',TRUE);
  533.             RETURN( FALSE );
  534.         ELSE
  535.             AddLibFile( FileName );
  536.             DebugMsg(' library file',TRUE);
  537.             RETURN( TRUE );
  538.         END;
  539.     ELSE
  540.         DebugMsg(' library file',TRUE);
  541.         RETURN( TRUE );
  542.     END;
  543. END LibraryFile;
  544.  
  545. PROCEDURE GetNextImport( Index:INTEGER; ImportName:ARRAY OF CHAR ):BOOLEAN;
  546. VAR
  547.     done,eol,gotname:BOOLEAN;
  548.     nextword:FileName;
  549. BEGIN
  550.     done := FALSE;
  551.     WHILE NOT ( done ) DO
  552.         CheckAbort;
  553.         gotname := FALSE;
  554.         WITH UserFiles^[ Index ] DO
  555.             eol := GetNextWord( Index , nextword );
  556.             DebugMsg('word=' , FALSE );DebugMsg( nextword , TRUE );
  557.             IF ( CompareString( nextword , 'CONST' ) = equal ) THEN
  558.                 done := TRUE;
  559.             ELSIF ( CompareString( nextword , 'TYPE' ) = equal ) THEN
  560.                 done := TRUE;
  561.             ELSIF ( CompareString( nextword , 'VAR' ) = equal ) THEN
  562.                 done := TRUE;
  563.             ELSIF ( CompareString( nextword , 'PROCEDURE' ) = equal ) THEN
  564.                 done := TRUE;
  565.             ELSIF ( CompareString( nextword , 'BEGIN' ) = equal ) THEN
  566.                 done := TRUE;
  567.             ELSIF ( CompareString( nextword , 'END' ) = equal ) THEN
  568.                 done := TRUE;
  569.             ELSIF CompareString( nextword , 'FROM' ) = equal THEN
  570.                 ufFROM := TRUE;
  571.                 ufIMPORT := FALSE;
  572.             ELSIF ( CompareString( nextword , 'IMPORT' ) = equal ) THEN
  573.                 IF ufFROM THEN
  574.                     ufFROM := FALSE;
  575.                 ELSE
  576.                     ufIMPORT := TRUE;
  577.                 END;
  578.             ELSIF ufFROM THEN
  579.                 CopyString( ImportName , nextword );
  580.                 gotname := TRUE;
  581.             ELSIF ufIMPORT THEN
  582.                  CopyString( ImportName , nextword );
  583.                  gotname := TRUE;
  584.             END;
  585.             IF gotname THEN
  586.                 DebugMsg('gotname',TRUE);
  587.                 IF NOT ( LibraryFile( ImportName ) ) THEN
  588.                     done := TRUE;
  589.                 END;
  590.             END;
  591.         END;
  592.     END;
  593.     RETURN( gotname );
  594. END GetNextImport;
  595.  
  596. PROCEDURE DefModule( Ext:ARRAY OF CHAR ):BOOLEAN;
  597. BEGIN
  598.     RETURN( CompareStringCAP( Ext , DefExt ) = equal );
  599. END DefModule;
  600.  
  601. PROCEDURE Compile( Index:INTEGER );
  602. VAR
  603.     cmd:ARRAY[ 0..100 ] OF CHAR;
  604.     stdin,stdout:FileHandle;
  605. BEGIN
  606.     WITH UserFiles^[ Index ] DO
  607.         cmd[ 0 ] := Null;
  608.         IF RunType # Batch THEN
  609.             ConcatString( cmd , CompilerName );
  610.             ConcatString( cmd , ' ' );
  611.         END;
  612.         ConcatString( cmd , ufName );
  613.         ConcatString( cmd , ' ' );
  614.         ConcatString( cmd , CompilerFlags );
  615.         IF ( RunType = Batch ) OR ( RunType = Xecute ) THEN
  616.             InOut.WriteString( cmd );
  617.             InOut.WriteLn;
  618.         ELSIF RunType = Immediate THEN
  619.             stdin := NIL;
  620.             stdout := Open( ADR( 'CON:0/0/320/200/Compile' ) , ModeNewFile );
  621.             IF Execute( ADR( cmd ) , stdin , stdout ) THEN
  622.             END;
  623.             Close( stdout );
  624.             ufStamped := FALSE;
  625.         ELSIF RunType = Show THEN
  626.             Info( 'Compile:' , FALSE );Info( ufName , TRUE );
  627.         END;
  628.     END;
  629. END Compile;
  630.  
  631. PROCEDURE MakeFile( Index:INTEGER );
  632. VAR
  633.     made:BOOLEAN;
  634. BEGIN
  635.     WITH UserFiles^[ Index ] DO
  636.         ufMade := TRUE;
  637.         made := FALSE;
  638.         IF Updating( 'a' ) THEN
  639.             made := TRUE;
  640.         ELSIF ( Updating( 'm' ) ) AND NOT ( ufDef ) THEN
  641.             made := TRUE;
  642.         ELSIF ( Updating( 'd' ) ) AND ( ufDef ) THEN
  643.             made := TRUE;
  644.         END;
  645.         IF made THEN
  646.             IF ufDef THEN
  647.                 INC( DefUpdated );
  648.             ELSE
  649.                 INC( ModUpdated );
  650.             END;
  651.             Compile( Index );
  652.         END;
  653.     END;
  654. END MakeFile;
  655.  
  656. PROCEDURE NeedsUpdate( Name,Ext,Bin:ARRAY OF CHAR ):BOOLEAN;
  657. VAR
  658.     update,make,baseoutofsync,defoutofsync,impoutofsync:BOOLEAN;
  659.     basename,binname,defname,defimport,import:FileName;
  660.     basehandle:FileHandle;
  661.     i:INTEGER;
  662. BEGIN
  663.     CheckAbort;
  664.     FormFileName( basename , Name , Ext );
  665.     i := FindUserFile( basename );
  666.     IF i # -1 THEN
  667.         WITH UserFiles^[ i ] DO
  668.             RETURN( ufUpdated );
  669.         END;
  670.     END;
  671.     INC( IndentNum );
  672.     AddFile( basename );
  673.     i := UserIndex;
  674.     basehandle := Open( ADR( basename ) , ModeOldFile );
  675.     IF basehandle = NIL THEN
  676.         IF ( CompareString( Name , MainFile ) = equal ) AND
  677.            ( DefModule( Ext ) ) THEN
  678.             RETURN( FALSE );
  679.         ELSE
  680.             Info( basename , TRUE );
  681.             Stop( 'Abort - Missing source file' );
  682.         END;
  683.     END;
  684.     Msg( 'Scanning:' , FALSE );Msg( basename , TRUE );
  685.     WITH UserFiles^[ i ] DO
  686.         ufLinePtr := -1;
  687.         ufBufPtr := -1;
  688.         ufHandle   := basehandle;
  689.         Alloc( ufLine , TSIZE( ReadBuffer ) , MemChip );
  690.         Alloc( ufBuffer , TSIZE( ReadBuffer ) , MemChip );
  691.     END;
  692.     FormFileName( binname , Name , Bin );
  693.     baseoutofsync := OutOfSync( basename , binname , TRUE , TRUE );
  694.     FormFileName( defname , Name , DefExt );
  695.     defoutofsync := ( NOT ( DefModule( Ext ) ) ) AND
  696.                     ( NeedsUpdate( Name , DefExt , SymExt ) );
  697.     impoutofsync := FALSE;
  698.     WHILE GetNextImport( i , import ) DO
  699.         FormFileName( defimport , import , DefExt );
  700.         Msg( basename , FALSE );Msg( ' imports:' , FALSE ); Msg( import , TRUE );
  701.         impoutofsync := ( NeedsUpdate( import , ModExt , LnkExt ) )
  702.                         OR
  703.                         ( OutOfSync( defimport , binname , TRUE , TRUE ) )
  704.                         OR
  705.                         ( impoutofsync );
  706.  
  707.     END;
  708.     Close( basehandle );
  709.     make := ( baseoutofsync ) OR ( defoutofsync ) OR
  710.             ( impoutofsync ) OR ( Updating( 'a' ) );
  711.     update := ( DefModule( Ext ) ) AND ( make );
  712.     IF make THEN
  713.         IF DefModule( Ext ) THEN
  714.             UserFiles^[ i ].ufDef := TRUE;
  715.             UserFiles^[ i ].ufDate.dsDays := MAX( LONGINT );
  716.         END;
  717.         MakeFile( i );
  718.     END;
  719.     IF NOT ( DefModule( Ext ) ) THEN
  720.         LnkOutOfSync := ( OutOfSync( binname , MainFile , TRUE , TRUE ) )
  721.                         OR
  722.                         ( LnkOutOfSync );
  723.     END;
  724.     WITH UserFiles^[ i ] DO
  725.         Free( ufLine , TSIZE( ReadBuffer ) );
  726.         Free( ufBuffer , TSIZE( ReadBuffer ) );
  727.         ufHandle := NIL;
  728.         ufScanned := TRUE;
  729.         ufUpdated := update;
  730.         ufMade := make;
  731.     END;
  732.     DEC( IndentNum );
  733.     RETURN( update );
  734. END NeedsUpdate;
  735.  
  736. PROCEDURE ProcessFlag( Flag:ARRAY OF CHAR; Parm:ARRAY OF CHAR ):BOOLEAN;
  737. VAR
  738.     size:LONGINT;
  739. BEGIN
  740.     IF HIGH( Parm ) = 0 THEN
  741.         IF CompareString( Flag , 'q' ) = equal THEN
  742.             MsgLevel := 0;
  743.         ELSIF CompareString( Flag , 't' ) = equal THEN
  744.             MsgLevel := 1;
  745.         ELSIF CompareString( Flag , 'v' ) = equal THEN
  746.             MsgLevel := 2;
  747.         ELSIF CompareString( Flag , 'z' ) = equal THEN
  748.             MsgLevel := 3;
  749.         ELSIF CompareString( Flag , 'i' ) = equal THEN
  750.             RunType := Immediate;
  751.         ELSIF CompareString( Flag , 's' ) = equal THEN
  752.             RunType := Show;
  753.         ELSE
  754.             RETURN( FALSE );
  755.         END;
  756.         RETURN( TRUE );
  757.     ELSE
  758.         IF ( CompareString( Flag , 'b' ) = equal ) AND ( RunType = Initial ) THEN
  759.             RunType := Batch;
  760.             CopyString( BatchFile , Parm );
  761.         ELSIF ( CompareString( Flag , 'x' ) = equal ) AND ( RunType = Initial ) THEN
  762.             RunType := Xecute;
  763.             CopyString( ExecuteFile , Parm );
  764.         ELSIF CompareString( Flag , 'cn' ) = equal THEN
  765.             CopyString( CompilerName , Parm );
  766.         ELSIF CompareString( Flag , 'ln' ) = equal THEN
  767.             CopyString( LinkerName , Parm );
  768.         ELSIF CompareString( Flag , 'cf' ) = equal THEN
  769.             CopyString( CompilerFlags , Parm );
  770.         ELSIF CompareString( Flag , 'lf' ) = equal THEN
  771.             CopyString( LinkerFlags , Parm );
  772.         ELSIF CompareString( Flag , 'm' ) = equal THEN
  773.             CopyString( ModExt , Parm );
  774.         ELSIF CompareString( Flag , 'd' ) = equal THEN
  775.             CopyString( DefExt , Parm );
  776.         ELSIF CompareString( Flag , 's' ) = equal THEN
  777.             CopyString( SymExt , Parm );
  778.         ELSIF CompareString( Flag , 'l' ) = equal THEN
  779.             CopyString( LnkExt , Parm );
  780.         ELSIF CompareString( Flag , 'u' ) = equal THEN
  781.             CopyString( UpdateFlags , Parm );
  782.         ELSIF CompareString( Flag , 'us' ) = equal THEN
  783.             IF ConvStringToNumber( Parm , size , FALSE , 10 ) THEN
  784.                 UserSize := SHORT( size );
  785.             ELSE
  786.                 UserSize := -1;
  787.             END;
  788.         ELSIF CompareString( Flag , 'ls' ) = equal THEN
  789.             IF ConvStringToNumber( Parm , size , FALSE , 10 ) THEN
  790.                 LibSize := SHORT( size );
  791.             ELSE
  792.                 LibSize := -1;
  793.             END;
  794.         END;
  795.         RETURN( TRUE );
  796.     END;
  797. END ProcessFlag;
  798.  
  799. PROCEDURE CheckParms;
  800. VAR
  801.     num:ARRAY[0..10] OF CHAR;
  802. BEGIN
  803.     IF ( UserSize = -1 ) OR ( LibSize = -1 ) THEN
  804.         Stop( 'File number invalid' );
  805.     END;
  806.     IndentNum := 0;
  807.  
  808.     ConvNumberToString( num , LONG( UserSize ) , FALSE , 10 , 3 , ' ');
  809.     Info( 'User file size=' , FALSE );Info( num , TRUE );
  810.     ConvNumberToString( num , LONG( LibSize ) , FALSE , 10 , 3 , ' ');
  811.     Info( 'Lib file size=' , FALSE );Info( num , TRUE );
  812.  
  813.     Info( 'Message level= ' , FALSE );
  814.     CASE MsgLevel OF
  815.         0:
  816.             |
  817.         1:
  818.             Info( 'Terse' , TRUE );
  819.             |
  820.         2:
  821.             Info( 'Verbose' , TRUE );
  822.             |
  823.         3:
  824.             Info( 'Debug' , TRUE );
  825.             |
  826.     END;
  827.     IF ( Updating( 'n' ) ) OR ( RunType = Initial ) THEN
  828.         RunType := Show;
  829.     END;
  830.     CASE RunType OF
  831.         Initial:
  832.             Info( 'Mode=Batch' , TRUE );
  833.             Info( 'Batch file=' , FALSE );Info( BatchFile , TRUE );
  834.             RunType := Batch;
  835.             InOut.OpenOutputFile( BatchFile );
  836.             |
  837.         Immediate:
  838.             Info( 'Mode=Immediate' , TRUE );
  839.             |
  840.         Xecute:
  841.             Info( 'Mode=Execute' , TRUE );
  842.             Info( 'Execute file=' , FALSE );Info( ExecuteFile , TRUE );
  843.             InOut.OpenOutputFile( ExecuteFile );
  844.             |
  845.         Batch:
  846.             Info( 'Mode=Batch' , TRUE );
  847.             Info( 'Batch file=' , FALSE );Info( BatchFile , TRUE );
  848.             InOut.OpenOutputFile( BatchFile );
  849.             |
  850.         Show:
  851.             Info( 'Mode=Show' , TRUE );
  852.             |
  853.     END;
  854.  
  855.     Info( 'Updating: ' , TRUE );
  856.     IF Updating( 'n' ) THEN
  857.         Info( '   No modules ' , TRUE );
  858.     ELSIF Updating( 'a' ) THEN
  859.         Info( '   All modules ' , TRUE );
  860.     ELSE
  861.         IF Updating( 'm' ) THEN
  862.             Info( '   Code modules ' , TRUE );
  863.         END;
  864.         IF Updating( 'd' ) THEN
  865.             Info( '   Definition modules ' , TRUE );
  866.         END;
  867.         IF Updating( 'l' ) THEN
  868.             Info( '   With re-link ' , TRUE );
  869.         END;
  870.     END;
  871.     Info( 'Mod ext=' , FALSE );Info( ModExt , FALSE );
  872.     Info( '  Def ext=' , FALSE );Info( DefExt , FALSE );
  873.     Info( '  Sym ext=' , FALSE );Info( SymExt , FALSE );
  874.     Info( '  Lnk ext=' , FALSE );Info( LnkExt , TRUE );
  875.  
  876.     Info( 'Compiler=' , FALSE );Info( CompilerName , TRUE );
  877.     Info( 'Compiler Flags=' , FALSE );Info( CompilerFlags , TRUE );
  878.     Info( 'Linker=' , FALSE );Info( LinkerName , TRUE );
  879.     Info( 'Linker Flags=' , FALSE );Info( LinkerFlags , TRUE );
  880. END CheckParms;
  881.  
  882. PROCEDURE ProcessParms;
  883. CONST
  884.     DefaultUpdateFlags          ='cdm';
  885.     DefaultModExt               ='mod';
  886.     DefaultDefExt               ='def';
  887.     DefaultSymExt               ='sbm';
  888.     DefaultLnkExt               ='obm';
  889.     Quote                       ="'";
  890. VAR
  891.     i,l:CARDINAL;
  892.     lastsingle,quote:BOOLEAN;
  893.     flag:ARRAY[ 0..1 ] OF CHAR;
  894.     parm:ARRAY[ 0..50 ] OF CHAR;
  895. BEGIN
  896.     IF argc <2 THEN
  897.         Stop( 'Too few parameters' );
  898.     END;
  899.     UserSize := 25;
  900.     LibSize  := 25;
  901.     CopyString( MainFile , argv^[ 1 ]^ );
  902.     CopyString( UpdateFlags , DefaultUpdateFlags );
  903.     CopyString( ModExt , DefaultModExt );
  904.     CopyString( DefExt , DefaultDefExt );
  905.     CopyString( SymExt , DefaultSymExt );
  906.     CopyString( LnkExt , DefaultLnkExt );
  907.     RunType := Initial;
  908.     CopyString( CompilerName , 'm2' );
  909.     CopyString( LinkerName , 'm2lk' );
  910.  
  911.     i := 2;
  912.     lastsingle := TRUE;
  913.     quote      := FALSE;
  914.  
  915.     WHILE i <= argc-1 DO
  916.         IF ( argv^[ i ]^[ 0 ] = '<' ) OR ( argv^[ i ]^[ 0 ] = '>' ) THEN
  917.         ELSIF ( argv^[ i ]^[ 0 ] = '-' ) AND ( lastsingle ) AND NOT ( quote ) THEN
  918.             flag[ 0 ] := argv^[ i ]^[ 1 ];
  919.             flag[ 1 ] := argv^[ i ]^[ 2 ];
  920.             lastsingle := ProcessFlag( flag , '' );
  921.         ELSIF quote THEN
  922.             ConcatString( parm , ' ' );
  923.             ConcatString( parm , argv^[ i ]^ );
  924.             quote := LocateChar( argv^[ i ]^ , Quote , 0 , 50 ) = -1;
  925.             IF NOT quote THEN
  926.                 DeleteSubString( parm , 0 , 1 );
  927.                 l := StringLength( parm );
  928.                 DeleteSubString( parm , l-1 , 1 );
  929.                 lastsingle := ProcessFlag( flag , parm );
  930.             END;
  931.         ELSIF ( argv^[ i ]^[ 0 ] # '-' ) AND NOT ( lastsingle ) THEN
  932.             CopyString( parm , argv^[ i ]^ );
  933.             IF argv^[ i ]^[ 0 ] # Quote THEN
  934.                 lastsingle := ProcessFlag( flag , parm );
  935.             ELSE
  936.                 l := StringLength( parm );
  937.                 IF parm[ l-1 ] # Quote THEN
  938.                     quote := TRUE;
  939.                 ELSE
  940.                     DeleteSubString( parm , 0 , 1 );
  941.                     DeleteSubString( parm , l-1 , 1 );
  942.                     lastsingle := ProcessFlag( flag , parm );
  943.                     quote := FALSE;
  944.                 END;
  945.             END;
  946.         ELSE
  947.             Stop( 'Parameters incorrect' );
  948.         END;
  949.         INC( i );
  950.     END;
  951.     CheckParms;
  952. END ProcessParms;
  953.  
  954. PROCEDURE Link;
  955. VAR
  956.     num:ARRAY[ 0..10 ] OF CHAR;
  957.     cmd:ARRAY[ 0..100 ] OF CHAR;
  958.     stdin,stdout:FileHandle;
  959. BEGIN
  960.     IF ModUpdated + DefUpdated > 0 THEN
  961.         ConvNumberToString( num , LONG( ModUpdated ) , FALSE , 10 , 3 , ' ');
  962.         Info( num , FALSE );
  963.         Info( ' MOD files require re-compilation' , TRUE );
  964.         ConvNumberToString( num , LONG( DefUpdated ) , FALSE , 10 , 3 , ' ');
  965.         Info( num , FALSE );
  966.         Info( ' DEF files require re-compilation' , TRUE );
  967.     ELSE
  968.         Info( 'No re-compiles necessary' , TRUE );
  969.     END;
  970.     IF LnkOutOfSync THEN
  971.         Info( 'Re-link of ' , FALSE );
  972.         Info( MainFile , FALSE );
  973.         Info( ' necessary' , TRUE );
  974.     ELSE
  975.         Info( 'No re-link necessary' , TRUE );
  976.     END;
  977.     IF ( Updating( 'l' ) )
  978.        AND
  979.        ( ( ModUpdated+DefUpdated > 0 ) OR ( LnkOutOfSync ) )
  980.        AND
  981.        ( RunType # Batch ) THEN
  982.         cmd[ 0 ] := Null;
  983.         ConcatString( cmd , LinkerName );
  984.         ConcatString( cmd , ' ' );
  985.         ConcatString( cmd , MainFile );
  986.         ConcatString( cmd , ' ' );
  987.         ConcatString( cmd , LinkerFlags );
  988.         IF RunType = Xecute THEN
  989.             InOut.WriteString( cmd );
  990.             InOut.WriteLn;
  991.         ELSIF RunType = Immediate THEN
  992.             stdin := NIL;
  993.             stdout := Open( ADR( 'CON:0/0/320/200/Link' ) , ModeNewFile );
  994.             IF Execute( ADR( cmd ) , stdin , stdout ) THEN
  995.             END;
  996.             Close( stdout );
  997.         ELSIF RunType = Show THEN
  998.             Info( 'Linking:' , FALSE );Info( MainFile , TRUE );
  999.         END;
  1000.     END;
  1001. END Link;
  1002.  
  1003. PROCEDURE CopyRight;
  1004. BEGIN
  1005.     Info( 'M2Make ' , FALSE );
  1006.     Info( CHAR( 0A9H ) , FALSE );
  1007.     Info( ' 1990 by Tim Coffey. All Rights Reserved.' , TRUE );
  1008. END CopyRight;
  1009.  
  1010. BEGIN
  1011.     MsgLevel := 1;
  1012.     ThisTask := FindTask( NIL );
  1013.     CopyRight;
  1014.     ProcessParms;
  1015.     CopyString( IndentChar , '          ' );
  1016.     UserIndex   :=  -1;
  1017.     LibIndex    :=  -1;
  1018.     DefUpdated := 0;
  1019.     ModUpdated := 0;
  1020.     LnkOutOfSync := FALSE;
  1021.     Alloc( UserFiles , TSIZE( UserFileArray )*UserSize*4 , MemPublic );
  1022.     Alloc( LibFiles , TSIZE( LibFileArray )*LibSize*4 , MemPublic );
  1023.     Alloc( FIB , TSIZE( FileInfoBlock ) , MemPublic );
  1024.     IndentNum := -1;
  1025.     NewLineLast := TRUE;
  1026.     IF NeedsUpdate( MainFile , ModExt , LnkExt ) THEN
  1027.     END;
  1028.     Link;
  1029.     Stop( 'Done' );
  1030. END M2Make.
  1031.