summaryrefslogtreecommitdiff
path: root/src/libmowgli/ext
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmowgli/ext')
-rw-r--r--src/libmowgli/ext/Makefile25
-rw-r--r--src/libmowgli/ext/confparse.c436
-rw-r--r--src/libmowgli/ext/confparse.h45
-rw-r--r--src/libmowgli/ext/error_backtrace.c109
-rw-r--r--src/libmowgli/ext/error_backtrace.h38
-rw-r--r--src/libmowgli/ext/getopt_long.c461
-rw-r--r--src/libmowgli/ext/getopt_long.h69
-rw-r--r--src/libmowgli/ext/global_storage.c69
-rw-r--r--src/libmowgli/ext/global_storage.h32
-rw-r--r--src/libmowgli/ext/proctitle.c311
-rw-r--r--src/libmowgli/ext/proctitle.h23
-rw-r--r--src/libmowgli/ext/program_opts.c191
-rw-r--r--src/libmowgli/ext/program_opts.h50
13 files changed, 1859 insertions, 0 deletions
diff --git a/src/libmowgli/ext/Makefile b/src/libmowgli/ext/Makefile
new file mode 100644
index 0000000..d7466b6
--- /dev/null
+++ b/src/libmowgli/ext/Makefile
@@ -0,0 +1,25 @@
+include ../../../extra.mk
+
+STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_EXT}
+STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_EXT}
+
+SRCS = confparse.c \
+ error_backtrace.c \
+ getopt_long.c \
+ global_storage.c \
+ program_opts.c \
+ proctitle.c
+
+INCLUDES = confparse.h \
+ error_backtrace.h \
+ getopt_long.h \
+ global_storage.h \
+ program_opts.h \
+ proctitle.h
+
+include ../../../buildsys.mk
+
+includesubdir = $(PACKAGE_NAME)/ext
+
+CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE
+
diff --git a/src/libmowgli/ext/confparse.c b/src/libmowgli/ext/confparse.c
new file mode 100644
index 0000000..898ba8c
--- /dev/null
+++ b/src/libmowgli/ext/confparse.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2005-2011 Atheme Project (http://www.atheme.org)
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+/*
+ * Description of config files parsed by this:
+ *
+ * configfile = *WS *configentry
+ * configentry = value [1*WS value] [1*WS "{" *(configentry 1*WS) "}" ] *WS ";"
+ * value = 1*achar / DQUOTE *qchar DQUOTE
+ * achar = <any CHAR except WS or DQUOTE>
+ * qchar = <any CHAR except DQUOTE or \> / "\\" / "\" DQUOTE
+ * comment = "/" "*" <anything except * /> "*" "/" /
+ * "#" *CHAR %0x0A /
+ * "//" *CHAR %0x0A
+ * WS = %x09 / %x0A / %x0D / SPACE / "=" / comment
+ *
+ * A value of "include" for toplevel configentries causes a file to be
+ * included. The included file is logically appended to the current file,
+ * no matter where the include directive is. Include files must have balanced
+ * braces.
+ */
+/*
+ * Original idea from the csircd config parser written by Fred Jacobs
+ * and Chris Behrens.
+ */
+
+#include "mowgli.h"
+#include <sys/stat.h>
+#include <limits.h>
+
+#define MAX_INCLUDE_NESTING 16
+
+static mowgli_config_file_t *mowgli_config_file_parse(const char *filename, char *confdata);
+static void mowgli_config_file_entry_free(mowgli_config_file_entry_t *ceptr);
+static mowgli_config_file_t *mowgli_config_file_load_internal(mowgli_config_file_t *parent, const char *filename);
+
+#define CF_ERRORED(cf) ((cf)->curline <= 0)
+
+static void mowgli_config_file_error(mowgli_config_file_t *cf, const char *format, ...)
+{
+ va_list ap;
+ char buffer[1024];
+ char *ptr;
+
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof buffer, format, ap);
+ va_end(ap);
+
+ if ((ptr = strchr(buffer, '\n')) != NULL)
+ *ptr = '\0';
+
+ if (cf != NULL)
+ {
+ if (cf->curline < 0)
+ cf->curline = -cf->curline;
+
+ mowgli_log("%s:%d: %s", cf->filename, cf->curline, buffer);
+
+ /* mark config parse as failed */
+ cf->curline = -cf->curline;
+ }
+ else
+ mowgli_log("mowgli_config_file_parse(): %s", buffer);
+}
+
+static void skip_ws(char **pos, mowgli_config_file_t *cf)
+{
+ int startline;
+
+ for (;;)
+ {
+ switch (**pos)
+ {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '=': /* XXX */
+ break;
+ case '\n':
+ cf->curline++;
+ break;
+ case '/':
+ if ((*pos)[1] == '*')
+ {
+ startline = cf->curline;
+ (*pos)++;
+ (*pos)++;
+ while (**pos != '\0' && (**pos != '*' || (*pos)[1] != '/'))
+ {
+ if (**pos == '\n')
+ cf->curline++;
+ (*pos)++;
+ }
+ if (**pos == '\0')
+ mowgli_config_file_error(cf, "File ends inside comment starting at line %d", startline);
+ else
+ (*pos)++; /* skip '*' */
+ }
+ else if ((*pos)[1] == '/')
+ {
+ while (**pos != '\0' && **pos != '\n' && **pos != '\r')
+ (*pos)++;
+ continue;
+ }
+ else
+ return;
+ break;
+ case '#':
+ while (**pos != '\0' && **pos != '\n' && **pos != '\r')
+ (*pos)++;
+ continue;
+ default:
+ return;
+ }
+ if (**pos == '\0')
+ return;
+ (*pos)++;
+ }
+}
+
+static char *get_value(char **pos, mowgli_config_file_t *cf, char *skipped)
+{
+ char *p = *pos;
+ char *q;
+ char *start;
+
+ *skipped = '\0';
+ if (*p == '"')
+ {
+ p++;
+ start = p;
+ q = p;
+ while (*p != '\0' && *p != '\r' && *p != '\n' && *p != '"')
+ {
+ if (*p == '\\' && (p[1] == '"' || p[1] == '\\'))
+ p++;
+ *q++ = *p++;
+ }
+ if (*p == '\0')
+ {
+ mowgli_config_file_error(cf, "File ends inside quoted string");
+ return NULL;
+ }
+ if (*p == '\r' || *p == '\n')
+ {
+ mowgli_config_file_error(cf, "Newline inside quoted string");
+ return NULL;
+ }
+ if (*p != '"')
+ {
+ mowgli_config_file_error(cf, "Weird character terminating quoted string (BUG)");
+ return NULL;
+ }
+ p++;
+ *q = '\0';
+ *pos = p;
+ skip_ws(pos, cf);
+ return start;
+ }
+ else
+ {
+ start = p;
+ while (*p != '\0' && *p != '\t' && *p != '\r' && *p != '\n' &&
+ *p != ' ' && *p != '/' && *p != '#' &&
+ *p != ';' && *p != '{' && *p != '}')
+ p++;
+ if (p == start)
+ return NULL;
+ *pos = p;
+ skip_ws(pos, cf);
+ if (p == *pos)
+ *skipped = *p;
+ *p = '\0';
+ if (p == *pos)
+ (*pos)++;
+ return start;
+ }
+}
+
+static mowgli_config_file_t *mowgli_config_file_parse(const char *filename, char *confdata)
+{
+ mowgli_config_file_t *cf, *subcf, *lastcf;
+ mowgli_config_file_entry_t **pprevce, *ce, *upce;
+ char *p, *val;
+ char c;
+
+ cf = mowgli_alloc(sizeof *cf);
+ cf->filename = mowgli_strdup(filename);
+ cf->curline = 1;
+ cf->mem = confdata;
+ lastcf = cf;
+ pprevce = &cf->entries;
+ upce = NULL;
+ p = confdata;
+ while (*p != '\0')
+ {
+ skip_ws(&p, cf);
+ if (*p == '\0' || CF_ERRORED(cf))
+ break;
+ if (*p == '}')
+ {
+ if (upce == NULL)
+ {
+ mowgli_config_file_error(cf, "Extraneous closing brace");
+ break;
+ }
+ ce = upce;
+ ce->sectlinenum = cf->curline;
+ pprevce = &ce->next;
+ upce = ce->prevlevel;
+ p++;
+ skip_ws(&p, cf);
+ if (CF_ERRORED(cf))
+ break;
+ if (*p != ';')
+ {
+ mowgli_config_file_error(cf, "Missing semicolon after closing brace for section ending at line %d", ce->sectlinenum);
+ break;
+ }
+ ce = NULL;
+ p++;
+ continue;
+ }
+ val = get_value(&p, cf, &c);
+ if (CF_ERRORED(cf))
+ break;
+ if (val == NULL)
+ {
+ mowgli_config_file_error(cf, "Unexpected character trying to read variable name");
+ break;
+ }
+ ce = mowgli_alloc(sizeof *ce);
+ ce->fileptr = cf;
+ ce->varlinenum = cf->curline;
+ ce->varname = val;
+ ce->prevlevel = upce;
+ *pprevce = ce;
+ pprevce = &ce->next;
+ if (c == '\0' && (*p == '{' || *p == ';'))
+ c = *p++;
+ if (c == '{')
+ {
+ pprevce = &ce->entries;
+ upce = ce;
+ ce = NULL;
+ }
+ else if (c == ';')
+ {
+ ce = NULL;
+ }
+ else if (c != '\0')
+ {
+ mowgli_config_file_error(cf, "Unexpected characters after unquoted string %s", ce->varname);
+ break;
+ }
+ else
+ {
+ val = get_value(&p, cf, &c);
+ if (CF_ERRORED(cf))
+ break;
+ if (val == NULL)
+ {
+ mowgli_config_file_error(cf, "Unexpected character trying to read value for %s", ce->varname);
+ break;
+ }
+ ce->vardata = val;
+ if (c == '\0' && (*p == '{' || *p == ';'))
+ c = *p++;
+ if (c == '{')
+ {
+ pprevce = &ce->entries;
+ upce = ce;
+ ce = NULL;
+ }
+ else if (c == ';')
+ {
+ if (upce == NULL && !strcasecmp(ce->varname, "include"))
+ {
+ subcf = mowgli_config_file_load_internal(cf, ce->vardata);
+ if (subcf == NULL)
+ {
+ mowgli_config_file_error(cf, "Error in file included from here");
+ break;
+ }
+ lastcf->next = subcf;
+ while (lastcf->next != NULL)
+ lastcf = lastcf->next;
+ }
+ ce = NULL;
+ }
+ else
+ {
+ mowgli_config_file_error(cf, "Unexpected characters after value %s %s", ce->varname, ce->vardata);
+ break;
+ }
+ }
+ }
+ if (!CF_ERRORED(cf) && upce != NULL)
+ {
+ mowgli_config_file_error(cf, "One or more sections not closed");
+ ce = upce;
+ while (ce->prevlevel != NULL)
+ ce = ce->prevlevel;
+ if (ce->vardata != NULL)
+ mowgli_config_file_error(cf, "First unclosed section is %s %s at line %d",
+ ce->varname, ce->vardata, ce->varlinenum);
+ else
+ mowgli_config_file_error(cf, "First unclosed section is %s at line %d",
+ ce->varname, ce->varlinenum);
+ }
+ if (CF_ERRORED(cf))
+ {
+ mowgli_config_file_free(cf);
+ cf = NULL;
+ }
+ return cf;
+}
+
+static void mowgli_config_file_entry_free(mowgli_config_file_entry_t *ceptr)
+{
+ mowgli_config_file_entry_t *nptr;
+
+ for (; ceptr; ceptr = nptr)
+ {
+ nptr = ceptr->next;
+ if (ceptr->entries)
+ mowgli_config_file_entry_free(ceptr->entries);
+ /* ce_varname and ce_vardata are inside cf_mem */
+ mowgli_free(ceptr);
+ }
+}
+
+void mowgli_config_file_free(mowgli_config_file_t *cfptr)
+{
+ mowgli_config_file_t *nptr;
+
+ for (; cfptr; cfptr = nptr)
+ {
+ nptr = cfptr->next;
+ if (cfptr->entries)
+ mowgli_config_file_entry_free(cfptr->entries);
+ mowgli_free(cfptr->filename);
+ mowgli_free(cfptr->mem);
+ mowgli_free(cfptr);
+ }
+}
+
+static mowgli_config_file_t *mowgli_config_file_load_internal(mowgli_config_file_t *parent, const char *filename)
+{
+ struct stat sb;
+ FILE *fp;
+ size_t ret;
+ char *buf = NULL;
+ mowgli_config_file_t *cfptr;
+ static int nestcnt;
+
+ if (nestcnt > MAX_INCLUDE_NESTING)
+ {
+ mowgli_config_file_error(parent, "Includes nested too deep \"%s\"\n", filename);
+ return NULL;
+ }
+
+ fp = fopen(filename, "rb");
+ if (!fp)
+ {
+ mowgli_config_file_error(parent, "Couldn't open \"%s\": %s\n", filename, strerror(errno));
+ return NULL;
+ }
+ if (stat(filename, &sb) == -1)
+ {
+ mowgli_config_file_error(parent, "Couldn't fstat \"%s\": %s\n", filename, strerror(errno));
+ fclose(fp);
+ return NULL;
+ }
+ if (!S_ISREG(sb.st_mode))
+ {
+ mowgli_config_file_error(parent, "Not a regular file: \"%s\"\n", filename);
+ fclose(fp);
+ return NULL;
+ }
+ if (sb.st_size > SSIZE_MAX - 1)
+ {
+ mowgli_config_file_error(parent, "File too large: \"%s\"\n", filename);
+ fclose(fp);
+ return NULL;
+ }
+ buf = (char *) mowgli_alloc(sb.st_size + 1);
+ if (sb.st_size)
+ {
+ errno = 0;
+ ret = fread(buf, 1, sb.st_size, fp);
+ if (ret != (size_t)sb.st_size)
+ {
+ mowgli_config_file_error(parent, "Error reading \"%s\": %s\n", filename, strerror(errno ? errno : EFAULT));
+ mowgli_free(buf);
+ fclose(fp);
+ return NULL;
+ }
+ }
+ else
+ ret = 0;
+ buf[ret] = '\0';
+ fclose(fp);
+ nestcnt++;
+ cfptr = mowgli_config_file_parse(filename, buf);
+ nestcnt--;
+ /* buf is owned by cfptr or freed now */
+ return cfptr;
+}
+
+mowgli_config_file_t *mowgli_config_file_load(const char *filename)
+{
+ return mowgli_config_file_load_internal(NULL, filename);
+}
+
+/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
+ * vim:ts=8
+ * vim:sw=8
+ * vim:noexpandtab
+ */
diff --git a/src/libmowgli/ext/confparse.h b/src/libmowgli/ext/confparse.h
new file mode 100644
index 0000000..d498b87
--- /dev/null
+++ b/src/libmowgli/ext/confparse.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2005-2008 William Pitcock, et al.
+ * Rights to this code are as documented in doc/LICENSE.
+ *
+ * Config file parser.
+ *
+ */
+
+#ifndef CONFPARSE_H
+#define CONFPARSE_H
+
+typedef struct _mowgli_configfile mowgli_config_file_t;
+typedef struct _mowgli_configentry mowgli_config_file_entry_t;
+
+struct _mowgli_configfile
+{
+ char *filename;
+ mowgli_config_file_entry_t *entries;
+ mowgli_config_file_t *next;
+ int curline;
+ char *mem;
+};
+
+struct _mowgli_configentry
+{
+ mowgli_config_file_t *fileptr;
+
+ int varlinenum;
+ char *varname;
+ char *vardata;
+ int sectlinenum; /* line containing closing brace */
+
+ mowgli_config_file_entry_t *entries;
+ mowgli_config_file_entry_t *prevlevel;
+ mowgli_config_file_entry_t *next;
+};
+
+/* confp.c */
+extern void mowgli_config_file_free(mowgli_config_file_t *cfptr);
+extern mowgli_config_file_t *mowgli_config_file_load(const char *filename);
+
+#endif
+
+/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs ts=8 sw=8 noexpandtab
+ */
diff --git a/src/libmowgli/ext/error_backtrace.c b/src/libmowgli/ext/error_backtrace.c
new file mode 100644
index 0000000..6c28c22
--- /dev/null
+++ b/src/libmowgli/ext/error_backtrace.c
@@ -0,0 +1,109 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * error_backtrace.c: Print errors and explain how they were reached.
+ *
+ * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include "mowgli.h"
+
+void
+mowgli_error_context_display(mowgli_error_context_t *e, const char *delim)
+{
+ mowgli_node_t *n;
+ char *bt_msg;
+
+ return_if_fail(e != NULL);
+ return_if_fail(delim != NULL);
+
+ if (MOWGLI_LIST_LENGTH(&e->bt) == 0)
+ mowgli_throw_exception(mowgli.error_backtrace.no_backtrace);
+
+ MOWGLI_LIST_FOREACH(n, e->bt.head)
+ {
+ bt_msg = (char *) n->data;
+
+ fprintf(stderr, "%s%s", bt_msg, n->next != NULL ? delim : "\n");
+ }
+}
+
+void
+mowgli_error_context_destroy(mowgli_error_context_t *e)
+{
+ mowgli_node_t *n, *tn;
+
+ return_if_fail(e != NULL);
+
+ if (MOWGLI_LIST_LENGTH(&e->bt) == 0)
+ {
+ mowgli_free(e);
+ return;
+ }
+
+ MOWGLI_LIST_FOREACH_SAFE(n, tn, e->bt.head)
+ {
+ mowgli_free(n->data);
+
+ mowgli_node_delete(n, &e->bt);
+ mowgli_node_free(n);
+ }
+
+ mowgli_free(e);
+}
+
+void
+mowgli_error_context_display_with_error(mowgli_error_context_t *e, const char *delim, const char *error)
+{
+ mowgli_error_context_display(e, delim);
+ fprintf(stderr, "Error: %s\n", error);
+
+ _exit(EXIT_FAILURE);
+}
+
+void
+mowgli_error_context_push(mowgli_error_context_t *e, const char *msg, ...)
+{
+ char buf[65535];
+ va_list va;
+
+ return_if_fail(e != NULL);
+ return_if_fail(msg != NULL);
+
+ va_start(va, msg);
+ vsnprintf(buf, 65535, msg, va);
+ va_end(va);
+
+ mowgli_node_add(mowgli_strdup(buf), mowgli_node_create(), &e->bt);
+}
+
+void
+mowgli_error_context_pop(mowgli_error_context_t *e)
+{
+ return_if_fail(e != NULL);
+
+ mowgli_node_delete(e->bt.tail, &e->bt);
+}
+
+mowgli_error_context_t *
+mowgli_error_context_create(void)
+{
+ mowgli_error_context_t *out = (mowgli_error_context_t *) mowgli_alloc(sizeof(mowgli_error_context_t));
+
+ return out;
+}
diff --git a/src/libmowgli/ext/error_backtrace.h b/src/libmowgli/ext/error_backtrace.h
new file mode 100644
index 0000000..d7da7cf
--- /dev/null
+++ b/src/libmowgli/ext/error_backtrace.h
@@ -0,0 +1,38 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * error_backtrace.h: Print errors and explain how they were reached.
+ *
+ * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 __MOWGLI_ERROR_BACKTRACE_H__
+#define __MOWGLI_ERROR_BACKTRACE_H__
+
+typedef struct mowgli_error_context_ {
+ mowgli_list_t bt;
+} mowgli_error_context_t;
+
+extern void mowgli_error_context_display(mowgli_error_context_t *e, const char *delim);
+extern void mowgli_error_context_display_with_error(mowgli_error_context_t *e, const char *delim, const char *error);
+extern void mowgli_error_context_destroy(mowgli_error_context_t *e);
+extern void mowgli_error_context_push(mowgli_error_context_t *e, const char *msg, ...);
+extern void mowgli_error_context_pop(mowgli_error_context_t *e);
+extern mowgli_error_context_t *mowgli_error_context_create(void);
+
+#endif
diff --git a/src/libmowgli/ext/getopt_long.c b/src/libmowgli/ext/getopt_long.c
new file mode 100644
index 0000000..adf64e5
--- /dev/null
+++ b/src/libmowgli/ext/getopt_long.c
@@ -0,0 +1,461 @@
+/* $NetBSD: getopt_long.c,v 1.25 2009/03/20 14:05:54 joerg Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <mowgli.h>
+
+#include "getopt_long.h"
+
+int mowgli_opterr = 1; /* if error message should be printed */
+int mowgli_optind = 1; /* index into parent argv vector */
+int mowgli_optopt = '?'; /* character checked for validity */
+int mowgli_optreset = 0; /* reset getopt */
+char *mowgli_optarg = NULL; /* argument associated with option */
+
+/* XXX: suppress const warnings */
+#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
+
+#define IGNORE_FIRST (*options == '-' || *options == '+')
+#define PRINT_ERROR ((mowgli_opterr) && ((*options != ':') \
+ || (IGNORE_FIRST && options[1] != ':')))
+#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
+#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
+/* XXX: GNU ignores PC if *options == '-' */
+#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
+
+/* return values */
+#define BADCH (int)'?'
+#define BADARG ((IGNORE_FIRST && options[1] == ':') \
+ || (*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#define EMSG ""
+
+static inline void
+warnx(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static int getopt_internal(int, char **, const char *);
+static int gcd(int, int);
+static void permute_args(int, int, int, char **);
+
+static const char *place = EMSG; /* option letter processing */
+
+/* XXX: set mowgli_optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1; /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+ int c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return b;
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end, char **nargv)
+{
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+ char *swap;
+
+ return_if_fail(nargv != NULL);
+
+ /*
+ * compute lengths of blocks and number and size of cycles
+ */
+ nnonopts = panonopt_end - panonopt_start;
+ nopts = opt_end - panonopt_end;
+ ncycle = gcd(nnonopts, nopts);
+ cyclelen = (opt_end - panonopt_start) / ncycle;
+
+ for (i = 0; i < ncycle; i++) {
+ cstart = panonopt_end+i;
+ pos = cstart;
+ for (j = 0; j < cyclelen; j++) {
+ if (pos >= panonopt_end)
+ pos -= nnonopts;
+ else
+ pos += nopts;
+ swap = nargv[pos];
+ nargv[pos] = nargv[cstart];
+ nargv[cstart] = swap;
+ }
+ }
+}
+
+/*
+ * getopt_internal --
+ * Parse argc/argv argument vector. Called by user level routines.
+ * Returns -2 if -- is found (can be long option or end of options marker).
+ */
+static int
+getopt_internal(int nargc, char **nargv, const char *options)
+{
+ char *oli; /* option letter list index */
+ int optchar;
+
+ return_val_if_fail(nargv != NULL, -1);
+ return_val_if_fail(options != NULL, -1);
+
+ mowgli_optarg = NULL;
+
+ /*
+ * XXX Some programs (like rsyncd) expect to be able to
+ * XXX re-initialize mowgli_optind to 0 and have getopt_long(3)
+ * XXX properly function again. Work around this braindamage.
+ */
+ if (mowgli_optind == 0)
+ mowgli_optind = 1;
+
+ if (mowgli_optreset)
+ nonopt_start = nonopt_end = -1;
+start:
+ if (mowgli_optreset || !*place) { /* update scanning pointer */
+ mowgli_optreset = 0;
+ if (mowgli_optind >= nargc) { /* end of argument vector */
+ place = EMSG;
+ if (nonopt_end != -1) {
+ /* do permutation, if we have to */
+ permute_args(nonopt_start, nonopt_end,
+ mowgli_optind, nargv);
+ mowgli_optind -= nonopt_end - nonopt_start;
+ }
+ else if (nonopt_start != -1) {
+ /*
+ * If we skipped non-options, set mowgli_optind
+ * to the first of them.
+ */
+ mowgli_optind = nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return -1;
+ }
+ if ((*(place = nargv[mowgli_optind]) != '-')
+ || (place[1] == '\0')) { /* found non-option */
+ place = EMSG;
+ if (IN_ORDER) {
+ /*
+ * GNU extension:
+ * return non-option as argument to option 1
+ */
+ mowgli_optarg = nargv[mowgli_optind++];
+ return INORDER;
+ }
+ if (!PERMUTE) {
+ /*
+ * if no permutation wanted, stop parsing
+ * at first non-option
+ */
+ return -1;
+ }
+ /* do permutation */
+ if (nonopt_start == -1)
+ nonopt_start = mowgli_optind;
+ else if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ mowgli_optind, nargv);
+ nonopt_start = mowgli_optind -
+ (nonopt_end - nonopt_start);
+ nonopt_end = -1;
+ }
+ mowgli_optind++;
+ /* process next argument */
+ goto start;
+ }
+ if (nonopt_start != -1 && nonopt_end == -1)
+ nonopt_end = mowgli_optind;
+ if (place[1] && *++place == '-') { /* found "--" */
+ place++;
+ return -2;
+ }
+ }
+ if ((optchar = (int)*place++) == (int)':' ||
+ (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
+ /* option letter unknown or ':' */
+ if (!*place)
+ ++mowgli_optind;
+ if (PRINT_ERROR)
+ warnx(illoptchar, optchar);
+ mowgli_optopt = optchar;
+ return BADCH;
+ }
+ if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
+ /* XXX: what if no long options provided (called by getopt)? */
+ if (*place)
+ return -2;
+
+ if (++mowgli_optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ mowgli_optopt = optchar;
+ return BADARG;
+ } else /* white space */
+ place = nargv[mowgli_optind];
+ /*
+ * Handle -W arg the same as --arg (which causes getopt to
+ * stop parsing).
+ */
+ return -2;
+ }
+ if (*++oli != ':') { /* doesn't take argument */
+ if (!*place)
+ ++mowgli_optind;
+ } else { /* takes (optional) argument */
+ mowgli_optarg = NULL;
+ if (*place) /* no white space */
+ mowgli_optarg = __UNCONST(place);
+ /* XXX: disable test for :: if PC? (GNU doesn't) */
+ else if (oli[1] != ':') { /* arg not optional */
+ if (++mowgli_optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ mowgli_optopt = optchar;
+ return BADARG;
+ } else
+ mowgli_optarg = nargv[mowgli_optind];
+ }
+ place = EMSG;
+ ++mowgli_optind;
+ }
+ /* dump back option letter */
+ return optchar;
+}
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the real getopt]
+ */
+int
+mowgli_getopt(nargc, nargv, options)
+ int nargc;
+ char * const *nargv;
+ const char *options;
+{
+ int retval;
+
+ return_val_if_fail(nargv != NULL, -1);
+ return_val_if_fail(options != NULL, -1);
+
+ retval = getopt_internal(nargc, __UNCONST(nargv), options);
+ if (retval == -2) {
+ ++mowgli_optind;
+ /*
+ * We found an option (--), so if we skipped non-options,
+ * we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end, mowgli_optind,
+ __UNCONST(nargv));
+ mowgli_optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ retval = -1;
+ }
+ return retval;
+}
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+mowgli_getopt_long(int nargc, char * const *nargv, const char *options,
+ const mowgli_getopt_option_t *long_options, int *idx)
+{
+ int retval;
+
+#define IDENTICAL_INTERPRETATION(_x, _y) \
+ (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
+ long_options[(_x)].flag == long_options[(_y)].flag && \
+ long_options[(_x)].val == long_options[(_y)].val)
+
+ return_val_if_fail(nargv != NULL, -1);
+ return_val_if_fail(options != NULL, -1);
+ return_val_if_fail(long_options != NULL, -1);
+ /* idx may be NULL */
+
+ retval = getopt_internal(nargc, __UNCONST(nargv), options);
+ if (retval == -2) {
+ char *current_argv, *has_equal;
+ size_t current_argv_len;
+ int i, ambiguous, match;
+
+ current_argv = __UNCONST(place);
+ match = -1;
+ ambiguous = 0;
+
+ mowgli_optind++;
+ place = EMSG;
+
+ if (*current_argv == '\0') { /* found "--" */
+ /*
+ * We found an option (--), so if we skipped
+ * non-options, we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ mowgli_optind, __UNCONST(nargv));
+ mowgli_optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return -1;
+ }
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ /* argument found (--option=arg) */
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ /* find matching long option */
+ if (strncmp(current_argv, long_options[i].name,
+ current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) ==
+ (unsigned)current_argv_len) {
+ /* exact match */
+ match = i;
+ ambiguous = 0;
+ break;
+ }
+ if (match == -1) /* partial match */
+ match = i;
+ else if (!IDENTICAL_INTERPRETATION(i, match))
+ ambiguous = 1;
+ }
+ if (ambiguous) {
+ /* ambiguous abbreviation */
+ if (PRINT_ERROR)
+ warnx(ambig, (int)current_argv_len,
+ current_argv);
+ mowgli_optopt = 0;
+ return BADCH;
+ }
+ if (match != -1) { /* option found */
+ if (long_options[match].has_arg == no_argument
+ && has_equal) {
+ if (PRINT_ERROR)
+ warnx(noarg, (int)current_argv_len,
+ current_argv);
+ /*
+ * XXX: GNU sets mowgli_optopt to val regardless of
+ * flag
+ */
+ if (long_options[match].flag == NULL)
+ mowgli_optopt = long_options[match].val;
+ else
+ mowgli_optopt = 0;
+ return BADARG;
+ }
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ mowgli_optarg = has_equal;
+ else if (long_options[match].has_arg ==
+ required_argument) {
+ /*
+ * optional argument doesn't use
+ * next nargv
+ */
+ mowgli_optarg = nargv[mowgli_optind++];
+ }
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (mowgli_optarg == NULL)) {
+ /*
+ * Missing argument; leading ':'
+ * indicates no error should be generated
+ */
+ if (PRINT_ERROR)
+ warnx(recargstring, current_argv);
+ /*
+ * XXX: GNU sets mowgli_optopt to val regardless
+ * of flag
+ */
+ if (long_options[match].flag == NULL)
+ mowgli_optopt = long_options[match].val;
+ else
+ mowgli_optopt = 0;
+ --mowgli_optind;
+ return BADARG;
+ }
+ } else { /* unknown option */
+ if (PRINT_ERROR)
+ warnx(illoptstring, current_argv);
+ mowgli_optopt = 0;
+ return BADCH;
+ }
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ retval = 0;
+ } else
+ retval = long_options[match].val;
+ if (idx)
+ *idx = match;
+ }
+ return retval;
+#undef IDENTICAL_INTERPRETATION
+}
diff --git a/src/libmowgli/ext/getopt_long.h b/src/libmowgli/ext/getopt_long.h
new file mode 100644
index 0000000..94c90a9
--- /dev/null
+++ b/src/libmowgli/ext/getopt_long.h
@@ -0,0 +1,69 @@
+/* $NetBSD: getopt.h,v 1.11 2008/04/28 20:22:54 martin Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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 _GETOPT_H_
+#define _GETOPT_H_
+
+/*
+ * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions
+ */
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+typedef struct {
+ /* name of long option */
+ const char *name;
+ /*
+ * one of no_argument, required_argument, and optional_argument:
+ * whether option takes an argument
+ */
+ int has_arg;
+ /* if not NULL, set *flag to val when option found */
+ int *flag;
+ /* if flag not NULL, value to set *flag to; else return value */
+ int val;
+ /* internal value */
+ int iflag;
+} mowgli_getopt_option_t;
+
+extern int mowgli_getopt(int nargc, char * const *nargv, const char *options);
+
+extern int mowgli_getopt_long(int, char * const *, const char *,
+ const mowgli_getopt_option_t *, int *);
+
+extern int mowgli_opterr;
+extern int mowgli_optind;
+extern int mowgli_optopt;
+extern int mowgli_optreset;
+extern char *mowgli_optarg;
+
+#endif /* !_GETOPT_H_ */
diff --git a/src/libmowgli/ext/global_storage.c b/src/libmowgli/ext/global_storage.c
new file mode 100644
index 0000000..4fec74d
--- /dev/null
+++ b/src/libmowgli/ext/global_storage.c
@@ -0,0 +1,69 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * global_storage.c: Simple key->value global storage tool.
+ *
+ * Copyright (c) 2007, 2011 William Pitcock <nenolod@dereferenced.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include "mowgli.h"
+
+static mowgli_patricia_t *mowgli_global_storage_dict = NULL;
+static mowgli_mutex_t mowgli_global_storage_lock;
+
+static void _storage_key_canon(char *key)
+{
+
+}
+
+void
+mowgli_global_storage_bootstrap(void)
+{
+ mowgli_global_storage_dict = mowgli_patricia_create(_storage_key_canon);
+
+ mowgli_mutex_init(&mowgli_global_storage_lock);
+}
+
+void *
+mowgli_global_storage_get(char *name)
+{
+ void *ret;
+
+ mowgli_mutex_lock(&mowgli_global_storage_lock);
+ ret = mowgli_patricia_retrieve(mowgli_global_storage_dict, name);
+ mowgli_mutex_unlock(&mowgli_global_storage_lock);
+
+ return ret;
+}
+
+void
+mowgli_global_storage_put(char *name, void *value)
+{
+ mowgli_mutex_lock(&mowgli_global_storage_lock);
+ mowgli_patricia_add(mowgli_global_storage_dict, name, value);
+ mowgli_mutex_unlock(&mowgli_global_storage_lock);
+}
+
+void
+mowgli_global_storage_free(char *name)
+{
+ mowgli_mutex_lock(&mowgli_global_storage_lock);
+ mowgli_patricia_delete(mowgli_global_storage_dict, name);
+ mowgli_mutex_unlock(&mowgli_global_storage_lock);
+}
+
diff --git a/src/libmowgli/ext/global_storage.h b/src/libmowgli/ext/global_storage.h
new file mode 100644
index 0000000..a26e699
--- /dev/null
+++ b/src/libmowgli/ext/global_storage.h
@@ -0,0 +1,32 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * global_storage.h: Simple key->value global storage tool.
+ *
+ * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 MOWGLI_GLOBAL_STORAGE_H
+#define MOWGLI_GLOBAL_STORAGE_H
+
+extern void mowgli_global_storage_bootstrap(void);
+extern void *mowgli_global_storage_get(char *name);
+extern void mowgli_global_storage_put(char *name, void *value);
+extern void mowgli_global_storage_free(char *name);
+
+#endif
diff --git a/src/libmowgli/ext/proctitle.c b/src/libmowgli/ext/proctitle.c
new file mode 100644
index 0000000..91885d5
--- /dev/null
+++ b/src/libmowgli/ext/proctitle.c
@@ -0,0 +1,311 @@
+/*
+ * Code has been calqued from PostgreSQL 9.1 by Elizabeth J. Myers.
+ * Below is their copyright header.
+ *
+ * Do note I've made extensive changes to this code, including adding
+ * Linux (and Irix?) prctl support.
+ */
+
+/*--------------------------------------------------------------------
+ * ps_status.c
+ *
+ * Routines to support changing the ps display of PostgreSQL backends
+ * to contain some useful information. Mechanism differs wildly across
+ * platforms.
+ *
+ * src/backend/utils/misc/ps_status.c
+ *
+ * Copyright (c) 2000-2011, PostgreSQL Global Development Group
+ * various details abducted from various places
+ *--------------------------------------------------------------------
+ */
+
+#include "mowgli.h"
+
+#ifdef HAVE_SYS_PSTAT_H
+#include <sys/pstat.h> /* for HP-UX */
+#endif
+#ifdef HAVE_PS_STRINGS
+#include <machine/vmparam.h> /* for old BSD */
+#include <sys/exec.h>
+#endif
+#if defined(__darwin__)
+#include <crt_externs.h>
+#endif
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
+extern char **environ;
+
+/*
+ * Alternative ways of updating ps display:
+ *
+ * MOWGLI_SETPROC_USE_SETPROCTITLE
+ * use the function setproctitle(const char *, ...)
+ * (newer BSD systems)
+ * MOWGLI_SETPROC_USE_PSTAT
+ * use the pstat(PSTAT_SETCMD, )
+ * (HPUX)
+ * MOWGLI_SETPROC_USE_PS_STRINGS
+ * assign PS_STRINGS->ps_argvstr = "string"
+ * (some BSD systems)
+ * MOWGLI_SETPROC_USE_PRCTL
+ * use prctl(PR_SET_NAME, ...)
+ * (Newer Linux and possibly Irix? -- Note some utilities don't use this name)
+ * MOWGLI_SETPROC_USE_CHANGE_ARGV
+ * assign argv[0] = "string"
+ * (some other BSD systems)
+ * MOWGLI_SETPROC_USE_CLOBBER_ARGV
+ * write over the argv and environment area
+ * (Old Linux and most SysV-like systems)
+ * MOWGLI_SETPROC_USE_WIN32
+ * push the string out as the name of a Windows event
+ * MOWGLI_SETPROC_USE_NONE
+ * don't update ps display
+ * (This is the default, as it is safest.)
+ */
+#if defined(HAVE_SETPROCTITLE)
+#define MOWGLI_SETPROC_USE_SETPROCTITLE
+#elif defined(PR_SET_NAME) && defined(HAVE_SYS_PRCTL_H)
+#define MOWGLI_SETPROC_USE_PRCTL
+#elif defined(HAVE_PSTAT) && defined(PSTAT_SETCMD)
+#define MOWGLI_SETPROC_USE_PSTAT
+#elif defined(HAVE_PS_STRINGS)
+#define MOWGLI_SETPROC_USE_PS_STRINGS
+#elif (defined(BSD) || defined(__bsdi__) || defined(__hurd__)) && !defined(__darwin__)
+#define MOWGLI_SETPROC_USE_CHANGE_ARGV
+#elif defined(__linux__) || defined(_AIX) || defined(__sgi) || (defined(sun) && !defined(BSD)) || defined(ultrix) || defined(__ksr__) || defined(__osf__) || defined(__svr4__) || defined(__svr5__) || defined(__darwin__)
+#define MOWGLI_SETPROC_USE_CLOBBER_ARGV
+#elif defined(WIN32)
+#define MOWGLI_SETPROC_USE_WIN32
+#else
+#define MOWGLI_SETPROC_USE_NONE
+#endif
+
+
+/* Different systems want the buffer padded differently */
+#if defined(_AIX) || defined(__linux__) || defined(__svr4__) || defined(__darwin__)
+#define PS_PADDING '\0'
+#else
+#define PS_PADDING ' '
+#endif
+
+
+#ifndef MOWGLI_SETPROC_USE_CLOBBER_ARGV
+/* all but one option need a buffer to write their ps line in */
+#define PS_BUFFER_SIZE 256
+static char ps_buffer[PS_BUFFER_SIZE];
+static const size_t ps_buffer_size = PS_BUFFER_SIZE;
+#else /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */
+static char *ps_buffer; /* will point to argv area */
+static size_t ps_buffer_size; /* space determined at run time */
+#endif /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */
+
+static size_t ps_buffer_fixed_size;
+static size_t ps_buffer_cur_len; /* nominal strlen(ps_buffer) */
+
+/* save the original argv[] location here */
+static int save_argc;
+static char **save_argv;
+
+/*
+ * Call this early in startup to save the original argc/argv values.
+ * If needed, we make a copy of the original argv[] array to preserve it
+ * from being clobbered by subsequent ps_display actions.
+ *
+ * (The original argv[] will not be overwritten by this routine, but may be
+ * overwritten during mowgli_proctitle_set. Also, the physical location of the
+ * environment strings may be moved, so this should be called before any code
+ * that might try to hang onto a getenv() result.)
+ */
+char **
+mowgli_proctitle_init(int argc, char **argv)
+{
+ save_argc = argc;
+ save_argv = argv;
+
+#if defined(MOWGLI_SETPROC_USE_CLOBBER_ARGV)
+
+ /*
+ * If we're going to overwrite the argv area, count the available space.
+ * Also move the environment to make additional room.
+ */
+ char *end_of_area = NULL;
+ char **new_environ;
+ int i;
+
+ /*
+ * check for contiguous argv strings
+ */
+ for (i = 0; i < argc; i++)
+ {
+ if (i == 0 || end_of_area + 1 == argv[i])
+ end_of_area = argv[i] + strlen(argv[i]);
+ }
+
+ if (end_of_area == NULL) /* probably can't happen? */
+ {
+ ps_buffer = NULL;
+ ps_buffer_size = 0;
+ return argv;
+ }
+
+ /*
+ * check for contiguous environ strings following argv
+ */
+ for (i = 0; environ[i] != NULL; i++)
+ {
+ if (end_of_area + 1 == environ[i])
+ end_of_area = environ[i] + strlen(environ[i]);
+ }
+
+ ps_buffer = argv[0];
+ ps_buffer_size = end_of_area - argv[0];
+
+ /*
+ * move the environment out of the way
+ */
+ new_environ = (char **) mowgli_alloc((i + 1) * sizeof(char *));
+ for (i = 0; environ[i] != NULL; i++)
+ new_environ[i] = mowgli_strdup(environ[i]);
+ new_environ[i] = NULL;
+ environ = new_environ;
+
+#endif /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */
+
+#if defined(MOWGLI_SETPROC_USE_CHANGE_ARGV) || defined(MOWGLI_SETPROC_USE_CLOBBER_ARGV)
+
+ /*
+ * If we're going to change the original argv[] then make a copy for
+ * argument parsing purposes.
+ *
+ * (NB: do NOT think to remove the copying of argv[].
+ * On some platforms, getopt() keeps pointers into the argv array, and will
+ * get horribly confused when it is re-called to analyze a subprocess'
+ * argument string if the argv storage has been clobbered meanwhile. Other
+ * platforms have other dependencies on argv[].
+ */
+
+ char **new_argv;
+ int i;
+
+ new_argv = (char **) mowgli_alloc((argc + 1) * sizeof(char *));
+ for (i = 0; i < argc; i++)
+ new_argv[i] = mowgli_strdup(argv[i]);
+ new_argv[argc] = NULL;
+
+#if defined(__darwin__)
+ /*
+ * Darwin (and perhaps other NeXT-derived platforms?) has a static
+ * copy of the argv pointer, which we may fix like so:
+ */
+ *_NSGetArgv() = new_argv;
+#endif
+
+ argv = new_argv;
+
+#endif /* MOWGLI_SETPROC_USE_CHANGE_ARGV or MOWGLI_SETPROC_USE_CLOBBER_ARGV */
+
+ return argv;
+}
+
+void
+mowgli_proctitle_set(const char *fmt, ...)
+{
+#ifndef MOWGLI_SETPROC_USE_NONE
+ va_list va;
+
+#if defined(MOWGLI_SETPROC_USE_CHANGE_ARGV) || defined(MOWGLI_SETPROC_USE_CLOBBER_ARGV)
+ if (!save_argv)
+ return;
+#endif
+
+ va_start(va, fmt);
+ vsnprintf(ps_buffer, ps_buffer_size, fmt, va);
+ va_end(va);
+
+ return_if_fail(*ps_buffer == '\0');
+
+ ps_buffer_cur_len = ps_buffer_fixed_size = strlen(ps_buffer);
+
+#ifdef MOWGLI_SETPROC_USE_CHANGE_ARGV
+ save_argv[0] = ps_buffer;
+ save_argv[1] = NULL;
+#endif
+
+#ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV
+ for (int i = 1; i < save_argc; i++)
+ save_argv[i] = ps_buffer + ps_buffer_size;
+
+ /* Pad unused bytes */
+ printf("%d %d\n", ps_buffer_size, ps_buffer_cur_len);
+ memset(ps_buffer + ps_buffer_cur_len, PS_PADDING, ps_buffer_size - ps_buffer_cur_len + 1);
+#endif
+
+#ifdef MOWGLI_SETPROC_USE_SETPROCTITLE
+ setproctitle("%s", ps_buffer);
+#endif
+
+#ifdef MOWGLI_SETPROC_USE_PRCTL
+ /* Limit us to 16 chars to be safe */
+ char procbuf[16];
+ mowgli_strlcpy(procbuf, ps_buffer, sizeof(procbuf));
+ prctl(PR_SET_NAME, procbuf, 0, 0, 0);
+ printf("%s\n", procbuf);
+#endif
+
+#ifdef MOWGLI_SETPROC_USE_PSTAT
+ union pstun pst;
+
+ pst.pst_command = ps_buffer;
+ pstat(PSTAT_SETCMD, pst, ps_buffer_cur_len, 0, 0);
+#endif /* MOWGLI_SETPROC_USE_PSTAT */
+
+#ifdef MOWGLI_SETPROC_USE_PS_STRINGS
+ PS_STRINGS->ps_nargvstr = 1;
+ PS_STRINGS->ps_argvstr = ps_buffer;
+#endif /* MOWGLI_SETPROC_USE_PS_STRINGS */
+
+#ifdef MOWGLI_SETPROC_USE_WIN32
+ /*
+ * Win32 does not support showing any changed arguments. To make it at
+ * all possible to track which backend is doing what, we create a
+ * named object that can be viewed with for example Process Explorer.
+ */
+ static HANDLE ident_handle = INVALID_HANDLE_VALUE;
+ char name[PS_BUFFER_SIZE + 32];
+
+ if (ident_handle != INVALID_HANDLE_VALUE)
+ CloseHandle(ident_handle);
+
+ sprintf(name, "mowgli_ident(%d): %s", getpid(), ps_buffer);
+
+ ident_handle = CreateEvent(NULL, TRUE, FALSE, name);
+#endif /* MOWGLI_SETPROC_USE_WIN32 */
+#endif /* not MOWGLI_SETPROC_USE_NONE */
+}
+
+
+/*
+ * Returns what's currently in the ps display, in case someone needs
+ * it. Note that only the activity part is returned. On some platforms
+ * the string will not be null-terminated, so return the effective
+ * length into *displen.
+ */
+const char *
+mowgli_proctitle_get(int *displen)
+{
+#ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV
+ /* If ps_buffer is a pointer, it might still be null */
+ if (!ps_buffer)
+ {
+ *displen = 0;
+ return "";
+ }
+#endif
+
+ *displen = (int) (ps_buffer_cur_len - ps_buffer_fixed_size);
+
+ return ps_buffer + ps_buffer_fixed_size;
+}
diff --git a/src/libmowgli/ext/proctitle.h b/src/libmowgli/ext/proctitle.h
new file mode 100644
index 0000000..479ee84
--- /dev/null
+++ b/src/libmowgli/ext/proctitle.h
@@ -0,0 +1,23 @@
+/*-------------------------------------------------------------------------
+ *
+ * ps_status.h
+ *
+ * Declarations for backend/utils/misc/ps_status.c
+ *
+ * src/include/utils/ps_status.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef __PS_STATUS_H__
+#define __PS_STATUS_H__
+
+extern bool mowgli_proctitle_update;
+
+extern char **mowgli_proctitle_init(int argc, char **argv);
+
+extern void mowgli_proctitle_set(const char *fmt, ...);
+
+extern const char *mowgli_proctitle_get(int *displen);
+
+#endif /* __PS_STATUS_H__ */
diff --git a/src/libmowgli/ext/program_opts.c b/src/libmowgli/ext/program_opts.c
new file mode 100644
index 0000000..75acd53
--- /dev/null
+++ b/src/libmowgli/ext/program_opts.c
@@ -0,0 +1,191 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * program_opts.h: Replacement for GNU getopt().
+ *
+ * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include "mowgli.h"
+
+#include "ext/getopt_long.h"
+
+void
+mowgli_program_opts_consumer_str(const char *arg, void *userdata)
+{
+ return_if_fail(arg != NULL);
+ return_if_fail(userdata != NULL);
+
+ *(char **) userdata = mowgli_strdup(arg);
+}
+
+void
+mowgli_program_opts_consumer_int(const char *arg, void *userdata)
+{
+ return_if_fail(arg != NULL);
+ return_if_fail(userdata != NULL);
+
+ *(int *) userdata = atoi(arg);
+}
+
+void
+mowgli_program_opts_consumer_bool(const char *arg, void *userdata)
+{
+ return_if_fail(arg != NULL);
+ return_if_fail(userdata != NULL);
+
+ *(bool *) userdata = true;
+}
+
+static inline mowgli_program_opts_t *
+mowgli_program_opts_lookup_name(mowgli_program_opts_t *opts, size_t opts_size, const char *name)
+{
+ size_t i;
+
+ if (strlen(name) > 1)
+ {
+ for (i = 0; i < opts_size; i++)
+ {
+ if (!strcasecmp(name, opts[i].longopt))
+ return &opts[i];
+ }
+ }
+ else
+ {
+ for (i = 0; i < opts_size; i++)
+ {
+ if (*name == opts[i].smallopt)
+ return &opts[i];
+ }
+ }
+
+ return NULL;
+}
+
+static inline mowgli_getopt_option_t *
+mowgli_program_opts_convert(const mowgli_program_opts_t *opts, size_t opts_size)
+{
+ mowgli_getopt_option_t *g_opts;
+ size_t i;
+
+ return_val_if_fail(opts != NULL, NULL);
+
+ g_opts = mowgli_alloc_array(sizeof(mowgli_getopt_option_t), opts_size);
+
+ for (i = 0; i < opts_size; i++)
+ {
+ if (opts[i].longopt == NULL)
+ continue;
+
+ g_opts[i].name = opts[i].longopt;
+ g_opts[i].iflag = i;
+ if (opts[i].has_param)
+ g_opts[i].has_arg = 1;
+ }
+
+ return g_opts;
+}
+
+static inline const char *
+mowgli_program_opts_compute_optstr(const mowgli_program_opts_t *opts, size_t opts_size)
+{
+ static char buf[256];
+ char *p = buf;
+ size_t i;
+
+ return_val_if_fail(opts != NULL, NULL);
+
+ memset(buf, '\0', sizeof buf);
+
+ for (i = 0; i < opts_size; i++)
+ {
+ if (!opts[i].smallopt)
+ continue;
+
+ *p++ = opts[i].smallopt;
+ if (opts[i].has_param)
+ *p++ = ':';
+ }
+
+ *p = '\0';
+
+ return buf;
+}
+
+static inline void
+mowgli_program_opts_dispatch(const mowgli_program_opts_t *opt, const char *optarg)
+{
+ return_if_fail(opt != NULL);
+
+ if (opt->has_param && optarg == NULL)
+ {
+ fprintf(stderr, "no optarg for option %s", opt->longopt);
+ return;
+ }
+
+ opt->consumer(optarg, opt->userdata);
+}
+
+void
+mowgli_program_opts_parse(const mowgli_program_opts_t *opts, size_t opts_size, int *argc, char ***argv)
+{
+ mowgli_getopt_option_t *g_opts;
+ const char *shortops;
+ int c;
+ size_t i;
+ int opt_index;
+
+ return_if_fail(opts != NULL);
+ return_if_fail(opts_size > 0);
+ return_if_fail(argc != NULL);
+ return_if_fail(argv != NULL);
+
+ g_opts = mowgli_program_opts_convert(opts, opts_size);
+ shortops = mowgli_program_opts_compute_optstr(opts, opts_size);
+
+ for (;;)
+ {
+ const mowgli_program_opts_t *opt = NULL;
+
+ c = mowgli_getopt_long(*argc, *argv, shortops, g_opts, &opt_index);
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ /* long-option was provided, resolve it. */
+ opt = &opts[g_opts[opt_index].iflag];
+ break;
+ default:
+ for (i = 0; i < opts_size; i++)
+ {
+ if (opts[i].smallopt == c)
+ {
+ opt = &opts[i];
+ break;
+ }
+ }
+ break;
+ }
+
+ mowgli_program_opts_dispatch(opt, mowgli_optarg);
+ }
+
+ mowgli_free(g_opts);
+}
diff --git a/src/libmowgli/ext/program_opts.h b/src/libmowgli/ext/program_opts.h
new file mode 100644
index 0000000..f418b96
--- /dev/null
+++ b/src/libmowgli/ext/program_opts.h
@@ -0,0 +1,50 @@
+/*
+ * libmowgli: A collection of useful routines for programming.
+ * program_opts.h: Replacement for GNU getopt().
+ *
+ * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice is present in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 __MOWGLI_PROGRAM_OPTS_H__
+#define __MOWGLI_PROGRAM_OPTS_H__
+
+typedef void (*mowgli_program_opts_consumer_t)(const char *arg, void *userdata);
+
+typedef struct {
+ const char *longopt;
+ const char smallopt;
+ bool has_param;
+ mowgli_program_opts_consumer_t consumer;
+ void *userdata;
+
+ /* optional data */
+ const char *description;
+ const char *paramname;
+} mowgli_program_opts_t;
+
+/* use when has_param is true */
+extern void mowgli_program_opts_consumer_str(const char *arg, void *userdata);
+extern void mowgli_program_opts_consumer_int(const char *arg, void *userdata);
+
+/* use when has_param is false */
+extern void mowgli_program_opts_consumer_bool(const char *arg, void *userdata);
+
+extern void mowgli_program_opts_parse(const mowgli_program_opts_t *opts, size_t opts_size, int *argc, char ***argv);
+
+#endif