1  /* Test program for argp argument parser
       2     Copyright (C) 1997-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #ifdef HAVE_CONFIG_H
      20  #include <config.h>
      21  #endif
      22  
      23  #include <stdlib.h>
      24  #include <time.h>
      25  #include <string.h>
      26  #include <argp.h>
      27  
      28  #include <support/support.h>
      29  
      30  const char *argp_program_version = "argp-test 1.0";
      31  
      32  struct argp_option sub_options[] =
      33  {
      34    {"subopt1",       's',     0,  0, "Nested option 1"},
      35    {"subopt2",       'S',     0,  0, "Nested option 2"},
      36  
      37    { 0, 0, 0, 0, "Some more nested options:", 10},
      38    {"subopt3",       'p',     0,  0, "Nested option 3"},
      39  
      40    {"subopt4",       'q',     0,  0, "Nested option 4", 1},
      41  
      42    {0}
      43  };
      44  
      45  static const char sub_args_doc[] = "STRING...\n-";
      46  static const char sub_doc[] = "\vThis is the doc string from the sub-arg-parser.";
      47  
      48  static error_t
      49  sub_parse_opt (int key, char *arg, struct argp_state *state)
      50  {
      51    switch (key)
      52      {
      53      case ARGP_KEY_NO_ARGS:
      54        printf ("NO SUB ARGS\n");
      55        break;
      56      case ARGP_KEY_ARG:
      57        printf ("SUB ARG: %s\n", arg);
      58        break;
      59  
      60      case 's' : case 'S': case 'p': case 'q':
      61        printf ("SUB KEY %c\n", key);
      62        break;
      63  
      64      default:
      65        return ARGP_ERR_UNKNOWN;
      66      }
      67    return 0;
      68  }
      69  
      70  static char *
      71  sub_help_filter (int key, const char *text, void *input)
      72  {
      73    if (key == ARGP_KEY_HELP_EXTRA)
      74      return strdup ("This is some extra text from the sub parser (note that it \
      75  is preceded by a blank line).");
      76    else
      77      return (char *)text;
      78  }
      79  
      80  static struct argp sub_argp = {
      81    sub_options, sub_parse_opt, sub_args_doc, sub_doc, 0, sub_help_filter
      82  };
      83  
      84  /* Structure used to communicate with the parsing functions.  */
      85  struct params
      86  {
      87    unsigned foonly;		/* Value parsed for foonly.  */
      88    unsigned foonly_default;	/* Default value for it.  */
      89  };
      90  
      91  #define OPT_PGRP 1
      92  #define OPT_SESS 2
      93  
      94  struct argp_option options[] =
      95  {
      96    {"pid",       'p',     "PID", 0, "List the process PID"},
      97    {"pgrp",      OPT_PGRP,"PGRP",0, "List processes in the process group PGRP"},
      98    {"no-parent", 'P',	 0,     0, "Include processes without parents"},
      99    {0,           'x',     0,     OPTION_ALIAS},
     100    {"all-fields",'Q',     0,     0, "Don't elide unusable fields (normally"
     101  				   " if there's some reason ps can't"
     102  				   " print a field for any process, it's"
     103  				   " removed from the output entirely)" },
     104    {"reverse",   'r',    0,      0, "Reverse the order of any sort"},
     105    {"gratuitously-long-reverse-option", 0, 0, OPTION_ALIAS},
     106    {"session",  OPT_SESS,"SID",  OPTION_ARG_OPTIONAL,
     107  				   "Add the processes from the session"
     108  				   " SID (which defaults to the sid of"
     109  				   " the current process)" },
     110  
     111    {0,0,0,0, "Here are some more options:"},
     112    {"foonly", 'f', "ZOT", OPTION_ARG_OPTIONAL, "Glork a foonly"},
     113    {"zaza", 'z', 0, 0, "Snit a zar"},
     114  
     115    {0}
     116  };
     117  
     118  static const char args_doc[] = "STRING";
     119  static const char doc[] = "Test program for argp."
     120   "\vThis doc string comes after the options."
     121   "\nHey!  Some manual formatting!"
     122   "\nThe current time is: %s";
     123  
     124  static void
     125  popt (int key, char *arg)
     126  {
     127    char buf[12];
     128    if (isprint (key))
     129      sprintf (buf, "%c", key);
     130    else
     131      sprintf (buf, "%d", key);
     132    if (arg)
     133      printf ("KEY %s: %s\n", buf, arg);
     134    else
     135      printf ("KEY %s\n", buf);
     136  }
     137  
     138  static error_t
     139  parse_opt (int key, char *arg, struct argp_state *state)
     140  {
     141    struct params *params = state->input;
     142  
     143    switch (key)
     144      {
     145      case ARGP_KEY_NO_ARGS:
     146        printf ("NO ARGS\n");
     147        break;
     148  
     149      case ARGP_KEY_ARG:
     150        if (state->arg_num > 0)
     151  	return ARGP_ERR_UNKNOWN; /* Leave it for the sub-arg parser.  */
     152        printf ("ARG: %s\n", arg);
     153        break;
     154  
     155      case 'f':
     156        if (arg)
     157  	params->foonly = atoi (arg);
     158        else
     159  	params->foonly = params->foonly_default;
     160        popt (key, arg);
     161        break;
     162  
     163      case 'p': case 'P': case OPT_PGRP: case 'x': case 'Q':
     164      case 'r': case OPT_SESS: case 'z':
     165        popt (key, arg);
     166        break;
     167  
     168      default:
     169        return ARGP_ERR_UNKNOWN;
     170      }
     171    return 0;
     172  }
     173  
     174  static char *
     175  help_filter (int key, const char *text, void *input)
     176  {
     177    char *new_text;
     178    struct params *params = input;
     179  
     180    if (key == ARGP_KEY_HELP_POST_DOC && text)
     181      {
     182        time_t now = time (0);
     183        new_text = xasprintf (text, ctime (&now));
     184      }
     185    else if (key == 'f')
     186      /* Show the default for the --foonly option.  */
     187      new_text = xasprintf ("%s (ZOT defaults to %x)",
     188  		          text, params->foonly_default);
     189    else
     190      new_text = (char *)text;
     191  
     192    return new_text;
     193  }
     194  
     195  static struct argp_child argp_children[] = { { &sub_argp }, { 0 } };
     196  static struct argp argp = {
     197    options, parse_opt, args_doc, doc, argp_children, help_filter
     198  };
     199  
     200  int
     201  main (int argc, char **argv)
     202  {
     203    struct params params;
     204    params.foonly = 0;
     205    params.foonly_default = random ();
     206    argp_parse (&argp, argc, argv, 0, 0, ¶ms);
     207    printf ("After parsing: foonly = %x\n", params.foonly);
     208    return 0;
     209  }