/* main.c	8/19/1995
 * The `main()' function for `hexer'.
 */

/* SPDX-FileCopyrightText: 1995,1996 Sascha Demetrio
 * SPDX-FileCopyrightText: 2009, 2010, 2015 Peter Pentchev
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>

#ifndef HEXER_LONG_OPTIONS
#define HEXER_LONG_OPTIONS 0
#endif

#if HEXER_LONG_OPTIONS
#include <getopt.h>
#endif

#ifndef HEXER_MAX_STARTUP_COMMANDS
#define HEXER_MAX_STARTUP_COMMANDS 256
#endif

#include "buffer.h"
#include "hexer.h"
#include "exh.h"
#include "readline.h"
#include "regex.h"
#include "set.h"
#include "signal.h"
#include "tio.h"

static const char *usage_message = "\
hexer - a binary file editor\n\
usage: hexer [options] [file [...]]\n\
  -R/--readonly\n\
  -v/--view\n\
      Edit files in read-only mode.\n\
  -r/--recover filename\n\
      Recover  the  file filename after a crash. (not implemented)\n\
  -c/--command command\n\
      Start the editing session by executing the editor command\n\
      `command'.  If command contains whitespace, the whitespace\n\
      should be quoted.\n\
  -t/--tite\n\
      Turn off the usage of the termcap/terminfo ti/te sequence.\n\
  -h/--help\n\
      Display a short help message and exit.\n\
  -V/--version\n\
      Display program version information and exit.\n\
  -F/--features\n\
      List the features supported by the program and exit.\n\
  +command\n\
      This is equivalent to the -c option.\n\
  Note: The long options are not available on all systems.\n";

#if HEXER_LONG_OPTIONS
static struct option longopts[] = {
  { "readonly", 0, 0, 'R' },
  { "view", 0, 0, 'v' },
  { "recover", 1, 0, 'r' },  /* recover from the given file. */
  { "command", 1, 0, 'c' },  /* the given command is executed in the first
                              * buffer. */
  { "help", 0, 0, 'h' },     /* print a short help message to `stdout'. */
  { "tite", 0, 0, 't' },     /* tite - turn off the ti/te sequence. */
  { "version", 0, 0, 'V' },  /* print program version information. */
  { "features", 0, 0, 'F' }, /* display program features information. */
  { 0, 0, 0, 0 }
};
#endif /* HEXER_LONG_OPTIONS */

static const char *shortopts = "Rvr:c:dthVF";

static int hexer_readonly;

static char *startup_commands[HEXER_MAX_STARTUP_COMMANDS];
static int startup_commands_n = 0;

static int tio_initialized = 0;

  static int
process_args(const int argc, char * const argv[])
{
  int c, i;
  int exit_f = 0;
  char *first_buffer = 0;
  int open_f = 0;
#if HEXER_LONG_OPTIONS
  int longopt_idx;
#endif

  /* set default options */
  hexer_readonly = 0;

  for (; !exit_f;) {
    if (optind >= argc) break;
    if (*argv[optind] == '+') {
      if (!argv[optind][1])
        startup_commands[startup_commands_n++] = argv[++optind];
      else
        startup_commands[startup_commands_n++] = argv[optind] + 1;
      ++optind;
      continue;
    }
#if HEXER_LONG_OPTIONS
    c = getopt_long(argc, argv, shortopts, longopts, &longopt_idx);
#else
    c = getopt(argc, argv, shortopts);
#endif
    if (c < 0) break;
    switch (c) {
      case 'v':
      case 'R': /* readonly */
        hexer_readonly = 1;
	break;
      case 'r': /* recover */
        printf("recover from file `%s'.\n", optarg);
	break;
      case 'c': /* command */
        startup_commands[startup_commands_n++] = optarg;
	break;
      case 'd': /* debug */
        setbuf(stdout, 0);
        break;
      case 't': /* tite - turn off the ti/te sequence */
        ++tio_tite_f;
        break;
      case 'h': /* help */
        puts(usage_message);
	exit_f = 1;
	break;
      case 'V':
	puts("hexer " HEXER_VERSION);
	exit_f = 1;
	break;
      case 'F':
	puts("Features: hexer=" HEXER_VERSION);
	exit_f = 1;
	break;
      default:
        fputs(usage_message, stderr);
	exit_f = 2;
	break;
    }
  }

  if (!exit_f) {
    if (tio_init(*argv) < 0) exit(1);
    tio_initialized = 1;
    if (optind < argc) /* read the files */
      while (optind < argc) {
        if (!he_open_buffer(argv[optind], argv[optind])) {
          open_f = 1;
          if (!first_buffer) first_buffer = argv[optind];
          if (hexer_readonly) he_set_buffer_readonly(argv[optind]);
        }
        ++optind;
      }
    if (!open_f) /* create an empty buffer */
      he_open_buffer("*scratch*", 0);
    if (first_buffer) he_select_buffer(first_buffer);
    /* execute the startup commands (if any).  some of the startup commands
     * may open or close buffers or even quit the editor, so we have to
     * check if `current_buffer' is 0 after each command. */
    hexer_init();
    if (startup_commands_n && current_buffer)
      for (i = 0; i < startup_commands_n; ++i) {
	// I think this is a false positive - current_buffer is global! :)
	// cppcheck-suppress nullPointer
        exh_command(current_buffer->hedit, startup_commands[i]);
        if (!current_buffer) break;
      }
    if (current_buffer) he_status_message(0);
  } else
    exit_f--;
  return exit_f;
}
/* process_args */

  static void
setup_screen(void)
{
  int fg, bg;

  if (tio_have_color()) {
    fg = s_get_option_integer("fg");
    bg = s_get_option_integer("bg");
    tio_set_colors(fg, bg);
    tio_flush();
  }
}
/* setup_screen */

  int
main(const int argc, char * const argv[])
{
  int exit_f;

  /* configure readline */
  rl_backspace_jump = 5;
  rl_cancel_on_bs = 1;
  completer = exh_completer;

  rx_interrupt = &caught_sigint;
  tio_interrupt = &caught_sigint;
  he_messages = 0;
  setup_signal_handlers();
  hexer_version();
  if ((exit_f = process_args(argc, argv)) ? 1 : !current_buffer) {
    if (tio_initialized)
      tio_reset();
    exit(exit_f);
  }
  tio_start_application();
  tio_echo(0);
  setup_screen();
  hexer();
  tio_echo(1);
  tio_goto_line(hx_lines - 1);
  tio_return();
  tio_end_application();
  tio_reset_attributes();
  tio_reset();
  return 0;
}
/* main */

/* end of main.c */


/* VIM configuration: (do not delete this line)
 *
 * vim:bk:nodg:efm=%f\:%l\:%m:hid:icon:
 * vim:sw=2:sm:textwidth=79:ul=1024:wrap:
 */
