#define CONFIG_COMPILER
/*
 * parseconfig.c
 *
 * Copyright (C) 1994 Alain Knaff
 */
#define _LARGEFILE64_SOURCE
#define _GNU_SOURCE

#include "sysincludes.h"

#define E_NOT_FOUND 0
#define E_EXP_STR -1
#define E_EXP_FA -2
#define E_EXP_PM -3
#define E_EXP_EOL -4
#define E_SHORT -5
#define E_BAD_TOK -6 
#define E_OOM -7
#define E_FA_TOO_BIG -8
#define E_EOF_REACHED -9
#define E_COM_FOL_FA -10
#define E_NO_CLASS -11
#define E_TWICE -12

commands_line *commands_lines;
int generation=0;
int zlib_mode=0;
commands_line *make_entry(char *name)
{
  commands_line *ptr,*newptr;
  
  for(ptr = commands_lines; ptr; ptr=ptr->globalnext){
    if (! strcmp(ptr->name, name) )
      return ptr;
  }
  newptr = (commands_line *) malloc(sizeof(commands_line));
  if (!newptr){
    fprintf(stderr,"Out of memory\n");
    exit(1);
    return 0;
  }
  newptr->globalnext = commands_lines;
  commands_lines = newptr;
  newptr->name = (char *) malloc(strlen(name)+1);
  if(!newptr->name){
    fprintf(stderr,"Out of memory\n");
    exit(1);
    return 0;
  }
  strcpy(newptr->name, name);
  newptr->mode = 0;
  newptr->modemask = 0;
  newptr->generation = 0;
  newptr->localnext = 0;
  newptr->class[0]='\0';
  newptr->defined = 0;
  return newptr;
}

commands_line *default_cl=0;

int add_prog(commands_line **cmd, char *name)
{
  commands_line *ptr;
  
  ptr = make_entry(name);
  if( !ptr)
    return E_OOM;
  default_cl = ptr;
  if(ptr->generation == generation)
    return E_TWICE;
  ptr->localnext = *cmd;
  *cmd = ptr;
  return 0;
}

int add_default(commands_line **cmd)
{
  commands_line *ptr;
  
  ptr = make_entry("");
  if(!ptr)
    return E_OOM;
  if(ptr->generation == generation)
    return E_TWICE;
  ptr->localnext = *cmd;
  *cmd = ptr;
  return 0;
}

#define PRINT(x) case x: printf(#x); break
#define PRINT2(x) case x: if(notfirst)putchar('|');printf(#x); notfirst=1;break

void print_class(FilenameActions *fa, char *name, int line)
{
  int i;
  int notfirst;

  commands_line *ptr;
  int needed;

  needed = 0;
  for(ptr = commands_lines; ptr; ptr=ptr->globalnext){
    if ( ! strcmp ( ptr->class, name )){
      if ( ptr->defined ){
	fprintf(stderr, "Class %s defined twice!\n", name);
	exit(1);
      }
      needed = 1;
      ptr->defined = 1;
    }
  }

  if (!needed )
    return;

  printf("static FilenameActions zlibc_class_%s[]={\n", name);
  while(1) {
    if ( fa->fa_type == FA_FS ){
#if 0
      printf("FSREC( ");
      printf("FA_FS,\t0x%x", fa->namelength);
#else
      fprintf(stderr,
	      "Skipping filesystem criterion in class %s near line %d\n",
	      name, line);
      fa++;
      continue;
#endif
    } else {
      printf("FREC( ");
      if ( fa->fa_type == FA_ALL)
	fa->namelength=0;

      switch(fa->fa_type){
	PRINT(FA_ALL);
	PRINT(FA_DIR);
	PRINT(FA_SUBDIR);
	PRINT(FA_BASENAME);
	PRINT(FA_SUFFIX);
	PRINT(FA_ALL2);
      }
      if( fa->fa_type != FA_FS){
	printf(",\t\"");
	for(i=0; i < fa->namelength; i++)
	  putchar(fa->name[i]);
	putchar('"');
      }
    }
    printf(",\t");
    if ( fa->pipe_mode == PM_NONE )
      printf("PM_NONE");
    else {
      notfirst=0;
      switch(fa->pipe_mode & PM_READ_MASK){
	PRINT2(PM_USE_TMP_FILE);
	PRINT2(PM_HIDE_PIPE);
	PRINT2(PM_SHOW_PIPE);
	PRINT2(PM_DIR_LEAVE_COMPR);
	PRINT2(PM_LEAVE_COMPR);
      }

      switch(fa->pipe_mode & PM_CREATE_MASK){
	PRINT2(PM_CREATE_COMPR);
	PRINT2(PM_NOCREATE_COMPR);
      }

      switch(fa->pipe_mode & PM_APPEND_MASK){
	PRINT2(PM_APPEND_COMPR);
	PRINT2(PM_NOAPPEND_COMPR);
      }

      switch(fa->pipe_mode & PM_UNCOMPR_MASK){
	PRINT2(PM_UNCOMPR_BEFORE_WRITE);
	PRINT2(PM_NO_UNCOMPR_BEFORE_WRITE);
      }

      switch(fa->pipe_mode & PM_SIZE_COMPR){
	PRINT2(PM_SIZE_COMPR);
	PRINT2(PM_SIZE_UNCOMPR);
      }
    }

    printf(")");
    if ( fa->fa_type == FA_ALL ){
      printf("};\n\n");
      break;
    } else
      printf(",\n");
    fa++;
  }
}

#define PRINT3(x) if(ptr->mode&x){if(notfirst)putchar('|');printf(#x);notfirst=1;}

void print_commands_line(commands_line *ptr, int end)
{
  int notfirst;
  notfirst=0;

  printf("{ ");
  if(ptr->name[0])    
    printf("\"%s\"",ptr->name);
  else
    putchar('0');
  printf(",\t");

  if ( !ptr->mode)
    printf("0");
  else {
    PRINT3(CM_DISAB);
    PRINT3(CM_DISAB_CHILD);
    PRINT3(CM_READDIR_COMPR);
    PRINT3(CM_VERBOSE);
    PRINT3(CM_UNLINK);
    PRINT3(CM_NORTCONF);
  }

  printf(",\t");
  if(ptr->class && ptr->class[0]){
    if ( !ptr->defined ){
      fprintf(stderr,"Class %s undefined (needed by %s)\n", ptr->class,
	      ptr->name);
      exit(1);
    }
    printf("zlibc_class_%s", ptr->class);
  } else if ( default_cl && default_cl->class && default_cl->class[0] )
    printf("zlibc_class_%s", default_cl->class);
  else {
    fprintf(stderr,"Missing default class\n");
    exit(1);
  }
  putchar('}');
  if(!end)
    putchar(',');
  putchar('\n');
}

void print_commands_lines(void)
{
  commands_line *ptr;
  commands_line *def;

  printf("\nCommandActions zlib_commandActions[]={\n");

  def=0;
  for(ptr= commands_lines; ptr; ptr=ptr->globalnext){
    if( ptr->name[0] == '\0' )
      def = ptr;
    else
      print_commands_line(ptr,0);
  }
  if ( def)
    print_commands_line(def,1);
  else
    printf("0,0,0}\n");
  printf("};\n");
}

int main(int argc, char **argv)
{
  int line;
  int ret;
  FILE *f;

  if ( argc == 1){
    fprintf(stderr,"Usage: %s file\n", argv[0]);
    exit(1);
  }
  f=fopen(argv[1], "r");
  if(!f){
    perror("fopen");
    exit(1);
  }
  printf("/* This file is generated automatically. DO NOT EDIT*/\n");
  printf("#define _LARGEFILE64_SOURCE\n");
  printf("#define _GNU_SOURCE\n");

  printf("#include \"sysincludes.h\" \n");
  ret=parse_file(0, f, &line,0,0,0);
  if ( ret < 0 ){
    fprintf(stderr,
	    "zlibc: %s in line %d\n", 
	    err_strings[ -ret], line);
    exit(1);
  }
  print_commands_lines();
  return 0;
}
