mirror of
https://github.com/rkd77/elinks.git
synced 2024-10-27 08:00:32 -04:00
[qs_parse] Added qs_parse code from https://github.com/bartgrantham/qs_parse
This commit is contained in:
parent
ae6bfdd4dd
commit
edddb70200
@ -3,6 +3,8 @@ include $(top_builddir)/Makefile.config
|
|||||||
|
|
||||||
INCLUDES += $(GNUTLS_CFLAGS) $(OPENSSL_CFLAGS)
|
INCLUDES += $(GNUTLS_CFLAGS) $(OPENSSL_CFLAGS)
|
||||||
|
|
||||||
|
SUBDIRS = qs_parse
|
||||||
|
|
||||||
OBJS-unless$(CONFIG_SMALL) += fastfind.o
|
OBJS-unless$(CONFIG_SMALL) += fastfind.o
|
||||||
OBJS-$(CONFIG_CSS) += scanner.o
|
OBJS-$(CONFIG_CSS) += scanner.o
|
||||||
OBJS-$(CONFIG_DEBUG) += memdebug.o
|
OBJS-$(CONFIG_DEBUG) += memdebug.o
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#INCLUDES += $(GNUTLS_CFLAGS) $(OPENSSL_CFLAGS)
|
subdir('qs_parse')
|
||||||
|
|
||||||
if not conf_data.get('CONFIG_SMALL')
|
if not conf_data.get('CONFIG_SMALL')
|
||||||
srcs += files('fastfind.c')
|
srcs += files('fastfind.c')
|
||||||
|
19
src/util/qs_parse/LICENSE
Normal file
19
src/util/qs_parse/LICENSE
Normal file
@ -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.
|
6
src/util/qs_parse/Makefile
Normal file
6
src/util/qs_parse/Makefile
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
top_builddir=../../..
|
||||||
|
include $(top_builddir)/Makefile.config
|
||||||
|
|
||||||
|
OBJS = qs_parse.o
|
||||||
|
|
||||||
|
include $(top_srcdir)/Makefile.lib
|
66
src/util/qs_parse/README.md
Normal file
66
src/util/qs_parse/README.md
Normal file
@ -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 <http://www.opensource.org/licenses/mit-license.php>
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
<bart@bartgrantham.com>
|
||||||
|
|
||||||
|
|
||||||
|
Enjoy!
|
||||||
|
|
||||||
|
-Bart
|
1
src/util/qs_parse/meson.build
Normal file
1
src/util/qs_parse/meson.build
Normal file
@ -0,0 +1 @@
|
|||||||
|
srcs += files('qs_parse.c')
|
106
src/util/qs_parse/qs_example.c
Normal file
106
src/util/qs_parse/qs_example.c
Normal file
@ -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 <stdio.h>
|
||||||
|
#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;
|
||||||
|
}
|
272
src/util/qs_parse/qs_parse.c
Normal file
272
src/util/qs_parse/qs_parse.c
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
#include "qs_parse.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// TODO: implement sorting of the qs_kv array; for now ensure it's not compiled
|
||||||
|
#undef _qsSORTING
|
||||||
|
|
||||||
|
// isxdigit _is_ available in <ctype.h>, 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<qs_kv_size; i++) qs_kv[i] = NULL;
|
||||||
|
|
||||||
|
// find the beginning of the k/v substrings
|
||||||
|
if ( (substr_ptr = strchr(qs, '?')) != NULL )
|
||||||
|
substr_ptr++;
|
||||||
|
else
|
||||||
|
substr_ptr = qs;
|
||||||
|
|
||||||
|
i=0;
|
||||||
|
while(i<qs_kv_size)
|
||||||
|
{
|
||||||
|
qs_kv[i] = substr_ptr;
|
||||||
|
j = strcspn(substr_ptr, "&");
|
||||||
|
if ( substr_ptr[j] == '\0' ) { break; }
|
||||||
|
substr_ptr += j + 1;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
i++; // x &'s -> 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<i; j++)
|
||||||
|
{
|
||||||
|
substr_ptr = qs_kv[j] + strcspn(qs_kv[j], "=&#");
|
||||||
|
if ( substr_ptr[0] == '&' ) // blank value: skip decoding
|
||||||
|
substr_ptr[0] = '\0';
|
||||||
|
else
|
||||||
|
qs_decode(++substr_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _qsSORTING
|
||||||
|
// TODO: qsort qs_kv, using qs_strncmp() for the comparison
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qs_decode(char * qs)
|
||||||
|
{
|
||||||
|
int i=0, j=0;
|
||||||
|
|
||||||
|
while( ISQSCHR(qs[j]) )
|
||||||
|
{
|
||||||
|
if ( qs[j] == '+' ) { qs[i] = ' '; }
|
||||||
|
else if ( qs[j] == '%' ) // easier/safer than scanf
|
||||||
|
{
|
||||||
|
if ( ! ISHEX(qs[j+1]) || ! ISHEX(qs[j+2]) )
|
||||||
|
{
|
||||||
|
qs[i] = '\0';
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
qs[i] = (HEX2DEC(qs[j+1]) * 16) + HEX2DEC(qs[j+2]);
|
||||||
|
j+=2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qs[i] = qs[j];
|
||||||
|
}
|
||||||
|
i++; j++;
|
||||||
|
}
|
||||||
|
qs[i] = '\0';
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char * qs_k2v(const char * key, char * qs_kv[], int qs_kv_size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
size_t key_len, skip;
|
||||||
|
|
||||||
|
key_len = strlen(key);
|
||||||
|
|
||||||
|
#ifdef _qsSORTING
|
||||||
|
// TODO: binary search for key in the sorted qs_kv
|
||||||
|
#else // _qsSORTING
|
||||||
|
for(i=0; i<qs_kv_size; i++)
|
||||||
|
{
|
||||||
|
// we rely on the unambiguous '=' to find the value in our k/v pair
|
||||||
|
if ( qs_strncmp(key, qs_kv[i], key_len) == 0 )
|
||||||
|
{
|
||||||
|
skip = strcspn(qs_kv[i], "=");
|
||||||
|
if ( qs_kv[i][skip] == '=' )
|
||||||
|
skip++;
|
||||||
|
// return (zero-char value) ? ptr to trailing '\0' : ptr to value
|
||||||
|
return qs_kv[i] + skip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // _qsSORTING
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len)
|
||||||
|
{
|
||||||
|
int i, key_len;
|
||||||
|
char * tmp;
|
||||||
|
|
||||||
|
// find the beginning of the k/v substrings
|
||||||
|
if ( (tmp = strchr(qs, '?')) != NULL )
|
||||||
|
qs = tmp + 1;
|
||||||
|
|
||||||
|
key_len = strlen(key);
|
||||||
|
while(qs[0] != '#' && qs[0] != '\0')
|
||||||
|
{
|
||||||
|
if ( qs_strncmp(key, qs, key_len) == 0 )
|
||||||
|
break;
|
||||||
|
qs += strcspn(qs, "&") + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( qs[0] == '\0' ) return NULL;
|
||||||
|
|
||||||
|
qs += strcspn(qs, "=&#");
|
||||||
|
if ( qs[0] == '=' )
|
||||||
|
{
|
||||||
|
qs++;
|
||||||
|
i = strcspn(qs, "&=#");
|
||||||
|
strncpy(val, qs, (val_len-1)<(i+1) ? (val_len-1) : (i+1));
|
||||||
|
qs_decode(val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( val_len > 0 )
|
||||||
|
val[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hex2dcolor(char * color, double * r, double * g, double * b, double * a)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if ( color == NULL ) return 0;
|
||||||
|
|
||||||
|
i = strlen(color);
|
||||||
|
if ( i != 8 && i != 6 && i != 4 && i != 3 ) return 0;
|
||||||
|
for(j=0; j<i; j++) if ( ! ISHEX(color[j]) ) return 0;
|
||||||
|
switch(i)
|
||||||
|
{
|
||||||
|
// (H*16+H)/255 == H*17/255 == H/15
|
||||||
|
case 3:
|
||||||
|
*r = HEX2DEC(color[0]) / 15.0;
|
||||||
|
*g = HEX2DEC(color[1]) / 15.0;
|
||||||
|
*b = HEX2DEC(color[2]) / 15.0;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*r = HEX2DEC(color[0]) / 15.0;
|
||||||
|
*g = HEX2DEC(color[1]) / 15.0;
|
||||||
|
*b = HEX2DEC(color[2]) / 15.0;
|
||||||
|
*a = HEX2DEC(color[3]) / 15.0;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
*r = ((HEX2DEC(color[0]) * 16) + HEX2DEC(color[1])) / 255.0;
|
||||||
|
*g = ((HEX2DEC(color[2]) * 16) + HEX2DEC(color[3])) / 255.0;
|
||||||
|
*b = ((HEX2DEC(color[4]) * 16) + HEX2DEC(color[5])) / 255.0;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
*r = ((HEX2DEC(color[0]) * 16) + HEX2DEC(color[1])) / 255.0;
|
||||||
|
*g = ((HEX2DEC(color[2]) * 16) + HEX2DEC(color[3])) / 255.0;
|
||||||
|
*b = ((HEX2DEC(color[4]) * 16) + HEX2DEC(color[5])) / 255.0;
|
||||||
|
*a = ((HEX2DEC(color[6]) * 16) + HEX2DEC(color[7])) / 255.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hex2ccolor(char * color, unsigned char * r, unsigned char * g, unsigned char * b, unsigned char * a)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if ( color == NULL ) return 0;
|
||||||
|
|
||||||
|
i = strlen(color);
|
||||||
|
if ( i != 8 && i != 6 && i != 4 && i != 3 ) return 0;
|
||||||
|
for(j=0; j<i; j++) if ( ! ISHEX(color[j]) ) return 0;
|
||||||
|
switch(i)
|
||||||
|
{
|
||||||
|
// (H*16+H) == H*17
|
||||||
|
case 3:
|
||||||
|
*r = HEX2DEC(color[0]) * 17;
|
||||||
|
*g = HEX2DEC(color[1]) * 17;
|
||||||
|
*b = HEX2DEC(color[2]) * 17;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*r = HEX2DEC(color[0]) * 17;
|
||||||
|
*g = HEX2DEC(color[1]) * 17;
|
||||||
|
*b = HEX2DEC(color[2]) * 17;
|
||||||
|
*a = HEX2DEC(color[3]) * 17;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
*r = (HEX2DEC(color[0]) * 16) + HEX2DEC(color[1]);
|
||||||
|
*g = (HEX2DEC(color[2]) * 16) + HEX2DEC(color[3]);
|
||||||
|
*b = (HEX2DEC(color[4]) * 16) + HEX2DEC(color[5]);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
*r = (HEX2DEC(color[0]) * 16) + HEX2DEC(color[1]);
|
||||||
|
*g = (HEX2DEC(color[2]) * 16) + HEX2DEC(color[3]);
|
||||||
|
*b = (HEX2DEC(color[4]) * 16) + HEX2DEC(color[5]);
|
||||||
|
*a = (HEX2DEC(color[6]) * 16) + HEX2DEC(color[7]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
54
src/util/qs_parse/qs_parse.h
Normal file
54
src/util/qs_parse/qs_parse.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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_
|
138
src/util/qs_parse/qs_test.c
Normal file
138
src/util/qs_parse/qs_test.c
Normal file
@ -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 <stdio.h>
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user