Line data Source code
1 : /*********************************** LICENSE **********************************\
2 : * Copyright 2017 Morphux *
3 : * *
4 : * Licensed under the Apache License, Version 2.0 (the "License"); *
5 : * you may not use this file except in compliance with the License. *
6 : * You may obtain a copy of the License at *
7 : * *
8 : * http://www.apache.org/licenses/LICENSE-2.0 *
9 : * *
10 : * Unless required by applicable law or agreed to in writing, software *
11 : * distributed under the License is distributed on an "AS IS" BASIS, *
12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13 : * See the License for the specific language governing permissions and *
14 : * limitations under the License. *
15 : \******************************************************************************/
16 :
17 : #include <m_args.h>
18 : #include <m_list.h>
19 : #define LIB_OPT_TOKEN_HELP 'h'
20 : #define LIB_OPT_STRING_HELP "help"
21 : #define LIB_OPT_TOKEN_VERSION 'V'
22 : #define LIB_OPT_STRING_VERSION "version"
23 :
24 : /*!
25 : * \brief Read the options given by the program
26 : * \param ac Number of argument in av
27 : * \param av Array of string, containing the arguments
28 : * \param args Array of margs_t, containing the preset options. Must end with
29 : * an empty structure.
30 : * \param params Adress of linked list, that will be filled with av with
31 : * flags removed
32 : * \return Number of options read
33 : *
34 : * The read_opt function reads a given list of arguments, and parse the options
35 : * in it. The options are read from the args array.
36 : * If an option is not known, the function calls the help and quit.
37 : * If the option -h | --help is passed, the function call the help and quit.
38 : * If the option -V | --version is passed, the function display the version
39 : * and quit.
40 : *
41 : * \note Only the arguments beginning with - are parsed.
42 : */
43 96 : u32_t read_opt(const int ac, char **av, const mopts_t *opts, \
44 : mlist_t **args) {
45 96 : u32_t ret = 0, i = 1, it, k;
46 : u8_t n_dash;
47 :
48 96 : if (ac == 0 || av == NULL || opts == NULL || args == NULL)
49 30 : return ret;
50 :
51 158 : for (/* Using u32_t i */ u32_t j = 0; i < (u32_t)ac; i++) {
52 :
53 112 : if (av[i] == NULL || strlen(av[i]) == 0)
54 16 : continue ;
55 :
56 96 : n_dash = 0;
57 228 : for (j = 0; av[i][j] != '\0' && av[i][j] == '-'; j++)
58 132 : n_dash++;
59 :
60 : /* Single letter option */
61 96 : if (n_dash == 1) {
62 :
63 : /* If single dash alone, its a parameter */
64 34 : if (strlen(av[i]) < 2) {
65 : /* And we stop reading options. */
66 0 : break ;
67 : }
68 :
69 : /* Builtins options */
70 34 : if (av[i][1] == LIB_OPT_TOKEN_HELP)
71 2 : opt_help(opts, 0);
72 32 : else if (av[i][1] == LIB_OPT_TOKEN_VERSION)
73 2 : p_version(0);
74 :
75 : /* Search the option in the opts array */
76 64 : for (u32_t z = 1; av[i][z] != '\0'; z++) {
77 42 : for (it = 0; !IS_EOL(opts[it]) && opts[it].opt != av[i][z]; it++)
78 : ;
79 :
80 : /* Can't find the option */
81 42 : if (IS_EOL(opts[it])) {
82 2 : m_error("Unknow option -%s\n", &(av[i][z]));
83 2 : opt_help(opts, 1);
84 : } else {
85 40 : if (opts[it].take_arg) {
86 6 : if (i + 1 < (u32_t)ac) {
87 4 : opts[it].callback(av[++i]);
88 4 : ret++;
89 4 : break ;
90 : } else {
91 2 : m_error("Option -%c must take an argument\n",
92 2 : opts[it].opt);
93 2 : opt_help(opts, 1);
94 : }
95 : } else {
96 34 : opts[it].callback(NULL);
97 34 : ret++;
98 : }
99 : }
100 : }
101 :
102 : /* Word option */
103 62 : } else if (n_dash == 2) {
104 46 : bool got_arg = false;
105 :
106 : /* If double dash alone, skip it and then stop reading options */
107 46 : if (strlen(av[i]) < 3) {
108 0 : i++;
109 0 : break ;
110 : }
111 :
112 : /* Builtins options */
113 46 : if (strcmp(&(av[i][2]), LIB_OPT_STRING_HELP) == 0)
114 4 : opt_help(opts, 0);
115 42 : else if (strcmp(&(av[i][2]), LIB_OPT_STRING_VERSION) == 0)
116 4 : p_version(0);
117 :
118 : /* Look for an argument */
119 38 : for (k = 2; av[i][k] != '\0' && av[i][k] != '='; k++)
120 : ;
121 :
122 38 : if (av[i][k] != '\0') {
123 8 : got_arg = true;
124 8 : k -= 2;
125 : } else {
126 30 : k = strlen(av[i]) - 2;
127 : }
128 :
129 : /* Search the option in the opts array */
130 196 : for (it = 0; !IS_EOL(opts[it]) &&
131 120 : (strncmp(opts[it].s_opt, &(av[i][2]), k) != 0); it++)
132 : ;
133 :
134 : /* Can't find the option */
135 38 : if (IS_EOL(opts[it])) {
136 2 : m_error("Unknown option %s\n", av[i]);
137 2 : opt_help(opts, 1);
138 : } else {
139 36 : if (opts[it].take_arg && !got_arg) {
140 2 : m_error("Option %s must take an argument", opts[it].s_opt);
141 2 : opt_help(opts, 1);
142 : }
143 34 : if (got_arg)
144 8 : opts[it].callback(&(av[i][k + 3]));
145 : else
146 26 : opts[it].callback(NULL);
147 34 : ret++;
148 : }
149 : /* Not beginning with a dash */
150 : } else {
151 : /* Stop reading options */
152 16 : list_add(*args, av[i], strlen(av[i]) + 1);
153 : }
154 : }
155 : /* If reading of flags is stopped by '-' or '--'
156 : * get the rest of the parameters */
157 46 : for ( /* Using u32_t i */ ; i < (u32_t)ac; i++) {
158 0 : if (av[i] && strlen(av[i]))
159 0 : list_add(*args, av[i], strlen(av[i]) + 1);
160 : }
161 46 : return ret;
162 : }
163 :
164 : /*!
165 : * \brief Print helps with a list of argument, and exit
166 : * \param opts List of arguments to print
167 : * \param ret Return code of the exit
168 : */
169 14 : void opt_help(const mopts_t *opts, u8_t ret) {
170 14 : m_info("Help:\n");
171 48 : for (u32_t i = 0; opts[i].opt != 0; i++) {
172 34 : m_info("\t-%c | --%s : %s\n", opts[i].opt, opts[i].s_opt, opts[i].desc);
173 : }
174 14 : write(1, "\n", 1);
175 14 : m_info("If an argument requires a value, you can set it two ways:\n");
176 14 : m_info("\t-o value\n");
177 14 : m_info("\t--option=value\n");
178 14 : exit(ret);
179 : }
180 :
181 : /*!
182 : * \brief Print the program name, the version and the maintainer, then exit
183 : * \param ret Return code of the exit
184 : */
185 6 : void p_version(u8_t ret) {
186 6 : m_info("Program: %s\n", get_program_name());
187 6 : m_info("Version: %s\n", get_version());
188 6 : m_info("%s\n", get_maintainer());
189 6 : exit(ret);
190 : }
|