/* This file is part of GNU Rush.
   Copyright (C) 2008-2025 Sergey Poznyakoff

   GNU Rush 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 3, or (at your option)
   any later version.

   GNU Rush 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 GNU Rush.  If not, see <http://www.gnu.org/licenses/>. */

#include <rush.h>
#include "error.h"
#include <parseopt.h>

char *base_name = RUSH_DB;
struct rush_wtmp *wtmp = NULL;
int  display_header = 1;  /* Display header line */
char *format;

static int
optset_zero(struct parseopt *po, struct optdef *opt, char *arg)
{
	*(int*) opt->opt_ptr = 0;
	return 0;
}

static struct optdef options[] = {
	{
		.opt_name = "format",
		.opt_argdoc = N_("STRING"),
		.opt_doc = N_("Use STRING instead of the default format."),
		.opt_set = optset_string_copy,
		.opt_ptr = &format
	},
	{
		.opt_name = "F",
		.opt_flags = OPTFLAG_ALIAS
	},

	{
		.opt_name = "file",
		.opt_argdoc = N_("DIR"),
		.opt_doc = N_("Look for database files in DIR."),
		.opt_set = optset_string_copy,
		.opt_ptr = &base_name
	},
	{
		.opt_name = "f",
		.opt_flags = OPTFLAG_ALIAS
	},

	{
		.opt_name = "no-header",
		.opt_doc = N_("Do not display header line."),
		.opt_set = optset_zero,
		.opt_ptr = &display_header
	},
	{
		.opt_name = "H",
		.opt_flags = OPTFLAG_ALIAS
	},

	{ NULL }
}, *optdef[] = { options, NULL };

extern void version_hook(WORDWRAP_FILE wf, struct parseopt *po);

static struct parseopt po = {
	.po_descr = N_("show listing of online rush users."),
	.po_optdef = optdef,
	.po_package_name = PACKAGE_NAME,
	.po_package_url = PACKAGE_URL,
	.po_bugreport_address = PACKAGE_BUGREPORT,
	.po_version_hook = version_hook
};

void
xalloc_die()
{
	error(1, 0, _("not enough memory"));
	abort();
}


char *default_format =
	"(user 10 Login) "
	"(rule 8 Rule) "
	"(start-time 0 Start) "
	"(duration 10 Time) "
	"(pid 10 PID) "
	"(command 28 Command)";

int
main(int argc, char **argv)
{
	int status;
	rushdb_format_t form;

	rush_set_program_name(argv[0]);
	rush_i18n_init();

	format = getenv("RUSHWHO_FORMAT");
	if (!format)
		format = default_format;

	if (parseopt_getopt(&po, argc, argv) == OPT_ERR)
		error(1, errno, "%s", _("parseopt_getopt failed"));
	parseopt_argv(&po, &argc, &argv);
	parseopt_free(&po);

	if (argc)
		error(1, 0, _("extra arguments"));

	if (format[0] == '@')
		format = rush_read_format(format + 1);
	form = rushdb_compile_format(format);
	if (!form)
		error(1, 0, _("invalid format: %s"), rushdb_error_string);

	switch (rushdb_open(base_name, 0)) {
	case rushdb_result_ok:
		break;

	case rushdb_result_eof:
		exit(0);

	case rushdb_result_fail:
		error(1, errno, _("cannot open database file %s"), base_name);
	}

	if (display_header)
		rushdb_print_header(form);
	while (rush_utmp_read(RUSH_STATUS_MAP_BIT(RUSH_STATUS_INUSE),
			      &status, &wtmp) == rushdb_result_ok) {

		rushdb_print(form, wtmp, 1);
		free(wtmp);
	}

	rushdb_close();

	exit(0);
}
