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