/* 
   Copyright 1994-2003 Free Software Foundation, Inc.

   This program 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 2 of the License, or
   (at your option) any later version.

   This program 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 this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.  

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222
*/
#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <dos.h>
#include "cmdline.h"
#include "umem.h"
#include "interp.h"
#include "input.h"
#include "parser.h"
#include "register.h"
#include "macros.h"
#include "if.h"
#include "maker.h"

extern int level;
extern char *prm_includepath;
extern short *bufptr,buffer[];
extern BOOL done;
extern BOOL ifskip;
extern short xandand[];
extern BOOL prm_autodepends;

short xinclude[] = { 0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0};
short xifdef[] = { 0x69, 0x66, 0x64, 0x65, 0x66, 0};
short xifndef[] = {0x69,0x66,0x6e,0x64,0x65,0x66,0 };
short xelse[] = { 0x65, 0x6c, 0x73,0x65, 0};
short xendif[] = { 0x65, 0x6e, 0x64, 0x69, 0x66, 0 };
short xpath[] = { 0x2e, 0x70, 0x61,0x74,0x68,0 };
short xautodep[] = { 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x64, 0x65,0x70, 0x65, 0x6e, 0x64, 0 };

void Extraneous(void)
{
	Error("Extraneous characters on line");
}
void readfilename(short **bp, short *buf, short mc)
{
	while (**bp != mc && **bp)
		*buf++ = *(*bp)++;
	*buf = 0;
	if (**bp)
		bp++;
}
void readtargetname(short **bp, short *buf, short mc)
{
	readfilename(bp,buf,mc);
	ExpandString(buf);
}
void NewInputFile(void)
{
	short matchchar = QUOTE;
	short filebuf[200];
	char filename[200];
	ExpandString(bufptr);
	skipSpace(&bufptr);
	if (*bufptr == LESS)
		matchchar = GREATER;
	else
		if (*bufptr != QUOTE)
			Error("Bad include specification");
	bufptr++;
	readfilename(&bufptr,filebuf,matchchar);
	if (*bufptr != matchchar)
		Error("Unterminated include");
	else
		bufptr++;
	skipSpace(&bufptr);
	if (*bufptr)
		Extraneous();
	CompressFile(filename,filebuf);
	if (!openFile(filename,prm_includepath,"r"))
		Error("Missing include file %s",filename);
}
void HandleExclamation(void)
{
	short ibuf[100], *p = ibuf;
	while (*bufptr && issymchar(*bufptr))
		*p++ = *bufptr++;
	*p = 0;
	if (!pstrcmp(ibuf,xinclude))
		NewInputFile();
	else
		if (!pstrcmp(ibuf,xifdef))
			ifdef();
		else
			if (!pstrcmp(ibuf,xifndef))
				ifndef();
			else
				if (!pstrcmp(ibuf,xelse))
					ifelse();
				else
/*					if (!pstrcmp(ibuf,xelseif))
 *						ifelseif();
 *
 *					else
 */
						if (!pstrcmp(ibuf,xendif))
							ifendif();
						else {
							char buffer[100];
							CompressFile(buffer,ibuf);
							Error("Invalid escape %s",buffer);
						}
}
void escape(void)
{
	while (TRUE) {
		NewLine();
		if (done)
			break;
		skipSpace(&bufptr);
		if (!*(bufptr))
			continue;
		if (*bufptr == EXCLAMATION) {
			bufptr++;
			HandleExclamation();
			continue;
		}
		else {
			if (!*bufptr)
				continue;
			if (!ifskip) {
				bufptr = buffer;
				break;
			}
		}
	}
}
short **ReadCommands(int *count )
{
	BOOL infile = FALSE;
	int matchchar = 0;
	short **rv;
	short *lines[COMMANDLINES];
	*count = 0;
	while (!done) {
		if (*count >=COMMANDLINES)
			fatal("Too many command lines");
		escape();
		if (!infile && !iswhitespacechar(*bufptr))
			break;
		if (iswhitespacechar(*bufptr)) {
			skipSpace(&bufptr);
		}
		if (*bufptr || infile) {
			lines[*count] = AllocateMemory(pstrlen(bufptr)*2+2);
			pstrcpy(lines[*count],bufptr);
			if (infile) {
				if (pstrchr(bufptr,matchchar))
					infile = FALSE;
			}
			else {
				short *temp;
				if ((temp = pstrstr(bufptr,xandand)) != 0) {
					matchchar = *(temp+2);
					infile = TRUE;
				}
			}
			(*count)++;
		}
	}
	if (infile)
		Error("End of file without match character %c",matchchar);
	lines[(*count)++] = 0;
	if (*count) {
		rv = AllocateMemory(sizeof(short *) * *count);
		memcpy(rv,lines,sizeof(char *) * *count);
	}
	return(rv);
}
void Implicit(void)
{
	short buf[100],**rv, *p=buf;
	int count;
	if (!pstrncmp(bufptr,xautodep,pstrlen(xautodep))) {
		prm_autodepends = TRUE;
		escape();
		return;
	}
	if (!pstrncmp(bufptr,xpath,pstrlen(xpath))) {
		while(*bufptr && *bufptr != ALTEQUAL && *bufptr != EQUAL)
			*p++ = *bufptr++;
		*p = 0;
		if (*bufptr)
			bufptr++;
		else
			Error("Missing path");
		RegisterPath(buf,bufptr);
		escape();
	}
	else {
		int *q = pstrchr(bufptr,COLON);
		int *r = pstrchr(bufptr,COLON2);
		if (r && (!q || q > r))
			readtargetname(&bufptr,buf,COLON2);
		else
			readtargetname(&bufptr,buf,COLON);
			
		if (*bufptr != COLON && *bufptr != COLON2)
			Error("Missing colon in implicit rule");
		bufptr++;
		skipSpace(&bufptr);
		if (*bufptr)
			Extraneous();
		rv = ReadCommands(&count);
		RegisterImplicit(buf,rv);
	}
}
void Explicit(void)
{
   short buf[100],value[4000],**rv, *p = buf,*q,*r,*s;
	int count;
	q = pstrchr(bufptr,COLON);
	r = pstrchr(bufptr,COLON2);
	if (r && (!q || q > r))
		q = r;
	if (q == 0)
		q = -1;
	r = pstrchr(bufptr,EQUAL);
	s = pstrchr(bufptr,ALTEQUAL);
	if ((r && r < q) || (s && s < q)) {
		while(*bufptr != EQUAL && *bufptr != ALTEQUAL)
			*p++ = *bufptr++;
		*p = 0;
      while (p > buf && iswhitespacechar(*(p-1))) 
         *--p = 0 ;
      ++bufptr ;
      p = value ;
      while (*bufptr) *p++ = *bufptr++ ;
      *p = 0 ;
      p = ExpandSelf(buf,value) ;
      RegisterMacro(buf,p,TRUE,TRUE);
		escape();
	}
	else {
		q = pstrchr(bufptr,COLON);
		r = pstrchr(bufptr,COLON2);
		if (r && (!q || q > r))
			readtargetname(&bufptr,buf,COLON2);
		else
			readtargetname(&bufptr,buf,COLON);
		if (*bufptr != COLON && *bufptr != COLON2)
			Error("Missing colon in explicit rule");
		bufptr++;
		RegisterExplicitName(buf,bufptr);
		rv = ReadCommands(&count);
		RegisterExplicitCommands(buf,rv);
	}
}
BOOL ReadMakeFile(char *path, char *string)
{
	openFile(string,path,"r");
	if (level < 0) {
		char buffer[256];
		strcpy(buffer,string);
		AddExt(buffer,".MAK");
		openFile(buffer,path,"r");
	}
	if (level < 0)
		return(FALSE);
	escape();
	while (!done) {
		if (iswhitespacechar(*bufptr))
			Error("Target expected");
		if (*bufptr == PERIOD)
			Implicit();
		else
			Explicit();
	}
	return(TRUE);
}