/* This file is part of cqual.
   Copyright (C) 2003 The Regents of the University of California.

cqual 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, or (at your option)
any later version.

cqual 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 cqual; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */

#include "pam.h"
#include "analyze.h"
#include "flow.h"
#include "pam-ast.h"
#include "pam-generic.h"

#define pam_undefineds_buffer "*Undefined Globals*"
#define pam_undefineds_click "undef"
#define pam_varargs_buffer "*Non-Polymorphic Varargs Functions*"
#define pam_varargs_click "varargs"

void pam_add_buffer_click(const char *bname, const char *cname,
			  click_func func, void *arg);

void pam_jump_file(const char *click_name, const char *file,
		   const char *name, location loc);

/* Make a hyperlink to an undefined global name */
void pam_markup_global(data_declaration ddecl, void *arg)
{
  pred_info pi;
  pi = (pred_info) arg;
  if (pi->pred(ddecl, pi->store))
    {
      pam_add_link(ddecl->name, pam_color_1, ddecl->name);
      pam_add_text("\n");
      pam_add_buffer_click(pi->buffer,
			   ddecl->name,
			   (click_func) pam_jump_file,
			   location_declaration(ddecl->ast));
    }
}


/* (Re)create the buffer listing k-kinded globals */
void pam_create_globals_buffer(kind_globals k)
{
  struct pred_info pi;
  const char *title;

  switch (k)
    {
    case undefined_globals:
      title = "Undefined Globals";
      pi.pred = (ddecl_pred)is_undefined_global;
      pi.buffer = pam_undefineds_buffer;
      pi.store = global_store;
      break;
    case varargs_globals:
      title = "Non-Polymorphic Varargs Functions";
      pi.pred = (ddecl_pred)is_unannotated_global;
      pi.buffer = pam_varargs_buffer;
      pi.store = global_store;
      break;
    default:
      fail("Unexpected kind_globals %x\n", k);
    }
  pam_clear_buffer(pi.buffer);
  pam_blobs_begin();
  pam_markup_buffer(pi.buffer);
  pam_add_text("%s:\n\n", title);
  traverse_globals_sorted(pam_markup_global, &pi);
  pam_blobs_end();
}


/* arg is a pred_info.  Set arg->flag to TRUE if arg->pred is true of
   ddecl.  Otherwise leave arg->flag alone. */
void set_if_pred(data_declaration ddecl, void *arg)
{
  pred_info2 pi;

  pi = (pred_info2) arg;
  if (pi->pred(ddecl, pi->store))
    pi->flag = TRUE;
}


/* Return TRUE iff there is some global satisfying pred */
bool exist_globals(ddecl_pred pred)
{
  struct pred_info2 pi;

  pi.pred = pred;
  pi.flag = FALSE;
  pi.store = global_store;
  traverse_globals(set_if_pred, &pi);
  return pi.flag;
}



/* Return TRUE iff there is some undefined but used global */
bool exist_undefineds(void)
{
  return exist_globals((ddecl_pred)is_undefined_global);
}

/* Return TRUE iff there is some unannotated (global) varargs function */
bool exist_varargs(void)
{
  return exist_globals((ddecl_pred)is_unannotated_global);
}
