Motr  M0
ugetopts.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2012-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #ifndef _POSIX_C_SOURCE
24 #define _POSIX_C_SOURCE 2 /* for getopt */
25 #endif
26 #include <unistd.h> /* getopt */
27 #include <stdio.h> /* fprintf, sscanf */
28 #include <stdlib.h> /* strtoll */
29 #include <string.h> /* strchr */
30 
31 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_LIB
32 #include "lib/trace.h"
33 
34 /* getopt(3) interface */
35 extern char *optarg;
36 extern int optind;
37 extern int optopt;
38 extern int opterr;
39 extern int optreset;
40 
41 #include "lib/assert.h"
42 #include "lib/errno.h"
43 #include "lib/memory.h"
44 #include "lib/getopts.h"
45 
51 static void usage(const char *progname,
52  const struct m0_getopts_opt *opts, unsigned nr)
53 {
54  int i;
55 
56  fprintf(stderr, "Usage: %s options...\n\nwhere valid options are\n\n",
57  progname);
58 
59  for (i = 0; i < nr; ++i) {
60  const struct m0_getopts_opt *o;
61 
62  o = &opts[i];
63  fprintf(stderr, "\t -%c %10s: %s\n", o->go_opt,
64  o->go_type == GOT_VOID ? "" :
65  o->go_type == GOT_HELP ? "" :
66  o->go_type == GOT_FLAG ? "" :
68  o->go_type == GOT_SCALED ? "scaled" :
69  o->go_type == GOT_NUMBER ? "number" : "string",
70  o->go_desc);
71  }
72 }
73 
74 static int getnum(const char *arg, const char *desc, int64_t *out)
75 {
76  char *end;
77 
78  *out = strtoll(arg, &end, 0);
79  if (*end != 0) {
80  fprintf(stderr, "Failed conversion of \"%s\" to %s\n",
81  arg, desc);
82  return M0_ERR(-EINVAL);
83  } else
84  return 0;
85 }
86 
87 static int getscaled(const char *arg, const char *desc, m0_bcount_t *out)
88 {
89  int rc;
90 
91  rc = m0_bcount_get(arg, out);
92  if (rc != 0)
93  fprintf(stderr, "Failed conversion of \"%s\" to %s\n",
94  arg, desc);
95  return M0_RC(rc);
96 }
97 
98 int m0_getopts(const char *progname, int argc, char *const *argv,
99  const struct m0_getopts_opt *opts, unsigned nr)
100 {
101  char *optstring;
102  int i;
103  int scan;
104  int ch;
105  int result;
106 
107  M0_ALLOC_ARR(optstring, 2 * nr + 1);
108  if (optstring == NULL)
109  return M0_ERR(-ENOMEM);
110 
111  for (scan = i = 0; i < nr; ++i) {
112  /* -W is reserved by POSIX.2 and used by GNU getopts as a long
113  option escape. */
114  M0_ASSERT(opts[i].go_opt != 'W');
115  optstring[scan++] = opts[i].go_opt;
116  if (!M0_IN(opts[i].go_type, (GOT_VOID, GOT_FLAG, GOT_HELP)))
117  optstring[scan++] = ':';
118  if (opts[i].go_type == GOT_FLAG)
119  *opts[i].go_u.got_flag = false;
120  }
121 
122  result = 0;
123 
124  /*
125  * Re-set global getopt(3) state before calling it.
126  */
127  optind = 1;
128  opterr = 1;
129 
130  while (result == 0 && (ch = getopt(argc, argv, optstring)) != -1) {
131  for (i = 0; i < nr; ++i) {
132  const struct m0_getopts_opt *o;
133  const union m0_getopts_union *u;
134 
135  o = &opts[i];
136  if (ch != o->go_opt)
137  continue;
138 
139  u = &o->go_u;
140  switch (o->go_type) {
141  case GOT_VOID:
142  u->got_void();
143  break;
144  case GOT_NUMBER: {
145  int64_t num;
146 
147  result = getnum(optarg, o->go_desc, &num);
148  if (result == 0)
149  u->got_number(num);
150  break;
151  }
152  case GOT_SCALED: {
154 
155  result = getscaled(optarg, o->go_desc, &num);
156  if (result == 0)
157  u->got_scaled(num);
158  break;
159  }
160  case GOT_STRING:
161  u->got_string(optarg);
162  break;
163  case GOT_FORMAT:
164  result = sscanf(optarg, u->got_fmt.f_string,
165  u->got_fmt.f_out);
166  result = result == 1 ? 0 : M0_ERR(-EINVAL);
167  if (result != 0) {
168  fprintf(stderr, "Cannot scan \"%s\" "
169  "as \"%s\" in \"%s\"\n",
170  optarg, u->got_fmt.f_string,
171  o->go_desc);
172  }
173  break;
174  case GOT_FLAG:
175  *u->got_flag = true;
176  break;
177  case GOT_HELP:
178  usage(progname, opts, nr);
179  exit(EXIT_FAILURE);
180  break;
181  default:
182  M0_IMPOSSIBLE("Wrong option type.");
183  }
184  break;
185  }
186  if (i == nr) {
187  M0_ASSERT(ch == '?');
188  fprintf(stderr, "Unknown option '%c'\n", optopt);
189  usage(progname, opts, nr);
190  result = M0_ERR(-EINVAL);
191  }
192  }
193 
194  m0_free(optstring);
195  return result;
196 }
197 
198 #undef M0_TRACE_SUBSYSTEM
199 
202 /*
203  * Local variables:
204  * c-indentation-style: "K&R"
205  * c-basic-offset: 8
206  * tab-width: 8
207  * fill-column: 80
208  * scroll-step: 1
209  * End:
210  */
static size_t nr
Definition: dump.c:1505
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
int optind
#define NULL
Definition: misc.h:38
union @126 u
int optreset
char * optarg
uint64_t m0_bcount_t
Definition: types.h:77
return M0_RC(rc)
static int getnum(const char *arg, const char *desc, int64_t *out)
Definition: ugetopts.c:74
int i
Definition: dir.c:1033
return M0_ERR(-EOPNOTSUPP)
enum m0_getopts_opt_type go_type
Definition: getopts.h:121
#define M0_ASSERT(cond)
static int getscaled(const char *arg, const char *desc, m0_bcount_t *out)
Definition: ugetopts.c:87
int opterr
struct m0_getopts_opt::m0_getopts_union::@271 got_fmt
union m0_getopts_opt::m0_getopts_union go_u
static const char * progname
Definition: traced.c:65
static void usage(const char *progname, const struct m0_getopts_opt *opts, unsigned nr)
Definition: ugetopts.c:51
M0_INTERNAL int m0_bcount_get(const char *arg, m0_bcount_t *out)
Definition: getopts.c:35
const char * go_desc
Definition: getopts.h:125
#define out(...)
Definition: gen.c:41
int optopt
static int scan(struct scanner *s)
Definition: beck.c:963
int num
Definition: bulk_if.c:54
void m0_free(void *data)
Definition: memory.c:146
int32_t rc
Definition: trigger_fop.h:47
int m0_getopts(const char *progname, int argc, char *const *argv, const struct m0_getopts_opt *opts, unsigned nr)
Definition: ugetopts.c:98
#define M0_IMPOSSIBLE(fmt,...)