usage.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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. #include <ccan/opt/opt.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <stdint.h>
  14. #include "private.h"
  15. /* We only use this for pointer comparisons. */
  16. const char opt_hidden[1];
  17. static unsigned write_short_options(char *str)
  18. {
  19. unsigned int i, num = 0;
  20. const char *p;
  21. for (p = first_sopt(&i); p; p = next_sopt(p, &i)) {
  22. if (opt_table[i].desc != opt_hidden)
  23. str[num++] = *p;
  24. }
  25. return num;
  26. }
  27. #define OPT_SPACE_PAD " "
  28. /* FIXME: Get all purdy. */
  29. char *opt_usage(const char *argv0, const char *extra)
  30. {
  31. unsigned int i, num, len;
  32. char *ret, *p;
  33. if (!extra) {
  34. extra = "";
  35. for (i = 0; i < opt_count; i++) {
  36. if (opt_table[i].cb == (void *)opt_usage_and_exit
  37. && opt_table[i].u.carg) {
  38. extra = opt_table[i].u.carg;
  39. break;
  40. }
  41. }
  42. }
  43. /* An overestimate of our length. */
  44. len = strlen("Usage: %s ") + strlen(argv0)
  45. + strlen("[-%.*s]") + opt_num_short + 1
  46. + strlen(" ") + strlen(extra)
  47. + strlen("\n");
  48. for (i = 0; i < opt_count; i++) {
  49. if (opt_table[i].type == OPT_SUBTABLE) {
  50. len += strlen("\n") + strlen(opt_table[i].desc)
  51. + strlen(":\n");
  52. } else if (opt_table[i].desc != opt_hidden) {
  53. len += strlen(opt_table[i].names) + strlen(" <arg>");
  54. len += strlen(OPT_SPACE_PAD)
  55. + strlen(opt_table[i].desc) + 1;
  56. if (opt_table[i].show) {
  57. len += strlen("(default: %s)")
  58. + OPT_SHOW_LEN + sizeof("...");
  59. }
  60. len += strlen("\n");
  61. }
  62. }
  63. p = ret = malloc(len);
  64. if (!ret)
  65. return NULL;
  66. p += sprintf(p, "Usage: %s", argv0);
  67. p += sprintf(p, " [-");
  68. num = write_short_options(p);
  69. if (num) {
  70. p += num;
  71. p += sprintf(p, "]");
  72. } else {
  73. /* Remove start of single-entry options */
  74. p -= 3;
  75. }
  76. if (extra)
  77. p += sprintf(p, " %s", extra);
  78. p += sprintf(p, "\n");
  79. for (i = 0; i < opt_count; i++) {
  80. if (opt_table[i].desc == opt_hidden)
  81. continue;
  82. if (opt_table[i].type == OPT_SUBTABLE) {
  83. p += sprintf(p, "%s:\n", opt_table[i].desc);
  84. continue;
  85. }
  86. len = sprintf(p, "%s", opt_table[i].names);
  87. if (opt_table[i].type == OPT_HASARG
  88. && !strchr(opt_table[i].names, ' ')
  89. && !strchr(opt_table[i].names, '='))
  90. len += sprintf(p + len, " <arg>");
  91. len += sprintf(p + len, "%.*s",
  92. len < strlen(OPT_SPACE_PAD)
  93. ? (unsigned)strlen(OPT_SPACE_PAD) - len : 1,
  94. OPT_SPACE_PAD);
  95. len += sprintf(p + len, "%s", opt_table[i].desc);
  96. if (opt_table[i].show) {
  97. char buf[OPT_SHOW_LEN + sizeof("...")];
  98. strcpy(buf + OPT_SHOW_LEN, "...");
  99. opt_table[i].show(buf, opt_table[i].u.arg);
  100. len += sprintf(p + len, " (default: %s)", buf);
  101. }
  102. p += len;
  103. p += sprintf(p, "\n");
  104. }
  105. *p = '\0';
  106. return ret;
  107. }