/* This is a very simple C preprocessor:
 *      Recognizes #include #define #undef #ifdef #ifndef #else #endif
 *      It doesn't keep track of line numbers.
 *
 * by Thomas Hallgren, July 1990
 * version 5
 * RISC/OS by Niklas Rjemo, August 1992 - removed 1997
 * Simplified by Gavin Wraith, June 1997 - no command line flags
 * needed for Risc OS use.
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "define.h"
#include "ifdef.h"
#include "comment.h"
#define MAXFILENAMELEN 256
#define MAXLINELEN 4096

extern void parse_error(char *msg);

static char linebuf[MAXLINELEN];
static char *currentfile;
static int   currentline;

void preprocess(FILE *source);       /* forward */

static void include(char *filename)
{
  char includefile[MAXFILENAMELEN];
  char *oldcurrentfile;
  int   oldcurrentline;
  FILE *f;
  strcpy(includefile,filename);    /* GCW */
  f=fopen(includefile,"r");
  if(!f) parse_error("Can't open include file");
  else {
        oldcurrentfile = currentfile;
        oldcurrentline = currentline;
        currentfile = includefile;
        currentline = 0;
        preprocess(f);
        fclose(f);
        currentfile = oldcurrentfile;
        currentline = oldcurrentline;
      }
}

static void processdirective(void)
{
  static char sep[]=" \t\n";    /* \n will only appear last on the line */
  char *dir,*name,*rest;

  dir=strtok(linebuf+1,sep);    /* skip '#', get the directive */
  if(!dir) parse_error("BAD directive");
  else if(!strcmp(dir,"else")) {
    gotelse();
  }
  else if(!strcmp(dir,"endif")) {
    gotendif();
  }
  else if(!strcmp(dir,"ifdef")) {
    name=strtok(NULL,sep);
    if(!name) parse_error("Missing macro name for #ifdef ");
    gotifdef(isdefined(name));
  }
  else if(!strcmp(dir,"ifndef")) {
    name=strtok(NULL,sep);
    if(!name) parse_error("Missing macro name for #ifndef ");
    gotifdef(!isdefined(name));
  }
  else if(skipping()) {
    /* ignore directive */
  }
  else if(!strcmp(dir,"include")) {
    name=strtok(NULL,sep);              /* get the filename  */
    if(!name) parse_error("Missing file name for #include ");
    else include(name);
  }
  else if(!strcmp(dir,"define")) {
    name=strtok(NULL,sep);
    if(!name) parse_error("Missing macro name for #define ");
    rest=strtok(NULL,"\n");
    while(*rest == ' ')
      rest++;
    define(name,rest);
  }
  else if(!strcmp(dir,"undef")) {
    name=strtok(NULL,sep);
    if(!name) parse_error("Missing macro name for #undef ");
    undef(name);
  }
  /* ... */
  else parse_error("UNRECOGNIZED directive ");
  /* should complain if there's extra text after valid directive... */
}

static char *getline(FILE *source)
{
  static int insidecomment=0;
  char *p;
  p=linebuf;
  while((p=fgets(p,sizeof(linebuf)-(p-linebuf),source))!=0
        && (*(p+=strlen(p)-2)=='\\')) {         /* !! buffer overflow? */
    *p++=' ';
  }
  insidecomment=removecomment(linebuf,insidecomment);
  return p;
}

void preprocess(FILE *source)
{
  startfile();
  while(getline(source)) {
    currentline++;  /* Wonder if this is the correct position !!! */
    if(linebuf[0]=='#') processdirective(/*source*/);
    else if(!skipping()) expandandputline(linebuf);
  }
  endfile();
}

