//
// tardy - a tar post-processor
// Copyright (C) 1993-1996, 1998, 1999, 2001-2004, 2008, 2009, 2011 Peter Miller
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//

#include <libtardy/ac/stdio.h>
#include <libtardy/ac/stdlib.h>
#include <libexplain/output.h>

#include <libtardy/tar/input/filenamelist.h>
#include <libtardy/trace.h>

#include <tardy/arglex/tardy.h>
#include <tardy/ifmt.h>
#include <tardy/tardy.h>


int
main(int argc, char **argv)
{
    arglex_tardy command_line(argc, argv);
    switch (command_line.lex())
    {
    case arglex::token_help:
        command_line.help();
        exit(0);

    case arglex::token_version:
        command_line.version();
        exit(0);

    default:
        break;
    }
    const char *infile = 0;
    const char *outfile = 0;
    while (command_line.get_token() != arglex::token_eoln)
    {
        trace(("token = %d\n", command_line.token));
        switch (command_line.get_token())
        {
        default:
            explain_output_error
            (
                "misplaced %s command line argument",
                rcstring(command_line.get_value_string()).quote_c().c_str()
            );
            command_line.usage();

        case arglex::token_string:
            if (!infile)
                infile = command_line.get_value_string();
            else if (!outfile)
                outfile = command_line.get_value_string();
            else
            {
                explain_output_error("too many file names specified");
                command_line.usage();
            }
            break;

        case arglex::token_stdio:
            if (!infile)
                infile = "";
            else if (!outfile)
                outfile = "";
            else
            {
                explain_output_error("too many file names specified");
                command_line.usage();
            }
            break;

        case arglex_tardy::token_user:
            switch (command_line.lex())
            {
            default:
                explain_output_error
                (
                    "the -User option requires a string or numeric argument"
                );
                command_line.usage();

            case arglex::token_string:
                tardy_user_name_by_string(command_line.get_value_string());
                tardy_user_number_by_string(command_line.get_value_string());
                break;

            case arglex::token_number:
                tardy_user_name_by_number(command_line.get_value_number());
                tardy_user_number_by_number(command_line.get_value_number());
                break;
            }
            break;

        case arglex_tardy::token_user_name:
            switch (command_line.lex())
            {
            default:
                explain_output_error
                (
                   "the -User_NAme option requires a string or numeric argument"
                );
                command_line.usage();

            case arglex::token_string:
                tardy_user_name_by_string(command_line.get_value_string());
                break;

            case arglex::token_number:
                tardy_user_name_by_number(command_line.get_value_number());
                break;
            }
            break;

        case arglex_tardy::token_user_number:
            switch (command_line.lex())
            {
            default:
                explain_output_error
                (
                 "the -User_NUmber option requires a string or numeric argument"
                );
                command_line.usage();

            case arglex::token_string:
                tardy_user_number_by_string(command_line.get_value_string());
                break;

            case arglex::token_number:
                tardy_user_number_by_number(command_line.get_value_number());
                break;
            }
            break;

        case arglex_tardy::token_group:
            switch (command_line.lex())
            {
            default:
                explain_output_error
                (
                    "the -Group option requires a string or numeric argument"
                );
                command_line.usage();

            case arglex::token_string:
                tardy_group_name_by_string(command_line.get_value_string());
                tardy_group_number_by_string(command_line.get_value_string());
                break;

            case arglex::token_number:
                tardy_group_name_by_number(command_line.get_value_number());
                tardy_group_number_by_number(command_line.get_value_number());
                break;
            }
            break;

        case arglex_tardy::token_group_name:
            switch (command_line.lex())
            {
            default:
                explain_output_error
                (
                  "the -Group_NAme option requires a string or numeric argument"
                );
                command_line.usage();

            case arglex::token_string:
                tardy_group_name_by_string(command_line.get_value_string());
                break;

            case arglex::token_number:
                tardy_group_name_by_number(command_line.get_value_number());
                break;
            }
            break;

        case arglex_tardy::token_group_number:
            switch (command_line.lex())
            {
            default:
                explain_output_error
                (
                "the -Group_NUmber option requires a string or numeric argument"
                );
                command_line.usage();

            case arglex::token_string:
                tardy_group_number_by_string(command_line.get_value_string());
                break;

            case arglex::token_number:
                tardy_group_number_by_number(command_line.get_value_number());
                break;
            }
            break;

        case arglex_tardy::token_prefix:
            if (command_line.lex() != arglex::token_string)
            {
                explain_output_error
                (
                    "the -Prefix option requires a string argument"
                );
                command_line.usage();
            }
            tardy_prefix(command_line.get_value_string());
            break;

        case arglex_tardy::token_remove_prefix:
            switch (command_line.lex())
            {
            case arglex::token_string:
                tardy_remove_prefix(command_line.get_value_string());
                break;

            case arglex::token_number:
                tardy_remove_prefix(command_line.get_value_number());
                break;

            default:
                explain_output_error
                (
                    "the -Remove_Prefix option requires a string argument"
                );
                command_line.usage();
                // NOTREACHED
            }
            break;

        case arglex_tardy::token_mode_set:
            if (command_line.lex() != arglex::token_number)
            {
                explain_output_error
                (
                   "the -Mode_Set option must be followed by a numeric argument"
                );
                command_line.usage();
            }
            tardy_mode_set(command_line.get_value_number());
            break;

        case arglex_tardy::token_mode_clear:
            if (command_line.lex() != arglex::token_number)
            {
                explain_output_error
                (
                 "the -Mode_Clear option must be followed by a numeric argument"
                );
                command_line.usage();
            }
            tardy_mode_clear(command_line.get_value_number());
            break;

        case arglex_tardy::token_list:
            tardy_list();
            break;

        case arglex_tardy::token_now:
            tardy_now();
            break;

        case arglex_tardy::token_mtime_debug:
            tardy_blocksize(1);
            tardy_group_name_by_string("root");
            tardy_group_number_by_number(0);
            tardy_mode_clear(07022);
            tardy_mode_set(0644);
            tardy_mtime(24 * 60 * 60);
            tardy_user_name_by_string("root");
            tardy_user_number_by_number(0);
            break;

        case arglex_tardy::token_old_type:
            tardy_no_fix_type();
            break;

        case arglex_tardy::token_no_directories:
            tardy_no_directories();
            break;

        case arglex_tardy::token_clean:
            tardy_clean_meta();
            tardy_clean_print();
            tardy_clean_space();
            break;

        case arglex_tardy::token_clean_meta:
            tardy_clean_meta();
            break;

        case arglex_tardy::token_clean_print:
            tardy_clean_print();
            break;

        case arglex_tardy::token_clean_space:
            tardy_clean_space();
            break;

        case arglex_tardy::token_downcase:
            tardy_downcase();
            break;

        case arglex_tardy::token_upcase:
            tardy_upcase();
            break;

        case arglex_tardy::token_progress:
            tar_input_filenamelist::issue_progress_reports();
            break;

        case arglex_tardy::token_format_input:
            if (command_line.lex() != arglex::token_string)
            {
                explain_output_error
                (
                    "the -Input_ForMaT option requires a string argument"
                );
                command_line.usage();
            }
            tardy_format_input(command_line.get_value_string());
            break;

        case arglex_tardy::token_format_output:
            if (command_line.lex() != arglex::token_string)
            {
                explain_output_error
                (
                    "the -Output_ForMaT option requires a string argument"
                );
                command_line.usage();
            }
            tardy_format_output(command_line.get_value_string());
            break;

        case arglex_tardy::token_gzip:
            tardy_gzip();
            break;

        case arglex_tardy::token_gunzip:
            tardy_gunzip();
            break;

        case arglex_tardy::token_blocksize:
            if (command_line.lex() != arglex::token_number)
            {
                explain_output_error
                (
                    "the -Block-Size option requires a numeric argument"
                );
                command_line.usage();
            }
            tardy_blocksize(command_line.get_value_number());
            break;

        case arglex_tardy::token_exclude:
            if (command_line.lex() != arglex::token_string)
            {
                explain_output_error
                (
                    "the -EXclude option requires a string argument"
                );
                command_line.usage();
            }
            tardy_exclude(command_line.get_value_string());
            break;

#ifdef DEBUG
        case arglex::token_trace:
            while (command_line.lex() == arglex::token_string)
                trace_enable(command_line.get_value_string());
            continue;
#endif

        case arglex_tardy::token_hexdump:
            tardy_hexdump();
            break;

        case arglex_tardy::token_extract:
            tardy_extract();
            break;

        case arglex_tardy::token_relative_paths:
            tardy_relative_paths();
            break;
        }
        command_line.lex();
    }
    if (outfile && !*outfile)
        outfile = 0;
    if (infile && !*infile)
        infile = 0;

    //
    // This catch something like:
    //     tar -cf - foo bar | tardy
    // no file arguments given to tardy.
    //
    if (!outfile && isatty(1))
    {
        explain_output_error_and_die("will not write to a terminal");
    }

    //
    // This catch the case where
    //     tardy >out.tar
    // when no input file has been specified.
    //
    if (!infile && isatty(0))
    {
        explain_output_error_and_die("will not read from a terminal");
    }

    tardy(infile, outfile);
    exit(0);
    return 0;
}
