/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * 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.
 */
#include "config.h"
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#ifndef  WAIT_ANY
#define  WAIT_ANY -1
#endif   /*  WAIT_ANY  */

#include "appenv.h"
#include "app_procs.h"
#include "errors.h"
#include "install.h"
#include "tile.h"

static RETSIGTYPE on_signal (int);
static RETSIGTYPE on_sig_child (int);
static void       init (void);

/* GLOBAL data */
int no_interface;
int no_data;
int no_splash;
int no_splash_image;
int be_verbose;
int use_shm;
char *prog_name;		/* The path name we are invoked with */
char **batch_cmds;

/* LOCAL data */
static int gimp_argc;
static char **gimp_argv;

/*
 *  argv processing: 
 *      Arguments are either switches, their associated
 *      values, or image files.  As switches and their
 *      associated values are processed, those slots in
 *      the argv[] array are NULLed.
 *
 *      The GTK switches are processed first (X switches are
 *      processed here, not by any X routines).  Then the
 *      general GIMP switches are processed.  Any args
 *      left are assumed to be image files the GIMP should
 *      display.
 *
 *      The exception is the batch switch.  When this is
 *      encountered, all remaining args are treated as batch
 *      commands.
 */

int
main (int argc, char **argv)
{
  int show_version;
  int show_help;
  int i, j;
  gchar *display_name, *display_env;

  atexit (g_mem_profile);

  /* Initialize variables */
  prog_name = argv[0];

  /* Initialize Gtk toolkit */
  gtk_set_locale ();
  setlocale(LC_NUMERIC, "C");  /* must use dot, not comma, as decimal separator */
  gtk_init (&argc, &argv);
  gtk_accelerator_table_set_mod_mask (NULL, GDK_SHIFT_MASK |
                                            GDK_CONTROL_MASK |
                                            GDK_MOD1_MASK);

  display_name = gdk_get_display ();
  display_env = g_new (gchar, strlen (display_name) + 9);
  *display_env = 0;
  strcat (display_env, "DISPLAY=");
  strcat (display_env, display_name);
  putenv (display_env);

  no_interface = FALSE;
  no_data = FALSE;
  no_splash = FALSE;
  no_splash_image = FALSE;
  use_shm = TRUE;
  batch_cmds = g_new (char*, argc);
  batch_cmds[0] = NULL;

  show_version = FALSE;
  show_help = FALSE;

  for (i = 1; i < argc; i++)
    {
      if ((strcmp (argv[i], "--no-interface") == 0) ||
	  (strcmp (argv[i], "-n") == 0))
	{
	  no_interface = TRUE;
	  argv[i] = NULL;
	}
      else if ((strcmp (argv[i], "--batch") == 0) ||
	       (strcmp (argv[i], "-b") == 0))
	{
	  argv[i] = NULL;
	  for (j = 0, i++ ; i < argc; j++, i++)
	    {
	      batch_cmds[j] = argv[i];
	      argv[i] = NULL;
	    }
	  batch_cmds[j] = NULL;
	}
      else if ((strcmp (argv[i], "--help") == 0) ||
	       (strcmp (argv[i], "-h") == 0))
	{
	  show_help = TRUE;
	}
      else if (strcmp (argv[i], "--version") == 0 ||
	       strcmp (argv[i], "-v") == 0)
	{
	  show_version = TRUE;
	}
      else if (strcmp (argv[i], "--no-data") == 0)
	{
	  no_data = TRUE;
	}
      else if (strcmp (argv[i], "--no-splash") == 0)
	{
	  no_splash = TRUE;
	}
      else if (strcmp (argv[i], "--no-splash-image") == 0)
	{
	  no_splash_image = TRUE;
	}
      else if (strcmp (argv[i], "--verbose") == 0)
	{
	  be_verbose = TRUE;
	}
      else if (strcmp (argv[i], "--no-shm") == 0)
	{
	  use_shm = FALSE;
	}
/*
 *    ANYTHING ELSE starting with a '-' is an error.
 */
      else if (argv[i][0] == '-')
	{
	  show_help = TRUE;
	}
    }

  if (show_version)
    g_print ("GIMP version " VERSION "\n");

  if (show_help)
    {
      g_print ("\007Usage: %s [option ...] [files ...]\n", argv[0]);
      g_print ("Valid options are:\n");
      g_print ("  -h --help              Output this help.\n");
      g_print ("  -v --version           Output version info.\n");
      g_print ("  -b --batch <commands>  Run in batch mode.\n");
      g_print ("  -n --no-interface      Run without a user interface.\n");
      g_print ("  --no-data              Do not load patterns, gradients, palettes, brushes.\n");
      g_print ("  --verbose              Show startup messages.\n");
      g_print ("  --no-splash            Do not show the startup window.\n");
      g_print ("  --no-splash-image      Do not add an image to the startup window.\n");
      g_print ("  --no-shm               Do not use shared memory between GIMP and its plugins.\n");
      g_print ("  --no-xshm              Do not use the X Shared Memory extension.\n");
      g_print ("  --display <display>    Use the designated X display.\n\n");

    }

  if (show_version || show_help)
    exit (0);

  /* Handle some signals */
  signal (SIGHUP, on_signal);
  signal (SIGINT, on_signal);
  signal (SIGQUIT, on_signal);
  signal (SIGABRT, on_signal);
  signal (SIGBUS, on_signal);
  signal (SIGSEGV, on_signal);
  signal (SIGPIPE, on_signal);
  signal (SIGTERM, on_signal);
  signal (SIGFPE, on_signal);

  /* Handle child exits */
  signal (SIGCHLD, on_sig_child);

  /* Keep the command line arguments--for use in gimp_init */
  gimp_argc = argc - 1;
  gimp_argv = argv + 1;

  /* Check the installation */
  install_verify (init);

  /* Main application loop */
  if (!app_exit_finish_done ())
    gtk_main ();
  
  return 0;
}

static void
init ()
{
  /*  Continue initializing  */
  gimp_init (gimp_argc, gimp_argv);
}

static int caught_fatal_sig = 0;

static RETSIGTYPE
on_signal (int sig_num)
{
  char *sig;

  if (caught_fatal_sig)
/*    raise (sig_num);*/
    kill (getpid (), sig_num);
  caught_fatal_sig = 1;

  switch (sig_num)
    {
    case SIGHUP:
      sig = "sighup";
      break;
    case SIGINT:
      sig = "sigint";
      break;
    case SIGQUIT:
      sig = "sigquit";
      break;
    case SIGABRT:
      sig = "sigabrt";
      break;
    case SIGBUS:
      sig = "sigbus";
      break;
    case SIGSEGV:
      sig = "sigsegv";
      break;
    case SIGPIPE:
      sig = "sigpipe";
      break;
    case SIGTERM:
      sig = "sigterm";
      break;
    case SIGFPE:
      sig = "sigfpe";
      break;
    default:
      sig = "unknown signal";
      break;
    }

  fatal_error ("%s caught", sig);
}

static RETSIGTYPE
on_sig_child (int sig_num)
{
  int pid;
  int status;

  while (1)
    {
      pid = waitpid (WAIT_ANY, &status, WNOHANG);
      if (pid <= 0)
	break;
    }
}
