Blender V5.0
BLI_args.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9
10#include <cctype> /* for tolower */
11#include <cstdio>
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
30#define USE_DUPLICATE_ARG_WORKAROUND
31
32static char NO_DOCS[] = "NO DOCUMENTATION SPECIFIED";
33
34struct bArgDoc;
35struct bArgDoc {
37 const char *short_arg;
38 const char *long_arg;
39 const char *documentation;
40 bool done;
41};
42
43struct bAKey {
44 const char *arg;
45 uintptr_t pass; /* cast easier */
46 int case_str; /* case specific or not */
47};
48
55
56struct bArgs {
59 int argc;
60 const char **argv;
61 int *passes;
65
68#ifdef USE_DUPLICATE_ARG_WORKAROUND
71#endif
72};
73
74static uint case_strhash(const void *ptr)
75{
76 const char *s = static_cast<const char *>(ptr);
77 uint i = 0;
78 uchar c;
79
80 while ((c = tolower(*s++))) {
81 i = i * 37 + c;
82 }
83
84 return i;
85}
86
87static uint keyhash(const void *ptr)
88{
89 const bAKey *k = static_cast<const bAKey *>(ptr);
90 return case_strhash(k->arg); /* ^ BLI_ghashutil_inthash((void *)k->pass); */
91}
92
93static bool keycmp(const void *a, const void *b)
94{
95 const bAKey *ka = static_cast<const bAKey *>(a);
96 const bAKey *kb = static_cast<const bAKey *>(b);
97 if (ka->pass == kb->pass || ka->pass == -1 || kb->pass == -1) { /* -1 is wildcard for pass */
98 if (ka->case_str == 1 || kb->case_str == 1) {
99 return (BLI_strcasecmp(ka->arg, kb->arg) != 0);
100 }
101 return !STREQ(ka->arg, kb->arg);
102 }
103 return BLI_ghashutil_intcmp((const void *)ka->pass, (const void *)kb->pass);
104}
105
106static bArgument *lookUp(bArgs *ba, const char *arg, int pass, int case_str)
107{
108 bAKey key;
109
110 key.case_str = case_str;
111 key.pass = pass;
112 key.arg = arg;
113
114 return static_cast<bArgument *>(BLI_ghash_lookup(ba->items, &key));
115}
116
119static void args_print_wrapper(void * /*user_data*/, const char *format, va_list args)
120{
121 vprintf(format, args);
122}
123
124bArgs *BLI_args_create(int argc, const char **argv)
125{
126 bArgs *ba = MEM_callocN<bArgs>("bArgs");
127 ba->passes = MEM_calloc_arrayN<int>(argc, "bArgs passes");
128 ba->items = BLI_ghash_new(keyhash, keycmp, "bArgs passes gh");
130 ba->argc = argc;
131 ba->argv = argv;
132
133 /* Must be initialized by #BLI_args_pass_set. */
134 ba->current_pass = 0;
135#ifdef USE_DUPLICATE_ARG_WORKAROUND
136 ba->pass_max = 0;
137#endif
138
140
141 return ba;
142}
143
145{
147 MEM_freeN(ba->passes);
148 BLI_freelistN(&ba->docs);
149 MEM_freeN(ba);
150}
151
152void BLI_args_printf(bArgs *ba, const char *format, ...)
153{
154 va_list args;
155 va_start(args, format);
156 ba->print_fn(ba->print_user_data, format, args);
157 va_end(args);
158}
159
160void BLI_args_print_fn_set(bArgs *ba, bArgPrintFn print_fn, void *user_data)
161{
162 ba->print_fn = print_fn;
163 ba->print_user_data = user_data;
164}
165
166void BLI_args_pass_set(bArgs *ba, int current_pass)
167{
168 BLI_assert((current_pass != 0) && (current_pass >= -1));
169 ba->current_pass = current_pass;
170
171#ifdef USE_DUPLICATE_ARG_WORKAROUND
172 ba->pass_max = std::max(ba->pass_max, current_pass);
173#endif
174}
175
176void BLI_args_print(const bArgs *ba)
177{
178 int i;
179 for (i = 0; i < ba->argc; i++) {
180 printf("argv[%d] = %s\n", i, ba->argv[i]);
181 }
182}
183
185 const char *short_arg,
186 const char *long_arg,
187 const char *doc)
188{
189 bArgDoc *d;
190
191 d = MEM_callocN<bArgDoc>("bArgDoc");
192
193 if (doc == nullptr) {
194 doc = NO_DOCS;
195 }
196
197 d->short_arg = short_arg;
198 d->long_arg = long_arg;
199 d->documentation = doc;
200
201 BLI_addtail(&ba->docs, d);
202
203 return d;
204}
205
206static void internalAdd(
207 bArgs *ba, const char *arg, int case_str, BA_ArgCallback cb, void *data, bArgDoc *d)
208{
209 const int pass = ba->current_pass;
210 bArgument *a;
211 bAKey *key;
212
213 a = lookUp(ba, arg, pass, case_str);
214
215 if (a) {
216 printf("WARNING: conflicting argument\n");
217 printf("\ttrying to add '%s' on pass %i, %scase sensitive\n",
218 arg,
219 pass,
220 case_str == 1 ? "not " : "");
221 printf("\tconflict with '%s' on pass %i, %scase sensitive\n\n",
222 a->key->arg,
223 int(a->key->pass),
224 a->key->case_str == 1 ? "not " : "");
225 }
226
227 a = MEM_callocN<bArgument>("bArgument");
228 key = MEM_callocN<bAKey>("bAKey");
229
230 key->arg = arg;
231 key->pass = pass;
232 key->case_str = case_str;
233
234 a->key = key;
235 a->func = cb;
236 a->data = data;
237 a->doc = d;
238
239 BLI_ghash_insert(ba->items, key, a);
240}
241
243 const char *short_arg,
244 int short_case,
245 const char *long_arg,
246 int long_case,
247 const char *doc,
249 void *data)
250{
251 bArgDoc *d = internalDocs(ba, short_arg, long_arg, doc);
252
253 if (short_arg) {
254 internalAdd(ba, short_arg, short_case, cb, data, d);
255 }
256
257 if (long_arg) {
258 internalAdd(ba, long_arg, long_case, cb, data, d);
259 }
260}
261
263 const char *short_arg,
264 const char *long_arg,
265 const char *doc,
267 void *data)
268{
269 BLI_args_add_case(ba, short_arg, 0, long_arg, 0, doc, cb, data);
270}
271
272static void internalDocPrint(bArgs *ba, bArgDoc *d)
273{
274 if (d->short_arg && d->long_arg) {
275 BLI_args_printf(ba, "%s or %s", d->short_arg, d->long_arg);
276 }
277 else if (d->short_arg) {
278 BLI_args_printf(ba, "%s", d->short_arg);
279 }
280 else if (d->long_arg) {
281 BLI_args_printf(ba, "%s", d->long_arg);
282 }
283
284 BLI_args_printf(ba, " %s\n\n", d->documentation);
285}
286
287void BLI_args_print_arg_doc(bArgs *ba, const char *arg)
288{
289#ifdef USE_DUPLICATE_ARG_WORKAROUND
290 bArgument *a = nullptr;
291 /* Find the first argument which has not been printed. */
292 for (int pass = 0; pass <= ba->pass_max; pass++) {
293 a = lookUp(ba, arg, pass, -1);
294 if (a != nullptr) {
295 const bArgDoc *d = a->doc;
296 if (d->done == true) {
297 a = nullptr;
298 }
299 }
300 if (a) {
301 break;
302 }
303 }
304#else
305 bArgument *a = lookUp(ba, arg, -1, -1);
306#endif
307
308 if (a) {
309 bArgDoc *d = a->doc;
310
311 internalDocPrint(ba, d);
312
313 d->done = true;
314 }
315}
316
318{
319 LISTBASE_FOREACH (bArgDoc *, d, &ba->docs) {
320 if (d->done == 0) {
321 internalDocPrint(ba, d);
322 }
323 }
324}
325
327{
328 LISTBASE_FOREACH (const bArgDoc *, d, &ba->docs) {
329 if (d->done == 0) {
330 return true;
331 }
332 }
333 return false;
334}
335
336void BLI_args_parse(bArgs *ba, int pass, BA_ArgCallback default_cb, void *default_data)
337{
338 BLI_assert((pass != 0) && (pass >= -1));
339 int i = 0;
340
341 for (i = 1; i < ba->argc; i++) { /* skip argv[0] */
342 if (ba->passes[i] == 0) {
343 /* -1 signal what side of the comparison it is */
344 bArgument *a = lookUp(ba, ba->argv[i], pass, -1);
345 BA_ArgCallback func = nullptr;
346 void *data = nullptr;
347
348 if (a) {
349 func = a->func;
350 data = a->data;
351 }
352 else {
353 func = default_cb;
354 data = default_data;
355 }
356
357 if (func) {
358 int retval = func(ba->argc - i, ba->argv + i, data);
359
360 if (retval >= 0) {
361 int j;
362
363 /* use extra arguments */
364 for (j = 0; j <= retval; j++) {
365 ba->passes[i + j] = pass;
366 }
367 i += retval;
368 }
369 else if (retval == -1) {
370 if (a) {
371 if (a->key->pass != -1) {
372 ba->passes[i] = pass;
373 }
374 }
375 break;
376 }
377 }
378 }
379 }
380}
static bArgument * lookUp(bArgs *ba, const char *arg, int pass, int case_str)
Definition BLI_args.cc:106
static void internalDocPrint(bArgs *ba, bArgDoc *d)
Definition BLI_args.cc:272
static void args_print_wrapper(void *, const char *format, va_list args)
Definition BLI_args.cc:119
bool BLI_args_has_other_doc(const bArgs *ba)
Definition BLI_args.cc:326
static bool keycmp(const void *a, const void *b)
Definition BLI_args.cc:93
void BLI_args_add(bArgs *ba, const char *short_arg, const char *long_arg, const char *doc, BA_ArgCallback cb, void *data)
Definition BLI_args.cc:262
void BLI_args_add_case(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.cc:242
void BLI_args_destroy(bArgs *ba)
Definition BLI_args.cc:144
void BLI_args_printf(bArgs *ba, const char *format,...)
Definition BLI_args.cc:152
void BLI_args_print_other_doc(bArgs *ba)
Definition BLI_args.cc:317
bArgs * BLI_args_create(int argc, const char **argv)
Definition BLI_args.cc:124
void BLI_args_print(const bArgs *ba)
Definition BLI_args.cc:176
static uint keyhash(const void *ptr)
Definition BLI_args.cc:87
static void internalAdd(bArgs *ba, const char *arg, int case_str, BA_ArgCallback cb, void *data, bArgDoc *d)
Definition BLI_args.cc:206
void BLI_args_pass_set(bArgs *ba, int current_pass)
Definition BLI_args.cc:166
static uint case_strhash(const void *ptr)
Definition BLI_args.cc:74
void BLI_args_print_fn_set(bArgs *ba, bArgPrintFn print_fn, void *user_data)
Definition BLI_args.cc:160
static bArgDoc * internalDocs(bArgs *ba, const char *short_arg, const char *long_arg, const char *doc)
Definition BLI_args.cc:184
static char NO_DOCS[]
Definition BLI_args.cc:32
void BLI_args_print_arg_doc(bArgs *ba, const char *arg)
Definition BLI_args.cc:287
void BLI_args_parse(bArgs *ba, int pass, BA_ArgCallback default_cb, void *default_data)
Definition BLI_args.cc:336
A general argument parsing module.
int(*)(int argc, const char **argv, void *data) BA_ArgCallback
Definition BLI_args.h:24
void(*)(void *user_data, const char *format, va_list args) bArgPrintFn
Definition BLI_args.h:29
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ATTR_PRINTF_FORMAT(format_param, dots_param)
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:686
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.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
int char char int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
unsigned char uchar
unsigned int uint
#define STREQ(a, b)
Read Guarded memory(de)allocation.
BMesh const char void * data
#define printf(...)
format
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
const char * arg
Definition BLI_args.cc:44
uintptr_t pass
Definition BLI_args.cc:45
int case_str
Definition BLI_args.cc:46
const char * documentation
Definition BLI_args.cc:39
bArgDoc * next
Definition BLI_args.cc:36
bArgDoc * prev
Definition BLI_args.cc:36
const char * short_arg
Definition BLI_args.cc:37
bool done
Definition BLI_args.cc:40
const char * long_arg
Definition BLI_args.cc:38
bArgPrintFn print_fn
Definition BLI_args.cc:63
int * passes
Definition BLI_args.cc:61
int current_pass
Definition BLI_args.cc:67
int pass_max
Definition BLI_args.cc:70
ListBase docs
Definition BLI_args.cc:57
GHash * items
Definition BLI_args.cc:58
void * print_user_data
Definition BLI_args.cc:64
const char ** argv
Definition BLI_args.cc:60
int argc
Definition BLI_args.cc:59
void * data
Definition BLI_args.cc:52
BA_ArgCallback func
Definition BLI_args.cc:51
bArgDoc * doc
Definition BLI_args.cc:53
bAKey * key
Definition BLI_args.cc:50
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238