aboutsummaryrefslogtreecommitdiff
path: root/sokol_args.h
diff options
context:
space:
mode:
authorAndre Weissflog <floooh@gmail.com>2023-09-18 16:22:56 +0200
committerAndre Weissflog <floooh@gmail.com>2023-09-18 16:22:56 +0200
commit737c263ff8fc522b54862a55dabfd3e2d6a27fec (patch)
tree06a0bdfd10904f9dc636152d24484afbf2165ca6 /sokol_args.h
parent751fc4c14a0cb80130ad8014f965ac62c7e89d34 (diff)
sokol_args.h: support key-only args (see documentation for details) fixes #876
Diffstat (limited to 'sokol_args.h')
-rw-r--r--sokol_args.h104
1 files changed, 64 insertions, 40 deletions
diff --git a/sokol_args.h b/sokol_args.h
index 4d37907c..d33ba3a0 100644
--- a/sokol_args.h
+++ b/sokol_args.h
@@ -35,11 +35,22 @@
When running as WebAssembly app, arguments are taken from the page URL:
- https://floooh.github.io/tiny8bit/kc85.html?type=kc85_3&mod=m022&snapshot=kc85/jungle.kcc
+ https://floooh.github.io/tiny8bit/kc85.html?type=kc85_3&mod=m022&snapshot=kc85/jungle.kcc
The same arguments provided to a command line app:
- kc85 type=kc85_3 mod=m022 snapshot=kc85/jungle.kcc
+ kc85 type=kc85_3 mod=m022 snapshot=kc85/jungle.kcc
+
+ You can also use standalone keys without value:
+
+ https://floooh.github.io/tiny8bit/kc85.html?bla&blub
+
+ On the command line:
+
+ kc85 bla blub
+
+ Such value-less keys are reported as the value being an empty string, but they
+ can be tested with `sapp_exists("bla")` or `sapp_boolean("blub")`.
ARGUMENT FORMATTING
===================
@@ -57,6 +68,12 @@
key=value
+ or
+
+ key
+
+ When a key has no value, the value will be assigned an empty string.
+
Key/value pairs are separated by 'whitespace', valid whitespace
characters are space and tab.
@@ -71,9 +88,6 @@
The 'key' string must be a simple string without escape sequences or whitespace.
- Currently 'single keys' without values are not allowed, but may be
- in the future.
-
The 'value' string can be quoted, and quoted value strings can contain
whitespace:
@@ -123,7 +137,7 @@
...
}
- // check if a key's value is "true", "yes" or "on"
+ // check if a key's value is "true", "yes" or "on" or if this is a standalone key
if (sargs_boolean("joystick_enabled")) {
...
}
@@ -183,23 +197,23 @@
Return true between sargs_setup() and sargs_shutdown()
bool sargs_exists(const char* key)
- Test if a key arg exists.
+ Test if an argument exists by its key name.
const char* sargs_value(const char* key)
- Return value associated with key. Returns an empty
- string ("") if the key doesn't exist.
+ Return value associated with key. Returns an empty string ("") if the
+ key doesn't exist, or if the key doesn't have a value.
const char* sargs_value_def(const char* key, const char* default)
- Return value associated with key, or the provided default
- value if the value doesn't exist.
+ Return value associated with key, or the provided default value if the
+ key doesn't exist, or this is a value-less key.
bool sargs_equals(const char* key, const char* val);
Return true if the value associated with key matches
the 'val' argument.
bool sargs_boolean(const char* key)
- Return true if the value string of 'key' is one
- of 'true', 'yes', 'on'.
+ Return true if the value string of 'key' is one of 'true', 'yes', 'on',
+ or this is a key without value.
int sargs_find(const char* key)
Find argument by key name and return its index, or -1 if not found.
@@ -213,7 +227,7 @@
const char* sargs_value_at(int index)
Return the value of argument at index. Returns empty string
- if index is outside range.
+ if the key at index has no value, or the index is out-of-range.
MEMORY ALLOCATION OVERRIDE
@@ -327,13 +341,13 @@ SOKOL_ARGS_API_DECL void sargs_shutdown(void);
SOKOL_ARGS_API_DECL bool sargs_isvalid(void);
/* test if an argument exists by key name */
SOKOL_ARGS_API_DECL bool sargs_exists(const char* key);
-/* get value by key name, return empty string if key doesn't exist */
+/* get value by key name, return empty string if key doesn't exist or an existing key has no value */
SOKOL_ARGS_API_DECL const char* sargs_value(const char* key);
-/* get value by key name, return provided default if key doesn't exist */
+/* get value by key name, return provided default if key doesn't exist or has no value */
SOKOL_ARGS_API_DECL const char* sargs_value_def(const char* key, const char* def);
/* return true if val arg matches the value associated with key */
SOKOL_ARGS_API_DECL bool sargs_equals(const char* key, const char* val);
-/* return true if key's value is "true", "yes" or "on" */
+/* return true if key's value is "true", "yes", "on" or an existing key has no value */
SOKOL_ARGS_API_DECL bool sargs_boolean(const char* key);
/* get index of arg by key name, return -1 if not exists */
SOKOL_ARGS_API_DECL int sargs_find(const char* key);
@@ -486,8 +500,8 @@ _SOKOL_PRIVATE bool _sargs_val_expected(void) {
return 0 != (_sargs.parse_state & _SARGS_EXPECT_VAL);
}
-_SOKOL_PRIVATE void _sargs_expect_sep(void) {
- _sargs.parse_state = _SARGS_EXPECT_SEP;
+_SOKOL_PRIVATE void _sargs_expect_sep_or_key(void) {
+ _sargs.parse_state = _SARGS_EXPECT_SEP | _SARGS_EXPECT_KEY;
}
_SOKOL_PRIVATE bool _sargs_any_expected(void) {
@@ -524,14 +538,17 @@ _SOKOL_PRIVATE bool _sargs_is_whitespace(char c) {
}
_SOKOL_PRIVATE void _sargs_start_key(void) {
- SOKOL_ASSERT(_sargs.num_args < _sargs.max_args);
+ SOKOL_ASSERT((_sargs.num_args >= 0) && (_sargs.num_args < _sargs.max_args));
_sargs.parse_state = _SARGS_PARSING_KEY;
_sargs.args[_sargs.num_args].key = _sargs.buf_pos;
}
_SOKOL_PRIVATE void _sargs_end_key(void) {
- SOKOL_ASSERT(_sargs.num_args < _sargs.max_args);
+ SOKOL_ASSERT((_sargs.num_args >= 0) && (_sargs.num_args < _sargs.max_args));
_sargs_putc(0);
+ // declare val as empty string in case this is a key-only arg
+ _sargs.args[_sargs.num_args].val = _sargs.buf_pos - 1;
+ _sargs.num_args++;
_sargs.parse_state = 0;
}
@@ -540,15 +557,13 @@ _SOKOL_PRIVATE bool _sargs_parsing_key(void) {
}
_SOKOL_PRIVATE void _sargs_start_val(void) {
- SOKOL_ASSERT(_sargs.num_args < _sargs.max_args);
+ SOKOL_ASSERT((_sargs.num_args > 0) && (_sargs.num_args <= _sargs.max_args));
_sargs.parse_state = _SARGS_PARSING_VAL;
- _sargs.args[_sargs.num_args].val = _sargs.buf_pos;
+ _sargs.args[_sargs.num_args - 1].val = _sargs.buf_pos;
}
_SOKOL_PRIVATE void _sargs_end_val(void) {
- SOKOL_ASSERT(_sargs.num_args < _sargs.max_args);
_sargs_putc(0);
- _sargs.num_args++;
_sargs.parse_state = 0;
}
@@ -596,7 +611,12 @@ _SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) {
if (_sargs_any_expected()) {
if (!_sargs_is_whitespace(c)) {
/* start of key, value or separator */
- if (_sargs_key_expected()) {
+ if (_sargs_is_separator(c)) {
+ /* skip separator and expect value */
+ _sargs_expect_val();
+ continue;
+ }
+ else if (_sargs_key_expected()) {
/* start of new key */
_sargs_start_key();
}
@@ -608,13 +628,6 @@ _SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) {
}
_sargs_start_val();
}
- else {
- /* separator */
- if (_sargs_is_separator(c)) {
- _sargs_expect_val();
- continue;
- }
- }
}
else {
/* skip white space */
@@ -629,7 +642,7 @@ _SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) {
_sargs_expect_val();
}
else {
- _sargs_expect_sep();
+ _sargs_expect_sep_or_key();
}
continue;
}
@@ -657,7 +670,7 @@ _SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) {
}
if (_sargs_parsing_key()) {
_sargs_end_key();
- _sargs_expect_sep();
+ _sargs_expect_sep_or_key();
}
else if (_sargs_parsing_val() && !_sargs_in_quotes()) {
_sargs_end_val();
@@ -823,7 +836,13 @@ SOKOL_API_IMPL const char* sargs_value_def(const char* key, const char* def) {
SOKOL_ASSERT(_sargs.valid && key && def);
int arg_index = sargs_find(key);
if (-1 != arg_index) {
- return sargs_value_at(arg_index);
+ const char* res = sargs_value_at(arg_index);
+ SOKOL_ASSERT(res);
+ if (res[0] == 0) {
+ return def;
+ } else {
+ return res;
+ }
}
else {
return def;
@@ -836,10 +855,15 @@ SOKOL_API_IMPL bool sargs_equals(const char* key, const char* val) {
}
SOKOL_API_IMPL bool sargs_boolean(const char* key) {
- const char* val = sargs_value(key);
- return (0 == strcmp("true", val)) ||
- (0 == strcmp("yes", val)) ||
- (0 == strcmp("on", val));
+ if (sargs_exists(key)) {
+ const char* val = sargs_value(key);
+ return (0 == strcmp("true", val)) ||
+ (0 == strcmp("yes", val)) ||
+ (0 == strcmp("on", val)) ||
+ (0 == strcmp("", val));
+ } else {
+ return false;
+ }
}
#endif /* SOKOL_ARGS_IMPL */