source: git/src/cmdline.c @ 42e3bb5

stereo-2025
Last change on this file since 42e3bb5 was a49a80c0, checked in by Olly Betts <olly@…>, 4 months ago

Clean up inclusion of osalloc.h

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