/* parsecl.c - command line parser implementation */
#include "cvstags.h"
CVSTAG(parsecl,"$Id: parsecl.c,v 1.21 2005/05/08 23:51:41 knilch Exp $")

/* Ramdefrag Command Line Parser
 *  (c) 2004, 2005 Tobias 'knilch' Jordan <knilch@users.sourceforge.net>
 *
 *  Setting Orange, the 50th day of Chaos in the YOLD 3170
 *  (Celebrate Chaoflux!)
 *
 *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* this was first created by gengetopts, but then heavily, heavily edited
 * by knilch because of the following:
 *  - he didn't like the default texts
 *  - this whole thingy should use PACKAGE_BUGREPORTS etc.
 *  - NLS support
 *  - autoconf/-make optimizations
 *  - support for some tricky specials
 *  - knilch is stupid.
 */

#include <stdio.h>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif

#ifdef HAVE_STRING_H
# include <string.h>
#else
# ifdef HAVE_STRINGS_H
#  include <strings.h>
# endif
#endif

#include "getopt.h"

#include "parsecl.h"

#include "support.h"  /* for gettext-macros _() etc */

#include "clierr.h"

#define UNKNOWN_OPT _("%s: option unknown: %c\n")
#define GTK_CLI_XOR_ONLY _("`--gtk' (`-g') and `--cli' (`-c') can't be used at the same time.")
#define CONF_BATCH_FIN _("warning: `--batchmode' (`-b') already implies `--fin-stats' (`-f')")
#define CONF_BATCH_STAT _("warning: `--batchmode' (`-b') already implies `--nostatus' (`-S')")

void version(void) {
  printf("%s %s\n\n", PACKAGE_NAME, PACKAGE_VERSION);
  printf("%s is free software; see the source for copying conditions.  There is\n"
         "NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
	 PACKAGE_NAME);
}

void usage(char * argz) {
  printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
  printf(_("\n"
  "  a multi platform RAM optimization/defragmentation utility\n"
  "\n"
  "Usage:\n"
  "   %s [OPTIONS]\n"
  "   %s {-c|--cli} [OPTIONS]\n\n"), argz, argz);
  printf(_("General Options:\n"));
  printf(_("   -h  --help       print help and exit\n"));
  printf(_("   -V  --version    print version and exit\n"));
  printf(_("   -H  --nohorsti   don't use H.O.R.S.T.I when not root\n"));
  printf(_("   -n  --dry-run    just simulate optimizing, don't touch RAM\n"));
  printf(_("   -v  --verbose    increase verbosity\n"));
  printf(_("User Interface Options:\n"));
  printf(_("   -g  --gtk        use GTK+ interface (this is the default)\n"));
  printf(_("   -c  --cli        use command line interface\n"));
  printf(_("Command Line Interface Options:\n"));
  printf(_("   -a  --analyze    don't start defragmentation, analyze only [*]\n"));
  printf(_("   -s  --std-alg    use default defragmentation algorithm [*]\n"));
  printf(_("   -d  --deep-alg   use `deep' defragmentation algorithm [*]\n"));
  printf(_("   -o  --opt-alg    use special optimized defragmentation [*]\n"));
  printf(_("     (options marked with `[*]' are mutually exclusive)\n"));
  printf(_("   -p  --progress   show a progress bar made of hash marks (`#')\n"));
  printf(_("   -S  --nostatus   do not show current defragmentation state\n"));
  printf(_("   -f  --statistics\n"
	   "       --fin-stats  show final statistics\n"));
  printf(_("   -b  --batchmode  produce machine readable output (implies -Sf)\n"));
  printf(_("Some GTK-Options:\n"));
  printf(_("       --display, --sync, --no-xshm\n\n"));
  printf(_("Send bugreports/suggestions to <%s>\n"), PACKAGE_BUGREPORT);
}



int parse_cl(int argc, char * const *argv, struct my_args *args_info, int err) {

  int c;	/* Character of the parsed option.  */

  static struct option long_options[] = {
    { "help",		0, NULL, 'h' },
    { "version",	0, NULL, 'V' },
    { "nohorsti",	0, NULL, 'H' },
    { "dry-run",	0, NULL, 'n' },
    { "verbose",	0, NULL, 'v' },
    { "gtk",		0, NULL, 'g' },
    { "cli",		0, NULL, 'c' },
    { "analyze",	0, NULL, 'a' },
    { "std-alg",	0, NULL, 's' },
    { "deep-alg",	0, NULL, 'd' },
    { "opt-alg",	0, NULL, 'o' },
    { "progress",	0, NULL, 'p' },
    { "nostatus",	0, NULL, 'S' },
    { "fin-stats",	0, NULL, 'f' }, { "statistics",	0, NULL, 'f' },
    { "batchmode",	0, NULL, 'b' },
    { NULL,		0, NULL, 0 }
  };

  args_info->nohorsti = 0;
  args_info->dry_run = 0;
  args_info->verboselev = 0;
  args_info->gtk = 0;
  args_info->cli = 0;
  args_info->ui = 0;
  args_info->nostat = 0;
  args_info->prog = 0;
  args_info->finalstat = 0;
  args_info->batchmode = 0;
  args_info->alg = '\0';

  optarg = 0;
  optind = 1;
  opterr = err;
  optopt = '?';

  while (42) {

    c = getopt_long(argc, argv, "hVHnvgcasdopSfb", long_options, NULL);

    if (c == -1) break;	/* Exit from `while (42)' loop.  */

    switch (c) {
      case 'h':	/* Print help and exit.  */
	usage(argv[0]);
	exit(EXIT_SUCCESS);

      case 'V':	/* Print version and exit.  */
	version();
	exit(EXIT_SUCCESS);

      case 'H':	/* don't use H.O.R.S.T.I when not root.  */
	if (args_info->nohorsti) {
	  clierr(_("`--nohorsti' (`-H') option given more than once"));
	  exit(EXIT_FAILURE);
	}
	args_info->nohorsti = 1;
	break;

      case 'g':	/* use GTK  */
	if (args_info->gtk) {
	  clierr(_("`--gtk' (`-g') option given more than once"));
	  exit(EXIT_FAILURE);
	}
	if (args_info->cli) {
	  clierr(GTK_CLI_XOR_ONLY);
	  exit(EXIT_FAILURE);
	}
	args_info->gtk = 1;
	break;

      case 'c':	/* CLI */
	if (args_info->cli) {
	  clierr(_("`--cli' (`-c') option given more than once"));
	  exit(EXIT_FAILURE);
	}
	if (args_info->gtk) {
	  clierr(GTK_CLI_XOR_ONLY);
	  exit(EXIT_FAILURE);
	}
	args_info->cli = 1;
	break;

      case 's':
      case 'd':
      case 'o':
      case 'a':
	if (! (args_info->cli)) {
	  clierr(_("CLI options need option `--cli' (`-c') first"));
	  exit(EXIT_FAILURE);
	}
	if (args_info->alg) {
	  clierr(_("options for algorithm selection are mutually exclusive "
                                         "and can't be given more than once"));
	  /* as above error message may not be very descriptive */
	  press_h_for_help(argv[0]);
	  exit(EXIT_FAILURE);
	}
	args_info->alg = c;
	break;

      case 'p':
	if (! (args_info->cli)) {
	  clierr(_("CLI options need option `--cli' (`-c') first"));
	  exit(EXIT_FAILURE);
	}
	if (args_info->prog) {
	  clierr(_("`--progress' (`-p') option given more than once"));
	  exit(EXIT_FAILURE);
	}
	args_info->prog = 1;
        break;

      case 'S':
	if (! (args_info->cli)) {
	  clierr(_("CLI options need option `--cli' (`-c') first"));
	  exit(EXIT_FAILURE);
	}
	if (args_info->nostat) {
	  if (args_info->batchmode) {
	    clierr(CONF_BATCH_STAT);
	  } else {
	    clierr(_("`--nostatus' (`-S') option given more than once"));
            exit(EXIT_FAILURE);
	  }
	}
	args_info->nostat = 1;
        break;

      case 'f':
	if (! (args_info->cli)) {
	  clierr(_("CLI options need option `--cli' (`-c') first"));
	  exit(EXIT_FAILURE);
	}
	if (args_info->finalstat) {
          if (args_info->batchmode) {
            clierr(CONF_BATCH_FIN);
	  } else {
            clierr(_("`--fin-stats' (`-f') option given more than once"));
            exit(EXIT_FAILURE);
	  }
	}
	args_info->finalstat = 1;
        break;

      case 'b':
	if (! (args_info->cli)) {
	  clierr(_("CLI options need option `--cli' (`-c') first"));
	  exit(EXIT_FAILURE);
	}
	if (args_info->batchmode) {
	  clierr(_("`--batchmode' (`-b') option given more than once"));
	  exit(EXIT_FAILURE);
	}
	if ((args_info->nostat) && (err)) {
	  clierr(CONF_BATCH_STAT);
	} else {
          args_info->nostat = 1;
	}
	if ((args_info->finalstat) && (err)) {
	  clierr(CONF_BATCH_FIN);
	} else {
	  args_info->finalstat = 1;
	}
	args_info->batchmode = 1;
        break;

      case 'n':	/* just simulate optimizing, don't touch RAM.  */
	if (args_info->dry_run) {
	  clierr(_("`--dry-run' (`-n') option given more than once"));
	  exit(EXIT_FAILURE);
	}
	args_info->dry_run = 1;
	break;

      case 'v':	/* be verbose.  */
	args_info->verboselev++;
	break;

      case 0:	/* Long option with no short option */

      case '?':	/* Invalid option. */
	if (err) {
          /* getopt already prints an error message */
	  press_h_for_help(argv[0]);
	  return 5;
	}
	break;

      default:	/* bug: option not considered. */
	if (err) {
	  fprintf(stderr, "* ");
	  fprintf(stderr, UNKNOWN_OPT, PACKAGE_NAME, c);
	  press_h_for_help(argv[0]);
	  return 5;
	}
    } /* switch */
  } /* while */

  args_info->ui = (args_info->cli) ? USE_CL_UI : USE_GTK_UI;

  return 0;
}

