Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Simple c99 argv parser with zero memory allocation

Notifications You must be signed in to change notification settings

ITotalJustice/args

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

args

Simple c99 argv parser with zero memory allocation

How to use

args is very simple, it allocates no memory and is only a single function call!

First, create the meta info for the args you want.

enum ArgID {
  ArgID_HELP,
  ArgID_VERSION,
  ArgID_FILE,
};

const struct ArgsMeta metas[] = {
  {
    .key = "help",
    .id = ArgID_HELP,
    .type = ArgsValueType_NONE,
    .single = 'h'
  },
  {
    .key = "version",
    .id = ArgID_VERSION,
    .type = ArgsValueType_NONE,
    .single = 'v'
  },
  {
    .key = "file",
    .id = ArgID_FILE,
    .type = ArgsValueType_STR,
    .single = 'f'
  },
};

Next, we need to setup our output data.

NOTE: The number of entries in this array MUST be the same size as the ArgsMeta array we created above!

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))

struct Argsdata data[ARRAY_SIZE(metas)] = {0};
// this is how many entires are filled by the parser!
unsigned data_count = {0};

Finally, we can call the parse function!

const enum ArgsResult result = args_parse(
  1, argc, argv,
  metas, ARRAY_SIZE(metas),
  data, &data_count
);

NOTE: You might notice that we pass a 1 as the first param. That's just the index that we want to start from.

Usually, argv[0] is the path of the program, so we can skip then, hence passing 1, so we start from argv[1]

The return value of the parser is an enum. in general, 0 == OK, any negative number is an error, any positive number is OK but with with a warning.

switch (result) {
  case ArgsResult_UNWANTED_VALUE:
  case ArgsResult_BAD_VALUE:
  case ArgsResult_MISSING_VALUE:
  case ArgsResult_ERROR:
    printf("Args Error: %d\n", result);
    return -1;

  case ArgsResult_OK:
  case ArgsResult_EXTRA_ARGS:
    break;
}

The filled out data struct looks like this:

struct Argsdata {
  const char* key; // key, not always NULL terminated
  unsigned key_len; // actual length of the key
  union ArgsValue value; // union of value types
  int id; // your ID that you set for the key
};

where value is a union of types:

union ArgsValue {
  const char* s;
  long long i;
  double d;
  bool b;
};

You can loop now through the struct Argsdata array we created earlier, here's an example

for (unsigned i = 0; i < data_count; ++i) {
  switch (data[i].id) {
    case ArgID_HELP:
      printf("key: %.*s\n", data[i].key_len, data[i].key);
      break;

    case ArgID_VERSION:
      printf("key: %.*s\n", data[i].key_len, data[i].key);
      break;

    case ArgID_FILE:
      printf("key: %.*s value: %s\n", data[i].key_len, data[i].key, data[i].value.s);
      break;
  }
}

The full example can be seen here

About

Simple c99 argv parser with zero memory allocation

Topics

Resources

Stars

Watchers

Forks