source: git/src/cmdline.c @ 350a042

stereo-2025
Last change on this file since 350a042 was ab8bd76, checked in by Olly Betts <olly@…>, 12 months ago

Use _ instead of - in --help placeholders

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