/**
* data.c
*
* Copyright (C) 2003 - 2008 Bojan Smojver, Rexursive
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
*/
#include "private.h"
/*
* Data creation and transformation functions
*/
/* single data element from a string, no copying */
rxv_spin_data_t *rxv_spin_datum(apr_pool_t *pool,const char *str,
rxv_spin_data_t *data){
apr_size_t size;
if(!((pool || data) && str) || (size=strlen(str))==RXV_SPIN_ROWS)
return NULL;
/* allocate data if required */
if(!data) data=apr_pcalloc(pool,sizeof(*data));
data->size=size;
data->data=(char *)str;
return data;
}
/* single data element from a counted string, no copying */
rxv_spin_data_t *rxv_spin_mdatum(apr_pool_t *pool,const char *str,
apr_size_t size,rxv_spin_data_t *data){
if(!((pool || data) && str) || size==RXV_SPIN_ROWS || *(str+size)!='\0')
return NULL;
/* allocate data if required */
if(!data) data=apr_pcalloc(pool,sizeof(*data));
data->size=size;
data->data=(char *)str;
return data;
}
/* string from single */
char *rxv_spin_string(rxv_spin_data_t *single){
if(!single || single->size==RXV_SPIN_ROWS)
return NULL;
return single->data;
}
/* hash table from rows */
apr_hash_t *rxv_spin_guts(rxv_spin_data_t *rows){
if(!(rows && rows->size==RXV_SPIN_ROWS))
return NULL;
return rows->cols;
}
/* size of single */
apr_size_t rxv_spin_size(rxv_spin_data_t *data){
if(!data)
return 0;
if(data->size==RXV_SPIN_ROWS){
apr_array_header_t *a;
apr_hash_index_t *hi=apr_hash_first(apr_hash_pool_get(data->cols),
data->cols);
if(hi){
apr_hash_this(hi,NULL,NULL,(void **)&a);
return (apr_size_t)a->nelts;
} else{
return 0;
}
} else{
return data->size;
}
}
/* column of rows from other data elements, no copying */
rxv_spin_data_t *rxv_spin_column(apr_pool_t *pool,const char *name,
rxv_spin_data_t *data,...){
va_list ap;
rxv_spin_data_t *rows,*d;
apr_array_header_t *a;
int size=0;
if(!(pool && name))
return NULL;
/* allocate rows if required */
rows=data?data:apr_pcalloc(pool,sizeof(*rows));
/* count the elements first */
va_start(ap,data);
while((d=va_arg(ap,rxv_spin_data_t*)))
size++;
va_end(ap);
rows->size=RXV_SPIN_ROWS;
rows->cols=apr_hash_make(pool);
apr_hash_set(rows->cols,name,APR_HASH_KEY_STRING,
a=apr_array_make(pool,size,sizeof(*d)));
/* populate array */
va_start(ap,data);
while((d=va_arg(ap,rxv_spin_data_t*)))
*((rxv_spin_data_t *)apr_array_push(a))=*d;
va_end(ap);
return rows;
}
/* column of rows from string by parsing, no copying */
rxv_spin_data_t *rxv_spin_parse(apr_pool_t *pool,const char *name,
char *str,const char *sep,
rxv_spin_data_t *data){
char *t,*last=NULL;
rxv_spin_data_t *p;
apr_array_header_t *a;
if(!(pool && name && str && sep))
return NULL;
a=apr_array_make(pool,10,sizeof(*p));
/* parse the string and store it into an array */
for(t=apr_strtok(str,sep,&last);t;t=apr_strtok(NULL,sep,&last)){
p=apr_array_push(a);
p->size=strlen(t);
p->data=t;
}
if(apr_is_empty_array(a))
return NULL;
/* allocate data if required */
if(!data) data=apr_pcalloc(pool,sizeof(*data));
data->size=RXV_SPIN_ROWS;
data->cols=apr_hash_make(pool);
apr_hash_set(data->cols,name,APR_HASH_KEY_STRING,a);
return data;
}
/* column of rows from an array of nul terminated strings, no copying */
rxv_spin_data_t *rxv_spin_array(apr_pool_t *pool,const char *name,
apr_array_header_t *arr,rxv_spin_data_t *data){
rxv_spin_data_t *p;
apr_array_header_t *a;
int i;
if(!(pool && name && arr))
return NULL;
/* allocate data if required */
if(!data) data=apr_pcalloc(pool,sizeof(*data));
data->size=RXV_SPIN_ROWS;
data->cols=apr_hash_make(pool);
apr_hash_set(data->cols,name,APR_HASH_KEY_STRING,
a=apr_array_make(pool,arr->nelts,sizeof(*p)));
/* copy content */
for(i=0;inelts;i++){
char *buf=apr_pstrdup(pool,*((char**)arr->elts+i));
p=apr_array_push(a);
p->size=strlen(buf);
p->data=buf;
}
return data;
}
/* column of rows from a brigade, full copying */
rxv_spin_data_t *rxv_spin_brigade(apr_pool_t *pool,const char *name,
apr_bucket_brigade *bb,
rxv_spin_data_t *data){
apr_bucket *b;
rxv_spin_data_t *p;
apr_array_header_t *a;
int size=0;
if(!(pool && name && bb))
return NULL;
/* allocate data if required */
if(!data) data=apr_pcalloc(pool,sizeof(*data));
/* count the number of buckets */
for(b=APR_BRIGADE_FIRST(bb);b!=APR_BRIGADE_SENTINEL(bb);b=APR_BUCKET_NEXT(b))
size++;
data->size=RXV_SPIN_ROWS;
data->cols=apr_hash_make(pool);
apr_hash_set(data->cols,name,APR_HASH_KEY_STRING,
a=apr_array_make(pool,size,sizeof(*p)));
/* copy content */
for(b=APR_BRIGADE_FIRST(bb);b!=APR_BRIGADE_SENTINEL(bb);b=APR_BUCKET_NEXT(b)){
char *buf=apr_palloc(pool,b->length);
const char *str;
apr_size_t pos=0,len;
while(poslength){
len=b->length-pos;
if(apr_bucket_read(b,&str,&len,APR_BLOCK_READ)!=APR_SUCCESS)
return NULL;
memcpy(buf+pos,str,len);
pos+=len;
}
p=apr_array_push(a);
p->size=strlen(buf);
p->data=buf;
}
return data;
}
/* create an empty column of rows */
rxv_spin_data_t *rxv_spin_null(apr_pool_t *pool,const char *name,
apr_size_t size,rxv_spin_data_t *data){
apr_array_header_t *a;
apr_size_t i;
if(!(pool && name && size>0))
return NULL;
/* allocate data if required */
if(!data) data=apr_pcalloc(pool,sizeof(*data));
data->size=RXV_SPIN_ROWS;
data->cols=apr_hash_make(pool);
apr_hash_set(data->cols,name,APR_HASH_KEY_STRING,
a=apr_array_make(pool,(int)size,sizeof(*data)));
for(i=0;isize!=RXV_SPIN_ROWS || !(hi=apr_hash_first(pool,s->cols)))
return NULL;
apr_hash_this(hi,NULL,NULL,(void **)&a);
if(a->nelts>size)
size=a->nelts;
}
va_end(ap);
/* allocate rows if required */
rows=data?data:apr_pcalloc(pool,sizeof(*rows));
rows->size=RXV_SPIN_ROWS;
rows->cols=apr_hash_make(pool);
/* populate */
va_start(ap,data);
while((s=va_arg(ap,rxv_spin_data_t*))){
apr_hash_index_t *hi;
apr_array_header_t *a;
char *k;
apr_ssize_t len;
for(hi=apr_hash_first(pool,s->cols);hi;hi=apr_hash_next(hi)){
apr_hash_this(hi,(const void **)&k,&len,(void **)&a);
apr_hash_set(rows->cols,k,len,a);
while(a->neltssize==RXV_SPIN_ROWS))
return 0;
/* allocate rows if required */
iter=apr_pcalloc(pool,sizeof(*iter));
iter->rows=rows;
iter->size=-1;
/* find size */
va_start(ap,rows);
while((s=va_arg(ap,const char*))){
c=va_arg(ap,rxv_spin_curs_t **);
if(!(a=apr_hash_get(rows->cols,s,APR_HASH_KEY_STRING)))
return 0;
if(!*c) *c=apr_pcalloc(pool,sizeof(**c));
(*c)->iter=iter;
(*c)->data=a;
if(iter->size<=0)
iter->size=(*c)->data->nelts;
}
va_end(ap);
return iter->index>=iter->size?0:(apr_size_t)(iter->index+1);
}
/* get next row */
apr_size_t rxv_spin_next(rxv_spin_curs_t *curs){
rxv_spin_iter_t *iter;
if(!curs)
return 0;
iter=curs->iter;
if(iter->indexsize)
iter->index++;
return iter->index>=iter->size?0:(apr_size_t)(iter->index+1);
}
/* get a piece of data */
rxv_spin_data_t *rxv_spin_this(rxv_spin_curs_t *curs){
if(!(curs && curs->iter->index<=curs->iter->size))
return NULL;
return ((rxv_spin_data_t *)curs->data->elts)+curs->iter->index;
}
/* get an entry from rows */
rxv_spin_data_t *rxv_spin_entry(rxv_spin_data_t *rows,const char *name,
apr_size_t index){
apr_array_header_t *a;
if(!(rows && rows->size==RXV_SPIN_ROWS && name && index))
return NULL;
if(!(a=apr_hash_get(rows->cols,name,APR_HASH_KEY_STRING)) ||
a->nelts<(int)index)
return NULL;
return ((rxv_spin_data_t *)a->elts)+index-1;
}
/* resize rows */
rxv_spin_data_t *rxv_spin_resize(rxv_spin_data_t *data,apr_size_t size){
apr_hash_index_t *hi;
apr_array_header_t *a;
if(!(data && size>=0 && data->size==RXV_SPIN_ROWS))
return NULL;
for(hi=apr_hash_first(apr_hash_pool_get(data->cols),data->cols);
hi;hi=apr_hash_next(hi)){
apr_hash_this(hi,NULL,NULL,(void **)&a);
if(a->nelts>(int)size)
while(a->nelts>(int)size)
apr_array_pop(a);
else
while(a->nelts<(int)size)
apr_array_push(a);
}
return data;
}
/* copy data (full copy) */
rxv_spin_data_t *rxv_spin_copy(apr_pool_t *pool,rxv_spin_data_t *src,
rxv_spin_data_t *data){
int i;
apr_hash_index_t *hi;
char *k,*s;
void *v;
apr_ssize_t len;
if(!(pool && src))
return NULL;
/* allocate data if required */
if(!data) data=apr_pcalloc(pool,sizeof(*data));
if(src->size==RXV_SPIN_ROWS){
apr_array_header_t *a,*b;
data->cols=apr_hash_make(pool);
for(hi=apr_hash_first(pool,src->cols);hi;hi=apr_hash_next(hi)){
apr_hash_this(hi,(const void **)&k,&len,&v);
s=apr_pstrmemdup(pool,k,len);
b=apr_array_make(pool,(a=(apr_array_header_t *)v)->nelts,sizeof(*data));
apr_hash_set(data->cols,s,len,b);
for(i=0;inelts;i++)
rxv_spin_copy(pool,((rxv_spin_data_t *)a->elts)+i,apr_array_push(b));
}
data->size=RXV_SPIN_ROWS;
} else{
data->data=apr_pstrmemdup(pool,src->data,src->size);
data->size=src->size;
}
return data;
}
/* string to upper/lower functions */
char *rxv_spin_slower(const char *str){
char *p;
if(!str)
return NULL;
for(p=(char *)str;*p;p++)
*p=tolower(*p);
return (char *)str;
}
char *rxv_spin_supper(const char *str){
char *p;
if(!str)
return NULL;
for(p=(char *)str;*p;p++)
*p=toupper(*p);
return (char *)str;
}
/* string trim function */
char *rxv_spin_strim(const char *str,rxv_spin_trim_e what){
char *tmp,*s=(char *)str;
apr_size_t size;
if(!str)
return NULL;
size=strlen(str);
if(what&RXV_SPIN_TRIM_LEFT){
for(tmp=s;size>0 && apr_isspace(*tmp);tmp++)
size--;
s=tmp;
}
if(what&RXV_SPIN_TRIM_RIGHT)
for(tmp=s+size-1;size>0 && apr_isspace(*tmp);tmp--){
*tmp='\0';
size--;
}
return s;
}