123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854 |
- #if defined(SOKOL_IMPL) && !defined(SOKOL_ARGS_IMPL)
- #define SOKOL_ARGS_IMPL
- #endif
- #ifndef SOKOL_ARGS_INCLUDED
- /*
- sokol_args.h -- cross-platform key/value arg-parsing for web and native
- Project URL: https://github.com/floooh/sokol
- Do this:
- #define SOKOL_IMPL or
- #define SOKOL_ARGS_IMPL
- before you include this file in *one* C or C++ file to create the
- implementation.
- Optionally provide the following defines with your own implementations:
- SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
- SOKOL_ARGS_API_DECL - public function declaration prefix (default: extern)
- SOKOL_API_DECL - same as SOKOL_ARGS_API_DECL
- SOKOL_API_IMPL - public function implementation prefix (default: -)
- If sokol_args.h is compiled as a DLL, define the following before
- including the declaration or implementation:
- SOKOL_DLL
- On Windows, SOKOL_DLL will define SOKOL_ARGS_API_DECL as __declspec(dllexport)
- or __declspec(dllimport) as needed.
- OVERVIEW
- ========
- sokol_args.h provides a simple unified argument parsing API for WebAssembly and
- native apps.
- When running as a 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
- The same arguments provided to a command line app:
- 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
- ===================
- On the web platform, arguments must be formatted as a valid URL query string
- with 'percent encoding' used for special characters.
- Strings are expected to be UTF-8 encoded (although sokol_args.h doesn't
- contain any special UTF-8 handling). See below on how to obtain
- UTF-8 encoded argc/argv values on Windows when using WinMain() as
- entry point.
- On native platforms the following rules must be followed:
- Arguments have the general form
- 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.
- Whitespace characters in front and after the separating '=' character
- are ignored:
- key = value
- ...is the same as
- key=value
- The 'key' string must be a simple string without escape sequences or whitespace.
- The 'value' string can be quoted, and quoted value strings can contain
- whitespace:
- key = 'single-quoted value'
- key = "double-quoted value"
- Single-quoted value strings can contain double quotes, and vice-versa:
- key = 'single-quoted value "can contain double-quotes"'
- key = "double-quoted value 'can contain single-quotes'"
- Note that correct quoting can be tricky on some shells, since command
- shells may remove quotes, unless they're escaped.
- Value strings can contain a small selection of escape sequences:
- \n - newline
- \r - carriage return
- \t - tab
- \\ - escaped backslash
- (more escape codes may be added in the future).
- CODE EXAMPLE
- ============
- int main(int argc, char* argv[]) {
- // initialize sokol_args with default parameters
- sargs_setup(&(sargs_desc){
- .argc = argc,
- .argv = argv
- });
- // check if a key exists...
- if (sargs_exists("bla")) {
- ...
- }
- // get value string for key, if not found, return empty string ""
- const char* val0 = sargs_value("bla");
- // get value string for key, or default string if key not found
- const char* val1 = sargs_value_def("bla", "default_value");
- // check if a key matches expected value
- if (sargs_equals("type", "kc85_4")) {
- ...
- }
- // check if a key's value is "true", "yes" or "on" or if this is a standalone key
- if (sargs_boolean("joystick_enabled")) {
- ...
- }
- // iterate over keys and values
- for (int i = 0; i < sargs_num_args(); i++) {
- printf("key: %s, value: %s\n", sargs_key_at(i), sargs_value_at(i));
- }
- // lookup argument index by key string, will return -1 if key
- // is not found, sargs_key_at() and sargs_value_at() will return
- // an empty string for invalid indices
- int index = sargs_find("bla");
- printf("key: %s, value: %s\n", sargs_key_at(index), sargs_value_at(index));
- // shutdown sokol-args
- sargs_shutdown();
- }
- WINMAIN AND ARGC / ARGV
- =======================
- On Windows with WinMain() based apps, getting UTF8-encoded command line
- arguments is a bit more complicated:
- First call GetCommandLineW(), this returns the entire command line
- as UTF-16 string. Then call CommandLineToArgvW(), this parses the
- command line string into the usual argc/argv format (but in UTF-16).
- Finally convert the UTF-16 strings in argv[] into UTF-8 via
- WideCharToMultiByte().
- See the function _sapp_win32_command_line_to_utf8_argv() in sokol_app.h
- for example code how to do this (if you're using sokol_app.h, it will
- already convert the command line arguments to UTF-8 for you of course,
- so you can plug them directly into sokol_app.h).
- API DOCUMENTATION
- =================
- void sargs_setup(const sargs_desc* desc)
- Initialize sokol_args, desc contains the following configuration
- parameters:
- int argc - the main function's argc parameter
- char** argv - the main function's argv parameter
- int max_args - max number of key/value pairs, default is 16
- int buf_size - size of the internal string buffer, default is 16384
- Note that on the web, argc and argv will be ignored and the arguments
- will be taken from the page URL instead.
- sargs_setup() will allocate 2 memory chunks: one for keeping track
- of the key/value args of size 'max_args*8', and a string buffer
- of size 'buf_size'.
- void sargs_shutdown(void)
- Shutdown sokol-args and free any allocated memory.
- bool sargs_isvalid(void)
- Return true between sargs_setup() and sargs_shutdown()
- bool sargs_exists(const char* key)
- 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, 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
- 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',
- 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.
- int sargs_num_args(void)
- Return number of key/value pairs.
- const char* sargs_key_at(int index)
- Return the key name of argument at index. Returns empty string if
- is index is outside range.
- const char* sargs_value_at(int index)
- Return the value of argument at index. Returns empty string
- if the key at index has no value, or the index is out-of-range.
- MEMORY ALLOCATION OVERRIDE
- ==========================
- You can override the memory allocation functions at initialization time
- like this:
- void* my_alloc(size_t size, void* user_data) {
- return malloc(size);
- }
- void my_free(void* ptr, void* user_data) {
- free(ptr);
- }
- ...
- sargs_setup(&(sargs_desc){
- // ...
- .allocator = {
- .alloc_fn = my_alloc,
- .free_fn = my_free,
- .user_data = ...,
- }
- });
- ...
- If no overrides are provided, malloc and free will be used.
- This only affects memory allocation calls done by sokol_args.h
- itself though, not any allocations in OS libraries.
- TODO
- ====
- - parsing errors?
- LICENSE
- =======
- zlib/libpng license
- Copyright (c) 2018 Andre Weissflog
- This software is provided 'as-is', without any express or implied warranty.
- In no event will the authors be held liable for any damages arising from the
- use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software in a
- product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not
- be misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source
- distribution.
- */
- #define SOKOL_ARGS_INCLUDED (1)
- #include <stdint.h>
- #include <stdbool.h>
- #include <stddef.h> // size_t
- #if defined(SOKOL_API_DECL) && !defined(SOKOL_ARGS_API_DECL)
- #define SOKOL_ARGS_API_DECL SOKOL_API_DECL
- #endif
- #ifndef SOKOL_ARGS_API_DECL
- #if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_ARGS_IMPL)
- #define SOKOL_ARGS_API_DECL __declspec(dllexport)
- #elif defined(_WIN32) && defined(SOKOL_DLL)
- #define SOKOL_ARGS_API_DECL __declspec(dllimport)
- #else
- #define SOKOL_ARGS_API_DECL extern
- #endif
- #endif
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*
- sargs_allocator
- Used in sargs_desc to provide custom memory-alloc and -free functions
- to sokol_args.h. If memory management should be overridden, both the
- alloc_fn and free_fn function must be provided (e.g. it's not valid to
- override one function but not the other).
- */
- typedef struct sargs_allocator {
- void* (*alloc_fn)(size_t size, void* user_data);
- void (*free_fn)(void* ptr, void* user_data);
- void* user_data;
- } sargs_allocator;
- typedef struct sargs_desc {
- int argc;
- char** argv;
- int max_args;
- int buf_size;
- sargs_allocator allocator;
- } sargs_desc;
- // setup sokol-args
- SOKOL_ARGS_API_DECL void sargs_setup(const sargs_desc* desc);
- // shutdown sokol-args
- SOKOL_ARGS_API_DECL void sargs_shutdown(void);
- // true between sargs_setup() and sargs_shutdown()
- 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 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 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", "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);
- // get number of parsed arguments
- SOKOL_ARGS_API_DECL int sargs_num_args(void);
- // get key name of argument at index, or empty string
- SOKOL_ARGS_API_DECL const char* sargs_key_at(int index);
- // get value string of argument at index, or empty string
- SOKOL_ARGS_API_DECL const char* sargs_value_at(int index);
- #ifdef __cplusplus
- } // extern "C"
- // reference-based equivalents for c++
- inline void sargs_setup(const sargs_desc& desc) { return sargs_setup(&desc); }
- #endif
- #endif // SOKOL_ARGS_INCLUDED
- //--- IMPLEMENTATION -----------------------------------------------------------
- #ifdef SOKOL_ARGS_IMPL
- #define SOKOL_ARGS_IMPL_INCLUDED (1)
- #if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE)
- #error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sargs_desc.allocator to override memory allocation functions"
- #endif
- #include <string.h> // memset, strcmp
- #include <stdlib.h> // malloc, free
- #if defined(__EMSCRIPTEN__)
- #include <emscripten/emscripten.h>
- #endif
- #ifndef SOKOL_API_IMPL
- #define SOKOL_API_IMPL
- #endif
- #ifndef SOKOL_DEBUG
- #ifndef NDEBUG
- #define SOKOL_DEBUG
- #endif
- #endif
- #ifndef SOKOL_ASSERT
- #include <assert.h>
- #define SOKOL_ASSERT(c) assert(c)
- #endif
- #ifndef _SOKOL_PRIVATE
- #if defined(__GNUC__) || defined(__clang__)
- #define _SOKOL_PRIVATE __attribute__((unused)) static
- #else
- #define _SOKOL_PRIVATE static
- #endif
- #endif
- #define _sargs_def(val, def) (((val) == 0) ? (def) : (val))
- #define _SARGS_MAX_ARGS_DEF (16)
- #define _SARGS_BUF_SIZE_DEF (16*1024)
- // parser state
- #define _SARGS_EXPECT_KEY (1<<0)
- #define _SARGS_EXPECT_SEP (1<<1)
- #define _SARGS_EXPECT_VAL (1<<2)
- #define _SARGS_PARSING_KEY (1<<3)
- #define _SARGS_PARSING_VAL (1<<4)
- #define _SARGS_ERROR (1<<5)
- // a key/value pair struct
- typedef struct {
- int key; // index to start of key string in buf
- int val; // index to start of value string in buf
- } _sargs_kvp_t;
- // sokol-args state
- typedef struct {
- int max_args; // number of key/value pairs in args array
- int num_args; // number of valid items in args array
- _sargs_kvp_t* args; // key/value pair array
- int buf_size; // size of buffer in bytes
- int buf_pos; // current buffer position
- char* buf; // character buffer, first char is reserved and zero for 'empty string'
- bool valid;
- uint32_t parse_state;
- char quote; // current quote char, 0 if not in a quote
- bool in_escape; // currently in an escape sequence
- sargs_allocator allocator;
- } _sargs_state_t;
- static _sargs_state_t _sargs;
- //== PRIVATE IMPLEMENTATION FUNCTIONS ==========================================
- _SOKOL_PRIVATE void _sargs_clear(void* ptr, size_t size) {
- SOKOL_ASSERT(ptr && (size > 0));
- memset(ptr, 0, size);
- }
- _SOKOL_PRIVATE void* _sargs_malloc(size_t size) {
- SOKOL_ASSERT(size > 0);
- void* ptr;
- if (_sargs.allocator.alloc_fn) {
- ptr = _sargs.allocator.alloc_fn(size, _sargs.allocator.user_data);
- } else {
- ptr = malloc(size);
- }
- SOKOL_ASSERT(ptr);
- return ptr;
- }
- _SOKOL_PRIVATE void* _sargs_malloc_clear(size_t size) {
- void* ptr = _sargs_malloc(size);
- _sargs_clear(ptr, size);
- return ptr;
- }
- _SOKOL_PRIVATE void _sargs_free(void* ptr) {
- if (_sargs.allocator.free_fn) {
- _sargs.allocator.free_fn(ptr, _sargs.allocator.user_data);
- } else {
- free(ptr);
- }
- }
- _SOKOL_PRIVATE void _sargs_putc(char c) {
- if ((_sargs.buf_pos+2) < _sargs.buf_size) {
- _sargs.buf[_sargs.buf_pos++] = c;
- }
- }
- _SOKOL_PRIVATE const char* _sargs_str(int index) {
- SOKOL_ASSERT((index >= 0) && (index < _sargs.buf_size));
- return &_sargs.buf[index];
- }
- //-- argument parser functions --------------------
- _SOKOL_PRIVATE void _sargs_expect_key(void) {
- _sargs.parse_state = _SARGS_EXPECT_KEY;
- }
- _SOKOL_PRIVATE bool _sargs_key_expected(void) {
- return 0 != (_sargs.parse_state & _SARGS_EXPECT_KEY);
- }
- _SOKOL_PRIVATE void _sargs_expect_val(void) {
- _sargs.parse_state = _SARGS_EXPECT_VAL;
- }
- _SOKOL_PRIVATE bool _sargs_val_expected(void) {
- return 0 != (_sargs.parse_state & _SARGS_EXPECT_VAL);
- }
- _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) {
- return 0 != (_sargs.parse_state & (_SARGS_EXPECT_KEY | _SARGS_EXPECT_VAL | _SARGS_EXPECT_SEP));
- }
- _SOKOL_PRIVATE bool _sargs_is_separator(char c) {
- return c == '=';
- }
- _SOKOL_PRIVATE bool _sargs_is_quote(char c) {
- if (0 == _sargs.quote) {
- return (c == '\'') || (c == '"');
- } else {
- return c == _sargs.quote;
- }
- }
- _SOKOL_PRIVATE void _sargs_begin_quote(char c) {
- _sargs.quote = c;
- }
- _SOKOL_PRIVATE void _sargs_end_quote(void) {
- _sargs.quote = 0;
- }
- _SOKOL_PRIVATE bool _sargs_in_quotes(void) {
- return 0 != _sargs.quote;
- }
- _SOKOL_PRIVATE bool _sargs_is_whitespace(char c) {
- return !_sargs_in_quotes() && ((c == ' ') || (c == '\t'));
- }
- _SOKOL_PRIVATE void _sargs_start_key(void) {
- 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 >= 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;
- }
- _SOKOL_PRIVATE bool _sargs_parsing_key(void) {
- return 0 != (_sargs.parse_state & _SARGS_PARSING_KEY);
- }
- _SOKOL_PRIVATE void _sargs_start_val(void) {
- SOKOL_ASSERT((_sargs.num_args > 0) && (_sargs.num_args <= _sargs.max_args));
- _sargs.parse_state = _SARGS_PARSING_VAL;
- _sargs.args[_sargs.num_args - 1].val = _sargs.buf_pos;
- }
- _SOKOL_PRIVATE void _sargs_end_val(void) {
- _sargs_putc(0);
- _sargs.parse_state = 0;
- }
- _SOKOL_PRIVATE bool _sargs_is_escape(char c) {
- return '\\' == c;
- }
- _SOKOL_PRIVATE void _sargs_start_escape(void) {
- _sargs.in_escape = true;
- }
- _SOKOL_PRIVATE bool _sargs_in_escape(void) {
- return _sargs.in_escape;
- }
- _SOKOL_PRIVATE char _sargs_escape(char c) {
- switch (c) {
- case 'n': return '\n';
- case 't': return '\t';
- case 'r': return '\r';
- case '\\': return '\\';
- default: return c;
- }
- }
- _SOKOL_PRIVATE void _sargs_end_escape(void) {
- _sargs.in_escape = false;
- }
- _SOKOL_PRIVATE bool _sargs_parsing_val(void) {
- return 0 != (_sargs.parse_state & _SARGS_PARSING_VAL);
- }
- _SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) {
- char c;
- while (0 != (c = *src++)) {
- if (_sargs_in_escape()) {
- c = _sargs_escape(c);
- _sargs_end_escape();
- } else if (_sargs_is_escape(c)) {
- _sargs_start_escape();
- continue;
- }
- if (_sargs_any_expected()) {
- if (!_sargs_is_whitespace(c)) {
- // start of key, value or separator
- 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();
- } else if (_sargs_val_expected()) {
- // start of value
- if (_sargs_is_quote(c)) {
- _sargs_begin_quote(c);
- continue;
- }
- _sargs_start_val();
- }
- } else {
- // skip white space
- continue;
- }
- } else if (_sargs_parsing_key()) {
- if (_sargs_is_whitespace(c) || _sargs_is_separator(c)) {
- // end of key string
- _sargs_end_key();
- if (_sargs_is_separator(c)) {
- _sargs_expect_val();
- } else {
- _sargs_expect_sep_or_key();
- }
- continue;
- }
- } else if (_sargs_parsing_val()) {
- if (_sargs_in_quotes()) {
- /* when in quotes, whitespace is a normal character
- and a matching quote ends the value string
- */
- if (_sargs_is_quote(c)) {
- _sargs_end_quote();
- _sargs_end_val();
- _sargs_expect_key();
- continue;
- }
- } else if (_sargs_is_whitespace(c)) {
- // end of value string (no quotes)
- _sargs_end_val();
- _sargs_expect_key();
- continue;
- }
- }
- _sargs_putc(c);
- }
- if (_sargs_parsing_key()) {
- _sargs_end_key();
- _sargs_expect_sep_or_key();
- } else if (_sargs_parsing_val() && !_sargs_in_quotes()) {
- _sargs_end_val();
- _sargs_expect_key();
- }
- return true;
- }
- _SOKOL_PRIVATE bool _sargs_parse_cargs(int argc, const char** argv) {
- _sargs_expect_key();
- bool retval = true;
- for (int i = 1; i < argc; i++) {
- retval &= _sargs_parse_carg(argv[i]);
- }
- _sargs.parse_state = 0;
- return retval;
- }
- //-- EMSCRIPTEN IMPLEMENTATION -------------------------------------------------
- #if defined(__EMSCRIPTEN__)
- #ifdef __cplusplus
- extern "C" {
- #endif
- #if defined(EM_JS_DEPS)
- EM_JS_DEPS(sokol_audio, "$withStackSave,$stringToUTF8OnStack")
- #endif
- EMSCRIPTEN_KEEPALIVE void _sargs_add_kvp(const char* key, const char* val) {
- SOKOL_ASSERT(_sargs.valid && key && val);
- if (_sargs.num_args >= _sargs.max_args) {
- return;
- }
- /* copy key string */
- char c;
- _sargs.args[_sargs.num_args].key = _sargs.buf_pos;
- const char* ptr = key;
- while (0 != (c = *ptr++)) {
- _sargs_putc(c);
- }
- _sargs_putc(0);
- // copy value string
- _sargs.args[_sargs.num_args].val = _sargs.buf_pos;
- ptr = val;
- while (0 != (c = *ptr++)) {
- _sargs_putc(c);
- }
- _sargs_putc(0);
- _sargs.num_args++;
- }
- #ifdef __cplusplus
- } // extern "C"
- #endif
- // JS function to extract arguments from the page URL
- EM_JS(void, sargs_js_parse_url, (void), {
- const params = new URLSearchParams(window.location.search).entries();
- for (let p = params.next(); !p.done; p = params.next()) {
- const key = p.value[0];
- const val = p.value[1];
- withStackSave(() => {
- const key_cstr = stringToUTF8OnStack(key);
- const val_cstr = stringToUTF8OnStack(val);
- __sargs_add_kvp(key_cstr, val_cstr)
- });
- }
- })
- #endif // EMSCRIPTEN
- //== PUBLIC IMPLEMENTATION FUNCTIONS ===========================================
- SOKOL_API_IMPL void sargs_setup(const sargs_desc* desc) {
- SOKOL_ASSERT(desc);
- _sargs_clear(&_sargs, sizeof(_sargs));
- _sargs.max_args = _sargs_def(desc->max_args, _SARGS_MAX_ARGS_DEF);
- _sargs.buf_size = _sargs_def(desc->buf_size, _SARGS_BUF_SIZE_DEF);
- SOKOL_ASSERT(_sargs.buf_size > 8);
- _sargs.args = (_sargs_kvp_t*) _sargs_malloc_clear((size_t)_sargs.max_args * sizeof(_sargs_kvp_t));
- _sargs.buf = (char*) _sargs_malloc_clear((size_t)_sargs.buf_size * sizeof(char));
- // the first character in buf is reserved and always zero, this is the 'empty string'
- _sargs.buf_pos = 1;
- _sargs.allocator = desc->allocator;
- _sargs.valid = true;
- // parse argc/argv
- _sargs_parse_cargs(desc->argc, (const char**) desc->argv);
- #if defined(__EMSCRIPTEN__)
- // on emscripten, also parse the page URL
- sargs_js_parse_url();
- #endif
- }
- SOKOL_API_IMPL void sargs_shutdown(void) {
- SOKOL_ASSERT(_sargs.valid);
- if (_sargs.args) {
- _sargs_free(_sargs.args);
- _sargs.args = 0;
- }
- if (_sargs.buf) {
- _sargs_free(_sargs.buf);
- _sargs.buf = 0;
- }
- _sargs.valid = false;
- }
- SOKOL_API_IMPL bool sargs_isvalid(void) {
- return _sargs.valid;
- }
- SOKOL_API_IMPL int sargs_find(const char* key) {
- SOKOL_ASSERT(_sargs.valid && key);
- for (int i = 0; i < _sargs.num_args; i++) {
- if (0 == strcmp(_sargs_str(_sargs.args[i].key), key)) {
- return i;
- }
- }
- return -1;
- }
- SOKOL_API_IMPL int sargs_num_args(void) {
- SOKOL_ASSERT(_sargs.valid);
- return _sargs.num_args;
- }
- SOKOL_API_IMPL const char* sargs_key_at(int index) {
- SOKOL_ASSERT(_sargs.valid);
- if ((index >= 0) && (index < _sargs.num_args)) {
- return _sargs_str(_sargs.args[index].key);
- } else {
- // index 0 is always the empty string
- return _sargs_str(0);
- }
- }
- SOKOL_API_IMPL const char* sargs_value_at(int index) {
- SOKOL_ASSERT(_sargs.valid);
- if ((index >= 0) && (index < _sargs.num_args)) {
- return _sargs_str(_sargs.args[index].val);
- } else {
- // index 0 is always the empty string
- return _sargs_str(0);
- }
- }
- SOKOL_API_IMPL bool sargs_exists(const char* key) {
- SOKOL_ASSERT(_sargs.valid && key);
- return -1 != sargs_find(key);
- }
- SOKOL_API_IMPL const char* sargs_value(const char* key) {
- SOKOL_ASSERT(_sargs.valid && key);
- return sargs_value_at(sargs_find(key));
- }
- 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) {
- const char* res = sargs_value_at(arg_index);
- SOKOL_ASSERT(res);
- if (res[0] == 0) {
- return def;
- } else {
- return res;
- }
- } else {
- return def;
- }
- }
- SOKOL_API_IMPL bool sargs_equals(const char* key, const char* val) {
- SOKOL_ASSERT(_sargs.valid && key && val);
- return 0 == strcmp(sargs_value(key), val);
- }
- SOKOL_API_IMPL bool sargs_boolean(const char* key) {
- 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
|