You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

240 lines
6.7KB

  1. /***************************************************************************
  2. * Copyright (C) 10/2010 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; version 2 of the License, *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <unistd.h>
  22. #include <string.h>
  23. #include <getopt.h>
  24. #include "list.h"
  25. #include "optarg.h"
  26. #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
  27. struct optarg_entry
  28. {
  29. struct list_head list;
  30. const struct option *opts;
  31. int count;
  32. int (* parser_cb)(int val, const char *arg, void *privdata);
  33. void *privdata;
  34. };
  35. static LIST_HEAD(option_list);
  36. /* *************************************************************************
  37. * optarg_register
  38. * ************************************************************************* */
  39. int optarg_register(const struct option *opts, int count,
  40. int (* parser_cb)(int val, const char *arg, void *privdata),
  41. void *privdata)
  42. {
  43. struct optarg_entry *entry;
  44. entry = malloc(sizeof(struct optarg_entry));
  45. if (entry == NULL)
  46. {
  47. return -1;
  48. }
  49. entry->opts = opts; /* TODO: copy? */
  50. entry->count = count;
  51. entry->parser_cb = parser_cb;
  52. entry->privdata = privdata;
  53. list_add_tail(&entry->list, &option_list);
  54. return 0;
  55. } /* optarg_register */
  56. /* *************************************************************************
  57. * optarg_free
  58. * ************************************************************************* */
  59. void optarg_free(void)
  60. {
  61. struct optarg_entry *entry, *entry_tmp;
  62. list_for_each_entry_safe(entry, entry_tmp, &option_list, list)
  63. {
  64. list_del(&entry->list);
  65. free(entry);
  66. }
  67. } /* optarg_free */
  68. /* *************************************************************************
  69. * optarg_getsize
  70. * ************************************************************************* */
  71. static void optarg_getsize(int *opt_count, int *optstring_len)
  72. {
  73. int count = 0;
  74. int length = 0;
  75. struct optarg_entry *entry;
  76. list_for_each_entry(entry, &option_list, list)
  77. {
  78. count += entry->count;
  79. int i;
  80. for (i = 0; i < entry->count; i++)
  81. {
  82. switch (entry->opts[i].has_arg)
  83. {
  84. case 0: /* no arguments */
  85. case 1: /* has argument */
  86. case 2: /* optional argument */
  87. length += entry->opts[i].has_arg +1;
  88. break;
  89. default:
  90. break;
  91. }
  92. }
  93. }
  94. *opt_count = count +1;
  95. *optstring_len = length +1;
  96. } /* optarg_getsize */
  97. /* *************************************************************************
  98. * optarg_copy
  99. * ************************************************************************* */
  100. static void optarg_copy(struct option *opts, char *optstring)
  101. {
  102. struct optarg_entry *entry;
  103. list_for_each_entry(entry, &option_list, list)
  104. {
  105. memcpy(opts, entry->opts, sizeof(struct option) * entry->count);
  106. opts += entry->count;
  107. int i;
  108. for (i = 0; i < entry->count; i++)
  109. {
  110. switch (entry->opts[i].has_arg)
  111. {
  112. case 0: /* no arguments */
  113. *optstring++ = (char)entry->opts[i].val;
  114. break;
  115. case 1: /* has argument */
  116. *optstring++ = (char)entry->opts[i].val;
  117. *optstring++ = ':';
  118. break;
  119. case 2: /* optional argument */
  120. *optstring++ = (char)entry->opts[i].val;
  121. *optstring++ = ':';
  122. *optstring++ = ':';
  123. break;
  124. default:
  125. break;
  126. }
  127. }
  128. }
  129. memset(opts++, 0x00, sizeof(struct option));
  130. *optstring++ = '\0';
  131. } /* optarg_copy */
  132. /* *************************************************************************
  133. * optarg_parse
  134. * ************************************************************************* */
  135. int optarg_parse(int argc, char * const argv[])
  136. {
  137. struct option *longopts;
  138. char *optstring;
  139. int opt_count;
  140. int optstring_len;
  141. optarg_getsize(&opt_count, &optstring_len);
  142. longopts = malloc(sizeof(struct option) * opt_count);
  143. if (longopts == NULL)
  144. {
  145. return -1;
  146. }
  147. optstring = malloc(optstring_len);
  148. if (optstring == NULL)
  149. {
  150. free(longopts);
  151. return -1;
  152. }
  153. optarg_copy(longopts, optstring);
  154. int retval = 0;
  155. int val = 0;
  156. while (val != -1 && retval == 0)
  157. {
  158. opterr = 1; /* print error message to stderr */
  159. val = getopt_long(argc, argv, optstring, longopts, NULL);
  160. /* variable assigned (not supported) */
  161. if (val == 0x00)
  162. {
  163. continue;
  164. }
  165. struct optarg_entry *entry;
  166. list_for_each_entry(entry, &option_list, list)
  167. {
  168. int ret = entry->parser_cb(val, optarg, entry->privdata);
  169. /* option recognized, with error */
  170. if (ret < 0)
  171. {
  172. retval = ret;
  173. break;
  174. }
  175. /* option recognized, no error */
  176. else if (ret == 0)
  177. {
  178. break;
  179. }
  180. }
  181. /* parsing completed */
  182. if (val == -1)
  183. {
  184. break;
  185. }
  186. /* parsing error */
  187. if (val == '?')
  188. {
  189. retval = 1;
  190. break;
  191. }
  192. }
  193. free(optstring);
  194. free(longopts);
  195. return retval;
  196. } /* optarg_parse */