/*
 *  smoke16/libObj/src/Search.c - Functions for SymSearch's.
 *  $Revision: 1.16 $
 *  Copyright 1997, Benjamin Sittler
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

/* #define DEBUG_OBJ */
/* #define DEBUG_SYMS */
/* #define DEBUG_RELOCS */
/* #define DEBUG_SEARCH */

#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <smoke16/libObj.h>

SymSearch *newSymSearch(SymTab *tab, int (*criterion)(Sym *)) {
  SymSearch *search;

  if ((search = (SymSearch *)malloc(sizeof(SymSearch)))) {
    search -> tab = tab;
    search -> bucket = -1;
    search -> node = 0;
    search -> criterion = criterion;
    search -> syms = 0;
#ifdef DEBUG_SEARCH
    fprintf(stderr,
	    "new search in table %p (%d syms) with criterion %p\n",
	    search -> tab, search -> tab -> syms, search -> criterion);
#endif
  } else
    perror("malloc");
  return search;
}

void freeSymSearch(SymSearch *search) {
#ifdef DEBUG_SEARCH
  fprintf(stderr,
	  "finished search in table %p (examined %d syms) with criterion %p\n",
	  search -> tab, search -> syms, search -> criterion);
#endif
  free(search);
}

Sym *nextSym(SymSearch *search) {
  while (search -> syms < search -> tab -> syms) {
    if (search -> node && search -> node -> next)
      search -> node = search -> node -> next;
    else
      if (++(search -> bucket) >= HASHSIZE) {
#ifdef DEBUG_SEARCH
	fputs("fell off end of table!\n", stderr);
#endif
	return 0;
      } else
	search -> node = search -> tab -> tab[search -> bucket];
    if (search -> node) {
#ifdef DEBUG_SEARCH
      fprintf(stderr, "inspecting '%s'\n", search -> node -> string);
#endif      
      search -> syms++;
      if (search -> criterion(search -> node))
	return search -> node;
    }
  }
#ifdef DEBUG_SEARCH
  fputs("searched all syms\n", stderr);
#endif
  return 0;
}

void backupSymSearch(SymSearch *search) {
  Sym *sym = search -> tab -> tab[search -> bucket];

#ifdef DEBUG_SEARCH
  fprintf(stderr,
	  "from table %p, bucket %d: '%s'\n",
	  search -> tab,
	  search -> bucket,
	  search -> node ? search -> node -> string : "(NULL)");
#endif
  if (sym == search -> node) {
    search -> node = 0;
    search -> bucket--;
  } else {
    while (sym && (sym -> next != search -> node))
      sym = sym -> next;
    search -> node = sym;
  }
  search -> syms--;
#ifdef DEBUG_SEARCH
  fprintf(stderr,
	  "to table %p, bucket %d: '%s'\n",
	  search -> tab,
	  search -> bucket,
	  search -> node ? search -> node -> string : "(NULL)");
#endif
}

int anySym(Sym *sym) {
#ifdef DEBUG_SEARCH
  fprintf(stderr,
	  "anySym(%s): 1\n",
	  sym -> string);
#endif
  return 1;
}

int externSym(Sym *sym) {
  int retval = sym -> type & SMOKE16_N_EXT;

#ifdef DEBUG_SEARCH
  fprintf(stderr,
	  "externSym(%s): %d\n",
	  sym -> string, retval);
#endif
  return retval;
}

int externorundfSym(Sym *sym) {
  int retval = externSym(sym)
    || ((sym -> type & SMOKE16_N_TYPE) == SMOKE16_N_UNDF)
    || commonSym(sym);

#ifdef DEBUG_SEARCH
  fprintf(stderr,
	  "externorundfSym(%s): %d\n",
	  sym -> string, retval);
#endif
  return retval;
}

int commonSym(Sym *sym) {
  int retval =
    (sym -> type & SMOKE16_N_TYPE) == SMOKE16__N_COMM;

#ifdef DEBUG_SEARCH
  fprintf(stderr,
	  "commonSym(%s): %d\n",
	  sym -> string, retval);
#endif
  return retval;
}

int usedSym(Sym *sym) {
  int retval = sym -> refcnt > 0;

#ifdef DEBUG_SEARCH
  fprintf(stderr,
	  "usedSym(%s): %d\n",
	  sym -> string, retval);
#endif
  return retval;
}

int debugSym(Sym *sym) {
  int retval = sym -> type & SMOKE16_N_STAB;

#ifdef DEBUG_SEARCH
  fprintf(stderr,
	  "debugSym(%s): %d\n",
	  sym -> string, retval);
#endif
  return retval;
}

int alignmentSym(Sym *sym) {
  int retval = (sym -> type & SMOKE16_N_TYPE) == SMOKE16_N_ALIGN;

#ifdef DEBUG_SEARCH
  fprintf(stderr,
	  "alignmentSym(%s): %d\n",
	  sym -> string, retval);
#endif
  return retval;
}

int nondebugSym(Sym *sym) {
  return ! debugSym(sym);
}

int usedorexternSym(Sym *sym) {
  int retval = usedSym(sym) || externSym(sym) || debugSym(sym);

#ifdef DEBUG_SEARCH
  fprintf(stderr,
	  "usedorexternSym(%s): %d\n",
	  sym -> string, retval);
#endif
  return retval;
}

int unusedinternSym(Sym *sym) {
  int retval = !usedorexternSym(sym);

#ifdef DEBUG_SEARCH
  fprintf(stderr,
	  "unusedinternSym(%s): %d\n",
	  sym -> string, retval);
#endif
  return retval;
}
