/CBFlib-0.9.2.3/src/cbf_getopt.c

# · C · 676 lines · 291 code · 294 blank · 91 comment · 99 complexity · a07d1917775341bde74ea1ca6dd012d8 MD5 · raw file

  1. /**********************************************************************
  2. * cbf_getopt.c *
  3. * *
  4. * *
  5. * Created by Herbert J. Bernstein on 6/8/09. *
  6. * (C) Copyright 2009 Herbert J. Bernstein *
  7. * *
  8. **********************************************************************/
  9. /**********************************************************************
  10. * *
  11. * YOU MAY REDISTRIBUTE THE CBFLIB PACKAGE UNDER THE TERMS OF THE GPL *
  12. * *
  13. * ALTERNATIVELY YOU MAY REDISTRIBUTE THE CBFLIB API UNDER THE TERMS *
  14. * OF THE LGPL *
  15. * *
  16. **********************************************************************/
  17. /*************************** GPL NOTICES ******************************
  18. * *
  19. * This program is free software; you can redistribute it and/or *
  20. * modify it under the terms of the GNU General Public License as *
  21. * published by the Free Software Foundation; either version 2 of *
  22. * (the License, or (at your option) any later version. *
  23. * *
  24. * This program is distributed in the hope that it will be useful, *
  25. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  26. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  27. * GNU General Public License for more details. *
  28. * *
  29. * You should have received a copy of the GNU General Public License *
  30. * along with this program; if not, write to the Free Software *
  31. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA *
  32. * 02111-1307 USA *
  33. * *
  34. **********************************************************************/
  35. /************************* LGPL NOTICES *******************************
  36. * *
  37. * This library is free software; you can redistribute it and/or *
  38. * modify it under the terms of the GNU Lesser General Public *
  39. * License as published by the Free Software Foundation; either *
  40. * version 2.1 of the License, or (at your option) any later version. *
  41. * *
  42. * This library is distributed in the hope that it will be useful, *
  43. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  44. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
  45. * Lesser General Public License for more details. *
  46. * *
  47. * You should have received a copy of the GNU Lesser General Public *
  48. * License along with this library; if not, write to the Free *
  49. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, *
  50. * MA 02110-1301 USA *
  51. * *
  52. **********************************************************************/
  53. #ifdef __cplusplus
  54. extern "C" {
  55. #endif
  56. #include <cbf.h>
  57. #include <cbf_getopt.h>
  58. #include <cbf_alloc.h>
  59. #include <cbf_context.h>
  60. #include <string.h>
  61. static const char * cbf_getopt_locate_option(const char * options,
  62. char * optchar,
  63. const char * * longopt,
  64. int * hasvalue) {
  65. char c;
  66. if (optchar) *optchar = '\0';
  67. if (longopt) *longopt = NULL;
  68. if (hasvalue) *hasvalue = 0;
  69. if (*options != '(' && *options != ':' && optchar)*optchar = *options;
  70. while ((c=*options)) {
  71. if (c=='(') {
  72. ++options;
  73. if (longopt) *longopt = options;
  74. while ((c=*options) && (c!=')')) {
  75. options++;
  76. }
  77. if (!c) {
  78. return options;
  79. }
  80. } else if (c==':') {
  81. if (hasvalue) *hasvalue = 1;
  82. options ++;
  83. if ((c=*options) && (c==':')) {
  84. if (hasvalue) *hasvalue = -1;
  85. options ++;
  86. }
  87. return options;
  88. } else if (c) {
  89. options ++;
  90. if ((c=*options) && (c=='(' || c==':')) continue;
  91. return options;
  92. }
  93. }
  94. return options;
  95. }
  96. /* create a cbf_getopt handle */
  97. int cbf_make_getopt_handle(cbf_getopt_handle * handle) {
  98. *handle = NULL;
  99. cbf_failnez (cbf_alloc ((void **) handle, NULL,
  100. sizeof (cbf_getopt_struct), 1))
  101. (*handle)->optstructs = NULL;
  102. cbf_onfailnez (cbf_alloc ((void **) &((*handle)->optstructs),
  103. &((*handle)->optstructs_capacity),sizeof(cbf_getopt_optstruct), 10),
  104. cbf_free((void **) handle, NULL))
  105. (*handle)->optstructs_size = 0;
  106. (*handle)->optind = 0; /* ordinal of option in options */
  107. (*handle)->options = NULL;
  108. return 0;
  109. }
  110. /* clear the data in a cbf_getopt handle */
  111. static int cbf_clear_getopt_handle(cbf_getopt_handle handle) {
  112. cbf_getopt_optstruct * optstruct;
  113. size_t index;
  114. for (index = 0; index < handle->optstructs_size; index++) {
  115. optstruct = &(handle->optstructs[index]);
  116. if (optstruct->optstr) {
  117. cbf_failnez(cbf_free_text(&(optstruct->optstr),NULL))
  118. }
  119. if (optstruct->optval) {
  120. cbf_failnez(cbf_free_text(&(optstruct->optval),NULL))
  121. }
  122. }
  123. handle-> optstructs_size = 0;
  124. handle->optind = 0;
  125. if (handle->options) {
  126. cbf_failnez(cbf_free_text(&(handle->options),NULL))
  127. }
  128. return 0;
  129. }
  130. /* free a cbf_getopt handle */
  131. int cbf_free_getopt_handle(cbf_getopt_handle handle) {
  132. void *memblock;
  133. cbf_failnez( cbf_clear_getopt_handle(handle) )
  134. memblock = (void *) handle;
  135. if (handle) {
  136. return cbf_free(&memblock, NULL);
  137. }
  138. return 0;
  139. }
  140. /* parse argc and argv into a newly created cbf_getopt */
  141. int cbf_getopt_parse(cbf_getopt_handle handle, int argc, char ** argv, const char * options) {
  142. int ii, iii, ios;
  143. void * voptstructs;
  144. cbf_getopt_optstruct * optstruct;
  145. const char * opts;
  146. int hasvalue;
  147. const char * longopt;
  148. char optchar;
  149. size_t optlen;
  150. int optord;
  151. int foundopt;
  152. if (handle == NULL || argv == NULL ) return CBF_ARGUMENT;
  153. cbf_failnez( cbf_clear_getopt_handle(handle) )
  154. /* Allocate as many opstruct slots as we have arguments */
  155. if (handle->optstructs) {
  156. voptstructs = (void *)(handle->optstructs);
  157. cbf_failnez(cbf_realloc((void **) &voptstructs,
  158. &(handle->optstructs_capacity),sizeof(cbf_getopt_optstruct),argc))
  159. } else {
  160. cbf_failnez(cbf_alloc((void **) &voptstructs,
  161. &(handle->optstructs_capacity),sizeof(cbf_getopt_optstruct),argc))
  162. }
  163. handle->optstructs = (cbf_getopt_optstruct *)voptstructs;
  164. if (handle->options != NULL) {
  165. cbf_failnez(cbf_free_text((const char * *)&(handle->options),NULL))
  166. }
  167. /* If options have been specified, use them. Otherwise
  168. default to "-"
  169. */
  170. if (options) {
  171. handle->options = cbf_copy_string(NULL,options,0);
  172. } else {
  173. handle->options = cbf_copy_string(NULL,"-",0);
  174. }
  175. handle->optind = 0;
  176. for ( ii=1; ii < argc; ii++) {
  177. /* Prepare the next slot */
  178. optstruct = &((handle->optstructs)[(handle->optind)++]);
  179. (handle->optstructs_size)++;
  180. optstruct->optopt = 0;
  181. optstruct->optord = -1;
  182. optstruct->optstr = NULL;
  183. optstruct->optval = NULL;
  184. /* on --, end the options scan */
  185. if ( !strcmp(argv[ii],"--") ) {
  186. /* copy all remaining arguments as unflagged values */
  187. break;
  188. }
  189. /* process a --option case */
  190. if (!strncmp("--",argv[ii],2)) {
  191. optstruct->optstr = cbf_copy_string(NULL,2+argv[ii],0);
  192. opts = options;
  193. if (*opts=='-' || *opts =='+') opts++;
  194. optlen = strlen(argv[ii]+2);
  195. optord = -1;
  196. foundopt = 0;
  197. do {
  198. opts= cbf_getopt_locate_option(opts, &optchar, &longopt, &hasvalue);
  199. optord++;
  200. if (longopt && !strncmp(longopt,argv[ii]+2,optlen) && longopt[optlen]==')') {
  201. optstruct->optopt = optchar;
  202. optstruct->optord = optord;
  203. optstruct->optval = NULL;
  204. if (ii+1 < argc && (hasvalue >0
  205. || (*(argv[ii+1])!='-'&& hasvalue < 0) )) {
  206. optstruct->optval = cbf_copy_string(NULL,argv[ii+1],0);
  207. ii++;
  208. foundopt++;
  209. break;
  210. }
  211. }
  212. } while (*opts);
  213. if (foundopt) continue;
  214. if (*options == '-') {
  215. optstruct->optopt = '\1';
  216. optstruct->optord = -1;
  217. optstruct->optval = NULL;
  218. if (ii+1 < argc && *(argv[ii+1])!='-' ) {
  219. optstruct->optval = cbf_copy_string(NULL,argv[ii+1],0);
  220. ii++;
  221. break;
  222. }
  223. continue;
  224. }
  225. /* this is not an expected long option and the option string
  226. does not have a leading '-', therefore this is simply
  227. a non-option value
  228. */
  229. if (*options=='+') break;
  230. optstruct->optval = cbf_copy_string(NULL,argv[ii],0);
  231. optstruct->optopt = 0;
  232. optstruct->optord = -1;
  233. cbf_failnez(cbf_free_text(&(optstruct->optstr),NULL))
  234. optstruct->optstr = NULL;
  235. continue;
  236. }
  237. /* now for the single '-' case marking a lone letter option */
  238. if (*(argv[ii]) == '-' && strlen(argv[ii]) > 1 ) {
  239. char xc[2];
  240. xc[0] = argv[ii][1];
  241. xc[1] = '\0';
  242. optstruct->optstr = cbf_copy_string(NULL,xc,0);
  243. opts = options;
  244. if (*opts=='-' || *opts =='+') opts++;
  245. optlen = 1;
  246. optord = -1;
  247. foundopt = 0;
  248. do {
  249. opts= cbf_getopt_locate_option(opts, &optchar, &longopt,&hasvalue);
  250. optord++;
  251. if (xc[0] == optchar) {
  252. optstruct->optopt = optchar;
  253. optstruct->optord = optord;
  254. optstruct->optval = NULL;
  255. if ((strlen(argv[ii]+2) > 0) ||
  256. (ii+1 < argc && (hasvalue >0
  257. || (*(argv[ii+1])!='-'&& hasvalue < 0) ))) {
  258. if (strlen(argv[ii]+2) > 0) {
  259. optstruct->optval = cbf_copy_string(NULL,argv[ii]+2,0);
  260. } else {
  261. optstruct->optval = cbf_copy_string(NULL,argv[ii+1],0);
  262. ii++;
  263. }
  264. }
  265. foundopt++;
  266. break;
  267. }
  268. } while (*opts);
  269. if (foundopt) continue;
  270. if (*options == '-') {
  271. optstruct->optopt = '\1';
  272. optstruct->optord = -1;
  273. optstruct->optval = NULL;
  274. if (ii+1 < argc && *(argv[ii+1])!='-' ) {
  275. optstruct->optval = cbf_copy_string(NULL,argv[ii+1],0);
  276. ii++;
  277. break;
  278. }
  279. continue;
  280. };
  281. /* this is not an expected short option and the option string
  282. does not have a leading '-', therefore this is simply
  283. a non-option value
  284. */
  285. if (*options=='+') break;
  286. optstruct->optval = cbf_copy_string(NULL,argv[ii],0);
  287. optstruct->optopt = 0;
  288. optstruct->optord = -1;
  289. cbf_failnez(cbf_free_text(&(optstruct->optstr),NULL))
  290. optstruct->optstr = NULL;
  291. continue;
  292. }
  293. /* All that is left is to treat this as a non-option value */
  294. optstruct->optval = cbf_copy_string(NULL,argv[ii],0);
  295. optstruct->optopt = 0;
  296. optstruct->optord = -1;
  297. optstruct->optstr = NULL;
  298. if (*options=='+') break;
  299. }
  300. /*
  301. ii is the last argument processed, the remaining arguments get added
  302. at the end
  303. */
  304. ios = handle->optstructs_size;
  305. for (iii = ii+1; iii < argc; iii++) {
  306. optstruct = &((handle->optstructs)[(handle->optind)++]);
  307. (handle->optstructs_size)++;
  308. optstruct->optval = cbf_copy_string(NULL,argv[iii],0);
  309. optstruct->optopt = 0;
  310. optstruct->optord = -1;
  311. optstruct->optstr = NULL;
  312. }
  313. /* if *options is not '-', then all non-options in obstructs need to
  314. be sorted to the end of the list
  315. */
  316. iii = ios-1;
  317. while (iii >= 0) {
  318. cbf_getopt_optstruct temp;
  319. optstruct = &((handle->optstructs)[iii]);
  320. /* Any option with no option ordinal moves up to index ios-1 */
  321. if (optstruct->optord < 0) {
  322. if (iii < ios-1) {
  323. memmove((void *)(&temp),(void *)optstruct,sizeof(cbf_getopt_optstruct));
  324. for (ii = iii; ii < ios-1; ii++) {
  325. memmove((void *)(&((handle->optstructs)[ii])),
  326. (void *)(&((handle->optstructs)[ii+1])), sizeof(cbf_getopt_optstruct));
  327. }
  328. memmove((void *)(&((handle->optstructs)[ios-1])),(void *)(&temp),sizeof(cbf_getopt_optstruct));
  329. }
  330. ios --;
  331. }
  332. iii--;
  333. }
  334. return 0;
  335. }
  336. /* Get first option from a cbf_getopt handle */
  337. int cbf_rewind_getopt_option ( cbf_getopt_handle handle ) {
  338. if ( !handle ) return CBF_ARGUMENT;
  339. handle->optind = 0 ;
  340. if ( handle->optind >= handle->optstructs_size) return CBF_NOTFOUND;
  341. return 0;
  342. }
  343. /* Get next option from a cbf_getopt handle */
  344. int cbf_next_getopt_option ( cbf_getopt_handle handle ){
  345. if ( !handle ) return CBF_ARGUMENT;
  346. handle->optind++;
  347. if ( handle->optind >= handle->optstructs_size) return CBF_NOTFOUND;
  348. return 0;
  349. }
  350. /* Get option by number (0 ... ) from a cbf_getopt handle */
  351. int cbf_select_getopt_option ( cbf_getopt_handle handle, unsigned int option ) {
  352. if ( !handle ) return CBF_ARGUMENT;
  353. if ( option < 0 || option >= handle->optstructs_size) return CBF_ARGUMENT;
  354. handle->optind = option;
  355. return 0;
  356. }
  357. /* Count the options in a cbf_getopt handle */
  358. int cbf_count_getopt_options ( cbf_getopt_handle handle, unsigned int * options ) {
  359. if ( !handle ) return CBF_ARGUMENT;
  360. if ( options ) *options = handle->optstructs_size;
  361. return 0;
  362. }
  363. /* Get the data for an option */
  364. int cbf_get_getopt_data ( cbf_getopt_handle handle, int * optopt,
  365. int * optord, const char * * optstr, const char * * optval) {
  366. cbf_getopt_optstruct * optstruct;
  367. if ( !handle ) return CBF_ARGUMENT;
  368. if ( handle->optind < 0 || handle->optind >= handle->optstructs_size) return CBF_NOTFOUND;
  369. optstruct = &(handle->optstructs[handle->optind]);
  370. if (optopt) *optopt = optstruct->optopt;
  371. if (optord) *optord = optstruct->optord;
  372. if (optstr) *optstr = optstruct->optstr;
  373. if (optval) *optval = optstruct->optval;
  374. return 0;
  375. }
  376. #ifdef __cplusplus
  377. }
  378. #endif