/**
* data.c
*
* Copyright (C) 2003 - 2007 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"
/* something we can always assign as read only */
static const char *empty="";
/*
* Data creation and transformation functions
*/
/* single data element from a string, no copying */
rxv_spin_data_t *rxv_spin_single(apr_pool_t *pool,const char *str){
rxv_spin_data_t *data;
if(!(pool && str))
return NULL;
data=apr_pcalloc(pool,sizeof(*data));
data->type=RXV_SPIN_DATA_SGL;
data->size=strlen(str);
data->data=(char *)str;
return data;
}
/* string from single */
char *rxv_spin_single_get(rxv_spin_data_t *single){
if(!(single && single->type==RXV_SPIN_DATA_SGL))
return NULL;
return single->data;
}
/* replace the data (string) in an exisiting single, no copying */
rxv_spin_data_t *rxv_spin_single_set(rxv_spin_data_t *single,const char *str){
if(!(single && single->type==RXV_SPIN_DATA_SGL && str))
return NULL;
single->size=strlen(str);
single->data=(char *)str;
return single;
}
/* single data element from a counted string, no copying */
rxv_spin_data_t *rxv_spin_single_mem(apr_pool_t *pool,const char *str,
apr_size_t size){
rxv_spin_data_t *data;
if(!(pool && str && *(str+size)=='\0'))
return NULL;
data=apr_pcalloc(pool,sizeof(*data));
data->type=RXV_SPIN_DATA_SGL;
data->size=size;
data->data=(char *)str;
return data;
}
/* replace the data (counted string) in an exisiting single, no copying */
rxv_spin_data_t *rxv_spin_single_memset(rxv_spin_data_t *single,const char *str,
apr_size_t size){
if(!(single && single->type==RXV_SPIN_DATA_SGL && str && *(str+size)=='\0'))
return NULL;
single->size=size;
single->data=(char *)str;
return single;
}
/* single to upper/lower functions */
rxv_spin_data_t *rxv_spin_single_tolower(rxv_spin_data_t *single){
char *p;
apr_size_t i;
if(!(single && single->type==RXV_SPIN_DATA_SGL))
return NULL;
for(i=0,p=single->data;isize;i++,p++)
*p=tolower(*p);
return single;
}
rxv_spin_data_t *rxv_spin_single_toupper(rxv_spin_data_t *single){
char *p;
apr_size_t i;
if(!(single && single->type==RXV_SPIN_DATA_SGL))
return NULL;
for(i=0,p=single->data;isize;i++,p++)
*p=toupper(*p);
return single;
}
/* single trim function */
rxv_spin_data_t *rxv_spin_single_trim(rxv_spin_data_t *single,
rxv_spin_trim_e what){
if(!(single && single->type==RXV_SPIN_DATA_SGL))
return NULL;
if(what&RXV_SPIN_TRIM_LEFT)
while(single->size>0 && isspace(*single->data)){
single->data++;
single->size--;
}
if(what&RXV_SPIN_TRIM_RIGHT){
char *tmp;
for(tmp=single->data+single->size-1;single->size>0 && isspace(*tmp);tmp--){
*tmp='\0';
single->size--;
}
}
return single;
}
/* metadata element (array) from other data elements, no copying */
rxv_spin_data_t *rxv_spin_meta(apr_pool_t *pool,...){
va_list ap;
rxv_spin_data_t *meta,*d,*p;
if(!pool)
return NULL;
/* allocate meta */
meta=apr_pcalloc(pool,sizeof(*meta));
meta->type=RXV_SPIN_DATA_MTA;
/* count the elements first */
va_start(ap,pool);
while((d=va_arg(ap,rxv_spin_data_t*)))
meta->size++;
va_end(ap);
/* allocate array */
meta->meta=apr_palloc(pool,sizeof(*meta->meta)*meta->size);
p=meta->meta;
/* populate array */
va_start(ap,pool);
while((d=va_arg(ap,rxv_spin_data_t*))){
*p=*d;
p++;
}
va_end(ap);
return meta;
}
/* metadata element (array) from strings, no copying */
rxv_spin_data_t *rxv_spin_meta_vstr(apr_pool_t *pool,...){
char *s;
va_list ap;
rxv_spin_data_t *meta,*p;
if(!pool)
return NULL;
/* allocate meta */
meta=apr_pcalloc(pool,sizeof(*meta));
meta->type=RXV_SPIN_DATA_MTA;
/* count the elements first */
va_start(ap,pool);
while((s=va_arg(ap,char*)))
meta->size++;
va_end(ap);
/* allocate array */
meta->meta=apr_palloc(pool,sizeof(*meta->meta)*meta->size);
p=meta->meta;
/* populate array */
va_start(ap,pool);
while((s=va_arg(ap,char*))){
p->type=RXV_SPIN_DATA_SGL;
p->size=strlen(s);
p->data=s;
p++;
}
va_end(ap);
return meta;
}
/* metadata element (array) from string by parsing, no copying */
rxv_spin_data_t *rxv_spin_meta_parse(apr_pool_t *pool,
char *str,const char *sep){
char *t,*last=NULL;
rxv_spin_data_t *meta,*p;
struct list{
char *str;
struct list *next;
} *list,*end,*tmp;
if(!(pool && str && sep))
return NULL;
/* allocate meta */
meta=apr_pcalloc(pool,sizeof(*meta));
meta->type=RXV_SPIN_DATA_MTA;
list=end=NULL;
/* parse the string and store it into a linked list */
for(t=apr_strtok(str,sep,&last);t;t=apr_strtok(NULL,sep,&last)){
tmp=apr_pcalloc(pool,sizeof(*tmp));
tmp->str=t;
if(list){
end->next=tmp;
end=tmp;
} else{
list=end=tmp;
}
meta->size++;
}
/* allocate array */
meta->meta=apr_palloc(pool,sizeof(*meta->meta)*meta->size);
p=meta->meta;
/* populate array */
for(tmp=list;tmp;tmp=tmp->next){
p->type=RXV_SPIN_DATA_SGL;
p->size=strlen(tmp->str);
p->data=tmp->str;
p++;
}
return meta;
}
/* metadata element (array) from brigade, full copying */
rxv_spin_data_t *rxv_spin_meta_brigade(apr_pool_t *pool,apr_bucket_brigade *bb){
apr_bucket *b;
rxv_spin_data_t *meta,*p;
if(!(pool && bb))
return NULL;
/* allocate meta */
meta=apr_pcalloc(pool,sizeof(*meta));
meta->type=RXV_SPIN_DATA_MTA;
/* count the number of buckets */
for(b=APR_BRIGADE_FIRST(bb);b!=APR_BRIGADE_SENTINEL(bb);b=APR_BUCKET_NEXT(b))
meta->size++;
/* allocate array */
meta->meta=apr_palloc(pool,sizeof(*meta->meta)*meta->size);
p=meta->meta;
/* 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->type=RXV_SPIN_DATA_SGL;
p->size=strlen(buf);
p->data=buf;
p++;
}
return meta;
}
/* create an empty column of metadata */
rxv_spin_data_t *rxv_spin_meta_empty(apr_pool_t *pool,apr_size_t size){
rxv_spin_data_t *column;
if(!(pool && size>0))
return NULL;
column=apr_palloc(pool,sizeof(*column));
column->meta=apr_pcalloc(pool,sizeof(*column->meta)*size);
column->type=RXV_SPIN_DATA_MTA;
column->size=size;
return column;
}
/* hash metadata */
apr_hash_t *rxv_spin_meta_hash(apr_pool_t *pool,rxv_spin_data_t *data){
apr_size_t i;
apr_hash_t *hash;
rxv_spin_data_t *meta;
if(!(pool && data && data->type==RXV_SPIN_DATA_MTA))
return NULL;
if(!(hash=apr_hash_make(pool)))
return NULL;
meta=data->meta;
for(i=0;isize;i++){
rxv_spin_data_t *s=meta+i;
if(s->type==RXV_SPIN_DATA_SGL)
apr_hash_set(hash,s->data,s->size,s);
}
return hash;
}
/* mark an element in the metadata */
rxv_spin_data_t *rxv_spin_meta_mark(rxv_spin_data_t *data,apr_size_t element){
rxv_spin_data_t *single;
if(!(data && data->type==RXV_SPIN_DATA_MTA &&
element>=0 && elementsize))
return NULL;
single=data->meta+element;
single->type=RXV_SPIN_DATA_SGL;
single->size=0;
single->data=(char *)empty;
return data;
}
/* mark each n-th element in the metadata */
rxv_spin_data_t *rxv_spin_meta_markeach(rxv_spin_data_t *data,
apr_size_t off,apr_size_t step){
apr_size_t i;
rxv_spin_data_t *single;
if(!(data && data->type==RXV_SPIN_DATA_MTA &&
off>=0 && offsize && step>0 && stepsize))
return NULL;
single=data->meta;
for(i=off;isize;i+=step,single+=step){
single->type=RXV_SPIN_DATA_SGL;
single->size=0;
single->data=(char *)empty;
}
return data;
}
/* select (mark) data that matches given data set */
rxv_spin_data_t *rxv_spin_meta_select(rxv_spin_data_t *data,
rxv_spin_data_t *select,
apr_hash_t *hash){
apr_size_t i,j;
rxv_spin_data_t *s,*f;
if(!(data && data->type==RXV_SPIN_DATA_MTA &&
select &&
(select->type==RXV_SPIN_DATA_SGL || select->type==RXV_SPIN_DATA_MTA)))
return NULL;
/* try hashed search first */
if(hash){
if(select->type==RXV_SPIN_DATA_SGL){
if((s=apr_hash_get(hash,select->data,select->size))){
s->type=RXV_SPIN_DATA_SGL;
s->size=0;
s->data=(char *)empty;
}
} else{
for(j=0;jsize;j++){
f=select->meta+j;
if(f->type==RXV_SPIN_DATA_SGL &&
(s=apr_hash_get(hash,f->data,f->size))){
s->type=RXV_SPIN_DATA_SGL;
s->size=0;
s->data=(char *)empty;
}
}
}
} else{ /* no hash, simple linear search */
if(select->type==RXV_SPIN_DATA_SGL){
for(i=0;isize;i++){
s=data->meta+i;
if(select->size==s->size && !strncmp(select->data,s->data,s->size)){
s->type=RXV_SPIN_DATA_SGL;
s->size=0;
s->data=(char *)empty;
}
}
} else{
for(i=0;isize;i++){
s=data->meta+i;
if(s->type==RXV_SPIN_DATA_SGL){
for(j=0;jsize;j++){
f=select->meta+j;
if(f->size==s->size && !strncmp(f->data,s->data,s->size)){
s->type=RXV_SPIN_DATA_SGL;
s->size=0;
s->data=(char *)empty;
}
}
}
}
}
}
return data;
}
/* rows data element from metadata elements (arrays), no copying */
rxv_spin_data_t *rxv_spin_rows(apr_pool_t *pool,...){
char *s;
va_list ap;
rxv_spin_data_t *meta,*rows;
if(!pool)
return NULL;
/* allocate */
rows=apr_palloc(pool,sizeof(*rows));
rows->cols=apr_hash_make(pool);
rows->type=RXV_SPIN_DATA_RWS;
rows->size=0;
/* populate */
va_start(ap,pool);
while((s=va_arg(ap,char*))){
meta=va_arg(ap,rxv_spin_data_t*);
apr_hash_set(rows->cols,s,APR_HASH_KEY_STRING,meta->meta);
if(rows->size){
if(meta->sizesize)
rows->size=meta->size;
} else{
rows->size=meta->size;
}
}
va_end(ap);
return rows;
}
/* hash a column inside rows */
apr_hash_t *rxv_spin_rows_hash(apr_pool_t *pool,rxv_spin_data_t *rows,
const char *column){
apr_size_t i;
apr_hash_t *hash;
rxv_spin_data_t *col;
if(!(pool && rows && rows->type==RXV_SPIN_DATA_RWS && column &&
(col=apr_hash_get(rows->cols,column,APR_HASH_KEY_STRING))))
return NULL;
if(!(hash=apr_hash_make(pool)))
return NULL;
for(i=0;isize;i++){
rxv_spin_data_t *s=col+i;
if(s->type==RXV_SPIN_DATA_SGL)
apr_hash_set(hash,s->data,s->size,s);
}
return hash;
}
/* mark an element in the column of rows of data */
rxv_spin_data_t *rxv_spin_rows_mark(rxv_spin_data_t *rows,const char *column,
apr_size_t element){
rxv_spin_data_t *col,*single;
if(!(rows && rows->type==RXV_SPIN_DATA_RWS &&
column && element>=0 && elementsize &&
(col=apr_hash_get(rows->cols,column,APR_HASH_KEY_STRING))))
return NULL;
single=col+element;
single->type=RXV_SPIN_DATA_SGL;
single->size=0;
single->data=(char *)empty;
return rows;
}
/* mark each n-th element in the column of rows of data */
rxv_spin_data_t *rxv_spin_rows_markeach(rxv_spin_data_t *rows,
const char *column,
apr_size_t off,apr_size_t step){
apr_size_t i;
rxv_spin_data_t *col,*single;
if(!(rows && rows->type==RXV_SPIN_DATA_RWS &&
off>=0 && offsize && column && step>0 && stepsize &&
(col=apr_hash_get(rows->cols,column,APR_HASH_KEY_STRING))))
return NULL;
single=col+off;
for(i=off;isize;i+=step,single+=step){
single->type=RXV_SPIN_DATA_SGL;
single->size=0;
single->data=(char *)empty;
}
return rows;
}
/* select (mark) rows of data that match given data set */
rxv_spin_data_t *rxv_spin_rows_select(rxv_spin_data_t *rows,
rxv_spin_data_t *select,
const char *column,const char *marker,
apr_hash_t *hash){
apr_size_t i,j;
rxv_spin_data_t *col,*mrk,*s,*f;
if(!(rows && rows->type==RXV_SPIN_DATA_RWS &&
select &&
(select->type==RXV_SPIN_DATA_SGL || select->type==RXV_SPIN_DATA_MTA) &&
column && marker &&
(col=apr_hash_get(rows->cols,column,APR_HASH_KEY_STRING)) &&
(mrk=apr_hash_get(rows->cols,marker,APR_HASH_KEY_STRING))))
return NULL;
/* try hashed search first */
if(hash){
if(select->type==RXV_SPIN_DATA_SGL){
if((s=apr_hash_get(hash,select->data,select->size))){
s=mrk+(s-col);
s->type=RXV_SPIN_DATA_SGL;
s->size=0;
s->data=(char *)empty;
}
} else{
for(j=0;jsize;j++){
f=select->meta+j;
if(f->type==RXV_SPIN_DATA_SGL &&
(s=apr_hash_get(hash,f->data,f->size))){
s=mrk+(s-col);
s->type=RXV_SPIN_DATA_SGL;
s->size=0;
s->data=(char *)empty;
}
}
}
} else{ /* no hash, simple linear search */
if(select->type==RXV_SPIN_DATA_SGL){
for(i=0;isize;i++){
s=col+i;
if(s->type==RXV_SPIN_DATA_SGL &&
select->size==s->size && !strncmp(select->data,s->data,s->size)){
s=mrk+i;
s->type=RXV_SPIN_DATA_SGL;
s->size=0;
s->data=(char *)empty;
}
}
} else{
for(i=0;isize;i++){
s=col+i;
if(s->type==RXV_SPIN_DATA_SGL){
for(j=0;jsize;j++){
f=select->meta+j;
if(f->type==RXV_SPIN_DATA_SGL &&
f->size==s->size && !strncmp(f->data,s->data,s->size)){
s=mrk+i;
s->type=RXV_SPIN_DATA_SGL;
s->size=0;
s->data=(char *)empty;
}
}
}
}
}
}
return rows;
}
/* get a column of data from rows */
rxv_spin_data_t *rxv_spin_column_get(apr_pool_t *pool,
rxv_spin_data_t *rows,const char *key){
rxv_spin_data_t *column;
if(!(rows && rows->type==RXV_SPIN_DATA_RWS && key))
return NULL;
column=apr_palloc(pool,sizeof(*column));
column->type=RXV_SPIN_DATA_MTA;
column->size=rows->size;
column->meta=apr_hash_get(rows->cols,key,APR_HASH_KEY_STRING);
return column;
}
/* set a column of data in rows */
rxv_spin_data_t *rxv_spin_column_set(rxv_spin_data_t *rows,
const char *key,rxv_spin_data_t *column){
if(!(rows && rows->type==RXV_SPIN_DATA_RWS && key))
return NULL;
if(column){
if(!(column->size>=rows->size && column->type==RXV_SPIN_DATA_MTA))
return NULL;
apr_hash_set(rows->cols,key,APR_HASH_KEY_STRING,column->meta);
} else{
apr_hash_set(rows->cols,key,APR_HASH_KEY_STRING,column);
}
return column;
}
/* resize rows or metadata */
rxv_spin_data_t *rxv_spin_resize(apr_pool_t *pool,rxv_spin_data_t *data,
apr_size_t size){
rxv_spin_data_t *mta,*tmp;
apr_size_t i;
apr_hash_index_t *hi;
const void *key;
void *val;
apr_ssize_t len;
if(!(pool && data && size>=0 &&
(data->type==RXV_SPIN_DATA_RWS || data->type==RXV_SPIN_DATA_MTA)))
return NULL;
/* shrink or stay the same */
if(size<=data->size){
data->size=size;
return data;
}
/* make larger */
switch(data->type){
case RXV_SPIN_DATA_RWS:
for(hi=apr_hash_first(pool,data->cols);hi;hi=apr_hash_next(hi)){
apr_hash_this(hi,&key,&len,&val);
if(key && len>0 && val){
tmp=apr_pcalloc(pool,sizeof(*tmp)*size);
apr_hash_set(data->cols,key,len,tmp);
mta=val;
for(i=0;isize;i++)
*(tmp+i)=*(mta+i);
} else{
return NULL;
}
}
break;
case RXV_SPIN_DATA_MTA:
tmp=apr_pcalloc(pool,sizeof(*tmp)*size);
data->meta=tmp;
mta=data->meta;
for(i=0;isize;i++)
*(tmp+i)=*(mta+i);
default:
return NULL;
break;
}
data->size=size;
return data;
}
/* copy data (full copy) */
rxv_spin_data_t *rxv_spin_copy(apr_pool_t *pool,rxv_spin_data_t *data){
rxv_spin_data_t *copy,*mta,*tmp;
apr_size_t i;
apr_hash_index_t *hi;
const void *key;
void *val;
char *s;
apr_ssize_t len;
if(!(pool && data))
return NULL;
copy=apr_pcalloc(pool,sizeof(*copy));
switch(data->type){
case RXV_SPIN_DATA_SGL:
copy->data=apr_pstrmemdup(pool,data->data,data->size);
break;
case RXV_SPIN_DATA_RWS:
if(!(copy->cols=apr_hash_make(pool)))
return NULL;
for(hi=apr_hash_first(pool,data->cols);hi;hi=apr_hash_next(hi)){
apr_hash_this(hi,&key,&len,&val);
if(key && len>0 && val){
s=apr_pstrmemdup(pool,key,len);
mta=apr_palloc(pool,sizeof(*mta)*data->size);
apr_hash_set(copy->cols,s,len,mta);
for(i=0;isize;i++){
if((tmp=rxv_spin_copy(pool,((rxv_spin_data_t *)val)+i)))
*(mta+i)=*tmp;
else
memset(mta+i,0,sizeof(rxv_spin_data_t));
}
} else{
return NULL;
}
}
break;
case RXV_SPIN_DATA_MTA:
copy->meta=apr_palloc(pool,sizeof(*copy->meta)*data->size);
for(i=0;isize;i++){
if((tmp=rxv_spin_copy(pool,data->meta+i)))
*(copy->meta+i)=*tmp;
else
memset(copy->meta+i,0,sizeof(rxv_spin_data_t));
}
break;
default:
return NULL;
break;
}
copy->type=data->type;
copy->size=data->size;
return copy;
}
/* string to upper/lower functions */
char *rxv_spin_str_tolower(const char *str){
char *p;
if(!str)
return NULL;
for(p=(char *)str;*p;p++)
*p=tolower(*p);
return (char *)str;
}
char *rxv_spin_str_toupper(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_str_trim(char *str,rxv_spin_trim_e what){
char *tmp;
apr_size_t size;
if(!str)
return NULL;
size=strlen(str);
if(what&RXV_SPIN_TRIM_LEFT){
for(tmp=str;size>0 && isspace(*tmp);tmp++)
size--;
memmove(str,tmp,size+1);
}
if(what&RXV_SPIN_TRIM_RIGHT)
for(tmp=str+size-1;size>0 && isspace(*tmp);tmp--){
*tmp='\0';
size--;
}
return str;
}