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.

194 lines
5.5KB

  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. struct list_head list;
  29. const struct option *opts;
  30. int count;
  31. int (* parser_cb)(int val, const char *arg, void *privdata);
  32. void *privdata;
  33. };
  34. static LIST_HEAD(option_list);
  35. int optarg_register(const struct option *opts, int count,
  36. int (* parser_cb)(int val, const char *arg, void *privdata),
  37. void *privdata)
  38. {
  39. struct optarg_entry *entry;
  40. entry = malloc(sizeof(struct optarg_entry));
  41. if (entry == NULL)
  42. return -1;
  43. entry->opts = opts; /* TODO: copy? */
  44. entry->count = count;
  45. entry->parser_cb = parser_cb;
  46. entry->privdata = privdata;
  47. list_add_tail(&entry->list, &option_list);
  48. return 0;
  49. }
  50. void optarg_free(void)
  51. {
  52. struct optarg_entry *entry, *entry_tmp;
  53. list_for_each_entry_safe(entry, entry_tmp, &option_list, list) {
  54. list_del(&entry->list);
  55. free(entry);
  56. }
  57. }
  58. static void optarg_getsize(int *opt_count, int *optstring_len)
  59. {
  60. int count = 0;
  61. int length = 0;
  62. struct optarg_entry *entry;
  63. list_for_each_entry(entry, &option_list, list) {
  64. count += entry->count;
  65. int i;
  66. for (i = 0; i < entry->count; i++) {
  67. switch (entry->opts[i].has_arg) {
  68. case 0: /* no arguments */
  69. case 1: /* has argument */
  70. case 2: /* optional argument */
  71. length += entry->opts[i].has_arg +1;
  72. break;
  73. default:
  74. break;
  75. }
  76. }
  77. }
  78. *opt_count = count +1;
  79. *optstring_len = length +1;
  80. }
  81. static void optarg_copy(struct option *opts, char *optstring)
  82. {
  83. struct optarg_entry *entry;
  84. list_for_each_entry(entry, &option_list, list) {
  85. memcpy(opts, entry->opts, sizeof(struct option) * entry->count);
  86. opts += entry->count;
  87. int i;
  88. for (i = 0; i < entry->count; i++) {
  89. switch (entry->opts[i].has_arg) {
  90. case 0: /* no arguments */
  91. *optstring++ = (char)entry->opts[i].val;
  92. break;
  93. case 1: /* has argument */
  94. *optstring++ = (char)entry->opts[i].val;
  95. *optstring++ = ':';
  96. break;
  97. case 2: /* optional argument */
  98. *optstring++ = (char)entry->opts[i].val;
  99. *optstring++ = ':';
  100. *optstring++ = ':';
  101. break;
  102. default:
  103. break;
  104. }
  105. }
  106. }
  107. memset(opts++, 0x00, sizeof(struct option));
  108. *optstring++ = '\0';
  109. }
  110. int optarg_parse(int argc, char * const argv[])
  111. {
  112. struct option *longopts;
  113. char *optstring;
  114. int opt_count;
  115. int optstring_len;
  116. optarg_getsize(&opt_count, &optstring_len);
  117. longopts = malloc(sizeof(struct option) * opt_count);
  118. if (longopts == NULL)
  119. return -1;
  120. optstring = malloc(optstring_len);
  121. if (optstring == NULL) {
  122. free(longopts);
  123. return -1;
  124. }
  125. optarg_copy(longopts, optstring);
  126. int retval = 0;
  127. int val = 0;
  128. while (val != -1 && retval == 0) {
  129. opterr = 1; /* print error message to stderr */
  130. val = getopt_long(argc, argv, optstring, longopts, NULL);
  131. if (val == 0x00) /* variable assigned (not supported) */
  132. continue;
  133. struct optarg_entry *entry;
  134. list_for_each_entry(entry, &option_list, list) {
  135. int ret = entry->parser_cb(val, optarg, entry->privdata);
  136. /* option recognized, with error */
  137. if (ret < 0) {
  138. retval = ret;
  139. break;
  140. /* option recognized, no error */
  141. } else if (ret == 0) {
  142. break;
  143. }
  144. }
  145. if (val == -1) /* parsing completed */
  146. break;
  147. if (val == '?') { /* parsing error */
  148. retval = 1;
  149. break;
  150. }
  151. }
  152. free(optstring);
  153. free(longopts);
  154. return retval;
  155. }