/* 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.
*/
/* This is part of wims source.
* This file does computations and output.
*/
#include "wims.h"
int _sort_numeric, _sort_nocase;
typedef struct SORT_STRUCT {char *str; double val; int serial;} SORT_STRUCT;
struct SORT_STRUCT sort_sep[MAX_SORT_ITEM+1];
void secure_exec(void)
{
if((untrust&6)==0) return;
module_error("Illegal_command");
}
/* internal comparers */
int __sorter(const void *p1, const void *p2)
{
struct SORT_STRUCT *pp1, *pp2;
pp1=(struct SORT_STRUCT *) p1; pp2=(struct SORT_STRUCT *) p2;
if(_sort_numeric) {
double dd=(pp1->val)-(pp2->val);
if(dd>0) return 1;
if(dd<0) return -1;
return 0;
}
if(_sort_nocase) return mystrcmp(pp1->str,pp2->str);
else return strcmp(pp1
->str
,pp2
->str
);
}
int _char_sorter(const void *c1, const void *c2)
{
else return *(char *)c1-*(char *)c2;
}
enum {sort_char, sort_word, sort_item, sort_line, sort_row,
sort_numeric, sort_nocase, sort_reverse
};
struct {char *name; int type;
} sort_keyw[]={
{"char",sort_char},
{"chars",sort_char},
{"character",sort_char},
{"characters",sort_char},
{"word",sort_word},
{"words",sort_word},
{"item",sort_item},
{"items",sort_item},
{"line",sort_line},
{"lines",sort_line},
{"list",sort_item},
{"numeric",sort_numeric},
{"numerical",sort_numeric},
{"nocase",sort_nocase},
{"ignorecase",sort_nocase},
{"reverse",sort_reverse},
{"row",sort_row},
{"rows",sort_row}
};
#define sort_keyw_no (sizeof(sort_keyw)/sizeof(sort_keyw[0]))
/* string sort */
void calc_sort(char *p)
{
char *p1, *p2, buf[MAX_LINELEN+1], *csep[MAX_SORT_ITEM+1];
char fs=0;
int (*cutfn)(char *p,char *list[],int max);
int nocase=0, reverse=0, numeric=0, type;
int i,j,l,t,total;
cutfn=NULL;
for(i=0,p1=find_word_start(p);i>=0;p1=find_word_start(p2)) {
p2=find_word_end(p1);
if(*p2!=0) *p2++=0;
for(i=0;i<sort_keyw_no && strcasecmp(p1,sort_keyw[i].name)!=0;i++);
if(i>=sort_keyw_no) module_error("syntax_error");
switch(type=sort_keyw[i].type) {
case sort_nocase: nocase=1; break;
case sort_reverse: reverse=1; break;
case sort_numeric: numeric=1; break;
case sort_char: i=-1; break;
case sort_word: cutfn=cutwords; fs=' '; i=-1; break;
case sort_item: cutfn=cutitems; fs=','; i=-1; break;
case sort_row:
case sort_line: cutfn=cutlines; fs='\n'; i=-1; break;
}
}
if(p1[0]=='o' && p1[1]=='f' && myisspace(p1[2])) p1=find_word_start(p1+2);
mystrncpy(buf,p1,sizeof(buf)); substit(buf); *p=0;
t=0; if(type==sort_row) t=rows2lines(buf);
_sort_nocase=nocase; _sort_numeric=numeric;
if(cutfn) {
char ordbuf[MAX_LINELEN+1];
total=cutfn(buf,csep,MAX_SORT_ITEM+1);
if(total<=0 || total>MAX_SORT_ITEM) return;
for(i=0;i<total;i++) {
sort_sep[i].str=csep[i];
if(numeric) sort_sep[i].val=evalue(csep[i]);
}
for(i=0;i<total;i++) sort_sep[i].serial=i+1;
qsort(sort_sep
,total
,sizeof(sort_sep
[0]),__sorter
);
p1=p;p2=ordbuf;ordbuf[0]=0;
for(i=0;i<total;i++) {
if(reverse) j=total-1-i; else j=i;
if(p1-p+l>=MAX_LINELEN-1) module_error("cmd_output_too_long");
if(p1>p) *p1++=fs;
memmove(p1
,sort_sep
[j
].
str,l
+1); p1
+=l
;
if(i>0) *p2++=',';
mystrncpy(p2,int2str(sort_sep[j].serial),
MAX_LINELEN-(p2-ordbuf)-1);
}
force_setvar("wims_sort_order",ordbuf);
}
else { /* case of chars */
if(reverse) {
for(i=total-1;i>=0;i--) *(p+total-i-1)=buf[i];
*(p+total)=0;
}
}
if(t) lines2rows(p);
}
/* Print a debug output */
void calc_debug(char *p)
{
secure_exec(); setvar("debug",p); module_error("debug");
}
/* execute a command thru wimslogd */
void calc_daemon(char *p)
{
if(!trusted_module() || is_class_module) {*p=0; return;}
_daemoncmd(p);
}
void _get_exec_error(char *errorfname, char *cmdname)
{
char *p2;
char obuf[MAX_LINELEN+1];
int l;
if(errorfname) accessfile(obuf,"e","%s",errorfname);
else {
l=read(mxtab[multiexec_index].pipe_stderr[0],obuf,MAX_LINELEN/4);
if(l<0 || l>MAX_LINELEN) l=0;
obuf[l]=0;
}
if(obuf[0]) {
p2=find_word_end(obuf);
if((manageable<1 || strcasecmp(tmp_debug,"yes")!=0) &&
!trusted_module() &&
*p2=0; setvar("missing_software",obuf);
if(!outputing) user_error(p2+1);
}
p2=getvar("wims_exec_error"); if(p2==NULL) p2="";
snprintf(tmplbuf
,sizeof(tmplbuf
),"%s\nERROR from %s:\n%s",p2
,cmdname
,obuf
);
force_setvar("wims_exec_error",tmplbuf);
}
}
/* execute an external program
* The output of the external program should be put into
* a file session_directory/session/cmd.tmp.
*/
void calc_exec(char *p)
{
int i,j,k;
char *cmd, *parm, *pp;
char namebuf[MAX_EXEC_NAME+1], cmdstr[MAX_LINELEN+256], obuf[MAX_LINELEN+1];
char outfname[MAX_FNAME+1], errorfname[MAX_FNAME+1],
typefname[MAX_FNAME+1], varfname[MAX_FNAME+1];
char *abuf[2]={NULL,NULL};
WORKING_FILE wf;
if(robot_access
|| time(0)>=limtimex
-1) {
*p=0;return;
}
cmd=find_word_start(p); if(*cmd==0) return; /* No command. */
parm=find_word_end(cmd);j=parm-cmd;parm=find_word_start(parm);
if(j>MAX_EXEC_NAME) {
wrong_command:
setvar(error_data_string,namebuf); module_error("bad_cmd");
*p=0; return; /* should not occur */
}
memmove(namebuf
,cmd
,j
); namebuf
[j
]=0;
/* Specifying parent directory in command name is of course
* prohibited.
* The module developper cannot start from root, for bin_dir
* will be prefixed to cmd.
*/
if(strstr(namebuf
,parent_dir_string
)!=NULL
) {
setvar(error_data_string,namebuf); module_error("illegal_cmd");
*p=0; return;
}
snprintf(cmdstr
,sizeof(cmdstr
),"%s/%s",bin_dir
,namebuf
);
if(ftest(cmdstr)!=is_exec) goto wrong_command;
abuf[0]=cmdstr;
mkfname(outfname,"%s/exec.out",tmp_dir);
mkfname(errorfname,"%s/exec.err",tmp_dir);
mkfname(typefname,"%s/exec.type",tmp_dir);
unlink(typefname);
mkfname(varfname,"%s/exec.var",tmp_dir);
unlink(varfname);
if(!trusted_module()) setenv("untrust","yes",1); else unsetenv("untrust");
if(strcmp(parm
,"about")!=0 && multiexec
(namebuf
,abuf
)) {
fd_set rset;
struct timeval t;
int v1, v2, fd;
fd=mxtab[multiexec_index].pipe_stdin[1];
(void)write(fd,parm,i);
(void)write
(fd
,multiexec_random
,strlen(multiexec_random
));
*p=0; i=0; k=MAX_LINELEN; fd=mxtab[multiexec_index].pipe_stdout[0];
while(k>0) {
FD_ZERO(&rset); FD_SET(fd,&rset);
t.tv_sec=0; t.tv_usec=100000; v1=0; v2=300; /* 3 seconds */
if(select(fd+1,&rset,NULL,NULL,&t)<=0) {
v1++; if(v1>=v2) break;
else continue;
}
j=read(fd,p+i,k);
if(j<0 || j>k) break;
i+=j; k-=j; p[i]=0;
pp
=strstr(p
,multiexec_random
);
if(pp) {*pp=0; break;}
}
fd=mxtab[multiexec_index].pipe_stderr[0];
FD_ZERO(&rset); FD_SET(fd,&rset);
t.tv_sec=0; t.tv_usec=0;
if(select(fd+1,&rset,NULL,NULL,&t)>0)
_get_exec_error(NULL,namebuf);
strip_trailing_spaces(p);
return;
}
exportall(); setenv("wims_exec_parm",parm,1);
execredirected(cmdstr,NULL,outfname,errorfname,abuf);
if(open_working_file(&wf,varfname)==0) {
char *pt, *pv;
while(wgetline(tmplbuf,MAX_LINELEN, &wf)!=EOF) {
pt
=find_word_start
(tmplbuf
); pv
=strchr(pt
,'=');
if(pv==NULL || pv<=tmplbuf) continue;
*pv=0; pv=find_word_start(++pv);
*find_word_end(pt)=0;
strip_trailing_spaces(pv);
setvar(pt,pv);
}
close_working_file(&wf,0);
}
read_tmp_file(p,"exec.out");
read_tmp_file(obuf,"exec.type");
if(obuf
[0]) k
=atoi(obuf
); else k
=0;
for(i=2;i<=k && i<256;i++) {
char nbuf[32];
snprintf(nbuf
,sizeof(nbuf
),"exec.out.%d",i
);
read_tmp_file(obuf,nbuf);
if(obuf[0]) {
snprintf(nbuf
,sizeof(nbuf
),"wims_exec_out_%d",i
);
force_setvar(nbuf,obuf);
}
}
strip_trailing_spaces(p);
_get_exec_error(errorfname,namebuf);
return;
}
/* execute external program in the module directory.
* For privileged modules only
*/
void calc_mexec(char *p)
{
char *public_bin;
if(robot_access) return;
if(trusted_module()!=1 || is_class_module) {
module_error("not_trusted"); *p=0; return;
}
/* The following is useless, because mexec content is often given
* by variables
*/
/* if(strstr(p,PARENT_DIR_STRING)!=NULL) {
setvar("wims_error_data",p);
module_error("illegal_fname"); *p=0; return;
}
*/ public_bin=bin_dir; bin_dir=module_prefix;
exec_is_module=1;
calc_exec(p); bin_dir=public_bin;
exec_is_module=0;
}
void _calc_exec(char *p, char *arg0, char *arg1, int n)
{
char *abuf[8];
char outfname[MAX_FNAME+1], errorfname[MAX_FNAME+1];
if(robot_access) {*p=0; return;}
if(!trusted_module() || is_class_module) {
if(strcasecmp(tmp_debug,"yes")==0)
accessfile(p,"w","%s/%s.cmd",tmp_dir,arg0);
abuf[0]="bin/ch..root";
abuf[1]="&"; abuf[2]=arg0; abuf[3]=p;
abuf[4]=NULL;
}
else {
/* if(strstr(p,PARENT_DIR_STRING)!=NULL) {
setvar("wims_error_data",p);
module_error("illegal_fname"); *p=0; return;
}
*/
abuf[0]=arg0; abuf[1]=arg1; abuf[n]=p; abuf[n+1]=NULL;
}
mkfname(outfname,"%s/exec.out",tmp_dir);
mkfname(errorfname,"%s/exec.err",tmp_dir);
wrapexec=1; exportall();
execredirected(abuf[0],NULL,outfname,errorfname,abuf);
read_tmp_file(p,"exec.out");
_get_exec_error(errorfname,arg0);
}
/* call shell. */
void calc_sh(char *p)
{
_calc_exec(p,"sh","-c",2);
}
/* call perl. */
void calc_perl(char *p)
{
_calc_exec(p,"perl","-e",2);
}
/* simple evaluation of string */
void calc_evalue(char *p)
{
double d;
d=evalue(p); float2str(d,p); return;
}
/* substitute math variables */
void calc_mathsubst(char *p)
{
char *expr, *val, *nam, *pp;
char buf[MAX_LINELEN+1];
expr=wordchr(p,"in"); if(expr==NULL) goto error;
ovlstrcpy
(buf
,find_word_start
(expr
+strlen("in")));substit
(buf
);
*expr=0; substit(p);
if(val==NULL) {
error:
module_error("mathsubst_syntax"); *p=0;return;
}
nam=find_word_start(p); *val=0;
val=find_word_start(val+1);
*find_word_end(nam)=0;
if(*nam==0) goto error;
if(*nam) for(pp=varchr(buf,nam);pp!=NULL;pp=varchr(pp,nam)) {
string_modify
(buf
,pp
,pp
+strlen(nam
),"%s",val
);
}
ovlstrcpy(p,buf);
}
/* substitute and evaluate. */
void calc_evalsubst(char *p)
{
calc_mathsubst(p);
calc_evalue(p);
}
/* Nothing needs to be done in the function;
* substitution is done or not by tag in the structure.
*/
void calc_subst(char *p)
{
}
int _randrep(char *p)
{
char *rep;
int i;
rep=wordchr(p,"repeat"); if(rep==NULL) return 1;
*rep
=0; rep
+=strlen("repeat"); i
=evalue
(rep
);
if(i<1) i=1;
if(i>MAX_VALUE_LIST) i=MAX_VALUE_LIST;
return i;
}
/* integer random */
void calc_randint(char *p)
{
int lbound, ubound, n, i, t;
char *p1, *parm[2];
t=_randrep(p); n=cutitems(p,parm,2);
if(n<=0) {
snprintf(p
,3,"0"); return; /* Random without bound: return 0. */
}
lbound=evalue(parm[0]);
/* Missing ubound: random between +-1 and lbound. */
if(n<=1) {if(lbound<0) ubound=-1; else ubound=1;}
else ubound=evalue(parm[1]);
if(lbound>ubound) {i=lbound; lbound=ubound; ubound=i;}
for(i=0,p1=p;i<t;i++) {
if(i>0) *p1++=',';
mystrncpy(p1,int2str((int) irand(ubound-lbound+1)+lbound),
MAX_LINELEN-(p1-p)-1);
}
return;
}
/* floating random */
void calc_randdouble(char *p)
{
double lbound, ubound;
int n, i, t;
char *parm[2], *p1;
t=_randrep(p); n=cutitems(p,parm,2);
if(n<=0) {
snprintf(p
,3,"0"); return; /* Random without bound: return 0. */
}
lbound=evalue(parm[0]);
if(n<=1) ubound=0; /* Missing ubound: random between 0 and lbound. */
else ubound=evalue(parm[1]);
for(i=0,p1=p;i<t;i++) {
float2str(drand(ubound-lbound)+lbound,tmplbuf);
mystrncpy(p1,tmplbuf,MAX_LINELEN-(p1-p));
if(i<t-1 && p1-p<MAX_LINELEN) *p1++=',';
}
*p1=0; return;
}
/* Takes randomly a record in a datafile */
void calc_randfile(char *p)
{
char *pp, n[MAX_FNAME+1];
int i, j;
pp=find_word_start(p); *find_word_end(pp)=0;
mystrncpy(n,pp,sizeof(n));
i=datafile_recordnum(pp);
if(i<=0) { /* zero records */
*p=0; return;
}
j=irand(i); datafile_fnd_record(n,j+1,p);
return;
}
/* random char, word, line, item in a string */
void calc_randchar(char *p)
{
p
[0]=p
[(int) irand
(strlen(p
))];p
[1]=0;
}
void calc_randitem(char *p)
{
int i;
i=itemnum(p);
(void) fnd_item(p,irand(i)+1,tmplbuf);
mystrncpy(p,tmplbuf,MAX_LINELEN);
}
void calc_randline(char *p)
{
int i;
i=linenum(p); fnd_line(p,irand(i)+1,tmplbuf);
mystrncpy(p,tmplbuf,MAX_LINELEN);
}
void calc_randrow(char *p)
{
rows2lines(p); calc_randline(p);
}
void calc_randword(char *p)
{
int i;
i=wordnum(p); fnd_word(p,irand(i)+1,tmplbuf);
mystrncpy(p,tmplbuf,MAX_LINELEN);
}
/* random permutation of {1,...,n} */
void calc_randperm(char *p)
{
int n, i, j, k, t, pt, type;
double v;
char buf1[MAX_LINELEN+1],buf2[MAX_LINELEN+1];
char *list[MAX_RANDPERM];
int table[MAX_RANDPERM];
char *p1,*p2,*pp;
t=0; pt=0; pp=p;
p1=find_word_start(p); p2=find_word_end(p1);
if(p2
-p1
==strlen("even") && strncasecmp
(p1
,"even",strlen("even"))==0) {
t=1; pp=p2;
}
if(p2
-p1
==strlen("odd") && strncasecmp
(p1
,"odd",strlen("odd"))==0) {
t=-1; pp=p2;
}
p1=find_item_end(pp);
if(*p1==',') {
type=1; n=cutitems(pp,list,MAX_RANDPERM); v=0;
}
else {
v=evalue(pp); n=v; type=0;
}
if(n==1 && !isfinite(v)) {ovlstrcpy(p,pp); goto shorder;}
if(n<=0) {*p=0; return;}
if(n==1 && type==0) {
ovlstrcpy(p,"1");
shorder: force_setvar("wims_shuffle_order","1"); return;
}
if(n>MAX_RANDPERM) n=MAX_RANDPERM;
for(i=0;i<n;i++) table[i]=i;
/* Uniformity of this algorithm is easy to show by induction. */
for(i=0;i<n-1;i++) {
j=irand(n-i)+i; if(j==i) continue;
k=table[i]; table[i]=table[j]; table[j]=k;
pt++;
}
pt&=1;
if((t==1 && pt==1) || (t==-1 && pt==0)) {
k=table[0]; table[0]=table[1]; table[1]=k;
}
if(type
) {mystrncpy
(buf1
,list
[table
[0]],MAX_LINELEN
); p1
=buf1
+strlen(buf1
);}
else buf1[0]=0;
mystrncpy
(buf2
,int2str
(table
[0]+1),MAX_LINELEN
); p2
=buf2
+strlen(buf2
);
for(i=1;i<n;i++) {
if(type) {
if(p1-buf1+j>=MAX_LINELEN-1) module_error("cmd_output_too_long");
*p1
++=','; memmove(p1
,list
[table
[i
]],j
+1); p1
+=j
;
}
*p2++=',';
mystrncpy(p2,int2str(table[i]+1), MAX_LINELEN-(p2-buf2)-1);
}
if(type) mystrncpy(p,buf1,MAX_LINELEN);
else mystrncpy(p,buf2,MAX_LINELEN);
force_setvar("wims_shuffle_order",buf2);
}
/* Computes number of lines in the parm. */
void calc_linenum(char *p)
{
int i=linenum(p); mystrncpy(p,int2str(i),MAX_LINELEN);
}
/* Computes number of lines in the parm. */
void calc_rownum(char *p)
{
int i=rownum(p); mystrncpy(p,int2str(i),MAX_LINELEN);
}
/* Computes number of items in the list p. */
void calc_itemnum(char *p)
{
int i=itemnum(p); mystrncpy(p,int2str(i),MAX_LINELEN);
}
/* Computes number of records in the datafile p. */
void calc_recordnum(char *p)
{
int i;
i=datafile_recordnum(p); mystrncpy(p,int2str(i),MAX_LINELEN);
}
/* Computes number of words in the parm. */
void calc_wordnum(char *p)
{
int i=wordnum(p); mystrncpy(p,int2str(i),MAX_LINELEN);
}
/* string length */
void calc_lengthof(char *p)
{
int i;
/* Strip leading and trailing spaces? */
i
=strlen(p
); mystrncpy
(p
,int2str
(i
),MAX_LINELEN
);
}
char *_blockof_one(char *buf,
unsigned int len,
char *(fnd_fn)(char *pl, int n, char bbuf[]),
int i, char bbuf[])
{
if(i<0 || i>len || (i==0 && fnd_fn!=datafile_fnd_record) ) {
bbuf[0]=0; return bbuf;
}
return fnd_fn(buf,i,bbuf);
}
void _blockof(char *p,
unsigned int (len_fn)(char *pl),
char *(fnd_fn)(char *pl, int n, char bbuf[]),
char *append_char,
char *msg_str)
{
int i,j,l,started;
char *pp, *pe, *po, *pnext;
char buf[MAX_LINELEN+1], obuf[MAX_LINELEN+1], bbuf[MAX_LINELEN+1];
pp=wordchr(p,"of");
if(pp==NULL) {
setvar(error_data_string,msg_str);
module_error("no_of"); *p=0; return;
}
*pp
=0; pp
=find_word_start
(pp
+strlen("of")+1);
mystrncpy(buf,pp,sizeof(buf)); substit(buf);
obuf[0]=0; started=0; po=obuf;
pp=strparstr(p,"to");
pp=strparstr(pp+2,"to");
if(*pp==0) pp=strparstr(p,"..");
if(*pp!=0) {
int t=len_fn(buf);
*pp=0; pe=find_word_start(pp+2);
i=evalue(p); j=evalue(pe); pnext=buf;
if(i<0) i=t+i+1;
if(i<1) i=1;
if(j<0) j=t+j+1;
if(j>t) j=t;
for(; i<=j; i++) {
if(started==0 || fnd_fn==datafile_fnd_record)
pp=_blockof_one(buf,t,fnd_fn,i,bbuf);
else
pp=_blockof_one(pnext,1,fnd_fn,1,bbuf);
l
=strlen(pp
); pnext
=fnd_nextpos
;
if(l+(po-obuf)>=MAX_LINELEN-3) {
too_long: user_error("cmd_output_too_long"); return;
}
if(started
) {ovlstrcpy
(po
,append_char
); po
+=strlen(po
);}
memmove(po
,pp
,l
); po
+=l
; *po
=0; started
++;
}
}
else {
char *p1,*p2,ibuf[MAX_LINELEN+1];
int t=len_fn(buf);
mystrncpy(ibuf,p,sizeof(ibuf)); substit(ibuf);
for(p1=ibuf;*p1;p1=find_word_start(p2)) {
p2=find_item_end(p1); if(*p2) *p2++=0;
i=evalue(p1);
if(i<0) i=t+i+1;
if(i>t || i<0) continue;
pp
=_blockof_one
(buf
,t
,fnd_fn
,i
,bbuf
);l
=strlen(pp
);
if(l+(po-obuf)>=MAX_LINELEN-3) goto too_long;
if(started
) {ovlstrcpy
(po
,append_char
); po
+=strlen(po
);}
memmove(po
,pp
,l
); po
+=l
; *po
=0; started
++;
}
}
mystrncpy(p,obuf,MAX_LINELEN);
}
/* pick lines */
void calc_lineof(char *p)
{
_blockof(p,linenum,fnd_line,"\n","line");
}
/* pick rows */
void calc_rowof(char *p)
{
char *cc, tbuf[MAX_LINELEN+1]; /* called by substit(); no right to use tmplbuf */
mystrncpy(tbuf,p,sizeof(tbuf)); substit(tbuf);
if(strchr(tbuf
,'\n')==NULL
&& strchr(tbuf
,';')!=NULL
) cc
=";";
else cc="\n";
_blockof(p,rownum,fnd_row,cc,"row");
}
/* pick items */
void calc_itemof(char *p)
{
_blockof(p,itemnum,fnd_item,", ","item");
}
/* pick records in datafile */
void calc_recordof(char *p)
{
_blockof(p,datafile_recordnum,datafile_fnd_record,"\n:","record");
}
/* pick words */
void calc_wordof(char *p)
{
_blockof(p,wordnum,fnd_word," ","word");
}
/* pick characters */
void calc_charof(char *p)
{
_blockof(p,charnum,fnd_char,"","char");
}
char *append_obj[]={
"item","line","word","semicolon","colon"
};
char apch_list[]={',','\n',' ',';',':'};
#define append_obj_no (sizeof(append_obj)/sizeof(append_obj[0]))
/* append object to string */
void calc_append(char *p)
{
char append_char, *p1,*p2,*p3,*p4;
int i,l1,l2;
p1=find_word_start(p);p2=find_word_end(p1);
if(*p2!=0) *p2++=0;
for(i
=0;i
<append_obj_no
&& strcmp(p1
,append_obj
[i
])!=0;i
++);
if(i>=append_obj_no) {
synterr:
module_error("append_syntax");
*p=0; return;
}
append_char=apch_list[i];
p3=wordchr(p2,"to");
if(p3==NULL) goto synterr;
for(p4
=p3
-1;p4
>p2
&& isspace(*(p4
-1));p4
--);
if(p4<=p2) goto synterr;
*p4
=0;p3
=find_word_start
(p3
+strlen("to"));
memmove(tmplbuf
,p2
,p4
-p2
); tmplbuf
[p4
-p2
]=0; ovlstrcpy
(p
,p3
);
substit(tmplbuf);substit(p);
if(l1+l2>=MAX_LINELEN-1) user_error("cmd_output_too_long");
p3=find_word_start(p); p4=p+l1;
if(*p3) *p4++=append_char;
}
/* character translation */
void calc_translate(char *p)
{
int i, internal;
char *q[3];
char bf[3][MAX_LINELEN+1];
char fn[3][MAX_FNAME+1], *arglist[8];
q[0]=find_word_start(p); internal=0;
if(strncasecmp
(q
[0],"internal",strlen("internal"))==0 &&
q
[0]=find_word_start
(q
[0]+strlen("internal"));
internal=1;
}
q[1]=wordchr(q[0],"to"); q[2]=wordchr(q[0],"in");
if(q[1]==NULL || q[2]==NULL) {
module_error("tr_syntax"); *p=0; return;
}
*q[1]=0; *q[2]=0;
q
[1]=find_word_start
(q
[1]+strlen("to"));
q
[2]=find_word_start
(q
[2]+strlen("in"));
for(i=0;i<3;i++) {
strip_trailing_spaces(q[i]);
mystrncpy(bf[i],q[i],sizeof(bf[i]));substit(bf[i]);
}
if(bf[0][0]==0) goto bailout;
if(internal
|| strstr(tmp_dir
,"sessions")==NULL
|| (strpbrk(bf
[0],"\\[-")==NULL
&&
strpbrk(bf
[1],"\\[-")==NULL
)) { /* direct internal translation */
char *pp;
for(pp
=strpbrk(bf
[2],bf
[0]);pp
!=NULL
&& *pp
!=0 && pp
<bf
[2]+MAX_LINELEN
;
for(i=0;bf[0][i]!=*pp && bf[0][i]!=0;i++);
if(bf[0][i]!=0) *pp=bf[1][i];
}
bailout: mystrncpy(p,bf[2],MAX_LINELEN);
return;
}
mkfname(fn[0],"%s/tr.in",tmp_dir);
mkfname(fn[1],"%s/tr.out",tmp_dir);
accessfile(bf[2],"w",fn[0]);
arglist[0]=tr_prog; arglist[1]=bf[0]; arglist[2]=bf[1];
arglist[3]=NULL; exportall();
execredirected(tr_prog,fn[0],fn[1],"/dev/null",arglist);
read_tmp_file(p,"tr.out");
strip_trailing_spaces(p);
}
/* internal common routine for positionof */
void _pos(char *hay, char *stitch, int style, char *out,
char *(fnd_obj)(char *p, int n, char bf[]),
unsigned int (objnum)(char *p))
{
int i,n,t;
char buf[MAX_LINELEN+1], nbuf[12];
n=objnum(hay);
for(i=1;i<=n;i++) {
fnd_obj(hay,i,buf);
if(strcmp(buf
,stitch
)!=0) continue;
t
=strlen(out
); if(t
>MAX_LINELEN
-12) return;
}
}
/* return positions of searched for objects */
void calc_pos(char *p)
{
char buf[2][MAX_LINELEN+1];
char *p1, *p2;
int style;
p1=find_word_start(p); p2=wordchr(p1,"in");
if(p2==NULL) module_error("syntax_error");
*p2
=0;p2
=find_word_start
(p2
+strlen("in"));
strip_trailing_spaces(p1);
ovlstrcpy(buf[0],p1);*find_word_end(buf[0])=0; style=0;
if(strcmp(buf
[0],"word")==0) style
=1;
else {
if(strcmp(buf
[0],"item")==0) style
=2;
else {
if(strcmp(buf
[0],"line")==0) style
=3;
else {
if(strcmp(buf
[0],"char")==0) style
=4;
else {
if(strcmp(buf
[0],"row")==0) style
=5;
}
}
}
}
if(style>0) p1=find_word_start(find_word_end(p1));
ovlstrcpy(buf[0],p1); ovlstrcpy(buf[1],p2);
substit(buf[0]); substit(buf[1]); *p=0;
switch(style) {
case 0: { /* string */
char *pp, nbuf[10];
int i,t;
for(pp
=strstr(buf
[1],buf
[0]);pp
!=NULL
;pp
=strstr(pp
+1,buf
[0])) {
i
=pp
-buf
[1]; t
=strlen(p
); if(t
>MAX_LINELEN
-12) return;
}
return;
}
case 1: { /* word */
_pos(buf[1],buf[0],style,p,fnd_word,wordnum);
return;
}
case 2: { /* item */
_pos(buf[1],buf[0],style,p,fnd_item,itemnum);
return;
}
case 3: { /* line */
_pos(buf[1],buf[0],style,p,fnd_line,linenum);
return;
}
case 4: { /* char */
_pos(buf[1],buf[0],style,p,fnd_char,charnum);
return;
}
case 5: { /* row */
_pos(buf[1],buf[0],style,p,fnd_row,rownum);
return;
}
}
}
/* internal routine for calc_replace. */
void _obj_replace(char *orig, char *by, char *in, int num,
char separator, char *result,
char *(fnd_obj)(char *p, int n, char bf[]),
unsigned int (objnum)(char *p),
char *(objchr)(char *p,char *w))
{
int i;
char *p1, *p2;
ovlstrcpy(result,in);
if(num!=0) {
num=objnum(in); i=evalue(orig);
if(i==0) module_error("bad_index");
if(i<0) i=num+i+1;
if(i>num || i<1) return;
if(separator==0) { /* char */
result[i-1]=by[0]; return;
}
fnd_obj(result,i,orig); p1=fnd_position;
if(i<num) {
fnd_obj(result,i+1,orig); p2=fnd_position;
}
else p2
=result
+strlen(result
);
if(p1==NULL || p2==NULL) internal_error("_obj_replace() error.");
if(i<num) {
i
=strlen(by
); by
[i
++]=separator
;by
[i
]=0;
}
string_modify(result,p1,p2,"%s",by);
}
else {
if(separator==0) {
if(orig[0]==0 || by[0]==0) return;
for(p1
=strchr(result
,orig
[0]);p1
!=NULL
;p1
=strchr(p1
+1,orig
[0]))
*p1=by[0];
return;
}
for(p1
=objchr
(result
,orig
);p1
!=NULL
;p1
=objchr
(p1
+strlen(by
)+1,orig
)) {
string_modify
(result
,p1
,p1
+strlen(orig
),"%s",by
);
}
}
}
/* replacement */
void calc_replace(char *p)
{
int i,style,num,internal;
char *q[3], *pp;
char bf[4][MAX_LINELEN+17];
char fn[3][MAX_FNAME+1], *arglist[8];
char regexp_char='/';
style=num=0;
q[0]=find_word_start(p); internal=0;
if(strncasecmp
(q
[0],"internal",strlen("internal"))==0 &&
q
[0]=find_word_start
(q
[0]+strlen("internal"));
internal=1;
}
q[1]=wordchr(q[0],"by"); q[2]=wordchr(q[0],"in");
if(q[1]==NULL || q[2]==NULL) {
module_error("replace_syntax"); *p=0; return;
}
*q[1]=0; *q[2]=0;
q
[1]=find_word_start
(q
[1]+strlen("by"));
q
[2]=find_word_start
(q
[2]+strlen("in"));
mystrncpy(bf[0],q[0],sizeof(bf[0]));
pp=find_word_end(bf[0]); if(*pp) *(pp++)=0;
if(strcmp(bf
[0],"word")==0) style
=1;
else {
if(strcmp(bf
[0],"item")==0) style
=2;
else {
if(strcmp(bf
[0],"line")==0) style
=3;
else {
if(strcmp(bf
[0],"char")==0) style
=4;
}
}
}
if(style>0) {
q[0]=find_word_start(find_word_end(q[0]));
mystrncpy(bf[0],q[0],sizeof(bf[0]));
pp=find_word_end(bf[0]); if(*pp) *(pp++)=0;
if(strcmp(bf
[0],"number")==0) {
num=1; q[0]=find_word_start(pp);
}
}
for(i=0;i<3;i++) {
strip_trailing_spaces(q[i]);
mystrncpy(bf[i],q[i],sizeof(bf[i]));
substit(bf[i]);
}
if(bf[0][0]==0) {mystrncpy(p,bf[2],MAX_LINELEN); return;}
switch(style) {
case 1: { /* word */
_obj_replace(bf[0],bf[1],bf[2],num,' ',p,
fnd_word,wordnum,wordchr);
return;
}
case 2: { /* item */
_obj_replace(bf[0],bf[1],bf[2],num,',',p,
fnd_item,itemnum,itemchr);
return;
}
case 3: { /* line */
_obj_replace(bf[0],bf[1],bf[2],num,'\n',p,
fnd_line,linenum,linechr);
return;
}
case 4: { /* char */
if(bf[1][0]==0) bf[1][0]=' ';
if(bf[0][0]==0) return;
_obj_replace(bf[0],bf[1],bf[2],num,0,p,
fnd_char,charnum,charchr);
return;
}
default: break;
}
if(internal
|| strstr(tmp_dir
,"sessions")==NULL
|| (strpbrk(bf
[0],"\\[^.*$")==NULL
&&
/* No regexp, direct replace */
char *pp;
for(pp
=strstr(bf
[2],bf
[0]);pp
<bf
[2]+MAX_LINELEN
&& pp
!=NULL
;
string_modify
(bf
[2],pp
,pp
+strlen(bf
[0]),"%s",bf
[1]);
}
mystrncpy(p,bf[2],MAX_LINELEN);return;
}
mkfname(fn[0],"%s/sed.in",tmp_dir);
mkfname(fn[1],"%s/sed.out",tmp_dir);
accessfile(bf[2],"w",fn[0]);
snprintf(bf
[3],sizeof(bf
[3]),"s%c%s%c%s%cg",
regexp_char,bf[0],regexp_char,bf[1],regexp_char);
arglist[0]=sed_prog; arglist[1]=bf[3]; arglist[2]=NULL;
execredirected(sed_prog,fn[0],fn[1],"/dev/null",arglist);
read_tmp_file(p,"sed.out");
strip_trailing_spaces(p);
}
/* transforms a string to hexadecimal code, upper-case */
void calc_hex(char *p)
{
unsigned char *p1, orig[MAX_LINELEN+1];
char *p2;
char *hex="0123456789ABCDEF";
mystrncpy((char*)orig,p,MAX_LINELEN);
for(p1=orig, p2=p; *p1 && p2-p<MAX_LINELEN-2; p1++) {
*p2++=hex[(*p1>>4)&15]; *p2++=hex[*p1&15];
}
*p2=0;
}
/* transforms to lower/upper cases */
void calc_tolower(char *p)
{
char *pp;
for(pp
=p
;*pp
;pp
++) *pp
=tolower(*pp
);
}
void calc_toupper(char *p)
{
char *pp;
for(pp
=p
;*pp
;pp
++) *pp
=toupper(*pp
);
}
/* strip leading and trailing spaces */
void calc_trim(char *p)
{
char *s;
s=find_word_start(p);
if(s
>p
) memmove(p
,s
,MAX_LINELEN
-(s
-p
)+1);
strip_trailing_spaces(p);
}
/* output date. Uses Linux 'date' utility. */
void calc_date(char *p)
{
char *p1, *p2, *p3;
if(!trusted_module() || is_class_module) {
if(strstr(p
,"..")!=NULL
) return;
for(p1=find_word_start(p); *p1; p1=find_word_start(p2)) {
p2=find_word_end(p1);
while(*p1=='\'' || *p1=='"') p1++;
if(*p1!='-') continue;
for(p3
=p1
+1;p3
<p2
;p3
++) if(strchr("rs",*p3
)!=NULL
) return;
}
}
wrapexec=1;
call_ssh("date %s >%s/date.out 2>/dev/null",p,tmp_dir);
read_tmp_file(p,"date.out");
}
/* ls, or dir */
void calc_listfile(char *p)
{
char *pp;
/* only for trusted modules */
if(!trusted_module() || is_class_module) {
module_error("not_trusted"); *p=0; return;
}
/* security measures. */
for(pp
=p
;*pp
;pp
++) if(isspace(*pp
) || *pp
==';') *pp
=' ';
if(strstr(p
,parent_dir_string
)!=NULL
) {
setvar(error_data_string,p);
module_error("illegal_fname"); return;
}
wrapexec=1;
call_sh("ls %s >%s/ls.out 2>%s/ls.err",
p,tmp_dir,tmp_dir);
read_tmp_file(p,"ls.out");
}
void calc_fileexists(char *p)
{
char *pp, *fname;
/* security measures. */
for(pp
=p
;*pp
;pp
++) if(isspace(*pp
) || *pp
==';') *pp
=' ';
if(strstr(p
,parent_dir_string
)!=NULL
) {
setvar(error_data_string,p);
module_error("illegal_fname"); return mystrncpy(p,"no",MAX_LINELEN);
}
if(robot_access || !trusted_module() || is_class_module){
module_error("illegal_fname"); return mystrncpy(p,"no",MAX_LINELEN);
}
else
{
if(ftest(mkfname(NULL,"%s/%s",getvar("wims_home"),fname))==is_file)
return mystrncpy(p,"yes",MAX_LINELEN);
}
}
if(ftest(mkfname(NULL,"%s",p))==is_file) return mystrncpy(p,"yes",MAX_LINELEN);
else return mystrncpy(p,"no",MAX_LINELEN);
}
/* instex static: static tex inserts */
void calc_instexst(char *p)
{
char nbuf[MAX_FNAME+1], bufc[MAX_LINELEN+1];
char buf2[1024], altbuf[1024], buf[MAX_LINELEN+1], urlbuf[MAX_LINELEN+1];
char *b, *at, *al, *md1, *md2;
int t, border, vspace;
struct stat st,stc;
char *p1, *p2, *p3, *ppp, *pt;
if(robot_access) {*p=0; return;}
p1=find_word_start(p); p2=find_word_end(p1);
p3=p2-4; vspace=0;
fix_tex_size();
t=untrust; untrust=0;
if(find_module_file(m_file.name,bufc,0)) module_error(m_file.name);
else stat(bufc,&stc);
untrust=t;
if(*p3
=='.' && (memcmp(p3
+1,"gif",3)==0 || memcmp(p3
+1,"png",3)==0)) {
char mbuf[MAX_LINELEN+1];
if(*p2!=0) *p2++=0;
p2=find_word_start(p2);
ovlstrcpy(mbuf,p1); substit(mbuf);
if(strstr(mbuf
,parent_dir_string
)!=NULL
) {
setvar(error_data_string,mbuf);
module_error("illegal_fname"); return;
}
mkfname(nbuf,"%s/%s",module_prefix,mbuf);
}
else {
ppp=getvar(ro_name[ro_module]);
if(ppp==NULL) internal_error("calc_instexst(): module name vanishes.");
p2=p1;
mkfname(nbuf,"w/instex/%d/%s/%s_%d.gif",
current_tex_size,ppp,m_file.name,m_file.l);
}
snprintf(urlbuf
,sizeof(urlbuf
),"%s%s?%X",ref_base
,nbuf
,
(unsigned short int) stc.st_mtime);
mystrncpy(buf,nbuf,sizeof(buf));
*ppp=0;mkdirs(buf);
}
b=getvar("ins_border");
at=getvar("ins_attr");
al=getvar("ins_align");
if(at==NULL) at="";
if(al==NULL) al="";
al=find_word_start(al);
if(*al
!=0) snprintf(buf2
,sizeof(buf2
),"vertical-align:%s",al
); else buf2
[0]=0;
if(b==NULL || *b==0) border=0;
if(border<0) border=0;
if(border>100) border=100;
if(instex_ready(p2,urlbuf)) goto prt;
if(stat(nbuf,&st)!=0 || st.st_mtime<stc.st_mtime || st.st_size<45) {
setenv("texgif_style",instex_style,1);
setenv("texgif_src",p2,1);
setenv("texgif_outfile",nbuf,1);
setenv("texgif_tmpdir",tmp_dir,1); exportall();
wrapexec=0; call_ssh("%s &>%s/instexst.log",tex2gif,tmp_dir);
setenv("instexst_src","",1);
}
prt: md1=md2="";
if(strcasecmp(al,"middle")==0) {
md1=mathalign_sup1; md2=mathalign_sup2;
vspace=5;
}
if(ins_alt[0]==0) mystrncpy(ins_alt,p2,sizeof(ins_alt));
if(strchr(ins_alt
,'"')!=NULL
|| strlen(ins_alt
)>256) ins_alt
[0]=0;
pt=getvar("wims_ins_alt"); if(pt==NULL) pt="";
if(strcmp(pt
,"empty")==0) altbuf
[0]=0;
else
if(ins_alt
[0] && strcmp(pt
,"none")!=0)
snprintf(altbuf
,sizeof(altbuf
)," alt=\"\"");
else
snprintf(altbuf
,sizeof(altbuf
)," alt=\"%s\"",ins_alt
);
snprintf(p
,MAX_LINELEN
,"%s<img src=\"%s\" style=\"border:solid;border-width:%dpx;margin-bottom:%dpx;%s\" %s %s>%s",
md1,urlbuf,border,vspace,buf2,at,altbuf,md2);
setvar("ins_attr",""); ins_alt[0]=0;
setvar("ins_url",urlbuf);
}
/* extract non-empty lines or items */
void calc_nonempty(char *p)
{
int type, i, cnt;
char *p1, *p2, buf[MAX_LINELEN+1], out[MAX_LINELEN+1];
p1=find_word_start(p); p2=find_word_end(p1);
if(*p2) *p2++=0; else {
*p=0; return;
}
type=0;
if(strcasecmp(p1,"item")==0 || strcasecmp(p1,"items")==0) type=1;
if(type==0 && (strcasecmp(p1,"line")==0 || strcasecmp(p1,"lines")==0))
type=2;
if(type==0 && (strcasecmp(p1,"row")==0 || strcasecmp(p1,"rows")==0))
type=3;
if(type==0) module_error("syntax_error");
out[0]=out[1]=0;
switch(type) {
case 1: { /* items */
cnt=itemnum(p2);
for(i=1; i<=cnt; i++) {
fnd_item(p2,i,buf);
if(*find_word_start(buf)) {
}
}
break;
}
case 2: { /* lines */
lines: cnt=linenum(p2);
for(i=1; i<=cnt; i++) {
fnd_line(p2,i,buf);
if(*find_word_start(buf)) {
}
}
break;
}
case 3: { /* rows */
int t=rows2lines(p2);
if(t==0) goto lines;
cnt=linenum(p2);
for(i=1; i<=cnt; i++) {
fnd_line(p2,i,buf);
if(*find_word_start(buf)) {
}
}
break;
}
default: break;
}
ovlstrcpy(p,out+1);
}
/* returns a list with unique items */
void calc_listuniq(char *p)
{
int i,n;
char lout[MAX_LINELEN+2], *ll;
char *cut[MAX_LIST];
lout[0]=lout[1]=0;
n=cutitems(p,cut,MAX_LIST); for(i=0;i<n;i++) {
ll=cut[i];
if(*ll && itemchr(lout,ll)==NULL &&
}
}
ovlstrcpy(p,lout+1);
}
/* returns intersection of 2 lists */
void calc_listintersect(char *p)
{
char l1[MAX_LINELEN+1],l2[MAX_LINELEN+1],lout[MAX_LINELEN+2];
char *cut[MAX_LIST];
char *pp, *ll;
int i,n;
pp=wordchr(p,"and");
if(pp==NULL) module_error("syntax_error");
*pp
=0;ovlstrcpy
(l1
,p
); ovlstrcpy
(l2
,pp
+strlen("and"));
lout[0]=lout[1]=0; substit(l1); substit(l2);
n=cutitems(l1,cut,MAX_LIST); if(n<=0) {*p=0; return;}
for(i=0;i<n;i++) {
ll=cut[i];
if(ll[0] && itemchr(l2,ll)!=NULL && itemchr(lout,ll)==NULL &&
}
}
ovlstrcpy(p,lout+1);
}
/* returns union of 2 lists */
void calc_listunion(char *p)
{
char l1[MAX_LINELEN+1],l2[MAX_LINELEN+1],lout[MAX_LINELEN+2];
char *cut[MAX_LIST];
char *pp, *ll;
int i,n;
pp=wordchr(p,"and");
if(pp==NULL) module_error("syntax_error");
*pp
=0;ovlstrcpy
(l1
,p
); ovlstrcpy
(l2
,pp
+strlen("and"));
lout[0]=lout[1]=0; substit(l1); substit(l2);
n=cutitems(l1,cut,MAX_LIST); for(i=0;i<n;i++) {
ll=cut[i];
if(ll[0] && itemchr(lout,ll)==NULL &&
}
}
n=cutitems(l2,cut,MAX_LIST); for(i=0;i<n;i++) {
ll=cut[i];
if(ll[0] && itemchr(lout,ll)==NULL &&
}
}
ovlstrcpy(p,lout+1);
}
/* returns items of list2 not in list1 */
void calc_listcomplement(char *p)
{
char l1[MAX_LINELEN+1],l2[MAX_LINELEN+1],lout[MAX_LINELEN+2];
char *cut[MAX_LIST];
char *pp, *ll;
int i,n;
pp=wordchr(p,"in");
if(pp==NULL) module_error("syntax_error");
*pp
=0;ovlstrcpy
(l1
,p
); ovlstrcpy
(l2
,pp
+strlen("in"));
lout[0]=lout[1]=0; substit(l1); substit(l2);
n=cutitems(l2,cut,MAX_LIST); if(n<=0) {*p=0; return;}
for(i=0;i<n;i++) {
ll=cut[i];
if(ll[0] && itemchr(l1,ll)==NULL && itemchr(lout,ll)==NULL &&
}
}
ovlstrcpy(p,lout+1);
}
/* Consult a dictionary to translate a string */
/*
void calc_dictionary(char *p)
{
char *pp;
char name[MAX_LINELEN+1], str[MAX_LINELEN+1];
int t;
pp=wordchr(p,"for");
if(pp==NULL || pp<=p) module_error("syntax_error");
*(find_word_end(pp-1))=0;
ovlstrcpy(name,p); substit(name);
pp=find_word_start(pp+strlen("for")); t=0;
if(memcmp(pp,"word",strlen("word"))==0 &&
(isspace(*(pp+strlen("word"))) ||
(*(pp+strlen("word"))=='s' && isspace(*(pp+strlen("words")))))) {
pp=find_word_start(pp+strlen("words")); t=1;
}
if(memcmp(pp,"line",strlen("line"))==0 &&
(isspace(*(pp+strlen("line"))) ||
(*(pp+strlen("line"))=='s' && isspace(*(pp+strlen("lines")))))) {
pp=find_word_start(pp+strlen("lines")); t=1;
}
if(memcmp(pp,"list",strlen("list"))==0 && isspace(*(pp+strlen("list")))) {
pp=find_word_start(pp+strlen("list"));
}
if(memcmp(pp,"items",strlen("items"))==0 && isspace(*(pp+strlen("items")))) {
pp=find_word_start(pp+strlen("items"));
}
if(memcmp(pp,"item",strlen("item"))==0 && isspace(*(pp+strlen("item")))) {
pp=find_word_start(pp+strlen("item"));
}
ovlstrcpy(str,pp); substit(str);
switch(t) {
case 1: {
calc_words2items(str); break;
}
case 2: {
calc_lines2items(str); break;
}
default: break;
}
}
*/
void calc_module(char *p)
{
char *p1,*p2, ind_buf[MAX_LINELEN+1], buf[MAX_FNAME+1];
char *tp;
p1=find_word_start(p); p2=find_word_end(p1);
if(*p2!=0) *p2++=0;
p2=find_word_start(p2); *find_word_end(p2)=0;
if(*p1==0) {empty: *p=0; return;}
if(*p2==0) {
snprintf(buf
,sizeof(buf
),"module_%s",p1
);
p1=getvar(buf); if(p1==NULL) p1="";
mystrncpy(p,p1,MAX_LINELEN); return;
}
mkfname(buf,"%s/%s/INDEX",module_dir,p2);
tp=readfile(buf,ind_buf,MAX_LINELEN);
if(tp==NULL) {
mkfname(buf,"%s/%s/index",module_dir,p2);
tp=readfile(buf,ind_buf,MAX_LINELEN);
}
if(tp
==NULL
&& p2
[strlen(p2
)-3]!='.') {
mkfname(buf,"%s/%s.%s/INDEX",module_dir,p2,lang);
tp=readfile(buf,ind_buf,MAX_LINELEN);
if(tp==NULL) {
mkfname(buf,"%s/%s.%s/index",module_dir,p2,lang);
tp=readfile(buf,ind_buf,MAX_LINELEN);
}
if(tp==NULL) {
int i;
for(i=0;i<available_lang_no;i++) {
mkfname(buf,"%s/%s.%s/INDEX",module_dir,p2,available_lang[i]);
tp=readfile(buf,ind_buf,MAX_LINELEN); if(tp) break;
mkfname(buf,"%s/%s.%s/index",module_dir,p2,
available_lang[i]);
tp=readfile(buf,ind_buf,MAX_LINELEN); if(tp) break;
}
}
}
if(tp==NULL) goto empty; /* module not found */
_getdef(ind_buf,p1,p);
}
/* strip enclosing parentheses */
void calc_declosing(char *p)
{
strip_enclosing_par(p);
}
/* return no if the parenthesis do not match */
void calc_checkallpar(char *p)
{
if(check_parentheses(p,1)==0)
ovlstrcpy(p, "yes");
else ovlstrcpy(p, "no");
}
/* remove html tag, very rudimentary.
by default, everything is detagged
one can choose what to detag by the parameter wims_parm_detag
*/
void calc_detag(char *p)
{
char *p1, *p2, *s, tag[100];
int n=0;
s=getvar("wims_parm_detag");
if(s==NULL || *s == 0)
{
if(p2==NULL) p1++; else ovlstrcpy(p1,p2+1);
}
else
for(s=find_word_start(s); *s; s=find_word_start(s+n))
{
n = find_word_end(s) - s; if (n > 96) n = 96;
tag[0]='<';
mystrncpy(tag+1, s, n+1); tag[n+1]=0;
{
if(p2==NULL) p1++; else ovlstrcpy(p1,p2+1);
}
tag[1]='/';
mystrncpy(tag+2, s, n+1); tag[n+2]='>'; tag[n+3]=0;
}
}
/* replace html symbols by their iso translation */
void calc_html2iso(char *p)
{
int st, ns;
unsigned char buffer[MAX_LINELEN], *s = buffer;
inithtmltrans();
while (*s)
if (*s == '&'){
unsigned char *p1 = ++s;
for (st
= 0; (ns
= htmltrans
[abs(st
)][*s
]); st
= ns
)
s++;
if (st > 0 && *s == ';')
{char *r
=htmlsymbs
[st
][1]; strcpy((char *)p
, r
); s
++; p
+=strlen(r
);}
else
{*p++='&'; s=p1;}
}
else *p++=*s++;
*p = 0;
}
/* prepare a string to be inserted into a form input or textarea as is */
void calc_reinput(char *p)
{
char *p1;
p1++; string_modify(p,p1,p1,"amp;");
}
string_modify(p,p1,p1+1,"<");
}
/* get a definition from a file. Trusted modules only. */
void calc_defof(char *p)
{
char *p1;
char fbuf[MAX_FNAME+1], nbuf[MAX_LINELEN+1], tbuf[MAX_LINELEN+1];
secure_exec();
p1=wordchr(p,"in"); if(p1==NULL) module_error("syntax_error");
*p1
=0; p1
=find_word_start
(p1
+strlen("in"));
mystrncpy(nbuf,p,sizeof(nbuf)); mystrncpy(tbuf,p1,sizeof(tbuf));
substit(nbuf); substit(tbuf);
p1=find_word_start(tbuf); *find_word_end(p1)=0;
if(find_module_file(p1,fbuf,0)) {*p=0; return;}
p1=find_word_start(nbuf); strip_trailing_spaces(p1);
getdef(fbuf,p1,p);
}
/* check host */
void calc_checkhost(char *p)
{
int t;
if(robot_access || !trusted_module()) ovlstrcpy(p,"0");
else {
t=checkhost(p); mystrncpy(p,int2str(t),MAX_LINELEN);
}
}
#define MAX_COLUMNS 256
/* A rudimentary database facility */
void calc_select(char *p)
{
char *p1, *p2, *p3, *bufp, c, sep;
char buf1[MAX_LINELEN+1], buf2[MAX_LINELEN+1];
char buf[MAX_LINELEN+1];
int i,j,lmax;
p2=wordchr(p,"where"); if(p2==NULL) module_error("syntax_error");
p2=find_word_start(p2); strip_trailing_spaces(p2);
p1=find_word_start(p) ; strip_trailing_spaces(p1);
if(*p1==0 || *p2==0) module_error("syntax_error");
ovlstrcpy(buf1,p1); ovlstrcpy(buf2,p2); sep='\n';
/* buf1: data; buf2: condition. */
substit(buf1);
if(strstr(buf2
,"column")!=NULL
) { /* matrix */
lmax=0; if(rows2lines(buf1)) sep=';';
for(p1
=strstr(buf2
,"column"); p1
; p1
=strstr(p1
+1,"column")) {
if(p1
>buf2
&& isalnum(*(p1
-1))) continue;
p2
=find_word_start
(p1
+strlen("column"));
for(p3=p2; myisdigit(*p3); p3++);
if(p3==p2) continue;
c
=*p3
; *p3
=0; i
=atoi(p2
); *p3
=c
;
if(i<=0 || i>MAX_COLUMNS) continue;
if(i>lmax) lmax=i;
string_modify(buf2,p1,p3,"$(wims_select_col_%d)",i);
}
buf[0]=0; bufp=buf;
for(p1=buf1; *p1; p1=p2) {
char ibuf[MAX_LINELEN+1], nbuf[MAX_NAMELEN+1];
if(p2
==NULL
) p2
=p1
+strlen(p1
); else *p2
++=0;
if(*find_word_start(p1)==0) continue;
for(j=1;j<=lmax;j++) {
snprintf(nbuf
,sizeof(nbuf
),"wims_select_col_%d",j
);
fnd_item(p1,j,ibuf); force_setvar(nbuf,ibuf);
}
ovlstrcpy(ibuf,buf2); if(compare(ibuf,0,0)) {
snprintf(bufp
,MAX_LINELEN
-(bufp
-buf
),"%s%c",p1
,sep
);
}
}
}
else { /* datafile */
module_error("syntax_error");
}
if(buf
[0]!=0) buf
[strlen(buf
)-1]=0;
mystrncpy(p,buf,MAX_LINELEN);
}
/* Extract a column from a matrix */
void calc_columnof(char *p)
{
char *p1, *p2, *bufp, sep;
char buf1[MAX_LINELEN+1], buf2[MAX_LINELEN+1];
char buf[MAX_LINELEN+1];
p2=wordchr(p,"of"); if(p2==NULL) module_error("syntax_error");
p2=find_word_start(p2); strip_trailing_spaces(p2);
p1=find_word_start(p) ; strip_trailing_spaces(p1);
if(*p1==0) module_error("syntax_error");
if(*p2==0) {*p=0; return;}
ovlstrcpy(buf1,p1); ovlstrcpy(buf2,p2); sep='\n';
/* buf1: number(s); buf2: matrix. */
substit(buf1); substit(buf2);
if(rows2lines(buf2)) sep=';';
if(strchr(buf1
,',')==NULL
&& wordchr
(buf1
,"to")==NULL
&& strstr(buf1
,"..")==NULL
) sep
=',';
buf[0]=0; bufp=buf;
for(p1=buf2; *p1; p1=p2) {
char ibuf[MAX_LINELEN+1];
if(p2
==NULL
) p2
=p1
+strlen(p1
); else *p2
++=0;
snprintf(ibuf
,sizeof(ibuf
),"%s of %s",buf1
,p1
);
calc_itemof(ibuf);
snprintf(bufp
,MAX_LINELEN
-(bufp
-buf
),"%s%c",ibuf
,sep
);
}
if(buf
[0]!=0) buf
[strlen(buf
)-1]=0;
mystrncpy(p,buf,MAX_LINELEN);
}
/* find roots of a function or equation in a given zone */
void calc_solve(char *p)
{
char *pp, *fp, *forp;
char buf[MAX_LINELEN+1], vbuf[MAX_LINELEN+1];
double v, dd, start, stop, step, old, v1, v2, v3, d1, d3;
int i, pos;
forp=wordchr(p,"for");
if(forp==NULL) { syntax: module_error("syntax_error"); *p=0; return; }
fp=find_word_start(p); strip_trailing_spaces(fp);
if(*fp==0) goto syntax;
i=cutfor(forp,NULL); if(i<0 || forstruct.type==for_in) goto syntax;
if(i>0) {*p=0; return;}
start=forstruct.from; stop=forstruct.to; forp=forstruct.var;
mystrncpy(buf,fp,sizeof(buf)); substitute(buf);
*p
=0; pp
=strchr(buf
,'='); if(pp
!=NULL
) {
if(strlen(buf
)>=MAX_LINELEN
-16) return;
string_modify(buf,pp,pp+1,"-(");
}
i=0; for(fp=varchr(buf,forp); fp!=NULL; fp=varchr(fp,forp)) {
string_modify
(buf
,fp
,fp
+strlen(forp
),EV_X
); fp
+=strlen(EV_X
); i
++;
}
if(i==0 || start==stop) return;
evalue_compile(buf); pos=eval_getpos(EV_X);
if(start>stop) {dd=start; start=stop; stop=dd;}
step=(stop-start)/100; if(step==0) return;
pp=p; old=0;
for(v=start; v<=stop; v+=step, old=dd) {
eval_setval(pos,v);
dd=checked_eval(buf);
if(v==start) continue;
if(!isfinite(old) || !isfinite(dd) || (old>0 && dd>0) || (old<0 && dd<0))
continue;
if(dd==0 && v<stop) continue;
v1=v-step; v2=v; d1=old;
for(i=0;i<30;i++) {
v3=(v1+v2)/2; eval_setval(pos,v3);
d3=checked_eval(buf);
if(!isfinite(d3)) goto next;
if((d1>0 && d3>0) || (d1<0 && d3<0)) {d1=d3; v1=v3;}
else {v2=v3;}
}
float2str
(v3
,vbuf
); if(pp
-p
+strlen(vbuf
)<MAX_LINELEN
-1) {
if(pp>p) *pp++=',';
ovlstrcpy(pp,vbuf);
}
else break;
next: ;
}
}
/* type: 1=values, 2=sum, 3=product, 4=recursion, 5=subst */
void _values(char *p, int type)
{
char *pp, *fp, *forp;
char vbuf[MAX_LINELEN+1], buf[MAX_LINELEN+1], fbuf[MAX_LINELEN+1], tbuf[MAX_LINELEN+1];
char *f[64];
double v, dd, start, stop, step, v0;
int i, k, fcnt, pos, posr;
forp=wordchr(p,"for");
if(forp==NULL) { syntax: module_error("syntax_error"); *p=0; return; }
*forp
=0; forp
+=strlen("for"); forp
=find_word_start
(forp
);
fp=find_word_start(p); strip_trailing_spaces(fp);
if(*fp==0) goto syntax;
if(type<5) i=cutfor(forp,NULL); else i=cutfor(forp,tbuf);
if(i<0) goto syntax;
if(i>0) {*p=0; return;}
start=forstruct.from; stop=forstruct.to; step=forstruct.step;
forp=forstruct.var;
mystrncpy(buf,fp,sizeof(buf)); substitute(buf);
for(fp=varchr(buf,forp); fp!=NULL; fp=varchr(fp,forp)) {
string_modify
(buf
,fp
,fp
+strlen(forp
),EV_X
); fp
+=strlen(EV_X
);
}
for(fp=varchr(buf,"last"); fp!=NULL; fp=varchr(fp,"last")) {
string_modify
(buf
,fp
,fp
+strlen("last"),EV_S
); fp
+=strlen(EV_S
);
}
fcnt=pos=posr=0;
if(type==5) goto skip;
fcnt=itemnum(buf); if(fcnt>64) fcnt=64; pp=fbuf;
for(k=0; k<fcnt; k++) {
fnd_item(buf,k+1,vbuf); evalue_compile(vbuf);
if(pp
-fbuf
+strlen(vbuf
)<MAX_LINELEN
-1) {
f
[k
]=pp
; ovlstrcpy
(pp
,vbuf
); pp
+=strlen(pp
)+1;
}
else f[k]="";
}
pos=eval_getpos(EV_X); posr=eval_getpos(EV_S);
skip:
if(step==0) step=1;/* if(step<0) step=-step;
if(stop<start) {dd=start; start=stop; stop=dd;} */
*p=0; v0=0;
switch(type) {
case 4:
case 1: {
pp=getvar("recursion_start");
if(pp==NULL || *pp==0) v0=0;
else {
v0=evalue(pp); if(!isfinite(v0)) return;
}
break;
}
case 2: v0=0; break;
case 3: v0=1; break;
case 5: break;
}
pp=p;
if(type==5) {
char *ps, *pt, buf2[MAX_LINELEN+1];
int l,ln;
*p
=0; l
=strlen(buf
); if(l
>=MAX_LINELEN
) return;
for(i=0,v=start; i<MAX_VALUE_LIST && v*step<=stop*step; v+=step, i++) {
if(forstruct.type==for_from) {
float2str(v,vbuf); ps=vbuf;
}
else ps=forstruct.pos[i];
for(pt=varchr(buf2,EV_X);pt!=NULL;pt=varchr(pt+l,EV_X))
string_modify(buf2,pt,pt+ln,"%s",ps);
if(pp
-p
+strlen(buf2
)>=MAX_LINELEN
-1) return;
if(pp>p) *pp++=',';
ovlstrcpy(pp,buf2);
}
return;
}
for(i=0,v=start; i<MAX_VALUE_LIST && v*step<=stop*step; v+=step, i++) {
if(forstruct.type==for_from) eval_setval(pos,v);
else eval_setval(pos,forstruct.list[i]);
eval_setval(posr,v0);
for(k=0; k<fcnt; k++) {
dd=checked_eval(f[k]);
switch(type) {
case 1: { /* values */
float2str(dd,vbuf);
if(pp
-p
+strlen(vbuf
)<MAX_LINELEN
-1) {
if(pp>p) *pp++=',';
ovlstrcpy(pp,vbuf);
}
v0=dd; break;
}
case 2: { /* sum */
v0=v0+dd; break;
}
case 3: { /* product */
v0=v0*dd; break;
}
case 4: { /* recursion */
v0=dd; break;
}
}
}
}
if(type!=1) float2str(v0,p);
}
/* cut a function into values */
void calc_values(char *p)
{ _values(p,1); }
/* compute sum */
void calc_sum(char *p)
{ _values(p,2); }
/* compute product */
void calc_product(char *p)
{ _values(p,3); }
/* simple recursion */
void calc_recursion(char *p)
{ _values(p,4); }
/* List substitution */
void calc_makelist(char *p)
{ _values(p,5); }
/* level curve data */
void calc_leveldata(char *p)
{
leveldata ld;
char *sizep, *rangep, *fp, *levelp, *stepp;
char *pp,*p2,fbuf[MAX_LINELEN+1],buf[MAX_LINELEN+1];
double d[4];
int i;
sizep=wordchr(p,"size");
rangep=wordchr(p,"ranges");
fp=wordchr(p,"function");
levelp=wordchr(p,"levels");
stepp=wordchr(p,"step");
if(sizep==NULL || rangep==NULL || fp==NULL) {
syntax: module_error("syntax_error"); *p=0; return;
}
*sizep
=0; sizep
+=strlen("size");
*rangep
=0; rangep
+=strlen("ranges");
*fp
=0; fp
+=strlen("function");
if(levelp
!=NULL
) {*levelp
=0; levelp
+=strlen("levels");}
else levelp="0";
if(stepp
!=NULL
) {*stepp
=0; stepp
+=strlen("step");}
else stepp="0";
mystrncpy(fbuf,fp,sizeof(fbuf)); substitute(fbuf);
ld.fn=fbuf;
ld.xname="x"; ld.yname="y"; ld.grain=evalue(stepp);
mystrncpy(buf,sizep,sizeof(buf)); substitute(buf);
for(i=0,pp=buf;i<2;i++,pp=p2) {
if(*pp==0) goto syntax;
p2=find_item_end(pp); if(*p2) *p2++=0;
d[i]=evalue(pp);
}
ld.xsize=d[0]; ld.ysize=d[1];
mystrncpy(buf,rangep,sizeof(buf)); substitute(buf);
for(i=0,pp=buf;i<4;i++,pp=p2) {
if(*pp==0) goto syntax;
p2=find_item_end(pp); if(*p2) *p2++=0;
d[i]=evalue(pp);
}
ld.xrange[0]=d[0]; ld.xrange[1]=d[1]; ld.yrange[0]=d[3]; ld.yrange[1]=d[2];
mystrncpy(buf,levelp,sizeof(buf)); substitute(buf);
ld.levelcnt=itemnum(buf); if(ld.levelcnt>LEVEL_LIM) ld.levelcnt=LEVEL_LIM;
for(i=0,pp=buf;i<ld.levelcnt;i++,pp=p2) {
if(*pp==0) goto syntax;
p2=find_item_end(pp); if(*p2) *p2++=0;
ld.levels[i]=evalue(pp);
}
levelcurve(&ld);
for(i=0, pp=p; i<ld.datacnt && pp<p+MAX_LINELEN-16; i++) {
float2str(ld.xdata[i],buf);
if(pp
-p
+strlen(buf
)<MAX_LINELEN
-1) {
if(pp>p) *pp++=';';
ovlstrcpy
(pp
,buf
); pp
+=strlen(pp
);
}
float2str(ld.ydata[i],buf);
if(pp
-p
+strlen(buf
)<MAX_LINELEN
-1) {
if(pp>p) *pp++=',';
ovlstrcpy
(pp
,buf
); pp
+=strlen(pp
);
}
}
}
/* internal routine with no security check */
void _lookup(char *p, char *fname)
{
char buf1[MAX_LINELEN+1];
char *p1, *p2, *mbuf;
mbuf=readfile(fname,NULL,WORKFILE_LIMIT);
if(mbuf
==NULL
) {abort: *p
=0; return;}
p1=find_word_start(p); strip_trailing_spaces(p1);
snprintf(buf1
,sizeof(buf1
),"%s:",p1
); substit
(buf1
);
p1!=NULL && p1>mbuf && *(p1-1)!='\n';
if(p2>p1 && *(p2-1)=='\\') {*(p2-1)=' '; continue;}
else break;
}
if(p2
==NULL
) p2
=p1
+strlen(p1
); else *p2
=0;
mystrncpy
(p
,p1
,MAX_LINELEN
); free(mbuf
);
}
/* lookup a definition in a definition file */
void calc_lookup(char *p)
{
char buf2[MAX_LINELEN+1], buf3[MAX_FNAME+1];
char *p2;
p2
=wordchr
(p
,"in"); if(p2
==NULL
) {abort: *p
=0; return;}
*p2=0;p2=find_word_start(p2+2);
mystrncpy(buf2,p2,sizeof(buf2)); substit(buf2);
*find_word_end(buf2)=0;
if(strstr(buf2
,parent_dir_string
)!=NULL
) {
force_setvar("wims_error_data",buf2); module_error("illegal_cmd");
}
if(datafile_check(buf2)!=0 || find_module_file(buf2,buf3,0)!=0)
_lookup(p,buf3);
}
else _lookup(p,buf2);
}
/* Hide name of a file. Only in module directory or in gifs/ */
void calc_rename(char *p)
{
char buf1[MAX_LINELEN+1], buf2[MAX_LINELEN+1];
char *p1, *ext, *s;
int t;
if(robot_access
|| strstr(p
,"getfile")!=NULL
) return;
p1=find_word_start(p); *find_word_end(p1)=0;
if(p1>p) ovlstrcpy(p,p1);
if(strstr(p
,parent_dir_string
)!=NULL
||
badfile: force_setvar("wims_error_data",p); module_error("illegal_cmd");
}
mkfname(buf1,"%s/getfile",session_prefix); mkdirs(buf1);
mkfname(buf1,"%s/.rename",session_prefix);
mystrncpy(buf2,p,sizeof(buf2)); _lookup(buf2,buf1);
if(buf2[0]!=0) { /* already */
mystrncpy(p,buf2,MAX_LINELEN); return;
}
if(cwdbuf[0]==0) return;
if(p1>p && *p1=='.') ext=p1; else ext="";
rerand: t=random();
mkfname(buf1,"%s/%s",cwdbuf,p);
mkfname(buf2,"%s/getfile/rename-%u%s",session_prefix,t,ext);
if(ftest(buf2)>=0) goto rerand;
(void) symlink(buf1,buf2);
s=getvar("wims_session"); if(s==NULL) return;
if(good_httpd
) snprintf(buf1
,sizeof(buf1
),
"getfile/rename-%u%s?session=%s", t,ext,s);
else snprintf(buf1
,sizeof(buf1
),"%s?cmd=getfile&+session=%s&+special_parm=rename-%u%s",
ref_name, s, t,ext);
snprintf(buf2
,sizeof(buf2
),"%s:%s\n",p
,buf1
);
accessfile(buf2,"a","%s/.rename",session_prefix);
mystrncpy(p,buf1,MAX_LINELEN);
}
/* Pick up and translate imgrename(...) within a string */
void calc_imgrename(char *p)
{
char buf[MAX_LINELEN+1], buf2[MAX_LINELEN+1];
char *p1, *p2, *p3, *p4;
for(p1=varchr(p,"imgrename"); p1!=NULL; p1=varchr(p1,"imgrename")) {
p2
=find_word_start
(p1
+strlen("imgrename"));
if(*p2!='(') {p1=p2; continue;}
p2++; p3=find_matching(p2,')');
if(*p3!=')') {p1=p2-1; continue;}
p2=find_word_start(p2); p4=find_word_end(p2);
memmove(buf
,p2
,p4
-p2
); buf
[p4
-p2
]=0;
calc_rename(buf); *p3=0;
snprintf(buf2
,sizeof(buf2
),"<img src=\"%s\"%s alt=\"\">",buf
, p4
);
*p3=')'; p3++;
string_modify(p,p1,p3,"%s",buf2);
}
}
/* internal use only */
void calc_unhttp(char *p)
{
_http2env(tmplbuf,p); mystrncpy(p,tmplbuf,MAX_LINELEN);
}
/*
method BDSi not maintained in linux:
...0 gives the number of DES rounds (2 here) _...0smiw
come back to "Nv", basic DES
*/
void _passcrypt(char *p, char *salted_hash)
{
#ifdef HAVE_CRYPT
char* saltstr=salted_hash ? salted_hash: "Nv";
char *p1, *p2, *pp, *s, buf[MAX_LINELEN+1];
buf[0]=0; pp=buf;
for(p1=find_word_start(p);*p1;p1=find_word_start(p2)) {
p2=find_word_end(p1); if(*p2) *p2++=0;
if(pp>buf) s=" "; else s="";
if(*p1=='*')
snprintf(pp
,MAX_LINELEN
-(pp
-buf
),"%s%s",s
,p1
);
else
snprintf(pp
,MAX_LINELEN
-(pp
-buf
),"%s*%s",s
,crypt
(p1
,saltstr
));
}
ovlstrcpy(p,buf);
#endif
}
void calc_passcrypt(char *p)
{
_passcrypt(p, NULL);
}
/*
syntax: passcheck nocrypt and list of words as *cryptwords
check if the passcrypt of nocrypt is amongst the list of words
*/
void calc_passcheck(char *p)
{
char cl[MAX_LINELEN+1],sh[MAX_LINELEN+1];
char *qq, *pp=wordchr(p,"and");
if(pp==NULL) module_error("syntax_error");
*pp
=0;ovlstrcpy
(cl
,p
); ovlstrcpy
(sh
,pp
+strlen("and"));
substit(cl); substit(sh);
for (pp = sh;*pp; pp=qq){
while (*pp && *pp != '*') ++pp;
/* delete the star */
pp++;
if(!*pp) break;
for (qq = pp; *qq && *qq != ' '; ++qq);
if (*qq) *qq++ = 0;
_passcrypt(cl, pp);
{ovlstrcpy(p, "yes"); return;}
}
ovlstrcpy(p, "no");
}
void exec_readproc(char *p);
/* crypted mail interface */
void calc_mailurl(char *p)
{
char *p0, buf[MAX_LINELEN+1];
if(robot_access) {*p=0; return;}
snprintf(buf
,sizeof(buf
),"mailurl.proc %s",p
);
exec_readproc(buf);
p0=getvar("mailurl_"); if(p0==NULL) p0="";
mystrncpy(p,p0,MAX_LINELEN);
}
/* get option word in a string */
void calc_getopt(char *p)
{
char *p1, *p2, *p3, *p4;
char buf1[MAX_LINELEN+1], buf2[MAX_LINELEN+1];
p1=wordchr(p,"in"); if(p1==NULL) module_error("syntax error");
*p1=0; p1=find_word_start(p1+3);
mystrncpy(buf1,p,MAX_LINELEN); mystrncpy(buf2,p1,MAX_LINELEN);
substitute(buf1); substitute(buf2);
p1=find_word_start(buf1); *find_word_end(p1)=0;
for(p2=buf2;*p2;p2++) {
if(myisspace(*p2)) *p2=' ';
if(*p2=='=') *p2=' ';
}
*p=0;
p2=wordchr(buf2,p1); if(p2==NULL) return;
for(p3=find_word_end(p2);myisspace(*p3);p3++) {
if(*p3==' ') {
p3=find_word_start(p3);
switch(*p3) {
case '"': {
goto tested;
}
case '(': {
p4=find_matching(p3+1,')');
goto tested;
}
case '[': {
p4=find_matching(p3+1,']');
goto tested;
}
case '{': {
p4=find_matching(p3+1,'}');
tested:
if(p4) {
p3++; *p4=0; break;
}
else goto nomatch;
}
default: {
nomatch:
*find_word_end(p3)=0;
}
}
mystrncpy(p,p3,MAX_LINELEN);
return;
}
}
*find_word_end(p2)=0;
mystrncpy(p,p2,MAX_LINELEN);
}
/* internal */
static void _embraced(char buf[], void (app)(char *p))
{
char *p1, *p2, buf2[MAX_LINELEN+1];
p2=find_matching(p1+1,'}');
if(p2==NULL) module_error("unmatched_parentheses");
*p2=0; mystrncpy(buf2,p1+1,sizeof(buf2)); app(buf2);
string_modify(buf,p1,p2+1,buf2);
}
}
static void _embraced_tree(char buf[])
{
char *p1, *p2, buf2[MAX_LINELEN+1];
int nb, index;
p2=find_matching(p1+1,'}');
if(p2==NULL) module_error("unmatched_parentheses");
*p2=0; nb=itemnum(p1+1); *p2='}'; index=(random()%nb)+1;
p2=find_matching(p1+1,'}');
if(p2==NULL) module_error("unmatched_parentheses");
*p2=0; fnd_item(p1+1,index,buf2);
string_modify(buf,p1,p2+1,buf2);
}
}
}
/* embraced operations */
void calc_embraced(char *p)
{
char *p1, *p2, buf[MAX_LINELEN+1];
p1=find_word_start(p); p2=find_word_end(p1);
if(*p2==0) {*p=0; return;}
*p2++=0; p2=find_word_start(p2);
mystrncpy(buf,p2,sizeof(buf)); substit(buf);
if(p1>p) ovlstrcpy(p,p1);
substit(p);
if(strcmp(p
,"randitem")==0) {_embraced
(buf
,calc_randitem
); goto end
;}
if(strcmp(p
,"randrow")==0) {_embraced
(buf
,calc_randrow
); goto end
;}
if(strcmp(p
,"linkedranditem")==0) {_embraced_tree
(buf
); goto end
;}
if(p1!=NULL) {
p2=find_matching(++p1,'}');
if(p2!=NULL) {
memmove(buf
,p1
,p2
-p1
); buf
[p2
-p1
]=0;
}
else buf[0]=0;
}
else buf[0]=0;
goto end;
}
p2=find_matching(p1+1,'}');
if(p2) ovlstrcpy(p1,p2+1); else p1++;
}
goto end;
}
module_error("syntax_error");
end:
mystrncpy(p,buf,MAX_LINELEN);
}
void calc_rows2lines(char *p)
{ rows2lines(p); }
void calc_lines2rows(char *p)
{ lines2rows(p); }
/* check whether datamodules exist */
void calc_checkdata(char *p)
{
char *p1, *p2, buf[MAX_LINELEN+1], nbuf[MAX_FNAME+1];
struct stat st;
p1=getvar("module_data");
if(p1==NULL || *p1==0) return;
for(p2=buf; *p2; p2++) if(*p2==',' || *p2==';') *p2=' ';
snprintf(p
,MAX_LINELEN
,"badly_defined_data_module");
return;
}
for(p1=find_word_start(buf); *p1; p1=find_word_start(p2)) {
p2=find_word_end(p1); if(*p2) *p2++=0;
snprintf(nbuf
,sizeof(nbuf
),"%s/%s/INDEX",module_dir
,p1
);
if(stat(nbuf,&st)<0) {
snprintf(nbuf
,sizeof(nbuf
),"%s/%s/index",module_dir
,p1
);
if(stat(nbuf,&st)<0) {
return;
}
}
}
}
/* tag!=0 if we don't want automatic substit(). */
MYFUNCTION calc_routine[]={
{"TeXmath", 0, texmath},
{"add", 1, calc_sum},
{"append", 1, calc_append},
{"call", 0, calc_exec},
{"char", 1, calc_charof},
{"charcnt", 0, calc_lengthof},
{"charcount", 0, calc_lengthof},
{"charno", 0, calc_lengthof},
{"charnum", 0, calc_lengthof},
{"chars", 1, calc_charof},
{"checkallpar",0,calc_checkallpar},
{"checkdata", 0, calc_checkdata},
{"checkdatamodule",0, calc_checkdata},
{"checkhost", 0, calc_checkhost},
{"column", 1, calc_columnof},
{"columns", 1, calc_columnof},
{"daemon", 0, calc_daemon},
{"date", 0, calc_date},
{"deaccent", 0, deaccent},
{"debug", 0, calc_debug},
{"declosing", 0, calc_declosing},
{"definitionof", 1, calc_defof},
{"defof", 1, calc_defof},
{"detag", 0, calc_detag},
/* {"dictionary", 1, calc_dictionary}, */
{"dir", 0, calc_listfile},
{"embraced", 1, calc_embraced},
{"encyclo", 0, pedia},
{"encyclopedia", 0, pedia},
{"eval", 0, calc_evalue},
{"evalsubst", 1, calc_evalsubst},
{"evalsubstit", 1, calc_evalsubst},
{"evalsubstitute",1, calc_evalsubst},
{"evalue", 0, calc_evalue},
{"evaluesubst", 1, calc_evalsubst},
{"evaluesubstit", 1, calc_evalsubst},
{"evaluesubstitute",1, calc_evalsubst},
{"examdep", 0, calc_examdep},
{"examscore", 0, calc_examscore},
{"exec", 0, calc_exec},
{"execute", 0, calc_exec},
{"fileexists", 0, calc_fileexists},
{"filelist", 0, calc_listfile},
{"filexists", 0, calc_fileexists},
{"getdef", 1, calc_defof},
{"getopt", 1, calc_getopt},
{"getscore", 0, calc_getscore},
{"getscorealltries", 0, calc_getscorealltries},
{"getscorebest", 0, calc_getscorebest},
{"getscorelast", 0, calc_getscorelast},
{"getscorelevel", 0, calc_getscorelevel},
{"getscoremaxexotry",0,calc_getscoremaxexotry},
{"getscoremean",0, calc_getscoremean},
{"getscorepercent",0, calc_getscorepercent},
{"getscorequality",0, calc_getscoremean},
{"getscoreremain",0, calc_getscoreremain},
{"getscorerequire",0, calc_getscorerequire},
{"getscorestatus",0, calc_getscorestatus},
{"getscoretry", 0, calc_getscoretry},
{"getscoreweight",0, calc_getscoreweight},
{"getseedlast", 0, calc_getseedlast},
{"getseedlastcnt", 0, calc_getseedlastcnt},
{"getseedscorelast", 0, calc_getseedscorelast},
{"getseedscores", 0, calc_getseedscores},
{"hex", 0, calc_hex},
{"html2iso", 0, calc_html2iso},
{"htmlmath", 0, htmlmath},
{"httpquery", 0, tohttpquery},
{"imgrename", 0, calc_imgrename},
{"instexst", 1, calc_instexst},
{"instexstatic", 1, calc_instexst},
{"item", 1, calc_itemof},
{"itemcnt", 0, calc_itemnum},
{"itemcount", 0, calc_itemnum},
{"itemno", 0, calc_itemnum},
{"itemnum", 0, calc_itemnum},
{"items", 1, calc_itemof},
{"items2lines", 0, items2lines},
{"items2words", 0, items2words},
{"itemstolines", 0, items2lines},
{"itemstowords", 0, items2words},
{"lengthof", 0, calc_lengthof},
{"leveldata", 1, calc_leveldata},
{"levelpoints", 1, calc_leveldata},
{"line", 1, calc_lineof},
{"linecnt", 0, calc_linenum},
{"linecount", 0, calc_linenum},
{"lineno", 0, calc_linenum},
{"linenum", 0, calc_linenum},
{"lines", 1, calc_lineof},
{"lines2items", 0, lines2items},
{"lines2list", 0, lines2items},
{"lines2rows", 0, calc_lines2rows},
{"lines2words", 0, lines2words},
{"linestoitems", 0, lines2items},
{"linestolist", 0, lines2items},
{"linestowords", 0, lines2words},
{"list2lines", 0, items2lines},
{"list2words", 0, items2words},
{"listcomplement",1, calc_listcomplement},
{"listfile", 0, calc_listfile},
{"listfiles", 0, calc_listfile},
{"listintersect", 1, calc_listintersect},
{"listintersection",1, calc_listintersect},
{"listtolines", 0, items2lines},
{"listtowords", 0, items2words},
{"listunion", 1, calc_listunion},
{"listuniq", 0, calc_listuniq},
{"listunique", 0, calc_listuniq},
{"listvar", 0, mathvarlist},
{"lookup", 1, calc_lookup},
{"lower", 0, calc_tolower},
{"lowercase", 0, calc_tolower},
{"ls", 0, calc_listfile},
{"mailurl", 0, calc_mailurl},
{"makelist", 1, calc_makelist},
{"math2html", 0, htmlmath},
{"math2mathml", 0,mathmlmath},
{"math2tex", 0, texmath},
{"mathmlmath", 0, mathmlmath},
{"mathsubst", 1, calc_mathsubst},
{"mathsubstit", 1, calc_mathsubst},
{"mathsubstitute",1, calc_mathsubst},
{"mexec", 0, calc_mexec},
{"module", 0, calc_module},
{"multiply", 1, calc_product},
{"non_empty", 0, calc_nonempty},
{"nonempty", 0, calc_nonempty},
{"nospace", 0, nospace},
{"nosubst", 1, calc_subst},
{"nosubstit", 1, calc_subst},
{"nosubstitute", 1, calc_subst},
{"passcheck", 1, calc_passcheck},
{"passcrypt", 0, calc_passcrypt},
{"pedia", 0, pedia},
{"perl", 0, calc_perl},
{"position", 1, calc_pos},
{"positionof", 1, calc_pos},
{"positions", 1, calc_pos},
{"prod", 1, calc_product},
{"product", 1, calc_product},
{"randchar", 0, calc_randchar},
{"randdouble", 0, calc_randdouble},
{"randfile", 0, calc_randfile},
{"randfloat", 0, calc_randdouble},
{"randint", 0, calc_randint},
{"randitem", 0, calc_randitem},
{"randline", 0, calc_randline},
{"random", 0, calc_randdouble},
{"randperm", 0, calc_randperm},
{"randpermute", 0, calc_randperm},
{"randreal", 0, calc_randdouble},
{"randrecord", 0, calc_randfile},
{"randrow", 0, calc_randrow},
{"randword", 0, calc_randword},
{"rawmath", 0, rawmath},
{"rawmatrix", 0, rawmatrix},
{"reaccent", 0, reaccent},
{"record", 1, calc_recordof},
{"recordcnt", 0, calc_recordnum},
{"recordcount", 0, calc_recordnum},
{"recordno", 0, calc_recordnum},
{"recordnum", 0, calc_recordnum},
{"records", 1, calc_recordof},
{"recursion", 1, calc_recursion},
{"reinput", 0, calc_reinput},
{"rename", 0, calc_rename},
{"replace", 1, calc_replace},
{"rootof", 1, calc_solve},
{"row", 1, calc_rowof},
{"rowcnt", 0, calc_rownum},
{"rowcount", 0, calc_rownum},
{"rowno", 0, calc_rownum},
{"rownum", 0, calc_rownum},
{"rows", 1, calc_rowof},
{"rows2lines", 0, calc_rows2lines},
{"run", 0, calc_exec},
{"select", 1, calc_select},
{"sh", 0, calc_sh},
{"shuffle", 0, calc_randperm},
{"singlespace", 0, singlespace},
{"slashsubst", 0, slashsubst},
{"solve", 1, calc_solve},
{"sort", 1, calc_sort},
/* {"sql", 0, calc_sql}, */
{"staticinstex", 1, calc_instexst},
{"stinstex", 1, calc_instexst},
{"subst", 0, calc_subst},
{"substit", 0, calc_subst},
{"substitute", 0, calc_subst},
{"sum", 1, calc_sum},
{"system", 0, calc_sh},
{"texmath", 0, texmath},
{"text", 1, text},
{"tohex", 0, calc_hex},
{"tolower", 0, calc_tolower},
{"toupper", 0, calc_toupper},
{"translate", 1, calc_translate},
{"trim", 0, calc_trim},
{"unhttp", 0, calc_unhttp},
{"upper", 0, calc_toupper},
{"uppercase", 0, calc_toupper},
{"values", 1, calc_values},
{"varlist", 0, mathvarlist},
{"word", 1, calc_wordof},
{"wordcnt", 0, calc_wordnum},
{"wordcount", 0,calc_wordnum},
{"wordno", 0, calc_wordnum},
{"wordnum", 0, calc_wordnum},
{"words", 1, calc_wordof},
{"words2items", 0, words2items},
{"words2lines", 0, words2lines},
{"words2list", 0, words2items},
{"wordstoitems", 0,words2items},
{"wordstolines", 0,words2lines},
{"wordstolist", 0, words2items}
};
int CALC_FN_NO=(sizeof(calc_routine)/sizeof(calc_routine[0]));