wmaker-eukara/dockapps/wmweather+/subst.c

189 lines
4.7 KiB
C

#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include "die.h"
#include "subst.h"
#define GROW(var, len){{ \
void *c; \
len<<=1; \
if(len==0) len=1; \
if((var=realloc(c=var, len))==NULL){ \
out=c; \
warn("realloc error"); \
goto fail; \
} \
}}
#define COPY(c) { \
if(k>=formatlen) GROW(format, formatlen); \
format[k++]=c; \
}
char *subst(const char *s, struct subst_val *substitutes){
int i, j, k, n, m;
char *out=NULL;
size_t outlen=0;
char *format=NULL;
size_t formatlen=0;
int flags;
ssize_t str_start;
for(i=j=0; s[i]!='\0'; i++){
if(s[i]!='%'){
if(j>=outlen) GROW(out, outlen);
out[j++]=s[i];
continue;
}
if(s[i+1]=='%'){
if(j>=outlen) GROW(out, outlen);
out[j++]=s[i++];
continue;
}
n=i;
k=0;
COPY('%');
/* skip flags */
flags=0;
while(strchr("#0- +'!", s[++n])){
if(s[n]=='!'){
flags|=1;
} else {
COPY(s[n]);
}
}
/* min width? */
if(isdigit(s[n]) && s[n]!='0'){
COPY(s[n]);
while(isdigit(s[++n])){ COPY(s[n]); }
}
/* precision? */
if(s[n]=='.'){
COPY('.');
while(isdigit(s[++n])){ COPY(s[n]); }
}
str_start=0;
if(s[n]=='>'){
if(s[n+1]=='-'){
flags|=2;
n++;
}
while(isdigit(s[++n])){
str_start=str_start*10+s[n]-'0';
}
if(flags&2) str_start=-str_start;
}
for(m=0; s[n]!=substitutes[m].id && substitutes[m].id!='\0'; m++);
if(substitutes[m].id=='\0'){
warn("Unknown substitition character '%c' (at %d)\n", s[n], i);
goto fail;
}
switch(substitutes[m].type){
case HEX:
case FLOAT_E:
case FLOAT_F:
case FLOAT_G:
case FLOAT_A:
if(flags&1){
COPY(toupper(substitutes[m].type));
break;
}
/* fall through*/
default:
COPY(substitutes[m].type);
break;
}
COPY('\0');
#define PRINT(var) { while((k=j+snprintf(out+j, outlen-j, format, var))>=outlen) GROW(out, outlen); j=k; }
switch(substitutes[m].type){
case INT:
PRINT(*(signed int *)substitutes[m].val);
break;
case UINT:
case OCTAL:
case HEX:
PRINT(*(unsigned int *)substitutes[m].val);
break;
case FLOAT_E:
case FLOAT_F:
case FLOAT_G:
case FLOAT_A:
PRINT(*(double *)substitutes[m].val);
break;
case CHAR:
PRINT(*(char *)substitutes[m].val);
if(flags&1) out[j-1]=toupper(out[j-1]);
break;
case STRING:
{
char *s=*(char **)substitutes[m].val;
if(str_start<0){
str_start+=strlen(s);
if(str_start<0) str_start=0;
} else if(str_start>strlen(s)){
s="";
str_start=0;
}
s+=str_start;
i=j;
PRINT(s);
if(flags&1){
for(; i<j; i++) out[i]=toupper(out[i]);
}
}
break;
default:
warn("Unknown substitution type '%c'\n", substitutes[m].type);
goto fail;
}
i=n;
}
free(format);
if(j>=outlen) GROW(out, outlen);
out[j]='\0';
return out;
fail:
free(format);
free(out);
return NULL;
}