|
Blender
V2.59
|
00001 /* 00002 * A general argument parsing module 00003 * 00004 * $Id: BLI_args.c 38847 2011-07-30 09:24:10Z campbellbarton $ 00005 * 00006 * ***** BEGIN GPL LICENSE BLOCK ***** 00007 * 00008 * This program is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU General Public License 00010 * as published by the Free Software Foundation; either version 2 00011 * of the License, or (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software Foundation, 00020 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00021 * 00022 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00023 * All rights reserved. 00024 * 00025 * The Original Code is: all of this file. 00026 * 00027 * Contributor(s): none yet. 00028 * 00029 * ***** END GPL LICENSE BLOCK ***** 00030 */ 00031 00037 #include <ctype.h> /* for tolower */ 00038 00039 #include "MEM_guardedalloc.h" 00040 00041 #include "BLI_listbase.h" 00042 #include "BLI_string.h" 00043 #include "BLI_utildefines.h" 00044 #include "BLI_args.h" 00045 #include "BLI_ghash.h" 00046 00047 static char NO_DOCS[] = "NO DOCUMENTATION SPECIFIED"; 00048 00049 struct bArgDoc; 00050 typedef struct bArgDoc { 00051 struct bArgDoc *next, *prev; 00052 const char *short_arg; 00053 const char *long_arg; 00054 const char *documentation; 00055 int done; 00056 } bArgDoc; 00057 00058 typedef struct bAKey { 00059 const char *arg; 00060 uintptr_t pass; /* cast easier */ 00061 int case_str; /* case specific or not */ 00062 } bAKey; 00063 00064 typedef struct bArgument { 00065 bAKey *key; 00066 BA_ArgCallback func; 00067 void *data; 00068 bArgDoc *doc; 00069 } bArgument; 00070 00071 struct bArgs { 00072 ListBase docs; 00073 GHash *items; 00074 int argc; 00075 const char **argv; 00076 int *passes; 00077 }; 00078 00079 static unsigned int case_strhash(const void *ptr) { 00080 const char *s= ptr; 00081 unsigned int i= 0; 00082 unsigned char c; 00083 00084 while ( (c= tolower(*s++)) ) 00085 i= i*37 + c; 00086 00087 return i; 00088 } 00089 00090 static unsigned int keyhash(const void *ptr) 00091 { 00092 const bAKey *k = ptr; 00093 return case_strhash(k->arg); // ^ BLI_ghashutil_inthash((void*)k->pass); 00094 } 00095 00096 static int keycmp(const void *a, const void *b) 00097 { 00098 const bAKey *ka = a; 00099 const bAKey *kb = b; 00100 if (ka->pass == kb->pass || ka->pass == -1 || kb->pass == -1) { /* -1 is wildcard for pass */ 00101 if (ka->case_str == 1 || kb->case_str == 1) 00102 return BLI_strcasecmp(ka->arg, kb->arg); 00103 else 00104 return strcmp(ka->arg, kb->arg); 00105 } else { 00106 return BLI_ghashutil_intcmp((const void*)ka->pass, (const void*)kb->pass); 00107 } 00108 } 00109 00110 static bArgument *lookUp(struct bArgs *ba, const char *arg, int pass, int case_str) 00111 { 00112 bAKey key; 00113 00114 key.case_str = case_str; 00115 key.pass = pass; 00116 key.arg = arg; 00117 00118 return BLI_ghash_lookup(ba->items, &key); 00119 } 00120 00121 bArgs *BLI_argsInit(int argc, const char **argv) 00122 { 00123 bArgs *ba = MEM_callocN(sizeof(bArgs), "bArgs"); 00124 ba->passes = MEM_callocN(sizeof(int) * argc, "bArgs passes"); 00125 ba->items = BLI_ghash_new(keyhash, keycmp, "bArgs passes gh"); 00126 ba->docs.first = ba->docs.last = NULL; 00127 ba->argc = argc; 00128 ba->argv = argv; 00129 00130 return ba; 00131 } 00132 00133 static void freeItem(void *val) 00134 { 00135 MEM_freeN(val); 00136 } 00137 00138 void BLI_argsFree(struct bArgs *ba) 00139 { 00140 BLI_ghash_free(ba->items, freeItem, freeItem); 00141 MEM_freeN(ba->passes); 00142 BLI_freelistN(&ba->docs); 00143 MEM_freeN(ba); 00144 } 00145 00146 void BLI_argsPrint(struct bArgs *ba) 00147 { 00148 int i; 00149 for (i = 0; i < ba->argc; i++) { 00150 printf("argv[%d] = %s\n", i, ba->argv[i]); 00151 } 00152 } 00153 00154 const char **BLI_argsArgv(struct bArgs *ba) 00155 { 00156 return ba->argv; 00157 } 00158 00159 static bArgDoc *internalDocs(struct bArgs *ba, const char *short_arg, const char *long_arg, const char *doc) 00160 { 00161 bArgDoc *d; 00162 00163 d = MEM_callocN(sizeof(bArgDoc), "bArgDoc"); 00164 00165 if (doc == NULL) 00166 doc = NO_DOCS; 00167 00168 d->short_arg = short_arg; 00169 d->long_arg = long_arg; 00170 d->documentation = doc; 00171 00172 BLI_addtail(&ba->docs, d); 00173 00174 return d; 00175 } 00176 00177 static void internalAdd(struct bArgs *ba, const char *arg, int pass, int case_str, BA_ArgCallback cb, void *data, bArgDoc *d) 00178 { 00179 bArgument *a; 00180 bAKey *key; 00181 00182 a = lookUp(ba, arg, pass, case_str); 00183 00184 if (a) { 00185 printf("WARNING: conflicting argument\n"); 00186 printf("\ttrying to add '%s' on pass %i, %scase sensitive\n", arg, pass, case_str == 1? "not ": ""); 00187 printf("\tconflict with '%s' on pass %i, %scase sensitive\n\n", a->key->arg, (int)a->key->pass, a->key->case_str == 1? "not ": ""); 00188 } 00189 00190 a = MEM_callocN(sizeof(bArgument), "bArgument"); 00191 key = MEM_callocN(sizeof(bAKey), "bAKey"); 00192 00193 key->arg = arg; 00194 key->pass = pass; 00195 key->case_str = case_str; 00196 00197 a->key = key; 00198 a->func = cb; 00199 a->data = data; 00200 a->doc = d; 00201 00202 BLI_ghash_insert(ba->items, key, a); 00203 } 00204 00205 void BLI_argsAddCase(struct bArgs *ba, int pass, const char *short_arg, int short_case, const char *long_arg, int long_case, const char *doc, BA_ArgCallback cb, void *data) 00206 { 00207 bArgDoc *d = internalDocs(ba, short_arg, long_arg, doc); 00208 00209 if (short_arg) 00210 internalAdd(ba, short_arg, pass, short_case, cb, data, d); 00211 00212 if (long_arg) 00213 internalAdd(ba, long_arg, pass, long_case, cb, data, d); 00214 00215 00216 } 00217 00218 void BLI_argsAdd(struct bArgs *ba, int pass, const char *short_arg, const char *long_arg, const char *doc, BA_ArgCallback cb, void *data) 00219 { 00220 BLI_argsAddCase(ba, pass, short_arg, 0, long_arg, 0, doc, cb, data); 00221 } 00222 00223 static void internalDocPrint(bArgDoc *d) 00224 { 00225 if (d->short_arg && d->long_arg) 00226 printf("%s or %s", d->short_arg, d->long_arg); 00227 else if (d->short_arg) 00228 printf("%s", d->short_arg); 00229 else if (d->long_arg) 00230 printf("%s", d->long_arg); 00231 00232 printf(" %s\n\n", d->documentation); 00233 } 00234 00235 void BLI_argsPrintArgDoc(struct bArgs *ba, const char *arg) 00236 { 00237 bArgument *a = lookUp(ba, arg, -1, -1); 00238 00239 if (a) 00240 { 00241 bArgDoc *d = a->doc; 00242 00243 internalDocPrint(d); 00244 00245 d->done = 1; 00246 } 00247 } 00248 00249 void BLI_argsPrintOtherDoc(struct bArgs *ba) 00250 { 00251 bArgDoc *d; 00252 00253 for( d = ba->docs.first; d; d = d->next) 00254 { 00255 if (d->done == 0) 00256 { 00257 internalDocPrint(d); 00258 } 00259 } 00260 } 00261 00262 void BLI_argsParse(struct bArgs *ba, int pass, BA_ArgCallback default_cb, void *default_data) 00263 { 00264 int i = 0; 00265 00266 for( i = 1; i < ba->argc; i++) { /* skip argv[0] */ 00267 if (ba->passes[i] == 0) { 00268 /* -1 signal what side of the comparison it is */ 00269 bArgument *a = lookUp(ba, ba->argv[i], pass, -1); 00270 BA_ArgCallback func = NULL; 00271 void *data = NULL; 00272 00273 if (a) { 00274 func = a->func; 00275 data = a->data; 00276 } else { 00277 func = default_cb; 00278 data = default_data; 00279 } 00280 00281 if (func) { 00282 int retval = func(ba->argc - i, ba->argv + i, data); 00283 00284 if (retval >= 0) { 00285 int j; 00286 00287 /* use extra arguments */ 00288 for (j = 0; j <= retval; j++) { 00289 ba->passes[i + j] = pass; 00290 } 00291 i += retval; 00292 } else if (retval == -1){ 00293 if (a) { 00294 if (a->key->pass != -1) 00295 ba->passes[i] = pass; 00296 } 00297 break; 00298 } 00299 } 00300 } 00301 } 00302 }