Line data Source code
1 : /***************************************************************************//**
2 :
3 : @file args.c
4 :
5 : @author Stephen Brennan
6 :
7 : @date Created Thursday, 31 October 2013
8 :
9 : @brief Implementations of "libstephen/ad.h".
10 :
11 : @copyright Copyright (c) 2013-2016, Stephen Brennan. Released under the
12 : Revised BSD License. See the LICENSE.txt file for details.
13 :
14 : *******************************************************************************/
15 :
16 : #include <stdio.h>
17 : #include <string.h>
18 : #include <assert.h>
19 : #include <inttypes.h>
20 :
21 : #include "libstephen/base.h"
22 : #include "libstephen/list.h"
23 : #include "libstephen/ad.h"
24 : #include "libstephen/ll.h"
25 :
26 : /*******************************************************************************
27 :
28 : Private Functions
29 :
30 : *******************************************************************************/
31 :
32 : /**
33 : @brief Returns the index of a flag for a specific character.
34 :
35 : Currently, only alphabetical characters are allowed. This could change. See
36 : the top of the file for the todo entry on this.
37 :
38 : @param c The character to find the index of.
39 : @returns The index of the flag.
40 : */
41 155 : int flag_index(char c)
42 : {
43 : int idx;
44 155 : if (c >= 'A' && c <= 'Z') {
45 60 : idx = 26 + (c - 'A');
46 95 : } else if (c >= 'a' && c <= 'z') {
47 78 : idx = (c - 'a');
48 : } else {
49 17 : idx = -1;
50 : }
51 155 : return idx;
52 : }
53 :
54 : /**
55 : @brief Add regular flags (i.e. characters) to the smb_ad structure.
56 :
57 : @param pData The structure containing the arg data.
58 : @param cFlags The string of flags. Null terminated.
59 : @returns The last flag in the string (for parameter purposes).
60 : */
61 17 : char process_flag(smb_ad *pData, char *cFlags)
62 : {
63 : char last;
64 : int idx;
65 :
66 72 : while (*cFlags != '\0') {
67 38 : if ((idx = flag_index(*cFlags)) != -1) {
68 21 : last = *cFlags;
69 21 : pData->flags |= UINT64_C(1) << idx;
70 : }
71 38 : cFlags++;
72 : }
73 17 : return last;
74 : }
75 :
76 : /**
77 : @brief Add the long flag to the data structure.
78 :
79 : @param pData The structure containing the arg data.
80 : @param sTitle The title of the long flag, including '--'
81 : @returns The adjusted pointer to the title, without '--'.
82 : */
83 6 : char *process_long_flag(smb_ad *pData, char *sTitle)
84 : {
85 : DATA d, e;
86 6 : d.data_ptr = sTitle + 2;
87 6 : ll_append(pData->long_flags, d); // Add the portion AFTER the "--"
88 :
89 6 : e.data_ptr = NULL;
90 6 : ll_append(pData->long_flag_strings, e);
91 6 : return sTitle + 2;
92 : }
93 :
94 : /**
95 : @brief Add the bare string to the data structure.
96 :
97 : This function will first attempt to add the string as an argument to the
98 : previous flag, then the previous long flag, and then, finally, it will add
99 : itself as just a bare string.
100 :
101 : @param pData The structure with argument data.
102 : @param sStr The string to add.
103 : @param previous_long_flag The last long flag encountered.
104 : @param previous_flag The last regular (character) flag encountered.
105 : */
106 10 : void process_bare_string(smb_ad *pData, char *sStr, char *previous_long_flag,
107 : int previous_flag)
108 : {
109 10 : if (previous_long_flag) {
110 : DATA d;
111 3 : d.data_ptr = sStr;
112 : smb_status status;
113 3 : ll_set(pData->long_flag_strings, ll_length(pData->long_flag_strings) - 1, d,
114 : &status);
115 3 : assert(status == SMB_SUCCESS);
116 7 : } else if (previous_flag != EOF) {
117 3 : int idx = flag_index(previous_flag);
118 : // The flag index would be negative if the previous flag was not a
119 : // letter. We'll accept the segfault as an error.
120 3 : pData->flag_strings[idx] = sStr;
121 : } else {
122 : DATA d;
123 4 : d.data_ptr = sStr;
124 4 : ll_append(pData->bare_strings, d);
125 : }
126 10 : }
127 :
128 : /**
129 : @brief Find the string in the list and return its index, or -1.
130 :
131 : @param toSearch Pointer to list to search.
132 : @param toFind String to find.
133 : @returns Index of the string.
134 : @retval -1 String is not in the list.
135 : */
136 15 : int find_string(smb_ll *toSearch, char *toFind)
137 : {
138 : DATA d;
139 : char *sCurr;
140 15 : smb_iter iter = ll_get_iter(toSearch);
141 15 : int retVal = -1;
142 : smb_status status;
143 45 : while (iter.has_next(&iter)) {
144 29 : d = iter.next(&iter, &status);
145 : // We are using 'has_next' to check first!
146 29 : assert(status == SMB_SUCCESS);
147 29 : sCurr = (char *)d.data_ptr;
148 29 : if (strcmp(toFind, sCurr) == 0) {
149 14 : retVal = iter.index-1; // previous index
150 14 : break;
151 : }
152 : }
153 15 : iter.destroy(&iter);
154 15 : return retVal;
155 : }
156 :
157 : /*******************************************************************************
158 :
159 : Public Functions
160 :
161 : *******************************************************************************/
162 :
163 8 : void arg_data_init(smb_ad *data)
164 : {
165 8 : data->flags = 0;
166 424 : for (int i = 0; i < MAX_FLAGS; i++) {
167 416 : data->flag_strings[i] = NULL;
168 : }
169 :
170 8 : data->long_flags = ll_create();
171 8 : data->long_flag_strings = ll_create();
172 8 : data->bare_strings = ll_create();
173 8 : return;
174 : }
175 :
176 1 : smb_ad *arg_data_create()
177 : {
178 1 : smb_ad *data = smb_new(smb_ad, 1);
179 1 : arg_data_init(data);
180 1 : return data;
181 : }
182 :
183 8 : void arg_data_destroy(smb_ad * data)
184 : {
185 8 : ll_delete(data->long_flags);
186 8 : ll_delete(data->bare_strings);
187 8 : ll_delete(data->long_flag_strings);
188 8 : }
189 :
190 1 : void arg_data_delete(smb_ad *data)
191 : {
192 1 : arg_data_destroy(data);
193 1 : smb_free(data);
194 1 : }
195 :
196 6 : void process_args(smb_ad *data, int argc, char **argv)
197 : {
198 6 : char *previous_long_flag = NULL;
199 6 : int previous_flag = EOF;
200 :
201 45 : while (argc--) {
202 : // At the beginning of the loop, argc refers to number of remaining args,
203 : // and argv points at the pointer to the current arg.
204 33 : switch (**argv) {
205 : case '-':
206 : // Processing new flag type, so set previous variables to invalid.
207 24 : previous_long_flag = NULL;
208 24 : previous_flag = EOF;
209 24 : switch (*(*argv + 1)) {
210 : case '-':
211 : // Long flag
212 6 : previous_long_flag = process_long_flag(data, *argv);
213 6 : previous_flag = EOF;
214 6 : break;
215 : case '\0':
216 : // A single '-'...counts as a bare string in my book
217 1 : process_bare_string(data, *argv, previous_long_flag, previous_flag);
218 :
219 1 : previous_long_flag = NULL;
220 1 : previous_flag = EOF;
221 1 : break;
222 : default:
223 : // The input is a short flag
224 17 : previous_flag = process_flag(data, *argv);
225 17 : previous_long_flag = NULL;
226 17 : break;
227 : }
228 24 : break;
229 :
230 : default:
231 : // This is a raw string. We first need to check if it belongs to a flag.
232 9 : process_bare_string(data, *argv, previous_long_flag, previous_flag);
233 9 : previous_long_flag = NULL;
234 9 : previous_flag = EOF;
235 9 : break;
236 : }
237 :
238 33 : argv++;
239 : }
240 6 : }
241 :
242 109 : int check_flag(smb_ad *pData, char flag)
243 : {
244 : int signed_idx;
245 : uint64_t idx;
246 109 : signed_idx = flag_index(flag);
247 109 : idx = (uint64_t) signed_idx;
248 109 : if (signed_idx != -1) {
249 109 : idx = pData->flags & (UINT64_C(1) << idx);
250 109 : if (idx) return 1;
251 : }
252 88 : return 0;
253 : }
254 :
255 7 : int check_long_flag(smb_ad *data, char *flag)
256 : {
257 7 : return find_string(data->long_flags, flag) + 1;
258 : }
259 :
260 4 : int check_bare_string(smb_ad *data, char *string)
261 : {
262 4 : return find_string(data->bare_strings, string) + 1;
263 : }
264 :
265 5 : char *get_flag_parameter(smb_ad *data, char flag)
266 : {
267 5 : int index = flag_index(flag);
268 5 : if (index == -1)
269 0 : return NULL;
270 : else
271 5 : return data->flag_strings[index];
272 : }
273 :
274 4 : char *get_long_flag_parameter(smb_ad *data, char *string)
275 : {
276 4 : int index = find_string(data->long_flags, string);
277 4 : if (index == -1)
278 0 : return NULL;
279 : else {
280 : DATA d;
281 : smb_status status;
282 4 : d = ll_get(data->long_flag_strings, index, &status);
283 4 : assert(status == SMB_SUCCESS);
284 4 : return (char*)d.data_ptr;
285 : }
286 : }
287 :
288 0 : void ad_print(smb_ad *data, FILE *f)
289 : {
290 0 : fprintf(f, "Arg Data:\n");
291 0 : fprintf(f, "Flags: 0x%" PRIx64 "\n", data->flags);
292 0 : for (int i = 0; i < MAX_FLAGS; i++) {
293 0 : if (data->flag_strings[i] != NULL) {
294 0 : fprintf(f, "%d: \"%s\"\n", i, data->flag_strings[i]);
295 : }
296 : }
297 0 : fprintf(f, "Long Flags: ");
298 0 : iter_print(ll_get_iter(data->long_flags), f, &data_printer_string);
299 :
300 0 : fprintf(f, "Long Flag Strings: ");
301 0 : iter_print(ll_get_iter(data->long_flag_strings), f, &data_printer_string);
302 :
303 0 : fprintf(f, "Bare Strings: ");
304 0 : iter_print(ll_get_iter(data->bare_strings), f, &data_printer_string);
305 0 : }
|