/*
    Copyright (C) 1998 by Jorrit Tyberghein
    Written by Andrew Zabolotny

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdio.h>

#define SYSDEF_GETOPT
#include "sysdef.h"
#include "cscom/com.h"

char *programversion = "0.0.1";
char *programname;

static struct option long_options[] =
{
  {"help", no_argument, 0, 'h'},
  {"register", no_argument, 0, 'r'},
  {"unregister", no_argument, 0, 'u'},
  {"version", no_argument, 0, 1},
  {"verbose", no_argument, 0, 'v'},
  {0, no_argument, 0, 0}
};

static void display_help ()
{
  printf ("Crystal Space COM object registration utility v%s\n", programversion);
  printf ("Copyright (C) 1998,1999 by Jorrit Tyberghein and others\n\n");
  printf ("Usage: %s {option/s} [shared library] [...]\n\n", programname);
  printf ("By default the program will register the COM components contained in the shared\n");
  printf ("library passed on command line; if Crystal Space was compiled with private\n");
  printf ("COM support (i.e. not system-wide), it will register the component(s) in the\n");
  printf ("configuration file passed in the -c switch (default is csCOM.cfg)\n\n");
  printf ("  -r   --register    Register COM components contained in file #\n");
  printf ("  -u   --unregister  Unregister COM components contained in file #\n");
  printf ("  -h   --help        Display this help text\n");
  printf ("  -v   --verbose     Comment on what's happening\n");
  printf ("       --version     Display program version\n");
  exit (1);
}

static bool verbose = false;

static bool RegisterServer (char *SharedLibraryFilename, bool Register)
{
  if (verbose)
  {
    printf ("Loading shared library %s ...", SharedLibraryFilename);
    fflush (stdout);
  } /* endif */

  CS_HLIBRARY Handle = csLoadLibrary (SharedLibraryFilename);

  if (!Handle)
  {
    if (verbose)
      printf (" FAILED\n");
    else
      printf ("ERROR: Failed to load library \"%s\"\n", SharedLibraryFilename);
    fflush (stdout);
    return false;
  } /* endif */

  if (verbose)
  {
    printf ("OK, handle = %08lX\n", Handle);
    fflush (stdout);
  } /* endif */

  char *entry;
  if (Register)
    entry = "DllRegisterServer";
  else
    entry = "DllUnregisterServer";

  if (verbose)
  {
    printf ("Looking for \"%s\" entry ...", entry);
    fflush (stdout);
  } /* endif */

  PROC pEntry = csGetProcAddress (Handle, entry);

  if (!pEntry)
  {
    if (verbose)
      printf (" FAILED\n");
    else
      printf ("ERROR: Failed to find entry \"%s\" in library \"%s\"\n", entry, SharedLibraryFilename);
    fflush (stdout);
    return false;
  } /* endif */

  if (verbose)
  {
    printf ("OK, address = %08lX\n", (unsigned long)pEntry);
    printf ("Calling the \"%s\" entry ...", entry);
    fflush (stdout);
  } /* endif */

  HRESULT hRes = pEntry ();
  if (FAILED (hRes))
  {
    if (verbose)
      printf (" FAILED\n");
    else
      printf ("ERROR: Library \"%s\" failed to register in COM class registry!\n", SharedLibraryFilename);
    fflush (stdout);
    return false;
  } /* endif */

  if (verbose)
  {
    printf ("OK\n");
    printf ("Unloading library \"%s\"...", SharedLibraryFilename);
    fflush (stdout);
  } /* endif */

  if (!csFreeLibrary (Handle))
  {
    if (verbose)
      printf (" FAILED\n");
    else
      printf ("WARNING: Unable to unload library \"%s\"!\n", SharedLibraryFilename);
  }
  else if (verbose)
    printf ("OK\n");

  printf ("Library \"%s\" successfully %sregistered\n", SharedLibraryFilename,
    Register ? "" : "de");
  fflush (stdout);
  return true;
}

int main (int argc, char *argv[])
{
#if defined (__EMX__)	// Expand wildcards on OS/2+GCC+EMX
  _wildcard (&argc, &argv);
#endif

  int operation = 1;
  programname = argv [0];

  int c;
  while ((c = getopt_long (argc, argv, "ruhv", long_options, NULL)) != EOF)
    switch (c)
    {
      case '?':
        // unknown option
        return -1;
      case 'r':
        operation = 1;
        break;
      case 'u':
        operation = 2;
        break;
      case 'h':
        display_help ();
        break;
      case 'v':
        verbose = true;
        break;
      case 1:
        printf ("%s version %s\n\n", programname, programversion);
        printf ("This program is distributed in the hope that it will be useful,\n");
        printf ("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
        printf ("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
        printf ("GNU Library General Public License for more details.\n");
        return 0;
    } /* endswitch */

  // Interpret the non-option arguments as file names
  bool did_something = false;
  for (; optind < argc; ++optind)
    switch (operation)
    {
      case 1:
        did_something = true;
        RegisterServer (argv [optind], true);
        break;
      case 2:
        did_something = true;
        RegisterServer (argv [optind], false);
        break;
    } /* endswitch */

  if (!did_something)
    display_help ();

  return 0;
}
