
/* special purpose post-optimizer for cc65 */

#include <stdio.h>

int matchstr(line, str)
char * line;
char * str;
{
  for ( ; *str ; )
    {
      if (*line != *str)
	return(0);
      ++line;
      ++str;
    }
  return(1);
}

int matchjsr(line, str)
{
  return(matchstr(line, "\tjsr\t") && (matchstr(line+5, str)));
}

/* returns ptr to stuff after ldy if it's usable, ie constant 0..7 */
char * matchldy(line)
char * line;
{
  if (matchstr(line, "\tldy\t#"))
    {
      if ((line[6] >= '0') && (line[6] < '8') && (line[7] == '\n'))
	return(line + 6);
    }
  return(0);
}

/* routines that can use implied offsets */
char * impl[] = 
{
  "ldaxysp",
  "ldaysp",
  "staxysp",
  "staysp",
  "pushwysp",
  "pushbysp",
  0
  };

/* handed 2 lines, return ptr to one to new one if optimized */
char buf[80];

char * opt_impl(lbuf1, lbuf2)
char * lbuf1;
char * lbuf2;
{
  char * ldystr;
  char ** rtn;

  ldystr = matchldy(lbuf1);
  if (!ldystr)
    return(0);
  for (rtn = impl ; *rtn ; rtn++)
    if (matchjsr(lbuf2, *rtn))
      break;
  if (!*rtn)
    return(0);
  strcpy(buf, "\tjsr\t");
  strcat(buf, *rtn);
  strcat(buf, ldystr);
  return(buf);
}

int readline(f, b)
FILE * f;
char * b;
{
  int c;
  char * p;

  for (p = b ; ((c = fgetc(f)) != EOF) ; )
    {
      *p++ = c;
      if (c == '\n')
	break;
    }
  *p = '\0';
  return(p != b);
}

char lbuf1[80];
char lbuf2[80];

main(argc, argv)
int argc;
char ** argv;
{
  FILE * inf, * outf;
  char * line;

  if (!(inf = fopen(argv[1], "r")))
    {
      printf("Can't open %s", argv[1]);
      exit(1);
    }
  outf = fopen("xopt.tmp", "w");
  readline(inf, lbuf1);
  while(readline(inf, lbuf2))
    {
      line = opt_impl(lbuf1, lbuf2);
      if (line)
	{
	  fputs(line, outf);
	  readline(inf, lbuf2);	/* get new input line */
	}
      else
	{
	  fputs(lbuf1, outf);
	}
      strcpy(lbuf1, lbuf2);
    }
  fputs(lbuf1, outf);
  fclose(inf);
  fclose(outf);
  unlink(argv[1]);
  rename("xopt.tmp", argv[1]);
}
