summaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/base_cpudep.c221
-rw-r--r--base/base_error.c78
-rw-r--r--base/base_hash.c274
-rw-r--r--base/base_matrix.c151
-rw-r--r--base/base_memory.c91
-rw-r--r--base/base_rect.c75
-rw-r--r--base/base_rune.c168
-rw-r--r--base/util_getopt.c116
-rw-r--r--base/util_strlcat.c35
-rw-r--r--base/util_strlcpy.c32
-rw-r--r--base/util_strsep.c11
11 files changed, 1252 insertions, 0 deletions
diff --git a/base/base_cpudep.c b/base/base_cpudep.c
new file mode 100644
index 00000000..0db2e331
--- /dev/null
+++ b/base/base_cpudep.c
@@ -0,0 +1,221 @@
+/*
+run-time cpu feature detection code
+mm, alphabet soup...
+
+Glenn Kennard <d98gk@efd.lth.se>
+*/
+
+#include <fitz.h>
+
+/* global run-time constant */
+unsigned fz_cpuflags = 0;
+
+#ifndef HAVE_CPUDEP
+
+void fz_accelerate(void)
+{
+}
+
+void fz_cpudetect(void)
+{
+}
+
+#else
+
+#include <signal.h> /* signal/sigaction */
+#include <setjmp.h> /* sigsetjmp/siglongjmp */
+
+#ifdef WIN32
+#define sigjmp_buf jmp_buf
+#define sigsetjmp(a,b) setjmp(a)
+#define siglongjmp longjmp
+#endif
+
+typedef struct {
+ void (*test)(void);
+ const unsigned flag;
+ const char *name;
+} featuretest;
+
+
+#if defined(ARCH_X86) || defined(ARCH_X86_64)
+
+/* need emms?? */
+static void mmx(void)
+{ __asm__ ("pand %mm0, %mm0\n\t"); }
+
+static void m3dnow(void)
+{ __asm__ ("pavgusb %mm0, %mm0\n\t"); }
+
+static void mmxext(void) /* aka Extended 3DNow! */
+{ __asm__ ("pmaxsw %mm0, %mm0\n\t"); }
+
+static void sse(void)
+{ __asm__ ("andps %xmm0, %xmm0\n\t"); }
+
+static void sse2(void)
+{ __asm__ ("andpd %xmm0, %xmm0\n\t"); }
+
+/* static void sse3(void) */
+/* { __asm__ ("haddps %%xmm0, %%xmm0\n\t" : : : "%xmm0"); } */
+
+#ifdef ARCH_X86_64
+static void amd64(void)
+{ __asm__ ("and %rax, %rax\n\t"); }
+#endif
+
+
+static const featuretest features[] = {
+ { mmx, HAVE_MMX, "mmx" },
+ { m3dnow, HAVE_3DNOW, "3dnow" },
+ { mmxext, HAVE_MMXEXT, "mmxext" },
+ { sse, HAVE_SSE, "sse" },
+ { sse2, HAVE_SSE2, "sse2" },
+/* { sse3, HAVE_SSE3, "sse3" }, */
+#ifdef ARCH_X86_64
+ { amd64, HAVE_AMD64, "amd64" }
+#endif
+};
+
+#endif
+
+
+#if defined(ARCH_SPARC)
+/* assembler must have -xarch=v8plusa passed to it (v9a for 64 bit binaries) */
+static void vis(void)
+{ __asm__ ("fand %f8, %f8, %f8\n\t"); }
+
+static const featuretest features[] = {
+ { vis, HAVE_VIS, "vis" }
+};
+
+#endif
+
+
+#if defined(ARCH_PPC)
+
+static void altivec(void)
+{ __asm__ ("vand v0, v0, v0\n\t"); }
+
+
+static const featuretest features[] = {
+ { altivec, HAVE_ALTIVEC, "altivec" },
+};
+
+#endif
+
+static sigjmp_buf jmpbuf;
+static volatile sig_atomic_t canjump;
+
+static void
+sigillhandler(int sig)
+{
+ if (!canjump) {
+ signal(sig, SIG_DFL);
+ raise(sig);
+ }
+
+ canjump = 0;
+ siglongjmp(jmpbuf, 1);
+}
+
+static int
+enabled(char *env, const char *ext)
+{
+ int len;
+ char *s;
+ if (!env)
+ return 1;
+ len = strlen(ext);
+ while ((s = strstr(env, ext)))
+ {
+ s += len;
+ if (*s == ' ' || *s == ',' || *s == '\0')
+ return 1;
+ }
+ return 0;
+}
+
+static void
+dumpflags(void)
+{
+ unsigned f = fz_cpuflags;
+ int i, n;
+
+ fputs("detected cpu features:", stdout);
+ n = 0;
+ for (i = 0; i < sizeof(features) / sizeof(featuretest); i++)
+ {
+ if (f & features[i].flag)
+ {
+ fputc(' ', stdout);
+ fputs(features[i].name, stdout);
+ n ++;
+ }
+ }
+ if (!n)
+ fputs(" none", stdout);
+ fputc('\n', stdout);
+}
+
+void fz_cpudetect(void)
+{
+ static int hasrun = 0;
+
+ unsigned flags = 0;
+ int i;
+ void (*oldhandler)(int) = NULL;
+ void (*tmphandler)(int);
+ char *env;
+
+ if (hasrun)
+ return;
+ hasrun = 1;
+
+ env = getenv("CPUACCEL");
+
+ for (i = 0; i < sizeof(features) / sizeof(featuretest); i++)
+ {
+ canjump = 0;
+
+ tmphandler = signal(SIGILL, sigillhandler);
+ if (!oldhandler)
+ oldhandler = tmphandler;
+
+ if (sigsetjmp(jmpbuf, 1))
+ {
+ /* test failed - disable feature */
+ flags &= ~features[i].flag;
+ continue;
+ }
+
+ canjump = 1;
+
+ features[i].test();
+
+ /* if we got here the test succeeded */
+ if (enabled(env, features[i].name))
+ flags |= features[i].flag;
+ else
+ flags &= ~features[i].flag;
+ }
+
+ /* restore previous signal handler */
+ signal(SIGILL, oldhandler);
+
+ fz_cpuflags = flags;
+
+#if defined(ARCH_X86) || defined(ARCH_X86_64)
+ __asm__ __volatile__ ("emms\n\t");
+#endif
+
+ dumpflags();
+}
+
+static __attribute__((constructor, used)) void fzcpudetect(void)
+{
+ fz_cpudetect();
+}
+
+#endif
+
diff --git a/base/base_error.c b/base/base_error.c
new file mode 100644
index 00000000..926c48dc
--- /dev/null
+++ b/base/base_error.c
@@ -0,0 +1,78 @@
+#include <fitz.h>
+
+void
+fz_warn(char *fmt, ...)
+{
+ va_list ap;
+ fprintf(stderr, "warning: ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+fz_error *
+fz_throw1(char *fmt, ...)
+{
+ va_list ap;
+ fz_error *eo;
+
+ eo = fz_malloc(sizeof(fz_error));
+ if (!eo) return fz_outofmem;
+
+ eo->refs = 1;
+ strlcpy(eo->func, "unknown", sizeof eo->func);
+ strlcpy(eo->file, "unknown", sizeof eo->file);
+ eo->line = 0;
+
+ va_start(ap, fmt);
+ vsnprintf(eo->msg, sizeof eo->msg, fmt, ap);
+ eo->msg[sizeof(eo->msg) - 1] = '\0';
+ va_end(ap);
+
+ return eo;
+}
+
+fz_error *
+fz_throw0(const char *func, const char *file, int line, char *fmt, ...)
+{
+ va_list ap;
+ fz_error *eo;
+
+ eo = fz_malloc(sizeof(fz_error));
+ if (!eo) return fz_outofmem;
+
+ eo->refs = 1;
+ strlcpy(eo->func, func, sizeof eo->func);
+ strlcpy(eo->file, file, sizeof eo->file);
+ eo->line = line;
+
+ va_start(ap, fmt);
+ vsnprintf(eo->msg, sizeof eo->msg, fmt, ap);
+ eo->msg[sizeof(eo->msg) - 1] = '\0';
+ va_end(ap);
+
+ if (getenv("BOMB"))
+ fz_abort(eo);
+
+ return eo;
+}
+
+void
+fz_droperror(fz_error *eo)
+{
+ if (eo->refs > 0)
+ eo->refs--;
+ if (eo->refs == 0)
+ fz_free(eo);
+}
+
+void
+fz_abort(fz_error *eo)
+{
+ fflush(stdout);
+ fprintf(stderr, "%s:%d: %s(): %s\n", eo->file, eo->line, eo->func, eo->msg);
+ fflush(stderr);
+ abort();
+}
+
diff --git a/base/base_hash.c b/base/base_hash.c
new file mode 100644
index 00000000..65bc7130
--- /dev/null
+++ b/base/base_hash.c
@@ -0,0 +1,274 @@
+/* Linear probe hash table.
+ * 2004 (C) Tor Andersson.
+ * BSD license.
+ *
+ * Simple hashtable with open adressing linear probe.
+ * Unlike text book examples, removing entries works
+ * correctly in this implementation so it wont start
+ * exhibiting bad behaviour if entries are inserted
+ * and removed frequently.
+ */
+
+#include <fitz.h>
+
+enum { MAXKEYLEN = 16 };
+
+typedef struct fz_hashentry_s fz_hashentry;
+
+struct fz_hashentry_s
+{
+ unsigned char key[MAXKEYLEN];
+ void *val;
+};
+
+struct fz_hashtable_s
+{
+ int keylen;
+ int size;
+ int load;
+ fz_hashentry *ents;
+};
+
+static unsigned hash(unsigned char *s, int len)
+{
+ unsigned hash = 0;
+ int i;
+ for (i = 0; i < len; i++)
+ {
+ hash += s[i];
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+ return hash;
+}
+
+fz_error *
+fz_newhash(fz_hashtable **tablep, int initialsize, int keylen)
+{
+ fz_hashtable *table;
+
+ assert(keylen <= MAXKEYLEN);
+
+ table = *tablep = fz_malloc(sizeof(fz_hashtable));
+ if (!table)
+ return fz_outofmem;
+
+ table->keylen = keylen;
+ table->size = initialsize;
+ table->load = 0;
+
+ table->ents = fz_malloc(sizeof(fz_hashentry) * table->size);
+ if (!table->ents)
+ {
+ fz_free(table);
+ *tablep = nil;
+ return fz_outofmem;
+ }
+
+ memset(table->ents, 0, sizeof(fz_hashentry) * table->size);
+
+ return nil;
+}
+
+void
+fz_emptyhash(fz_hashtable *table)
+{
+ table->load = 0;
+ memset(table->ents, 0, sizeof(fz_hashentry) * table->size);
+}
+
+int
+fz_hashlen(fz_hashtable *table)
+{
+ return table->size;
+}
+
+void *
+fz_hashgetkey(fz_hashtable *table, int idx)
+{
+ return table->ents[idx].key;
+}
+
+void *
+fz_hashgetval(fz_hashtable *table, int idx)
+{
+ return table->ents[idx].val;
+}
+
+void
+fz_drophash(fz_hashtable *table)
+{
+ fz_free(table->ents);
+ fz_free(table);
+}
+
+fz_error *
+fz_resizehash(fz_hashtable *table, int newsize)
+{
+ fz_error *error;
+ fz_hashentry *newents;
+ fz_hashentry *oldents;
+ int oldload;
+ int oldsize;
+ int i;
+
+ oldsize = table->size;
+ oldload = table->load;
+ oldents = table->ents;
+
+ if (newsize < oldload * 8 / 10)
+ return fz_throw("rangecheck: resize hash too small");
+
+ newents = fz_malloc(sizeof(fz_hashentry) * newsize);
+ if (!newents)
+ return fz_outofmem;
+
+ table->size = newsize;
+ table->load = 0;
+ table->ents = newents;
+ memset(table->ents, 0, sizeof(fz_hashentry) * table->size);
+
+ for (i = 0; i < oldsize; i++)
+ {
+ if (oldents[i].val)
+ {
+ error = fz_hashinsert(table, oldents[i].key, oldents[i].val);
+ if (error)
+ {
+ table->size = oldsize;
+ table->load = oldload;
+ table->ents = oldents;
+ fz_free(newents);
+ return error;
+ }
+ }
+ }
+
+ fz_free(oldents);
+ return nil;
+}
+
+void *
+fz_hashfind(fz_hashtable *table, void *key)
+{
+ fz_hashentry *ents = table->ents;
+ unsigned size = table->size;
+ unsigned pos = hash(key, table->keylen) % size;
+
+ while (1)
+ {
+ if (!ents[pos].val)
+ return nil;
+
+ if (memcmp(key, &ents[pos].key, table->keylen) == 0)
+ return ents[pos].val;
+
+ pos = (pos + 1) % size;
+ }
+}
+
+fz_error *
+fz_hashinsert(fz_hashtable *table, void *key, void *val)
+{
+ fz_error *error;
+ fz_hashentry *ents;
+ unsigned size;
+ unsigned pos;
+
+ if (table->load > table->size * 8 / 10)
+ {
+ error = fz_resizehash(table, table->size * 2);
+ if (error)
+ return error;
+ }
+
+ ents = table->ents;
+ size = table->size;
+ pos = hash(key, table->keylen) % size;
+
+ while (1)
+ {
+ if (!ents[pos].val)
+ {
+ memcpy(ents[pos].key, key, table->keylen);
+ ents[pos].val = val;
+ table->load ++;
+ return nil;
+ }
+
+ if (memcmp(key, &ents[pos].key, table->keylen) == 0)
+ return fz_throw("rangecheck: overwrite hash slot");
+
+ pos = (pos + 1) % size;
+ }
+
+ return nil;
+}
+
+fz_error *
+fz_hashremove(fz_hashtable *table, void *key)
+{
+ fz_hashentry *ents = table->ents;
+ unsigned size = table->size;
+ unsigned pos = hash(key, table->keylen) % size;
+ unsigned hole, look, code;
+
+ while (1)
+ {
+ if (!ents[pos].val)
+ return fz_throw("rangecheck: remove inexistant hash entry");
+
+ if (memcmp(key, &ents[pos].key, table->keylen) == 0)
+ {
+ ents[pos].val = nil;
+
+ hole = pos;
+ look = (hole + 1) % size;
+
+ while (ents[look].val)
+ {
+ code = hash(ents[look].key, table->keylen) % size;
+ if ((code <= hole && hole < look) ||
+ (look < code && code <= hole) ||
+ (hole < look && look < code))
+ {
+ ents[hole] = ents[look];
+ ents[look].val = nil;
+ hole = look;
+ }
+
+ look = (look + 1) % size;
+ }
+
+ table->load --;
+ return nil;
+ }
+
+ pos = (pos + 1) % size;
+ }
+}
+
+void
+fz_debughash(fz_hashtable *table)
+{
+ int i, k;
+
+ printf("cache load %d / %d\n", table->load, table->size);
+
+ for (i = 0; i < table->size; i++)
+ {
+ if (!table->ents[i].val)
+ printf("table % 4d: empty\n", i);
+ else
+ {
+ printf("table % 4d: key=", i);
+ for (k = 0; k < MAXKEYLEN; k++)
+ printf("%02x", ((char*)table->ents[i].key)[k]);
+ printf(" val=$%p\n", table->ents[i].val);
+ }
+ }
+}
+
diff --git a/base/base_matrix.c b/base/base_matrix.c
new file mode 100644
index 00000000..e24196f9
--- /dev/null
+++ b/base/base_matrix.c
@@ -0,0 +1,151 @@
+#include <fitz.h>
+
+void fz_invert3x3(float *dst, float *m)
+{
+ float det;
+ int i;
+
+#define M3(m,i,j) (m)[3*i+j]
+#define D2(a,b,c,d) (a * d - b * c)
+#define D3(a1,a2,a3,b1,b2,b3,c1,c2,c3) \
+ (a1 * D2(b2,b3,c2,c3)) - \
+ (b1 * D2(a2,a3,c2,c3)) + \
+ (c1 * D2(a2,a3,b2,b3))
+
+ det = D3(M3(m,0,0), M3(m,1,0), M3(m,2,0),
+ M3(m,0,1), M3(m,1,1), M3(m,2,1),
+ M3(m,0,2), M3(m,1,2), M3(m,2,2));
+ if (det == 0)
+ det = 1.0;
+ det = 1.0 / det;
+
+ M3(dst,0,0) = M3(m,1,1) * M3(m,2,2) - M3(m,1,2) * M3(m,2,1);
+ M3(dst,0,1) = -M3(m,0,1) * M3(m,2,2) + M3(m,0,2) * M3(m,2,1);
+ M3(dst,0,2) = M3(m,0,1) * M3(m,1,2) - M3(m,0,2) * M3(m,1,1);
+
+ M3(dst,1,0) = -M3(m,1,0) * M3(m,2,2) + M3(m,1,2) * M3(m,2,0);
+ M3(dst,1,1) = M3(m,0,0) * M3(m,2,2) - M3(m,0,2) * M3(m,2,0);
+ M3(dst,1,2) = -M3(m,0,0) * M3(m,1,2) + M3(m,0,2) * M3(m,1,0);
+
+ M3(dst,2,0) = M3(m,1,0) * M3(m,2,1) - M3(m,1,1) * M3(m,2,0);
+ M3(dst,2,1) = -M3(m,0,0) * M3(m,2,1) + M3(m,0,1) * M3(m,2,0);
+ M3(dst,2,2) = M3(m,0,0) * M3(m,1,1) - M3(m,0,1) * M3(m,1,0);
+
+ for (i = 0; i < 9; i++)
+ dst[i] *= det;
+}
+
+fz_matrix
+fz_concat(fz_matrix one, fz_matrix two)
+{
+ fz_matrix dst;
+ dst.a = one.a * two.a + one.b * two.c;
+ dst.b = one.a * two.b + one.b * two.d;
+ dst.c = one.c * two.a + one.d * two.c;
+ dst.d = one.c * two.b + one.d * two.d;
+ dst.e = one.e * two.a + one.f * two.c + two.e;
+ dst.f = one.e * two.b + one.f * two.d + two.f;
+ return dst;
+}
+
+fz_matrix
+fz_identity(void)
+{
+ fz_matrix m;
+ m.a = 1; m.b = 0;
+ m.c = 0; m.d = 1;
+ m.e = 0; m.f = 0;
+ return m;
+}
+
+fz_matrix
+fz_scale(float sx, float sy)
+{
+ fz_matrix m;
+ m.a = sx; m.b = 0;
+ m.c = 0; m.d = sy;
+ m.e = 0; m.f = 0;
+ return m;
+}
+
+fz_matrix
+fz_rotate(float theta)
+{
+ fz_matrix m;
+ float s = sin(theta * M_PI / 180.0);
+ float c = cos(theta * M_PI / 180.0);
+ m.a = c; m.b = s;
+ m.c = -s; m.d = c;
+ m.e = 0; m.f = 0;
+ return m;
+}
+
+fz_matrix
+fz_translate(float tx, float ty)
+{
+ fz_matrix m;
+ m.a = 1; m.b = 0;
+ m.c = 0; m.d = 1;
+ m.e = tx; m.f = ty;
+ return m;
+}
+
+fz_matrix
+fz_invertmatrix(fz_matrix src)
+{
+ fz_matrix dst;
+ float rdet = 1.0 / (src.a * src.d - src.b * src.c);
+ dst.a = src.d * rdet;
+ dst.b = -src.b * rdet;
+ dst.c = -src.c * rdet;
+ dst.d = src.a * rdet;
+ dst.e = -src.e * dst.a - src.f * dst.c;
+ dst.f = -src.e * dst.b - src.f * dst.d;
+ return dst;
+}
+
+int
+fz_isrectilinear(fz_matrix m)
+{
+ return (fabs(m.b) < FLT_EPSILON && fabs(m.c) < FLT_EPSILON) ||
+ (fabs(m.a) < FLT_EPSILON && fabs(m.d) < FLT_EPSILON);
+}
+
+float
+fz_matrixexpansion(fz_matrix m)
+{
+ return sqrt(fabs(m.a * m.d - m.b * m.c));
+}
+
+fz_point
+fz_transformpoint(fz_matrix m, fz_point p)
+{
+ fz_point t;
+ t.x = p.x * m.a + p.y * m.c + m.e;
+ t.y = p.x * m.b + p.y * m.d + m.f;
+ return t;
+}
+
+fz_rect
+fz_transformaabb(fz_matrix m, fz_rect r)
+{
+ fz_point s, t, u, v;
+
+ if (fz_isinfiniterect(r))
+ return r;
+
+ s.x = r.x0; s.y = r.y0;
+ t.x = r.x0; t.y = r.y1;
+ u.x = r.x1; u.y = r.y1;
+ v.x = r.x1; v.y = r.y0;
+ s = fz_transformpoint(m, s);
+ t = fz_transformpoint(m, t);
+ u = fz_transformpoint(m, u);
+ v = fz_transformpoint(m, v);
+ r.x0 = MIN4(s.x, t.x, u.x, v.x);
+ r.y0 = MIN4(s.y, t.y, u.y, v.y);
+ r.x1 = MAX4(s.x, t.x, u.x, v.x);
+ r.y1 = MAX4(s.y, t.y, u.y, v.y);
+ return r;
+}
+
diff --git a/base/base_memory.c b/base/base_memory.c
new file mode 100644
index 00000000..48988dbc
--- /dev/null
+++ b/base/base_memory.c
@@ -0,0 +1,91 @@
+#include <fitz.h>
+
+/* Make this thread local storage if you wish. */
+
+static void *stdmalloc(fz_memorycontext *mem, int n)
+{
+#if 0
+ void *p = malloc(n);
+ if (!p)
+ fprintf(stderr, "failed to malloc %d bytes\n", n);
+ return p;
+#else
+ return malloc(n);
+#endif
+}
+
+static void *stdrealloc(fz_memorycontext *mem, void *p, int n)
+{
+#if 0
+ void *np = realloc(p, n);
+ if (np == nil)
+ fprintf(stderr, "realloc failed %d nytes", n);
+ else if (np == p)
+ fprintf(stderr, "realloc kept %d\n", n);
+ else
+ fprintf(stderr, "realloc moved %d\n", n);
+ return np;
+#else
+ return realloc(p, n);
+#endif
+}
+
+static void stdfree(fz_memorycontext *mem, void *p)
+{
+ free(p);
+}
+
+static fz_memorycontext defmem = { stdmalloc, stdrealloc, stdfree };
+static fz_memorycontext *curmem = &defmem;
+
+fz_error fz_koutofmem = {
+ -1,
+ {"out of memory"},
+ {"<malloc>"},
+ {"memory.c"},
+ 0
+};
+
+fz_memorycontext *
+fz_currentmemorycontext()
+{
+ return curmem;
+}
+
+void
+fz_setmemorycontext(fz_memorycontext *mem)
+{
+ curmem = mem;
+}
+
+void *
+fz_malloc(int n)
+{
+ fz_memorycontext *mem = fz_currentmemorycontext();
+ return mem->malloc(mem, n);
+}
+
+void *
+fz_realloc(void *p, int n)
+{
+ fz_memorycontext *mem = fz_currentmemorycontext();
+ return mem->realloc(mem, p, n);
+}
+
+void
+fz_free(void *p)
+{
+ fz_memorycontext *mem = fz_currentmemorycontext();
+ mem->free(mem, p);
+}
+
+char *
+fz_strdup(char *s)
+{
+ int len = strlen(s);
+ char *ns = fz_malloc(len + 1);
+ if (ns)
+ strcpy(ns, s);
+ return ns;
+}
+
diff --git a/base/base_rect.c b/base/base_rect.c
new file mode 100644
index 00000000..18acb952
--- /dev/null
+++ b/base/base_rect.c
@@ -0,0 +1,75 @@
+#include <fitz.h>
+
+fz_rect fz_infiniterect = { 1, 1, -1, -1 };
+fz_rect fz_emptyrect = { 0, 0, 0, 0 };
+
+static fz_irect infinite = { 1, 1, -1, -1 };
+static fz_irect empty = { 0, 0, 0, 0 };
+
+fz_irect
+fz_roundrect(fz_rect f)
+{
+ fz_irect i;
+ i.x0 = fz_floor(f.x0);
+ i.y0 = fz_floor(f.y0);
+ i.x1 = fz_ceil(f.x1);
+ i.y1 = fz_ceil(f.y1);
+ return i;
+}
+
+fz_rect
+fz_intersectrects(fz_rect a, fz_rect b)
+{
+ fz_rect r;
+ if (fz_isinfiniterect(a)) return b;
+ if (fz_isinfiniterect(b)) return a;
+ r.x0 = MAX(a.x0, b.x0);
+ r.y0 = MAX(a.y0, b.y0);
+ r.x1 = MIN(a.x1, b.x1);
+ r.y1 = MIN(a.y1, b.y1);
+ return (r.x1 < r.x0 || r.y1 < r.y0) ? fz_emptyrect : r;
+}
+
+fz_rect
+fz_mergerects(fz_rect a, fz_rect b)
+{
+ fz_rect r;
+ if (fz_isinfiniterect(a) || fz_isinfiniterect(b))
+ return fz_infiniterect;
+ if (fz_isemptyrect(a)) return b;
+ if (fz_isemptyrect(b)) return a;
+ r.x0 = MIN(a.x0, b.x0);
+ r.y0 = MIN(a.y0, b.y0);
+ r.x1 = MAX(a.x1, b.x1);
+ r.y1 = MAX(a.y1, b.y1);
+ return r;
+}
+
+fz_irect
+fz_intersectirects(fz_irect a, fz_irect b)
+{
+ fz_irect r;
+ if (fz_isinfiniterect(a)) return b;
+ if (fz_isinfiniterect(b)) return a;
+ r.x0 = MAX(a.x0, b.x0);
+ r.y0 = MAX(a.y0, b.y0);
+ r.x1 = MIN(a.x1, b.x1);
+ r.y1 = MIN(a.y1, b.y1);
+ return (r.x1 < r.x0 || r.y1 < r.y0) ? empty : r;
+}
+
+fz_irect
+fz_mergeirects(fz_irect a, fz_irect b)
+{
+ fz_irect r;
+ if (fz_isinfiniterect(a) || fz_isinfiniterect(b))
+ return infinite;
+ if (fz_isemptyrect(a)) return b;
+ if (fz_isemptyrect(b)) return a;
+ r.x0 = MIN(a.x0, b.x0);
+ r.y0 = MIN(a.y0, b.y0);
+ r.x1 = MAX(a.x1, b.x1);
+ r.y1 = MAX(a.y1, b.y1);
+ return r;
+}
+
diff --git a/base/base_rune.c b/base/base_rune.c
new file mode 100644
index 00000000..4aa81df3
--- /dev/null
+++ b/base/base_rune.c
@@ -0,0 +1,168 @@
+enum
+{
+ UTFmax = 3, /* maximum bytes per rune */
+ Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
+ Runeself = 0x80, /* rune and UTF sequences are the same (<) */
+ Runeerror = 0x80 /* decoding error in UTF */
+};
+
+enum
+{
+ Bit1 = 7,
+ Bitx = 6,
+ Bit2 = 5,
+ Bit3 = 4,
+ Bit4 = 3,
+
+ T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
+ Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
+ T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
+ T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
+ T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
+
+ Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */
+ Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */
+ Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */
+
+ Maskx = (1<<Bitx)-1, /* 0011 1111 */
+ Testx = Maskx ^ 0xFF, /* 1100 0000 */
+
+ Bad = Runeerror
+};
+
+int
+chartorune(int *rune, char *str)
+{
+ int c, c1, c2;
+ int l;
+
+ /*
+ * one character sequence
+ * 00000-0007F => T1
+ */
+ c = *(unsigned char*)str;
+ if(c < Tx) {
+ *rune = c;
+ return 1;
+ }
+
+ /*
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ */
+ c1 = *(unsigned char*)(str+1) ^ Tx;
+ if(c1 & Testx)
+ goto bad;
+ if(c < T3) {
+ if(c < T2)
+ goto bad;
+ l = ((c << Bitx) | c1) & Rune2;
+ if(l <= Rune1)
+ goto bad;
+ *rune = l;
+ return 2;
+ }
+
+ /*
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ */
+ c2 = *(unsigned char*)(str+2) ^ Tx;
+ if(c2 & Testx)
+ goto bad;
+ if(c < T4) {
+ l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
+ if(l <= Rune2)
+ goto bad;
+ *rune = l;
+ return 3;
+ }
+
+ /*
+ * bad decoding
+ */
+bad:
+ *rune = Bad;
+ return 1;
+}
+
+int
+runetochar(char *str, int *rune)
+{
+ int c;
+
+ /*
+ * one character sequence
+ * 00000-0007F => 00-7F
+ */
+ c = *rune;
+ if(c <= Rune1) {
+ str[0] = c;
+ return 1;
+ }
+
+ /*
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ */
+ if(c <= Rune2) {
+ str[0] = T2 | (c >> 1*Bitx);
+ str[1] = Tx | (c & Maskx);
+ return 2;
+ }
+
+ /*
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ */
+ str[0] = T3 | (c >> 2*Bitx);
+ str[1] = Tx | ((c >> 1*Bitx) & Maskx);
+ str[2] = Tx | (c & Maskx);
+ return 3;
+}
+
+int
+runelen(int c)
+{
+ int rune;
+ char str[10];
+
+ rune = c;
+ return runetochar(str, &rune);
+}
+
+int
+runenlen(int *r, int nrune)
+{
+ int nb, c;
+
+ nb = 0;
+ while(nrune--) {
+ c = *r++;
+ if(c <= Rune1)
+ nb++;
+ else
+ if(c <= Rune2)
+ nb += 2;
+ else
+ nb += 3;
+ }
+ return nb;
+}
+
+int
+fullrune(char *str, int n)
+{
+ int c;
+
+ if(n > 0) {
+ c = *(unsigned char*)str;
+ if(c < Tx)
+ return 1;
+ if(n > 1)
+ if(c < T3 || n > 2)
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/base/util_getopt.c b/base/util_getopt.c
new file mode 100644
index 00000000..c870e206
--- /dev/null
+++ b/base/util_getopt.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 4.13 (Berkeley) 2/23/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * get option letter from argument vector
+ */
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt; /* character checked for validity */
+char *optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define EMSG ""
+
+int getopt(int nargc, char * const * nargv, const char *ostr)
+{
+ static char *place = EMSG; /* option letter processing */
+ register char *oli; /* option letter list index */
+ char *p;
+
+ if (!*place) { /* update scanning pointer */
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return(EOF);
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ ++optind;
+ place = EMSG;
+ return(EOF);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = strchr(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means EOF.
+ */
+ if (optopt == (int)'-')
+ return(EOF);
+ if (!*place)
+ ++optind;
+ if (opterr) {
+ if (!(p = strrchr(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ (void)fprintf(stderr, "%s: illegal option -- %c\n",
+ p, optopt);
+ }
+ return(BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if (!(p = strrchr(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ p, optopt);
+ return(BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return(optopt); /* dump back option letter */
+}
diff --git a/base/util_strlcat.c b/base/util_strlcat.c
new file mode 100644
index 00000000..c659b73a
--- /dev/null
+++ b/base/util_strlcat.c
@@ -0,0 +1,35 @@
+/* Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+
+#include <string.h>
+
+int strlcat(char *dst, const char *src, int siz)
+{
+ register char *d = dst;
+ register const char *s = src;
+ register int n = siz;
+ int dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (*d != '\0' && n-- != 0)
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return dlen + strlen(s);
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return dlen + (s - src); /* count does not include NUL */
+}
+
diff --git a/base/util_strlcpy.c b/base/util_strlcpy.c
new file mode 100644
index 00000000..73416ae1
--- /dev/null
+++ b/base/util_strlcpy.c
@@ -0,0 +1,32 @@
+/* Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+
+#include <string.h>
+
+int strlcpy(char *dst, const char *src, int siz)
+{
+ register char *d = dst;
+ register const char *s = src;
+ register int n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+
diff --git a/base/util_strsep.c b/base/util_strsep.c
new file mode 100644
index 00000000..e54903ce
--- /dev/null
+++ b/base/util_strsep.c
@@ -0,0 +1,11 @@
+#include <string.h>
+
+char *strsep(char **stringp, const char *delim)
+{
+ char *ret = *stringp;
+ if (ret == NULL) return NULL;
+ if ((*stringp = strpbrk(*stringp, delim)) != NULL)
+ *((*stringp)++) = '\0';
+ return ret;
+}
+