Blender  V2.93
BLI_args.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
25 #include <ctype.h> /* for tolower */
26 #include <stdio.h>
27 #include <string.h>
28 
29 #include "MEM_guardedalloc.h"
30 
31 #include "BLI_args.h"
32 #include "BLI_ghash.h"
33 #include "BLI_listbase.h"
34 #include "BLI_string.h"
35 #include "BLI_utildefines.h"
36 
37 static char NO_DOCS[] = "NO DOCUMENTATION SPECIFIED";
38 
39 struct bArgDoc;
40 typedef struct bArgDoc {
41  struct bArgDoc *next, *prev;
42  const char *short_arg;
43  const char *long_arg;
44  const char *documentation;
45  bool done;
47 
48 typedef struct bAKey {
49  const char *arg;
50  uintptr_t pass; /* cast easier */
51  int case_str; /* case specific or not */
53 
54 typedef struct bArgument {
57  void *data;
60 
61 struct bArgs {
64  int argc;
65  const char **argv;
66  int *passes;
67 
68  /* Only use when initializing arguments. */
70 };
71 
72 static uint case_strhash(const void *ptr)
73 {
74  const char *s = ptr;
75  uint i = 0;
76  unsigned char c;
77 
78  while ((c = tolower(*s++))) {
79  i = i * 37 + c;
80  }
81 
82  return i;
83 }
84 
85 static uint keyhash(const void *ptr)
86 {
87  const bAKey *k = ptr;
88  return case_strhash(k->arg); /* ^ BLI_ghashutil_inthash((void *)k->pass); */
89 }
90 
91 static bool keycmp(const void *a, const void *b)
92 {
93  const bAKey *ka = a;
94  const bAKey *kb = b;
95  if (ka->pass == kb->pass || ka->pass == -1 || kb->pass == -1) { /* -1 is wildcard for pass */
96  if (ka->case_str == 1 || kb->case_str == 1) {
97  return (BLI_strcasecmp(ka->arg, kb->arg) != 0);
98  }
99  return (!STREQ(ka->arg, kb->arg));
100  }
101  return BLI_ghashutil_intcmp((const void *)ka->pass, (const void *)kb->pass);
102 }
103 
104 static bArgument *lookUp(struct bArgs *ba, const char *arg, int pass, int case_str)
105 {
106  bAKey key;
107 
108  key.case_str = case_str;
109  key.pass = pass;
110  key.arg = arg;
111 
112  return BLI_ghash_lookup(ba->items, &key);
113 }
114 
115 bArgs *BLI_args_create(int argc, const char **argv)
116 {
117  bArgs *ba = MEM_callocN(sizeof(bArgs), "bArgs");
118  ba->passes = MEM_callocN(sizeof(int) * argc, "bArgs passes");
119  ba->items = BLI_ghash_new(keyhash, keycmp, "bArgs passes gh");
120  BLI_listbase_clear(&ba->docs);
121  ba->argc = argc;
122  ba->argv = argv;
123 
124  /* Must be initialized by #BLI_args_pass_set. */
125  ba->current_pass = 0;
126 
127  return ba;
128 }
129 
130 void BLI_args_destroy(struct bArgs *ba)
131 {
133  MEM_freeN(ba->passes);
134  BLI_freelistN(&ba->docs);
135  MEM_freeN(ba);
136 }
137 
138 void BLI_args_pass_set(struct bArgs *ba, int current_pass)
139 {
140  BLI_assert((current_pass != 0) && (current_pass >= -1));
141  ba->current_pass = current_pass;
142 }
143 
144 void BLI_args_print(struct bArgs *ba)
145 {
146  int i;
147  for (i = 0; i < ba->argc; i++) {
148  printf("argv[%d] = %s\n", i, ba->argv[i]);
149  }
150 }
151 
152 static bArgDoc *internalDocs(struct bArgs *ba,
153  const char *short_arg,
154  const char *long_arg,
155  const char *doc)
156 {
157  bArgDoc *d;
158 
159  d = MEM_callocN(sizeof(bArgDoc), "bArgDoc");
160 
161  if (doc == NULL) {
162  doc = NO_DOCS;
163  }
164 
165  d->short_arg = short_arg;
166  d->long_arg = long_arg;
167  d->documentation = doc;
168 
169  BLI_addtail(&ba->docs, d);
170 
171  return d;
172 }
173 
174 static void internalAdd(
175  struct bArgs *ba, const char *arg, int case_str, BA_ArgCallback cb, void *data, bArgDoc *d)
176 {
177  const int pass = ba->current_pass;
178  bArgument *a;
179  bAKey *key;
180 
181  a = lookUp(ba, arg, pass, case_str);
182 
183  if (a) {
184  printf("WARNING: conflicting argument\n");
185  printf("\ttrying to add '%s' on pass %i, %scase sensitive\n",
186  arg,
187  pass,
188  case_str == 1 ? "not " : "");
189  printf("\tconflict with '%s' on pass %i, %scase sensitive\n\n",
190  a->key->arg,
191  (int)a->key->pass,
192  a->key->case_str == 1 ? "not " : "");
193  }
194 
195  a = MEM_callocN(sizeof(bArgument), "bArgument");
196  key = MEM_callocN(sizeof(bAKey), "bAKey");
197 
198  key->arg = arg;
199  key->pass = pass;
200  key->case_str = case_str;
201 
202  a->key = key;
203  a->func = cb;
204  a->data = data;
205  a->doc = d;
206 
207  BLI_ghash_insert(ba->items, key, a);
208 }
209 
210 void BLI_args_add_case(struct bArgs *ba,
211  const char *short_arg,
212  int short_case,
213  const char *long_arg,
214  int long_case,
215  const char *doc,
216  BA_ArgCallback cb,
217  void *data)
218 {
219  bArgDoc *d = internalDocs(ba, short_arg, long_arg, doc);
220 
221  if (short_arg) {
222  internalAdd(ba, short_arg, short_case, cb, data, d);
223  }
224 
225  if (long_arg) {
226  internalAdd(ba, long_arg, long_case, cb, data, d);
227  }
228 }
229 
230 void BLI_args_add(struct bArgs *ba,
231  const char *short_arg,
232  const char *long_arg,
233  const char *doc,
234  BA_ArgCallback cb,
235  void *data)
236 {
237  BLI_args_add_case(ba, short_arg, 0, long_arg, 0, doc, cb, data);
238 }
239 
240 static void internalDocPrint(bArgDoc *d)
241 {
242  if (d->short_arg && d->long_arg) {
243  printf("%s or %s", d->short_arg, d->long_arg);
244  }
245  else if (d->short_arg) {
246  printf("%s", d->short_arg);
247  }
248  else if (d->long_arg) {
249  printf("%s", d->long_arg);
250  }
251 
252  printf(" %s\n\n", d->documentation);
253 }
254 
255 void BLI_args_print_arg_doc(struct bArgs *ba, const char *arg)
256 {
257  bArgument *a = lookUp(ba, arg, -1, -1);
258 
259  if (a) {
260  bArgDoc *d = a->doc;
261 
262  internalDocPrint(d);
263 
264  d->done = true;
265  }
266 }
267 
269 {
270  bArgDoc *d;
271 
272  for (d = ba->docs.first; d; d = d->next) {
273  if (d->done == 0) {
274  internalDocPrint(d);
275  }
276  }
277 }
278 
279 bool BLI_args_has_other_doc(const struct bArgs *ba)
280 {
281  for (const bArgDoc *d = ba->docs.first; d; d = d->next) {
282  if (d->done == 0) {
283  return true;
284  }
285  }
286  return false;
287 }
288 
289 void BLI_args_parse(struct bArgs *ba, int pass, BA_ArgCallback default_cb, void *default_data)
290 {
291  BLI_assert((pass != 0) && (pass >= -1));
292  int i = 0;
293 
294  for (i = 1; i < ba->argc; i++) { /* skip argv[0] */
295  if (ba->passes[i] == 0) {
296  /* -1 signal what side of the comparison it is */
297  bArgument *a = lookUp(ba, ba->argv[i], pass, -1);
298  BA_ArgCallback func = NULL;
299  void *data = NULL;
300 
301  if (a) {
302  func = a->func;
303  data = a->data;
304  }
305  else {
306  func = default_cb;
307  data = default_data;
308  }
309 
310  if (func) {
311  int retval = func(ba->argc - i, ba->argv + i, data);
312 
313  if (retval >= 0) {
314  int j;
315 
316  /* use extra arguments */
317  for (j = 0; j <= retval; j++) {
318  ba->passes[i + j] = pass;
319  }
320  i += retval;
321  }
322  else if (retval == -1) {
323  if (a) {
324  if (a->key->pass != -1) {
325  ba->passes[i] = pass;
326  }
327  }
328  break;
329  }
330  }
331  }
332  }
333 }
void BLI_args_print(struct bArgs *ba)
Definition: BLI_args.c:144
void BLI_args_destroy(struct bArgs *ba)
Definition: BLI_args.c:130
bArgs * BLI_args_create(int argc, const char **argv)
Definition: BLI_args.c:115
static bArgument * lookUp(struct bArgs *ba, const char *arg, int pass, int case_str)
Definition: BLI_args.c:104
void BLI_args_print_other_doc(struct bArgs *ba)
Definition: BLI_args.c:268
void BLI_args_print_arg_doc(struct bArgs *ba, const char *arg)
Definition: BLI_args.c:255
static void internalAdd(struct bArgs *ba, const char *arg, int case_str, BA_ArgCallback cb, void *data, bArgDoc *d)
Definition: BLI_args.c:174
void BLI_args_add_case(struct bArgs *ba, const char *short_arg, int short_case, const char *long_arg, int long_case, const char *doc, BA_ArgCallback cb, void *data)
Definition: BLI_args.c:210
void BLI_args_pass_set(struct bArgs *ba, int current_pass)
Definition: BLI_args.c:138
static bool keycmp(const void *a, const void *b)
Definition: BLI_args.c:91
void BLI_args_add(struct bArgs *ba, const char *short_arg, const char *long_arg, const char *doc, BA_ArgCallback cb, void *data)
Definition: BLI_args.c:230
struct bArgDoc bArgDoc
bool BLI_args_has_other_doc(const struct bArgs *ba)
Definition: BLI_args.c:279
static void internalDocPrint(bArgDoc *d)
Definition: BLI_args.c:240
static uint keyhash(const void *ptr)
Definition: BLI_args.c:85
struct bArgument bArgument
void BLI_args_parse(struct bArgs *ba, int pass, BA_ArgCallback default_cb, void *default_data)
Definition: BLI_args.c:289
static uint case_strhash(const void *ptr)
Definition: BLI_args.c:72
static char NO_DOCS[]
Definition: BLI_args.c:37
static bArgDoc * internalDocs(struct bArgs *ba, const char *short_arg, const char *long_arg, const char *doc)
Definition: BLI_args.c:152
struct bAKey bAKey
A general argument parsing module.
int(* BA_ArgCallback)(int argc, const char **argv, void *data)
Definition: BLI_args.h:39
#define BLI_assert(a)
Definition: BLI_assert.h:58
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:718
bool BLI_ghashutil_intcmp(const void *a, const void *b)
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:666
unsigned int uint
Definition: BLI_sys_types.h:83
#define STREQ(a, b)
Read Guarded memory(de)allocation.
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static unsigned c
Definition: RandGen.cpp:97
static unsigned a[3]
Definition: RandGen.cpp:92
_W64 unsigned int uintptr_t
Definition: stdint.h:122
void * first
Definition: DNA_listBase.h:47
Definition: BLI_args.c:48
const char * arg
Definition: BLI_args.c:49
uintptr_t pass
Definition: BLI_args.c:50
int case_str
Definition: BLI_args.c:51
const char * documentation
Definition: BLI_args.c:44
struct bArgDoc * prev
Definition: BLI_args.c:41
const char * short_arg
Definition: BLI_args.c:42
bool done
Definition: BLI_args.c:45
struct bArgDoc * next
Definition: BLI_args.c:41
const char * long_arg
Definition: BLI_args.c:43
Definition: BLI_args.c:61
int * passes
Definition: BLI_args.c:66
int current_pass
Definition: BLI_args.c:69
ListBase docs
Definition: BLI_args.c:62
GHash * items
Definition: BLI_args.c:63
const char ** argv
Definition: BLI_args.c:65
int argc
Definition: BLI_args.c:64
void * data
Definition: BLI_args.c:57
BA_ArgCallback func
Definition: BLI_args.c:56
bArgDoc * doc
Definition: BLI_args.c:58
bAKey * key
Definition: BLI_args.c:55
PointerRNA * ptr
Definition: wm_files.c:3157