/*
 *	Macro control for make
 */


#include "h.h"


MACRO *macrohead;


MACRO *getmp(char * name)
{
  register MACRO *rp;
  
  for (rp = macrohead; rp; rp = rp->m_next)
    if (strcmp(name, rp->m_name) == 0)
      break;

  return rp;
}

char *mksubst(char *mval,char *colon)
{
  static substbuf[LZ];
  char   *psrc,*pdst,*match;
  char   *newval;
  int    advance,oldlen;

  if (colon == 0)
    return mval;
  newval = strchr(colon,'=');
  *(newval++) = '\0';
  oldlen = newval - colon - 1;

#if 0
  printf("(mksubst)  colon  = %s\n"
	 "(mksubst) newval = %s\n",colon,newval);
#endif
  
  psrc = mval; pdst = substbuf;
  while (1)
    {
      match = strstr(psrc,colon);
      if (match == NULL) {
	strcpy(pdst,psrc);
        break;
      }
      advance = match-psrc;
      strncpy(pdst,psrc,advance);
      pdst += advance;
      strcpy(pdst,newval);
      while (*pdst)
	pdst++;
#if 0
      printf("(mksubst)  psrc     = %s\n"
	     "(mksubst)  match    = %s\n"
	     "(mksubst)  substbuf = %s\n",psrc,match,substbuf);
#endif 
      psrc = match+oldlen;
    }
    return substbuf;
}

MACRO *setmacro(name, val)
char *name;
char *val;
{
  register MACRO *	rp;
  
  
  /*  Replace macro definition if it exists  */
  for (rp = macrohead; rp; rp = rp->m_next)
    if (strcmp(name, rp->m_name) == 0)
      {
	free(rp->m_val);	/*  Free space from old  */
	break;
      }
  
  if (!rp)		/*  If not defined, allocate space for new  */
    {
      rp = (MACRO *)malloc(sizeof (MACRO));
      if (rp == NULL)
	fatal("No memory for macro");
      
      rp->m_next = macrohead;
      macrohead = rp;
      rp->m_flag = FALSE;
      if ((rp->m_name = strdup(name)) == NULL)
      fatal("No memory for macro '%s'",name);
    }
  
  if ((rp->m_val = strdup(val))==NULL)
    fatal("No memory for macro'%s'",rp->m_name);
  
  return rp;
}

/*
 *	Do the dirty work for expand
 *
 *
 */
void doexp(char **to,char *from,int *len,char *buf)
{
  register char *rp;
  register char *p;
  register char *q;
  register MACRO *mp;
  char           *colon;

  rp = from;
  p = *to;
  while (*rp)
    {
      if (*rp != '$')
	{
	  *p++ = *rp++;
	  (*len)--;
	}
      else
	{
	  q = buf;
	  if (*++rp == '{')
	    while (*++rp && *rp != '}')
	      *q++ = *rp;
	  else if (*rp == '(')
	    while (*++rp && *rp != ')')
	      *q++ = *rp;
	  else if (!*rp)
	    {
	      *p++ = '$';
	      break;
	    }
	  else
	    *q++ = *rp;
	  *q = '\0';
	  if (*rp)
	    rp++;

	  colon = strchr(buf,';');
	  if (colon) {
	    *(colon++) = '\0';
	    if (strchr(colon,'=') == NULL) {
	      *(--colon) = ';';
	      fatal("Syntax error in macro '%s'",buf);
	    }
	  }
	  if (!(mp = getmp(buf)))
	    mp = setmacro(buf, "");
	  if (mp->m_flag)
	    fatal("Infinitely recursive macro %s", mp->m_name);
	  mp->m_flag = TRUE;
	  *to = p;
	  doexp(to, mksubst(mp->m_val,colon), len, buf);
	  p = *to;
	  mp->m_flag = FALSE;
	}
      if (*len <= 0)
	error("Expanded line too line");
    }
  *p = '\0';
  *to = p;
}


/*
 *	Expand any macros in str.
 */
void
expand(str)
char *		str;
{
	static char		a[LZ];
	static char		b[LZ];
	char *			p = str;
	int			len = LZ-1;

	strcpy(a, str);
	doexp(&p, a, &len, b);
}
