/* Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Low-level variable management routines. */
#include "wims.h"
#define VARBUF_LEN (256*1024)
#define VARBUF_NUM 16
#define VARNAME_LEN 32768
#define VARNUM_LIMIT 4096
#define vb_internal 1
#define vb_ro 2
#define vb_dirty 4
#define vb_noexport 8
#define vb_hacked 16
char *_varbuf[VARBUF_NUM]; /* main variable value buffer */
char *_varptr;
int _varbufcurr;
char *_varnamebuf, *_varnameptr; /* variable name buffer */
/* wims_ variables that should be exported */
char *exportvars[]={
"class",
"deposit",
"home",
"inssub",
"sesdir",
"session",
"site_languages",
"supervisor",
"supervisormail",
"tmp_debug",
"user",
"version",
};
int exportvarcnt=(sizeof(exportvars)/sizeof(exportvars[0]));
struct vartab {
char *name, *val;
unsigned short int vlen;
char tag,lvl;
} fastvartab[128], mainvartab[VARNUM_LIMIT];
/* int vlenmin[]={0,1,20,45,100,200,400,800,1500,3000,6000}; */
int vlenmax[]={1,32,64,128,256,512,1024,2048,4096,8192,MAX_LINELEN+1};
int freelim[]={1,500,500,300,200,150,100,80,60,50,30};
#define lvlno (sizeof(vlenmax)/sizeof(vlenmax[0]))
#define freevtot (1+500+500+300+200+150+100+80+60+50+30)
int freevars[lvlno], freevstart[lvlno];
int freevcnt=0,bufvcnt=0;
char *freevbuf[freevtot];
int mainvarcnt=0;
void add_hack(char *name);
void get_var_privileges(void)
{
int sav=untrust;
untrust=0;
var_readable=getvar("wims_readable");
var_writable=getvar("wims_writable");
var_nr=getvar("wims_nr");
var_nw=getvar("wims_nw");
var_pfx=getvar("wims_prefix");
untrust=sav;
}
/* Returns 1 if rights OK. Else 0. */
int var_checkright(char *name, char *allow, char *deny, char *prefix)
{
if(strcmp(name
,"wims_read_parm")==0) return 1;
if(allow!=NULL && allow[0]!=0 && wordchr(allow,name)!=NULL) return 1;
if(deny!=NULL && deny[0]!=0 && wordchr(deny,name)!=NULL) return 0;
if(prefix!=NULL && prefix[0]!=0) {
char *p, buf[MAX_NAMELEN+1];
for(p=name; *p!=0 && *p!='_'; p++);
if(*p!='_' || p-name>=MAX_NAMELEN) return 0;
memmove(buf
,name
,p
-name
); buf
[p
-name
]=0;
if(wordchr(prefix,buf)==NULL) return 0;
}
return 1;
}
/* initialisation */
void var_init(void)
{
int i,j;
memset(freevars
,0,sizeof(freevars
));
_varbufcurr=0;
_varbuf[0]=xmalloc(VARBUF_LEN);
_varnamebuf=xmalloc(VARNAME_LEN);
_varptr=_varbuf[0]; _varnameptr=_varnamebuf;
for(i=j=0;i<lvlno;i++) {freevstart[i]=j; j+=freelim[i];}
if(j!=freevtot) internal_error("var.c: wrong count freevtot!");
}
void exportall(void)
{
int i, j, tag; char buf[MAX_NAMELEN+17];
char *p, *p1, *p2;
char *noexpword[1024];
int noexplen[1024];
int noexpcnt;
noexpcnt=0;
p=getvar("wims_noexport"); if(p==NULL) p="";
for(p1=find_word_start(p),noexpcnt=0;
*p1 && noexpcnt<1024;
p1=find_word_start(p2)) {
p2=find_word_end(p1);
noexpword[noexpcnt]=p1; noexplen[noexpcnt]=p2-p1;
noexpcnt++;
}
for(i=0;i<mainvarcnt;i++) {
tag=mainvartab[i].tag;
if((tag&vb_dirty)==0 || (tag&vb_noexport)!=0) continue;
p=mainvartab[i].name;
for(j
=0;j
<noexpcnt
;j
++) if(strncmp(p
,noexpword
[j
],noexplen
[j
])==0) {
mainvartab[i].tag|=vb_noexport;
goto lend;
}
if(mainvartab[i].tag&vb_hacked) {
add_hack(p); mainvartab[i].tag&=~vb_hacked;
}
snprintf(buf
,sizeof(buf
),"%s%s",var_prefix
,p
);
setenv(buf,mainvartab[i].val,1);
mainvartab[i].tag&=~vb_dirty;
lend: ;
}
}
char *vaskbuf(int lvl)
{
char *p;
if(lvl>=lvlno) { /* should never occur */
module_error("Internal_variable_length_overflow"); return NULL;
}
if(freevars[lvl]>0) {
freevars[lvl]--; freevcnt--;
return freevbuf[freevstart[lvl]+freevars[lvl]];
}
if(_varptr+vlenmax[lvl]>=_varbuf[_varbufcurr]+VARBUF_LEN) {
if(_varbufcurr>=VARBUF_NUM) {
module_error("variable_buffer_overflow"); return NULL;
}
_varbufcurr++; _varptr=_varbuf[_varbufcurr]=xmalloc(VARBUF_LEN);
}
bufvcnt++;
p=_varptr; _varptr+=vlenmax[lvl]; return p;
}
/* returns 1 if free succeeded. */
int vfreebuf(int lvl, char *p)
{
if(p>=_varptr) return 0;
if(p+vlenmax[lvl]==_varptr) {_varptr=p; bufvcnt--;return 1;}
if(lvl<=0 || lvl>=lvlno || freevars[lvl]>=freelim[lvl]) return 0;
freevcnt++;
freevbuf[freevstart[lvl]+freevars[lvl]]=p; freevars[lvl]++; return 1;
}
int _char_int(char *vn)
{
int t; char v;
v=vn[0]; if(vn[1]) t=64; else t=0;
if(v>='0' && v<='9') return v-'0'+t;
else {
if(v>='A' && v<='Z') return v-'A'+10+t;
else {
if(v>='a' && v<='z') return v-'a'+10+26+t;
else return -1;
}
}
}
int var_ins(char *name,int inspoint)
{
int i, nlen, tag;
if(mainvarcnt>=VARNUM_LIMIT) {
module_error("too_many_variable_names"); return -1;
}
for(nlen=0;nlen<=MAX_NAMELEN && (myisalnum(name[nlen]) || name[nlen]=='_');nlen++);
if(nlen<=1 || nlen>MAX_NAMELEN || name[nlen]!=0) return -1;
if(_varnameptr+nlen+1>_varnamebuf+VARNAME_LEN) {
module_error("variable_name_buffer_overflow"); return -1;
}
tag=0;
if(search_list(ro_name,RO_NAME_NO,sizeof(ro_name[0]),name)>=0)
tag|=vb_ro;
if(nlen
<=2 || strncmp(name
,mathfont_prefix
,strlen(mathfont_prefix
))==0 ||
name[nlen-1]=='_')
tag|=vb_noexport;
if(var_noexport) tag|=vb_noexport;
if(name
[0]=='w' && strncmp(name
,wims_prefix
,wpflen
)==0) {
if(search_list(exportvars,exportvarcnt,sizeof(exportvars[0]),name+wpflen)<0)
tag|=vb_noexport;
search_list(internal_name,INTERNAL_NAME_NO,sizeof(internal_name[0]),name+wpflen)>=0)
tag|=vb_internal;
}
i=inspoint; if(i>mainvarcnt) i=mainvarcnt; if(i<0) i=0;
memmove(mainvartab
+i
+1,mainvartab
+i
,(mainvarcnt
-i
)*sizeof(mainvartab
[0]));
mainvarcnt++; nlen++;
mainvartab[i].name=_varnameptr; _varnameptr+=nlen;
mainvartab[i].val=NULL; mainvartab[i].vlen=0;
mainvartab[i].tag=tag;
mainvartab[i].lvl=0; return i;
}
char *fast_getvar(char *vname)
{
int n;
n=_char_int(vname); if(n<0) return "";
if(fastvartab[n].tag&vb_hacked) {
add_hack(vname); fastvartab[n].tag&=~vb_hacked;
}
getvar_len=fastvartab[n].vlen;
return fastvartab[n].val;
}
int _setvar_(struct vartab *vtb, char *vval)
{
int l,lvl;
char *p;
if(vval
) l
=strlen(vval
); else l
=0;
if(l>MAX_LINELEN) return 1;
lvl=vtb->lvl;
if(l==0) {
if(lvl>0) {
vfreebuf(lvl,vtb->val); vtb->tag|=vb_dirty;
if(var_hacking) vtb->tag|=vb_hacked; else vtb->tag&=~vb_hacked;
vtb->lvl=0; vtb->vlen=0;
}
if(vval) vtb->val=""; else vtb->val=NULL;
return 0;
}
if(l>=vlenmax[lvl]) {
vfreebuf(lvl,vtb->val);
do lvl++; while(l>=vlenmax[lvl]);
vtb->lvl=lvl;
vtb->val=p=vaskbuf(lvl);
}
else p=vtb->val;
vtb->vlen=l; vtb->tag|=vb_dirty;
if(var_hacking) vtb->tag|=vb_hacked; else vtb->tag&=~vb_hacked;
}
int fast_setvar(char *vname, char *vval)
{
int n;
n=_char_int(vname); if(n<0) return 1;
return _setvar_(fastvartab+n,vval);
}
/* internal constant */
int setvar_force=0;
/* Set a user variable. Now it no longer uses environment.
* Returns 0 if OK. */
int setvar(char *vname, char *vvalue)
{
int i,overwrite,tag;
if(vname[0]==0) return 1;
if((vname[1]==0 || (vname[1]=='_' && vname[2]==0)))
return fast_setvar(vname,vvalue);
i=search_list(mainvartab,mainvarcnt,sizeof(mainvartab[0]),vname);
if(i<0) i=var_ins(vname,~i);
if(i<0) return 1; /* error */
overwrite=1; tag=mainvartab[i].tag;
if(setvar_force==0 && confset==0) {
/* user file has no right to modify wims variables. */
if((untrust&6)!=0) {
if(var_checkright(vname,var_writable,var_nw,var_pfx)==0)
return 1;
if(strncmp(vname
,wims_prefix
,wpflen
)==0 &&
strcmp(vname
,"wims_read_parm")!=0) return 1;
}
if((tag&vb_ro)!=0) overwrite=0;
else if((tag&vb_internal)!=0 && !trusted_module()) return 1;
}
if(!overwrite && mainvartab[i].val!=NULL) return 1;
_setvar_(mainvartab+i,vvalue);
if(vname[0]=='w') {
if(strcmp(vname
,"wims_print_precision")==0) {
if(a>0 && a<100) print_precision=a;
}
if(strcmp(vname
,"wims_backslash_insmath")==0) {
if(strcasecmp(vvalue,"yes")==0) backslash_insmath=1;
else backslash_insmath=0;
}
}
if (trace_file && wordchr(tmp_debug_var,vname)) {
fprintf(trace_file
,"\n%s='%s'\n",vname
,vvalue
);
}
return 0;
}
int force_setvar(char *vname,char *vvalue)
{
int i;
setvar_force=1; i=setvar(vname,vvalue); setvar_force=0; return i;
}
void unsetvar(char *vname)
{
int i;
if(vname[0]!=0 && (vname[1]==0 || (vname[1]=='_' && vname[2]==0))) {
fast_setvar(vname,NULL); return;
}
i=search_list(mainvartab,mainvarcnt,sizeof(mainvartab[0]),vname);
if(i>=0) _setvar_(mainvartab+i,NULL);
}
/* Get a variable's value. */
char *_getvar(char *vname)
{
char *val;
int i;
if((untrust&4)!=0 || vname[0]==0) return ""; /* called from !readdef */
if(vname[1]==0 || (vname[1]=='_' && vname[2]==0)) return fast_getvar(vname);
if((untrust&6)!=0) {
if(var_checkright(vname,var_readable,var_nr,var_pfx)==0)
return "";
}
i=search_list(mainvartab,mainvarcnt,sizeof(mainvartab[0]),vname);
if(i<0) val=NULL; else {
if(mainvartab[i].tag&vb_hacked) {
add_hack(vname); mainvartab[i].tag&=~vb_hacked;
}
val=mainvartab[i].val; getvar_len=mainvartab[i].vlen;
}
if(vname
[0]=='w' && strcmp(vname
,"wims_incremental")==0) {
static char buf[32];
if(val==NULL) i=0;
mystrncpy(buf,int2str(i),sizeof(buf));
force_setvar
(vname
,buf
); getvar_len
=strlen(buf
); val
=buf
;
}
return val;
}
char *getvar(char *vname)
{
char *val;
getvar_len=0; val=_getvar(vname);
if(val
==NULL
&& memcmp(vname
,mathfont_prefix
,strlen(mathfont_prefix
))==0) {// mathfont_prefix m_ is add
val=mathfont(vname);
if(val
) getvar_len
=strlen(val
); else getvar_len
=0;
}
if (trace_file && wordchr(tmp_debug_use_var,vname)) {
fprintf(trace_file
,"\nuse %s:'%s'\n",vname
,val
);
}
return val;
}
/* Search variables with numeric subscripts, from beg to end.
* Store result to pbuf. Returns number of variables found.
*/
int varsuite(char *stem, int beg, int end, char *pbuf[], int pbuflen)
{
int i,t,l,v;
i=search_list(mainvartab,mainvarcnt,sizeof(mainvartab[0]),stem);
if(i<0) i=~i;
for(t
=0,l
=strlen(stem
);i
<mainvarcnt
&& t
<pbuflen
;i
++){
if(strncmp(mainvartab
[i
].
name,stem
,l
)!=0) break;
v
=atoi(mainvartab
[i
].
name+l
); if(v
<beg
|| v
>end
) continue;
if(mainvartab[i].val==NULL || mainvartab[i].val[0]==0) continue;
pbuf[t++]=mainvartab[i].name;
}
return t;
}
/* output debug information */
void debug_output(void)
{
long int endmtime2, time1;
struct timeval tv;
struct rusage us;
if(noout || robot_access || strcasecmp(tmp_debug,"yes")!=0 ||
checkhost(manager_site)<1) return;
if(instex_cnt>0) instex_flush();
if(gettimeofday(&tv,NULL)) endmtime2=0;
else endmtime2=((tv.tv_sec%1000)*1000000+tv.tv_usec);
endmtime2=(endmtime2-startmtime2)/100;
time1=0;
if(getrusage(RUSAGE_SELF,&us)==0) {
time1+=us.ru_utime.tv_sec*1000+us.ru_utime.tv_usec/1000;
time1+=us.ru_stime.tv_sec*1000+us.ru_stime.tv_usec/1000;
}
if(getrusage(RUSAGE_CHILDREN,&us)==0) {
time1+=us.ru_utime.tv_sec*1000+us.ru_utime.tv_usec/1000;
time1+=us.ru_stime.tv_sec*1000+us.ru_stime.tv_usec/1000;
}
snprintf(tmplbuf
,sizeof(tmplbuf
),"%d,%d,%d,%.4f,%.2f,%d,%d,%d",
(int)(_varptr-_varbuf[_varbufcurr])+_varbufcurr*VARBUF_LEN,
bufvcnt-freevcnt,freevcnt,
(double) endmtime2/10000, (double) time1/1000,
mcachecnt,mfilecnt,execnt);
setvar("wims_debug_info",tmplbuf);
lastout_file=-1; phtml_put_base("debug.phtml",0);
}
/* Add to list of hacked variables */
void add_hack(char *name)
{
char buf[MAX_LINELEN+1];
char *p;
p=getvar("wims_hacked_variables"); if(p==NULL) buf[0]=0;
if(p
-buf
>= sizeof(buf
)-strlen(name
)-4) return; /* too long */
if(p
>buf
) snprintf(p
,sizeof(buf
)-(p
-buf
),", %s",name
);
else snprintf(buf
,sizeof(buf
),"%s",name
);
setvar("wims_hacked_variables",buf);
}