source: git/src/cmdline.c @ 3ed9c56

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

Fix mingw build

This has started to fail due to the GNU getopt code not declaring
getopt().

Survex only uses getopt_long() so we can remove the declaration of
getopt() and then there's no potential for clashing prototypes so
we can just include <stdlib.h>.

  • 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
16 * along with this program; if not, write to the Free Software
[ecbc6c18]17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
[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.