]> mj.ucw.cz Git - libucw.git/commitdiff
Initial revision
authorMartin Mares <mj@ucw.cz>
Wed, 9 Apr 1997 07:55:49 +0000 (07:55 +0000)
committerMartin Mares <mj@ucw.cz>
Wed, 9 Apr 1997 07:55:49 +0000 (07:55 +0000)
19 files changed:
lib/alloc.c [new file with mode: 0644]
lib/alloc_str.c [new file with mode: 0644]
lib/config.h [new file with mode: 0644]
lib/ctmatch.c [new file with mode: 0644]
lib/lib.h [new file with mode: 0644]
lib/lists.c [new file with mode: 0644]
lib/lists.h [new file with mode: 0644]
lib/log.c [new file with mode: 0644]
lib/log.h [new file with mode: 0644]
lib/log2.c [new file with mode: 0644]
lib/md5.c [new file with mode: 0644]
lib/md5.h [new file with mode: 0644]
lib/patmatch.c [new file with mode: 0644]
lib/str_ctype.c [new file with mode: 0644]
lib/str_upper.c [new file with mode: 0644]
lib/temp.c [new file with mode: 0644]
lib/url.c [new file with mode: 0644]
lib/url.h [new file with mode: 0644]
lib/wordsplit.c [new file with mode: 0644]

diff --git a/lib/alloc.c b/lib/alloc.c
new file mode 100644 (file)
index 0000000..6559466
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *     Sherlock Library -- Memory Allocation
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lib.h"
+
+void *
+xmalloc(uns size)
+{
+  void *x = malloc(size);
+  if (!x)
+       die("Cannot allocate %d bytes of memory", size);
+  return x;
+}
diff --git a/lib/alloc_str.c b/lib/alloc_str.c
new file mode 100644 (file)
index 0000000..7c9f92d
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *     Sherlock Library -- String Allocation
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "lib.h"
+
+byte *
+stralloc(byte *s)
+{
+  uns l = strlen(s);
+  byte *k = xmalloc(l + 1);
+  strcpy(k, s);
+  return k;
+}
diff --git a/lib/config.h b/lib/config.h
new file mode 100644 (file)
index 0000000..8b09c82
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *     Sherlock Library -- Configuration-Dependent Definitions
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+/* Version */
+
+#define SHER_VER "0.1"
+
+/* Types */
+
+typedef unsigned char byte;            /* exactly 8 bits, unsigned */
+typedef signed char sbyte;             /* exactly 8 bits, signed */
+typedef unsigned short word;           /* exactly 16 bits, unsigned */
+typedef short sword;                   /* exactly 16 bits, signed */
+typedef unsigned int ulg;              /* exactly 32 bits, unsigned */
+typedef int slg;                       /* exactly 32 bits, signed */
+typedef unsigned int uns;              /* at least 32 bits */
+
+/* Misc */
+
+#ifdef __GNUC__
+
+#undef inline
+#define NONRET __attribute__((noreturn))
+
+#else
+
+#define inline
+#define NONRET
+
+#endif
+
+#ifdef linux
+#define HAVE_FFS
+#endif
diff --git a/lib/ctmatch.c b/lib/ctmatch.c
new file mode 100644 (file)
index 0000000..7a7d967
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *     Sherlock Library -- Content-Type Pattern Matching
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <stdio.h>
+
+#include "lib.h"
+#include "string.h"
+
+int
+match_ct_patt(byte *p, byte *t)
+{
+  if (*p == '*' && !p[1])              /* "*" matches everything */
+    return 1;
+
+  if (*p == '*' && p[1] == '/')                /* "*" on the left-hand side */
+    {
+      while (*t && *t != ' ' && *t != ';' && *t != '/')
+       t++;
+      p += 2;
+    }
+  else                                 /* Normal left-hand side */
+    {
+      while (*p != '/')
+       if (Cupcase(*p++) != Cupcase(*t++))
+         return 0;
+      p++;
+    }
+  if (*t != '/')
+    return 0;
+
+  if (*p == '*' && p[1] == '/')                /* "*" on the right-hand side */
+    return 1;
+  while (*p)
+    if (Cupcase(*p++) != Cupcase(*t++))
+      return 0;
+  if (*t && *t != ' ' && *t != ';')
+    return 0;
+
+  return 1;
+}
diff --git a/lib/lib.h b/lib/lib.h
new file mode 100644 (file)
index 0000000..e58e52a
--- /dev/null
+++ b/lib/lib.h
@@ -0,0 +1,109 @@
+/*
+ *     Sherlock Library -- Miscellaneous Functions
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <lib/config.h>
+
+/* Temporary Files */
+
+#define TMP_DIR "tmp"
+#define TMP_DIR_LEN 3
+
+struct tempfile {
+  int fh;
+  byte name[32];
+};
+
+void open_temp(struct tempfile *, byte *);
+void delete_temp(struct tempfile *);
+ulg temprand(uns);
+
+#define TF_GENERIC "t"
+#define TF_QUEUE_CONTROL "c"
+#define TF_QUEUE_DATA "d"
+
+/* Config Files */
+
+struct cfitem {
+  byte *name;
+  int type;
+  void *var;
+};
+
+#define CI_STOP 0
+#define CI_INT 1
+#define CI_STRING 2
+#define CI_FUNCTION 3
+
+typedef byte *(*ci_func)(struct cfitem *, byte *);
+
+void cf_read(byte *, struct cfitem *);
+
+/* Logging */
+
+#define L_DEBUG "<0>"
+#define L_INFO "<2>"
+#define L_WARN "<4>"
+#define L_ERROR "<6>"
+#define L_FATAL "<9>"
+
+void log(byte *, ...);
+void die(byte *, ...) NONRET;
+void initlog(byte *);
+
+/* Allocation */
+
+void *xmalloc(uns);
+byte *stralloc(byte *);
+
+/* Content-Type pattern matching */
+
+int match_ct_patt(byte *, byte *);
+
+/* Binary log */
+
+#ifdef HAVE_FFS
+#define log2(x) (ffs(x) - 1)
+#else
+int log2(ulg);
+#endif
+
+/* obj.c */
+
+struct odes {                          /* Object description */
+  struct oattr *attrs;
+};
+
+struct oattr {                         /* Object attribute */
+  struct oattr *next, *same;
+  byte attr;
+  byte val[1];
+};
+
+void obj_dump(struct odes *);
+struct odes *obj_fload(FILE *);
+struct odes *obj_new(void);
+struct odes *obj_load(byte *);
+void obj_fwrite(FILE *, struct odes *);        /* Closes the file afterwards... */
+void obj_free(struct odes *);
+struct oattr *find_attr(struct odes *, uns);
+struct oattr *find_attr_last(struct odes *, uns);
+byte *find_aval(struct odes *, uns);
+struct oattr *set_attr(struct odes *, uns, byte *);
+struct oattr *set_attr_num(struct odes *, uns, uns);
+struct oattr *add_attr(struct odes *, struct oattr *, uns, byte *);
+
+/* oname.c */
+
+void mk_obj_name(byte *, ulg, byte *);
+FILE *create_obj_file(byte *, ulg);
+
+/* wordsplit.c */
+
+int wordsplit(byte *, byte **, uns);
+
+/* patmatch.c */
+
+int match_pattern(byte *, byte *);
diff --git a/lib/lists.c b/lib/lists.c
new file mode 100644 (file)
index 0000000..b0d611d
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *     Sherlock Library -- Linked Lists
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <stdio.h>
+
+#include "lists.h"
+
+void
+add_tail(list *l, node *n)
+{
+  node *z = l->tail.prev;
+
+  n->next = &l->tail;
+  n->prev = z;
+  z->next = n;
+  l->tail.prev = n;
+}
+
+void
+add_head(list *l, node *n)
+{
+  node *z = l->head.next;
+
+  n->next = z;
+  n->prev = &l->head;
+  z->prev = n;
+  l->head.next = n;
+}
+
+void
+insert_node(node *n, node *after)
+{
+  node *z = after->next;
+
+  n->next = z;
+  n->prev = after;
+  after->next = n;
+  z->prev = n;
+}
+
+void
+rem_node(node *n)
+{
+  node *z = n->prev;
+  node *x = n->next;
+
+  z->next = x;
+  x->prev = z;
+}
+
+void
+init_list(list *l)
+{
+  l->head.next = &l->tail;
+  l->head.prev = NULL;
+  l->tail.next = NULL;
+  l->tail.prev = &l->head;
+}
+
+void
+add_tail_list(list *to, list *l)
+{
+  node *p = to->tail.prev;
+  node *q = l->head.next;
+
+  p->next = q;
+  q->prev = p;
+  q = l->tail.prev;
+  q->next = &to->tail;
+  to->tail.prev = q;
+}
diff --git a/lib/lists.h b/lib/lists.h
new file mode 100644 (file)
index 0000000..4f60569
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ *     Sherlock Library -- Linked Lists
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+struct node {
+  struct node *next, *prev;
+};
+typedef struct node node;
+
+struct list {
+  struct node head, tail;
+};
+typedef struct list list;
+
+#define NODE (node *)
+#define HEAD(list) ((void *)((list).head.next))
+#define TAIL(list) ((void *)((list).tail.prev))
+#define DO_FOR_ALL(n,list) for((n)=HEAD(list);(NODE (n))->next; \
+                                n=(void *)((NODE (n))->next))
+#define EMPTY_LIST(list) (!(list).head.next->next)
+
+void add_tail(list *, node *);
+void add_head(list *, node *);
+void rem_node(node *);
+void add_tail_list(list *, list *);
+void init_list(list *);
+void insert_node(node *, node *);
+
+#ifdef __GNUC__
+
+extern inline void
+add_tail(list *l, node *n)
+{
+  node *z = l->tail.prev;
+
+  n->next = &l->tail;
+  n->prev = z;
+  z->next = n;
+  l->tail.prev = n;
+}
+
+extern inline void
+add_head(list *l, node *n)
+{
+  node *z = l->head.next;
+
+  n->next = z;
+  n->prev = &l->head;
+  z->prev = n;
+  l->head.next = n;
+}
+
+extern inline void
+insert_node(node *n, node *after)
+{
+  node *z = after->next;
+
+  n->next = z;
+  n->prev = after;
+  after->next = n;
+  z->prev = n;
+}
+
+extern inline void
+rem_node(node *n)
+{
+  node *z = n->prev;
+  node *x = n->next;
+
+  z->next = x;
+  x->prev = z;
+}
+
+extern inline void
+init_list(list *l)
+{
+  l->head.next = &l->tail;
+  l->head.prev = NULL;
+  l->tail.next = NULL;
+  l->tail.prev = &l->head;
+}
+
+extern inline void
+add_tail_list(list *to, list *l)
+{
+  node *p = to->tail.prev;
+  node *q = l->head.next;
+
+  p->next = q;
+  q->prev = p;
+  q = l->tail.prev;
+  q->next = &to->tail;
+  to->tail.prev = q;
+}
+
+#endif
diff --git a/lib/log.c b/lib/log.c
new file mode 100644 (file)
index 0000000..267270a
--- /dev/null
+++ b/lib/log.c
@@ -0,0 +1,77 @@
+/*
+ *     Sherlock Library -- Logging
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "lib.h"
+
+static byte *progname = "???";
+static pid_t pid;
+
+static void
+logit(int level, byte *msg, va_list args)
+{
+  time_t tim;
+  struct tm *tm;
+  char buf[32];
+
+  tim = time(NULL);
+  tm = localtime(&tim);
+  strftime(buf, sizeof(buf), "%d-%m-%y %H-%M-%S", tm);
+  fprintf(stderr, "%s %s [%d] <%d> ", buf, progname, pid, level);
+  vfprintf(stderr, msg, args);
+  fputc('\n', stderr);
+  fflush(stderr);
+}
+
+void
+log(byte *msg, ...)
+{
+  int level = 2;
+  va_list args;
+
+  va_start(args, msg);
+  if (msg[0] == '<' && msg[1] >= '0' && msg[1] <= '9' && msg[2] == '>')
+       {
+         level = msg[1] - '0';
+         msg += 3;
+       }
+  logit(level, msg, args);
+  va_end(args);
+}
+
+void
+die(byte *msg, ...)
+{
+  va_list args;
+
+  va_start(args, msg);
+  logit(9, msg, args);
+  va_end(args);
+  exit(99);
+}
+
+static byte *
+basename(byte *n)
+{
+  byte *p = n;
+
+  while (*n)
+       if (*n++ == '/')
+         p = n;
+  return p;
+}
+
+void
+initlog(byte *argv0)
+{
+  progname = basename(argv0);
+  pid = getpid();
+}
diff --git a/lib/log.h b/lib/log.h
new file mode 100644 (file)
index 0000000..fdd0ace
--- /dev/null
+++ b/lib/log.h
@@ -0,0 +1,14 @@
+/*
+ *     Sherlock Library -- Logging
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#define L_DEBUG "<0>"
+#define L_INFO "<2>"
+#define L_WARN "<4>"
+#define L_ERROR "<6>"
+#define L_FATAL "<9>"
+
+int log(byte *, ...);
+void initlog(byte *);
diff --git a/lib/log2.c b/lib/log2.c
new file mode 100644 (file)
index 0000000..dc0a929
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *     Sherlock Library -- Binary Logarithm
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <stdio.h>
+
+#include "lib.h"
+
+int
+ffs(ulg x)
+{
+  ulg l;
+
+  if (!x)
+       return 0;
+
+  l = 0;
+  if (x & 0xffff0000) l += 16;
+  if (x & 0xff00ff00) l += 8;
+  if (x & 0xf0f0f0f0) l += 4;
+  if (x & 0xcccccccc) l += 2;
+  if (x & 0xaaaaaaaa) l++;
+  return l;
+}
diff --git a/lib/md5.c b/lib/md5.c
new file mode 100644 (file)
index 0000000..d4f8535
--- /dev/null
+++ b/lib/md5.c
@@ -0,0 +1,247 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include <string.h>            /* for memcpy() */
+#include "md5.h"
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len)  /* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+    uint32 t;
+    do {
+       t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+           ((unsigned) buf[1] << 8 | buf[0]);
+       *(uint32 *) buf = t;
+       buf += 4;
+    } while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+    uint32 t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+       ctx->bits[1]++;         /* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;       /* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+       unsigned char *p = (unsigned char *) ctx->in + t;
+
+       t = 64 - t;
+       if (len < t) {
+           memcpy(p, buf, len);
+           return;
+       }
+       memcpy(p, buf, t);
+       byteReverse(ctx->in, 16);
+       MD5Transform(ctx->buf, (uint32 *) ctx->in);
+       buf += t;
+       len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+       memcpy(ctx->in, buf, 64);
+       byteReverse(ctx->in, 16);
+       MD5Transform(ctx->buf, (uint32 *) ctx->in);
+       buf += 64;
+       len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+    unsigned count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+       /* Two lots of padding:  Pad the first block to 64 bytes */
+       memset(p, 0, count);
+       byteReverse(ctx->in, 16);
+       MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+       /* Now fill the next block with 56 bytes */
+       memset(ctx->in, 0, 56);
+    } else {
+       /* Pad block to 56 bytes */
+       memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((uint32 *) ctx->in)[14] = ctx->bits[0];
+    ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (uint32 *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    memcpy(digest, ctx->buf, 16);
+    memset((char *) ctx, 0, sizeof(ctx));      /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+       ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+    register uint32 a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
diff --git a/lib/md5.h b/lib/md5.h
new file mode 100644 (file)
index 0000000..53a40c2
--- /dev/null
+++ b/lib/md5.h
@@ -0,0 +1,22 @@
+#ifndef MD5_H
+#define MD5_H
+
+#ifdef __alpha
+typedef unsigned int uint32;
+#else
+typedef unsigned long uint32;
+#endif
+
+struct MD5Context {
+       uint32 buf[4];
+       uint32 bits[2];
+       unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+              unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+#endif /* !MD5_H */
diff --git a/lib/patmatch.c b/lib/patmatch.c
new file mode 100644 (file)
index 0000000..32e3df1
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *     Sherlock Library -- Shell-Like Pattern Matching (currently only '?' and '*')
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "lib.h"
+
+int
+match_pattern(byte *p, byte *s)
+{
+  while (*p)
+    {
+      if (*p == '?' && *s)
+       p++, s++;
+      else if (*p == '*')
+       {
+         int z = p[1];
+
+         if (!z)
+           return 1;
+         while (s = strchr(s, z))
+           {
+             if (match_pattern(p+1, s))
+               return 1;
+             s++;
+           }
+         return 0;
+       }
+      else if (*p++ != *s++)
+       return 0;
+    }
+  return !*s;
+}
diff --git a/lib/str_ctype.c b/lib/str_ctype.c
new file mode 100644 (file)
index 0000000..fa71920
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ *     Sherlock Library -- Character Classes
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include "string.h"
+
+unsigned char _c_cat[256] = {
+#define CHAR(code,upper,unacc,acc,cat) cat,
+#include "charmap.h"
+#undef CHAR
+};
diff --git a/lib/str_upper.c b/lib/str_upper.c
new file mode 100644 (file)
index 0000000..2742cd4
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ *     Sherlock Library -- Uppercase Map
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include "string.h"
+
+unsigned char _c_upper[256] = {
+#define CHAR(code,upper,unacc,acc,cat) upper,
+#include "charmap.h"
+#undef CHAR
+};
diff --git a/lib/temp.c b/lib/temp.c
new file mode 100644 (file)
index 0000000..ce9ab57
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *     Sherlock Library -- Temporary Files
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "lib.h"
+
+ulg
+temprand(uns key)
+{
+  static int seeded = 0;
+  ulg rand;
+
+  if (!seeded)
+    {
+      seeded = 1;
+      srand(getpid());
+    }
+  rand = random();
+  rand += key * 0xdeadbeef;
+  return rand;
+}
+
+void
+open_temp(struct tempfile *tf, byte *tftype)
+{
+  int retry = 50;
+  while (retry--)
+    {
+      sprintf(tf->name, TMP_DIR "/%s%08x", tftype, temprand(retry));
+      tf->fh = open(tf->name, O_RDWR | O_CREAT | O_EXCL, 0666);
+      if (tf->fh >= 0)
+       return;
+    }
+  die("Unable to create temporary file");
+}
+
+void
+delete_temp(struct tempfile *tf)
+{
+  close(tf->fh);
+  unlink(tf->name);
+}
diff --git a/lib/url.c b/lib/url.c
new file mode 100644 (file)
index 0000000..91b53ef
--- /dev/null
+++ b/lib/url.c
@@ -0,0 +1,479 @@
+/*
+ *     Sherlock Library -- URL Functions (according to RFC 1738 and 1808)
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "lib.h"
+#include "url.h"
+#include "string.h"
+
+/* Escaping and de-escaping */
+
+static uns
+enhex(uns x)
+{
+  return (x<10) ? (x + '0') : (x - 10 + 'A');
+}
+
+int
+url_deescape(byte *s, byte *d)
+{
+  byte *end = d + MAX_URL_SIZE - 10;
+  while (*s)
+    {
+      if (d >= end)
+       return URL_ERR_TOO_LONG;
+      if (*s == '%')
+       {
+         unsigned int val;
+         if (!Cxdigit(s[1]) || !Cxdigit(s[2]))
+           return URL_ERR_INVALID_ESCAPE;
+         val = Cxvalue(s[1])*16 + Cxvalue(s[2]);
+         if (!Cprint(val))
+           return URL_ERR_INVALID_ESCAPED_CHAR;
+         switch (val)
+           {
+           case ';':
+             val = NCC_SEMICOLON; break;
+           case '/':
+             val = NCC_SLASH; break;
+           case '?':
+             val = NCC_QUEST; break;
+           case ':':
+             val = NCC_COLON; break;
+           case '@':
+             val = NCC_AT; break;
+           case '=':
+             val = NCC_EQUAL; break;
+           case '&':
+             val = NCC_AND; break;
+           }
+         *d++ = val;
+         s += 3;
+       }
+      else if (*s >= 0x20 && *s <= 0x7e)
+       *d++ = *s++;
+      else
+       return URL_ERR_INVALID_CHAR;
+    }
+  *d = 0;
+  return 0;
+}
+
+int
+url_enescape(byte *s, byte *d)
+{
+  byte *end = d + MAX_URL_SIZE - 10;
+
+  while (*s)
+    {
+      if (d >= end)
+       return URL_ERR_TOO_LONG;
+      if (   *s >= 'A' && *s <= 'Z'
+            || *s >= 'a' && *s <= 'z'
+            || *s >= '0' && *s <= '9'
+            || *s == '$' || *s == '-' || *s == '.' || *s == '+'
+            || *s == '!' || *s == '*' || *s == '\'' || *s == '('
+            || *s == ')' || *s == '_' || *s == ';' || *s == '/'
+            || *s == '?' || *s == ':' || *s == '@' || *s == '='
+            || *s == '&')
+       *d++ = *s++;
+      else
+       {
+         uns val = (*s < NCC_MAX) ? ";/?:@=&"[*s] : *s;
+         *d++ = '%';
+         *d++ = enhex(val >> 4);
+         *d++ = enhex(val & 0x0f);
+         s++;
+       }
+    }
+  *d = 0;
+  return 0;
+}
+
+/* Split an URL (several parts may be copied to the destination buffer) */
+
+uns
+identify_protocol(byte *p)
+{
+  if (!strcasecmp(p, "http"))
+    return URL_PROTO_HTTP;
+  if (!strcasecmp(p, "ftp"))
+    return URL_PROTO_FTP;
+  return 0;
+}
+
+int
+url_split(byte *s, struct url *u, byte *d)
+{
+  bzero(u, sizeof(struct url));
+  u->port = ~0;
+  u->bufend = d + MAX_URL_SIZE - 10;
+
+  if (s[0] != '/')                     /* Seek for "protocol:" */
+    {
+      byte *p = s;
+      while (*p && Calnum(*p))
+       p++;
+      if (p != s && *p == ':')
+       {
+         u->protocol = d;
+         while (s < p)
+           *d++ = *s++;
+         *d++ = 0;
+         u->protoid = identify_protocol(u->protocol);
+         s++;
+       }
+    }
+
+  if (s[0] == '/')                     /* Host spec or absolute path */
+    {
+      if (s[1] == '/')                 /* Host spec */
+       {
+         byte *q, *w, *e;
+         char *ep;
+
+         s += 2;
+         q = d;
+         while (*s && *s != '/')       /* Copy user:passwd@host:port */
+           *d++ = *s++;
+         *d++ = 0;
+         w = strchr(q, '@');
+         if (w)                        /* user:passwd present */
+           {
+             *w++ = 0;
+             u->user = q;
+           }
+         else
+           w = q;
+         e = strchr(w, ':');
+         if (e)                        /* host:port present */
+           {
+             *e++ = 0;
+             u->port = strtoul(e, &ep, 10);
+             if (ep && *ep || u->port > 65535 || !u->port)
+               return URL_ERR_INVALID_PORT;
+           }
+         u->host = w;
+       }
+    }
+
+  u->rest = s;
+  u->buf = d;
+  return 0;
+}
+
+/* Normalization according to given base URL */
+
+static uns std_ports[] = { ~0, 80, 21 }; /* Default port numbers */
+
+static int
+relpath_merge(struct url *u, struct url *b)
+{
+  byte *a = u->rest;
+  byte *o = b->rest;
+  byte *d = u->buf;
+  byte *e = u->bufend;
+  byte *p;
+
+  if (a[0] == '/')                     /* Absolute path => OK */
+    return 0;
+  if (o[0] != '/')
+    return URL_PATH_UNDERFLOW;
+
+  if (!a[0])                           /* Empty relative URL is a special case */
+    {
+      u->rest = b->rest;
+      return 0;
+    }
+
+  u->rest = d;
+  p = strrchr(o, '/');                 /* Must be found! */
+  while (o <= p)                       /* Copy original path */
+    {
+      if (d >= e)
+       return URL_ERR_TOO_LONG;
+      *d++ = *o++;
+    }
+
+  while (*a)
+    {
+      if (a[0] == '.')
+       {
+         if (a[1] == '/' || !a[1])     /* Skip "./" and ".$" */
+           {
+             a++;
+             if (a[0])
+               a++;
+             continue;
+           }
+         else if (a[1] == '.' && (a[2] == '/' || !a[2])) /* "../" */
+           {
+             a += 2;
+             if (d <= u->buf + 1)
+               return URL_PATH_UNDERFLOW;
+             d--;                      /* Discard trailing slash */
+             while (d[-1] != '/')
+               d--;
+             if (a[0])
+               a++;
+             continue;
+           }
+       }
+      while (a[0] && a[0] != '/')
+       {
+         if (d >= e)
+           return URL_ERR_TOO_LONG;
+         *d++ = *a++;
+       }
+      if (a[0])
+       *d++ = *a++;
+    }
+
+  *d++ = 0;
+  u->buf = d;
+  return 0;
+}
+
+int
+url_normalize(struct url *u, struct url *b)
+{
+  byte *k;
+
+  if (u->protocol && !u->protoid)
+    return 0;
+
+  if ((u->protoid == URL_PROTO_HTTP || (!u->protoid && b && b->protoid == URL_PROTO_HTTP))
+      && u->rest && (k = strchr(u->rest, '#')))
+    *k = 0;                            /* Kill fragment reference */
+
+  if (u->port == ~0)
+    u->port = std_ports[u->protoid];
+
+  if (   u->protocol && !u->host
+        || u->host && !*u->host
+        || !u->host && u->user
+        || !u->rest)
+    return URL_SYNTAX_ERROR;
+
+  if (u->protocol)                     /* Absolute URL */
+    return 0;
+
+  if (!b)                              /* Relative to something? */
+    return URL_ERR_REL_NOTHING;
+  if (!b->protoid)
+    return URL_ERR_UNKNOWN_PROTOCOL;
+
+  if (!u->protocol)
+    {
+      u->protocol = b->protocol;
+      u->protoid = b->protoid;
+    }
+
+  if (!u->host)
+    {
+      u->host = b->host;
+      u->user = b->user;
+      u->port = b->port;
+      return relpath_merge(u, b); 
+    }
+
+  return 0;
+}
+
+/* Name canonicalization */
+
+static void
+lowercase(byte *b)
+{
+  if (b)
+    while (*b)
+      {
+       if (*b >= 'A' && *b <= 'Z')
+         *b = *b + 0x20;
+       b++;
+      }
+}
+
+static void
+kill_end_dot(byte *b)
+{
+  byte *k;
+
+  if (b)
+    {
+      k = b + strlen(b) - 1;
+      if (k > b && *k == '.')
+       *k = 0;
+    }
+}
+
+int
+url_canonicalize(struct url *u)
+{
+  lowercase(u->protocol);
+  lowercase(u->host);
+  kill_end_dot(u->host);
+  if ((!u->rest || !*u->rest) && (u->protoid == URL_PROTO_HTTP || u->protoid == URL_PROTO_FTP))
+    u->rest = "/";
+  return 0;
+}
+
+/* Pack a broken-down URL */
+
+byte *
+append(byte *d, byte *s, byte *e)
+{
+  if (d)
+    while (*s)
+      {
+       if (d >= e)
+         return NULL;
+       *d++ = *s++;
+      }
+  return d;
+}
+
+int
+url_pack(struct url *u, byte *d)
+{
+  byte *e = d + MAX_URL_SIZE - 10;
+
+  if (u->protocol)
+    {
+      d = append(d, u->protocol, e);
+      d = append(d, ":", e);
+      u->protoid = identify_protocol(u->protocol);
+    }
+  if (u->host)
+    {
+      d = append(d, "//", e);
+      if (u->user)
+       {
+         d = append(d, u->user, e);
+         d = append(d, "@", e);
+       }
+      d = append(d, u->host, e);
+      if (u->port != std_ports[u->protoid] && u->port != ~0)
+       {
+         char z[10];
+         sprintf(z, "%d", u->port);
+         d = append(d, ":", e);
+         d = append(d, z, e);
+       }
+    }
+  if (u->rest)
+    d = append(d, u->rest, e);
+  if (!d)
+    return URL_ERR_TOO_LONG;
+  *d = 0;
+  return 0;
+}
+
+/* Error messages */
+
+static char *errmsg[] = {
+  "Something is wrong",
+  "Too long",
+  "Invalid character",
+  "Invalid escape",
+  "Invalid escaped character",
+  "Invalid port number",
+  "Relative URL not allowed",
+  "Unknown protocol",
+  "Syntax error",
+  "Path underflow"
+};
+
+char *
+url_error(uns err)
+{
+  if (err >= sizeof(errmsg) / sizeof(char *))
+    err = 0;
+  return errmsg[err];
+}
+
+/* A "macro" for canonical split */
+
+int
+url_canon_split(byte *u, byte *buf1, byte *buf2, struct url *url)
+{
+  int err;
+
+  if (err = url_deescape(u, buf1))
+    return err;
+  if (err = url_split(buf1, url, buf2))
+    return err;
+  if (err = url_normalize(url, NULL))
+    return err;
+  return url_canonicalize(url);
+}
+
+/* Testing */
+
+#ifdef TEST
+
+int main(int argc, char **argv)
+{
+  char buf1[MAX_URL_SIZE], buf2[MAX_URL_SIZE], buf3[MAX_URL_SIZE], buf4[MAX_URL_SIZE];
+  int err;
+  struct url url, url0;
+
+  if (argc != 2)
+    return 1;
+  if (err = url_deescape(argv[1], buf1))
+    {
+      printf("deesc: error %d\n", err);
+      return 1;
+    }
+  printf("deesc: %s\n", buf1);
+  if (err = url_split(buf1, &url, buf2))
+    {
+      printf("split: error %d\n", err);
+      return 1;
+    }
+  printf("split: @%s@%s@%s@%d@%s\n", url.protocol, url.user, url.host, url.port, url.rest);
+  if (err = url_split("http://mj@www.hell.org/123/sub_dir/index.html", &url0, buf3))
+    {
+      printf("split base: error %d\n", err);
+      return 1;
+    }
+  if (err = url_normalize(&url0, NULL))
+    {
+      printf("normalize base: error %d\n", err);
+      return 1;
+    }
+  printf("base: @%s@%s@%s@%d@%s\n", url0.protocol, url0.user, url0.host, url0.port, url0.rest);
+  if (err = url_normalize(&url, &url0))
+    {
+      printf("normalize: error %d\n", err);
+      return 1;
+    }
+  printf("normalize: @%s@%s@%s@%d@%s\n", url.protocol, url.user, url.host, url.port, url.rest);
+  if (err = url_canonicalize(&url))
+    {
+      printf("canonicalize: error %d\n", err);
+      return 1;
+    }
+  printf("canonicalize: @%s@%s@%s@%d@%s\n", url.protocol, url.user, url.host, url.port, url.rest);
+  if (err = url_pack(&url, buf4))
+    {
+      printf("pack: error %d\n", err);
+      return 1;
+    }
+  printf("pack: %s\n", buf1);
+  if (err = url_enescape(buf4, buf2))
+    {
+      printf("enesc: error %d\n", err);
+      return 1;
+    }
+  printf("enesc: %s\n", buf2);
+  return 0;
+}
+
+#endif
diff --git a/lib/url.h b/lib/url.h
new file mode 100644 (file)
index 0000000..df1ad76
--- /dev/null
+++ b/lib/url.h
@@ -0,0 +1,63 @@
+/*
+ *     Sherlock Library -- URL Functions
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#define MAX_URL_SIZE 1024
+
+/* Non-control meanings of control characters */
+
+#define NCC_SEMICOLON 1
+#define NCC_SLASH 2
+#define NCC_QUEST 3
+#define NCC_COLON 4
+#define NCC_AT 5
+#define NCC_EQUAL 6
+#define NCC_AND 7
+#define NCC_MAX 8
+
+/* Remove/Introduce '%' escapes */
+
+int url_deescape(byte *, byte *);
+int url_enescape(byte *, byte *);
+
+/* URL splitting and normalization */
+
+struct url {
+  byte *protocol;
+  uns protoid;
+  byte *user;
+  byte *host;
+  uns port;                            /* ~0 if unspec */
+  byte *rest;
+  byte *buf, *bufend;
+};
+
+int url_split(byte *, struct url *, byte *);
+int url_normalize(struct url *, struct url *);
+int url_canonicalize(struct url *);
+int url_pack(struct url *, byte *);
+int url_canon_split(byte *, byte *, byte *, struct url *);
+uns identify_protocol(byte *);
+
+/* Error codes */
+
+char *url_error(uns);
+
+#define URL_ERR_TOO_LONG 1
+#define URL_ERR_INVALID_CHAR 2
+#define URL_ERR_INVALID_ESCAPE 3
+#define URL_ERR_INVALID_ESCAPED_CHAR 4
+#define URL_ERR_INVALID_PORT 5
+#define URL_ERR_REL_NOTHING 6
+#define URL_ERR_UNKNOWN_PROTOCOL 7
+#define URL_SYNTAX_ERROR 8
+#define URL_PATH_UNDERFLOW 9
+
+#define URL_PROTO_UNKNOWN 0
+#define URL_PROTO_HTTP 1
+#define URL_PROTO_FTP 2
+#define URL_PROTO_MAX 3
+
+#define URL_PNAMES { "unknown", "http", "ftp" }
diff --git a/lib/wordsplit.c b/lib/wordsplit.c
new file mode 100644 (file)
index 0000000..b1b2ada
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *     Sherlock Library -- Word Splitting
+ *
+ *     (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <stdio.h>
+
+#include "lib.h"
+#include "string.h"
+
+int
+wordsplit(byte *src, byte **dst, uns max)
+{
+  int cnt = 0;
+
+  for(;;)
+    {
+      while (Cspace(*src))
+       *src++ = 0;
+      if (!*src)
+       break;
+      if (cnt >= max)
+       return -1;
+      dst[cnt++] = src;
+      while (*src && !Cspace(*src))
+       src++;
+    }
+  return cnt;
+}