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