gethopt.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * gehopt; options processing with both single-character and whole-word
  3. * options both introduced with -
  4. */
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include "gethopt.h"
  8. void
  9. hoptset(ctx, argc, argv)
  10. struct h_context *ctx;
  11. int argc;
  12. char **argv;
  13. {
  14. memset(ctx, 0, sizeof *ctx);
  15. ctx->argc = argc;
  16. ctx->argv = argv;
  17. ctx->optind = 1;
  18. }
  19. char *
  20. hoptarg(ctx)
  21. struct h_context *ctx;
  22. {
  23. return ctx->optarg;
  24. }
  25. int
  26. hoptind(ctx)
  27. struct h_context *ctx;
  28. {
  29. return ctx->optind;
  30. }
  31. char
  32. hoptopt(ctx)
  33. struct h_context *ctx;
  34. {
  35. return ctx->optopt;
  36. }
  37. int
  38. hopterr(ctx,val)
  39. struct h_context *ctx;
  40. {
  41. int old = ctx->opterr;
  42. ctx->opterr = !!val;
  43. return old;
  44. }
  45. struct h_opt *
  46. gethopt(ctx, opts, nropts)
  47. struct h_context *ctx;
  48. struct h_opt *opts;
  49. int nropts;
  50. {
  51. int i;
  52. int dashes;
  53. if ( (ctx == 0) || ctx->optend || (ctx->optind >= ctx->argc) )
  54. return 0;
  55. ctx->optarg = 0;
  56. ctx->optopt = 0;
  57. if ( ctx->optchar == 0) {
  58. /* check for leading -
  59. */
  60. if ( ctx->argv[ctx->optind][0] != '-' ) {
  61. /* out of arguments */
  62. ctx->optend = 1;
  63. return 0;
  64. }
  65. if ( ctx->argv[ctx->optind][1] == 0
  66. || strcmp(ctx->argv[ctx->optind], "--") == 0 ) {
  67. /* option list finishes with - or -- token
  68. */
  69. ctx->optend = 1;
  70. ctx->optind++;
  71. return 0;
  72. }
  73. dashes = 1;
  74. if ( ctx->argv[ctx->optind][dashes] == '-' ) {
  75. /* support GNU-style long option double-dash prefix
  76. * (if gethopt is passed an unknown option with a double-dash
  77. * prefix, it won't match a word and then the second dash
  78. * will be scanned as if it was a regular old single-character
  79. * option.)
  80. */
  81. dashes = 2;
  82. }
  83. for ( i=0; i < nropts; i++ ) {
  84. if ( ! opts[i].optword )
  85. continue;
  86. if (strcmp(opts[i].optword, dashes+(ctx->argv[ctx->optind]) ) == 0 ) {
  87. if ( opts[i].opthasarg ) {
  88. if ( ctx->argc > ctx->optind ) {
  89. ctx->optarg = ctx->argv[ctx->optind+1];
  90. ctx->optind += 2;
  91. }
  92. else {
  93. /* word argument with required arg at end of
  94. *command line
  95. */
  96. if ( ctx->opterr )
  97. fprintf(stderr,
  98. "%s: option requires an argument -- %s\n",
  99. ctx->argv[0], opts[i].optword);
  100. ctx->optind ++;
  101. return HOPTERR;
  102. }
  103. }
  104. else {
  105. ctx->optind ++;
  106. }
  107. return &opts[i];
  108. }
  109. }
  110. ctx->optchar = 1;
  111. }
  112. ctx->optopt = ctx->argv[ctx->optind][ctx->optchar++];
  113. if ( !ctx->optopt ) {
  114. /* fell off the end of this argument */
  115. ctx->optind ++;
  116. ctx->optchar = 0;
  117. return gethopt(ctx, opts, nropts);
  118. }
  119. for ( i=0; i<nropts; i++ ) {
  120. if ( opts[i].optchar == ctx->optopt ) {
  121. /* found a single-char option!
  122. */
  123. if ( opts[i].opthasarg ) {
  124. if ( ctx->argv[ctx->optind][ctx->optchar] ) {
  125. /* argument immediately follows this options (-Oc)
  126. */
  127. ctx->optarg = &ctx->argv[ctx->optind][ctx->optchar];
  128. ctx->optind ++;
  129. ctx->optchar = 0;
  130. }
  131. else if ( ctx->optind < ctx->argc-1 ) {
  132. /* argument is next arg (-O c)
  133. */
  134. ctx->optarg = &ctx->argv[ctx->optind+1][0];
  135. ctx->optind += 2;
  136. ctx->optchar = 0;
  137. }
  138. else {
  139. /* end of arg string (-O); set optarg to null, return
  140. * (should it opterr on me?)
  141. */
  142. ctx->optarg = 0;
  143. ctx->optind ++;
  144. ctx->optchar = 0;
  145. if ( ctx->opterr )
  146. fprintf(stderr,
  147. "%s: option requires an argument -- %c\n",
  148. ctx->argv[0], opts[i].optchar);
  149. return HOPTERR;
  150. }
  151. }
  152. else {
  153. if ( !ctx->argv[ctx->optind][ctx->optchar] ) {
  154. ctx->optind ++;
  155. ctx->optchar = 0;
  156. }
  157. }
  158. return &opts[i];
  159. }
  160. }
  161. if ( ctx->opterr )
  162. fprintf(stderr, "%s: illegal option -- %c\n", ctx->argv[0], ctx->optopt);
  163. return HOPTERR;
  164. }
  165. void
  166. hoptusage(char *pgm, struct h_opt opts[], int nropts, char *arguments)
  167. {
  168. int i;
  169. int optcount;
  170. fprintf(stderr, "usage: %s", pgm);
  171. /* print out the options that don't have flags first */
  172. for ( optcount=i=0; i < nropts; i++ ) {
  173. if ( opts[i].optchar && !opts[i].opthasarg) {
  174. if (optcount == 0 )
  175. fputs(" [-", stderr);
  176. fputc(opts[i].optchar, stderr);
  177. optcount++;
  178. }
  179. }
  180. if ( optcount )
  181. fputc(']', stderr);
  182. /* print out the options WITH flags */
  183. for ( i = 0; i < nropts; i++ )
  184. if ( opts[i].optchar && opts[i].opthasarg)
  185. fprintf(stderr, " [-%c %s]", opts[i].optchar, opts[i].opthasarg);
  186. /* print out the long options */
  187. for ( i = 0; i < nropts; i++ )
  188. if ( opts[i].optword ) {
  189. fprintf(stderr, " [-%s", opts[i].optword);
  190. if ( opts[i].opthasarg )
  191. fprintf(stderr, " %s", opts[i].opthasarg);
  192. fputc(']', stderr);
  193. }
  194. /* print out the arguments string, if any */
  195. if ( arguments )
  196. fprintf(stderr, " %s", arguments);
  197. /* and we're done */
  198. fputc('\n', stderr);
  199. }
  200. #if DEBUG
  201. struct h_opt opts[] = {
  202. { 0, "css", 0, 1, "css file" },
  203. { 1, "header", 0, 1, "header file" },
  204. { 2, 0, 'a', 0, "option a (no arg)" },
  205. { 3, 0, 'b', 1, "option B (with arg)" },
  206. { 4, "help", '?', 0, "help message" },
  207. } ;
  208. #define NROPT (sizeof opts/sizeof opts[0])
  209. int
  210. main(argc, argv)
  211. char **argv;
  212. {
  213. struct h_opt *ret;
  214. struct h_context ctx;
  215. int i;
  216. hoptset(&ctx, argc, argv);
  217. hopterr(&ctx, 1);
  218. while (( ret = gethopt(&ctx, opts, NROPT) )) {
  219. if ( ret != HOPTERR ) {
  220. if ( ret->optword )
  221. printf("%s", ret->optword);
  222. else
  223. printf("%c", ret->optchar);
  224. if ( ret->opthasarg ) {
  225. if ( hoptarg(&ctx) )
  226. printf(" with argument \"%s\"", hoptarg(&ctx));
  227. else
  228. printf(" with no argument?");
  229. }
  230. printf(" (%s)\n", ret->optdesc);
  231. }
  232. }
  233. argc -= hoptind(&ctx);
  234. argv += hoptind(&ctx);
  235. for ( i=0; i < argc; i++ )
  236. printf("%d: %s\n", i, argv[i]);
  237. return 0;
  238. }
  239. #endif /*DEBUG*/