Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

new long format options parsing and auto-generated --help docs

  • Loading branch information...
commit 75c54e697605a7d224ec0a6a499f750d32d75fff 1 parent b16abb9
@jehiah jehiah authored
View
77 jujufly/jujufly.c
@@ -78,13 +78,13 @@ typedef struct juju_db {
TAILQ_ENTRY(juju_db) entries;
} juju_db;
-static size_t db_size = DB_SIZE;
-static char *db_name = "db";
-static int ndatabases = 100;
+size_t db_size = DB_SIZE;
+char *db_file = "db";
+int ndatabases = 100;
-static int fieldc;
-static char **fieldv;
-static int *field_indexed;
+int fieldc;
+char **fieldv;
+int *field_indexed;
Pvoid_t field_array = (PWord_t)NULL;
TAILQ_HEAD(db_list, juju_db) dbs;
@@ -336,7 +336,7 @@ void roll_dbs()
jjdb->filename, strerror(errno));
exit(1);
} else {
- sprintf(buf, "%s.%03d", db_name, i+1);
+ sprintf(buf, "%s.%03d", db_file, i+1);
rename(jjdb->filename, buf);
free(jjdb->filename);
jjdb->filename = strdup(buf);
@@ -354,7 +354,7 @@ void open_all_dbs()
char buf[1024];
int i;
- sprintf(buf, "%s.[0-9][0-9][0-9]", db_name);
+ sprintf(buf, "%s.[0-9][0-9][0-9]", db_file);
fprintf(stderr, "looking for: %s\n", buf);
glob(buf, 0, NULL, &g);
for (i=0; i < GLOBC(g) && i < ndatabases; i++) {
@@ -386,7 +386,7 @@ void put_cb(struct evhttp_request *req, struct evbuffer *evb,void *ctx)
while (append_record(jjdb, s) == false) {
roll_dbs();
jjdb = calloc(1, sizeof(*jjdb));
- asprintf(&jjdb->filename, "%s.000", db_name);
+ asprintf(&jjdb->filename, "%s.000", db_file);
open_db(jjdb);
TAILQ_INSERT_HEAD(&dbs, jjdb, entries);
}
@@ -686,56 +686,30 @@ void dbstats_cb(struct evhttp_request *req, struct evbuffer *evb,void *ctx)
evhttp_send_reply(req, HTTP_OK, "OK", evb);
}
-void info()
-{
- fprintf(stdout, "%s: time series server with indices.\n", NAME);
- fprintf(stdout, "Version %s, "
- "https://github.com/bitly/simplehttp/tree/master/jujufly\n",
- VERSION);
-}
-void usage()
-{
- fprintf(stderr, "Provides search access to time based streams\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "usage: jujufly\n");
- fprintf(stderr, "\t-f /path/to/dbfile\n");
- fprintf(stderr, "\t-n field1,field2,field3 (field names)\n");
- fprintf(stderr, "\t-i field2,field3 (index by field name)\n");
- fprintf(stderr, "\t-a 127.0.0.1 (address to listen on)\n");
- fprintf(stderr, "\t-p 8080 (port to listen on)\n");
- fprintf(stderr, "\t-D (daemonize)\n");
- fprintf(stderr, "\n");
- exit(1);
+int version_cb(int value) {
+ fprintf(stdout, "Version: %s\n", VERSION);
+ return 0;
}
int main(int argc, char **argv)
{
- int i, j, ch, indexc=0;
+ int i, j, indexc=0;
Word_t *val;
char **indexv;
- opterr = 0;
- while ((ch = getopt(argc, argv, "f:i:n:h")) != -1) {
- if (ch == '?') {
- optind--;
- break;
- }
- switch (ch) {
- case 'f':
- db_name = strdup(optarg);
- break;
- case 'n':
- fieldv = split_keys(optarg, &fieldc, ',');
- break;
- case 'i':
- indexv = split_keys(optarg, &indexc, ',');
- break;
- case 'h':
- usage();
- exit(1);
- }
+ define_simplehttp_options();
+ option_define_str("db_file", OPT_REQUIRED, "db", &db_file, NULL, NULL);
+ option_define_str("field_names", OPT_REQUIRED, NULL, NULL, NULL, "field1,field2,field3 (field names)");
+ option_define_str("field_index", OPT_REQUIRED, NULL, NULL, NULL, "field2,field3 (index by field name)");
+ option_define_bool("version", OPT_OPTIONAL, 0, NULL, version_cb, VERSION);
+
+ if (!option_parse_command_line(argc, argv)){
+ return 1;
}
+
+ fieldv = split_keys(option_get_str("field_names"), &fieldc, ',');
+ indexv = split_keys(option_get_str("field_index"), &indexc, ',');
field_indexed = calloc(fieldc+1, sizeof(int));
for (i=0; i < indexc; i++) {
@@ -755,6 +729,7 @@ int main(int argc, char **argv)
simplehttp_set_cb("/search*", search_cb, NULL);
simplehttp_set_cb("/printidx*", printidx_cb, NULL);
simplehttp_set_cb("/dbstats*", dbstats_cb, NULL);
- simplehttp_main(argc, argv);
+ simplehttp_main();
+ free_options();
return 0;
}
View
2  ps_to_file/Makefile
@@ -5,7 +5,7 @@ LIBSIMPLEHTTP_INC ?= $(LIBSIMPLEHTTP)/..
LIBSIMPLEHTTP_LIB ?= $(LIBSIMPLEHTTP)
CFLAGS = -I. -I$(LIBSIMPLEHTTP_INC) -I$(LIBEVENT)/include -g
-LIBS = -L. -L$(LIBSIMPLEHTTP_LIB) -L$(LIBEVENT)/lib -levent -lpubsubclient
+LIBS = -L. -L$(LIBSIMPLEHTTP_LIB) -L$(LIBEVENT)/lib -levent -lpubsubclient -lsimplehttp -lm
all: ps_to_file
View
49 ps_to_file/ps_to_file.c
@@ -8,6 +8,7 @@
#include <simplehttp/simplehttp.h>
#define DEBUG 0
+#define VERSION "1.1"
struct output_metadata {
char *filename_format;
@@ -43,44 +44,26 @@ process_message_cb(char *source, void *cbarg){
fprintf(data->output_file,"%s\n",source);
}
-void usage(){
- fprintf(stderr, "You must specify -s SOURCE_PORT -f /path/to/output_%%Y_%%m_%%d_%%H.csv\n");
- fprintf(stderr, "or -s HOST:PORT\n");
+int version_cb(int value) {
+ fprintf(stdout, "Version: %s\n", VERSION);
+ return 0;
}
int
main(int argc, char **argv)
{
- int source_port;
- source_port = 0;
- char source_address[20];
+ char *source_address = "127.0.0.1";
+ int source_port = 80;
char *filename_format = NULL;
- char *ptr;
- int ch;
-
- while ((ch = getopt(argc, argv, "s:f:h")) != -1) {
- switch (ch) {
- case 's':
- ptr = strchr(optarg,':');
- if (ptr != NULL && (ptr - optarg) < strlen(optarg)){
- sscanf(optarg, "%[^:]:%d",&source_address, &source_port);
- }else{
- source_port = atoi(optarg);
- strcpy(source_address,"127.0.0.1");
- }
- break;
- case 'f':
- filename_format = optarg;
- fprintf(stdout,"format is %s\n",filename_format);
- break;
- case 'h':
- usage();
- exit(1);
- }
- }
- if (!source_port || !filename_format){
- usage();
- exit(1);
+
+ define_simplehttp_options();
+ option_define_bool("version", OPT_OPTIONAL, 0, NULL, version_cb, VERSION);
+ option_define_str("source_host", OPT_OPTIONAL, "127.0.0.1", &source_address, NULL, NULL);
+ option_define_int("source_port", OPT_OPTIONAL, 80, &source_port, NULL, NULL);
+ option_define_str("filename_format", OPT_REQUIRED, NULL, &filename_format, NULL, "/var/log/pubsub.%%Y-%%m-%%d_%%H.log");
+
+ if (!option_parse_command_line(argc, argv)){
+ return 1;
}
struct output_metadata *data;
@@ -89,7 +72,7 @@ main(int argc, char **argv)
data->current_filename[0] = '\0';
data->temp_filename[0] = '\0';
data->output_file = NULL;
-
+
return pubsub_to_pubsub_main(source_address, source_port, process_message_cb, data);
}
View
16 pubsub/README.md
@@ -5,11 +5,19 @@ pubsub (short for publish/subscribe) is a server that brokers new messages
to all connected subscribers at the time a message is received.
http://en.wikipedia.org/wiki/Publish/subscribe
-Cmdline usage:
+Commandline options:
- -a 0.0.0.0 (address to bind to)
- -p 8080 (port to bind to)
- -D daemonize (default off)
+ --address=<str> address to listen on
+ default: 0.0.0.0
+ --daemon daemonize process
+ --enable-logging request logging
+ --group=<str> run as this group
+ --help list usage
+ --port=<int> port to listen on
+ default: 8080
+ --root=<str> chdir and run from this directory
+ --user=<str> run as this user
+ --version
API endpoints:
View
17 pubsub/pubsub.c
@@ -8,6 +8,7 @@
#define BOUNDARY "xXPubSubXx"
#define MAX_PENDING_DATA 1024*1024*50
+#define VERSION "1.1"
int ps_debug = 0;
@@ -288,16 +289,30 @@ void sub_cb(struct evhttp_request *req, struct evbuffer *evb, void *ctx)
evhttp_clear_headers(&args);
}
+int version_cb(int value) {
+ fprintf(stdout, "Version: %s\n", VERSION);
+ return 0;
+}
+
int
main(int argc, char **argv)
{
+
+ define_simplehttp_options();
+ option_define_bool("version", OPT_OPTIONAL, 0, NULL, version_cb, VERSION);
+
+ if (!option_parse_command_line(argc, argv)){
+ return 1;
+ }
+
TAILQ_INIT(&clients);
simplehttp_init();
simplehttp_set_cb("/pub*", pub_cb, NULL);
simplehttp_set_cb("/sub*", sub_cb, NULL);
simplehttp_set_cb("/stats*", stats_cb, NULL);
simplehttp_set_cb("/clients", clients_cb, NULL);
- simplehttp_main(argc, argv);
+ simplehttp_main();
+ free_options();
return 0;
}
View
139 pubsub_filtered/pubsub_filtered.c
@@ -14,7 +14,7 @@
#define DEBUG 1
#define SUCCESS 0
#define FAILURE 1
-#define LOCALHOST "127.0.0.1"
+#define VERSION "1.1"
#define RECONNECT_SECS 5
#define ADDR_BUFSZ 256
#define BOUNDARY "xXPubSubXx"
@@ -62,9 +62,8 @@ int connect_to_source();
char* md5_hash(const char *string);
void process_message_cb(struct evhttp_request *req, void *arg);
-void parse_address_arg(char *optarg, char *addr, int *port);
-void parse_encrypted_fields(char *str);
-void parse_blacklisted_fields(char *str);
+int parse_encrypted_fields(char *str);
+int parse_blacklisted_fields(char *str);
int parse_fields(char *str, char **field_array);
int can_kick(struct cli *client);
@@ -82,49 +81,29 @@ uint64_t msgRecv = 0;
uint64_t msgSent = 0;
uint64_t number_reconnects = 0;
-static char *version = "1.1";
-static char *g_progname = "pubsub_filtered";
+char *version = "1.1";
+char *g_progname = "pubsub_filtered";
struct event reconnect_ev;
struct timeval reconnect_tv = {RECONNECT_SECS,0};
struct evhttp_connection *evhttp_source_connection = NULL;
struct evhttp_request *evhttp_source_request = NULL;
-static char *source_path = "/sub?multipart=0";
-static char source_address[ADDR_BUFSZ];
-static int source_port = 0;
+char *source_path = "/sub?multipart=0";
+char *source_address = "127.0.0.1";
+int source_port = 80;
-static char *encrypted_fields[64];
-static int num_encrypted_fields = 0;
-static char *blacklisted_fields[64];
-static char expected_key[1024];
-static char expected_value[1024];
-static int expect_value=0;
-static int num_blacklisted_fields = 0;
+char *encrypted_fields[64];
+int num_encrypted_fields = 0;
+char *blacklisted_fields[64];
+char *expected_key = NULL;
+char *expected_value = NULL;
+int expect_value=0;
+int num_blacklisted_fields = 0;
struct global_data *data = NULL;
-/*
- * Convenience function to parse address and port info
- * out of command line args.
- *
- */
-void parse_address_arg(char *optarg, char *addr, int *port)
-{
- char *ptr;
- char tmp_addr[ADDR_BUFSZ];
-
- ptr = strchr(optarg,':');
- if (ptr != NULL && (ptr - optarg) < strlen(optarg)) {
- sscanf(optarg, "%[^:]:%d", (char *)&tmp_addr, port);
- strcpy(addr, tmp_addr);
- } else {
- strcpy(addr, LOCALHOST);
- *port = atoi(optarg);
- }
- return;
-}
/*
* Parse a comma-delimited string and populate
@@ -132,7 +111,7 @@ void parse_address_arg(char *optarg, char *addr, int *port)
*
* See parse_fields().
*/
-void parse_blacklisted_fields(char *str)
+int parse_blacklisted_fields(char *str)
{
int i;
@@ -142,7 +121,7 @@ void parse_blacklisted_fields(char *str)
fprintf(stdout, "Blacklist field: \"%s\"\n", blacklisted_fields[i]);
}
- return;
+ return 1;
}
@@ -152,7 +131,7 @@ void parse_blacklisted_fields(char *str)
*
* See parse_fields().
*/
-void parse_encrypted_fields(char *str)
+int parse_encrypted_fields(char *str)
{
int i;
num_encrypted_fields = parse_fields(str, encrypted_fields);
@@ -161,7 +140,7 @@ void parse_encrypted_fields(char *str)
fprintf(stdout, "Encrypted field: \"%s\"\n", encrypted_fields[i]);
}
- return;
+ return 1;
}
/*
@@ -651,72 +630,29 @@ int connect_to_source()
return SUCCESS;
}
-
-void print_version()
-{
- fprintf(stdout, "%s v%s\n", g_progname, version);
-}
-
-void usage()
-{
- fprintf(stderr, "%s: expose a filtered pubsub stream by connecting to -s\n", g_progname);
- fprintf(stderr, "and applying -e -b and -x operations before sending to clients\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "usage:\n");
- fprintf(stderr, "\t-s source_pubsub_address:port\n");
- fprintf(stderr, "\t-b comma separated list of keys to blacklist\n");
- fprintf(stderr, "\t-e comma separated list of keys for values to be encrypted\n");
- fprintf(stderr, "\t-x key=value (require a key=value field in the message body)\n");
- fprintf(stderr, "\t-v print version\n");
- fprintf(stderr, "\t-h print help\n");
- fprintf(stderr, "\t---------------\n");
- fprintf(stderr, "\tpubsub server options. note: these must appear after filter options\n");
- fprintf(stderr, "\t---------------\n");
- fprintf(stderr, "\t-a 0.0.0.0 (address to bind to)\n");
- fprintf(stderr, "\t-p 8080 (port to bind to)\n");
- fprintf(stderr, "\n");
+int version_cb(int value) {
+ fprintf(stdout, "Version: %s\n", VERSION);
+ return 0;
}
-
int
main(int argc, char **argv)
{
- int ch;
- char *ptr;
- opterr=0;
- while ((ch = getopt(argc, argv, "vs:b:e:x:h")) != -1) {
- if (ch == '?') {
- optind--; // re-set for next getopt() parse
- break;
- }
- switch (ch) {
- case 'v':
- print_version();
- exit(0);
- case 's':
- parse_address_arg(optarg, source_address, &source_port);
- break;
- case 'b':
- // blacklist output fields
- parse_blacklisted_fields(optarg);
- break;
- case 'e':
- // encrypt output fields
- parse_encrypted_fields(optarg);
- break;
- case 'x':
- // expected key=value
- sscanf(optarg, "%[^=]=%s", (char *)&expected_key, (char *)&expected_value);
- fprintf(stdout, "expecting %s=\"%s\" in messages\n", expected_key, expected_value);
- expect_value=1;
- break;
- case 'h':
- usage();
- exit(0);
- }
+
+ define_simplehttp_options();
+ option_define_bool("version", OPT_OPTIONAL, 0, NULL, version_cb, VERSION);
+ option_define_str("source_host", OPT_OPTIONAL, "127.0.0.1", &source_address, NULL, NULL);
+ option_define_int("source_port", OPT_OPTIONAL, 80, &source_port, NULL, NULL);
+ option_define_str("blacklist_fields", OPT_OPTIONAL, NULL, NULL, parse_blacklisted_fields, "comma separated list of fields to remove");
+ option_define_str("encrypted_fields", OPT_OPTIONAL, NULL, NULL, parse_encrypted_fields, "comma separated list of fields to encrypt");
+ option_define_str("expected_key", OPT_OPTIONAL, NULL, &expected_key, NULL, "key to expect in messages before echoing to clients");
+ option_define_str("expected_value", OPT_OPTIONAL, NULL, &expected_value, NULL, "value to expect in --expected-key field in messages before echoing to clients");
+
+ if (!option_parse_command_line(argc, argv)){
+ return 1;
}
- if (!source_port){
- usage();
+ if ((expected_value && !expected_key) || (expected_key && !expected_value)) {
+ fprintf(stderr, "--expected-key and --expected-value must be used together\n");
exit(1);
}
@@ -730,7 +666,8 @@ main(int argc, char **argv)
exit(1);
}
- simplehttp_main(argc, argv);
+ simplehttp_main();
+ free_options();
return 0;
}
View
10 qrencode/qrencode.c
@@ -185,17 +185,23 @@ main(int argc, char **argv)
char *outfile = "/tmp/qrencode.png";
+ define_simplehttp_options();
+ option_define_str("temp_file", OPT_OPTIONAL, "/tmp/qrencode.png", &outfile, NULL, NULL);
+ if (!option_parse_command_line(argc, argv)){
+ return 1;
+ }
+
fp = fopen(outfile, "a+");
if(fp == NULL) {
fprintf(stderr, "Failed to create file: %s\n", outfile);
perror(NULL);
exit(EXIT_FAILURE);
}
- //unlink(outfile);
simplehttp_init();
simplehttp_set_cb("/qr*", cb, NULL);
- simplehttp_main(argc, argv);
+ simplehttp_main();
+ free_options();
fclose(fp);
return 0;
View
39 simpleattributes/simpleattributes.c
@@ -23,11 +23,10 @@ void get_cb(struct evhttp_request *req, struct evbuffer *evb, void *ctx);
struct event ev;
struct timeval tv = {RECONNECT,0};
-static char *db_host = "0.0.0.0";
-static int db_port = 1978;
-static TCRDB *rdb;
-static int db_status;
-static char *g_progname;
+char *db_host = "127.0.0.1";
+int db_port = 1978;
+TCRDB *rdb;
+int db_status;
void finalize_json(struct evhttp_request *req, struct evbuffer *evb,
@@ -291,32 +290,15 @@ void get_cb(struct evhttp_request *req, struct evbuffer *evb, void *ctx)
finalize_json(req, evb, &args, jsobj);
}
-void usage()
-{
- fprintf(stderr, "%s: http wrapper for Tokyo Tyrant\n", g_progname);
- fprintf(stderr, "\n");
- fprintf(stderr, "usage:\n");
- fprintf(stderr, " %s [-tchost 0.0.0.0] [-tcport 1978]\n", g_progname);
- fprintf(stderr, "\n");
- exit(1);
-}
int
main(int argc, char **argv)
{
- int i;
-
- g_progname = argv[0];
- for (i=1; i < argc; i++) {
- if(!strcmp(argv[i], "-tchost")) {
- if(++i >= argc) usage();
- db_host = argv[i];
- } else if(!strcmp(argv[i], "-tcport")) {
- if(++i >= argc) usage();
- db_port = tcatoi(argv[i]);
- } else if (!strcmp(argv[i], "-help")) {
- usage();
- }
+ define_simplehttp_options();
+ option_define_str("ttserver_host", OPT_OPTIONAL, "127.0.0.1", &db_host, NULL, NULL);
+ option_define_int("ttserver_port", OPT_OPTIONAL, 1978, &db_port, NULL, NULL);
+ if (!option_parse_command_line(argc, argv)){
+ return 1;
}
memset(&db_status, -1, sizeof(db_status));
@@ -326,7 +308,8 @@ main(int argc, char **argv)
simplehttp_set_cb("/put*", put_cb, NULL);
simplehttp_set_cb("/del*", del_cb, NULL);
simplehttp_set_cb("/idx*", idx_cb, NULL);
- simplehttp_main(argc, argv);
+ simplehttp_main();
+ free_options();
return 0;
}
View
47 simplegeo/simplegeo.c
@@ -28,16 +28,16 @@ static int CmpElem(const void *e1, const void *e2);
struct event ev;
struct timeval tv = {RECONNECT,0};
-static char *db_host = "0.0.0.0";
-static int db_port = 1978;
-static TCRDB *rdb;
-static int db_status;
-static char *g_progname;
+char *db_host = "127.0.0.1";
+int db_port = 1978;
+TCRDB *rdb;
+int db_status;
+char *g_progname;
-static double pi;
-static double longDistance[181];
-static double latDistance = 69.169144;
-static double radius = 3958.75587;
+double pi;
+double longDistance[181];
+double latDistance = 69.169144;
+double radius = 3958.75587;
typedef struct Geo_Result {
int id;
@@ -447,16 +447,6 @@ void search_cb(struct evhttp_request *req, struct evbuffer *evb, void *ctx)
finalize_json(req, evb, &args, jsobj);
}
-void usage()
-{
- fprintf(stderr, "%s: http wrapper for Tokyo Tyrant\n", g_progname);
- fprintf(stderr, "\n");
- fprintf(stderr, "usage:\n");
- fprintf(stderr, " %s [-tchost 0.0.0.0] [-tcport 1978]\n", g_progname);
- fprintf(stderr, "\n");
- exit(1);
-}
-
int
main(int argc, char **argv)
{
@@ -464,17 +454,11 @@ main(int argc, char **argv)
double magic, rlat, s, c;
int lat;
- g_progname = argv[0];
- for (i=1; i < argc; i++) {
- if(!strcmp(argv[i], "-tchost")) {
- if(++i >= argc) usage();
- db_host = argv[i];
- } else if(!strcmp(argv[i], "-tcport")) {
- if(++i >= argc) usage();
- db_port = tcatoi(argv[i]);
- } else if (!strcmp(argv[i], "-help")) {
- usage();
- }
+ define_simplehttp_options();
+ option_define_str("ttserver_host", OPT_OPTIONAL, "127.0.0.1", &db_host, NULL, NULL);
+ option_define_int("ttserver_port", OPT_OPTIONAL, 1978, &db_port, NULL, NULL);
+ if (!option_parse_command_line(argc, argv)){
+ return 1;
}
pi = atan(1.0)*4;
@@ -495,13 +479,14 @@ main(int argc, char **argv)
simplehttp_set_cb("/del*", del_cb, NULL);
simplehttp_set_cb("/distance*", distance_cb, NULL);
simplehttp_set_cb("/box*", box_cb, NULL);
- simplehttp_main(argc, argv);
+ simplehttp_main();
if (!tcrdbclose(rdb)) {
errCode = tcrdbecode(rdb);
fprintf(stderr, "close error: %s\n", tcrdberrmsg(errCode));
}
tcrdbdel(rdb);
+ free_options();
return 0;
}
View
10 simplehttp/Makefile
@@ -1,14 +1,14 @@
LIBEVENT ?= /usr/local
TARGET ?= /usr/local
-CFLAGS = -I. -I$(LIBEVENT)/include -Wall -g -O2
+CFLAGS = -I. -I$(LIBEVENT)/include -Wall -g
LIBS = -L. -L$(LIBEVENT)/lib -levent -lm
AR = ar
AR_FLAGS = rc
RANLIB = ranlib
-libsimplehttp.a: simplehttp.o async_simplehttp.o timer.o log.o util.o stat.o request.o
+libsimplehttp.a: simplehttp.o async_simplehttp.o timer.o log.o util.o stat.o request.o options.o
/bin/rm -f $@
$(AR) $(AR_FLAGS) $@ $^
$(RANLIB) $@
@@ -23,7 +23,13 @@ install:
/usr/bin/install -d $(TARGET)/include/simplehttp/
/usr/bin/install libsimplehttp.a $(TARGET)/lib/
/usr/bin/install simplehttp.h $(TARGET)/include/simplehttp/
+ /usr/bin/install simplehttp.h $(TARGET)/include/simplehttp/
/usr/bin/install queue.h $(TARGET)/include/simplehttp/
+ /usr/bin/install uthash.h $(TARGET)/include/simplehttp/
+ /usr/bin/install utlist.h $(TARGET)/include/simplehttp/
+ /usr/bin/install utstring.h $(TARGET)/include/simplehttp/
+ /usr/bin/install utarray.h $(TARGET)/include/simplehttp/
+ /usr/bin/install options.h $(TARGET)/include/simplehttp/
clean:
rm -rf *.a *.o testserver *.dSYM
View
416 simplehttp/options.c
@@ -0,0 +1,416 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h> // for basename()
+
+#include "options.h"
+#include "uthash.h"
+
+enum option_type {
+ OPT_BOOL = 1,
+ OPT_STR = 2,
+ OPT_INT = 3,
+ OPT_FLOAT = 4,
+ OPT_CHAR = 5,
+};
+
+struct Option {
+ char *option_name;
+ int option_type;
+ int required;
+ int found;
+ char *value_str;
+ int value_int;
+ char value_char;
+
+ int default_int;
+ char *default_str;
+ char default_char;
+ int *dest_int;
+ char **dest_str;
+ char *dest_char;
+ int(*cb_int)(int value);
+ int(*cb_str)(char *value);
+ int(*cb_char)(char value);
+
+ char *help;
+ UT_hash_handle hh;
+};
+
+struct Option *option_list = NULL;
+char *option_process_name = NULL;
+
+int format_option_name(char *option_name);
+int option_sort(struct Option *a, struct Option *b)
+{
+ return strcmp(a->option_name, b->option_name);
+}
+
+int help_cb(int value) {
+ option_help();
+ return 0;
+}
+
+/*
+handle the following option formats
+-p {value} -p={value} (for single character option_list)
+--port {value} --port={value} (for longer option_list)
+--debug (implicit true)
+--debug=true|false
+
+@return 1 when parsing was successful. 0 when not
+*/
+int option_parse_command_line(int argc, char **argv) {
+ int i;
+ char *option_str;
+ char *option_name;
+ size_t option_name_len;
+ char *value;
+ struct Option *option, *tmp_option;
+
+ // lazily define help option
+ HASH_FIND_STR(option_list, "help", option);
+ if (!option) {
+ option_define_bool("help", OPT_OPTIONAL, 0, NULL, help_cb, "list usage");
+ }
+
+ option_process_name=basename(argv[0]);
+ for (i=1; i < argc; i++) {
+ // fprintf(stdout, "DEBUG: option %d : %s\n", i, argv[i]);
+ option_str = argv[i];
+ // find the option_name
+ if (strncmp(option_str, "--", 2) != 0) {
+ fprintf(stderr, "ERROR: invalid argument \"%s\"\n", option_str);
+ return 0;
+ }
+ option_name = strchr(option_str, '-');
+ option_name++;
+ option_name = strchr(option_name, '-');
+ option_name++;
+ value = strchr(option_name, '=');
+ option_name_len = strlen(option_str) - (option_name - option_str);
+ if (value != NULL) {
+ option_name_len -= strlen(value);
+ *value = '\0';
+ value++;
+ }
+ if (format_option_name(option_name)) {
+ fprintf(stderr, "ERROR: unknown option \"--%s\"\n", option_name); // option_str ?
+ return 0;
+ }
+ HASH_FIND(hh, option_list, option_name, option_name_len, option);
+ if (!option) {
+ fprintf(stderr, "ERROR: unknown option \"--%s\"\n", option_name); // option_str ?
+ return 0;
+ }
+ if (option->option_type != OPT_BOOL && value == NULL) {
+ fprintf(stderr, "ERROR: missing argument for \"--%s\"", option_name);
+ return 0;
+ }
+
+ // TODO: strip quotes from value
+
+ switch(option->option_type) {
+ case OPT_CHAR:
+ if (strlen(value) != 1) {
+ fprintf(stderr, "ERROR: argument for --%s must be a single character (got %s)\n", option_name, value);
+ return 0;
+ }
+ option->value_char = value[0];
+ if (option->cb_char) {
+ if (!option->cb_char(option->value_char)) {
+ return 0;
+ }
+ }
+ if (option->dest_char) {
+ *(option->dest_char) = option->value_char;
+ }
+ break;
+ case OPT_STR:
+ option->value_str = value;
+ if (option->cb_str) {
+ if(!option->cb_str(value)){
+ return 0;
+ }
+ }
+ if (option->dest_str) {
+ *(option->dest_str) = strdup(value);
+ }
+ break;
+ case OPT_BOOL:
+ if (value == NULL) {
+ option->value_int = 1;
+ } else if (strcasecmp(value, "false") == 0) {
+ option->value_int = 0;
+ } else if (strcasecmp(value, "true") == 0) {
+ option->value_int = 1;
+ } else {
+ fprintf(stderr, "ERROR: unknown value for --%s (%s). should be \"true\" or \"false\"\n", option->option_name, value);
+ return 0;
+ }
+ if (option->cb_int) {
+ if(!option->cb_int(option->value_int)) {
+ return 0;
+ };
+ }
+ if (option->dest_int) {
+ *(option->dest_int) = option->value_int;
+ }
+ break;
+ case OPT_INT:
+ option->value_int = atoi(value);
+ if (option->cb_int) {
+ if(!option->cb_int(option->value_int)) {
+ return 0;
+ }
+ }
+ if (option->dest_int) {
+ *(option->dest_int) = option->value_int;
+ }
+ break;
+ }
+ option->found++;
+ }
+
+ // check for not found entries
+ HASH_ITER(hh, option_list, option, tmp_option) {
+ if (option->required == OPT_REQUIRED && option->found == 0) {
+ fprintf(stderr, "ERROR: required option --%s not present\n", option->option_name);
+ fprintf(stderr, " for a complete list of options use --help\n");
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+@returns -1 if option not found or not defined
+*/
+int option_get_int(const char *option_name) {
+ struct Option *option;
+ char *tmp_option_name = strdup(option_name);
+ if (format_option_name(tmp_option_name)) {
+ free(tmp_option_name);
+ return -1;
+ }
+ HASH_FIND_STR(option_list, tmp_option_name, option);
+ free(tmp_option_name);
+ if (!option) {
+ return -1;
+ }
+ if (option->option_type != OPT_INT && option->option_type != OPT_BOOL) {return -1;}
+ if (option->found) {
+ return option->value_int;
+ }
+ return option->default_int;
+}
+
+char *option_get_str(const char *option_name) {
+ struct Option *option;
+ char *tmp_option_name = strdup(option_name);
+ if (format_option_name(tmp_option_name)) {
+ free(tmp_option_name);
+ return NULL;
+ }
+ HASH_FIND_STR(option_list, tmp_option_name, option);
+ free(tmp_option_name);
+ if (!option) {return NULL;}
+ if (option->option_type != OPT_STR) {return NULL;}
+ if (option->found) {
+ return option->value_str;
+ }
+ return option->default_str;
+}
+
+char option_get_char(const char *option_name) {
+ struct Option *option;
+ char *tmp_option_name = strdup(option_name);
+ if (format_option_name(tmp_option_name)) {
+ free(tmp_option_name);
+ return '\0';
+ }
+ HASH_FIND_STR(option_list, tmp_option_name, option);
+ free(tmp_option_name);
+ if (!option) {return '\0';}
+ if (option->option_type != OPT_CHAR) {return '\0';}
+ if (option->found) {
+ return option->value_char;
+ }
+ return option->default_char;
+}
+
+struct Option *new_option(const char *option_name, int required, const char *help){
+ struct Option *option;
+ char *tmp_option_name = strdup(option_name);
+ if (format_option_name(tmp_option_name)) {
+ fprintf(stderr, "ERROR: option %s is invalid\n", option_name);
+ free(tmp_option_name);
+ return NULL;
+ }
+
+ HASH_FIND_STR(option_list, tmp_option_name, option);
+ if (option){
+ fprintf(stderr, "ERROR: option %s is already defined\n", tmp_option_name);
+ return NULL;
+ }
+ option = malloc(sizeof(struct Option));
+ option->option_name = tmp_option_name;
+ option->required = required;
+ option->found = 0;
+ option->value_str = NULL;
+ option->value_int = 0;
+ option->value_char = '\0';
+ option->cb_int = NULL;
+ option->default_int = 0;
+ option->dest_int = NULL;
+ option->cb_str = NULL;
+ option->default_str = NULL;
+ option->dest_str = NULL;
+ option->cb_char = NULL;
+ option->default_char = 0;
+ option->dest_char = NULL;
+ option->help = NULL;
+ if (help) {
+ option->help = strdup(help);
+ }
+ //fprintf(stdout, "adding option %s to option_list %p\n", option->option_name, option);
+ HASH_ADD_KEYPTR(hh, option_list, option->option_name, strlen(option->option_name), option);
+ return option;
+}
+
+int option_define_int(const char *option_name, int required, int default_val, int *dest, int(*cb)(int value), const char *help) {
+ struct Option *option = new_option(option_name, required, help);
+ if (!option) {return -1;}
+ option->option_type = OPT_INT;
+ option->default_int = default_val;
+ option->dest_int = dest;
+ option->cb_int = cb;
+ return 1;
+}
+
+int option_define_str(const char *option_name, int required, char *default_val, char **dest, int(*cb)(char *value), const char *help) {
+ struct Option *option = new_option(option_name, required, help);
+ if (!option) {return -1;}
+ option->option_type = OPT_STR;
+ if (default_val) {
+ option->default_str = strdup(default_val);
+ }
+ option->dest_str = dest;
+ option->cb_str = cb;
+ return 1;
+}
+
+int option_define_bool(const char *option_name, int required, int default_val, int *dest, int(*cb)(int value), const char *help) {
+ struct Option *option = new_option(option_name, required, help);
+ if (!option) {return -1;}
+ option->option_type = OPT_BOOL;
+ option->default_int = default_val;
+ option->dest_int = dest;
+ option->cb_int = cb;
+ return 1;
+}
+
+int option_define_char(const char *option_name, int required, char default_val, char *dest, int(*cb)(char value), const char *help) {
+ struct Option *option = new_option(option_name, required, help);
+ if (!option) {return -1;}
+ option->option_type = OPT_CHAR;
+ option->default_char = default_val;
+ option->dest_char = dest;
+ option->cb_char = cb;
+ return 1;
+}
+
+void option_help() {
+ struct Option *option, *tmp_option;
+ char buffer[1024] = {'\0'};
+
+ // lazily define help option
+ HASH_FIND_STR(option_list, "help", option);
+ if (!option) {
+ option_define_bool("help", OPT_OPTIONAL, 0, NULL, help_cb, "list usage");
+ }
+
+ fprintf(stdout, "\n");
+ fprintf(stdout, "%s accepts the following options, listed alphabetically.\n\n", option_process_name);
+ fprintf(stdout, "OPTIONS\n");
+
+ HASH_SORT(option_list, option_sort);
+ HASH_ITER(hh, option_list, option, tmp_option) {
+ switch(option->option_type) {
+ case OPT_STR:
+ sprintf(buffer, "--%s=<str>", option->option_name);
+ break;
+ case OPT_CHAR:
+ sprintf(buffer, "--%s=<char>", option->option_name);
+ break;
+ case OPT_INT:
+ sprintf(buffer, "--%s=<int>", option->option_name);
+ break;
+ case OPT_BOOL:
+ if (option->default_int != 0) {
+ sprintf(buffer, "--%s=True|False", option->option_name);
+ } else {
+ sprintf(buffer, "--%s", option->option_name);
+ }
+ break;
+ }
+ fprintf(stdout, " %-22s", buffer);
+ if (option->help) {
+ fprintf(stdout, " %s", option->help);
+ }
+ fprintf(stdout, "\n");
+ switch(option->option_type) {
+ case OPT_CHAR:
+ if (option->default_char) {
+ fprintf(stdout, "%25sdefault:%c\n", "", option->default_char);
+ }
+ break;
+ case OPT_STR:
+ if (option->default_str) {
+ if (isatty(fileno(stdout))) {
+ fprintf(stdout, "%25sdefault: %c[1m%s%c[0m\n", "", 27, option->default_str, 27);
+ } else {
+ fprintf(stdout, "%25sdefault: %s\n", "", option->default_str);
+ }
+ }
+ break;
+ case OPT_INT:
+ if (option->default_int) {
+ fprintf(stdout, "%25sdefault: %d\n", "", option->default_int);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ fprintf(stdout, "\n");
+}
+
+void free_options() {
+ struct Option *option, *tmp_option;
+ HASH_ITER(hh, option_list, option, tmp_option) {
+ HASH_DELETE(hh, option_list, option);
+ free(option->option_name);
+ free(option->help);
+ free(option->default_str);
+ free(option);
+ }
+}
+
+int format_option_name(char *option_name) {
+ char *ptr = option_name;
+ char *end = ptr + strlen(option_name);
+ while(ptr <= end && *ptr != '\0') {
+ if (*ptr >= 'A' && *ptr <= 'Z') {
+ *ptr += 32;
+ } else if (*ptr == '_') {
+ *ptr = '-';
+ } else if (*ptr < 48 && *ptr != 45){
+ fprintf(stderr, "invalid char %c\n", *ptr);
+ return 1;
+ }
+ ptr++;
+ }
+ return 0;
+}
View
22 simplehttp/options.h
@@ -0,0 +1,22 @@
+#ifndef _SIMPLEHTTP_OPTIONS_H
+#define _SIMPLEHTTP_OPTIONS_H
+
+enum required_option {
+ OPT_REQUIRED = 1,
+ OPT_OPTIONAL = 0
+};
+
+int option_parse_command_line(int argc, char **argv);
+int option_define_int(const char *option_name, int required, int default_val, int *dest, int(*cb)(int value), const char *help);
+int option_define_str(const char *option_name, int required, char *default_val, char **dest, int(*cb)(char *value), const char *help);
+int option_define_bool(const char *option_name, int required, int default_val, int *dest, int(*cb)(int value), const char *help);
+int option_define_char(const char *option_name, int required, char default_val, char *dest, int(*cb)(char value), const char *help);
+
+void option_help();
+int option_get_int(const char *option_name);
+char *option_get_str(const char *option_name);
+char option_get_char(const char *option_name);
+
+void free_options();
+
+#endif
View
4 simplehttp/request.c
@@ -8,7 +8,7 @@
#include "request.h"
#include "stat.h"
-extern int verbose;
+extern int simplehttp_logging;
struct simplehttp_request *simplehttp_request_new(struct evhttp_request *req, uint64_t id)
{
@@ -88,7 +88,7 @@ void simplehttp_request_finish(struct evhttp_request *req, struct simplehttp_req
simplehttp_stats_store(s_req->index, req_time);
}
- if (verbose) {
+ if (simplehttp_logging) {
sprintf(id_buf, "%"PRIu64, s_req->id);
simplehttp_log("", req, req_time, id_buf);
}
View
88 simplehttp/simplehttp.c
@@ -16,6 +16,7 @@
#include "simplehttp.h"
#include "stat.h"
#include "request.h"
+#include "options.h"
typedef struct cb_entry {
char *path;
@@ -25,11 +26,12 @@ typedef struct cb_entry {
} cb_entry;
TAILQ_HEAD(, cb_entry) callbacks;
-static int debug = 0;
-int verbose = 0;
+int simplehttp_logging = 0;
int callback_count = 0;
uint64_t request_count = 0;
+int help_cb(int *value);
+
static void ignore_cb(int sig, short what, void *arg)
{
}
@@ -115,9 +117,7 @@ void generic_request_handler(struct evhttp_request *req, void *arg)
struct simplehttp_request *s_req;
struct evbuffer *evb = evbuffer_new();
- if (debug) {
- fprintf(stderr, "request for %s from %s\n", req->uri, req->remote_host);
- }
+ // fprintf(stderr, "request for %s from %s\n", req->uri, req->remote_host);
request_count++;
@@ -177,51 +177,33 @@ void simplehttp_set_cb(char *path, void (*cb)(struct evhttp_request *, struct ev
printf("registering callback for path \"%s\"\n", path);
}
-int simplehttp_main(int argc, char **argv)
+void define_simplehttp_options() {
+ option_define_str("address", OPT_OPTIONAL, "0.0.0.0", NULL, NULL, "address to listen on");
+ option_define_int("port", OPT_OPTIONAL, 8080, NULL, NULL, "port to listen on");
+ option_define_bool("enable_logging", OPT_OPTIONAL, 0, NULL, NULL, "request logging");
+ option_define_bool("daemon", OPT_OPTIONAL, 0, NULL, NULL, "daemonize process");
+ option_define_str("root", OPT_OPTIONAL, NULL, NULL, NULL, "chdir and run from this directory");
+ option_define_str("user", OPT_OPTIONAL, NULL, NULL, NULL, "run as this user");
+ option_define_str("group", OPT_OPTIONAL, NULL, NULL, NULL, "run as this group");
+}
+
+int simplehttp_main()
{
uid_t uid = 0;
gid_t gid = 0;
- char *address;
- char *root = NULL;
- char *garg = NULL;
- char *uarg = NULL;
- int daemon = 0;
- int port, ch, errno;
pid_t pid, sid;
+ int errno;
struct evhttp *httpd;
struct event pipe_ev;
- address = "0.0.0.0";
- port = 8080;
- opterr = 0;
- while ((ch = getopt(argc, argv, "a:p:d:D:r:u:g:V")) != -1) {
- switch (ch) {
- case 'a':
- address = optarg;
- break;
- case 'p':
- port = atoi(optarg);
- break;
- case 'd':
- debug = 1;
- break;
- case 'r':
- root = optarg;
- break;
- case 'D':
- daemon = 1;
- break;
- case 'g':
- garg = optarg;
- break;
- case 'u':
- uarg = optarg;
- break;
- case 'V':
- verbose = 1;
- break;
- }
- }
+ char *address = option_get_str("address");
+ int port = option_get_int("port");
+
+ int daemon = option_get_int("daemon");
+ char *root = option_get_str("root");
+ char *user = option_get_str("user");
+ char *group = option_get_str("group");
+ simplehttp_logging = option_get_int("enable_logging");
if (daemon) {
pid = fork();
@@ -238,21 +220,21 @@ int simplehttp_main(int argc, char **argv)
}
}
- if (uarg != NULL) {
- uid = get_uid(uarg);
- gid = get_user_gid(uarg);
+ if (user != NULL) {
+ uid = get_uid(user);
+ gid = get_user_gid(user);
if (uid < 0) {
- uid = atoi(uarg);
- uarg = NULL;
+ uid = atoi(user);
+ user = NULL;
}
if (uid == 0) {
err(1, "invalid user");
}
}
- if (garg != NULL) {
- gid = get_gid(garg);
+ if (group != NULL) {
+ gid = get_gid(group);
if (gid < 0) {
- gid = atoi(garg);
+ gid = atoi(group);
if (gid == 0) {
err(1, "invalid group");
}
@@ -269,8 +251,8 @@ int simplehttp_main(int argc, char **argv)
}
if (getuid() == 0) {
- if (uarg != NULL) {
- if (initgroups(uarg, (int) gid) != 0) {
+ if (user != NULL) {
+ if (initgroups(user, (int) gid) != 0) {
err(1, "initgroups() failed");
}
} else {
View
4 simplehttp/simplehttp.h
@@ -2,6 +2,7 @@
#define _SIMPLEHTTP_H
#include "queue.h"
+#include "options.h"
#include <event.h>
#include <evhttp.h>
@@ -31,7 +32,7 @@ struct simplehttp_stats {
};
void simplehttp_init();
-int simplehttp_main(int argc, char **argv);
+int simplehttp_main();
void simplehttp_set_cb(char *path, void (*cb)(struct evhttp_request *, struct evbuffer *,void *), void *ctx);
uint64_t simplehttp_request_id(struct evhttp_request *req);
@@ -63,5 +64,6 @@ int get_argument_format(struct evkeyvalq *args);
int get_int_argument(struct evkeyvalq *args, char *key, int default_value);
double get_double_argument(struct evkeyvalq *args, char *key, double default_value);
+void define_simplehttp_options();
#endif
View
22 simplehttp/testserver.c
@@ -1,20 +1,36 @@
#include <stdio.h>
-#include "simplehttp.h"
+#include "<siplehttp/simplehttp.h>"
+
+#define VERSION "0.1"
void
cb(struct evhttp_request *req, struct evbuffer *evb,void *ctx)
{
- evbuffer_add_printf(evb, "Hello bitches\n%s\n", req->uri);
+ evbuffer_add_printf(evb, "Hello World!\n%s\n", req->uri);
evhttp_send_reply(req, HTTP_OK, "OK", evb);
}
+int version_cb(int value) {
+ fprintf(stdout, "Version: %s\n", VERSION);
+ return 0;
+}
+
+
int
main(int argc, char **argv)
{
+ define_simplehttp_options();
+ option_define_bool("version", OPT_OPTIONAL, 0, NULL, version_cb, VERSION);
+
+ if (!option_parse_command_line(argc, argv)){
+ return 1;
+ }
+
simplehttp_init();
simplehttp_set_cb("/ass*", cb, NULL);
simplehttp_set_cb("/foo*", cb, NULL);
simplehttp_set_cb("/bar*", cb, NULL);
- simplehttp_main(argc, argv);
+ simplehttp_main();
+ free_options();
return 0;
}
View
224 simplehttp/utarray.h
@@ -0,0 +1,224 @@
+/*
+Copyright (c) 2008-2010, Troy D. Hanson http://uthash.sourceforge.net
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* a dynamic array implementation using macros
+ * see http://uthash.sourceforge.net/utarray
+ */
+#ifndef UTARRAY_H
+#define UTARRAY_H
+
+#define UTARRAY_VERSION 1.9.1
+
+#ifdef __GNUC__
+#define _UNUSED_ __attribute__ ((__unused__))
+#else
+#define _UNUSED_
+#endif
+
+#include <stddef.h> /* size_t */
+#include <string.h> /* memset, etc */
+#include <stdlib.h> /* exit */
+
+#define oom() exit(-1)
+
+typedef void (ctor_f)(void *dst, const void *src);
+typedef void (dtor_f)(void *elt);
+typedef void (init_f)(void *elt);
+typedef struct {
+ size_t sz;
+ init_f *init;
+ ctor_f *copy;
+ dtor_f *dtor;
+} UT_icd;
+
+typedef struct {
+ unsigned i,n;/* i: index of next available slot, n: num slots */
+ const UT_icd *icd; /* initializer, copy and destructor functions */
+ char *d; /* n slots of size icd->sz*/
+} UT_array;
+
+#define utarray_init(a,_icd) do { \
+ memset(a,0,sizeof(UT_array)); \
+ (a)->icd=_icd; \
+} while(0)
+
+#define utarray_done(a) do { \
+ if ((a)->n) { \
+ if ((a)->icd->dtor) { \
+ size_t _ut_i; \
+ for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
+ (a)->icd->dtor(utarray_eltptr(a,_ut_i)); \
+ } \
+ } \
+ free((a)->d); \
+ } \
+ (a)->n=0; \
+} while(0)
+
+#define utarray_new(a,_icd) do { \
+ a=(UT_array*)malloc(sizeof(UT_array)); \
+ utarray_init(a,_icd); \
+} while(0)
+
+#define utarray_free(a) do { \
+ utarray_done(a); \
+ free(a); \
+} while(0)
+
+#define utarray_reserve(a,by) do { \
+ if (((a)->i+by) > ((a)->n)) { \
+ while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \
+ if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd->sz)) == NULL) oom(); \
+ } \
+} while(0)
+
+#define utarray_push_back(a,p) do { \
+ utarray_reserve(a,1); \
+ if ((a)->icd->copy) { (a)->icd->copy( _utarray_eltptr(a,(a)->i++), p); } \
+ else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd->sz); }; \
+} while(0)
+
+#define utarray_pop_back(a) do { \
+ if ((a)->icd->dtor) { (a)->icd->dtor( _utarray_eltptr(a,--((a)->i))); } \
+ else { (a)->i--; } \
+} while(0)
+
+#define utarray_extend_back(a) do { \
+ utarray_reserve(a,1); \
+ if ((a)->icd->init) { (a)->icd->init(_utarray_eltptr(a,(a)->i)); } \
+ else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd->sz); } \
+ (a)->i++; \
+} while(0)
+
+#define utarray_len(a) ((a)->i)
+
+#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL)
+#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd->sz*(j) )))
+
+#define utarray_insert(a,p,j) do { \
+ utarray_reserve(a,1); \
+ if (j > (a)->i) break; \
+ if ((j) < (a)->i) { \
+ memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \
+ ((a)->i - (j))*((a)->icd->sz)); \
+ } \
+ if ((a)->icd->copy) { (a)->icd->copy( _utarray_eltptr(a,j), p); } \
+ else { memcpy(_utarray_eltptr(a,j), p, (a)->icd->sz); }; \
+ (a)->i++; \
+} while(0)
+
+#define utarray_inserta(a,w,j) do { \
+ if (utarray_len(w) == 0) break; \
+ if (j > (a)->i) break; \
+ utarray_reserve(a,utarray_len(w)); \
+ if ((j) < (a)->i) { \
+ memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \
+ _utarray_eltptr(a,j), \
+ ((a)->i - (j))*((a)->icd->sz)); \
+ } \
+ if (a->icd->copy) { \
+ size_t _ut_i; \
+ for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \
+ (a)->icd->copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \
+ } \
+ } else { \
+ memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \
+ utarray_len(w)*((a)->icd->sz)); \
+ } \
+ (a)->i += utarray_len(w); \
+} while(0)
+
+#define utarray_resize(dst,num) do { \
+ size_t _ut_i; \
+ if (dst->i > (size_t)(num)) { \
+ if ((dst)->icd->dtor) { \
+ for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \
+ (dst)->icd->dtor(utarray_eltptr(dst,_ut_i)); \
+ } \
+ } \
+ } else if (dst->i < (size_t)(num)) { \
+ utarray_reserve(dst,num-dst->i); \
+ if ((dst)->icd->init) { \
+ for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \
+ (dst)->icd->init(utarray_eltptr(dst,_ut_i)); \
+ } \
+ } else { \
+ memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd->sz*(num-dst->i)); \
+ } \
+ } \
+ dst->i = num; \
+} while(0)
+
+#define utarray_concat(dst,src) do { \
+ utarray_inserta(dst,src,utarray_len(dst)); \
+} while(0)
+
+#define utarray_erase(a,pos,len) do { \
+ if ((a)->icd->dtor) { \
+ size_t _ut_i; \
+ for(_ut_i=0; _ut_i < len; _ut_i++) { \
+ (a)->icd->dtor(utarray_eltptr(a,pos+_ut_i)); \
+ } \
+ } \
+ if ((a)->i > (pos+len)) { \
+ memmove( _utarray_eltptr(a,pos), _utarray_eltptr(a,pos+len), \
+ ((a->i)-(pos+len))*((a)->icd->sz)); \
+ } \
+ (a)->i -= (len); \
+} while(0)
+
+#define utarray_clear(a) do { \
+ if ((a)->i > 0) { \
+ if ((a)->icd->dtor) { \
+ size_t _ut_i; \
+ for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
+ (a)->icd->dtor(utarray_eltptr(a,_ut_i)); \
+ } \
+ } \
+ (a)->i = 0; \
+ } \
+} while(0)
+
+#define utarray_sort(a,cmp) do { \
+ qsort((a)->d, (a)->i, (a)->icd->sz, cmp); \
+} while(0)
+
+#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL)
+#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL))
+#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL)
+#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(a)->icd->sz) : -1)
+
+/* last we pre-define a few icd for common utarrays of ints and strings */
+static void utarray_str_cpy(void *dst, const void *src) {
+ char **_src = (char**)src, **_dst = (char**)dst;
+ *_dst = (*_src == NULL) ? NULL : strdup(*_src);
+}
+static void utarray_str_dtor(void *elt) {
+ char **eltc = (char**)elt;
+ if (*eltc) free(*eltc);
+}
+static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor};
+static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL};
+
+
+#endif /* UTARRAY_H */
View
972 simplehttp/uthash.h
@@ -0,0 +1,972 @@
+/*
+Copyright (c) 2003-2010, Troy D. Hanson http://uthash.sourceforge.net
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UTHASH_H
+#define UTHASH_H
+
+#include <string.h> /* memcmp,strlen */
+#include <stddef.h> /* ptrdiff_t */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+ As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+ when compiling c++ source) this code uses whatever method is needed
+ or, for VS2008 where neither is available, uses casting workarounds. */
+#ifdef _MSC_VER /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
+#define DECLTYPE(x) (decltype(x))
+#else /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#define DECLTYPE(x)
+#endif
+#else /* GNU, Sun and other compilers */
+#define DECLTYPE(x) (__typeof(x))
+#endif
+
+#ifdef NO_DECLTYPE
+#define DECLTYPE_ASSIGN(dst,src) \
+do { \
+ char **_da_dst = (char**)(&(dst)); \
+ *_da_dst = (char*)(src); \
+} while(0)
+#else
+#define DECLTYPE_ASSIGN(dst,src) \
+do { \
+ (dst) = DECLTYPE(dst)(src); \
+} while(0)
+#endif
+
+/* a number of the hash function use uint32_t which isn't defined on win32 */
+#ifdef _MSC_VER
+typedef unsigned int uint32_t;
+#else
+#include <inttypes.h> /* uint32_t */
+#endif
+
+#define UTHASH_VERSION 1.9.3
+
+#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */
+#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
+#define uthash_free(ptr,sz) free(ptr) /* free fcn */
+
+#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
+#define uthash_expand_fyi(tbl) /* can be defined to log expands */
+
+/* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */
+#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */
+
+/* calculate the element whose hash handle address is hhe */
+#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
+
+#define HASH_FIND(hh,head,keyptr,keylen,out) \
+do { \
+ unsigned _hf_bkt,_hf_hashv; \
+ out=NULL; \
+ if (head) { \
+ HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \
+ if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \
+ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \
+ keyptr,keylen,out); \
+ } \
+ } \
+} while (0)
+
+#ifdef HASH_BLOOM
+#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
+#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)
+#define HASH_BLOOM_MAKE(tbl) \
+do { \
+ (tbl)->bloom_nbits = HASH_BLOOM; \
+ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \
+ if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \
+ memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \
+ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
+} while (0);
+
+#define HASH_BLOOM_FREE(tbl) \
+do { \
+ uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
+} while (0);
+
+#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))
+#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))
+
+#define HASH_BLOOM_ADD(tbl,hashv) \
+ HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#define HASH_BLOOM_TEST(tbl,hashv) \
+ HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#else
+#define HASH_BLOOM_MAKE(tbl)
+#define HASH_BLOOM_FREE(tbl)
+#define HASH_BLOOM_ADD(tbl,hashv)
+#define HASH_BLOOM_TEST(tbl,hashv) (1)
+#endif
+
+#define HASH_MAKE_TABLE(hh,head) \
+do { \
+ (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \
+ sizeof(UT_hash_table)); \
+ if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \
+ memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \
+ (head)->hh.tbl->tail = &((head)->hh); \
+ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
+ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
+ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \
+ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \
+ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
+ if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \
+ memset((head)->hh.tbl->buckets, 0, \
+ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
+ HASH_BLOOM_MAKE((head)->hh.tbl); \
+ (head)->hh.tbl->signature = HASH_SIGNATURE; \
+} while(0)
+
+#define HASH_ADD(hh,head,fieldname,keylen_in,add) \
+ HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add)
+
+#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \
+do { \
+ unsigned _ha_bkt; \
+ (add)->hh.next = NULL; \
+ (add)->hh.key = (char*)keyptr; \
+ (add)->hh.keylen = keylen_in; \
+ if (!(head)) { \
+ head = (add); \
+ (head)->hh.prev = NULL; \
+ HASH_MAKE_TABLE(hh,head); \
+ } else { \
+ (head)->hh.tbl->tail->next = (add); \
+ (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \
+ (head)->hh.tbl->tail = &((add)->hh); \
+ } \
+ (head)->hh.tbl->num_items++; \
+ (add)->hh.tbl = (head)->hh.tbl; \
+ HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \
+ (add)->hh.hashv, _ha_bkt); \
+ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \
+ HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \
+ HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \
+ HASH_FSCK(hh,head); \
+} while(0)
+
+#define HASH_TO_BKT( hashv, num_bkts, bkt ) \
+do { \
+ bkt = ((hashv) & ((num_bkts) - 1)); \
+} while(0)
+
+/* delete "delptr" from the hash table.
+ * "the usual" patch-up process for the app-order doubly-linked-list.
+ * The use of _hd_hh_del below deserves special explanation.
+ * These used to be expressed using (delptr) but that led to a bug
+ * if someone used the same symbol for the head and deletee, like
+ * HASH_DELETE(hh,users,users);
+ * We want that to work, but by changing the head (users) below
+ * we were forfeiting our ability to further refer to the deletee (users)
+ * in the patch-up process. Solution: use scratch space to
+ * copy the deletee pointer, then the latter references are via that
+ * scratch pointer rather than through the repointed (users) symbol.
+ */
+#define HASH_DELETE(hh,head,delptr) \
+do { \
+ unsigned _hd_bkt; \
+ struct UT_hash_handle *_hd_hh_del; \
+ if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \
+ uthash_free((head)->hh.tbl->buckets, \
+ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+ HASH_BLOOM_FREE((head)->hh.tbl); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ head = NULL; \
+ } else { \
+ _hd_hh_del = &((delptr)->hh); \
+ if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \
+ (head)->hh.tbl->tail = \
+ (UT_hash_handle*)((char*)((delptr)->hh.prev) + \
+ (head)->hh.tbl->hho); \
+ } \
+ if ((delptr)->hh.prev) { \
+ ((UT_hash_handle*)((char*)((delptr)->hh.prev) + \
+ (head)->hh.tbl->hho))->next = (delptr)->hh.next; \
+ } else { \
+ DECLTYPE_ASSIGN(head,(delptr)->hh.next); \
+ } \
+ if (_hd_hh_del->next) { \
+ ((UT_hash_handle*)((char*)_hd_hh_del->next + \
+ (head)->hh.tbl->hho))->prev = \
+ _hd_hh_del->prev; \
+ } \
+ HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
+ HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
+ (head)->hh.tbl->num_items--; \
+ } \
+ HASH_FSCK(hh,head); \
+} while (0)
+
+
+/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
+#define HASH_FIND_STR(head,findstr,out) \
+ HASH_FIND(hh,head,findstr,strlen(findstr),out)
+#define HASH_ADD_STR(head,strfield,add) \
+ HASH_ADD(hh,head,strfield,strlen(add->strfield),add)
+#define HASH_FIND_INT(head,findint,out) \
+ HASH_FIND(hh,head,findint,sizeof(int),out)
+#define HASH_ADD_INT(head,intfield,add) \
+ HASH_ADD(hh,head,intfield,sizeof(int),add)
+#define HASH_FIND_PTR(head,findptr,out) \
+ HASH_FIND(hh,head,findptr,sizeof(void *),out)
+#define HASH_ADD_PTR(head,ptrfield,add) \
+ HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
+#define HASH_DEL(head,delptr) \
+ HASH_DELETE(hh,head,delptr)
+
+/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
+ * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
+ */
+#ifdef HASH_DEBUG
+#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
+#define HASH_FSCK(hh,head) \
+do { \
+ unsigned _bkt_i; \
+ unsigned _count, _bkt_count; \
+ char *_prev; \
+ struct UT_hash_handle *_thh; \
+ if (head) { \
+ _count = 0; \
+ for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \
+ _bkt_count = 0; \
+ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
+ _prev = NULL; \
+ while (_thh) { \
+ if (_prev != (char*)(_thh->hh_prev)) { \
+ HASH_OOPS("invalid hh_prev %p, actual %p\n", \
+ _thh->hh_prev, _prev ); \
+ } \
+ _bkt_count++; \
+ _prev = (char*)(_thh); \
+ _thh = _thh->hh_next; \
+ } \
+ _count += _bkt_count; \
+ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
+ HASH_OOPS("invalid bucket count %d, actual %d\n", \
+ (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
+ } \
+ } \
+ if (_count != (head)->hh.tbl->num_items) { \
+ HASH_OOPS("invalid hh item count %d, actual %d\n", \
+ (head)->hh.tbl->num_items, _count ); \
+ } \
+ /* traverse hh in app order; check next/prev integrity, count */ \
+ _count = 0; \
+ _prev = NULL; \
+ _thh = &(head)->hh; \
+ while (_thh) { \
+ _count++; \
+ if (_prev !=(char*)(_thh->prev)) { \
+ HASH_OOPS("invalid prev %p, actual %p\n", \
+ _thh->prev, _prev ); \
+ } \
+ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \
+ _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \
+ (head)->hh.tbl->hho) : NULL ); \
+ } \
+ if (_count != (head)->hh.tbl->num_items) { \
+ HASH_OOPS("invalid app item count %d, actual %d\n", \
+ (head)->hh.tbl->num_items, _count ); \
+ } \
+ } \
+} while (0)
+#else
+#define HASH_FSCK(hh,head)
+#endif
+
+/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
+ * the descriptor to which this macro is defined for tuning the hash function.
+ * The app can #include <unistd.h> to get the prototype for write(2). */
+#ifdef HASH_EMIT_KEYS
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \
+do { \
+ unsigned _klen = fieldlen; \
+ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \
+ write(HASH_EMIT_KEYS, keyptr, fieldlen); \
+} while (0)
+#else
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
+#endif
+
+/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
+#ifdef HASH_FUNCTION
+#define HASH_FCN HASH_FUNCTION
+#else
+#define HASH_FCN HASH_JEN
+#endif
+
+/* The Bernstein hash function, used in Perl prior to v5.6 */
+#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _hb_keylen=keylen; \
+ char *_hb_key=(char*)(key); \
+ (hashv) = 0; \
+ while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \
+ bkt = (hashv) & (num_bkts-1); \
+} while (0)
+
+
+/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
+ * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
+#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _sx_i; \
+ char *_hs_key=(char*)(key); \
+ hashv = 0; \
+ for(_sx_i=0; _sx_i < keylen; _sx_i++) \
+ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
+ bkt = hashv & (num_bkts-1); \
+} while (0)
+
+#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _fn_i; \
+ char *_hf_key=(char*)(key); \
+ hashv = 2166136261UL; \
+ for(_fn_i=0; _fn_i < keylen; _fn_i++) \
+ hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \
+ bkt = hashv & (num_bkts-1); \
+} while(0);
+
+#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _ho_i; \
+ char *_ho_key=(char*)(key); \
+ hashv = 0; \
+ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \
+ hashv += _ho_key[_ho_i]; \
+ hashv += (hashv << 10); \
+ hashv ^= (hashv >> 6); \
+ } \
+ hashv += (hashv << 3); \
+ hashv ^= (hashv >> 11); \
+ hashv += (hashv << 15); \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+
+#define HASH_JEN_MIX(a,b,c) \
+do { \
+ a -= b; a -= c; a ^= ( c >> 13 ); \
+ b -= c; b -= a; b ^= ( a << 8 ); \
+ c -= a; c -= b; c ^= ( b >> 13 ); \
+ a -= b; a -= c; a ^= ( c >> 12 ); \
+ b -= c; b -= a; b ^= ( a << 16 ); \
+ c -= a; c -= b; c ^= ( b >> 5 ); \
+ a -= b; a -= c; a ^= ( c >> 3 ); \
+ b -= c; b -= a; b ^= ( a << 10 ); \
+ c -= a; c -= b; c ^= ( b >> 15 ); \
+} while (0)
+
+#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ unsigned _hj_i,_hj_j,_hj_k; \
+ char *_hj_key=(char*)(key); \
+ hashv = 0xfeedbeef; \
+ _hj_i = _hj_j = 0x9e3779b9; \
+ _hj_k = keylen; \
+ while (_hj_k >= 12) { \
+ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \
+ + ( (unsigned)_hj_key[2] << 16 ) \
+ + ( (unsigned)_hj_key[3] << 24 ) ); \
+ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \
+ + ( (unsigned)_hj_key[6] << 16 ) \
+ + ( (unsigned)_hj_key[7] << 24 ) ); \
+ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \
+ + ( (unsigned)_hj_key[10] << 16 ) \
+ + ( (unsigned)_hj_key[11] << 24 ) ); \
+ \
+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
+ \
+ _hj_key += 12; \
+ _hj_k -= 12; \
+ } \
+ hashv += keylen; \
+ switch ( _hj_k ) { \
+ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \
+ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \
+ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \
+ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \
+ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \
+ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \
+ case 5: _hj_j += _hj_key[4]; \
+ case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \
+ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \
+ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \
+ case 1: _hj_i += _hj_key[0]; \
+ } \
+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+
+/* The Paul Hsieh hash function */
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ char *_sfh_key=(char*)(key); \
+ uint32_t _sfh_tmp, _sfh_len = keylen; \
+ \
+ int _sfh_rem = _sfh_len & 3; \
+ _sfh_len >>= 2; \
+ hashv = 0xcafebabe; \
+ \
+ /* Main loop */ \
+ for (;_sfh_len > 0; _sfh_len--) { \
+ hashv += get16bits (_sfh_key); \
+ _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \
+ hashv = (hashv << 16) ^ _sfh_tmp; \
+ _sfh_key += 2*sizeof (uint16_t); \
+ hashv += hashv >> 11; \
+ } \
+ \
+ /* Handle end cases */ \
+ switch (_sfh_rem) { \
+ case 3: hashv += get16bits (_sfh_key); \
+ hashv ^= hashv << 16; \
+ hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \
+ hashv += hashv >> 11; \
+ break; \
+ case 2: hashv += get16bits (_sfh_key); \
+ hashv ^= hashv << 11; \
+ hashv += hashv >> 17; \
+ break; \
+ case 1: hashv += *_sfh_key; \
+ hashv ^= hashv << 10; \
+ hashv += hashv >> 1; \
+ } \
+ \
+ /* Force "avalanching" of final 127 bits */ \
+ hashv ^= hashv << 3; \
+ hashv += hashv >> 5; \
+ hashv ^= hashv << 4; \
+ hashv += hashv >> 17; \
+ hashv ^= hashv << 25; \
+ hashv += hashv >> 6; \
+ bkt = hashv & (num_bkts-1); \
+} while(0);
+
+#ifdef HASH_USING_NO_STRICT_ALIASING
+/* The MurmurHash exploits some CPU's (e.g. x86) tolerance for unaligned reads.
+ * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
+ * So MurmurHash comes in two versions, the faster unaligned one and the slower
+ * aligned one. We only use the faster one on CPU's where we know it's safe.
+ *
+ * Note the preprocessor built-in defines can be emitted using:
+ *
+ * gcc -m64 -dM -E - < /dev/null (on gcc)
+ * cc -## a.c (where a.c is a simple test file) (Sun Studio)
+ */
+#if (defined(__i386__) || defined(__x86_64__))
+#define HASH_MUR HASH_MUR_UNALIGNED
+#else
+#define HASH_MUR HASH_MUR_ALIGNED
+#endif
+
+/* Appleby's MurmurHash fast version for unaligned-tolerant archs like i386 */
+#define HASH_MUR_UNALIGNED(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ const unsigned int _mur_m = 0x5bd1e995; \
+ const int _mur_r = 24; \
+ hashv = 0xcafebabe ^ keylen; \
+ char *_mur_key = (char *)(key); \
+ uint32_t _mur_tmp, _mur_len = keylen; \
+ \
+ for (;_mur_len >= 4; _mur_len-=4) { \
+ _mur_tmp = *(uint32_t *)_mur_key; \
+ _mur_tmp *= _mur_m; \
+ _mur_tmp ^= _mur_tmp >> _mur_r; \
+ _mur_tmp *= _mur_m; \
+ hashv *= _mur_m; \
+ hashv ^= _mur_tmp; \
+ _mur_key += 4; \
+ } \
+ \
+ switch(_mur_len) \
+ { \
+ case 3: hashv ^= _mur_key[2] << 16; \
+ case 2: hashv ^= _mur_key[1] << 8; \
+ case 1: hashv ^= _mur_key[0]; \
+ hashv *= _mur_m; \
+ }; \
+ \
+ hashv ^= hashv >> 13; \
+ hashv *= _mur_m; \
+ hashv ^= hashv >> 15; \
+ \
+ bkt = hashv & (num_bkts-1); \
+} while(0)
+
+/* Appleby's MurmurHash version for alignment-sensitive archs like Sparc */
+#define HASH_MUR_ALIGNED(key,keylen,num_bkts,hashv,bkt) \
+do { \
+ const unsigned int _mur_m = 0x5bd1e995; \
+ const int _mur_r = 24; \
+ hashv = 0xcafebabe ^ (keylen); \
+ char *_mur_key = (char *)(key); \
+ uint32_t _mur_len = keylen; \
+ int _mur_align = (int)_mur_key & 3; \
+ \
+ if (_mur_align && (_mur_len >= 4)) { \
+ unsigned _mur_t = 0, _mur_d = 0; \
+ switch(_mur_align) { \
+ case 1: _mur_t |= _mur_key[2] << 16; \
+ case 2: _mur_t |= _mur_key[1] << 8; \
+ case 3: _mur_t |= _mur_key[0]; \
+ } \
+ _mur_t <<= (8 * _mur_align); \
+ _mur_key += 4-_mur_align; \
+ _mur_len -= 4-_mur_align; \
+ int _mur_sl = 8 * (4-_mur_align); \
+ int _mur_sr = 8 * _mur_align; \
+ \
+ for (;_mur_len >= 4; _mur_len-=4) { \
+ _mur_d = *(unsigned *)_mur_key; \
+ _mur_t = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \
+ unsigned _mur_k = _mur_t; \
+ _mur_k *= _mur_m; \
+ _mur_k ^= _mur_k >> _mur_r; \
+ _mur_k *= _mur_m; \
+ hashv *= _mur_m; \
+ hashv ^= _mur_k; \
+ _mur_t = _mur_d; \
+ _mur_key += 4; \
+ } \
+ _mur_d = 0; \
+ if(_mur_len >= _mur_align) { \
+ switch(_mur_align) { \
+ case 3: _mur_d |= _mur_key[2] << 16; \
+ case 2: _mur_d |= _mur_key[1] << 8; \
+ case 1: _mur_d |= _mur_key[0]; \
+ } \
+ unsigned _mur_k = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \
+ _mur_k *= _mur_m; \
+ _mur_k ^= _mur_k >> _mur_r; \
+ _mur_k *= _mur_m; \
+ hashv *= _mur_m; \
+ hashv ^= _mur_k; \
+ _mur_k += _mur_align; \
+ _mur_len -= _mur_align; \
+ \
+ switch(_mur_len) \
+ { \
+ case 3: hashv ^= _mur_key[2] << 16; \
+ case 2: hashv ^= _mur_key[1] << 8; \
+ case 1: hashv ^= _mur_key[0]; \
+ hashv *= _mur_m; \
+ } \
+ } else { \
+ switch(_mur_len) \
+ { \
+ case 3: _mur_d ^= _mur_key[2] << 16; \
+ case 2: _mur_d ^= _mur_key[1] << 8; \
+ case 1: _mur_d ^= _mur_key[0]; \
+ case 0: hashv ^= (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \