static char rcsid[] = "@(#)$Id: url_path.c,v 1.5 2006/05/07 08:35:31 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.5 $ $State: Exp $
*
* Author: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* or Kari Hurtta <elm@elmme-mailer.org>
*****************************************************************************/
#include "def_url.h"
#include "s_me.h"
DEBUG_VAR(Debug,__FILE__,"url");
static unsigned char * s2us P_((char *str));
static unsigned char * s2us(str)
char *str;
{
return (unsigned char *)str;
}
static struct url_path_elem * alloc_url_path_elem P_((void));
static struct url_path_elem * alloc_url_path_elem()
{
struct url_path_elem * ret = safe_malloc (sizeof (*ret));
/* bzero is defined hdrs/defs.h */
bzero((void *)ret,sizeof (*ret));
ret->magic = URL_path_elem_magic;
ret->elem = NULL;
ret->trailing_slash = 0;
return ret;
}
static void free_url_path_elem P_((struct url_path_elem **ptr));
static void free_url_path_elem(ptr)
struct url_path_elem **ptr;
{
if (URL_path_elem_magic != (*ptr)->magic)
panic("URL PANIC",__FILE__,__LINE__,"free_url_path_elem",
"bad magic number",0);
if ((*ptr)->elem)
free_url_element(& ((*ptr)->elem));
(*ptr)->trailing_slash = 0;
(*ptr)->magic = 0; /* Invalidate */
free(*ptr);
*ptr = NULL;
}
struct url_path_elem * dup_url_path_elem P_((struct url_path_elem *ptr));
struct url_path_elem * dup_url_path_elem(ptr)
struct url_path_elem *ptr;
{
struct url_path_elem * ret = alloc_url_path_elem();
if (URL_path_elem_magic != ptr->magic)
panic("URL PANIC",__FILE__,__LINE__,"dup_url_path_elem",
"bad magic number",0);
if (ptr->elem)
ret->elem = dup_url_element(ptr->elem);
ret->trailing_slash = ptr->trailing_slash;
return ret;
}
enum elem_class { p_error, p_normal, p_this, p_up
} classify_url_path_elem P_((struct url_path_elem *ptr));
enum elem_class classify_url_path_elem(ptr)
struct url_path_elem *ptr;
{
CONST struct string * parsed;
uint16 ch;
int len;
if (URL_path_elem_magic != ptr->magic)
panic("URL PANIC",__FILE__,__LINE__,"classify_url_path_elem",
"bad magic number",0);
if (!ptr->elem)
panic("URL PANIC",__FILE__,__LINE__,"classify_url_path_elem",
"Is root element?",0);
parsed = parsed_from_element(ptr->elem,NULL);
if (!parsed)
return p_error;
len = string_len(parsed);
if (len < 1)
return p_normal;
ch = give_unicode_from_string(parsed,0);
if (0x002E /* . */ != ch)
return p_normal;
if (1 == len)
return p_this; /* "." */
ch = give_unicode_from_string(parsed,1);
if (0x002E /* . */ != ch)
return p_normal;
if (2 == len)
return p_up; /* ".." */
return p_normal;
}
/* ------------------------------------------------------------------------- */
#define URL_path_magic 0xEC04
struct url_path {
unsigned short magic; /* URL_path_magic */
struct url_path_elem **elems;
int elem_count;
};
static struct url_path * alloc_url_path P_((void));
static struct url_path * alloc_url_path()
{
struct url_path *ret = safe_malloc (sizeof (*ret));
/* bzero is defined hdrs/defs.h */
bzero((void *)ret,sizeof (*ret));
ret->magic = URL_path_magic;
ret->elems = NULL;
ret->elem_count = 0;
return ret;
}
struct url_path * raw_to_url_path(raw)
struct string *raw;
{
int len = string_len(raw);
int X = 0;
int startpos = 0;
int count = 1;
struct url_path_elem **elems;
int elem_count = 0;
struct url_path *ret = NULL;
uint16 ch = 0;
for (X = 0; X < len; X++) {
ch = give_unicode_from_string(raw,X);
if (0x002F /* / */ == ch)
count++;
}
DPRINT(Debug,12,(&Debug,
"url_from_raw: count=%d raw=%S\n",
count,raw));
elems = safe_malloc(count * sizeof (elems[0]));
/* Special first element ... */
X = 0;
if (len > 0) {
ch = give_unicode_from_string(raw,X);
if (0x002F /* / */ == ch) {
elems[0] = alloc_url_path_elem();
elems[0]->elem = NULL;
elems[0]->trailing_slash = 1;
DPRINT(Debug,12,(&Debug,
"raw_to_url_path: trailing slash -- root element\n"));
elem_count = 1;
X++;
ch = 0;
}
}
while ( X < len && elem_count < count) {
struct string * elem = NULL;
int L;
startpos = X;
for (; X < len; X++) {
ch = give_unicode_from_string(raw,X);
if (0x002F /* / */ == ch)
break;
}
L = X - startpos;
elem = clip_from_string(raw,&startpos,L);
if (startpos != X)
panic("URL PANIC",__FILE__,__LINE__,"raw_to_url_path",
"Clipping Error",0);
DPRINT(Debug,12,(&Debug,
"raw_to_url_path: elem=%S\n",elem));
elems[elem_count] = alloc_url_path_elem();
elems[elem_count]->elem = element_from_raw(elem);
if (0x002F /* / */ == ch) {
elems[elem_count]->trailing_slash = 1;
DPRINT(Debug,12,(&Debug,
"raw_to_url_path: trailing slash\n"));
X++; /* Skip / */
ch = 0;
}
elem_count++;
free_string(&elem);
}
ret = alloc_url_path();
ret->elems = elems;
ret->elem_count = elem_count;
DPRINT(Debug,12,(&Debug,
"raw_to_url_path: elem_count=%d\n",elem_count));
return ret;
}
int url_path_len(path)
struct url_path *path;
{
if (URL_path_magic != path->magic)
panic("URL PANIC",__FILE__,__LINE__,"url_path_len",
"bad magic number",0);
return path->elem_count;
}
CONST struct url_path_elem * get_url_path_element(path,idx)
struct url_path *path;
int idx;
{
if (URL_path_magic != path->magic)
panic("URL PANIC",__FILE__,__LINE__,"get_url_path_element",
"bad magic number",0);
if (idx < 0 || idx >= path->elem_count)
panic("URL PANIC",__FILE__,__LINE__,"get_url_path_element",
"bad index",0);
if (! path->elems[idx])
panic("URL PANIC",__FILE__,__LINE__,"get_url_path_element",
"NULL element",0);
return path->elems[idx];
}
void free_url_path(path)
struct url_path **path;
{
if (URL_path_magic != (*path)->magic)
panic("URL PANIC",__FILE__,__LINE__,"free_url_path",
"bad magic number",0);
if ((*path)->elems) {
int i;
for (i = 0; i < (*path)->elem_count; i++) {
if ((*path)->elems[i])
free_url_path_elem(& ((*path)->elems[i]));
}
free((*path)->elems);
(*path)->elems = NULL;
}
(*path)->elem_count = 0;
(*path)->magic = 0; /* Invalidate */
free(*path);
*path = NULL;
}
struct url_path * join_url_path(parent,relative)
struct url_path *parent;
struct url_path *relative;
{
int count;
struct url_path_elem **elems;
int elem_count = 0;
int i;
struct url_path *ret = NULL;
if (URL_path_magic != parent->magic)
panic("URL PANIC",__FILE__,__LINE__,"join_url_path",
"bad magic number (parent)",0);
if (URL_path_magic != relative->magic)
panic("URL PANIC",__FILE__,__LINE__,"join_url_path",
"bad magic number (relative)",0);
if (parent->elem_count < 1)
panic("URL PANIC",__FILE__,__LINE__,"join_url_path",
"Empty parent",0);
count = parent->elem_count + relative->elem_count;
elems = safe_malloc(count * sizeof (elems[0]));
if (!parent->elems[0]->trailing_slash ||
parent->elems[0]->elem)
panic("URL PANIC",__FILE__,__LINE__,"join_url_path",
"Parent is not absolute",0);
elems[elem_count++] = dup_url_path_elem(parent->elems[0]);
for (i = 1; i < parent->elem_count; i++) {
if (!parent->elems[i]->trailing_slash)
break;
elems[elem_count++] = dup_url_path_elem(parent->elems[i]);
}
if (elem_count < parent->elem_count-1)
panic("URL PANIC",__FILE__,__LINE__,"join_url_path",
"Bad parent path",0);
for (i = 0; i < relative->elem_count; i++) {
enum elem_class c = classify_url_path_elem(relative->elems[i]);
if (p_error == c)
goto failure;
if (p_this == c) /* Skip "." element */
continue;
if (p_up == c && elem_count > 1) {
enum elem_class c1 = classify_url_path_elem(elems[elem_count]);
if (p_error == c1)
goto failure;
if (p_normal == c1) { /* Remove one element */
free_url_path_elem(& elems[elem_count]);
elem_count--;
continue;
}
elems[elem_count++] = dup_url_path_elem(relative->elems[i]);
}
}
ret = alloc_url_path();
ret->elems = elems;
ret->elem_count = elem_count;
DPRINT(Debug,12,(&Debug,
"join_url_path: elem_count=%d\n",elem_count));
return ret;
failure:
for (i = 0; i < elem_count; i++)
free_url_path_elem(& elems[i]);
free(elems);
return NULL;
}
struct url_path * dup_url_path(path)
struct url_path *path;
{
struct url_path_elem **elems = NULL;
int elem_count = 0;
struct url_path *ret = NULL;
if (URL_path_magic != path->magic)
panic("URL PANIC",__FILE__,__LINE__,"dup_url_path",
"bad magic number",0);
if (path->elem_count > 0) {
int i;
elems = safe_malloc(path->elem_count * sizeof (elems[0]));
for (i = 0; i < path->elem_count; i++) {
elems[elem_count++] = dup_url_path_elem(path->elems[i]);
}
}
ret = alloc_url_path();
ret->elems = elems;
ret->elem_count = elem_count;
DPRINT(Debug,12,(&Debug,
"dup_url_path: elem_count=%d\n",elem_count));
return ret;
}
struct string * url_path_to_raw(url_path)
struct url_path *url_path;
{
struct string * ret = NULL;
charset_t ascii_ptr = MIME_name_to_charset("US-ASCII",0);
int i;
if (!ascii_ptr)
panic("CHARSET PANIC",__FILE__,__LINE__,"url_path_to_raw",
"US-ASCII not found",0);
if (URL_path_magic != url_path->magic)
panic("URL PANIC",__FILE__,__LINE__,"url_path_to_raw",
"bad magic number",0);
ret = new_string(ascii_ptr);
for (i = 0; i < url_path->elem_count; i++) {
/* On first element this is NULL */
if (url_path->elems[i]->elem) {
CONST struct string * R =
raw_from_element(url_path->elems[i]->elem);
if (!R) {
DPRINT(Debug,12,(&Debug,
"url_path_to_raw: Failed to get url path element\n"));
goto failure;
}
append_string(&ret,R);
}
/* This should be set on all elements except last */
if (url_path->elems[i]->trailing_slash) {
add_ascii_to_string(ret,s2us("/"));
}
}
return ret;
failure:
free_string(&ret);
return NULL;
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1