/* $Id: mthdrf.c,v 1.1.1.1 2008/10/28 13:28:21 kiesling Exp $ */

/*
  This file is part of ctalk.
  Copyright © 2005-2008 Robert Kiesling, ctalk@ctalklang.org.
  Permission is granted to copy this software provided that this copyright
  notice is included in all source code modules.

  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., 51 Franklin St., Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include "object.h"
#include "message.h"
#include "ctalk.h"
#include "lex.h"
#include "classlib.h"
#include "symbol.h"

extern CLASSLIB *lib_includes[MAXARGS + 1];  /* Declared in class.c.  */
extern int lib_includes_ptr;
extern CLASSLIB *input_declarations[MAXARGS+1];
extern int input_declarations_ptr;

extern MESSAGE *var_messages[N_MESSAGES + 1];  /* Declared in cvars.c. */
extern int var_messageptr;

static int old_input_size = 0;
static char *input = NULL;

int method_prototypes (char *p_lib_fn, CLASSLIB *c) {

  int idx, tmpsize, end_ptr;
  MESSAGE *m;
  char *d_buf;
  LIST *l;

  if (!file_exists (p_lib_fn))
    _error ("%s: %s.", p_lib_fn, strerror (errno));
  
  tmpsize = file_size (p_lib_fn);
  if (tmpsize > old_input_size) {
    old_input_size = tmpsize+1;
    if ((input = (char *)realloc (input, tmpsize+1)) == NULL)
      _error ("parse_vars: %s.", strerror (errno));
  }
  memset ((void *)input, 0, old_input_size);
  read_file (input, p_lib_fn);

  end_ptr = tokenize (var_message_push, input);

  for (idx = N_MESSAGES; idx >= end_ptr; idx--) {

    m = var_messages[idx];

    if (M_ISSPACE(m)) continue;

    switch (M_TOK(m))
      {
      case LABEL:
	if (!strcmp (M_NAME(m), "instanceMethod") ||
	    !strcmp (M_NAME(m), "classMethod")) {
	  int _class_idx, _selector_idx, _alias_idx;
	  int _open_arg_idx, _close_arg_idx;
	  if (((_class_idx = prevlangmsg (var_messages, idx)) == ERROR) ||
	      ((_selector_idx = nextlangmsg (var_messages, idx)) == ERROR) ||
	      ((_alias_idx = nextlangmsg (var_messages, _selector_idx)) == ERROR))
	    _error ("Parse error.\n");

	  if (M_TOK(var_messages[_alias_idx]) == OPENPAREN) {
	    _open_arg_idx = _alias_idx;
	  } else {
	    if ((_open_arg_idx = nextlangmsg (var_messages, _alias_idx)) == ERROR)
	      _error ("Parse error.\n");
	  }
	  if ((_close_arg_idx = match_paren (var_messages, 
	     _open_arg_idx, get_stack_top (var_messages))) == ERROR)
	    _error ("Parse error.\n");

	  d_buf = collect_tokens (var_messages, _class_idx, _close_arg_idx);
	
	  l = new_list ();
	  l -> data = d_buf;
	  list_push (&(c -> _method_proto), &l);
	}
	break;
      }
  }
  DELETE_MESSAGES(var_messages,var_messageptr,N_MESSAGES)

  return SUCCESS;
}

#define INPUT_DECLARATION input_declarations[input_declarations_ptr+1]

int is_method_proto (char *classname, char *selector) {
  LIST *l;
  char buf[MAXMSG];
  if (lib_includes_ptr < MAXARGS) {
    if (!strcmp (C_LIB_INCLUDE->name, classname)) {
      for (l = C_LIB_INCLUDE->_method_proto; l; l = l -> next) {
	sprintf (buf, "%s instanceMethod %s ", classname, selector);
	if (!strncmp ((char *)l->data, buf, strlen (buf)))
	  return TRUE;
      }
    }
  }
  if (input_declarations_ptr < MAXARGS) {
    for (l = INPUT_DECLARATION->_method_proto; l; l = l -> next) {
      sprintf (buf, "%s instanceMethod %s ", classname, selector);
      if (!strncmp ((char *)l->data, buf, strlen (buf)))
	return TRUE;
      sprintf (buf, "%s classMethod %s ", classname, selector);
      if (!strncmp ((char *)l->data, buf, strlen (buf)))
	return TRUE;
    }
  }
  return FALSE;
}

void input_prototypes (char *fn) {
  method_prototypes (fn, input_declarations[input_declarations_ptr+1]);
}
