diff --git a/src/util/Makefile b/src/util/Makefile index 96a55d46..ecad54d6 100644 --- a/src/util/Makefile +++ b/src/util/Makefile @@ -3,6 +3,8 @@ include $(top_builddir)/Makefile.config INCLUDES += $(GNUTLS_CFLAGS) $(OPENSSL_CFLAGS) +SUBDIRS = qs_parse + OBJS-unless$(CONFIG_SMALL) += fastfind.o OBJS-$(CONFIG_CSS) += scanner.o OBJS-$(CONFIG_DEBUG) += memdebug.o diff --git a/src/util/meson.build b/src/util/meson.build index 8c619ba9..54039e45 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -1,4 +1,4 @@ -#INCLUDES += $(GNUTLS_CFLAGS) $(OPENSSL_CFLAGS) +subdir('qs_parse') if not conf_data.get('CONFIG_SMALL') srcs += files('fastfind.c') diff --git a/src/util/qs_parse/LICENSE b/src/util/qs_parse/LICENSE new file mode 100644 index 00000000..e57b0d49 --- /dev/null +++ b/src/util/qs_parse/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010 Bart Grantham + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/util/qs_parse/Makefile b/src/util/qs_parse/Makefile new file mode 100644 index 00000000..4bfa68f9 --- /dev/null +++ b/src/util/qs_parse/Makefile @@ -0,0 +1,6 @@ +top_builddir=../../.. +include $(top_builddir)/Makefile.config + +OBJS = qs_parse.o + +include $(top_srcdir)/Makefile.lib diff --git a/src/util/qs_parse/README.md b/src/util/qs_parse/README.md new file mode 100644 index 00000000..66857340 --- /dev/null +++ b/src/util/qs_parse/README.md @@ -0,0 +1,66 @@ +# qs_parse # + +## Description ## + +A set of simple and easy functions for parsing URL query strings, such as +those generated in an HTTP GET form submission. + + +## How to Use ## + +These qs_* functions can be used in two different ways: + +`qs_parse()`/`qs_k2v()`: A faster version that requires a pre-processing stage +and **is destructive to the query string** + + * Better for repeated lookups of k/v pairs + * Does all decoding/processing in-place, so no memory copying + * Requires an array of pointers to strings to be passed to the preprocessing stage + * Cannot be used where the query string is const + +`qs_scanvalue()`: A slower version that will scan for the given key and will +decode the value into a user-provided string + + * Doesn't alter the query string so can be used where it is const, or cannot be altered + * Only needs a user-passed char string for copying into + * Scans the entire qs on each call, so isn't as fast as qs_k2v() + + +Since `qs_parse()`/`qs_k2v()` alters the query string that is passed to it in a way +that defeats `qs_scanvalue()`, do not mix these two methods (or if you must, +either don't call `qs_scanvalue()` after a call to `qs_parse()` or be sure make +a copy of the query string beforehand) + +[note: speed comparisons will be more relevant when the sorting the k/v pairs +code is implemented] + + +## Installation ## +All you really need is qs_parse.h and qs_parse.c. I've included my test program +("qs_test.c") and an example program that shows how to use these functions +("qs_example.c"). Also included is a quick Makefile. If you want to see it +come to life just get all the files and: + + # make + # ./qs_example + + +## Bugs, etc. ## + +Please let me know if you find any, or if you have license-friendly enhancements +to add. + + +## License ## + +MIT License. See ./LICENSE or + +Few things are more enjoyable than the knowledge that you've helped another +person. If you do use these functions for anything, I'd love to hear about it: + + + + +Enjoy! + +-Bart diff --git a/src/util/qs_parse/meson.build b/src/util/qs_parse/meson.build new file mode 100644 index 00000000..dd8c8e2d --- /dev/null +++ b/src/util/qs_parse/meson.build @@ -0,0 +1 @@ +srcs += files('qs_parse.c') diff --git a/src/util/qs_parse/qs_example.c b/src/util/qs_parse/qs_example.c new file mode 100644 index 00000000..70265233 --- /dev/null +++ b/src/util/qs_parse/qs_example.c @@ -0,0 +1,106 @@ +/* Licensed under the MIT License by Bart Grantham, 2010. See ./LICENSE or + * http://www.opensource.org/licenses/mit-license.php + */ +#include +#include "qs_parse.h" + +#define NUMKVPAIRS 256 +#define VALSIZE 256 + +int main(int argc, char * argv[]) +{ + int i; + char * kvpairs[NUMKVPAIRS]; + char value[VALSIZE]; + char * value_ptr; + unsigned char r, g, b, a; + double dr, dg, db, da; + + char getstring[] = "scheme://username:password@domain:port/path?foo=bar&frob&baz=quux&color=09FA#anchor"; + + printf("Our GET string is %s\n\n", getstring); + + /********************************************************/ + /* The easy, but not as efficient way: qs_scanvalue() */ + /********************************************************/ + if ( qs_scanvalue("foo", getstring, value, sizeof(value)) != NULL ) + printf("Key %s is set, and the value is: \"%s\"\n", "foo", value); + else + printf("Key %s is NOT set\n", "foo"); + + if ( qs_scanvalue("baz", getstring, value, sizeof(value)) != NULL ) + printf("Key %s is set, and the value is: \"%s\"\n", "baz", value); + else + printf("Key %s is NOT set\n", "baz"); + + if ( qs_scanvalue("frob", getstring, value, sizeof(value)) != NULL ) + printf("Key %s is set, and the value is: \"%s\"\n", "frob", value); + else + printf("Key %s is NOT set\n", "frob"); + + if ( qs_scanvalue("blah", getstring, value, sizeof(value)) != NULL ) + printf("Key %s is set, and the value is: \"%s\"\n", "blah", value); + else + printf("Key %s is NOT set\n", "blah"); + + if ( qs_scanvalue("color", getstring, value, sizeof(value)) != NULL ) + { + printf("Key %s is set, and the value is: \"%s\"\n", "color", value); + if ( hex2ccolor(value, &r, &g, &b, &a) != 0 && hex2dcolor(value, &dr, &dg, &db, &da) != 0 ) + { + printf(" \"%s\" successfully decoded as uchar : r=%d, g=%d, b=%d, a=%d\n", "color", r, g, b, a); + printf(" \"%s\" successfully decoded as double : r=%.2f, g=%.2f, b=%.2f, a=%.2f\n", "color", dr, dg, db, da); + } + else + printf(" \"%s\" NOT successfully decoded\n", "color"); + } + else + printf("Key %s is NOT set\n", "color"); + + printf("\n"); + + + /*************************************************************************/ + /* The faster, more complex, and destructive way: qs_parse() / qs_k2v() */ + /*************************************************************************/ + + /* ***THIS WILL ALTER getstring*** */ + i = qs_parse(getstring, kvpairs, 256); + /* At this point qs_scanvalue() will no longer work with this query string */ + + if ( (value_ptr = qs_k2v("foo", kvpairs, i)) != NULL ) + printf("Key %s is set, and the value is: \"%s\"\n", "foo", value_ptr); + else + printf("Key %s is NOT set\n", "foo"); + + if ( (value_ptr = qs_k2v("baz", kvpairs, i)) != NULL ) + printf("Key %s is set, and the value is: \"%s\"\n", "baz", value_ptr); + else + printf("Key %s is NOT set\n", "baz"); + + if ( (value_ptr = qs_k2v("frob", kvpairs, i)) != NULL ) + printf("Key %s is set, and the value is: \"%s\"\n", "frob", value_ptr); + else + printf("Key %s is NOT set\n", "frob"); + + if ( (value_ptr = qs_k2v("blah", kvpairs, i)) != NULL ) + printf("Key %s is set, and the value is: \"%s\"\n", "blah", value_ptr); + else + printf("Key %s is NOT set\n", "blah"); + + if ( (value_ptr = qs_k2v("color", kvpairs, i)) != NULL ) + { + printf("Key %s is set, and the value is: \"%s\"\n", "color", value_ptr); + if ( hex2ccolor(value_ptr, &r, &g, &b, &a) != 0 && hex2dcolor(value_ptr, &dr, &dg, &db, &da) != 0 ) + { + printf(" \"%s\" successfully decoded as uchar : r=%d, g=%d, b=%d, a=%d\n", "color", r, g, b, a); + printf(" \"%s\" successfully decoded as double : r=%.2f, g=%.2f, b=%.2f, a=%.2f\n", "color", dr, dg, db, da); + } + else + printf(" \"%s\" NOT successfully decoded\n", "color"); + } + else + printf("Key %s is NOT set\n", "color"); + + return 0; +} diff --git a/src/util/qs_parse/qs_parse.c b/src/util/qs_parse/qs_parse.c new file mode 100644 index 00000000..8de810d7 --- /dev/null +++ b/src/util/qs_parse/qs_parse.c @@ -0,0 +1,272 @@ +#include "qs_parse.h" +#include + +// TODO: implement sorting of the qs_kv array; for now ensure it's not compiled +#undef _qsSORTING + +// isxdigit _is_ available in , but let's avoid another header instead +#define ISHEX(x) ((((x)>='0'&&(x)<='9') || ((x)>='A'&&(x)<='F') || ((x)>='a'&&(x)<='f')) ? 1 : 0) +#define HEX2DEC(x) (((x)>='0'&&(x)<='9') ? (x)-48 : ((x)>='A'&&(x)<='F') ? (x)-55 : ((x)>='a'&&(x)<='f') ? (x)-87 : 0) +#define ISQSCHR(x) ((((x)=='=')||((x)=='#')||((x)=='&')||((x)=='\0')) ? 0 : 1) + +int qs_strncmp(const char * s, const char * qs, register size_t n) +{ + int i=0; + register unsigned char u1, u2, unyb, lnyb; + + while(n-- > 0) + { + u1 = (unsigned char) *s++; + u2 = (unsigned char) *qs++; + + if ( ! ISQSCHR(u1) ) { u1 = '\0'; } + if ( ! ISQSCHR(u2) ) { u2 = '\0'; } + + if ( u1 == '+' ) { u1 = ' '; } + if ( u1 == '%' ) // easier/safer than scanf + { + unyb = (unsigned char) *s++; + lnyb = (unsigned char) *s++; + if ( ISHEX(unyb) && ISHEX(lnyb) ) + u1 = (HEX2DEC(unyb) * 16) + HEX2DEC(lnyb); + else + u1 = '\0'; + } + + if ( u2 == '+' ) { u2 = ' '; } + if ( u2 == '%' ) // easier/safer than scanf + { + unyb = (unsigned char) *qs++; + lnyb = (unsigned char) *qs++; + if ( ISHEX(unyb) && ISHEX(lnyb) ) + u2 = (HEX2DEC(unyb) * 16) + HEX2DEC(lnyb); + else + u2 = '\0'; + } + + if ( u1 != u2 ) + return u1 - u2; + if ( u1 == '\0' ) + return 0; + i++; + } + if ( ISQSCHR(*qs) ) + return -1; + else + return 0; +} + + +int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) +{ + int i, j; + char * substr_ptr; + + for(i=0; i means x iterations of this loop -> means *x+1* k/v pairs + + // we only decode the values in place, the keys could have '='s in them + // which will hose our ability to distinguish keys from values later + for(j=0; j + +#ifndef BG_QSPARSE_H_ +#define BG_QSPARSE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* string.h needed for strcspn() and strlen() */ + + +/* Similar to strncmp, but handles URL-encoding for either string */ +int qs_strncmp(const char * s, const char * qs, register size_t n); + + +/* Finds the beginning of each key/value pair and stores a pointer in qs_kv. + * Also decodes the value portion of the k/v pair *in-place*. In a future + * enhancement it will also have a compile-time option of sorting qs_kv + * alphabetically by key. */ +int qs_parse(char * qs, char * qs_kv[], int qs_kv_size); + + +/* Used by qs_parse to decode the value portion of a k/v pair */ +int qs_decode(char * qs); + + +/* Looks up the value according to the key on a pre-processed query string + * A future enhancement will be a compile-time option to look up the key + * in a pre-sorted qs_kv array via a binary search. */ +char * qs_k2v(const char * key, char * qs_kv[], int qs_kv_size); + + +/* Non-destructive lookup of value, based on key. User provides the + * destinaton string and length. */ +char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len); + + +/* Converts the 3 or 6 (RGB), or 4 or 8 (RGBA) hex chars in the color string + * to double values in the range 0.0-1.0. Returns the number of converted + * chars. */ +int hex2dcolor(char * color, double * r, double * g, double * b, double * a); + + +/* Converts the 3/6 (RGB) or 4/8 (RGBA) hex chars in the color string to + * values spanning the full range of unsigned char, 0-255. Returns the + * number of converted chars. */ +int hex2ccolor(char * color, unsigned char * r, unsigned char * g, unsigned char * b, unsigned char * a); + +#ifdef __cplusplus +} +#endif + +#endif // BG_QSPARSE_H_ diff --git a/src/util/qs_parse/qs_test.c b/src/util/qs_parse/qs_test.c new file mode 100644 index 00000000..d45fc4da --- /dev/null +++ b/src/util/qs_parse/qs_test.c @@ -0,0 +1,138 @@ +/* Licensed under the MIT License by Bart Grantham, 2010. See ./LICENSE or + * http://www.opensource.org/licenses/mit-license.php + */ +#include +#include "qs_parse.h" + +int main(int argc, char * argv[]) +{ + int i,j; + char * kvpairs[256]; + char value[256]; + unsigned char r, g, b, a; + double dr, dg, db, da; + + char foo[] = "foo"; + char foobar[] = "foobar"; + char foo_enc[] = "fo%6f"; + char foobar_enc[] = "fo%6fbar"; + char foo_mal[] = "fo%6"; + char foo_mal2[] = "foo%6"; + char foo_end[] = "foo&"; + + /* This test query string includes: + * - URL encoded values (percent-encoded and +-as-space) + * - URL encoded keys (percent-encoded +-as-space) + * - Incorrectly encoded values (FFFFFF%f) + * - A trailing anchor + * - null (0-char) values + * + * I should add: + * - leading URL junk (before a ?) + */ + char getstring[] = "FUNNYJUNK://@?t%65xt=bleh+bleh%20!&font=Vera.ttf&size=40.3&fg=Fa98BF44%f&debug1&bg=0C0&color=FF4455F&hash=24a%62cdef%7a&rot=123.1&tr+i=cky&debug2#don'tparseme,bro"; + + printf("Testing qs_* functions\n"); + + printf(" Testing qs_strncmp():\n"); + printf(" %s, %s, 3 should be 0 : %d\n", foo, foo, qs_strncmp(foo, foo, 3)); + printf(" %s, %s, 4 should be 0 : %d\n", foo, foo, qs_strncmp(foo, foo, 4)); + printf(" %s, %s, 99 should be 0 : %d\n", foo, foo, qs_strncmp(foo, foo, 99)); + printf(" %s, %s, 3 should be 0 : %d\n", foo, foo_enc, qs_strncmp(foo, foo_enc, 3)); + printf(" %s, %s, 4 should be 0 : %d\n", foo, foo_enc, qs_strncmp(foo, foo_enc, 4)); + printf(" %s, %s, 99 should be 0 : %d\n", foo, foo_enc, qs_strncmp(foo, foo_enc, 99)); + printf(" %s, %s, 3 should be 0 : %d\n", foo_enc, foo_enc, qs_strncmp(foo_enc, foo_enc, 3)); + printf(" %s, %s, 4 should be 0 : %d\n", foo_enc, foo_enc, qs_strncmp(foo_enc, foo_enc, 4)); + printf(" %s, %s, 99 should be 0 : %d\n", foo_enc, foo_enc, qs_strncmp(foo_enc, foo_enc, 99)); + printf(" %s, %s, 3 should be 0 : %d\n", foo, foobar, qs_strncmp(foo, foobar, 3)); + printf(" %s, %s, 4 should be - : %d\n", foo, foobar, qs_strncmp(foo, foobar, 4)); + printf(" %s, %s, 99 should be - : %d\n", foo, foobar, qs_strncmp(foo, foobar, 99)); + printf(" %s, %s, 3 should be 0 : %d\n", foo, foobar_enc, qs_strncmp(foo, foobar_enc, 3)); + printf(" %s, %s, 4 should be - : %d\n", foo, foobar_enc, qs_strncmp(foo, foobar_enc, 4)); + printf(" %s, %s, 99 should be - : %d\n", foo, foobar_enc, qs_strncmp(foo, foobar_enc, 99)); + printf(" %s, %s, 3 should be 0 : %d\n", foo_enc, foobar_enc, qs_strncmp(foo_enc, foobar_enc, 3)); + printf(" %s, %s, 4 should be - : %d\n", foo_enc, foobar_enc, qs_strncmp(foo_enc, foobar_enc, 4)); + printf(" %s, %s, 99 should be - : %d\n", foo_enc, foobar_enc, qs_strncmp(foo_enc, foobar_enc, 99)); + printf(" %s, %s, 2 should be 0 : %d\n", foo, foo_mal, qs_strncmp(foo, foo_mal, 2)); + printf(" %s, %s, 3 should be + : %d\n", foo, foo_mal, qs_strncmp(foo, foo_mal, 3)); + printf(" %s, %s, 99 should be + : %d\n", foo, foo_mal, qs_strncmp(foo, foo_mal, 99)); + printf(" %s, %s, 2 should be 0 : %d\n", foo, foo_mal2, qs_strncmp(foo, foo_mal2, 2)); + printf(" %s, %s, 3 should be 0 : %d\n", foo, foo_mal2, qs_strncmp(foo, foo_mal2, 3)); + printf(" %s, %s, 4 should be 0 : %d\n", foo, foo_mal2, qs_strncmp(foo, foo_mal2, 4)); + printf(" %s, %s, 99 should be 0 : %d\n", foo, foo_mal2, qs_strncmp(foo, foo_mal2, 99)); + printf(" %s, %s, 2 should be 0 : %d\n", foo, foo_end, qs_strncmp(foo, foo_end, 2)); + printf(" %s, %s, 3 should be 0 : %d\n", foo, foo_end, qs_strncmp(foo, foo_end, 3)); + printf(" %s, %s, 4 should be 0 : %d\n", foo, foo_end, qs_strncmp(foo, foo_end, 4)); + printf(" %s, %s, 99 should be 0 : %d\n", foo, foo_end, qs_strncmp(foo, foo_end, 99)); + + printf("\n"); + + + printf(" Testing qs_scanvalue() with query string:\n %s\n", getstring); + printf(" The following should say \"bleh bleh !\" : \"%s\"\n", qs_scanvalue("text", getstring, value, 256)); + printf(" The following should say \"Vera.ttf\" : \"%s\"\n", qs_scanvalue("font", getstring, value, 256)); + printf(" The following should say \"40.3\" : \"%s\"\n", qs_scanvalue("size", getstring, value, 256)); + printf(" The following should say \"Fa98BF44\" : \"%s\"\n", qs_scanvalue("fg", getstring, value, 256)); + printf(" The following should say \"\" : \"%s\"\n", qs_scanvalue("debug1", getstring, value, 256)); + printf(" The following should say \"0C0\" : \"%s\"\n", qs_scanvalue("bg", getstring, value, 256)); + printf(" The following should say \"FF4455F\" : \"%s\"\n", qs_scanvalue("color", getstring, value, 256)); + printf(" The following should say \"24abcdefz\" : \"%s\"\n", qs_scanvalue("hash", getstring, value, 256)); + printf(" The following should say \"123.1\" : \"%s\"\n", qs_scanvalue("rot", getstring, value, 256)); + printf(" The following should say \"cky\" : \"%s\"\n", qs_scanvalue("tr i", getstring, value, 256)); + printf(" The following should say \"\" : \"%s\"\n", qs_scanvalue("debug2", getstring, value, 256)); + printf("\n"); + + printf(" Running qs_parse() against query string (also exersizes qs_decode()):\n %s\n", getstring); + i = qs_parse(getstring, kvpairs, 256); + printf(" I should have found 11 k/v substrings, actually found: %d\n", i); + printf("\n"); + + printf(" Testing qs_k2v() against our kv pair substrings:\n"); + printf(" The following should say \"bleh bleh !\" : \"%s\"\n", qs_k2v("text", kvpairs, i)); + printf(" The following should say \"Vera.ttf\" : \"%s\"\n", qs_k2v("font", kvpairs, i)); + printf(" The following should say \"40.3\" : \"%s\"\n", qs_k2v("size", kvpairs, i)); + printf(" The following should say \"Fa98BF44\" : \"%s\"\n", qs_k2v("fg", kvpairs, i)); + printf(" The following should say \"\" : \"%s\"\n", qs_k2v("debug1", kvpairs, i)); + printf(" The following should say \"0C0\" : \"%s\"\n", qs_k2v("bg", kvpairs, i)); + printf(" The following should say \"FF4455F\" : \"%s\"\n", qs_k2v("color", kvpairs, i)); + printf(" The following should say \"24abcdefz\" : \"%s\"\n", qs_k2v("hash", kvpairs, i)); + printf(" The following should say \"123.1\" : \"%s\"\n", qs_k2v("rot", kvpairs, i)); + printf(" The following should say \"cky\" : \"%s\"\n", qs_k2v("tr i", kvpairs, i)); + printf(" The following should say \"\" : \"%s\"\n", qs_k2v("debug2", kvpairs, i)); + printf("\n"); + + printf(" Testing hex2ccolor() and hex2dcolor() with fg (\"%s\"):\n", qs_k2v("fg", kvpairs, i)); + j = hex2ccolor(qs_k2v("fg", kvpairs, i), &r, &g, &b, &a); + printf(" hex2ccolor() should have decoded 8 chars, r/g/b/a should be 250/152/191/68 : %d chars decoded, r/g/b/a is %d/%d/%d/%d\n", j, r, g, b, a); + j = hex2dcolor(qs_k2v("fg", kvpairs, i), &dr, &dg, &db, &da); + printf(" hex2dcolor() should have decoded 8 chars, r/g/b/a should be 0.98/0.60/0.75/0.27 : %d chars decoded, r/g/b/a is %.2f/%.2f/%.2f/%.2f\n", j, dr, dg, db, da); + + printf(" Testing hex2ccolor() and hex2dcolor() with bg (\"%s\"):\n", qs_k2v("bg", kvpairs, i)); + j = hex2ccolor(qs_k2v("bg", kvpairs, i), &r, &g, &b, &a); + printf(" hex2ccolor() should have decoded 3 chars, r/g/b should be 0/204/0 : %d chars decoded, r/g/b is %d/%d/%d\n", j, r, g, b); + j = hex2dcolor(qs_k2v("bg", kvpairs, i), &dr, &dg, &db, &da); + printf(" hex2dcolor() should have decoded 3 chars, r/g/b should be 0.00/0.80/0.00 : %d chars decoded, r/g/b is %.2f/%.2f/%.2f\n", j, dr, dg, db); + + printf(" Testing hex2ccolor() and hex2dcolor() with color (\"%s\"):\n", qs_k2v("color", kvpairs, i)); + j = hex2ccolor(qs_k2v("color", kvpairs, i), &r, &g, &b, &a); + printf(" hex2ccolor() should have decoded 0 chars : %d chars decoded\n", j); + j = hex2dcolor(qs_k2v("color", kvpairs, i), &dr, &dg, &db, &da); + printf(" hex2dcolor() should have decoded 0 chars : %d chars decoded\n", j); + +/* + print + + if ( qs_scanvalue("color", getstring, value, sizeof(value)) != NULL ) + { + printf("Key %s is set, and the value is: \"%s\"\n", "color", value); + if ( hex2ccolor(value, &r, &g, &b, &a) != 0 && hex2dcolor(value, &dr, &dg, &db, &da) != 0 ) + { + printf(" \"%s\" successfully decoded as uchar : r=%d, g=%d, b=%d, a=%d\n", "color", r, g, b, a); + printf(" \"%s\" successfully decoded as double : r=%.2f, g=%.2f, b=%.2f, a=%.2f\n", "color", dr, dg, db, da); + } + else + printf(" \"%s\" NOT successfully decoded\n", "color"); + } +*/ + return 0; +}