source: git/src/cmdline.c @ 8a7804fb

main
Last change on this file since 8a7804fb was 0b99107, checked in by Olly Betts <olly@…>, 7 weeks ago

Eliminate old FSF addresses

Update GPL/LGPL licence files and boilerplate to direct people who
didn't receive the licence text to the FSF website, as the current
versions of the FSF licence texts now do, rather than giving a postal
address.

  • Property mode set to 100644
File size: 7.0 KB
RevLine 
[6974a34]1/* cmdline.c
[aadc86e]2 * Wrapper for GNU getopt which deals with standard options
[ab8bd76]3 * Copyright (C) 1998-2001,2003,2004,2011,2012,2014,2024 Olly Betts
[846746e]4 *
[89231c4]5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
[846746e]9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
[89231c4]12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
[846746e]14 *
[89231c4]15 * You should have received a copy of the GNU General Public License
[0b99107]16 * along with this program; if not, see
17 * <https://www.gnu.org/licenses/>.
[aadc86e]18 */
19
20#include <config.h>
21
22#include <ctype.h>
[3b9ec3f]23#include <errno.h>
[dd6f74e]24#include <float.h>
[aadc86e]25#include <stdio.h>
[a49a80c0]26#include <stdlib.h>
[e05bdb8]27#include <string.h>
[f2122f0]28#include <limits.h>
[aadc86e]29
[be97baf]30#include "getopt.h"
31
[aadc86e]32#include "cmdline.h"
[45af761]33#include "debug.h"
[e05bdb8]34#include "filename.h"
[aadc86e]35
[d227ee5]36#include "message.h"
37
[aadc86e]38/*
39 * bad command line give:
40 * <problem>
[cb3d1e2]41 *
[e05bdb8]42 * <short syntax>
[cb3d1e2]43 *
[aadc86e]44 * --help gives:
45 * <version>
[cb3d1e2]46 *
[aadc86e]47 * <short syntax>
48 *
49 * <table>
[cb3d1e2]50 *
[aadc86e]51 * <blurb>
52 *
53 * --version gives:
54 * <version>
55 */
56
57/*
58 * want to cope with optional/required parameters on long options
59 * and also parameters on short options
[3b9ec3f]60 */
[aadc86e]61
62static const char newline_tabs[] = "\n\t\t\t\t";
63
[3b9ec3f]64static int argc;
[647407d]65static char * const *argv;
[3b9ec3f]66static const char *shortopts;
67static const struct option *longopts;
68static int *longind;
69static const struct help_msg *help;
70static int min_args, max_args;
[d8dbdff]71static int msg_args, msg_extra;
72static const char * msg_extra_arg;
[3b9ec3f]73
74void
75cmdline_help(void)
[aadc86e]76{
[9e513bd3]77   while (help && help->opt) {
[aadc86e]78      const char *longopt = 0;
79      int opt = help->opt;
80      const struct option *o = 0;
81
82      if (HLP_ISLONG(opt)) {
[3b9ec3f]83         o = longopts + HLP_DECODELONG(opt);
[aadc86e]84         longopt = o->name;
85         opt = o->val;
86      }
87
[0580c6a]88      if (isalnum((unsigned char)opt))
[5fbfd8d]89         printf("  -%c%c", opt, longopt ? ',' : ' ');
[aadc86e]90      else
91         fputs("     ", stdout);
92
93      if (longopt) {
94         int len = strlen(longopt);
95         printf(" --%s", longopt);
96         if (o && o->has_arg) {
97            const char *p;
98            len += len + 1;
99
100            if (o->has_arg == optional_argument) {
[ce668fb]101               PUTCHAR('[');
[aadc86e]102               len += 2;
103            }
104
[ce668fb]105            PUTCHAR('=');
[aadc86e]106
[5a2d346]107            if (help->placeholder) {
108                fputs(help->placeholder, stdout);
109            } else {
110                for (p = longopt; *p ; p++) {
111                    unsigned char ch = *p;
[ce668fb]112                    PUTCHAR((ch == '-') ? '_' : toupper(ch));
[5a2d346]113                }
[ab8bd76]114            }
[aadc86e]115
[ce668fb]116            if (o->has_arg == optional_argument) PUTCHAR(']');
[aadc86e]117         }
118         len = (len >> 3) + 2;
119         if (len > 4) len = 0;
120         fputs(newline_tabs + len, stdout);
121      } else {
122         fputs(newline_tabs + 1, stdout);
123      }
124
[45af761]125      if (help->arg) {
126          SVX_ASSERT(strstr(msg(help->msg_no), "%s") != NULL);
127          printf(msg(help->msg_no), help->arg);
128          putnl();
129      } else {
130          SVX_ASSERT(strstr(msg(help->msg_no), "%s") == NULL);
131          puts(msg(help->msg_no));
132      }
[aadc86e]133      help++;
134   }
[45af761]135   fputs("      --help\t\t\t", stdout);
[736f7df]136   /* TRANSLATORS: description of --help option */
[45af761]137   puts(msg(/*display this help and exit*/150));
138   fputs("      --version\t\t\t", stdout);
[c5d45ba]139   /* TRANSLATORS: description of --version option */
[45af761]140   puts(msg(/*output version information and exit*/151));
[acc20b1]141
[d8dbdff]142   if (msg_extra) {
[acc20b1]143      putnl();
[d8dbdff]144      if (msg_extra_arg) {
145          SVX_ASSERT(strstr(msg(msg_extra), "%s") != NULL);
146          printf(msg(msg_extra), msg_extra_arg);
147          putnl();
148      } else {
149          SVX_ASSERT(strstr(msg(msg_extra), "%s") == NULL);
150          puts(msg(msg_extra));
151      }
[acc20b1]152   }
[647407d]153
[aadc86e]154   exit(0);
155}
156
[3b9ec3f]157void
158cmdline_version(void)
[aadc86e]159{
[82afbc4]160   printf("%s - "PRETTYPACKAGE" "VERSION"\n", msg_appname());
[aadc86e]161}
162
[3b9ec3f]163void
164cmdline_syntax(void)
[cb3d1e2]165{
[736f7df]166   /* TRANSLATORS: as in: Usage: cavern … */
[ee7511a]167   printf("\n%s: %s", msg(/*Usage*/49), msg_appname());
[736f7df]168   /* TRANSLATORS: in command line usage messages e.g. Usage: cavern [OPTION]… */
[9e513bd3]169   if (help && help->opt) printf(" [%s]...", msg(/*OPTION*/153));
[d8dbdff]170   if (msg_args) {
[ce668fb]171      PUTCHAR(' ');
[d8dbdff]172      puts(msg(msg_args));
[acc20b1]173      return;
174   }
[3b9ec3f]175   if (min_args) {
176      int i = min_args;
[a580dc1]177      while (i--) printf(" %s", msg(/*FILE*/124));
[3b9ec3f]178   }
[647407d]179   if (max_args == -1) {
[a580dc1]180      if (!min_args) printf(" [%s]", msg(/*FILE*/124));
[647407d]181      fputs("...", stdout);
182   } else if (max_args > min_args) {
183      int i = max_args - min_args;
[a580dc1]184      while (i--) printf(" [%s]", msg(/*FILE*/124));
[647407d]185   }
[3b9ec3f]186   putnl();
187}
188
[2668614]189static void
190syntax_and_help_pointer(void)
191{
192   cmdline_syntax();
[ee7511a]193   fprintf(stderr, msg(/*Try “%s --help” for more information.\n*/157),
[2668614]194           msg_appname());
195   exit(1);
196}
197
198static void
199moan_and_die(int msgno)
200{
201   fprintf(stderr, "%s: ", msg_appname());
202   fprintf(stderr, msg(msgno), optarg);
203   fputnl(stderr);
204   cmdline_syntax();
205   exit(1);
206}
207
208void
209cmdline_too_few_args(void)
210{
211   fprintf(stderr, "%s: %s\n", msg_appname(), msg(/*too few arguments*/122));
212   syntax_and_help_pointer();
213}
214
215void
216cmdline_too_many_args(void)
217{
218   fprintf(stderr, "%s: %s\n", msg_appname(), msg(/*too many arguments*/123));
219   syntax_and_help_pointer();
220}
221
[acc20b1]222void
[d8dbdff]223cmdline_set_syntax_message(int msg_args_, int msg_extra_, const char * arg)
[acc20b1]224{
[d8dbdff]225   msg_args = msg_args_;
226   msg_extra = msg_extra_;
227   msg_extra_arg = arg;
[acc20b1]228}
229
[3b9ec3f]230int
231cmdline_int_arg(void)
[aadc86e]232{
[f2122f0]233   long result;
[3b9ec3f]234   char *endptr;
[cb3d1e2]235
[3b9ec3f]236   errno = 0;
237
238   result = strtol(optarg, &endptr, 10);
239
[f2122f0]240   if (errno == ERANGE || result > INT_MAX || result < INT_MIN) {
[0804fbe]241      moan_and_die(/*numeric argument “%s” out of range*/185);
[3b9ec3f]242   } else if (*optarg == '\0' || *endptr != '\0') {
[0804fbe]243      moan_and_die(/*argument “%s” not an integer*/186);
[3b9ec3f]244   }
[cb3d1e2]245
[f2122f0]246   return (int)result;
[aadc86e]247}
248
[acc20b1]249double
250cmdline_double_arg(void)
[aadc86e]251{
[acc20b1]252   double result;
[3b9ec3f]253   char *endptr;
[cb3d1e2]254
[3b9ec3f]255   errno = 0;
256
257   result = strtod(optarg, &endptr);
258
259   if (errno == ERANGE) {
[0804fbe]260      moan_and_die(/*numeric argument “%s” out of range*/185);
[3b9ec3f]261   } else if (*optarg == '\0' || *endptr != '\0') {
[0804fbe]262      moan_and_die(/*argument “%s” not a number*/187);
[3b9ec3f]263   }
[cb3d1e2]264
[3b9ec3f]265   return result;
266}
267
268void
269cmdline_init(int argc_, char *const *argv_, const char *shortopts_,
270             const struct option *longopts_, int *longind_,
271             const struct help_msg *help_,
272             int min_args_, int max_args_)
273{
274   argc = argc_;
275   argv = argv_;
276   shortopts = shortopts_;
277   longopts = longopts_;
278   longind = longind_;
279   help = help_;
280   min_args = min_args_;
281   max_args = max_args_;
282}
283
284int
285cmdline_getopt(void)
286{
287   int opt = getopt_long(argc, argv, shortopts, longopts, longind);
[aadc86e]288
[2668614]289   switch (opt) {
290    case EOF:
[a580dc1]291      /* check valid # of args given - if not give syntax message */
[3b9ec3f]292      if (argc - optind < min_args) {
[2668614]293         cmdline_too_few_args();
[3b9ec3f]294      } else if (max_args >= 0 && argc - optind > max_args) {
[2668614]295         cmdline_too_many_args();
[3b9ec3f]296      }
[2668614]297      break;
[aadc86e]298    case ':': /* parameter missing */
299    case '?': /* unknown opt, ambiguous match, or extraneous param */
[a580dc1]300      /* getopt displays a message for us */
[2668614]301      syntax_and_help_pointer();
302      break;
[aadc86e]303    case HLP_VERSION: /* --version */
[3b9ec3f]304      cmdline_version();
[aadc86e]305      exit(0);
306    case HLP_HELP: /* --help */
[3b9ec3f]307      cmdline_version();
308      cmdline_syntax();
[ce668fb]309      PUTCHAR('\n');
[3b9ec3f]310      cmdline_help();
[aadc86e]311      exit(0);
312   }
313   return opt;
314}
Note: See TracBrowser for help on using the repository browser.