Upstream tarball

This commit is contained in:
Juhani Krekelä 2021-04-19 13:47:21 +03:00
commit 21863d7241
134 changed files with 40816 additions and 0 deletions

11
common/Imakefile Normal file
View file

@ -0,0 +1,11 @@
#include <../Common.tmpl>
SRCS = mime.c list.c ml.c mempool.c dmem.c util.c dir.c url.c uproc.c
OBJS = mime.o list.o ml.o mempool.o dmem.o util.o dir.o url.o uproc.o
EXTRA_DEFINES = $(CHIMERA_DEFINES)
EXTRA_INCLUDES = -I./ -I../port
NormalLibraryTarget(xcommon, $(OBJS))
DependTarget()

84
common/common.h Normal file
View file

@ -0,0 +1,84 @@
/*
* common.h
*
* Copyright (c) 1996-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __COMMON_H__
#define __COMMON_H__ 1
/* mempool.c */
typedef struct MemPoolP *MemPool;
#define MPCreate() MPCreateTrack(__LINE__, __FILE__)
MemPool MPCreateTrack _ArgProto((int, char *));
void *MPGet _ArgProto((MemPool, size_t));
void *MPCGet _ArgProto((MemPool, size_t));
char *MPStrDup _ArgProto((MemPool, const char *));
void MPDestroy _ArgProto((MemPool));
void MPPrintStatus _ArgProto((void));
/* dmem.c */
void free_mem _ArgProto((void *));
void *alloc_mem _ArgProto((size_t));
void *calloc_mem _ArgProto((size_t, size_t));
void *realloc_mem _ArgProto((void *, size_t));
char *alloc_string _ArgProto((char *));
/* util.c */
char *FixPath _ArgProto((MemPool, char *));
char *mystrtok _ArgProto((char *, size_t, char **));
char *GetBaseFilename _ArgProto((char *));
char *mytmpnam _ArgProto((MemPool));
#ifdef NDEBUG
#define myassert(a, b)
#else
#define myassert(a, b) xmyassert(a, b, __FILE__, __LINE__)
void xmyassert _ArgProto((bool, char *, char *, int));
#endif
/* dir.c */
char *compress_path _ArgProto((MemPool, char *, char *));
char *whack_filename _ArgProto((MemPool, char *));
/* list.c */
typedef struct GListP *GList;
#define GListCreate() GListCreateTrack(__LINE__, __FILE__)
GList GListCreateTrack _ArgProto((int, char *));
GList GListCreateX _ArgProto((MemPool));
void GListAddHead _ArgProto((GList, void *));
#define GListPush(a, b) GListAddHead(a, b)
void GListAddTail _ArgProto((GList, void *));
void GListDestroy _ArgProto((GList));
void *GListGetHead _ArgProto((GList));
void *GListGetTail _ArgProto((GList));
void *GListGetNext _ArgProto((GList));
void *GListGetPrev _ArgProto((GList));
void GListRemoveItem _ArgProto((GList, void *));
bool GListEmpty _ArgProto((GList));
void *GListPop _ArgProto((GList));
void *GListGetCurrent _ArgProto((GList));
void GListPrintStatus _ArgProto((void));
void GListClear _ArgProto((GList));
void *GListCurrent _ArgProto((GList));
/* uproc.c */
void StartReaper _ArgProto((void));
int PipeCommand _ArgProto((char *, int *));
#endif /* __COMMON_H__ */

135
common/dir.c Normal file
View file

@ -0,0 +1,135 @@
/*
* dir.c
*
* Copyright (c) 1996-1997, John Kilburg <john@cs.unlv.edu>
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "port_after.h"
#include "common.h"
/*
* whack_filename
*/
char *
whack_filename(mp, p)
MemPool mp;
char *p;
{
char *n = MPStrDup(mp, p);
size_t last;
last = strlen(n) - 1;
if (*(n + last) != '/')
{
for (p = n + last; p >= n; p--)
{
if (*p == '/')
{
*(p + 1) = '\0';
break;
}
}
}
return(n);
}
/*
* compress_path
*
* This assumes sizeof(char) == 1 which is probably a really bad idea.
*/
char *
compress_path(mp, c, cwd)
MemPool mp;
char *c;
char *cwd;
{
char *r;
char *p, *p1, *p2, *p3;
char *ps;
if (*c != '/')
{
if (*cwd != '/') return(NULL);
r = (char *)MPGet(mp, strlen("/") + strlen(c) + strlen(cwd) + 1);
strcpy(r, cwd);
strcat(r, "/");
strcat(r, c);
}
else r = MPStrDup(mp, c);
for (p = r; *p != '\0'; )
{
if (*p == '/')
{
p1 = p + 1;
if (*p1 == '/')
{
memmove(p, p1, strlen(p1) + 1);
continue;
}
else if (*p1 == '.')
{
p2 = p1 + 1;
if (*p2 == '/')
{
memmove(p, p2, strlen(p2) + 1);
continue;
}
else if (*p2 == '\0')
{
*p1 = '\0';
return(r);
}
else if (*p2 == '.')
{
p3 = p2 + 1;
if (*p3 == '/' || *p3 == '\0')
{
for (ps = p - 1; ps >= r; ps--)
{
if (*ps == '/') break;
}
if (ps < r) ps = r;
if (*p3 == '/') memmove(ps, p3, strlen(p3) + 1);
else
{
*(ps + 1) = '\0';
return(r);
}
p = ps;
continue;
}
}
}
}
p++;
}
return(r);
}

87
common/dmem.c Normal file
View file

@ -0,0 +1,87 @@
/*
* dmem.c
*
* Copyright (C) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "common.h"
/*
* free_mem
*/
void
free_mem(m)
void *m;
{
free(m);
return;
}
/*
* calloc_mem
*/
void *
calloc_mem(len, elen)
size_t len, elen;
{
return(calloc(len, elen));
}
/*
* alloc_mem
*/
void *
alloc_mem(len)
size_t len;
{
return(malloc(len));
}
/*
* realloc_mem
*/
void *
realloc_mem(s, len)
void *s;
size_t len;
{
return(realloc(s, len));
}
/*
* alloc_string
*/
char *
alloc_string(str)
char *str;
{
char *ns;
ns = (char *)malloc(strlen(str) + 1);
strcpy(ns, str);
return(ns);
}

353
common/list.c Normal file
View file

@ -0,0 +1,353 @@
/*
* list.c
*
* Copyright (c) 1996-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "port_after.h"
#include "common.h"
struct GNodeP
{
void *thing;
struct GNodeP *prev, *next;
};
struct GListP
{
bool localmp;
MemPool mp;
struct GNodeP *f;
struct GNodeP *head, *tail;
struct GNodeP *c;
};
/*
#define TRACKER 1
*/
#ifdef TRACKER
struct track
{
GList gl;
int line;
char *file;
struct track *next;
};
static struct track *track_list = NULL;
#endif
static void FreeListNode _ArgProto((GList, struct GNodeP *));
static struct GNodeP *GetFreedNode _ArgProto((GList));
static void
FreeListNode(gl, f)
GList gl;
struct GNodeP *f;
{
#ifdef TRACKER
memset(f, 0, sizeof(struct GNodeP));
#endif
f->next = gl->f;
gl->f = f;
return;
}
static struct GNodeP *
GetFreedNode(gl)
GList gl;
{
struct GNodeP *f;
return(NULL);
if (gl->f == NULL) return(NULL);
f = gl->f;
gl->f = f->next;
memset(f, 0, sizeof(struct GNodeP));
return(f);
}
GList
GListCreateX(mp)
MemPool mp;
{
GList gl;
gl = (GList)MPCGet(mp, sizeof(struct GListP));
gl->mp = mp;
gl->localmp = false;
return(gl);
}
GList
GListCreateTrack(line, file)
int line;
char *file;
{
MemPool mp;
GList gl;
#ifdef TRACKER
struct track *f;
#endif
mp = MPCreate();
gl = (GList)MPCGet(mp, sizeof(struct GListP));
gl->mp = mp;
gl->localmp = true;
#ifdef TRACKER
f = (struct track *)malloc(sizeof(struct track));
f->gl = gl;
f->line = line;
f->file = file;
f->next = track_list;
track_list = f;
#endif
return(gl);
}
void *
GListPop(gl)
GList gl;
{
void *thing;
struct GNodeP *f;
if (gl->head != NULL)
{
thing = gl->head->thing;
f = gl->head;
if (gl->head != NULL) gl->head = gl->head->next;
if (gl->head != NULL) gl->head->prev = NULL;
gl->c = gl->head;
FreeListNode(gl, f);
return(thing);
}
return(NULL);
}
void
GListAddHead(gl, thing)
GList gl;
void *thing;
{
struct GNodeP *gn;
if ((gn = GetFreedNode(gl)) == NULL)
{
gn = (struct GNodeP *)MPCGet(gl->mp, sizeof(struct GNodeP));
}
gn->next = gl->head;
if (gl->head != NULL) gl->head->prev = gn;
gl->head = gn;
if (gl->tail == NULL) gl->tail = gn;
gn->thing = thing;
return;
}
void
GListAddTail(gl, thing)
GList gl;
void *thing;
{
struct GNodeP *gn;
if ((gn = GetFreedNode(gl)) == NULL)
{
gn = (struct GNodeP *)MPCGet(gl->mp, sizeof(struct GNodeP));
}
gn->prev = gl->tail;
if (gl->tail != NULL) gl->tail->next = gn;
gl->tail = gn;
if (gl->head == NULL) gl->head = gn;
gn->thing = thing;
return;
}
void
GListDestroy(gl)
GList gl;
{
#ifdef TRACKER
struct track *f;
#endif
if (gl->localmp) MPDestroy(gl->mp);
#ifdef TRACKER
for (f = track_list; f != NULL; f = f->next)
{
if (f->gl == gl)
{
f->gl = NULL;
break;
}
}
#endif
return;
}
void *
GListGetHead(gl)
GList gl;
{
if (gl->head == NULL) return(NULL);
gl->c = gl->head;
return(gl->head->thing);
}
void *
GListGetTail(gl)
GList gl;
{
if (gl->tail == NULL) return(NULL);
gl->c = gl->tail;
return(gl->tail->thing);
}
void *
GListGetNext(gl)
GList gl;
{
if (gl->c == NULL) return(NULL);
gl->c = gl->c->next;
if (gl->c == NULL) return(NULL);
return(gl->c->thing);
}
void *
GListGetPrev(gl)
GList gl;
{
if (gl->c == NULL) return(NULL);
gl->c = gl->c->prev;
if (gl->c == NULL) return(NULL);
return(gl->c->thing);
}
void *
GListGetCurrent(gl)
GList gl;
{
if (gl->c == NULL) return(NULL);
return(gl->c->thing);
}
void
GListRemoveItem(gl, thing)
GList gl;
void *thing;
{
struct GNodeP *c, *n;
for (c = gl->head; c != NULL; )
{
if (c->thing == thing)
{
if (gl->c == c) gl->c = NULL;
n = c->next;
if (c == gl->head) gl->head = c->next;
if (c == gl->tail) gl->tail = c->prev;
if (c->next != NULL) c->next->prev = c->prev;
if (c->prev != NULL) c->prev->next = c->next;
FreeListNode(gl, c);
c = n;
}
else c = c->next;
}
return;
}
bool
GListEmpty(gl)
GList gl;
{
return(gl == NULL || gl->head == NULL);
}
MemPool
GListMP(gl)
GList gl;
{
return(gl->mp);
}
void
GListPrintStatus()
{
#ifdef TRACKER
struct track *f;
for (f = track_list; f != NULL; f = f->next)
{
if (f->gl != NULL)
{
fprintf (stderr, "GList unfreed: Line %d, File %s\n", f->line, f->file);
}
}
#endif
return;
}
void
GListClear(gl)
GList gl;
{
struct GNodeP *c, *t;
gl->c = NULL;
c = gl->head;
t = NULL;
while (c != NULL)
{
t = c;
c = c->next;
}
if (t != NULL)
{
t->next = gl->f;
gl->f = gl->head;
}
gl->head = NULL;
gl->tail = NULL;
return;
}

318
common/mempool.c Normal file
View file

@ -0,0 +1,318 @@
/*
* mempool.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "port_after.h"
#include "common.h"
/*
* MPDEBUG - If this is defined then all memory pooling goes away and
* malloc is used. This is useful if you suspect problems
* with the memory pooling code (e.g. alignment problems)
* or you want to use a malloc checker.
*
* MPALIGN - If the alignment size is guessed wrong then this can be
* defined to be the appropriate alignment size to override
* the automatic thing.
*
* MPPOOLSIZE - This is the minimum allocation size. Maybe changing
* it would result in better performance. Must be
* larger than sizeof(struct pool)...probably much larger.
*/
/*
#define MPDEBUG 1
*/
#define MPPOOLSIZE BUFSIZ
#ifndef MPALIGN
typedef struct Alignment
{
union { int a; char *b; size_t c; off_t d; long e; } align;
} Alignment;
#define MPALIGNSIZE(x) ((x / sizeof(Alignment) + 1) * sizeof(Alignment))
#else
#define MPALIGNSIZE(x) ((x / MPALIGN + 1) * MPALIGN)
#endif
/*
#define TRACKER 1
*/
#ifdef TRACKER
struct track
{
MemPool mp;
int line;
char *file;
struct track *next;
};
static struct track *track_list = NULL;
#endif
struct pool
{
size_t used, len;
#ifdef MPDEBUG
void *mem;
#endif
struct pool *next;
};
struct MemPoolP
{
struct pool *plist;
size_t len;
};
#ifndef MPDEBUG
static struct pool *create_pool _ArgProto((size_t));
static void *use_pool _ArgProto((struct pool *, size_t));
/*
* create_pool
*/
static struct pool *
create_pool(alen)
size_t alen;
{
size_t blen, len, plen;
struct pool *pool;
plen = MPALIGNSIZE(sizeof(struct pool));
len = MPALIGNSIZE(alen) + plen;
blen = (len / MPPOOLSIZE + 1) * MPPOOLSIZE;
pool = (struct pool *)malloc(blen);
if (pool == NULL)
{
fprintf (stderr, "create_pool malloc failed: %ld\n", (long)blen);
return(NULL);
}
pool->len = blen;
pool->used = plen;
pool->next = NULL;
return(pool);
}
/*
* use_pool
*/
static void *
use_pool(pool, len)
struct pool *pool;
size_t len;
{
byte *mem;
len = MPALIGNSIZE(len);
if (pool->used + len > pool->len) return(NULL);
mem = (byte *)pool + pool->used;
pool->used += len;
return((void *)mem);
}
#endif
/*
* MPCreate
*/
MemPool
MPCreateTrack(line, file)
int line;
char *file;
{
MemPool mp;
struct pool *pool;
#ifdef TRACKER
struct track *f;
#endif
#ifndef MPDEBUG
pool = create_pool(sizeof(struct MemPoolP));
if (pool == NULL) return(NULL);
mp = (MemPool)use_pool(pool, sizeof(struct MemPoolP));
myassert(mp != NULL, "MPCreate: use_pool failed!");
mp->plist = pool;
mp->len = pool->len;
#else
mp = (MemPool)malloc(sizeof(struct MemPoolP));
if (mp == NULL) return(NULL);
memset(mp, 0, sizeof(struct MemPoolP));
#endif
#ifdef TRACKER
f = (struct track *)malloc(sizeof(struct track));
if (f == NULL) abort();
f->mp = mp;
f->line = line;
f->file = file;
f->next = track_list;
track_list = f;
#endif
return(mp);
}
/*
* MPGet
*/
void *
MPGet(mp, len)
MemPool mp;
size_t len;
{
struct pool *pool;
void *mem;
myassert(len > 0, "MPGet: must allocate sizes greater than zero!");
#ifndef MPDEBUG
pool = mp->plist;
if ((mem = use_pool(pool, len)) == NULL)
{
pool = create_pool(len);
pool->next = mp->plist;
mp->len += pool->len;
mp->plist = pool;
mem = use_pool(pool, len);
myassert(mem != NULL, "MPGet: use_pool failed!");
}
#else
pool = (struct pool *)malloc(sizeof(struct pool));
if (pool == NULL) return(NULL);
pool->next = mp->plist;
mp->plist = pool;
mem = pool->mem = malloc(len);
#endif
return(mem);
}
/*
* MPCGet
*/
void *
MPCGet(mp, len)
MemPool mp;
size_t len;
{
void *m;
m = MPGet(mp, len);
memset(m, 0, len);
return(m);
}
/*
* MPStrDup
*/
char *
MPStrDup(mp, s)
MemPool mp;
const char *s;
{
size_t len;
char *ns;
if (s == NULL) return(NULL);
len = strlen(s);
ns = (char *)MPGet(mp, len + 1);
strcpy(ns, s);
return(ns);
}
/*
* MPDestroy
*/
void
MPDestroy(mp)
MemPool mp;
{
struct pool *m, *t;
#ifdef TRACKER
struct track *f;
#endif
for (m = mp->plist; m != NULL; )
{
t = m;
m = m->next;
#ifdef MPDEBUG
free(t->mem);
#endif
free(t);
}
#ifdef MPDEBUG
free(mp);
#endif
#ifdef TRACKER
for (f = track_list; f != NULL; f = f->next)
{
if (f->mp == mp)
{
f->mp = NULL;
break;
}
}
#endif
return;
}
/*
* MPPrintStats
*/
void
MPPrintStatus()
{
#ifdef TRACKER
struct track *f;
size_t total;
total = 0;
for (f = track_list; f != NULL; f = f->next)
{
if (f->mp != NULL)
{
fprintf (stderr, "MP unfreed: Line %d, File %s, Length %ld\n",
f->line, f->file, (long)f->mp->len);
total += f->mp->len;
}
}
fprintf (stderr, "Total unfreed: %ld\n", (long)total);
#endif
return;
}

432
common/mime.c Normal file
View file

@ -0,0 +1,432 @@
/*
* mime.c
*
* Copyright (c) 1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "common.h"
#include "mime.h"
typedef struct MIMEFieldP *MIMEField;
typedef struct MIMEParamP *MIMEParam;
/*
* MIMEish parsing thing.
*
* Tries to deal with stuff of the form:
*
* field-name: field-value; param[=value]; param[=value]; ...
*/
struct MIMEHeaderP
{
GList list; /* list of MIMEField */
MemPool mp;
size_t i;
size_t len;
bool data_found;
};
struct MIMEFieldP
{
char *name;
char *value;
GList list; /* list of param */
};
struct MIMEParamP
{
char *name;
char *value;
};
static MIMEParam parse_param _ArgProto((char *));
static MIMEField parse_line _ArgProto((MemPool, char *));
MIMEHeader
MIMECreateHeader()
{
MemPool mp;
MIMEHeader mh;
mp = MPCreate();
mh = MPCGet(mp, sizeof(struct MIMEHeaderP));
mh->mp = mp;
mh->list = GListCreateX(mp);
mh->data_found = false;
return(mh);
}
static MIMEParam
parse_param(line)
char *line;
{
MIMEParam p = NULL;
return(p);
}
static MIMEField
parse_line(mp, line)
MemPool mp;
char *line;
{
MIMEField mf = NULL;
MIMEParam param;
char *cp;
char *ps = NULL;
bool inquote = false;
char *t;
for (cp = line; *cp != '\0'; cp++)
{
if (mf != NULL)
{
if (inquote)
{
if (*cp == '"') inquote = false;
}
else
{
if (*cp == '"') inquote = true;
else if (*cp == ';' || *cp == '\0')
{
while (isspace8(*ps) && ps < cp) ps++;
if (ps < cp)
{
t = (char *)MPGet(mp, cp - ps + 1);
strncpy(t, ps, cp - ps);
t[cp - ps] = '\0';
if (mf->value == NULL) mf->value = t;
else
{
if (mf->list == NULL) mf->list = GListCreateX(mp);
if ((param = parse_param(t)) != NULL)
{
GListAddTail(mf->list, param);
}
}
}
ps = cp + 1;
}
}
}
else if (*cp == ':')
{
mf = (MIMEField)MPCGet(mp, sizeof(struct MIMEFieldP));
mf->name = (char *)MPGet(mp, cp - line + 1);
strncpy(mf->name, line, cp - line);
mf->name[cp - line] = '\0';
ps = cp + 1;
}
}
/*
* Catch the value or parameter that is terminated with \0
*/
if (mf != NULL && ps < cp)
{
while (isspace8(*ps) && ps < cp) ps++;
if (ps < cp)
{
t = (char *)MPGet(mp, cp - ps + 1);
strncpy(t, ps, cp - ps);
t[cp - ps] = '\0';
if (mf->value == NULL) mf->value = t;
else
{
if (mf->list == NULL) mf->list = GListCreateX(mp);
if ((param = parse_param(t)) != NULL)
{
GListAddTail(mf->list, param);
}
}
}
}
return(mf);
}
/*
* MIMEParseBuffer
*
* This is the entry point for code to parse a buffer that contains
* a MIME-like thing chunk of chars.
*/
int
MIMEParseBuffer(mh, buf, len)
MIMEHeader mh;
char *buf;
size_t len;
{
MIMEField mf;
size_t j;
char *cp, *pcp, *ls, *le;
char *line;
size_t usedlen;
size_t linelen;
myassert(mh->data_found, "Must call MIMEFindData before MIMEParseBuffer");
usedlen = 0;
linelen = BUFSIZ;
line = (char *)alloc_mem(linelen);
le = NULL;
ls = cp = buf;
pcp = "";
for (j = 0; j < len; j++, pcp = cp, cp++)
{
if (*cp != '\n') continue;
/*
* If line ends with \r\n then shift EOL back one character so that
* \r doesn't get included in the line.
*/
if (*pcp == '\r') le = pcp;
else le = cp;
/*
* If the line start is the same as the line end then it must be
* a blank line and its time to bail out.
*/
if (ls == le) break;
/*
* If the line doesn't begin with a space character then flush the
* previous line (if there was a previous) as a complete field.
* Otherwise remove the blank space from the continuation line.
*/
if (!isspace8(*ls))
{
if (usedlen > 0)
{
if ((mf = parse_line(mh->mp, line)) != NULL)
{
GListAddTail(mh->list, mf);
}
usedlen = 0;
}
}
else
{
while(isspace8(*ls) && ls < le) ls++;
}
/*
* If there is something besides whitespace then stick it in the line
* buffer.
*/
if (ls < le)
{
if (linelen < usedlen + (le - ls))
{
linelen += ((le - ls) / BUFSIZ + 1) * BUFSIZ;
line = (char *)realloc(line, linelen);
}
strncpy(line + usedlen, ls, le - ls);
usedlen += le - ls;
line[usedlen] = '\0';
}
/*
* Start the next line after the \n
*/
ls = cp + 1;
}
if (usedlen > 0)
{
if ((mf = parse_line(mh->mp, line)) != NULL)
{
GListAddTail(mh->list, mf);
}
usedlen = 0;
}
free_mem(line);
return(0);
}
/*
* MIMEDestroyHeader
*/
void
MIMEDestroyHeader(mh)
MIMEHeader mh;
{
MPDestroy(mh->mp);
return;
}
/*
* MIMEFindData
*
* Searches for \n\n and \r\n\r\n in a string. Returns the offset after
* the pattern;
*/
int
MIMEFindData(mh, data, len, doff)
MIMEHeader mh;
char *data;
size_t len;
size_t *doff;
{
char *cp;
char n[4];
size_t j;
myassert(mh->i < len, "MIMEFindData: Inconsistent buffer sizes");
memset(n, 0, sizeof(n));
j = 0;
for (cp = data + mh->i; mh->i < len; mh->i++, j++, cp++)
{
n[j % 4] = *cp;
/*
* Mmmm fun. If there are two or more characters and the current
* and previous character are '\n' (i.e. blank line) then the end
* of the header has been reached. If there are 4 or more characters
* and the sequence of characters (in reverse order) is \n\r\n\r then
* the end of header has been reached.
*/
if (j >= 2 && n[j % 4] == '\n' &&
(n[(j - 1) % 4] == '\n' ||
(j >= 4 && n[(j - 1) % 4] == '\r' && n[(j - 2) % 4] == '\n' &&
n[(j - 3) % 4] == '\r')))
{
mh->data_found = true;
*doff = mh->i + 1;
return(0);
}
}
return(-1);
}
/*
* MIMEGetField
*/
int
MIMEGetField(mh, name, value)
MIMEHeader mh;
char *name;
char **value;
{
MIMEField f;
for (f = (MIMEField)GListGetHead(mh->list); f != NULL;
f = (MIMEField)GListGetNext(mh->list))
{
if (strlen(f->name) == strlen(name) && strcasecmp(f->name, name) == 0)
{
*value = f->value;
return(0);
}
}
return(-1);
}
/*
* MIMEAddLine
*
* Adds a field to a header. Parses out parameters into structures.
*/
void
MIMEAddLine(mh, line)
MIMEHeader mh;
char *line;
{
MIMEField f;
if ((f = parse_line(mh->mp, line)) != NULL)
{
GListAddTail(mh->list, f);
}
return;
}
/*
* MIMEAddField
*/
void
MIMEAddField(mh, name, value)
MIMEHeader mh;
char *name;
char *value;
{
MIMEField mf;
mf = (MIMEField)MPCGet(mh->mp, sizeof(struct MIMEFieldP));
mf->name = MPStrDup(mh->mp, name);
mf->value = MPStrDup(mh->mp, value);
GListAddTail(mh->list, mf);
return;
}
/*
* MIMEWriteHeader
*
* This doesn't break long lines.
*/
int
MIMEWriteHeader(mh, fp)
MIMEHeader mh;
FILE *fp;
{
MIMEField mf;
MIMEParam param;
for (mf = (MIMEField)GListGetHead(mh->list); mf != NULL;
mf = (MIMEField)GListGetNext(mh->list))
{
fprintf (fp, "%s: %s", mf->name, mf->value);
if (mf->list != NULL)
{
for (param = (MIMEParam)GListGetHead(mf->list); param != NULL;
param = (MIMEParam)GListGetNext(mf->list))
{
fprintf (fp, "; %s", param->name);
if (param->value != NULL) fprintf (fp, "=%s", param->value);
}
}
fprintf (fp, "\n");
}
fprintf (fp, "\n");
return(0);
}

37
common/mime.h Normal file
View file

@ -0,0 +1,37 @@
/*
* mime.h
*
* Copyright (c) 1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __MIME_H__
#define __MIME_H__ 1
typedef struct MIMEHeaderP *MIMEHeader;
MIMEHeader MIMECreateHeader _ArgProto((void));
int MIMEParseBuffer _ArgProto((MIMEHeader, char *, size_t));
void MIMEDestroyHeader _ArgProto((MIMEHeader));
int MIMEGetField _ArgProto((MIMEHeader, char *, char **));
void MIMEAddField _ArgProto((MIMEHeader, char *, char *));
void MIMEAddLine _ArgProto((MIMEHeader, char *));
int MIMEGetHeaderEnd _ArgProto((MIMEHeader, size_t *));
int MIMEFindData _ArgProto((MIMEHeader, char *, size_t, size_t *));
int MIMEWriteHeader _ArgProto((MIMEHeader, FILE *));
#endif

788
common/ml.c Normal file
View file

@ -0,0 +1,788 @@
/*
* ml.c
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* Bogus parser for things that kind of maybe look like HTML/SGML.
* Or something.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "common.h"
#include "ml.h"
typedef enum
{
MLS_TAG, /* inside tag */
MLS_AVS, /* inside attribute value (single quote) */
MLS_AVD, /* inside attribute value (double quote) */
MLS_PSCOMMENT, /* possible start comment */
MLS_PECOMMENT, /* possible end comment */
MLS_COMMENT, /* inside comment */
MLS_DATA, /* between tags */
MLS_START /* start state */
} MLStateID;
#define IN_STATE(a, b) ((a)->plist->state == (b))
struct MLAttributeP
{
char *name;
char *value;
struct MLAttributeP *next;
};
struct MLElementP
{
MLElementType type;
char *ptext; /* processed text */
size_t plen; /* processed text length */
MLAttribute ta; /* attribute list */
};
struct PState
{
MLStateID state;
size_t off;
struct PState *next;
};
struct MLStateP
{
MemPool tmp; /* temporary memory pool */
MemPool mp; /* memory pool descriptor */
char *data; /* address of HTML buffer */
size_t len; /* length of HTML buffer */
size_t off; /* offset of parse */
MLElementHandler func; /* called when part created */
void *closure; /* state info for callback */
MLElement head, tail; /* element list */
MLElement curr; /* next unprocessed element */
struct PState *plist; /* parser state stack */
int count; /* call count */
};
static MLAttribute hs_parse_tag _ArgProto((MLState, char *, size_t));
static void hs_add_element _ArgProto((MLState, MLElement));
static MLElement hs_create_element _ArgProto((MLState, char *, size_t));
static MLElement hs_create_text _ArgProto((MLState, char *, size_t));
static MLElement hs_create_tag _ArgProto((MLState, char *, size_t));
static char *hs_condense _ArgProto((MLState, char *, size_t, size_t *));
static MLAttribute hs_create_attribute _ArgProto((MLState, char *, size_t));
static void hs_push _ArgProto((MLState, int));
static size_t hs_pop _ArgProto((MLState));
static void hs_handle_data _ArgProto((MLState, char *, size_t, bool));
/*
* hs_push
*/
static void
hs_push(hs, state)
MLState hs;
int state;
{
struct PState *ps;
ps = (struct PState *)MPCGet(hs->tmp, sizeof(struct PState));
ps->off = hs->off;
ps->state = state;
ps->next = hs->plist;
hs->plist = ps;
return;
}
/*
* hs_pop
*/
static size_t
hs_pop(hs)
MLState hs;
{
size_t off;
if (hs->plist == NULL) abort();
off = hs->plist->off;
hs->plist = hs->plist->next;
return(off);
}
/*
* hs_create_attribute
*/
static MLAttribute
hs_create_attribute(hs, text, len)
MLState hs;
char *text;
size_t len;
{
MLAttribute ta;
ta = (MLAttribute)MPCGet(hs->mp, sizeof(struct MLAttributeP));
ta->name = (char *)MPGet(hs->mp, len + 1);
strncpy(ta->name, text, len);
ta->name[len] = '\0';
return(ta);
}
struct entity
{
char *text;
int len;
unsigned char c;
} clist[] =
{
{ "amp", 3, '&' },
{ "lt", 2, '<' },
{ "gt", 2, '>' },
{ "copy", 4, 169 },
{ "AElig", 5, 198 },
{ "Aacute", 6, 193 },
{ "Acirc", 5, 194 },
{ "Agrave", 6, 192 },
{ "Aring", 5, 197 },
{ "Atilde", 6, 195 },
{ "Auml", 4, 196 },
{ "Ccedil", 6, 199 },
{ "ETH", 3, 208 },
{ "Eacute", 6, 201 },
{ "Ecirc", 5, 202 },
{ "Egrave", 6, 200 },
{ "Euml", 4, 203 },
{ "Iacute", 6, 205 },
{ "Icirc", 5, 206 },
{ "Igrave", 6, 204 },
{ "Iuml", 4, 207 },
{ "Ntilde", 6, 209 },
{ "Oacute", 6, 211 },
{ "Ocirc", 5, 212 },
{ "Ograve", 6, 210 },
{ "Oslash", 6, 216 },
{ "Otilde", 6, 213 },
{ "Ouml", 4, 214 },
{ "THORN", 5, 222 },
{ "Uacute", 6, 218 },
{ "Ucirc", 5, 219 },
{ "Ugrave", 6, 217 },
{ "Uuml", 4, 220 },
{ "Yacute", 6, 221 },
{ "aacute", 6, 225 },
{ "acirc", 5, 226 },
{ "aelig", 5, 230 },
{ "agrave", 6, 224 },
{ "aring", 5, 229 },
{ "atilde", 6, 227 },
{ "auml", 4, 228 },
{ "ccedil", 6, 231 },
{ "eacute", 6, 233 },
{ "ecirc", 5, 234 },
{ "egrave", 6, 232 },
{ "eth", 3, 240 },
{ "euml", 4, 235 },
{ "iacute", 6, 237 },
{ "icirc", 5, 238 },
{ "igrave", 6, 236 },
{ "iuml", 4, 239 },
{ "ntilde", 6, 241 },
{ "oacute", 6, 243 },
{ "ocirc", 5, 244 },
{ "ograve", 6, 242 },
{ "oslash", 6, 248 },
{ "otilde", 6, 245 },
{ "ouml", 4, 246 },
{ "szlig", 5, 223 },
{ "thorn", 5, 254 },
{ "uacute", 6, 250 },
{ "ucirc", 5, 251 },
{ "ugrave", 6, 249 },
{ "uuml", 4, 252 },
{ "yacute", 6, 253 },
{ "yuml", 4, 255 },
{ "reg", 3, 174 },
{ "comma", 5, 44 },
{ "colon", 5, 58 },
{ "quot", 4, '\"' },
{ "nbsp", 4, ' ' },
{ NULL, 0, '\0' },
};
/*
* hs_condense
*/
static char *
hs_condense(hs, text, len, newlen)
MLState hs;
char *text;
size_t len;
size_t *newlen;
{
char *cp, *lastcp;
size_t i;
char *b, *bcp;
char *x;
/*
* allocate a buffer for the new text. the new text will be smaller than
* the incoming text
*/
b = (char *)MPGet(hs->mp, len + 1);
bcp = b;
for (cp = text, lastcp = text + len; cp < lastcp; cp++)
{
/*
* Found entity and there is at least one more character?
*/
if (*cp == '&')
{
for (x = cp; x < lastcp && *x != ';' && !isspace8(*x); x++)
;
if (x < lastcp) /* found end of entity ? */
{
if (*x == '\r') x++; /* this may die */
if (*(cp + 1) == '#') /* number given ? */
{
*bcp = (char)atoi(cp + 2); /* get the character */
bcp++;
cp = x;
}
else
{
char *crap;
/* Search in the table of entity names */
for (i = 0, crap = cp + 1; clist[i].text != NULL; i++)
{
if (strncmp(clist[i].text, crap, clist[i].len) == 0)
{
*bcp = clist[i].c;
bcp++;
cp = x;
break;
}
}
}
}
if (cp < x)
{
*bcp = *cp;
bcp++;
}
}
else
{
*bcp = *cp; /* not part of entity */
bcp++;
}
}
*newlen = bcp - b;
*bcp = '\0';
return(b);
}
/*
* hs_parse_tag
*/
MLAttribute
hs_parse_tag(hs, text, len)
MLState hs;
char *text;
size_t len;
{
char *cp, *start, *lastcp;
MLAttribute tahead, tatail, ta;
size_t newlen;
tahead = NULL;
tatail = NULL;
lastcp = text + len;
for (cp = text; cp < lastcp; )
{
/* Eat leading spaces */
for (; cp < lastcp && isspace8(*cp); cp++)
;
if (cp == lastcp) break;
/* Look for value */
for (start = cp; cp < lastcp && !isspace8(*cp) && *cp != '='; cp++)
;
ta = hs_create_attribute(hs, start, cp - start);
if (isspace8(*cp))
{
for (; cp < lastcp && isspace8(*cp); cp++)
;
}
/* Found value */
if (cp < lastcp && *cp == '=')
{
cp++; /* past '=' */
/* Eat leading spaces */
for (; cp < lastcp && isspace8(*cp); cp++)
;
if (cp < lastcp)
{
/* Quoted value */
if (*cp == '"')
{
cp++; /* past '"' */
for (start = cp; cp < lastcp && *cp != '"'; cp++)
;
}
else if (*cp == '\'') /* single quoted value */
{
cp++; /* past ' */
for (start = cp; cp < lastcp && *cp != '\''; cp++)
;
}
else /* Unquoted value */
{
for (start = cp; cp < lastcp && !isspace8(*cp); cp++)
;
}
ta->value = hs_condense(hs, start, cp - start, &newlen);
}
}
if (tatail == NULL) tahead = ta;
else tatail->next = ta;
tatail = ta;
}
return(tahead);
}
/*
* hs_add_element
*/
static void
hs_add_element(hs, p)
MLState hs;
MLElement p;
{
(hs->func)(hs->closure, p);
return;
}
/*
* hs_create_element
*/
static MLElement
hs_create_element(hs, ptext, plen)
MLState hs;
char *ptext;
size_t plen;
{
MLElement p;
p = (MLElement)MPCGet(hs->mp, sizeof(struct MLElementP));
p->ptext = ptext;
p->plen = plen;
return(p);
}
/*
* hs_create_text
*/
static MLElement
hs_create_text(hs, text, len)
MLState hs;
char *text;
size_t len;
{
char *cp;
size_t newlen;
size_t i;
MLElement p;
/* Check for an entity */
for (cp = text, i = 0; i < len && *cp != '&'; cp++, i++)
;
if (i == len) p = hs_create_element(hs, text, len);
else
{
/* found an entity...condense */
cp = hs_condense(hs, text, len, &newlen);
p = hs_create_element(hs, cp, newlen);
}
p->type = ML_DATA;
return(p);
}
/*
* hs_create_tag
*/
static MLElement
hs_create_tag(hs, text, len)
MLState hs;
char *text;
size_t len;
{
MLElement p;
p = hs_create_element(hs, text, len);
p->ta = hs_parse_tag(hs, text + 1, len - 2);
if (p->ta != NULL && p->ta->name != NULL && p->ta->name[0] == '/')
{
p->ta->name++; /* this should be OK because it is not free'd */
p->type = ML_ENDTAG;
}
else p->type = ML_BEGINTAG;
return(p);
}
/*
* MLInit
*/
MLState
MLInit(func, closure)
MLElementHandler func;
void *closure;
{
MLState hs;
MemPool mp;
mp = MPCreate();
hs = (MLState)MPCGet(mp, sizeof(struct MLStateP));
hs->mp = mp;
hs->func = func;
hs->closure = closure;
hs->tmp = MPCreate();
hs_push(hs, MLS_START);
hs_push(hs, MLS_DATA);
return(hs);
}
/*
* MLDestroy
*/
void
MLDestroy(hs)
MLState hs;
{
MPDestroy(hs->mp);
return;
}
/*
* hs_handle_data
*/
void
hs_handle_data(hs, data, len, dend)
MLState hs;
char *data;
size_t len;
bool dend;
{
char *cp;
size_t poff;
MLElement n;
if (data == NULL || len == 0) return;
hs->data = data;
hs->len = len;
while (hs->off < len)
{
cp = data + hs->off;
if (IN_STATE(hs, MLS_DATA))
{
if (*cp == '<')
{
poff = hs_pop(hs);
if (hs->off - poff > 0)
{
n = hs_create_text(hs, hs->data + poff, hs->off - poff);
hs_add_element(hs, n);
}
hs_push(hs, MLS_TAG);
}
hs->off++;
}
else if (IN_STATE(hs, MLS_TAG))
{
if (*cp == '<') hs->off++;
else if (*cp == '>')
{
poff = hs_pop(hs);
n = hs_create_tag(hs, hs->data + poff, hs->off - poff + 1);
hs_add_element(hs, n);
hs->off++;
hs_push(hs, MLS_DATA);
}
else if (*cp == '-')
{
hs_push(hs, MLS_PSCOMMENT);
hs->off++;
}
else if (*cp == '"')
{
hs_push(hs, MLS_AVD);
hs->off++;
}
else if (*cp == '\'')
{
hs_push(hs, MLS_AVS);
hs->off++;
}
else hs->off++;
}
else if (IN_STATE(hs, MLS_PSCOMMENT))
{
hs_pop(hs);
if (*cp == '-')
{
hs_push(hs, MLS_COMMENT);
hs->off++;
}
else if (*cp == '>')
{
poff = hs_pop(hs);
n = hs_create_tag(hs, hs->data + poff, hs->off - poff + 1);
hs_add_element(hs, n);
hs->off++;
hs_push(hs, MLS_DATA);
}
else hs->off++;
}
else if (IN_STATE(hs, MLS_AVS))
{
if (*cp == '\'')
{
hs_pop(hs);
hs->off++;
}
else if (*cp == '>') hs_pop(hs);
else hs->off++;
}
else if (IN_STATE(hs, MLS_AVD))
{
if (*cp == '"')
{
hs_pop(hs);
hs->off++;
}
else if (*cp == '>') hs_pop(hs);
else hs->off++;
}
else if (IN_STATE(hs, MLS_COMMENT))
{
if (*cp == '-') hs_push(hs, MLS_PECOMMENT);
hs->off++;
}
else if (IN_STATE(hs, MLS_PECOMMENT))
{
/* Depends on only COMMENT state pushing PECOMMENT state */
hs_pop(hs);
if (*cp == '-')
{
hs->off++;
hs_pop(hs);
}
else if (*cp == '>')
{
poff = hs_pop(hs);
n = hs_create_tag(hs, hs->data + poff, hs->off - poff + 1);
hs_add_element(hs, n);
hs->off++;
hs_push(hs, MLS_DATA);
}
else hs->off++;
}
else
{
fprintf (stderr, "Invalid markup parser state.\n");
hs->off++;
}
}
return;
}
/*
* MLAddData
*/
void
MLAddData(hs, data, len)
MLState hs;
char *data;
size_t len;
{
hs_handle_data(hs, data, len, false);
return;
}
/*
* MLEndData
*/
void
MLEndData(hs, data, len)
MLState hs;
char *data;
size_t len;
{
MLElement p;
size_t poff;
if (data == NULL || len == 0 || len < hs->off) return;
hs_handle_data(hs, data, len, true);
poff = hs_pop(hs);
if (len - poff > 0)
{
if (IN_STATE(hs, MLS_DATA))
{
p = hs_create_text(hs, hs->data + poff, len - poff);
}
else
{
p = hs_create_tag(hs, hs->data + poff, len - poff);
}
hs_add_element(hs, p);
}
p = (MLElement)MPCGet(hs->mp, sizeof(struct MLElementP));
p->type = ML_EOF;
hs_add_element(hs, p);
MPDestroy(hs->tmp);
hs->tmp = NULL;
return;
}
/*
* MLFindAttribute
*/
char *
MLFindAttribute(p, name)
MLElement p;
char *name;
{
MLAttribute ta;
for (ta = p->ta; ta != NULL; ta = ta->next)
{
if (strcasecmp(ta->name, name) == 0)
{
return(ta->value == NULL ? "":ta->value);
}
}
return(NULL);
}
/*
* MLGetText
*/
void
MLGetText(p, text, len)
MLElement p;
char **text;
size_t *len;
{
*text = p->ptext;
*len = p->plen;
return;
}
/*
* MLGetType
*/
MLElementType
MLGetType(p)
MLElement p;
{
return(p->type);
}
/*
* MLTagName
*/
char *
MLTagName(p)
MLElement p;
{
if ((p->type == ML_BEGINTAG || p->type == ML_ENDTAG) && p->ta != NULL)
{
return(p->ta->name);
}
return(NULL);
}
/*
* MLCreateTag
*/
MLElement
MLCreateTag(hs, text, len)
MLState hs;
char *text;
size_t len;
{
return(hs_create_tag(hs, text, len));
}
/*
* MLAttributeToInt
*/
int
MLAttributeToInt(p, name)
MLElement p;
char *name;
{
char *value;
if ((value = MLFindAttribute(p, name)) == NULL) return(-1);
return(atoi(value));
}

59
common/ml.h Normal file
View file

@ -0,0 +1,59 @@
/*
* ml.h
*
* Copyright (c) 1996-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
typedef struct MLElementP *MLElement;
typedef struct MLAttributeP *MLAttribute;
typedef struct MLStateP *MLState;
typedef enum
{
ML_BEGINTAG,
ML_ENDTAG,
ML_DATA,
ML_CONTROLTAG,
ML_EOF
} MLElementType;
/*
* Public functions
*/
/*
* Functions for providing raw data to the markup-language code.
*/
typedef void (*MLElementHandler) _ArgProto((void *, MLElement));
MLState MLInit _ArgProto((MLElementHandler, void *));
void MLAddData _ArgProto((MLState, char *, size_t));
void MLEndData _ArgProto((MLState, char *, size_t));
void MLDestroy _ArgProto((MLState));
/*
* Functions for extracting information about elements created
*/
char *MLFindAttribute _ArgProto((MLElement, char *));
char *MLTagName _ArgProto((MLElement));
void MLGetText _ArgProto((MLElement, char **, size_t *));
MLElementType MLGetType(MLElement);
int MLAttributeToInt _ArgProto((MLElement, char *));
/*
* Random stuff
*/
MLElement MLCreateTag _ArgProto((MLState, char *, size_t));

147
common/uproc.c Normal file
View file

@ -0,0 +1,147 @@
/*
* uproc.c
*
* Code grabbed from chimera 1.65.
*/
#include "port_before.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#ifndef __QNX__
#include <sys/signal.h>
#else
#include <signal.h>
#endif
#include <sys/wait.h>
#include <sys/stat.h>
#include "port_after.h"
#include "common.h"
/*
* ReapChild
*
* This code grabs the status from an exiting child process. We really
* don't care about the status, we just want to keep zombie's from
* cropping up.
*/
static void
ReapChild()
{
#if defined(WNOHANG) && !defined(SYSV) && !defined(SVR4)
int pid;
#endif
extern int errno;
int old_errno = errno;
/*
* It would probably be better to use the POSIX mechanism here,but I have not
* checked into it. This gets us off the ground with SYSV. RSE@GMI
*/
#if defined(WNOHANG) && !defined(SYSV) && !defined(SVR4) && !defined(__QNX__) && !defined(__EMX__)
union wait st;
do
{
errno = 0;
pid = wait3(&st, WNOHANG, 0);
}
while (pid <= 0 && errno == EINTR);
#else
int st;
wait(&st);
#endif
StartReaper();
errno = old_errno;
return;
}
/*
* StartReaper
*
* This code inits the code which reaps child processes that where
* fork'd off for external viewers.
*/
void
StartReaper()
{
#ifdef SIGCHLD
signal(SIGCHLD, ReapChild);
#else
signal(SIGCLD, ReapChild);
#endif
return;
}
/*
* PipeCommand
*
* fork and exec to get a program running and supply it with
* a stdin, stdout, stderr that so we can talk to it.
*/
int
PipeCommand(command, fd)
char *command;
int *fd;
{
int pout[2];
int pin[2];
int pid;
/*
if (pipe(pout) == -1) return(-1);
*/
if (pipe(pin) == -1)
{
close(pout[0]);
close(pout[1]);
return(-1);
}
pid = fork();
if (pid == -1)
{
return(-1);
}
else if (pid == 0)
{
/*
if (pout[1] != 1)
{
dup2(pout[1], 1);
close(pout[1]);
}
*/
if (pin[0] != 0)
{
dup2(pin[0], 0);
close(pin[0]);
}
signal(SIGPIPE, SIG_DFL);
execl(command, command, (char *)0);
}
else
{
close(pout[1]);
close(pin[0]);
}
fd[0] = pin[1];
/*
fd[1] = pout[0];
*/
return(0);
}

614
common/url.c Normal file
View file

@ -0,0 +1,614 @@
/*
* url.c
*
* Copyright (C) 1993-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <ctype.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "port_after.h"
#include "url.h"
#define URLDELIMS ":/?#"
#ifndef NullString
#define NullString(s) (s == NULL || *s == '\0')
#endif
static URLParts *URLCreate _ArgProto((MemPool));
static char *resolve_filename _ArgProto((MemPool, char *, char *));
/*
* URLcmp
*
* Return 0 if equal.
*/
int
URLcmp(u1, u2)
URLParts *u1, *u2;
{
if (strcasecmp(u1->scheme, u2->scheme) == 0 &&
strcasecmp(u1->hostname, u2->hostname) == 0 &&
u1->port == u2->port &&
strcasecmp(u1->filename, u2->filename) == 0)
{
return(0);
}
return(-1);
}
/*
* URLEscape
*
* Puts escape codes in URLs. NOT complete.
*/
char *
URLEscape(mp, url, s2p)
MemPool mp;
char *url;
bool s2p;
{
char *cp;
char *n, *s;
static char *hex = "0123456789ABCDEF";
/*
* use a bit of memory so i don't have to mess around here
*/
s = n = (char *)MPGet(mp, strlen(url) * 3 + 2);
for (cp = url; *cp; cp++, n++)
{
if (*cp == ' ' && s2p)
{
*n = '+';
}
else if (*cp == '+' && s2p)
{
*n = '%';
n++;
*n = hex[*cp / 16];
n++;
*n = hex[*cp % 16];
}
#ifdef ORIGINAL_CODE
/*
else if (isalnum(*cp) || strchr("$-_.'(),+!*", *cp))
*/
else if (strchr("<>\"#{}|\\^~[]`",*cp))
#else
/* My CGI scripts and the Apache daemon say it's closer the first way - djhjr */
else if (isalnum(*cp) || strchr("$-_.'(),+!*", *cp))
#endif
{
*n = *cp;
}
else
{
*n = '%';
n++;
*n = hex[*cp / 16];
n++;
*n = hex[*cp % 16];
}
}
*n = '\0';
return(s);
}
/*
* UnescapeURL
*
* Converts the escape codes (%xx) into actual characters. NOT complete.
* Could do everthing in place I guess.
*/
char *
URLUnescape(mp, url)
MemPool mp;
char *url;
{
char *cp, *n, *s;
char hex[3];
s = n = (char *)MPGet(mp, strlen(url) + 2);
for (cp = url; *cp; cp++, n++)
{
if (*cp == '%')
{
cp++;
if (*cp == '%')
{
*n = *cp;
}
else
{
hex[0] = *cp;
cp++;
hex[1] = *cp;
hex[2] = '\0';
*n = (char)strtol(hex, NULL, 16);
}
}
else if (*cp == '+') *n = ' ';
else
{
*n = *cp;
}
}
*n = '\0';
return(s);
}
/*
* URLMakeString
*/
char *
URLMakeString(mp, up, addfrag)
MemPool mp;
URLParts *up;
bool addfrag;
{
size_t len;
char *u;
char *delim;
char *delim2;
char *filename;
char *hostname;
char *scheme;
char *delim3;
char *fragment;
if (NullString(up->scheme)) scheme = "file";
else scheme = up->scheme;
if (NullString(up->hostname))
{
delim = "";
hostname = "";
}
else
{
delim = "//";
hostname = up->hostname;
}
if (NullString(up->filename)) filename = "/";
else filename = up->filename;
delim2 = "";
if (up->fragment != NULL && addfrag)
{
fragment = up->fragment;
delim3 = "#";
}
else
{
fragment = "";
delim3 = "";
}
len = strlen(scheme) + strlen(hostname) + strlen(filename) +
strlen(delim) + strlen(fragment) + 11;
u = (char *)MPGet(mp, len + 1);
if (up->port == 0)
{
snprintf (u, len, "%s:%s%s%s%s%s%s", scheme, delim, hostname, delim2,
filename, delim3, fragment);
}
else
{
snprintf (u, len, "%s:%s%s:%d%s%s%s%s", scheme, delim, hostname, up->port,
delim2, filename, delim3, fragment);
}
return(u);
}
/*
* URLCreate
*
* Allocate URLParts and initialize to NULLs
*/
static URLParts *
URLCreate(mp)
MemPool mp;
{
URLParts *up;
up = (URLParts *)MPCGet(mp, sizeof(URLParts));
return(up);
}
/*
* resolve_filename
*
* I'm not sure this is much better than the original.
*/
static char *
resolve_filename(mp, c, p)
MemPool mp;
char *c, *p;
{
char *r;
char *t;
MemPool tmp;
/*
* If current is an absolute path then use it otherwise
* build an absolute path using the parent as a reference.
*/
if (c == NULL || c[0] == '/') r = MPStrDup(mp, c);
else if (c[0] == '~')
{
r = MPGet(mp, strlen(c) + 2);
r[0] = '/';
strcpy(r + 1, c);
}
else
{
tmp = MPCreate();
if (p == NULL || p[0] != '/') p = "/";
else p = whack_filename(tmp, p);
t = compress_path(tmp, c, p);
if (t == NULL) r = MPStrDup(mp, "/");
else r = MPStrDup(mp, t);
MPDestroy(tmp);
}
return(r);
}
/*
* URLResolve
*
* c - current
* p - parent
* r - result
*/
URLParts *
URLResolve(mp, c, p)
MemPool mp;
URLParts *c, *p;
{
URLParts *r;
/*
* If the protocols are different then just return the original with
* some empty fields filled in.
*/
if (c->scheme != NULL && p->scheme != NULL &&
strcasecmp(c->scheme, p->scheme) != 0)
{
r = URLDup(mp, c);
if (r->hostname == NULL) r->hostname = MPStrDup(mp, "localhost");
r->filename = resolve_filename(mp, c->filename, p->filename);
return(r);
}
r = URLCreate(mp);
/*
* If current has a protocol then use it, otherwise
* use the parent's protocol. If the parent doesn't have a protocol for
* some reason then use "file".
*/
if (c->scheme == NULL)
{
if (p->scheme != NULL) r->scheme = MPStrDup(mp, p->scheme);
else r->scheme = MPStrDup(mp, "file");
}
else r->scheme = MPStrDup(mp, c->scheme);
/*
* If current has a hostname then use it, otherwise
* use the parent's hostname. If neither has a hostname then
* fallback to "localhost".
*/
if (c->hostname == NULL)
{
if (p->hostname != NULL)
{
r->hostname = MPStrDup(mp, p->hostname);
r->port = p->port;
}
else
{
r->hostname = MPStrDup(mp, "localhost"); /* fallback */
r->port = 0;
}
}
else
{
r->hostname = MPStrDup(mp, c->hostname);
r->port = c->port;
}
r->filename = resolve_filename(mp, c->filename, p->filename);
/*
* Copy misc. fields.
*/
r->username = MPStrDup(mp, c->username);
r->password = MPStrDup(mp, c->password);
r->fragment = MPStrDup(mp, c->fragment);
return(r);
}
URLParts *
URLDup(mp, up)
MemPool mp;
URLParts *up;
{
URLParts *dp;
dp = URLCreate(mp);
dp->scheme = MPStrDup(mp, up->scheme);
dp->hostname = MPStrDup(mp, up->hostname);
dp->port = up->port;
dp->filename = up->filename != NULL ?
MPStrDup(mp, up->filename):MPStrDup(mp, "/");
dp->fragment = MPStrDup(mp, up->fragment);
dp->username = MPStrDup(mp, up->username);
dp->password = MPStrDup(mp, up->password);
return(dp);
}
/*
* URLParse
*
* Turns a URL into a URLParts structure
*
* The good stuff was written by Rob May <robert.may@rd.eng.bbc.co.uk>
* and heavily mangled/modified by john to suite his own weird style.
*/
URLParts *
URLParse(mp, url)
MemPool mp;
char *url;
{
URLParts *up;
char *start;
char *colon, *slash, *fslash;
char *pound; /* link pound (#) sign */
char *at; /* username/password @ */
char *ucolon; /* username colon */
char *pcolon; /* port number colon */
up = URLCreate(mp);
/* skip leading white-space (if any)*/
for (start = url; isspace8(*start); start++)
;
/*
* Look for indication of a scheme.
*/
colon = strchr(start, ':');
/*
* Search for characters that indicate the beginning of the
* path/params/query/fragment part.
*/
slash = strchr(start, '/');
if (slash == NULL) slash = strchr(start, ';');
if (slash == NULL) slash = strchr(start, '?');
if (slash == NULL) slash = strchr(start, '#');
/*
* Check to see if there is a scheme. There is a scheme only if
* all other separators appear after the colon.
*/
if (colon != NULL && (slash == NULL || colon < slash))
{
up->scheme = MPGet(mp, colon - start + 1);
strncpy(up->scheme, start, colon - start);
up->scheme[colon - start] = '\0';
}
/*
* If there is a slash then sort out the hostname and filename.
* If there is no slash then there is no hostname but there is a
* filename.
*/
if (slash != NULL)
{
/*
* Check for leading //. If its there then there is a host string.
*/
if ((*(slash + 1) == '/') && ((colon == NULL && slash == start) ||
(colon != NULL && slash == colon + 1)))
{
/*
* Check for filename at end of host string.
*/
slash += 2;
if ((fslash = strchr(slash, '/')) != NULL)
{
up->hostname = MPGet(mp, fslash - slash + 1);
strncpy(up->hostname, slash, fslash - slash);
up->hostname[fslash - slash] = '\0';
up->filename = MPStrDup(mp, fslash);
}
else
{ /* there is no filename */
up->hostname = MPStrDup(mp, slash);
}
}
else
{
/*
* the rest is a filename because there is no // or it appears
* after other characters
*/
if (colon != NULL && colon < slash)
{
up->filename = MPStrDup(mp, colon + 1);
}
else up->filename = MPStrDup(mp, start);
}
}
else
{
/*
* No slashes at all so the rest must be a filename.
*/
if (colon == NULL) up->filename = MPStrDup(mp, start);
else up->filename = MPStrDup(mp, colon + 1);
}
/*
* If there is a host string then divide it into
* username:password@hostname:port as needed.
*/
if (up->hostname != NULL)
{
/*
* Look for username:password.
*/
if ((at = strchr(up->hostname, '@')) != NULL)
{
char *mumble;
up->username = MPGet(mp, at - up->hostname + 1);
strncpy(up->username, up->hostname, at - up->hostname);
up->username[at - up->hostname] = '\0';
mumble = MPStrDup(mp, at + 1);
up->hostname = mumble;
if ((ucolon = strchr(up->username, ':')) != NULL)
{
up->password = MPStrDup(mp, ucolon + 1);
*ucolon = '\0';
}
}
/*
* Grab the port.
*/
if ((pcolon = strchr(up->hostname, ':')) != NULL)
{
up->port = atoi(pcolon + 1);
*pcolon = '\0';
}
}
/*
* Check the filename for a '#foo' string.
*/
if (up->filename != NULL)
{
if ((pound = strchr(up->filename, '#')) != NULL)
{
*pound = '\0';
up->fragment = MPStrDup(mp, pound + 1);
if (strlen(up->filename) == 0) up->filename = NULL;
}
}
return(up);
}
/*
* URLIsAbsolute
*/
bool
URLIsAbsolute(up)
URLParts *up;
{
if (up->scheme == NULL) return(false);
return(true);
}
/*
* URLBaseFilename
*/
char *
URLBaseFilename(mp, up)
MemPool mp;
URLParts *up;
{
char *cp;
if (up->filename == NULL) return(NULL);
for (cp = up->filename + strlen(up->filename) - 1;
cp >= up->filename; cp--)
{
if (*cp == '/') break;
}
cp++;
if (*cp == '\0') return(NULL);
return(MPStrDup(mp, cp));
}
/*
* URLGetScheme
*/
char *
URLGetScheme(mp, url)
MemPool mp;
char *url;
{
char *cp, *dp;
char *r;
for (cp = url; *cp != '\0'; cp++)
{
for (dp = URLDELIMS; *dp != '\0'; dp++)
{
if (*cp == *dp)
{
if (*cp == ':')
{
r = (char *)MPCGet(mp, cp - url + 1);
strncpy(r, url, cp - url);
return(r);
}
return(NULL);
}
}
}
return(NULL);
}

61
common/url.h Normal file
View file

@ -0,0 +1,61 @@
/*
* url.h
*
* Copyright (c) 1995-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __URL_H__
#define __URL_H__ 1
#include "common.h"
/*
* <scheme>://<net_loc>/<path>;<params>?<query>#<fragment>
*
* net_loc = username:password@hostname:port
*/
typedef struct
{
char *scheme;
char *username;
char *password;
char *hostname;
int port;
char *filename;
char *params;
char *query;
char *fragment;
} URLParts;
int URLcmp _ArgProto((URLParts *, URLParts *));
char *URLMakeString _ArgProto((MemPool, URLParts *, bool));
URLParts *URLResolve _ArgProto((MemPool, URLParts *, URLParts *));
URLParts *URLParse _ArgProto((MemPool, char *));
char *URLUnescape _ArgProto((MemPool, char *));
char *URLEscape _ArgProto((MemPool, char *, bool));
URLParts *URLDup _ArgProto((MemPool, URLParts *));
bool URLIsAbsolute _ArgProto((URLParts *));
char *URLBaseFilename _ArgProto((MemPool, URLParts *));
char *URLGetScheme _ArgProto((MemPool, char *));
/*
* url_translate.c
*/
int URLReadTranslations _ArgProto((GList, char *));
char *URLTranslate _ArgProto((MemPool, GList, char *));
#endif

196
common/util.c Normal file
View file

@ -0,0 +1,196 @@
/*
* util.c
*
* Copyright (C) 1993-1997, John Kilburg <john@cs.unlv.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "port_before.h"
#include <stdio.h>
#include <pwd.h>
#include <errno.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <time.h>
#include "port_after.h"
#include "common.h"
/*
* FixPath
*
* The only thing this does right now is to handle the '~' stuff.
*/
char *
FixPath(mp, filename)
MemPool mp;
char *filename;
{
struct passwd *p;
char *cp, *cp2;
char username[BUFSIZ];
char *fname;
char *home;
char *newfilename;
if (filename[0] == '~') fname = filename;
else if (filename[0] == '/' && filename[1] == '~') fname = filename + 1;
else fname = NULL;
if (fname != NULL)
{
if (fname[1] == '/')
{
if ((home = getenv("HOME")) == NULL) return(NULL);
cp = fname + 1;
}
else
{
for (cp = fname + 1, cp2 = username; *cp && *cp != '/'; cp++, cp2++)
{
*cp2 = *cp;
}
*cp2 = '\0';
p = getpwnam(username);
if (p == NULL) return(NULL);
home = p->pw_dir;
}
newfilename = (char *)MPGet(mp, strlen(home) + strlen(cp) + 1);
strcpy(newfilename, home);
strcat(newfilename, cp);
}
else
{
newfilename = MPStrDup(mp, filename);
}
return(newfilename);
}
/*
* mystrtok
*
*/
char *
mystrtok(s, c, cdr)
char *s;
size_t c;
char **cdr;
{
char *cp, *cp2;
static char str[BUFSIZ];
if (s == NULL) return(NULL);
for (cp = s, cp2 = str; ; cp++)
{
if (*cp == '\0') break;
else if (*cp == c)
{
for (cp++; *cp == c; )
{
cp++;
}
break;
}
else *cp2++ = *cp;
if (cp2 == str + BUFSIZ - 1) break;
}
*cp2 = '\0';
if (*cp == '\0') *cdr = NULL;
else *cdr = cp;
return(str);
}
/*
* GetBaseFilename
*/
char *
GetBaseFilename(path)
char *path;
{
char *cp;
if (path == NULL) return(NULL);
for (cp = path + strlen(path) - 1; cp >= path; cp--)
{
if (*cp == '/') break;
}
cp++;
if (*cp == '\0') return(NULL);
return(cp);
}
/*
* xmyassert
*/
void
xmyassert(isok, msg, file, line)
bool isok;
char *msg;
char *file;
int line;
{
if (!isok)
{
fprintf (stderr, "%s: %d\n", file, line);
fprintf (stderr, "%s\n", msg);
fflush(stderr);
abort();
}
return;
}
#ifndef P_tmpdir
#define P_tmpdir "/tmp"
#endif
#ifndef L_tmpnam
#define L_tmpnam 256
#endif
/*
* mytmpnam
*/
char *
mytmpnam(mp)
MemPool mp;
{
char *n;
n = (char *)MPGet(mp, L_tmpnam + 1);
snprintf (n, L_tmpnam, "%s/%d%ld",
P_tmpdir, getpid(), (long)time(NULL));
return(n);
}