parse.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /*
  2. * Copyright 2011 Rusty Russell
  3. *
  4. * This program is free software; you can redistribute it and/or modify it under
  5. * the terms of the GNU General Public License as published by the Free Software
  6. * Foundation; either version 2 of the License, or (at your option) any later
  7. * version. See LICENSE for more details.
  8. */
  9. /* Actual code to parse commandline. */
  10. #include <ccan/opt/opt.h>
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include <assert.h>
  14. #include "private.h"
  15. /* glibc does this as:
  16. /tmp/opt-example: invalid option -- 'x'
  17. /tmp/opt-example: unrecognized option '--long'
  18. /tmp/opt-example: option '--someflag' doesn't allow an argument
  19. /tmp/opt-example: option '--s' is ambiguous
  20. /tmp/opt-example: option requires an argument -- 's'
  21. */
  22. static int parse_err(void (*errlog)(const char *fmt, ...),
  23. const char *argv0, const char *arg, unsigned len,
  24. const char *problem)
  25. {
  26. errlog("%s: %.*s: %s", argv0, len, arg, problem);
  27. return -1;
  28. }
  29. static void consume_option(int *argc, char *argv[], unsigned optnum)
  30. {
  31. memmove(&argv[optnum], &argv[optnum+1],
  32. sizeof(argv[optnum]) * (*argc-optnum));
  33. (*argc)--;
  34. }
  35. /* Returns 1 if argument consumed, 0 if all done, -1 on error. */
  36. int parse_one(int *argc, char *argv[], unsigned *offset,
  37. void (*errlog)(const char *fmt, ...))
  38. {
  39. unsigned i, arg, len;
  40. const char *o, *optarg = NULL;
  41. char *problem;
  42. if (getenv("POSIXLY_CORRECT")) {
  43. /* Don't find options after non-options. */
  44. arg = 1;
  45. } else {
  46. for (arg = 1; argv[arg]; arg++) {
  47. if (argv[arg][0] == '-')
  48. break;
  49. }
  50. }
  51. if (!argv[arg] || argv[arg][0] != '-')
  52. return 0;
  53. /* Special arg terminator option. */
  54. if (strcmp(argv[arg], "--") == 0) {
  55. consume_option(argc, argv, arg);
  56. return 0;
  57. }
  58. /* Long options start with -- */
  59. if (argv[arg][1] == '-') {
  60. assert(*offset == 0);
  61. for (o = first_lopt(&i, &len); o; o = next_lopt(o, &i, &len)) {
  62. if (strncmp(argv[arg] + 2, o, len) != 0)
  63. continue;
  64. if (argv[arg][2 + len] == '=')
  65. optarg = argv[arg] + 2 + len + 1;
  66. else if (argv[arg][2 + len] != '\0')
  67. continue;
  68. break;
  69. }
  70. if (!o)
  71. return parse_err(errlog, argv[0],
  72. argv[arg], strlen(argv[arg]),
  73. "unrecognized option");
  74. /* For error messages, we include the leading '--' */
  75. o -= 2;
  76. len += 2;
  77. } else {
  78. /* offset allows us to handle -abc */
  79. for (o = first_sopt(&i); o; o = next_sopt(o, &i)) {
  80. if (argv[arg][*offset + 1] != *o)
  81. continue;
  82. (*offset)++;
  83. break;
  84. }
  85. if (!o)
  86. return parse_err(errlog, argv[0],
  87. argv[arg], strlen(argv[arg]),
  88. "unrecognized option");
  89. /* For error messages, we include the leading '-' */
  90. o--;
  91. len = 2;
  92. }
  93. if (opt_table[i].type == OPT_NOARG) {
  94. if (optarg)
  95. return parse_err(errlog, argv[0], o, len,
  96. "doesn't allow an argument");
  97. problem = opt_table[i].cb(opt_table[i].u.arg);
  98. } else {
  99. if (!optarg) {
  100. /* Swallow any short options as optarg, eg -afile */
  101. if (*offset && argv[arg][*offset + 1]) {
  102. optarg = argv[arg] + *offset + 1;
  103. *offset = 0;
  104. } else
  105. optarg = argv[arg+1];
  106. }
  107. if (!optarg)
  108. return parse_err(errlog, argv[0], o, len,
  109. "requires an argument");
  110. problem = opt_table[i].cb_arg(optarg, opt_table[i].u.arg);
  111. }
  112. if (problem) {
  113. parse_err(errlog, argv[0], o, len, problem);
  114. free(problem);
  115. return -1;
  116. }
  117. /* If no more letters in that short opt, reset offset. */
  118. if (*offset && !argv[arg][*offset + 1])
  119. *offset = 0;
  120. /* All finished with that option? */
  121. if (*offset == 0) {
  122. consume_option(argc, argv, arg);
  123. if (optarg && optarg == argv[arg])
  124. consume_option(argc, argv, arg);
  125. }
  126. return 1;
  127. }