C command line parser API

All C type and function names described in this document are presented in their default naming style (lower_case_with_underscorces)

Generic public API

Messages

enum nsxml_message_type
{
  nsxml_message_type_debug = 0,
  nsxml_message_type_warning,
  nsxml_message_type_error,
  nsxml_message_type_fatal_error,

  nsxml_message_type_count
};

struct _nsxml_message
{
  int type;
  int code;
  char *message;
  struct _nsxml_message* next_message;
};
typedef struct _nsxml_message nsxml_message;

This struct stores messages raised by the parser during the command line argument parsing process. The code member refers to the message codes defines in the specification compliance page.

Value

enum nsxml_value_type
{
  nsxml_value_type_unset = -1,
  nsxml_value_type_null,
  nsxml_value_type_int,
  nsxml_value_type_float,
  nsxml_value_type_string
};

struct _nsxml_value
{
  int type;
  const char *string_value;
  int int_value;
  float float_value;
  struct _nsxml_value *next_value;
};
typedef struct _nsxml_value nsxml_value;

This struct stores options argument(s) and positional arguments values.

The string_value is always filled and points to one of the command line argument item (argv[]) except if type is set to nsxml_value_type_null.

Depending on option/positional argument specifications. int_value and float_value will be set by converting the value of string_value

Utilities

Theses elements are used internally by the C parser but can be used for various purpose. See the code for more informations

String copy

int nsxml_util_strncpy(char *output, size_t output_length, const char *input, size_t input_length);
int nsxml_util_strcpy(char *output, size_t output_length, const char *input);
int nsxml_util_asnprintf(char **output, size_t *output_length, const char *format, ...);

Text wrapping

enum nsxml_util_text_indent_mode
{
  nsxml_util_text_wrap_indent_none = 0,/**!< Do not indent */
  nsxml_util_text_wrap_indent_first,   /**!< Indent first line */
  nsxml_util_text_wrap_indent_others   /**!< Indent all line except the first */
};
enum nsxml_util_text_wrap_eol
{
  nsxml_util_text_wrap_eol_cr = 1,
  nsxml_util_text_wrap_eol_lf = 2,
  nsxml_util_text_wrap_eol_crlf = 3
};
void nsxml_util_text_wrap_options_init(struct nsxml_util_text_wrap_options* options, int tab, int line, int indent_mode, int eol);
void nsxml_util_text_wrap_fprintf(FILE *stream, const char *text, const struct nsxml_util_text_wrap_options* options, int level);

Auto-generated types and functions

Here, we assume your_app as the prefix used to generate the program parser.

Structs

Program interface informations

A C representation of the program interface description is generated based on the generic

typedef struct nsxml_program_info your_app_info;
your_app_info *your_app_info_new();
void your_app_info_init(your_app_info *info);

Initialize or create a new C representation of the program interface description.

void your_app_info_cleanup(your_app_info *info);
void your_app_info_free(your_app_info *info);

Release internal resources or completely free a your_app_info struct

Parser result

The parsing result is stored in a struct where most of members depends on subcommand and variable names described in the program interface XML definition file.

Here is a sample of what you can get.

struct _your_app_result
{
  /* Messages - Sorted by severity */
  nsxml_message *messages[nsxml_message_type_count];
  /* Messages - Sorted by apparition */
  nsxml_message *first_message;
 
  /* Subcommand */
  const char *subcommand_name;
  /* Values */
  int value_count;
  nsxml_value *values;
  /* Global options */
  struct
  {
    struct nsxml_switch_option_result displayHelp;
    struct nsxml_switch_option_result verboseProgram;
    struct nsxml_argument_option_result uiArg;
    struct nsxml_argument_option_result standardArg;
    /* ... */
  } options;
 
  /* Subcommands */
  struct
  {
    struct your_app_sub_subcommand_result
    {
      /* Subcommand options */
      struct nsxml_switch_option_result _switch;
    } sub;
    struct your_app_sub_subcommand_result
    {
      /* Subcommand options */
      struct nsxml_argument_option_result subFile;
      struct nsxml_argument_option_result subEnum;
    } foo;
  } subcommands;
};
typedef struct _your_app_result your_app_result;   

All nsxml_*_option_result structs have a is_set member. This member is set to 1 if the option is present and valid.

Functions

your_app_result *your_app_parse(your_app_info *info, int argc, const char **argv, int start_index);

Parse the command line arguments (given by argc and argv), starting with the start_indexth argument.

The function returns a new your_app_result* described above

void your_app_usage(FILE *stream, your_app_info *info, your_app_result *result, int format, const struct nsxml_util_text_wrap_options *wrap);

Print program usage. If result is given, the function will use the result state to display contextual help (depending if a subcommand was set or not)

int your_app_result_error_count(your_app_result *result);

Return the number of errors (+ the fatal error if any) raised during the command line parsing

nsxml_message *your_app_result_get_warnings(your_app_result *result);
nsxml_message *your_app_result_get_errors(your_app_result *result);
nsxml_message *your_app_result_get_fatal_error(your_app_result *result);

Shortcuts to access your_app_result->messages[nsxml_message_type_*]

void your_app_result_display_errors(FILE *stream, your_app_result *result, const char *line_prefix);

Display errors (and fatal error) on a given output, prefixing all lines with line_prefix

void your_app_result_free(your_app_result *result);

Free a your_app_result allocated by a call to your_app_parse()

Code snippets

Display program usage

your_app_info info;
your_app_info_init(&info);
your_app_usage(stdout, &info, NULL, nsxml_usage_format_short, NULL);
your_app_info_cleanup(&info);

Or ...

your_app_info *info = your_app_info_new();
your_app_usage(stdout, info, NULL, nsxml_usage_format_short, NULL);
your_app_info_free(info);

Calling the parser

your_app_info *info = your_app_info_new();
your_app_result *result = your_app_parse(info, argc, argv, 1);
if (your_app_result_error_count(result))
{
  your_app_result_display_errors(stderr, result, " - ");
  your_app_result_free(result);
  your_app_info_free(info);
  return EXIT_FAILURE;
}

/* Dealing with a switch */
if (result.options.displayHelp.is_set)
{
  your_app_usage(stdout, info, NULL, nsxml_usage_format_details, NULL);
  your_app_result_free(result);
  your_app_info_free(info);
  return EXIT_SUCCESS;
}

/* .. with a single-argument option */
if (result.options.arg.is_set)
{
  printf("Value of the single-argument option: %s\n", result.options.arg.argument.string_value);
}

/* ... with a multi-argument option */
if (result.options.multi.is_set)
{
  nsxml_value *v = result.options.multi.arguments;
  int i = 0;
  while (v)
  {
    printf("Value of argument %d of multi option: %s\n", i, v->string_value);
    v = v->next_value;
    ++i;
  }
}

your_app_result_free(result);
your_app_info_free(info);
return EXIT_SUCCESS;

About memory usage

Most of all elements of the your_app_result will be valid until a call to your_app_result_free() or

So releasing or modifying your_app_info or argc/argv[] is not recommended before a call to your_app_result_free() or

Tweaking

Identifier naming style

The general naming style of the C parser source code is lower_case_with_underscorces. Naming style of the public API and auto-generated structs, functions and enums can be changed to CamelCase or camelCase using build-c.sh tool

build-c.sh -x myapp.xml --struct CamelCase --function camelCase -o out

Variable names given in the program interface XML description file (<prg:databinding><prg:variable>my_option</prg:variable></prg:databinding>) and internal API structs and functions are not modified.

Code formatting

There is no parameters to change the default code formatting of the generated files. You may post process the generated files using a third party tool such as Artistic Style

See also


The program interface definition framework