/* Test program for argp argument parser
   Copyright (C) 1997 Free Software Foundation, Inc.
   This file is part of the GNU C Library.
   Written by Miles Bader <miles@gnu.ai.mit.edu>.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library 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
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <argp.h>
#include <stdio.h>

const char *argp_program_version = "argp-test 1.0";

struct argp_option sub_options[] =
    {
        {"subopt1", 's', 0, 0, "Nested option 1"},
        {"subopt2", 'S', 0, 0, "Nested option 2"},

        {0,         0,   0, 0, "Some more nested options:", 10},
        {"subopt3", 'p', 0, 0, "Nested option 3"},

        {"subopt4", 'q', 0, 0, "Nested option 4",           1},

        {0}
    };

static const char sub_args_doc[] = "STRING...\n-";
static const char sub_doc[] = "\vThis is the doc string from the sub-arg-parser.";

static error_t
sub_parse_opt(int key, char *arg, struct argp_state *state) {
    switch (key) {
        case ARGP_KEY_NO_ARGS:
            printf("NO SUB ARGS\n");
            break;
        case ARGP_KEY_ARG:
            printf("SUB ARG: %s\n", arg);
            break;

        case 's' :
        case 'S':
        case 'p':
        case 'q':
            printf("SUB KEY %c\n", key);
            break;

        default:
            return ARGP_ERR_UNKNOWN;
    }
    return 0;
}

static char *
sub_help_filter(int key, const char *text, void *input) {
    if (key == ARGP_KEY_HELP_EXTRA)
        return strdup("This is some extra text from the sub parser (note that it \
is preceded by a blank line).");
    else
        return (char *) text;
}

static struct argp sub_argp = {
    sub_options, sub_parse_opt, sub_args_doc, sub_doc, 0, sub_help_filter
};

/* Structure used to communicate with the parsing functions.  */
struct params {
    unsigned foonly;        /* Value parsed for foonly.  */
    unsigned foonly_default;    /* Default value for it.  */
};

#define OPT_PGRP 1
#define OPT_SESS 2

struct argp_option options[] =
    {
        {"pid",                              'p', "PID",  0,                   "List the process PID"},
        {"pgrp",    OPT_PGRP,                     "PGRP", 0,                   "List processes in the process group PGRP"},
        {"no-parent",                        'P', 0,      0,                   "Include processes without parents"},
        {0,                                  'x', 0,      OPTION_ALIAS},
        {"all-fields",                       'Q', 0,      0,                   "Don't elide unusable fields (normally"
                                                                               " if there's some reason ps can't"
                                                                               " print a field for any process, it's"
                                                                               " removed from the output entirely)"},
        {"reverse",                          'r', 0,      0,                   "Reverse the order of any sort"},
        {"gratuitously-long-reverse-option", 0,   0,      OPTION_ALIAS},
        {"session", OPT_SESS,                     "SID",  OPTION_ARG_OPTIONAL,
                                                                               "Add the processes from the session"
                                                                               " SID (which defaults to the sid of"
                                                                               " the current process)"},

        {0,                                  0,   0,      0,                   "Here are some more options:"},
        {"foonly",                           'f', "ZOT",  OPTION_ARG_OPTIONAL, "Glork a foonly"},
        {"zaza",                             'z', 0,      0,                   "Snit a zar"},

        {0}
    };

static const char args_doc[] = "STRING";
static const char doc[] = "Test program for argp."
                          "\vThis doc string comes after the options."
                          "\nHey!  Some manual formatting!"
                          "\nThe current time is: %s";

static void
popt(int key, char *arg) {
    char buf[10];
    if (isprint(key))
        sprintf(buf, "%c", key);
    else
        sprintf(buf, "%d", key);
    if (arg)
        printf("KEY %s: %s\n", buf, arg);
    else
        printf("KEY %s\n", buf);
}

static error_t
parse_opt(int key, char *arg, struct argp_state *state) {
    struct params *params = state->input;

    switch (key) {
        case ARGP_KEY_NO_ARGS:
            printf("NO ARGS\n");
            break;

        case ARGP_KEY_ARG:
            if (state->arg_num > 0)
                return ARGP_ERR_UNKNOWN; /* Leave it for the sub-arg parser.  */
            printf("ARG: %s\n", arg);
            break;

        case 'f':
            if (arg)
                params->foonly = atoi(arg);
            else
                params->foonly = params->foonly_default;
            popt(key, arg);
            break;

        case 'p':
        case 'P':
        case OPT_PGRP:
        case 'x':
        case 'Q':
        case 'r':
        case OPT_SESS:
        case 'z':
            popt(key, arg);
            break;

        default:
            return ARGP_ERR_UNKNOWN;
    }
    return 0;
}

static struct argp_child argp_children[] = {{&sub_argp},
                                            {0}};
static struct argp argp = {options, parse_opt, args_doc, doc, argp_children};

int
main(int argc, char **argv) {
    struct params params;
    params.foonly = 0;
    params.foonly_default = 10;
    argp_parse(&argp, argc, argv, 0, 0, &params);
    printf("After parsing: foonly = %x\n", params.foonly);
    return 0;
}
