#import "gdb.h"
#import "language.h"
#import "valprint.h"
#import "c-lang.h"
#import <libc.h>			/* For getenv() */

#import <stdio.h>
#import <sys/types.h>
#import <sys/stat.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSString.h>
#import "DisplaySupport/TellDisplayer.h"

static char *view_program = NULL;
static char *view_host = NULL;
static char *view_connection = NULL;
int do_display_lines = 0;
int noprompt = 0;	/* if true, turns off prompt when we have DO connection to PB */

static int have_connection = 0;

void
connect_to(const char *arg)
{
    if (setup_display_system(arg)) {
	do_display_lines = 1;
	have_connection = 1;
    }
}

void
set_noprompt()
{
    noprompt = 1;
}

void set_view_program(char *name);




#define VIEW_CONN "ViewForGdb"

static void
compute_view_connection()
{
    char	buff[256];

    sprintf(buff, "%s:%s",
            view_program, VIEW_CONN);

    view_connection = savestring(buff, strlen(buff) + 1);
}

char *
get_view_connection()
{
    return view_connection;
}

static void
view_command (arg)
     char *arg;
{
    char *host = arg ? arg : *view_host ? view_host : NULL;

    if (have_connection) {
	printf_unfiltered("Viewing disabled when gdb is started by ProjectBuilder.\n");
	return;
    }
    
    if (arg)
        set_view_host(arg);

    compute_view_connection();

    if (setup_display_system(NULL) == 0) {/* in DisplaySupport/TellDisplayer.m */
	printf("Could not connect to view_program %s", view_program);
	if (arg)
	    printf(" on host %s", arg);
	printf(".\nYou may need to start the view_program.\n");
	return;
    }

    do_display_lines = 1;
    if (target_has_stack)
        print_sel_frame(1);

  return;
}

static void
unview_command (arg, from_tty)
     char *arg;
     int from_tty;
{
    do_display_lines = 0;
    shut_down_display_system();
    if (target_has_stack)
        print_sel_frame(1);
    return;
}

void
turn_off_viewing()
{
    if (do_display_lines == 0)
        return;
    
    do_display_lines = 0;
    
    if (view_host)
	printf("%s on host %s has gone away.  Viewing is now off.\n",
	       view_program, view_host);
    else
	printf("%s has gone away.  Viewing is now off.\n", view_program);
}

void
set_view_program(char *name)
{
  view_program = savestring(name, strlen(name) + 1);
}

void
set_view_host(const char *name)
{
  view_host = savestring(name, strlen(name) + 1);
}

char *
get_view_host()
{
    return view_host;
}

static void
annotation_level_command(char	*arg,
			 int	from_tty)
{
    extern	annotation_level;

    if (strcmp(arg,"AnnotateForPB") == 0)
	annotation_level = 2;
    else
	annotation_level = 0;
}


/* stolen from ../breakpoint.c */
#define ALL_BREAKPOINTS(b)  for (b = breakpoint_chain; b; b = b->next)
extern struct breakpoint *breakpoint_chain;

void
pb_breakpoint_move_command(char	*arg,
			   int	from_tty)
{
    int			bp_number;
    int			line_number;
    struct breakpoint	*bp, *b;

    if (sscanf(arg,"%d %d", &bp_number, &line_number) != 2) {
	/* barf */

	return;
    }

    bp = NULL;
    ALL_BREAKPOINTS (b) {
	if (b->number == bp_number) {
	    bp = b;
	    break;
	}
    }
    if (bp) {
	do_breakpoint_move(bp, line_number);
    }
    else {
        printf_unfiltered ("No breakpoint number %d.\n", bp_number);
    }
}

static int
my_c_val_print (type, valaddr, address, stream, format, deref_ref, recurse,
	     pretty)
     struct type *type;
     char *valaddr;
     CORE_ADDR address;
     GDB_FILE *stream;
     int format;
     int deref_ref;
     int recurse;
     enum val_prettyprint pretty;
{
  fprintf_filtered (stream, "(");
  type_print (type, "", stream, -100);
  fprintf_filtered (stream, ") ");

  return c_val_print (type, valaddr, address, stream, format, deref_ref,
		      recurse, pretty);
}

static int
my_c_value_print (val, stream, format, pretty)
     value_ptr val;
     GDB_FILE *stream;
     int format;
     enum val_prettyprint pretty;
{
  /* A "repeated" value really contains several values in a row.
     They are made by the @ operator.
     Print such values as if they were arrays.  */

  if (VALUE_REPEATED (val))
    {
      register unsigned int n = VALUE_REPETITIONS (val);
      register unsigned int typelen = TYPE_LENGTH (VALUE_TYPE (val));
      fprintf_filtered (stream, "{");
      /* Print arrays of characters using string syntax.  */
      if (typelen == 1 && TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT
	  && format == 0)
	LA_PRINT_STRING (stream, VALUE_CONTENTS (val), n, 0);
      else
	{
	  value_print_array_elements (val, stream, format, pretty);
	}
      fprintf_filtered (stream, "}");
      return (n * typelen);
    }
  else
    {
      return (val_print (VALUE_TYPE (val), VALUE_CONTENTS (val),
			 VALUE_ADDRESS (val), stream, format, 1, 0, pretty));
    }
}

static void
printTypedCommand (args, from_tty)
{
  extern struct language_defn c_language_defn;
  extern void print_command (exp, from_tty);

  c_language_defn.la_val_print = my_c_val_print;
  c_language_defn.la_value_print = my_c_value_print;

  print_command (args, from_tty);

  c_language_defn.la_val_print = c_val_print;
  c_language_defn.la_value_print = c_value_print;
}

static void
infoTypedArguments (args, from_tty)
     char *args;
     int from_tty;
{
  extern struct language_defn c_language_defn;

  c_language_defn.la_val_print = my_c_val_print;
  c_language_defn.la_value_print = my_c_value_print;

  args_info (args, from_tty);
  locals_info (args, from_tty);

  c_language_defn.la_val_print = c_val_print;
  c_language_defn.la_value_print = c_value_print;
}

void
_initialize_display ()
{
  add_com ("view", class_files, view_command,
	   "Displays the current line in an editor program;\n the default program is ProjectBuilder.");
  add_com_alias ("v", "view", class_files, 1);
  add_com ("unview", class_files, unview_command,
	   "Stops viewing of source files.");
  if (!view_program)
    view_program = getenv("ViewProgram");
  if (!view_program)
    view_program = (char *)NXGetDefaultValue("gdb", "ViewProgram");
  if (!view_program)
    view_program = savestring("ProjectBuilder", sizeof("ProjectBuilder"));
  if (!view_host)
    view_host = savestring("", sizeof(""));
  add_show_from_set(
    add_set_cmd("view-program", class_files, var_string_noescape, 
                (char *)&view_program,
                "Set name of program to connect to when viewing.",
		&setlist),
    &showlist);		
  add_show_from_set(
    add_set_cmd("view-host", class_files, var_string_noescape,
                (char *)&view_host,
                "Set host to connect to when viewing.",
		&setlist),
    &showlist);

  add_com ("annotation_level", class_support, annotation_level_command,
	   "Sets the annotation level.");
  add_com ("pb_breakpoint_move", class_support, pb_breakpoint_move_command,
	   "<bp_num> <line_number> : moves breakpoint bp_num to line line_number in same file.");

  add_info("typed-variables", infoTypedArguments, "All arguments of the current frame prefixed by their types");

  add_com ("print-typed", class_vars, printTypedCommand,
"Same as \"print\" command, except that shows the type before each printed value.");

}

#ifdef NeXT
/* The vaprintf function is missing from the standard C library, define it here
   using NSString.
 */

int vasprintf (char** ptr, const char* format, va_list ap)
{
  id pool = [NSAutoreleasePool new];
  id string = [[[NSString alloc] initWithFormat:
				  [NSString stringWithCString:format]
				arguments:ap]
		    autorelease];

  if (ptr) {
    *ptr = malloc ([string cStringLength] + 1);
    strcpy (*ptr, [string cString]);
  }

  [pool release];
}

#endif
