/** * data.c * * Copyright (C) 2003, 2004 Bojan Smojver, Rexursive * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licence as published by the Free * Software Foundation; either version 2 of the Licence, 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 Licence for * more details. * * You should have received a copy of the GNU General Public Licence along * with this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place, Suite 330, Boston, MA 02111-1307 USA * * In addition, as two special exceptions, Bojan Smojver, Rexursive, gives * permission to: * * 1. Link, both statically and dynamically, the code of this program with * Apache HTTP Server, Apache Portable Runtime and Apache Portable Runtime * Utility Library from Apache Software Foundation (or with modified versions * of the above, that use the same licence - Apache Software Licence 1.1, 2.0 * or any later version), and distribute linked combinations including the * program and the above software from Apache Software Foundation. You must * obey the GNU General Public Licence in all respects for all of the code * used other than Apache HTTP Server, Apache Portable Runtime and Apache * Portable Runtime Utility Library. * * 2. Dynamically link any shared library with this program at run-time, * through the interface of SpinApplication/SpinAppEntry or LoadModule * run-time configuration directives of Apache HTTP Server, as provided by * this program or Apache HTTP Server itself, regardless of licensing terms of * those shared libraries. You must obey the GNU General Public Licence in all * respects for all of the code used other than that of those shared * libraries. * * If you modify this file, you may extend these exceptions to your version of * the file, but you are not obligated to do so. If you do not wish to do so, * delete one or both of these exception statements from your version. * */ #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; if(!(data=apr_pcalloc(pool,sizeof(*data)))) return NULL; 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, size_t size){ rxv_spin_data_t *data; if(!(pool && str && *(str+size)=='\0')) return NULL; if(!(data=apr_pcalloc(pool,sizeof(*data)))) return NULL; 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, 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; 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; 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, unsigned char 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 */ if(!(meta=apr_pcalloc(pool,sizeof(*meta)))) return NULL; 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 */ if(!(meta->meta=apr_palloc(pool,sizeof(*meta->meta)*meta->size))) return NULL; 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 */ if(!(meta=apr_pcalloc(pool,sizeof(*meta)))) return NULL; 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 */ if(!(meta->meta=apr_palloc(pool,sizeof(*meta->meta)*meta->size))) return NULL; 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 */ if(!(meta=apr_pcalloc(pool,sizeof(*meta)))) return NULL; 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)){ if(!(tmp=apr_pcalloc(pool,sizeof(*tmp)))) return NULL; tmp->str=t; if(list){ end->next=tmp; end=tmp; } else{ list=end=tmp; } meta->size++; } /* allocate array */ if(!(meta->meta=apr_palloc(pool,sizeof(*meta->meta)*meta->size))) return NULL; 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; } /* create an empty column of metadata */ rxv_spin_data_t *rxv_spin_meta_empty(apr_pool_t *pool,size_t size){ rxv_spin_data_t *column; if(!(pool && size>0 && (column=apr_palloc(pool,sizeof(*column))))) return NULL; if(!(column->meta=apr_pcalloc(pool,sizeof(*column->meta)*size))) return NULL; 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){ 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,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, size_t off,size_t step){ 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){ 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=(rxv_spin_data_t *)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=(rxv_spin_data_t *)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 */ if(!((rows=apr_palloc(pool,sizeof(*rows))) && (rows->cols=apr_hash_make(pool)))) return NULL; 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){ size_t i; apr_hash_t *hash; rxv_spin_data_t *meta,*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; meta=col; 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 column of rows of data */ rxv_spin_data_t *rxv_spin_rows_mark(rxv_spin_data_t *rows,const char *column, size_t element){ rxv_spin_data_t *col,*single; if(!(rows && rows->type==RXV_SPIN_DATA_RWS && column && element>=0 && elementsize && (col=(rxv_spin_data_t *)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, size_t off,size_t step){ 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=(rxv_spin_data_t *)apr_hash_get(rows->cols,column, APR_HASH_KEY_STRING)))) return NULL; single=col; 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){ 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=(rxv_spin_data_t *)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=(rxv_spin_data_t *)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; if(!(column=apr_palloc(pool,sizeof(*column)))) return NULL; 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, size_t size){ rxv_spin_data_t *mta,*tmp; 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){ if(!(tmp=apr_pcalloc(pool,sizeof(*tmp)*size))) return NULL; apr_hash_set(data->cols,key,len,tmp); mta=(rxv_spin_data_t *)val; for(i=0;isize;i++) *(tmp+i)=*(mta+i); } else{ return NULL; } } break; case RXV_SPIN_DATA_MTA: if(!(tmp=apr_pcalloc(pool,sizeof(*tmp)*size))) return NULL; 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; size_t i; apr_hash_index_t *hi; const void *key; void *val; char *s; apr_ssize_t len; if(!(pool && data)) return NULL; if(!(copy=apr_pcalloc(pool,sizeof(*copy)))) return NULL; switch(data->type){ case RXV_SPIN_DATA_SGL: if(!(copy->data=apr_pstrmemdup(pool,data->data,data->size))) return NULL; 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){ if(!(s=apr_pstrmemdup(pool,key,len))) return NULL; if(!(mta=apr_palloc(pool,sizeof(*mta)*data->size))) return NULL; 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: if(!(copy->meta=apr_palloc(pool,sizeof(*copy->meta)*data->size))) return NULL; 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,unsigned char what){ char *tmp; 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; }