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