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.

parseopt.c 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * 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 Free Software
  16. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. FILE_LICENCE ( GPL2_OR_LATER );
  19. #include <stddef.h>
  20. #include <stdint.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <errno.h>
  25. #include <getopt.h>
  26. #include <ipxe/netdevice.h>
  27. #include <ipxe/image.h>
  28. #include <ipxe/parseopt.h>
  29. /** @file
  30. *
  31. * Command line option parsing
  32. *
  33. */
  34. /** Return status code for "--help" option */
  35. #define ECANCELED_NO_OP __einfo_error ( EINFO_ECANCELED_NO_OP )
  36. #define EINFO_ECANCELED_NO_OP \
  37. __einfo_uniqify ( EINFO_ECANCELED, 0x01, "Nothing to do" )
  38. /**
  39. * Parse string value
  40. *
  41. * @v text Text
  42. * @ret value String value
  43. * @ret rc Return status code
  44. */
  45. int parse_string ( const char *text, const char **value ) {
  46. /* Sanity check */
  47. assert ( text != NULL );
  48. /* Parse string */
  49. *value = text;
  50. return 0;
  51. }
  52. /**
  53. * Parse integer value
  54. *
  55. * @v text Text
  56. * @ret value Integer value
  57. * @ret rc Return status code
  58. */
  59. int parse_integer ( const char *text, unsigned int *value ) {
  60. char *endp;
  61. /* Sanity check */
  62. assert ( text != NULL );
  63. /* Parse integer */
  64. *value = strtoul ( text, &endp, 0 );
  65. if ( *endp ) {
  66. printf ( "\"%s\": invalid integer value\n", text );
  67. return -EINVAL;
  68. }
  69. return 0;
  70. }
  71. /**
  72. * Parse network device name
  73. *
  74. * @v text Text
  75. * @ret netdev Network device
  76. * @ret rc Return status code
  77. */
  78. int parse_netdev ( const char *text, struct net_device **netdev ) {
  79. /* Sanity check */
  80. assert ( text != NULL );
  81. /* Find network device */
  82. *netdev = find_netdev ( text );
  83. if ( ! *netdev ) {
  84. printf ( "\"%s\": no such network device\n", text );
  85. return -ENODEV;
  86. }
  87. return 0;
  88. }
  89. /**
  90. * Parse image name
  91. *
  92. * @v text Text
  93. * @ret image Image
  94. * @ret rc Return status code
  95. */
  96. int parse_image ( const char *text, struct image **image ) {
  97. /* Sanity check */
  98. assert ( text != NULL );
  99. /* Find network device */
  100. *image = find_image ( text );
  101. if ( ! *image ) {
  102. printf ( "\"%s\": no such image\n", text );
  103. return -ENOENT;
  104. }
  105. return 0;
  106. }
  107. /**
  108. * Parse flag
  109. *
  110. * @v text Text (ignored)
  111. * @ret flag Flag to set
  112. * @ret rc Return status code
  113. */
  114. int parse_flag ( const char *text __unused, int *flag ) {
  115. /* Set flag */
  116. *flag = 1;
  117. return 0;
  118. }
  119. /**
  120. * Print command usage message
  121. *
  122. * @v cmd Command descriptor
  123. * @v argv Argument list
  124. */
  125. void print_usage ( struct command_descriptor *cmd, char **argv ) {
  126. printf ( "Usage:\n\n %s %s\n\nSee http://ipxe.org/cmd/%s for further "
  127. "information\n", argv[0], cmd->usage, argv[0] );
  128. }
  129. /**
  130. * Parse command-line options
  131. *
  132. * @v argc Argument count
  133. * @v argv Argument list
  134. * @v cmd Command descriptor
  135. * @v opts Options
  136. * @ret rc Return status code
  137. */
  138. int parse_options ( int argc, char **argv, struct command_descriptor *cmd,
  139. void *opts ) {
  140. struct option longopts[ cmd->num_options + 1 /* help */ + 1 /* end */ ];
  141. char shortopts[ cmd->num_options * 3 /* possible "::" */ + 1 /* "h" */
  142. + 1 /* NUL */ ];
  143. unsigned int shortopt_idx = 0;
  144. int ( * parse ) ( const char *text, void *value );
  145. void *value;
  146. unsigned int i;
  147. unsigned int j;
  148. unsigned int num_args;
  149. int c;
  150. int rc;
  151. /* Construct long and short option lists for getopt_long() */
  152. memset ( longopts, 0, sizeof ( longopts ) );
  153. for ( i = 0 ; i < cmd->num_options ; i++ ) {
  154. longopts[i].name = cmd->options[i].longopt;
  155. longopts[i].has_arg = cmd->options[i].has_arg;
  156. longopts[i].val = cmd->options[i].shortopt;
  157. shortopts[shortopt_idx++] = cmd->options[i].shortopt;
  158. assert ( cmd->options[i].has_arg <= optional_argument );
  159. for ( j = cmd->options[i].has_arg ; j > 0 ; j-- )
  160. shortopts[shortopt_idx++] = ':';
  161. }
  162. longopts[i].name = "help";
  163. longopts[i].val = 'h';
  164. shortopts[shortopt_idx++] = 'h';
  165. shortopts[shortopt_idx++] = '\0';
  166. assert ( shortopt_idx <= sizeof ( shortopts ) );
  167. DBGC ( cmd, "Command \"%s\" has options \"%s\", %d-%d args, len %d\n",
  168. argv[0], shortopts, cmd->min_args, cmd->max_args, cmd->len );
  169. /* Clear options */
  170. memset ( opts, 0, cmd->len );
  171. /* Parse options */
  172. while ( ( c = getopt_long ( argc, argv, shortopts, longopts,
  173. NULL ) ) >= 0 ) {
  174. switch ( c ) {
  175. case 'h' :
  176. /* Print help */
  177. print_usage ( cmd, argv );
  178. return -ECANCELED_NO_OP;
  179. case '?' :
  180. case ':' :
  181. /* Print usage message */
  182. print_usage ( cmd, argv );
  183. return -EINVAL;
  184. default:
  185. /* Search for an option to parse */
  186. for ( i = 0 ; i < cmd->num_options ; i++ ) {
  187. if ( c != cmd->options[i].shortopt )
  188. continue;
  189. parse = cmd->options[i].parse;
  190. value = ( opts + cmd->options[i].offset );
  191. if ( ( rc = parse ( optarg, value ) ) != 0 )
  192. return rc;
  193. break;
  194. }
  195. assert ( i < cmd->num_options );
  196. }
  197. }
  198. /* Check remaining arguments */
  199. num_args = ( argc - optind );
  200. if ( ( num_args < cmd->min_args ) || ( num_args > cmd->max_args ) ) {
  201. print_usage ( cmd, argv );
  202. return -ERANGE;
  203. }
  204. return 0;
  205. }