项目作者: ITotalJustice

项目描述 :
Simple c99 argv parser with zero memory allocation
高级语言: C
项目地址: git://github.com/ITotalJustice/args.git
创建时间: 2021-05-10T15:15:55Z
项目社区:https://github.com/ITotalJustice/args

开源协议:

下载


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.

  1. enum ArgID {
  2. ArgID_HELP,
  3. ArgID_VERSION,
  4. ArgID_FILE,
  5. };
  6. const struct ArgsMeta metas[] = {
  7. {
  8. .key = "help",
  9. .id = ArgID_HELP,
  10. .type = ArgsValueType_NONE,
  11. .single = 'h'
  12. },
  13. {
  14. .key = "version",
  15. .id = ArgID_VERSION,
  16. .type = ArgsValueType_NONE,
  17. .single = 'v'
  18. },
  19. {
  20. .key = "file",
  21. .id = ArgID_FILE,
  22. .type = ArgsValueType_STR,
  23. .single = 'f'
  24. },
  25. };

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!

  1. #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
  2. struct Argsdata data[ARRAY_SIZE(metas)] = {0};
  3. // this is how many entires are filled by the parser!
  4. unsigned data_count = {0};

Finally, we can call the parse function!

  1. const enum ArgsResult result = args_parse(
  2. 1, argc, argv,
  3. metas, ARRAY_SIZE(metas),
  4. data, &data_count
  5. );

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.

  1. switch (result) {
  2. case ArgsResult_UNWANTED_VALUE:
  3. case ArgsResult_BAD_VALUE:
  4. case ArgsResult_MISSING_VALUE:
  5. case ArgsResult_ERROR:
  6. printf("Args Error: %d\n", result);
  7. return -1;
  8. case ArgsResult_OK:
  9. case ArgsResult_EXTRA_ARGS:
  10. break;
  11. }

The filled out data struct looks like this:

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

where value is a union of types:

  1. union ArgsValue {
  2. const char* s;
  3. long long i;
  4. double d;
  5. bool b;
  6. };

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

  1. for (unsigned i = 0; i < data_count; ++i) {
  2. switch (data[i].id) {
  3. case ArgID_HELP:
  4. printf("key: %.*s\n", data[i].key_len, data[i].key);
  5. break;
  6. case ArgID_VERSION:
  7. printf("key: %.*s\n", data[i].key_len, data[i].key);
  8. break;
  9. case ArgID_FILE:
  10. printf("key: %.*s value: %s\n", data[i].key_len, data[i].key, data[i].value.s);
  11. break;
  12. }
  13. }

The full example can be seen here