#include "make.h"

char *ReadFile( name )
char *name;
   {
   char *first;
   char *line;
   char *ep, *lp, *cp;
   char toktype, gathering;
   char *stpbrk(), *stpchr();
   BPTR fp;
   TNODE *nodep;
   STRNODE *lastcmd, *thiscmd, *namenode, *lastname;

   lastcmd = lastname = NULL;
   nodep = NULL;
   first = NULL;

   if ( (fp = Open( name, MODE_OLDFILE )) == NULL)
      {
      msg("Unable to open '%s' for rules\n", name );
      return(NULL);
      }

   gathering = FALSE;
   while ( (line = getline(MAXILINE, fp)) != NULL)
      {
      if (PrintMakeFile)
         puts(line);

      tstbreak();

      if (*line != COMMENT)
         {
         /* are we in the process of gathering commands ? */
         if (gathering && *line == ' ')
            {
            /* create a command node for us */
            thiscmd = (STRNODE *)gmem( sizeof(STRNODE) );
            thiscmd->next   = NULL;
            thiscmd->string = line;
   
            /* add this to the current command */
            if (nodep->commands == NULL)
               nodep->commands = thiscmd;
            else
               lastcmd->next = thiscmd;

            /* remember where to put the next command */
            lastcmd = thiscmd;
            }
   
         else
            {
            gathering = FALSE;

            /* make sure we don't have a blank line to deal with */
            if (*line)
               {
               /* commands may be in any of two forms:                */
               /*   <macro> = string                                  */
               /*   <targets>: <dependancies>                         */
               /*   <macro> := [a-zA-Z_@@][a-zA-Z_0-9@@@-]*           */
               /*   <target> may contain macro calls and patterns     */

               /* Do a preliminary scan to see what we have */
               if ( (lp = stpbrk(line, ":=")) == NULL)
                  err( "Invalid statement:'%s'", line );

               /* do we have a macro definition ? */
               if (*lp == '=')
                  {
                  ep = lp;
         
                  /* null out equals sign and skip over blanks */
                  for ( *lp++ = 0; isspace(*lp); lp++ );
         
                  /* remove any trailing blanks from the target or symbol */
                  for ( --ep; isspace(*ep); *ep-- = 0 );
      
                  /* we have a macro command so store it */
                  tree( line, lp, &Macros);
                  }

               else
                  {
                  /* we have a dependancy line (we hope) */
                  nodep  = (TNODE *) gmem( sizeof(TNODE) );
                  gathering = TRUE;
                  nodep->commands   = NULL;
                  nodep->targets    = NULL;
                  nodep->depends    = NULL;
                  nodep->error      = 0;

                  cp = line;
                  while ( (toktype = parse( &cp, &namenode )) != COLON )
                     {
                     if (toktype != FILENAME)
                        err("Missing ':' in '%s'", line);

                     if (nodep->targets == NULL)
                        {
                        if (first==NULL &&
                            (*(namenode->string) != '.') &&
                            (stpchr(namenode->string,'/') == NULL))
                           first = namenode->string;
                        nodep->targets = namenode;
                        }
                     else
                        lastname->next = namenode;
                     lastname = namenode;

                     /* add this target to the dependancy list */
                     tree( namenode->string, nodep, &Root );
                     }

                  while ( (toktype = parse( &cp, &namenode )) == FILENAME )
                     {
                     if (nodep->depends == NULL)
                        nodep->depends = namenode;
                     else
                        lastname->next = namenode;
                     lastname = namenode;
                     }

                  if (toktype == SEMICOLON)
                     {
                     /* create a command node for us */
                     thiscmd = (STRNODE *)gmem( sizeof(STRNODE) );
                     thiscmd->next   = NULL;
                     thiscmd->string = cp;
   
                     nodep->commands = thiscmd;

                     /* remember where to put the next command */
                     lastcmd = thiscmd;
                     }
                  else
                     if (toktype != EOS)
                        err("Invalid command '%s'", line);
                  }
               }
            }
         }
      };

   Close(fp);
   return(first);
   }

/*------------------------------------------------------------------------*/
int parse( parseptr, result )
char **parseptr;
STRNODE **result;
   {
   char *textbuff, *start, *endp, *stpchr(), *stpbrk();
   int len;

   start = *parseptr;

   /* skip over any leading whitespace */
   while(isspace(*start))
      start++;

   switch(*start)
      {
      case 0:     /* end of string */
         *parseptr = start;
         return(EOS);
         break;

      case COLON:
      case SEMICOLON:
         *parseptr = start+1;
         return((int)*start);
         break;

      case '\'':  /* single quoted file names */
      case '"' :  /* double quoted file names */
         if ( (endp=stpchr(start+1, *start)) == NULL )
            err("missing quote for '%s'", start);

         /* figure out the length to copy */
         len = endp-(start++);

         /* update the parse pointer */
         *parseptr = endp+1;
         goto makename;
 
      default:
         if ( (endp=stpbrk(start, " '\";:")) == NULL )
            len = strlen(start);
         else
            len = endp-start;
           
         *parseptr = start+len;

makename:
         textbuff = (char *)gmem( len+1 );
         movmem( start, textbuff, len);
         *(textbuff+len) = 0;

         *result = (STRNODE *)gmem( sizeof(STRNODE) );
         (*result)->string  = textbuff;
         (*result)->next    = NULL;
         return(FILENAME);
      }
   }
