Fix Walls #DATE to act like DECL= with active .REF
[survex.git] / src / cmdline.c
blobc6a65c34b8f0ff7aa28384798ec4ef47961fafd9
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
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.
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.
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
20 #include <config.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <float.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <limits.h>
29 #include "getopt.h"
31 #include "cmdline.h"
32 #include "debug.h"
33 #include "filename.h"
35 #include "message.h"
37 /* It might be useful to be able to disable all long options on small
38 * platforms like older PDAs.
40 #if 0
41 # define getopt_long(ARGC, ARGV, STR, OPTS, PTR) getopt(ARGC, ARGV, STR)
42 #endif
45 * bad command line give:
46 * <problem>
48 * <short syntax>
50 * --help gives:
51 * <version>
53 * <short syntax>
55 * <table>
57 * <blurb>
59 * --version gives:
60 * <version>
64 * want to cope with optional/required parameters on long options
65 * and also parameters on short options
68 static const char newline_tabs[] = "\n\t\t\t\t";
70 static int argc;
71 static char * const *argv;
72 static const char *shortopts;
73 static const struct option *longopts;
74 static int *longind;
75 static const struct help_msg *help;
76 static int min_args, max_args;
77 static int msg_args, msg_extra;
78 static const char * msg_extra_arg;
80 void
81 cmdline_help(void)
83 while (help && help->opt) {
84 const char *longopt = 0;
85 int opt = help->opt;
86 const struct option *o = 0;
88 if (HLP_ISLONG(opt)) {
89 o = longopts + HLP_DECODELONG(opt);
90 longopt = o->name;
91 opt = o->val;
94 if (isalnum((unsigned char)opt))
95 printf(" -%c%c", opt, longopt ? ',' : ' ');
96 else
97 fputs(" ", stdout);
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;
106 if (o->has_arg == optional_argument) {
107 putchar('[');
108 len += 2;
111 putchar('=');
113 for (p = longopt; *p ; p++) {
114 unsigned char ch = *p;
115 putchar((ch == '-') ? '_' : toupper(ch));
118 if (o->has_arg == optional_argument) putchar(']');
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);
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));
135 help++;
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));
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));
156 exit(0);
159 void
160 cmdline_version(void)
162 printf("%s - "PRETTYPACKAGE" "VERSION"\n", msg_appname());
165 void
166 cmdline_syntax(void)
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;
177 if (min_args) {
178 int i = min_args;
179 while (i--) printf(" %s", msg(/*FILE*/124));
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));
188 putnl();
191 static void
192 syntax_and_help_pointer(void)
194 cmdline_syntax();
195 fprintf(stderr, msg(/*Try “%s --help” for more information.\n*/157),
196 msg_appname());
197 exit(1);
200 static void
201 moan_and_die(int msgno)
203 fprintf(stderr, "%s: ", msg_appname());
204 fprintf(stderr, msg(msgno), optarg);
205 fputnl(stderr);
206 cmdline_syntax();
207 exit(1);
210 void
211 cmdline_too_few_args(void)
213 fprintf(stderr, "%s: %s\n", msg_appname(), msg(/*too few arguments*/122));
214 syntax_and_help_pointer();
217 void
218 cmdline_too_many_args(void)
220 fprintf(stderr, "%s: %s\n", msg_appname(), msg(/*too many arguments*/123));
221 syntax_and_help_pointer();
224 void
225 cmdline_set_syntax_message(int msg_args_, int msg_extra_, const char * arg)
227 msg_args = msg_args_;
228 msg_extra = msg_extra_;
229 msg_extra_arg = arg;
233 cmdline_int_arg(void)
235 long result;
236 char *endptr;
238 errno = 0;
240 result = strtol(optarg, &endptr, 10);
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);
248 return (int)result;
251 double
252 cmdline_double_arg(void)
254 double result;
255 char *endptr;
257 errno = 0;
259 result = strtod(optarg, &endptr);
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);
267 return result;
270 void
271 cmdline_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_)
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_;
287 cmdline_getopt(void)
289 int opt = getopt_long(argc, argv, shortopts, longopts, longind);
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();
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);
315 return opt;