/*
 *      fhist - file history and comparison tools
 *      Copyright (C) 1991-1995, 1998, 2000, 2002, 2004, 2005 Peter Miller;
 *      All rights reserved.
 *
 *      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, USA.
 *
 * MANIFEST: functions to provide consistent treatment of -Help options
 */

#include <ac/stdlib.h>
#include <ac/unistd.h>

#include <arglex.h>
#include <env.h>
#include <error.h>
#include <error_intl.h>
#include <help.h>
#include <libdir.h>
#include <progname.h>
#include <quit.h>
#include <str_list.h>
#include <trace.h>


static void
help_env(void)
{
    char            *cp;
    string_list_ty  manpath;
    string_ty       *s;
    string_list_ty  lib;
    string_list_ty  lang;
    size_t          j, k;
    string_list_ty  wl;

    /*
     * Honour any existing MANPATH setting by appending only.
     * Read the MANPATH to set the initial path.
     */
    cp = getenv("MANPATH");
    if (cp)
    {
        s = str_from_c(cp);
        str2wl(&manpath, s, ":", 0);
        str_free(s);
    }
    else
    {
        string_list_constructor(&manpath);
        s = str_from_c("/usr/man");
        string_list_append(&manpath, s);
        str_free(s);

        s = str_from_c("/usr/share/man");
        string_list_append(&manpath, s);
        str_free(s);
    }

    /*
     * The list of library directories to look in.
     */
    string_list_constructor(&lib);
    s = str_from_c(configured_datadir());
    string_list_append_unique(&lib, s);
    str_free(s);
    cp = getenv("FHIST_MESSAGE_LIBRARY");
    if (cp)
    {
        s = str_from_c(cp);
        str2wl(&wl, s, ":", 0);
        for (j = 0; j < wl.nstrings; ++j)
            string_list_append_unique(&lib, wl.string[j]);
        string_list_destructor(&wl);
    }

    /*
     * Use the LANGUAGE (or LANG) environment
     * variables to know which languages to add.
     * Default to "en" if not set.
     */
    string_list_constructor(&lang);
    cp = getenv("LANGUAGE");
    if (cp)
    {
        s = str_from_c(cp);
        str2wl(&wl, s, ":", 0);
        for (j = 0; j < wl.nstrings; ++j)
            string_list_append_unique(&lang, wl.string[j]);
        string_list_destructor(&wl);
    }
    cp = getenv("LANG");
    if (cp)
    {
        s = str_from_c(cp);
        str2wl(&wl, s, ":", 0);
        for (j = 0; j < wl.nstrings; ++j)
            string_list_append_unique(&lang, wl.string[j]);
        string_list_destructor(&wl);
    }
    if (!lang.nstrings)
    {
        s = str_from_c("en");
        string_list_append(&lang, s);
        str_free(s);
    }

    /*
     * convolve the lib and lang lists and append them to the manpath
     */
    for (j = 0; j < lib.nstrings; ++j)
    {
        string_list_append_unique(&manpath, lib.string[j]);
        for (k = 0; k < lang.nstrings; ++k)
        {
            s = str_format("%S/%S", lib.string[j], lang.string[k]);
            string_list_append_unique(&manpath, s);
            str_free(s);
        }
    }
    string_list_destructor(&lib);
    string_list_destructor(&lang);

    s = str_from_c(configured_mandir());
    string_list_append_unique(&lib, s);
    str_free(s);

    /*
     * set the MANPATH environment variable
     */
    s = wl2str(&manpath, 0, manpath.nstrings, ":");
    string_list_destructor(&manpath);
    env_set("MANPATH", s->str_text);
    str_free(s);
}


void
help(char *progname, void (*usage)(void))
{
    char            *argv[3];
    sub_context_ty  *scp;

    /*
     * collect the rest of the command line,
     * if necessary
     */
    if (usage)
    {
        arglex();
        while (arglex_token != arglex_token_eoln)
            bad_argument(usage);
    }
    if (!progname)
        progname = progname_get();

    /*
     * set the MANPATH environment variable
     * to point into the libraries
     */
    help_env();

    /*
     * Invoke the appropriate ``man'' command.  This will find the
     * right language on the search path, and it already knows how
     * to translate the *roff into text.
     */
    argv[0] = "man";
    argv[1] = progname;
    argv[2] = 0;
    error_raw("%s %s", argv[0], argv[1]);
    execvp(argv[0], argv);
    scp = sub_context_new();
    sub_errno_set(scp);
    sub_var_set_charstar(scp, "File_Name", argv[0]);
    fatal_intl(scp, i18n("exec \"$filename\": $errno"));
    /* NOTREACHED */
}


void
bad_argument(void (*usage)(void))
{
    sub_context_ty  *scp;

    trace(("bad_argument()\n{\n"));
    switch (arglex_token)
    {
    case arglex_token_string:
        scp = sub_context_new();
        sub_var_set_charstar(scp, "File_Name", arglex_value.alv_string);
        error_intl(scp, i18n("misplaced file name (\"$filename\")"));
        sub_context_delete(scp);
        break;

    case arglex_token_number:
        scp = sub_context_new();
        sub_var_set_charstar(scp, "Number", arglex_value.alv_string);
        error_intl(scp, i18n("misplaced number ($number)"));
        sub_context_delete(scp);
        break;

    case arglex_token_option:
        scp = sub_context_new();
        sub_var_set_charstar(scp, "Name", arglex_value.alv_string);
        error_intl(scp, i18n("unknown \"$name\" option"));
        sub_context_delete(scp);
        break;

    case arglex_token_eoln:
        error_intl(0, i18n("command line too short"));
        break;

    default:
        scp = sub_context_new();
        sub_var_set_charstar(scp, "Name", arglex_token_name(arglex_token));
        error_intl(scp, i18n("misplaced \"$name\" option"));
        sub_context_delete(scp);
        break;
    }
    usage();
    trace(("}\n"));
    quit(1);
    /* NOTREACHED */
}


void
mutually_exclusive(int arg1, int arg2, void (*usage)(void))
{
    sub_context_ty  *scp;

    scp = sub_context_new();
    sub_var_set_charstar(scp, "Name1", arglex_token_name(arg1));
    sub_var_set_charstar(scp, "Name2", arglex_token_name(arg2));
    error_intl(scp, i18n("$name1 and $name2 mutually exclusive"));
    sub_context_delete(scp);
    usage();
    quit(1);
}


syntax highlighted by Code2HTML, v. 0.9.1