#include "rules.h"
#include "vars.h"
#include <stdio.h>
#include <libraries/dos.h>

int debug;
long int days, mins, secs;

main( argc, argv )
   int argc;
   char **argv;
{
   FILE *MakeFile;
   int i,j;

   printf("Make V1.0 (c) 1985 by General Overall Design.\n");
   printf("May (only) be distributed free of charge.\n");
   /* General Overall Design
    * P.O. Box 2039
    * W. Lavayette IN 47906
    */
   if( argc > 2 && strcmp(argv[1], "-f")==0 ){       /* make -f file ... */
      MakeFile = fopen( argv[2] , "r" );
      argc -= 2;
      argv += 2;
   } else
      MakeFile = fopen("makefile" , "r");

   if( argc > 1 && strcmp( argv[1], "-d" ) == 0 ){
      debug=1;
      argc--;
      argv++;
      printf("debug on.\n");
   }

   if( MakeFile == NULL ){                  /* open failed  */
      printf("make: can't open makefile\n");
      exit( 1 );
   }
   if ( debug )
      printf("makefile open\n");

   Parse( MakeFile );

   if( debug ){
      printf("Variables:\n");
      for( i=0 ; i < n_Vars ; i++ )
         printf( "%s = '%s'\n", avr_Vars[i].pch_name , avr_Vars[i].string );
      printf("Rules:\n");
      for( i=0 ; i < n_Rules ; i++ ){
         printf( "%s : ", arl_Rules[i].pch_target );
         for( j = 0; j < arl_Rules[i].c_depend; j++ )
            printf("'%s' ", arl_Rules[i].apch_depend[ j ] );
         printf("\n");
         for( j = 0; j < arl_Rules[i].c_action; j++ )
            printf("%s\n", arl_Rules[i].apch_action[j] );
      }
   }

   if( argc == 1 )
      make( arl_Rules[0].pch_target, &days, &mins, &secs );
   else
      while( --argc != 0 )
         make( *++argv, &days, &mins, &secs );

   printf("done.\n");
}

static char *GetLine(), *NextWord(), *malloc();

Parse( fd )
    FILE *fd;
{
    char *pch_Position, *pch_Word, *pch_Target;

    pch_Position = GetLine( fd );
    while( pch_Position ){
        if( debug )
           printf("Parsing:%s\n", pch_Position );
        if( '#' == *pch_Position ){
            pch_Position = GetLine(fd);
            continue;
        }
        pch_Word = pch_Position;
        pch_Position = NextWord( pch_Position );
        if( *pch_Position == '=' ){
            DefineVar( pch_Word, ++ pch_Position );
            pch_Position = GetLine( fd );
        } else {
            pch_Target = pch_Word;
            pch_Word = pch_Position = NextWord( pch_Position );
            pch_Position = NextWord( pch_Position );
            while( pch_Word ){
                 AddDependant( pch_Word, pch_Target );
                 pch_Word = pch_Position;
                 pch_Position = NextWord( pch_Position );
            }
            pch_Position = GetLine( fd );
            while( ' ' == *pch_Position ){
                 AddAction( pch_Position , pch_Target );
                 pch_Position = GetLine( fd );
            }
        }
    }
}

char *
NextWord( pch )
    char *pch;
{
    if( NULL == pch || NULL == *pch )
        return NULL;
    while( *pch && *pch != ' ' && *pch != '\t' && *pch != ',' )
        pch++;
    if( *pch == '\0' )
        return NULL;
    else
        *pch = '\0';
    do
        pch++;
    while ( *pch && (' ' == *pch || '\t' == *pch || ',' == *pch ));
    if(*pch == '\0')
        return NULL;
    else
        return pch;
}

/* states for GetLine */
#define HALT        -1
#define IGNOREWHITE  0
#define START        1
#define NONWHITE     2
#define BACKSLASH    3
#define VARIABLE     4
char *names[]={"ignorewhite","start","nonwhite","backslash","variable"};

static char *
GetLine( fd )
   FILE *fd;
{
   static char buf[ 1024 ];
   auto int pos = 0;
   auto int state = START;
   int ch;
   char *pch_var, *pch_replace;

   ch = getc(fd);
   if( EOF == ch )
      return NULL;
   while( state != HALT ){
       if( debug )
          printf( "state: %s\n", names[state]);
       switch( state ){
       case IGNOREWHITE:
                  if ( ' ' == ch || '\t' == ch || ',' == ch )
                      ch = getc(fd);
                  else
                      state = START;
                  break;
       case START:
                  if( ' ' == ch || '\t' == ch || ',' == ch ) {
                      buf[pos++] = ch;
                      ch = getc(fd);
                      state = IGNOREWHITE;
                      break;
                  } else if( '$' == ch ) {
                      state = VARIABLE;
                      ch = getc(fd);
                      break;
                  } else if( '\\' == ch ) {
                      ch = getc(fd);
                      state = BACKSLASH;
                      break;
                  } else if( '\n' == ch || EOF == ch ) {
                      state = HALT;
                      break;
                  } else {
                      state = NONWHITE;
                      break;
                  }
     case NONWHITE :
                 if( ch != EOF && ch != '\n' && ch != '$' &&
                     ch != '\\' && ch != ' ' && ch != '\t' && ch != ',' ) {
                      buf[ pos++ ] = ch;
                      ch = getc(fd);
                 } else
                      state = START;
                 break;
     case BACKSLASH:
                 if( ch != '\n' ){
                    buf[pos++] = '\\';
                    buf[pos++] = ch;
                 }
                 ch = getc(fd );
                 state = START;
                 break;
     case VARIABLE:
                 if( '$' == ch ) {
                    buf[pos++] = ch;
                    state = START;
                 } else if ( '{'== ch || '(' == ch ) {
                    ch = getc(fd);
                    pch_var = &buf[ pos ];
                    while ( ')' != ch && '}' != ch ){
                         buf[ pos++ ] = ch;
                         ch = getc(fd);
                    }
                    ch = getc(fd);
                    buf[pos]=NULL;
                    pch_replace = VarLookup( pch_var );
                    strcpy( pch_var , pch_replace );
                    pos = strlen( buf );
                    state = START;
                 }
                 break;
         }
     }
     buf[pos] = NULL;
     if( debug )
        printf("buf='%s'\n", buf );
     pch_replace = malloc( strlen(buf) + 1 );
     if( pch_replace == NULL ){
        printf("make: out of memory" );
        exit(1);
     }
     strcpy( pch_replace , buf );
     return pch_replace;
}

make( pch_Target, mydays, mymins, mytics )
   char *pch_Target;
   long int *mydays, *mymins, *mytics;
{
   long int hisdays, hismins, histics;
   int fl_Action;
   char **depends, **actions;

   GetDate( pch_Target, mydays, mymins, mytics );
   if( debug )
      printf("make(): %s %ld %ld:%ld\n",pch_Target,*mydays,*mymins,*mytics );
   depends = GetDependants( pch_Target );
   actions = GetActions( pch_Target );
   fl_Action = *mydays == 0 && *mymins == 0 && *mytics == 0;
   while( *depends ){
      if( make( *depends++, &hisdays, &hismins, &histics ) )
         fl_Action = 1;
      if( hisdays > *mydays || (hisdays == *mydays &&
          ( hismins > *mymins || (hismins == *mymins && histics > *mytics ))))
         fl_Action = 1;
   }
   if( fl_Action )
      while( *actions ) {
          printf("%s\n", *actions );
          Execute( *actions, 0, 0 );
          actions++;
      }
   return fl_Action;
}

GetDate( pch_FileName, days, mins, secs )
   char *pch_FileName;
   long int *days, *mins, *secs;
{
   static struct FileInfoBlock buf;
   char *p;

   if( p = (char *)Lock( pch_FileName, ACCESS_READ )){
      if( Examine( p , &buf ) ) {
         *days = buf.fib_Date.ds_Days;
         *mins = buf.fib_Date.ds_Minute;
         *secs = buf.fib_Date.ds_Tick;
      } else
         printf("Couldn't get info for %s\n", pch_FileName );
      UnLock( p );
   } else {
      if ( debug )
         printf("couldn't lock %s\n", pch_FileName );
      *days = *mins = *secs = 0;
   }
}
