Subversion Repositories wimsdev

Rev

Rev 8185 | Rev 9378 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
10 reyssat 1
/*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
2
 *
3
 *  This program is free software; you can redistribute it and/or modify
4
 *  it under the terms of the GNU General Public License as published by
5
 *  the Free Software Foundation; either version 2 of the License, or
6
 *  (at your option) any later version.
7
 *
8
 *  This program is distributed in the hope that it will be useful,
9
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 *  GNU General Public License for more details.
12
 *
13
 *  You should have received a copy of the GNU General Public License
14
 *  along with this program; if not, write to the Free Software
15
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16
 */
17
 
7673 bpr 18
/* This is part of wims source.
8155 bpr 19
 * This file does computations and output.
20
 */
8185 bpr 21
#include "wims.h"
10 reyssat 22
 
23
int _sort_numeric, _sort_nocase;
24
typedef struct SORT_STRUCT {char *str; double val; int serial;} SORT_STRUCT;
25
struct SORT_STRUCT sort_sep[MAX_SORT_ITEM+1];
26
 
27
void secure_exec(void)
28
{
29
    if((untrust&6)==0) return;
30
    module_error("Illegal_command");
31
}
32
 
7673 bpr 33
/* internal comparers */
10 reyssat 34
int __sorter(const void *p1, const void *p2)
35
{
36
    struct SORT_STRUCT *pp1, *pp2;
7404 bpr 37
 
10 reyssat 38
    pp1=(struct SORT_STRUCT *) p1; pp2=(struct SORT_STRUCT *) p2;
39
    if(_sort_numeric) {
7673 bpr 40
     double dd=(pp1->val)-(pp2->val);
41
     if(dd>0) return 1;
42
     if(dd<0) return -1;
43
     return 0;
10 reyssat 44
    }
45
    if(_sort_nocase) return strcasecmp(pp1->str,pp2->str);
46
    else return strcmp(pp1->str,pp2->str);
47
}
48
 
49
int _char_sorter(const void *c1, const void *c2)
50
{
51
    if(_sort_nocase) return tolower(*(char *)c1)-tolower(*(char *)c2);
52
    else return *(char *)c1-*(char *)c2;
53
}
54
 
55
enum {sort_char, sort_word, sort_item, sort_line, sort_row,
56
      sort_numeric, sort_nocase, sort_reverse
57
};
58
struct {char *name; int type;
59
} sort_keyw[]={
7673 bpr 60
       {"char",sort_char},
61
       {"chars",sort_char},
62
       {"character",sort_char},
63
       {"characters",sort_char},
64
       {"word",sort_word},
65
       {"words",sort_word},
66
       {"item",sort_item},
67
       {"items",sort_item},
68
       {"line",sort_line},
69
       {"lines",sort_line},
70
       {"list",sort_item},
71
       {"numeric",sort_numeric},
72
       {"numerical",sort_numeric},
73
       {"nocase",sort_nocase},
74
       {"ignorecase",sort_nocase},
75
       {"reverse",sort_reverse},
76
       {"row",sort_row},
77
       {"rows",sort_row}
10 reyssat 78
};
79
#define sort_keyw_no (sizeof(sort_keyw)/sizeof(sort_keyw[0]))
80
 
7673 bpr 81
/* string sort */
10 reyssat 82
void calc_sort(char *p)
83
{
84
    char *p1, *p2, buf[MAX_LINELEN+1], *csep[MAX_SORT_ITEM+1];
85
    char fs=0;
86
    int (*cutfn)(char *p,char *list[],int max);
87
    int nocase=0, reverse=0, numeric=0, type;
88
    int i,j,l,t,total;
7404 bpr 89
 
10 reyssat 90
    cutfn=NULL;
91
    for(i=0,p1=find_word_start(p);i>=0;p1=find_word_start(p2)) {
7673 bpr 92
     p2=find_word_end(p1); if(*p2!=0) *p2++=0;
93
     for(i=0;i<sort_keyw_no && strcasecmp(p1,sort_keyw[i].name)!=0;i++);
94
     if(i>=sort_keyw_no) module_error("syntax_error");
95
     switch(type=sort_keyw[i].type) {
96
         case sort_nocase: nocase=1; break;
97
         case sort_reverse: reverse=1; break;
98
         case sort_numeric: numeric=1; break;
99
         case sort_char: i=-1; break;
100
         case sort_word: cutfn=cutwords; fs=' '; i=-1; break;
101
         case sort_item: cutfn=cutitems; fs=','; i=-1; break;
102
         case sort_row:
103
         case sort_line: cutfn=cutlines; fs='\n'; i=-1; break;
104
     }
10 reyssat 105
    }
106
    if(p1[0]=='o' && p1[1]=='f' && myisspace(p1[2])) p1=find_word_start(p1+2);
107
    mystrncpy(buf,p1,sizeof(buf)); substit(buf); *p=0;
108
    t=0; if(type==sort_row) t=rows2lines(buf);
109
    _sort_nocase=nocase; _sort_numeric=numeric;
110
    if(cutfn) {
7673 bpr 111
     char ordbuf[MAX_LINELEN+1];
112
     total=cutfn(buf,csep,MAX_SORT_ITEM+1);
113
     if(total<=0 || total>MAX_SORT_ITEM) return;
114
     for(i=0;i<total;i++) {
115
         sort_sep[i].str=csep[i];
116
         if(numeric) sort_sep[i].val=evalue(csep[i]);
117
     }
118
     for(i=0;i<total;i++) sort_sep[i].serial=i+1;
119
     qsort(sort_sep,total,sizeof(sort_sep[0]),__sorter);
120
     p1=p;p2=ordbuf;ordbuf[0]=0;
121
     for(i=0;i<total;i++) {
122
         if(reverse) j=total-1-i; else j=i;
123
         l=strlen(sort_sep[j].str);
124
         if(p1-p+l>=MAX_LINELEN-1) module_error("cmd_output_too_long");
125
         if(p1>p) *p1++=fs;
126
         memmove(p1,sort_sep[j].str,l+1); p1+=l;
127
         if(i>0) *p2++=',';
128
         mystrncpy(p2,int2str(sort_sep[j].serial),
129
                MAX_LINELEN-(p2-ordbuf)-1);
130
         p2+=strlen(p2);
131
     }
132
     force_setvar("wims_sort_order",ordbuf);
10 reyssat 133
    }
134
    else { /* case of chars */
7673 bpr 135
     qsort(buf,strlen(buf),1,_char_sorter);
136
     total=strlen(buf);
137
     if(reverse) {
138
         for(i=total-1;i>=0;i--) *(p+total-i-1)=buf[i];
139
         *(p+total)=0;
140
     }
141
     else memmove(p,buf,total+1);
10 reyssat 142
    }
143
    if(t) lines2rows(p);
144
}
145
 
7673 bpr 146
/* Print a debug output */
10 reyssat 147
void calc_debug(char *p)
148
{
149
    secure_exec(); setvar("debug",p); module_error("debug");
150
}
151
 
7673 bpr 152
/* execute a command thru wimslogd */
10 reyssat 153
void calc_daemon(char *p)
154
{
155
    if(!trusted_module() || is_class_module) {*p=0; return;}
156
    _daemoncmd(p);
157
}
158
 
159
void _get_exec_error(char *errorfname, char *cmdname)
160
{
161
    char *p2;
162
    char obuf[MAX_LINELEN+1];
163
    int l;
164
    if(errorfname) accessfile(obuf,"e","%s",errorfname);
165
    else {
7673 bpr 166
     l=read(mxtab[multiexec_index].pipe_stderr[0],obuf,MAX_LINELEN/4);
167
     if(l<0 || l>MAX_LINELEN) l=0;
168
     obuf[l]=0;
10 reyssat 169
    }
170
    if(obuf[0]) {
7673 bpr 171
     p2=find_word_end(obuf);
172
     if((manageable<1 || strcasecmp(tmp_debug,"yes")!=0) &&
173
        !trusted_module() &&
174
        strncmp(p2," not_INStalled",strlen(" not_INStalled"))==0) {
175
         *p2=0; setvar("missing_software",obuf);
176
         snprintf(p2+1,MAX_LINELEN-strlen(obuf)-8,"missing_%s",obuf);
177
         if(!outputing) user_error(p2+1);
178
     }
179
     p2=getvar("wims_exec_error"); if(p2==NULL) p2="";
180
     snprintf(tmplbuf,sizeof(tmplbuf),"%s\nERROR from %s:\n%s",p2,cmdname,obuf);
181
     force_setvar("wims_exec_error",tmplbuf);
10 reyssat 182
    }
183
}
184
 
8155 bpr 185
/* execute an external program
186
 * The output of the external program should be put into
187
 * a file session_directory/session/cmd.tmp.
188
 */
10 reyssat 189
void calc_exec(char *p)
190
{
191
    int i,j,k;
192
    char *cmd, *parm, *pp;
193
    char namebuf[MAX_EXEC_NAME+1], cmdstr[MAX_LINELEN+256], obuf[MAX_LINELEN+1];
194
    char outfname[MAX_FNAME+1], errorfname[MAX_FNAME+1],
195
      typefname[MAX_FNAME+1], varfname[MAX_FNAME+1];
196
    char *abuf[2]={NULL,NULL};
197
    WORKING_FILE wf;
198
    if(robot_access || time(0)>=limtimex-1) {
7673 bpr 199
     *p=0;return;
10 reyssat 200
    }
201
    cmd=find_word_start(p); if(*cmd==0) return; /* No command. */
202
    parm=find_word_end(cmd);j=parm-cmd;parm=find_word_start(parm);
203
    if(j>MAX_EXEC_NAME) {
7673 bpr 204
     wrong_command:
205
     setvar(error_data_string,namebuf); module_error("bad_cmd");
206
     *p=0; return; /* should not occur */
10 reyssat 207
    }
208
    memmove(namebuf,cmd,j); namebuf[j]=0;
7673 bpr 209
/* Specifying parent directory in command name is of course
210
 * prohibited.
211
 * The module developper cannot start from root, for bin_dir
8155 bpr 212
 * will be prefixed to cmd.
213
 */
10 reyssat 214
    if(strstr(namebuf,parent_dir_string)!=NULL) {
7673 bpr 215
     setvar(error_data_string,namebuf); module_error("illegal_cmd");
216
     *p=0; return;
10 reyssat 217
    }
218
    snprintf(cmdstr,sizeof(cmdstr),"%s/%s",bin_dir,namebuf);
219
    if(ftest(cmdstr)!=is_exec) goto wrong_command;
220
    abuf[0]=cmdstr;
221
    mkfname(outfname,"%s/exec.out",tmp_dir);
222
    mkfname(errorfname,"%s/exec.err",tmp_dir);
223
    mkfname(typefname,"%s/exec.type",tmp_dir);
224
    unlink(typefname);
225
    mkfname(varfname,"%s/exec.var",tmp_dir);
226
    unlink(varfname);
227
    if(!trusted_module()) setenv("untrust","yes",1); else unsetenv("untrust");
228
    if(strcmp(parm,"about")!=0 && multiexec(namebuf,abuf)) {
7673 bpr 229
     fd_set rset;
230
     struct timeval t;
231
     int v1, v2, fd;
7404 bpr 232
 
7673 bpr 233
     i=strlen(parm);
234
     fd=mxtab[multiexec_index].pipe_stdin[1];
235
     (void)write(fd,parm,i);
236
     (void)write(fd,multiexec_random,strlen(multiexec_random));
237
     *p=0; i=0; k=MAX_LINELEN; fd=mxtab[multiexec_index].pipe_stdout[0];
238
     while(k>0) {
239
         FD_ZERO(&rset); FD_SET(fd,&rset);
240
         t.tv_sec=0; t.tv_usec=100000; v1=0; v2=300; /* 3 seconds */
241
         if(select(fd+1,&rset,NULL,NULL,&t)<=0) {
242
          v1++; if(v1>=v2) break;
243
          else continue;
244
         }
245
         j=read(fd,p+i,k);
246
         if(j<0 || j>k) break;
247
         i+=j; k-=j; p[i]=0;
248
         pp=strstr(p,multiexec_random);
249
         if(pp) {*pp=0; break;}
250
     }
251
     fd=mxtab[multiexec_index].pipe_stderr[0];
252
     FD_ZERO(&rset); FD_SET(fd,&rset);
253
     t.tv_sec=0; t.tv_usec=0;
254
     if(select(fd+1,&rset,NULL,NULL,&t)>0)
255
       _get_exec_error(NULL,namebuf);
256
     strip_trailing_spaces(p);
257
     return;
10 reyssat 258
    }
259
    exportall(); setenv("wims_exec_parm",parm,1);
260
    execredirected(cmdstr,NULL,outfname,errorfname,abuf);
261
    if(open_working_file(&wf,varfname)==0) {
7673 bpr 262
     char *pt, *pv;
263
     while(wgetline(tmplbuf,MAX_LINELEN, &wf)!=EOF) {
264
         pt=find_word_start(tmplbuf); pv=strchr(pt,'=');
265
         if(pv==NULL || pv<=tmplbuf) continue;
266
         *pv=0; pv=find_word_start(++pv);
267
         *find_word_end(pt)=0;
268
         strip_trailing_spaces(pv);
269
         setvar(pt,pv);
270
 }
271
     close_working_file(&wf,0);
10 reyssat 272
    }
273
    read_tmp_file(p,"exec.out");
274
    read_tmp_file(obuf,"exec.type");
275
    if(obuf[0]) k=atoi(obuf); else k=0;
276
    for(i=2;i<=k && i<256;i++) {
7673 bpr 277
     char nbuf[32];
278
     snprintf(nbuf,sizeof(nbuf),"exec.out.%d",i);
279
     read_tmp_file(obuf,nbuf);
280
     if(obuf[0]) {
281
         snprintf(nbuf,sizeof(nbuf),"wims_exec_out_%d",i);
282
         force_setvar(nbuf,obuf);
283
     }
10 reyssat 284
    }
285
    strip_trailing_spaces(p);
286
    _get_exec_error(errorfname,namebuf);
287
    return;
288
}
289
 
7673 bpr 290
/* execute external program in the module directory.
8155 bpr 291
 * For privileged modules only
292
 */
10 reyssat 293
void calc_mexec(char *p)
294
{
295
    char *public_bin;
296
    if(robot_access) return;
297
    if(trusted_module()!=1 || is_class_module) {
7673 bpr 298
     module_error("not_trusted"); *p=0; return;
10 reyssat 299
    }
7673 bpr 300
/* The following is useless, because mexec content is often given
8155 bpr 301
 * by variables
302
 */
10 reyssat 303
/*    if(strstr(p,PARENT_DIR_STRING)!=NULL) {
7673 bpr 304
     setvar("wims_error_data",p);
305
     module_error("illegal_fname"); *p=0; return;
10 reyssat 306
    }
307
*/    public_bin=bin_dir; bin_dir=module_prefix;
308
    exec_is_module=1;
309
    calc_exec(p); bin_dir=public_bin;
310
    exec_is_module=0;
311
}
312
 
313
void _calc_exec(char *p, char *arg0, char *arg1, int n)
314
{
315
    char *abuf[8];
316
    char outfname[MAX_FNAME+1], errorfname[MAX_FNAME+1];
317
 
318
    if(robot_access) {*p=0; return;}
319
    if(!trusted_module() || is_class_module) {
7673 bpr 320
     if(strcasecmp(tmp_debug,"yes")==0)
321
       accessfile(p,"w","%s/%s.cmd",tmp_dir,arg0);
322
     abuf[0]="bin/ch..root";
323
     abuf[1]="&"; abuf[2]=arg0; abuf[3]=p;
324
     abuf[4]=NULL;
10 reyssat 325
    }
326
    else {
7673 bpr 327
/* if(strstr(p,PARENT_DIR_STRING)!=NULL) {
328
         setvar("wims_error_data",p);
329
         module_error("illegal_fname"); *p=0; return;
330
     }
331
*/
332
      abuf[0]=arg0; abuf[1]=arg1; abuf[n]=p; abuf[n+1]=NULL;
10 reyssat 333
    }
334
    mkfname(outfname,"%s/exec.out",tmp_dir);
335
    mkfname(errorfname,"%s/exec.err",tmp_dir);
336
    wrapexec=1; exportall();
337
    execredirected(abuf[0],NULL,outfname,errorfname,abuf);
338
    read_tmp_file(p,"exec.out");
339
    _get_exec_error(errorfname,arg0);
340
}
341
 
7673 bpr 342
/* call shell. */
10 reyssat 343
void calc_sh(char *p)
344
{
345
    _calc_exec(p,"sh","-c",2);
346
}
347
 
7673 bpr 348
/* call perl. */
10 reyssat 349
void calc_perl(char *p)
350
{
351
    _calc_exec(p,"perl","-e",2);
352
}
353
 
7673 bpr 354
/* simple evaluation of string */
10 reyssat 355
void calc_evalue(char *p)
356
{
357
    double d;
358
    d=evalue(p); float2str(d,p); return;
359
}
360
 
7673 bpr 361
/* substitute math variables */
10 reyssat 362
void calc_mathsubst(char *p)
363
{
364
    char *expr, *val, *nam, *pp;
365
    char buf[MAX_LINELEN+1];
366
    expr=wordchr(p,"in"); if(expr==NULL) goto error;
3718 reyssat 367
    ovlstrcpy(buf,find_word_start(expr+strlen("in")));substit(buf);
10 reyssat 368
    *expr=0; substit(p);
369
    val=strchr(p,'=');
370
    if(val==NULL) {
7673 bpr 371
     error:
372
     module_error("mathsubst_syntax"); *p=0;return;
10 reyssat 373
    }
374
    nam=find_word_start(p); *val=0;
375
    val=find_word_start(val+1);
376
    for(pp=val+strlen(val)-1;pp>=val && isspace(*pp);*pp--=0);
377
    *find_word_end(nam)=0;
378
    if(*nam==0) goto error;
379
    if(*nam) for(pp=varchr(buf,nam);pp!=NULL;pp=varchr(pp,nam)) {
7673 bpr 380
     string_modify(buf,pp,pp+strlen(nam),"%s",val);
381
     pp+=strlen(val);
10 reyssat 382
    }
3718 reyssat 383
    ovlstrcpy(p,buf);
10 reyssat 384
}
385
 
7673 bpr 386
/* substitute and evaluate. */
10 reyssat 387
void calc_evalsubst(char *p)
388
{
389
    calc_mathsubst(p);
390
    calc_evalue(p);
391
}
392
 
7673 bpr 393
/* Nothing needs to be done in the function;
8155 bpr 394
 * substitution is done or not by tag in the structure.
395
 */
10 reyssat 396
void calc_subst(char *p)
397
{
398
}
399
 
400
int _randrep(char *p)
401
{
402
    char *rep;
403
    int i;
404
    rep=wordchr(p,"repeat"); if(rep==NULL) return 1;
405
    *rep=0; rep+=strlen("repeat"); i=evalue(rep);
406
    if(i<1) i=1; if(i>MAX_VALUE_LIST) i=MAX_VALUE_LIST;
407
    return i;
408
}
409
 
7673 bpr 410
/* integer random */
10 reyssat 411
void calc_randint(char *p)
412
{
413
    int lbound, ubound, n, i, t;
414
    char *p1, *parm[2];
415
 
416
    t=_randrep(p); n=cutitems(p,parm,2);
417
    if(n<=0) {
7673 bpr 418
     snprintf(p,3,"0"); return; /* Random without bound: return 0. */
10 reyssat 419
    }
420
    lbound=evalue(parm[0]);
7673 bpr 421
/* Missing ubound: random between +-1 and lbound. */
10 reyssat 422
    if(n<=1) {if(lbound<0) ubound=-1; else ubound=1;}
423
    else ubound=evalue(parm[1]);
424
    if(lbound>ubound) {i=lbound; lbound=ubound; ubound=i;}
425
    for(i=0,p1=p;i<t;i++) {
7673 bpr 426
     if(i>0) *p1++=',';
427
     mystrncpy(p1,int2str((int) irand(ubound-lbound+1)+lbound),
428
            MAX_LINELEN-(p1-p)-1);
429
     p1+=strlen(p1);
10 reyssat 430
    }
431
    return;
432
}
433
 
7673 bpr 434
/* floating random */
10 reyssat 435
void calc_randdouble(char *p)
436
{
437
    double lbound, ubound;
438
    int n, i, t;
439
    char *parm[2], *p1;
7404 bpr 440
 
10 reyssat 441
    t=_randrep(p); n=cutitems(p,parm,2);
442
    if(n<=0) {
7673 bpr 443
     snprintf(p,3,"0"); return; /* Random without bound: return 0. */
10 reyssat 444
    }
445
    lbound=evalue(parm[0]);
446
    if(n<=1) ubound=0; /* Missing ubound: random between 0 and lbound. */
447
    else ubound=evalue(parm[1]);
448
    for(i=0,p1=p;i<t;i++) {
7673 bpr 449
     float2str(drand(ubound-lbound)+lbound,tmplbuf);
450
     mystrncpy(p1,tmplbuf,MAX_LINELEN-(p1-p));
451
     p1+=strlen(p1);
452
     if(i<t-1 && p1-p<MAX_LINELEN) *p1++=',';
10 reyssat 453
    }
454
    *p1=0; return;
455
}
456
 
7673 bpr 457
/* Takes randomly a record in a datafile */
10 reyssat 458
void calc_randfile(char *p)
459
{
460
    char *pp, n[MAX_FNAME+1];
461
    int i, j;
7404 bpr 462
 
10 reyssat 463
    pp=find_word_start(p); *find_word_end(pp)=0;
464
    mystrncpy(n,pp,sizeof(n));
465
    i=datafile_recordnum(pp);
466
    if(i<=0) {  /* zero records */
7673 bpr 467
     *p=0; return;
10 reyssat 468
    }
469
    j=irand(i); datafile_fnd_record(n,j+1,p);
470
    return;
471
}
472
 
7673 bpr 473
/* random char, word, line, item in a string */
10 reyssat 474
void calc_randchar(char *p)
475
{
476
    p[0]=p[(int) irand(strlen(p))];p[1]=0;
477
}
478
 
479
void calc_randitem(char *p)
480
{
6790 bpr 481
    int i;
10 reyssat 482
    i=itemnum(p);
6790 bpr 483
   (void) fnd_item(p,irand(i)+1,tmplbuf);
10 reyssat 484
    mystrncpy(p,tmplbuf,MAX_LINELEN);
485
}
486
 
487
void calc_randline(char *p)
488
{
489
    int i;
490
    i=linenum(p); fnd_line(p,irand(i)+1,tmplbuf);
491
    mystrncpy(p,tmplbuf,MAX_LINELEN);
492
}
493
 
494
void calc_randrow(char *p)
495
{
496
    rows2lines(p); calc_randline(p);
497
}
498
 
499
void calc_randword(char *p)
500
{
501
    int i;
502
    i=wordnum(p); fnd_word(p,irand(i)+1,tmplbuf);
503
    mystrncpy(p,tmplbuf,MAX_LINELEN);
504
}
505
 
7673 bpr 506
/* random permutation of {1,...,n} */
10 reyssat 507
void calc_randperm(char *p)
508
{
509
    int n, i, j, k, t, pt, type;
510
    double v;
511
    char buf1[MAX_LINELEN+1],buf2[MAX_LINELEN+1];
512
    char *list[MAX_RANDPERM];
513
    int table[MAX_RANDPERM];
514
    char *p1,*p2,*pp;
7404 bpr 515
 
10 reyssat 516
    t=0; pt=0; pp=p;
517
    p1=find_word_start(p); p2=find_word_end(p1);
518
    if(p2-p1==strlen("even") && strncasecmp(p1,"even",strlen("even"))==0) {
7673 bpr 519
     t=1; pp=p2;
10 reyssat 520
    }
521
    if(p2-p1==strlen("odd") && strncasecmp(p1,"odd",strlen("odd"))==0) {
7673 bpr 522
     t=-1; pp=p2;
10 reyssat 523
    }
7404 bpr 524
 
10 reyssat 525
    p1=find_item_end(pp); if(*p1==',') {
7673 bpr 526
     type=1; n=cutitems(pp,list,MAX_RANDPERM); v=0;
10 reyssat 527
    }
528
    else {
7673 bpr 529
     v=evalue(pp); n=v; type=0;
10 reyssat 530
    }
8171 bpr 531
    if(n==1 && !isfinite(v)) {ovlstrcpy(p,pp); goto shorder;}
10 reyssat 532
    if(n<=0) {*p=0; return;}
533
    if(n==1 && type==0) {
7673 bpr 534
     ovlstrcpy(p,"1");
535
     shorder: force_setvar("wims_shuffle_order","1"); return;
10 reyssat 536
    }
537
    if(n>MAX_RANDPERM) n=MAX_RANDPERM;
538
    for(i=0;i<n;i++) table[i]=i;
8155 bpr 539
/* Uniformity of this algorithm is easy to show by induction. */
10 reyssat 540
    for(i=0;i<n-1;i++) {
7673 bpr 541
     j=irand(n-i)+i; if(j==i) continue;
542
     k=table[i]; table[i]=table[j]; table[j]=k;
543
     pt++;
10 reyssat 544
    }
545
    pt&=1;
546
    if((t==1 && pt==1) || (t==-1 && pt==0)) {
7673 bpr 547
     k=table[0]; table[0]=table[1]; table[1]=k;
10 reyssat 548
    }
549
    if(type) {mystrncpy(buf1,list[table[0]],MAX_LINELEN); p1=buf1+strlen(buf1);}
550
    else buf1[0]=0;
551
    mystrncpy(buf2,int2str(table[0]+1),MAX_LINELEN); p2=buf2+strlen(buf2);
552
    for(i=1;i<n;i++) {
7673 bpr 553
     if(type) {
554
         j=strlen(list[table[i]]);
555
         if(p1-buf1+j>=MAX_LINELEN-1) module_error("cmd_output_too_long");
556
         *p1++=','; memmove(p1,list[table[i]],j+1); p1+=j;
557
     }
558
     *p2++=',';
559
     mystrncpy(p2,int2str(table[i]+1), MAX_LINELEN-(p2-buf2)-1);
560
     p2+=strlen(p2);
10 reyssat 561
    }
562
    if(type) mystrncpy(p,buf1,MAX_LINELEN);
563
    else mystrncpy(p,buf2,MAX_LINELEN);
564
    force_setvar("wims_shuffle_order",buf2);
565
}
566
 
7673 bpr 567
/* Computes number of lines in the parm. */
10 reyssat 568
void calc_linenum(char *p)
569
{
570
    int i=linenum(p); mystrncpy(p,int2str(i),MAX_LINELEN);
571
}
572
 
7673 bpr 573
/* Computes number of lines in the parm. */
10 reyssat 574
void calc_rownum(char *p)
575
{
576
    int i=rownum(p); mystrncpy(p,int2str(i),MAX_LINELEN);
577
}
578
 
7673 bpr 579
/* Computes number of items in the list p. */
10 reyssat 580
void calc_itemnum(char *p)
581
{
582
    int i=itemnum(p); mystrncpy(p,int2str(i),MAX_LINELEN);
583
}
584
 
7673 bpr 585
/* Computes number of records in the datafile p. */
10 reyssat 586
void calc_recordnum(char *p)
587
{
588
    int i;
589
    i=datafile_recordnum(p); mystrncpy(p,int2str(i),MAX_LINELEN);
590
}
591
 
7673 bpr 592
/* Computes number of words in the parm. */
10 reyssat 593
void calc_wordnum(char *p)
594
{
595
    int i=wordnum(p); mystrncpy(p,int2str(i),MAX_LINELEN);
596
}
597
 
7673 bpr 598
/* string length */
10 reyssat 599
void calc_lengthof(char *p)
600
{
601
    int i;
7404 bpr 602
/* Strip leading and trailing spaces? */
10 reyssat 603
    i=strlen(p); mystrncpy(p,int2str(i),MAX_LINELEN);
604
}
605
 
606
char *_blockof_one(char *buf,
7673 bpr 607
            unsigned int len,
608
            char *(fnd_fn)(char *pl, int n, char bbuf[]),
609
            int i, char bbuf[])
10 reyssat 610
{
611
    if(i<0 || i>len || (i==0 && fnd_fn!=datafile_fnd_record) ) {
7673 bpr 612
     bbuf[0]=0; return bbuf;
10 reyssat 613
    }
614
    return fnd_fn(buf,i,bbuf);
615
}
616
 
617
void _blockof(char *p,
7673 bpr 618
           unsigned int (len_fn)(char *pl),
619
           char *(fnd_fn)(char *pl, int n, char bbuf[]),
620
           char *append_char,
621
           char *msg_str)
10 reyssat 622
{
623
    int i,j,l,started;
624
    char *pp, *pe, *po, *pnext;
625
    char buf[MAX_LINELEN+1], obuf[MAX_LINELEN+1], bbuf[MAX_LINELEN+1];
626
    pp=wordchr(p,"of");
627
    if(pp==NULL) {
7673 bpr 628
     setvar(error_data_string,msg_str);
629
     module_error("no_of"); *p=0; return;
10 reyssat 630
    }
631
    *pp=0; pp=find_word_start(pp+strlen("of")+1);
632
    mystrncpy(buf,pp,sizeof(buf)); substit(buf);
633
    obuf[0]=0; started=0; po=obuf;
634
    pp=strparstr(p,"to");
635
    while(*pp!=0 && ((pp>p && !isspace(*(pp-1))) || !isspace(*(pp+2))))
636
      pp=strparstr(pp+2,"to");
637
    if(*pp==0) pp=strparstr(p,"..");
638
    if(*pp!=0) {
7673 bpr 639
     int t=len_fn(buf);
640
     *pp=0; pe=find_word_start(pp+2);
641
     i=evalue(p); j=evalue(pe); pnext=buf;
642
     if(i<0) i=t+i+1; if(i<1) i=1;
643
     if(j<0) j=t+j+1; if(j>t) j=t;
644
     for(; i<=j; i++) {
645
         if(started==0 || fnd_fn==datafile_fnd_record)
646
           pp=_blockof_one(buf,t,fnd_fn,i,bbuf);
647
         else
648
           pp=_blockof_one(pnext,1,fnd_fn,1,bbuf);
649
         l=strlen(pp); pnext=fnd_nextpos;
650
         if(l+(po-obuf)>=MAX_LINELEN-3) {
651
          too_long: user_error("cmd_output_too_long"); return;
652
         }
653
         if(started) {ovlstrcpy(po,append_char); po+=strlen(po);}
654
         memmove(po,pp,l); po+=l; *po=0; started++;
655
     }
10 reyssat 656
    }
657
    else {
7673 bpr 658
     char *p1,*p2,ibuf[MAX_LINELEN+1];
659
     int t=len_fn(buf);
660
     mystrncpy(ibuf,p,sizeof(ibuf)); substit(ibuf);
661
     for(p1=ibuf;*p1;p1=find_word_start(p2)) {
662
         p2=find_item_end(p1); if(*p2) *p2++=0;
663
         i=evalue(p1);
664
         if(i<0) i=t+i+1;
665
         if(i>t || i<0) continue;
666
         pp=_blockof_one(buf,t,fnd_fn,i,bbuf);l=strlen(pp);
667
         if(l+(po-obuf)>=MAX_LINELEN-3) goto too_long;
668
         if(started) {ovlstrcpy(po,append_char); po+=strlen(po);}
669
         memmove(po,pp,l); po+=l; *po=0; started++;
670
     }
10 reyssat 671
    }
672
    mystrncpy(p,obuf,MAX_LINELEN);
673
}
674
 
7673 bpr 675
/* pick lines */
10 reyssat 676
void calc_lineof(char *p)
677
{
678
    _blockof(p,linenum,fnd_line,"\n","line");
679
}
680
 
7673 bpr 681
/* pick rows */
10 reyssat 682
void calc_rowof(char *p)
683
{
7673 bpr 684
    char *cc, tbuf[MAX_LINELEN+1]; /* called by substit(); no right to use tmplbuf */
10 reyssat 685
    mystrncpy(tbuf,p,sizeof(tbuf)); substit(tbuf);
686
    if(strchr(tbuf,'\n')==NULL && strchr(tbuf,';')!=NULL) cc=";";
687
    else cc="\n";
688
    _blockof(p,rownum,fnd_row,cc,"row");
689
}
690
 
7673 bpr 691
/* pick items */
10 reyssat 692
void calc_itemof(char *p)
693
{
694
    _blockof(p,itemnum,fnd_item,", ","item");
695
}
696
 
7673 bpr 697
/* pick records in datafile */
10 reyssat 698
void calc_recordof(char *p)
699
{
700
    _blockof(p,datafile_recordnum,datafile_fnd_record,"\n:","record");
701
}
702
 
7673 bpr 703
/* pick words */
10 reyssat 704
void calc_wordof(char *p)
705
{
706
    _blockof(p,wordnum,fnd_word," ","word");
707
}
708
 
7673 bpr 709
/* pick characters */
10 reyssat 710
void calc_charof(char *p)
711
{
712
    _blockof(p,charnum,fnd_char,"","char");
713
}
714
 
715
char *append_obj[]={
9375 bpr 716
    "item","line","word","semicolon","colon"
10 reyssat 717
};
9375 bpr 718
char apch_list[]={',','\n',' ',':',';'};
10 reyssat 719
#define append_obj_no (sizeof(append_obj)/sizeof(append_obj[0]))
720
 
7673 bpr 721
/* append object to string */
10 reyssat 722
void calc_append(char *p)
723
{
724
    char append_char, *p1,*p2,*p3,*p4;
725
    int i,l1,l2;
726
    p1=find_word_start(p);p2=find_word_end(p1);
727
    if(*p2!=0) *p2++=0;
728
    for(i=0;i<append_obj_no && strcmp(p1,append_obj[i])!=0;i++);
729
    if(i>=append_obj_no) {
7673 bpr 730
     synterr:
731
     module_error("append_syntax");
732
     *p=0; return;
10 reyssat 733
    }
734
    append_char=apch_list[i];
735
    p3=wordchr(p2,"to");
736
    if(p3==NULL) goto synterr;
737
    for(p4=p3-1;p4>p2 && isspace(*(p4-1));p4--);
2652 reyssat 738
    if(p4<=p2) goto synterr;
10 reyssat 739
    *p4=0;p3=find_word_start(p3+strlen("to"));
3718 reyssat 740
    memmove(tmplbuf,p2,p4-p2); tmplbuf[p4-p2]=0; ovlstrcpy(p,p3);
10 reyssat 741
    substit(tmplbuf);substit(p);
742
    l1=strlen(p); l2=strlen(tmplbuf);
743
    if(l1+l2>=MAX_LINELEN-1) user_error("cmd_output_too_long");
744
    p3=find_word_start(p); p4=p+l1;
745
    if(*p3) *p4++=append_char;
746
    memmove(p4,tmplbuf,l2); p4[l2]=0;
747
}
748
 
7673 bpr 749
/* character translation */
10 reyssat 750
void calc_translate(char *p)
751
{
752
    int i, internal;
753
    char *q[3];
754
    char bf[3][MAX_LINELEN+1];
755
    char fn[3][MAX_FNAME+1], *arglist[8];
756
 
757
    q[0]=find_word_start(p); internal=0;
758
    if(strncasecmp(q[0],"internal",strlen("internal"))==0 &&
759
       isspace(*(q[0]+strlen("internal")))) {
7673 bpr 760
     q[0]=find_word_start(q[0]+strlen("internal"));
761
     internal=1;
10 reyssat 762
    }
763
    q[1]=wordchr(q[0],"to"); q[2]=wordchr(q[0],"in");
764
    if(q[1]==NULL || q[2]==NULL) {
7673 bpr 765
     module_error("tr_syntax"); *p=0; return;
10 reyssat 766
    }
767
    *q[1]=0; *q[2]=0;
768
    q[1]=find_word_start(q[1]+strlen("to"));
769
    q[2]=find_word_start(q[2]+strlen("in"));
770
    for(i=0;i<3;i++) {
7673 bpr 771
     strip_trailing_spaces(q[i]);
772
     mystrncpy(bf[i],q[i],sizeof(bf[i]));substit(bf[i]);
10 reyssat 773
    }
774
    if(bf[0][0]==0) goto bailout;
7404 bpr 775
    if(internal || strstr(tmp_dir,"sessions")==NULL || (strpbrk(bf[0],"\\[-")==NULL &&
7673 bpr 776
       strpbrk(bf[1],"\\[-")==NULL)) { /* direct internal translation */
777
     char *pp;
778
     if(strlen(bf[1])<strlen(bf[0])) bf[0][strlen(bf[1])]=0;
779
     for(pp=strpbrk(bf[2],bf[0]);pp!=NULL && *pp!=0 && pp<bf[2]+MAX_LINELEN;
780
         pp=strpbrk(pp+1,bf[0])) {
781
         for(i=0;bf[0][i]!=*pp && bf[0][i]!=0;i++);
782
         if(bf[0][i]!=0) *pp=bf[1][i];
783
     }
784
     bailout: mystrncpy(p,bf[2],MAX_LINELEN);
785
     return;
10 reyssat 786
    }
787
    mkfname(fn[0],"%s/tr.in",tmp_dir);
788
    mkfname(fn[1],"%s/tr.out",tmp_dir);
789
    accessfile(bf[2],"w",fn[0]);
790
    arglist[0]=tr_prog; arglist[1]=bf[0]; arglist[2]=bf[1];
791
    arglist[3]=NULL; exportall();
792
    execredirected(tr_prog,fn[0],fn[1],"/dev/null",arglist);
793
    read_tmp_file(p,"tr.out");
794
    strip_trailing_spaces(p);
795
}
796
 
7673 bpr 797
/* internal common routine for positionof */
10 reyssat 798
void _pos(char *hay, char *stitch, int style, char *out,
7673 bpr 799
       char *(fnd_obj)(char *p, int n, char bf[]),
800
       unsigned int (objnum)(char *p))
10 reyssat 801
{
802
    int i,n,t;
803
    char buf[MAX_LINELEN+1], nbuf[10];
7404 bpr 804
 
10 reyssat 805
    n=objnum(hay);
806
    for(i=1;i<=n;i++) {
7673 bpr 807
     fnd_obj(hay,i,buf);
808
     if(strcmp(buf,stitch)!=0) continue;
809
     t=strlen(out); if(t>MAX_LINELEN-12) return;
810
     if(t>0) strcat(out,",");
811
     snprintf(nbuf,sizeof(nbuf),"%d",i); strcat(out,nbuf);
10 reyssat 812
    }
813
}
814
 
7673 bpr 815
/* return positions of searched for objects */
10 reyssat 816
void calc_pos(char *p)
817
{
818
    char buf[2][MAX_LINELEN+1];
819
    char *p1, *p2;
820
    int  style;
7404 bpr 821
 
10 reyssat 822
    p1=find_word_start(p); p2=wordchr(p1,"in");
823
    if(p2==NULL) module_error("syntax_error");
824
    *p2=0;p2=find_word_start(p2+strlen("in"));
825
    strip_trailing_spaces(p1);
3718 reyssat 826
    ovlstrcpy(buf[0],p1);*find_word_end(buf[0])=0; style=0;
10 reyssat 827
    if(strcmp(buf[0],"word")==0) style=1;
828
    else {
7673 bpr 829
     if(strcmp(buf[0],"item")==0) style=2;
830
     else {
831
         if(strcmp(buf[0],"line")==0) style=3;
832
         else {
833
          if(strcmp(buf[0],"char")==0) style=4;
834
         }
835
     }
10 reyssat 836
    }
837
    if(style>0) p1=find_word_start(find_word_end(p1));
3718 reyssat 838
    ovlstrcpy(buf[0],p1); ovlstrcpy(buf[1],p2);
10 reyssat 839
    substit(buf[0]); substit(buf[1]); *p=0;
840
    switch(style) {
7673 bpr 841
     case 0: {  /* string */
842
         char *pp, nbuf[10];
843
         int i,t;
844
         for(pp=strstr(buf[1],buf[0]);pp!=NULL;pp=strstr(pp+1,buf[0])) {
845
          i=pp-buf[1]; t=strlen(p); if(t>MAX_LINELEN-12) return;
846
          if(t>0) strcat(p,",");
847
          snprintf(nbuf,sizeof(nbuf),"%d",i); strcat(p,nbuf);
848
         }
849
         return;
850
     }
851
     case 1: { /* word */
852
         _pos(buf[1],buf[0],style,p,fnd_word,wordnum);
853
         return;
854
     }
855
     case 2: { /* item */
856
         _pos(buf[1],buf[0],style,p,fnd_item,itemnum);
857
         return;
858
     }
859
     case 3: { /* line */
860
         _pos(buf[1],buf[0],style,p,fnd_line,linenum);
861
         return;
862
     }
863
     case 4: { /* char */
864
         _pos(buf[1],buf[0],style,p,fnd_char,charnum);
865
         return;
866
     }
10 reyssat 867
    }
868
}
869
 
7673 bpr 870
/* internal routine for calc_replace. */
10 reyssat 871
void _obj_replace(char *orig, char *by, char *in, int num,
7673 bpr 872
            char separator, char *result,
873
            char *(fnd_obj)(char *p, int n, char bf[]),
874
            unsigned int (objnum)(char *p),
875
            char *(objchr)(char *p,char *w))
10 reyssat 876
{
877
    int i;
878
    char *p1, *p2;
7404 bpr 879
 
3718 reyssat 880
    ovlstrcpy(result,in);
10 reyssat 881
    if(num!=0) {
7673 bpr 882
     num=objnum(in); i=evalue(orig);
883
     if(i==0) module_error("bad_index");
884
     if(i<0) i=num+i+1;
885
     if(i>num || i<1) return;
886
     if(separator==0) {  /* char */
887
         result[i-1]=by[0]; return;
888
     }
889
     fnd_obj(result,i,orig); p1=fnd_position;
890
     if(i<num) {
891
         fnd_obj(result,i+1,orig); p2=fnd_position;
892
     }
893
     else p2=result+strlen(result);
894
     if(p1==NULL || p2==NULL) internal_error("_obj_replace() error.");
895
     if(i<num) {
896
         i=strlen(by); by[i++]=separator;by[i]=0;
897
     }
898
     string_modify(result,p1,p2,"%s",by);
10 reyssat 899
    }
900
    else {
7673 bpr 901
     if(separator==0) {
902
         if(orig[0]==0 || by[0]==0) return;
903
         for(p1=strchr(result,orig[0]);p1!=NULL;p1=strchr(p1+1,orig[0]))
904
               *p1=by[0];
905
         return;
906
     }
907
     if(strlen(orig)+strlen(by)==0) return;
908
     for(p1=objchr(result,orig);p1!=NULL;p1=objchr(p1+strlen(by)+1,orig)) {
909
         string_modify(result,p1,p1+strlen(orig),"%s",by);
910
     }
10 reyssat 911
    }
912
}
913
 
7673 bpr 914
/* replacement */
10 reyssat 915
void calc_replace(char *p)
916
{
917
    int i,style,num,internal;
918
    char *q[3], *pp;
919
    char bf[4][MAX_LINELEN+17];
920
    char fn[3][MAX_FNAME+1], *arglist[8];
921
    char regexp_char='/';
922
 
923
    style=num=0;
924
    q[0]=find_word_start(p); internal=0;
925
    if(strncasecmp(q[0],"internal",strlen("internal"))==0 &&
926
       isspace(*(q[0]+strlen("internal")))) {
7673 bpr 927
     q[0]=find_word_start(q[0]+strlen("internal"));
928
     internal=1;
10 reyssat 929
    }
930
    q[1]=wordchr(q[0],"by"); q[2]=wordchr(q[0],"in");
931
    if(q[1]==NULL || q[2]==NULL) {
7673 bpr 932
     module_error("replace_syntax"); *p=0; return;
10 reyssat 933
    }
934
    *q[1]=0; *q[2]=0;
935
    q[1]=find_word_start(q[1]+strlen("by"));
936
    q[2]=find_word_start(q[2]+strlen("in"));
937
    mystrncpy(bf[0],q[0],sizeof(bf[0]));
938
    pp=find_word_end(bf[0]); if(*pp) *(pp++)=0;
939
    if(strcmp(bf[0],"word")==0) style=1;
940
    else {
7673 bpr 941
     if(strcmp(bf[0],"item")==0) style=2;
942
     else {
943
         if(strcmp(bf[0],"line")==0) style=3;
944
         else {
945
          if(strcmp(bf[0],"char")==0) style=4;
946
         }
947
     }
10 reyssat 948
    }
949
    if(style>0) {
7673 bpr 950
     q[0]=find_word_start(find_word_end(q[0]));
951
     mystrncpy(bf[0],q[0],sizeof(bf[0]));
952
     pp=find_word_end(bf[0]); if(*pp) *(pp++)=0;
953
     if(strcmp(bf[0],"number")==0) {
954
         num=1; q[0]=find_word_start(pp);
955
     }
10 reyssat 956
    }
957
    for(i=0;i<3;i++) {
7673 bpr 958
     strip_trailing_spaces(q[i]);
959
     mystrncpy(bf[i],q[i],sizeof(bf[i]));
960
     substit(bf[i]);
10 reyssat 961
    }
962
    if(bf[0][0]==0) {mystrncpy(p,bf[2],MAX_LINELEN); return;}
963
    switch(style) {
7673 bpr 964
     case 1: { /* word */
965
         _obj_replace(bf[0],bf[1],bf[2],num,' ',p,
966
                fnd_word,wordnum,wordchr);
967
         return;
968
     }
969
     case 2: { /* item */
970
         _obj_replace(bf[0],bf[1],bf[2],num,',',p,
971
                fnd_item,itemnum,itemchr);
972
         return;
973
     }
974
     case 3: { /* line */
975
         _obj_replace(bf[0],bf[1],bf[2],num,'\n',p,
976
                fnd_line,linenum,linechr);
977
         return;
978
     }
979
     case 4: { /* char */
980
         if(bf[1][0]==0) bf[1][0]=' ';
981
         if(bf[0][0]==0) return;
982
         _obj_replace(bf[0],bf[1],bf[2],num,0,p,
983
                fnd_char,charnum,charchr);
984
         return;
985
     }
986
     default: break;
10 reyssat 987
    }
988
    if(internal || strstr(tmp_dir,"sessions")==NULL || (strpbrk(bf[0],"\\[^.*$")==NULL &&
989
       strpbrk(bf[1],"\\[^.*$")==NULL)) {
7673 bpr 990
/* No regexp, direct replace */
991
     char *pp;
992
     for(pp=strstr(bf[2],bf[0]);pp<bf[2]+MAX_LINELEN && pp!=NULL;
993
         pp=strstr(pp+strlen(bf[1]),bf[0])) {
994
         string_modify(bf[2],pp,pp+strlen(bf[0]),"%s",bf[1]);
995
     }
996
     mystrncpy(p,bf[2],MAX_LINELEN);return;
10 reyssat 997
    }
998
    mkfname(fn[0],"%s/sed.in",tmp_dir);
999
    mkfname(fn[1],"%s/sed.out",tmp_dir);
1000
    accessfile(bf[2],"w",fn[0]);
1001
    snprintf(bf[3],sizeof(bf[3]),"s%c%s%c%s%cg",
7673 bpr 1002
          regexp_char,bf[0],regexp_char,bf[1],regexp_char);
10 reyssat 1003
    arglist[0]=sed_prog; arglist[1]=bf[3]; arglist[2]=NULL;
1004
    execredirected(sed_prog,fn[0],fn[1],"/dev/null",arglist);
1005
    read_tmp_file(p,"sed.out");
1006
    strip_trailing_spaces(p);
1007
}
1008
 
7673 bpr 1009
/* transforms a string to hexadecimal code, upper-case */
10 reyssat 1010
void calc_hex(char *p)
1011
{
1012
    unsigned char *p1, orig[MAX_LINELEN+1];
1013
    char *p2;
1014
    char *hex="0123456789ABCDEF";
7404 bpr 1015
 
3247 bpr 1016
    mystrncpy((char*)orig,p,MAX_LINELEN);
10 reyssat 1017
    for(p1=orig, p2=p; *p1 && p2-p<MAX_LINELEN-2; p1++) {
7673 bpr 1018
     *p2++=hex[(*p1>>4)&15]; *p2++=hex[*p1&15];
10 reyssat 1019
    }
7404 bpr 1020
    *p2=0;
10 reyssat 1021
}
1022
 
7673 bpr 1023
/* transforms to lower/upper cases */
10 reyssat 1024
void calc_tolower(char *p)
1025
{
1026
    char *pp;
1027
    for(pp=p;*pp;pp++) *pp=tolower(*pp);
1028
}
1029
 
1030
void calc_toupper(char *p)
1031
{
1032
    char *pp;
1033
    for(pp=p;*pp;pp++) *pp=toupper(*pp);
1034
}
1035
 
7673 bpr 1036
/* strip leading and trailing spaces */
10 reyssat 1037
void calc_trim(char *p)
1038
{
1039
    char *s;
1040
    s=find_word_start(p);
1041
    if(s>p) memmove(p,s,MAX_LINELEN-(s-p)+1);
1042
    strip_trailing_spaces(p);
1043
}
1044
 
7673 bpr 1045
/* output date. Uses Linux 'date' utility. */
10 reyssat 1046
void calc_date(char *p)
1047
{
1048
    char *p1, *p2, *p3;
1049
    if(!trusted_module() || is_class_module) {
7673 bpr 1050
     if(strstr(p,"..")!=NULL) return;
1051
     for(p1=find_word_start(p); *p1; p1=find_word_start(p2)) {
1052
         p2=find_word_end(p1);
1053
         while(*p1=='\'' || *p1=='"') p1++;
1054
         if(*p1!='-') continue;
1055
         for(p3=p1+1;p3<p2;p3++) if(strchr("rs",*p3)!=NULL) return;
1056
     }
10 reyssat 1057
    }
1058
    wrapexec=1;
1059
    call_ssh("date %s >%s/date.out 2>/dev/null",p,tmp_dir);
1060
    read_tmp_file(p,"date.out");
1061
}
1062
 
7673 bpr 1063
/* ls, or dir */
10 reyssat 1064
void calc_listfile(char *p)
1065
{
1066
    char *pp;
7404 bpr 1067
 
7673 bpr 1068
/* only for trusted modules */
10 reyssat 1069
    if(!trusted_module() || is_class_module) {
7673 bpr 1070
     module_error("not_trusted"); *p=0; return;
10 reyssat 1071
    }
7673 bpr 1072
/* security measures. */
10 reyssat 1073
    for(pp=p;*pp;pp++) if(isspace(*pp) || *pp==';') *pp=' ';
1074
    if(strstr(p,parent_dir_string)!=NULL) {
7673 bpr 1075
     setvar(error_data_string,p);
1076
     module_error("illegal_fname"); return;
10 reyssat 1077
    }
1078
    wrapexec=1;
1079
    call_sh("ls %s >%s/ls.out 2>%s/ls.err",
7673 bpr 1080
         p,tmp_dir,tmp_dir);
10 reyssat 1081
    read_tmp_file(p,"ls.out");
1082
}
1083
 
7673 bpr 1084
/* instex static: static tex inserts */
10 reyssat 1085
void calc_instexst(char *p)
1086
{
1087
    char nbuf[MAX_FNAME+1], bufc[MAX_LINELEN+1];
1088
    char buf2[1024], altbuf[1024], buf[MAX_LINELEN+1], urlbuf[MAX_LINELEN+1];
1089
    char *b, *at, *al, *md1, *md2;
1090
    int t, border, vspace;
1091
    struct stat st,stc;
1092
    char *p1, *p2, *p3, *ppp, *pt;
1093
 
1094
    if(robot_access) {*p=0; return;}
1095
    p1=find_word_start(p); p2=find_word_end(p1);
1096
    p3=p2-4; vspace=0;
1097
    fix_tex_size();
7404 bpr 1098
    t=untrust; untrust=0;
10 reyssat 1099
    if(find_module_file(m_file.name,bufc,0)) module_error(m_file.name);
1100
    else stat(bufc,&stc);
1101
    untrust=t;
1102
    if(*p3=='.' && (memcmp(p3+1,"gif",3)==0 || memcmp(p3+1,"png",3)==0)) {
7673 bpr 1103
     char mbuf[MAX_LINELEN+1];
1104
     if(*p2!=0) *p2++=0;
1105
     p2=find_word_start(p2);
1106
     ovlstrcpy(mbuf,p1); substit(mbuf);
1107
     if(strstr(mbuf,parent_dir_string)!=NULL) {
1108
         setvar(error_data_string,mbuf);
1109
         module_error("illegal_fname"); return;
1110
     }
1111
     mkfname(nbuf,"%s/%s",module_prefix,mbuf);
10 reyssat 1112
    }
1113
    else {
7673 bpr 1114
     ppp=getvar(ro_name[ro_module]);
1115
     if(ppp==NULL) internal_error("calc_instexst(): module name vanishes.");
1116
     p2=p1;
1117
     mkfname(nbuf,"w/instex/%d/%s/%s_%d.gif",
1118
           current_tex_size,ppp,m_file.name,m_file.l);
10 reyssat 1119
    }
1120
    snprintf(urlbuf,sizeof(urlbuf),"%s%s?%X",ref_base,nbuf,
7673 bpr 1121
          (unsigned short int) stc.st_mtime);
10 reyssat 1122
    mystrncpy(buf,nbuf,sizeof(buf));
1123
    if((ppp=strrchr(buf,'/'))!=NULL) {
7673 bpr 1124
     *ppp=0;mkdirs(buf);
10 reyssat 1125
    }
1126
    b=getvar("ins_border");
1127
    at=getvar("ins_attr");
1128
    al=getvar("ins_align");
1129
    if(at==NULL) at="";
1130
    if(al==NULL) al="";al=find_word_start(al);
6265 bpr 1131
    if(*al!=0) snprintf(buf2,sizeof(buf2),"vertical-align:%s",al); else buf2[0]=0;
10 reyssat 1132
    if(b==NULL || *b==0) border=0;
1133
    else border=atoi(b);
1134
    if(border<0) border=0; if(border>100) border=100;
1135
    if(instex_ready(p2,urlbuf)) goto prt;
1136
    if(stat(nbuf,&st)!=0 || st.st_mtime<stc.st_mtime || st.st_size<45) {
7673 bpr 1137
     setenv("texgif_style",instex_style,1);
1138
     setenv("texgif_src",p2,1);
1139
     setenv("texgif_outfile",nbuf,1);
1140
     setenv("texgif_tmpdir",tmp_dir,1); exportall();
1141
     wrapexec=0; call_ssh("%s &>%s/instexst.log",tex2gif,tmp_dir);
1142
     setenv("instexst_src","",1);
10 reyssat 1143
    }
1144
    prt: md1=md2="";
1145
    if(strcasecmp(al,"middle")==0) {
7673 bpr 1146
     md1=mathalign_sup1; md2=mathalign_sup2;
1147
     vspace=5;
10 reyssat 1148
    }
1149
    if(ins_alt[0]==0) mystrncpy(ins_alt,p2,sizeof(ins_alt));
1150
    if(strchr(ins_alt,'"')!=NULL || strlen(ins_alt)>256) ins_alt[0]=0;
1151
    pt=getvar("wims_ins_alt"); if(pt==NULL) pt="";
1152
    if(ins_alt[0] && strcmp(pt,"none")!=0)
1153
      snprintf(altbuf,sizeof(altbuf)," alt=\"%s\"",ins_alt);
3522 bpr 1154
    else  snprintf(altbuf,sizeof(altbuf)," alt=\"\"");
6265 bpr 1155
    snprintf(p,MAX_LINELEN,"%s<img src=\"%s\" style=\"border:solid;border-width:%dpx;margin-bottom:%dpx;%s\" %s %s />%s",
7673 bpr 1156
          md1,urlbuf,border,vspace,buf2,at,altbuf,md2);
10 reyssat 1157
    setvar("ins_attr",""); ins_alt[0]=0;
1158
    setvar("ins_url",urlbuf);
1159
}
1160
 
7673 bpr 1161
/* extract non-empty lines or items */
10 reyssat 1162
void calc_nonempty(char *p)
1163
{
1164
    int type, i, cnt;
1165
    char *p1, *p2, buf[MAX_LINELEN+1], out[MAX_LINELEN+1];
1166
    p1=find_word_start(p); p2=find_word_end(p1);
1167
    if(*p2) *p2++=0; else {
7673 bpr 1168
     *p=0; return;
10 reyssat 1169
    }
1170
    type=0;
1171
    if(strcasecmp(p1,"item")==0 || strcasecmp(p1,"items")==0) type=1;
1172
    if(type==0 && (strcasecmp(p1,"line")==0 || strcasecmp(p1,"lines")==0))
1173
      type=2;
1174
    if(type==0 && (strcasecmp(p1,"row")==0 || strcasecmp(p1,"rows")==0))
1175
      type=3;
1176
    if(type==0) module_error("syntax_error");
1177
    out[0]=out[1]=0;
1178
    switch(type) {
7673 bpr 1179
     case 1: { /* items */
1180
         cnt=itemnum(p2);
1181
         for(i=1; i<=cnt; i++) {
1182
          fnd_item(p2,i,buf);
1183
          if(*find_word_start(buf)) {
1184
              strcat(out,",");strcat(out,buf);
1185
          }
1186
         }
1187
         break;
1188
     }
1189
     case 2: { /* lines */
1190
         lines: cnt=linenum(p2);
1191
         for(i=1; i<=cnt; i++) {
1192
          fnd_line(p2,i,buf);
1193
          if(*find_word_start(buf)) {
1194
              strcat(out,"\n");strcat(out,buf);
1195
          }
1196
         }
1197
         break;
1198
     }
1199
     case 3: { /* rows */
1200
         int t=rows2lines(p2);
1201
         if(t==0) goto lines;
1202
         cnt=linenum(p2);
1203
         for(i=1; i<=cnt; i++) {
1204
          fnd_line(p2,i,buf);
1205
          if(*find_word_start(buf)) {
1206
              strcat(out,";");strcat(out,buf);
1207
          }
1208
         }
1209
         break;
1210
     }
1211
     default: break;
10 reyssat 1212
    }
3718 reyssat 1213
    ovlstrcpy(p,out+1);
10 reyssat 1214
}
1215
 
7673 bpr 1216
/* returns a list with unique items */
10 reyssat 1217
void calc_listuniq(char *p)
1218
{
1219
    int i,n;
1220
    char lout[MAX_LINELEN+2], *ll;
1221
    char *cut[MAX_LIST];
1222
    lout[0]=lout[1]=0;
1223
    n=cutitems(p,cut,MAX_LIST); for(i=0;i<n;i++) {
7673 bpr 1224
     ll=cut[i];
1225
     if(*ll && itemchr(lout,ll)==NULL &&
1226
        strlen(lout)+strlen(ll)<MAX_LINELEN-2) {
1227
         strcat(lout,",");strcat(lout,ll);
1228
     }
10 reyssat 1229
    }
3718 reyssat 1230
    ovlstrcpy(p,lout+1);
10 reyssat 1231
}
1232
 
7673 bpr 1233
/* returns intersection of 2 lists */
10 reyssat 1234
void calc_listintersect(char *p)
1235
{
1236
    char l1[MAX_LINELEN+1],l2[MAX_LINELEN+1],lout[MAX_LINELEN+2];
1237
    char *cut[MAX_LIST];
1238
    char *pp, *ll;
1239
    int i,n;
7404 bpr 1240
 
10 reyssat 1241
    pp=wordchr(p,"and");
1242
    if(pp==NULL) module_error("syntax_error");
3718 reyssat 1243
    *pp=0;ovlstrcpy(l1,p); ovlstrcpy(l2,pp+strlen("and"));
10 reyssat 1244
    lout[0]=lout[1]=0; substit(l1); substit(l2);
1245
    n=cutitems(l1,cut,MAX_LIST); if(n<=0) {*p=0; return;}
1246
    for(i=0;i<n;i++) {
7673 bpr 1247
     ll=cut[i];
1248
     if(ll[0] && itemchr(l2,ll)!=NULL && itemchr(lout,ll)==NULL &&
1249
        strlen(lout)+strlen(ll)<MAX_LINELEN-2) {
1250
         strcat(lout,",");strcat(lout,ll);
1251
     }
10 reyssat 1252
    }
3718 reyssat 1253
    ovlstrcpy(p,lout+1);
10 reyssat 1254
}
1255
 
7673 bpr 1256
/* returns union of 2 lists */
10 reyssat 1257
void calc_listunion(char *p)
1258
{
1259
    char l1[MAX_LINELEN+1],l2[MAX_LINELEN+1],lout[MAX_LINELEN+2];
1260
    char *cut[MAX_LIST];
1261
    char *pp, *ll;
1262
    int i,n;
7404 bpr 1263
 
10 reyssat 1264
    pp=wordchr(p,"and");
1265
    if(pp==NULL) module_error("syntax_error");
3718 reyssat 1266
    *pp=0;ovlstrcpy(l1,p); ovlstrcpy(l2,pp+strlen("and"));
10 reyssat 1267
    lout[0]=lout[1]=0; substit(l1); substit(l2);
1268
    n=cutitems(l1,cut,MAX_LIST); for(i=0;i<n;i++) {
7673 bpr 1269
     ll=cut[i];
1270
     if(ll[0] && itemchr(lout,ll)==NULL &&
1271
        strlen(lout)+strlen(ll)<MAX_LINELEN-2) {
1272
         strcat(lout,",");strcat(lout,ll);
1273
     }
10 reyssat 1274
    }
1275
    n=cutitems(l2,cut,MAX_LIST); for(i=0;i<n;i++) {
7673 bpr 1276
     ll=cut[i];
1277
     if(ll[0] && itemchr(lout,ll)==NULL &&
1278
        strlen(lout)+strlen(ll)<MAX_LINELEN-2) {
1279
         strcat(lout,",");strcat(lout,ll);
1280
     }
10 reyssat 1281
    }
3718 reyssat 1282
    ovlstrcpy(p,lout+1);
10 reyssat 1283
}
1284
 
7673 bpr 1285
/* returns items of list2 not in list1 */
10 reyssat 1286
void calc_listcomplement(char *p)
1287
{
1288
    char l1[MAX_LINELEN+1],l2[MAX_LINELEN+1],lout[MAX_LINELEN+2];
1289
    char *cut[MAX_LIST];
1290
    char *pp, *ll;
1291
    int i,n;
7404 bpr 1292
 
10 reyssat 1293
    pp=wordchr(p,"in");
1294
    if(pp==NULL) module_error("syntax_error");
3718 reyssat 1295
    *pp=0;ovlstrcpy(l1,p); ovlstrcpy(l2,pp+strlen("in"));
10 reyssat 1296
    lout[0]=lout[1]=0; substit(l1); substit(l2);
1297
    n=cutitems(l2,cut,MAX_LIST); if(n<=0) {*p=0; return;}
1298
    for(i=0;i<n;i++) {
7673 bpr 1299
     ll=cut[i];
1300
     if(ll[0] && itemchr(l1,ll)==NULL && itemchr(lout,ll)==NULL &&
1301
        strlen(lout)+strlen(ll)<MAX_LINELEN-2) {
1302
         strcat(lout,",");strcat(lout,ll);
1303
     }
10 reyssat 1304
    }
3718 reyssat 1305
    ovlstrcpy(p,lout+1);
10 reyssat 1306
}
1307
 
7673 bpr 1308
/* Consult a dictionary to translate a string */
10 reyssat 1309
/*
1310
void calc_dictionary(char *p)
1311
{
1312
    char *pp;
1313
    char name[MAX_LINELEN+1], str[MAX_LINELEN+1];
1314
    int t;
1315
    pp=wordchr(p,"for");
1316
    if(pp==NULL || pp<=p) module_error("syntax_error");
7404 bpr 1317
    *(find_word_end(pp-1))=0;
3718 reyssat 1318
    ovlstrcpy(name,p); substit(name);
10 reyssat 1319
    pp=find_word_start(pp+strlen("for")); t=0;
7404 bpr 1320
    if(memcmp(pp,"word",strlen("word"))==0 &&
1321
       (isspace(*(pp+strlen("word"))) ||
7673 bpr 1322
     (*(pp+strlen("word"))=='s' && isspace(*(pp+strlen("words")))))) {
1323
     pp=find_word_start(pp+strlen("words")); t=1;
10 reyssat 1324
    }
7404 bpr 1325
    if(memcmp(pp,"line",strlen("line"))==0 &&
1326
       (isspace(*(pp+strlen("line"))) ||
7673 bpr 1327
     (*(pp+strlen("line"))=='s' && isspace(*(pp+strlen("lines")))))) {
1328
     pp=find_word_start(pp+strlen("lines")); t=1;
10 reyssat 1329
    }
1330
    if(memcmp(pp,"list",strlen("list"))==0 && isspace(*(pp+strlen("list")))) {
7673 bpr 1331
     pp=find_word_start(pp+strlen("list"));
10 reyssat 1332
    }
1333
    if(memcmp(pp,"items",strlen("items"))==0 && isspace(*(pp+strlen("items")))) {
7673 bpr 1334
     pp=find_word_start(pp+strlen("items"));
10 reyssat 1335
    }
1336
    if(memcmp(pp,"item",strlen("item"))==0 && isspace(*(pp+strlen("item")))) {
7673 bpr 1337
     pp=find_word_start(pp+strlen("item"));
10 reyssat 1338
    }
3718 reyssat 1339
    ovlstrcpy(str,pp); substit(str);
10 reyssat 1340
    switch(t) {
7673 bpr 1341
     case 1: {
1342
         calc_words2items(str); break;
1343
     }
1344
     case 2: {
1345
         calc_lines2items(str); break;
1346
     }
1347
     default: break;
10 reyssat 1348
    }
1349
}
1350
*/
1351
 
1352
void calc_module(char *p)
1353
{
1354
    char *p1,*p2, ind_buf[MAX_LINELEN+1], buf[MAX_FNAME+1];
1355
    char *tp;
7404 bpr 1356
 
10 reyssat 1357
    p1=find_word_start(p); p2=find_word_end(p1);
1358
    if(*p2!=0) *p2++=0;
1359
    p2=find_word_start(p2); *find_word_end(p2)=0;
1360
    if(*p1==0) {empty: *p=0; return;}
1361
    if(*p2==0) {
7673 bpr 1362
     snprintf(buf,sizeof(buf),"module_%s",p1);
1363
     p1=getvar(buf); if(p1==NULL) p1="";
1364
     mystrncpy(p,p1,MAX_LINELEN); return;
10 reyssat 1365
    }
1366
    mkfname(buf,"%s/%s/INDEX",module_dir,p2);
1367
    tp=readfile(buf,ind_buf,MAX_LINELEN);
1368
    if(tp==NULL) {
7673 bpr 1369
     mkfname(buf,"%s/%s/index",module_dir,p2);
1370
     tp=readfile(buf,ind_buf,MAX_LINELEN);
10 reyssat 1371
    }
1372
    if(tp==NULL && p2[strlen(p2)-3]!='.') {
7673 bpr 1373
     mkfname(buf,"%s/%s.%s/INDEX",module_dir,p2,lang);
1374
     tp=readfile(buf,ind_buf,MAX_LINELEN); if(tp==NULL) {
1375
         mkfname(buf,"%s/%s.%s/index",module_dir,p2,lang);
1376
         tp=readfile(buf,ind_buf,MAX_LINELEN);
1377
     }
1378
     if(tp==NULL) {
1379
         int i;
1380
         for(i=0;i<available_lang_no;i++) {
1381
          mkfname(buf,"%s/%s.%s/INDEX",module_dir,p2,available_lang[i]);
1382
          tp=readfile(buf,ind_buf,MAX_LINELEN); if(tp) break;
1383
          mkfname(buf,"%s/%s.%s/index",module_dir,p2,
1384
                available_lang[i]);
1385
          tp=readfile(buf,ind_buf,MAX_LINELEN); if(tp) break;
1386
         }
1387
     }
10 reyssat 1388
    }
7673 bpr 1389
    if(tp==NULL) goto empty; /* module not found */
10 reyssat 1390
    _getdef(ind_buf,p1,p);
1391
}
1392
 
7673 bpr 1393
/* strip enclosing parentheses */
10 reyssat 1394
void calc_declosing(char *p)
1395
{
1396
    strip_enclosing_par(p);
1397
}
1398
 
7673 bpr 1399
/* remove html tag, very rudimentary. */
10 reyssat 1400
void calc_detag(char *p)
1401
{
1402
    char *p1, *p2;
1403
    for(p1=strchr(p,'<'); p1!=NULL; p1=strchr(p1,'<')) {
7673 bpr 1404
     p2=strchr(p1,'>'); if(p2==NULL) p1++;
1405
     else ovlstrcpy(p1,p2+1);
10 reyssat 1406
    }
1407
}
1408
 
8155 bpr 1409
/* prepare a string to be inserted into a form input or textarea as is */
10 reyssat 1410
void calc_reinput(char *p)
1411
{
1412
    char *p1;
1413
    for(p1=strchr(p,'&'); p1!=NULL; p1=strchr(p1,'&')) {
7673 bpr 1414
     p1++; string_modify(p,p1,p1,"amp;");
10 reyssat 1415
    }
1416
    for(p1=strchr(p,'<'); p1!=NULL; p1=strchr(++p1,'<'))
1417
      string_modify(p,p1,p1+1,"&lt;");
1418
}
1419
 
7673 bpr 1420
/* get a definition from a file. Trusted modules only. */
10 reyssat 1421
void calc_defof(char *p)
1422
{
1423
    char *p1;
1424
    char fbuf[MAX_FNAME+1], nbuf[MAX_LINELEN+1], tbuf[MAX_LINELEN+1];
7404 bpr 1425
 
10 reyssat 1426
    secure_exec();
1427
    p1=wordchr(p,"in"); if(p1==NULL) module_error("syntax_error");
1428
    *p1=0; p1=find_word_start(p1+strlen("in"));
1429
    mystrncpy(nbuf,p,sizeof(nbuf));  mystrncpy(tbuf,p1,sizeof(tbuf));
1430
    substit(nbuf); substit(tbuf);
1431
    p1=find_word_start(tbuf); *find_word_end(p1)=0;
1432
    if(find_module_file(p1,fbuf,0)) {*p=0; return;}
1433
    p1=find_word_start(nbuf); strip_trailing_spaces(p1);
1434
    getdef(fbuf,p1,p);
1435
}
1436
 
7673 bpr 1437
/* check host */
10 reyssat 1438
void calc_checkhost(char *p)
1439
{
1440
    int t;
3718 reyssat 1441
    if(robot_access || !trusted_module()) ovlstrcpy(p,"0");
10 reyssat 1442
    else {
7673 bpr 1443
     t=checkhost(p); mystrncpy(p,int2str(t),MAX_LINELEN);
10 reyssat 1444
    }
1445
}
1446
 
1447
#define MAX_COLUMNS 256
1448
 
7673 bpr 1449
/* A rudimentary database facility */
10 reyssat 1450
void calc_select(char *p)
1451
{
1452
    char *p1, *p2, *p3, *bufp, c, sep;
1453
    char buf1[MAX_LINELEN+1], buf2[MAX_LINELEN+1];
1454
    char buf[MAX_LINELEN+1];
1455
    int i,j,lmax;
1456
    p2=wordchr(p,"where"); if(p2==NULL) module_error("syntax_error");
1457
    *p2=0; p2+=strlen("where");
1458
    p2=find_word_start(p2); strip_trailing_spaces(p2);
1459
    p1=find_word_start(p) ; strip_trailing_spaces(p1);
1460
    if(*p1==0 || *p2==0) module_error("syntax_error");
3718 reyssat 1461
    ovlstrcpy(buf1,p1); ovlstrcpy(buf2,p2); sep='\n';
7673 bpr 1462
/* buf1: data; buf2: condition. */
7404 bpr 1463
    substit(buf1);
7673 bpr 1464
    if(strstr(buf2,"column")!=NULL) { /* matrix */
1465
     lmax=0; if(rows2lines(buf1)) sep=';';
1466
     for(p1=strstr(buf2,"column"); p1; p1=strstr(p1+1,"column")) {
1467
         if(p1>buf2 && isalnum(*(p1-1))) continue;
1468
         p2=find_word_start(p1+strlen("column"));
1469
         for(p3=p2; myisdigit(*p3); p3++);
1470
         if(p3==p2) continue;
1471
         c=*p3; *p3=0; i=atoi(p2); *p3=c;
1472
         if(i<=0 || i>MAX_COLUMNS) continue;
1473
         if(i>lmax) lmax=i;
1474
         string_modify(buf2,p1,p3,"$(wims_select_col_%d)",i);
1475
     }
1476
     buf[0]=0; bufp=buf;
1477
     for(p1=buf1; *p1; p1=p2) {
1478
         char ibuf[MAX_LINELEN+1], nbuf[MAX_NAMELEN+1];
1479
         p2=strchr(p1,'\n');
1480
         if(p2==NULL) p2=p1+strlen(p1); else *p2++=0;
1481
         if(*find_word_start(p1)==0) continue;
1482
         for(j=1;j<=lmax;j++) {
1483
          snprintf(nbuf,sizeof(nbuf),"wims_select_col_%d",j);
1484
          fnd_item(p1,j,ibuf); force_setvar(nbuf,ibuf);
1485
         }
1486
         ovlstrcpy(ibuf,buf2); if(compare(ibuf,0,0)) {
1487
          snprintf(bufp,MAX_LINELEN-(bufp-buf),"%s%c",p1,sep);
1488
          bufp+=strlen(bufp);
1489
         }
1490
     }
10 reyssat 1491
    }
7673 bpr 1492
    else { /* datafile */
1493
     module_error("syntax_error");
7404 bpr 1494
 
10 reyssat 1495
    }
1496
    if(buf[0]!=0) buf[strlen(buf)-1]=0;
1497
    mystrncpy(p,buf,MAX_LINELEN);
1498
}
1499
 
7673 bpr 1500
/* Extract a column from a matrix */
10 reyssat 1501
void calc_columnof(char *p)
1502
{
1503
    char *p1, *p2, *bufp, sep;
1504
    char buf1[MAX_LINELEN+1], buf2[MAX_LINELEN+1];
1505
    char buf[MAX_LINELEN+1];
1506
    p2=wordchr(p,"of"); if(p2==NULL) module_error("syntax_error");
1507
    *p2=0; p2+=strlen("of");
1508
    p2=find_word_start(p2); strip_trailing_spaces(p2);
1509
    p1=find_word_start(p) ; strip_trailing_spaces(p1);
1510
    if(*p1==0) module_error("syntax_error");
1511
    if(*p2==0) {*p=0; return;}
3718 reyssat 1512
    ovlstrcpy(buf1,p1); ovlstrcpy(buf2,p2); sep='\n';
7673 bpr 1513
/* buf1: number(s); buf2: matrix. */
7404 bpr 1514
    substit(buf1); substit(buf2);
10 reyssat 1515
    if(rows2lines(buf2)) sep=';';
1516
    if(strchr(buf1,',')==NULL && wordchr(buf1,"to")==NULL
1517
       && strstr(buf1,"..")==NULL) sep=',';
1518
    buf[0]=0; bufp=buf;
1519
    for(p1=buf2; *p1; p1=p2) {
7673 bpr 1520
     char ibuf[MAX_LINELEN+1];
1521
     p2=strchr(p1,'\n');
1522
     if(p2==NULL) p2=p1+strlen(p1); else *p2++=0;
1523
     snprintf(ibuf,sizeof(ibuf),"%s of %s",buf1,p1);
1524
     calc_itemof(ibuf);
1525
     snprintf(bufp,MAX_LINELEN-(bufp-buf),"%s%c",ibuf,sep);
1526
     bufp+=strlen(bufp);
10 reyssat 1527
    }
1528
    if(buf[0]!=0) buf[strlen(buf)-1]=0;
1529
    mystrncpy(p,buf,MAX_LINELEN);
1530
}
1531
 
7673 bpr 1532
/* find roots of a function or equation in a given zone */
10 reyssat 1533
void calc_solve(char *p)
1534
{
1535
    char *pp, *fp, *forp;
1536
    char buf[MAX_LINELEN+1], vbuf[MAX_LINELEN+1];
8176 bpr 1537
    double v, dd, start, stop, step, old, v1, v2, v3, d1, d3;
10 reyssat 1538
    int i, pos;
7404 bpr 1539
 
10 reyssat 1540
    forp=wordchr(p,"for");
1541
    if(forp==NULL) { syntax: module_error("syntax_error"); *p=0; return; }
1542
    *forp=0; forp+=strlen("for");
1543
    fp=find_word_start(p); strip_trailing_spaces(fp);
1544
    if(*fp==0) goto syntax;
1545
    i=cutfor(forp,NULL); if(i<0 || forstruct.type==for_in) goto syntax;
1546
    if(i>0) {*p=0; return;}
1547
    start=forstruct.from; stop=forstruct.to; forp=forstruct.var;
1548
    mystrncpy(buf,fp,sizeof(buf)); substitute(buf);
1549
    *p=0; pp=strchr(buf,'='); if(pp!=NULL) {
7673 bpr 1550
     if(strlen(buf)>=MAX_LINELEN-16) return;
1551
     strcat(buf,")");
1552
     string_modify(buf,pp,pp+1,"-(");
10 reyssat 1553
    }
1554
    i=0; for(fp=varchr(buf,forp); fp!=NULL; fp=varchr(fp,forp)) {
7673 bpr 1555
     string_modify(buf,fp,fp+strlen(forp),EV_X); fp+=strlen(EV_X); i++;
10 reyssat 1556
    }
1557
    if(i==0 || start==stop) return;
1558
    evalue_compile(buf); pos=eval_getpos(EV_X);
1559
    if(start>stop) {dd=start; start=stop; stop=dd;}
1560
    step=(stop-start)/100; if(step==0) return;
1561
    pp=p; old=0;
1562
    for(v=start; v<=stop; v+=step, old=dd) {
7673 bpr 1563
     eval_setval(pos,v);
7847 bpr 1564
     dd=checked_eval(buf);
7673 bpr 1565
     if(v==start) continue;
8171 bpr 1566
     if(!isfinite(old) || !isfinite(dd) || (old>0 && dd>0) || (old<0 && dd<0))
7673 bpr 1567
       continue;
1568
     if(dd==0 && v<stop) continue;
8176 bpr 1569
     v1=v-step; v2=v; d1=old;
7673 bpr 1570
     for(i=0;i<30;i++) {
1571
         v3=(v1+v2)/2; eval_setval(pos,v3);
7847 bpr 1572
         d3=checked_eval(buf);
8171 bpr 1573
         if(!isfinite(d3)) goto next;
7673 bpr 1574
         if((d1>0 && d3>0) || (d1<0 && d3<0)) {d1=d3; v1=v3;}
8176 bpr 1575
         else {v2=v3;}
7673 bpr 1576
     }
1577
     float2str(v3,vbuf); if(pp-p+strlen(vbuf)<MAX_LINELEN-1) {
1578
         if(pp>p) *pp++=','; ovlstrcpy(pp,vbuf);
1579
         pp+=strlen(pp);
1580
     }
1581
     else break;
1582
     next: ;
10 reyssat 1583
    }
1584
}
1585
 
7673 bpr 1586
/* type: 1=values, 2=sum, 3=product, 4=recursion, 5=subst */
10 reyssat 1587
void _values(char *p, int type)
1588
{
1589
    char *pp, *fp, *forp;
1590
    char vbuf[MAX_LINELEN+1], buf[MAX_LINELEN+1], fbuf[MAX_LINELEN+1], tbuf[MAX_LINELEN+1];
1591
    char *f[64];
1592
    double v, dd, start, stop, step, v0;
1593
    int i, k, fcnt, pos, posr;
7404 bpr 1594
 
10 reyssat 1595
    forp=wordchr(p,"for");
1596
    if(forp==NULL) { syntax: module_error("syntax_error"); *p=0; return; }
1597
    *forp=0; forp+=strlen("for"); forp=find_word_start(forp);
1598
    fp=find_word_start(p); strip_trailing_spaces(fp);
1599
    if(*fp==0) goto syntax;
1600
    if(type<5) i=cutfor(forp,NULL); else i=cutfor(forp,tbuf);
1601
    if(i<0) goto syntax; if(i>0) {*p=0; return;}
1602
    start=forstruct.from; stop=forstruct.to; step=forstruct.step;
1603
    forp=forstruct.var;
1604
    mystrncpy(buf,fp,sizeof(buf)); substitute(buf);
1605
    for(fp=varchr(buf,forp); fp!=NULL; fp=varchr(fp,forp)) {
7673 bpr 1606
     string_modify(buf,fp,fp+strlen(forp),EV_X); fp+=strlen(EV_X);
10 reyssat 1607
    }
1608
    for(fp=varchr(buf,"last"); fp!=NULL; fp=varchr(fp,"last")) {
7673 bpr 1609
     string_modify(buf,fp,fp+strlen("last"),EV_S); fp+=strlen(EV_S);
10 reyssat 1610
    }
1611
    fcnt=pos=posr=0;
1612
    if(type==5) goto skip;
1613
    fcnt=itemnum(buf); if(fcnt>64) fcnt=64; pp=fbuf;
1614
    for(k=0; k<fcnt; k++) {
7673 bpr 1615
     fnd_item(buf,k+1,vbuf); evalue_compile(vbuf);
1616
     if(pp-fbuf+strlen(vbuf)<MAX_LINELEN-1) {
1617
         f[k]=pp; ovlstrcpy(pp,vbuf); pp+=strlen(pp)+1;
1618
     }
1619
     else f[k]="";
10 reyssat 1620
    }
1621
    pos=eval_getpos(EV_X); posr=eval_getpos(EV_S);
1622
    skip:
1623
    if(step==0) step=1;/* if(step<0) step=-step;
1624
    if(stop<start) {dd=start; start=stop; stop=dd;} */
1625
    *p=0; v0=0;
1626
    switch(type) {
7673 bpr 1627
     case 4:
1628
     case 1: {
1629
         pp=getvar("recursion_start");
1630
         if(pp==NULL || *pp==0) v0=0;
1631
         else {
8176 bpr 1632
          v0=evalue(pp); if(!isfinite(v0)) return;
7673 bpr 1633
         }
1634
         break;
1635
     }
1636
     case 2: v0=0; break;
1637
     case 3: v0=1; break;
1638
     case 5: break;
10 reyssat 1639
    }
1640
    pp=p;
1641
    if(type==5) {
7673 bpr 1642
     char *ps, *pt, buf2[MAX_LINELEN+1];
1643
     int l,ln;
1644
     *p=0; l=strlen(buf); if(l>=MAX_LINELEN) return;
1645
     for(i=0,v=start; i<MAX_VALUE_LIST && v*step<=stop*step; v+=step, i++) {
1646
         if(forstruct.type==for_from) {
1647
          float2str(v,vbuf); ps=vbuf;
1648
         }
1649
         else ps=forstruct.pos[i];
1650
         ovlstrcpy(buf2,buf); l=strlen(ps);ln=strlen(EV_X);
1651
         for(pt=varchr(buf2,EV_X);pt!=NULL;pt=varchr(pt+l,EV_X))
1652
           string_modify(buf2,pt,pt+ln,"%s",ps);
1653
         if(pp-p+strlen(buf2)>=MAX_LINELEN-1) return;
1654
         if(pp>p) *pp++=','; ovlstrcpy(pp,buf2);
1655
         pp+=strlen(pp);
1656
     }
1657
     return;
10 reyssat 1658
    }
1659
    for(i=0,v=start; i<MAX_VALUE_LIST && v*step<=stop*step; v+=step, i++) {
7673 bpr 1660
     if(forstruct.type==for_from) eval_setval(pos,v);
1661
     else eval_setval(pos,forstruct.list[i]);
1662
     eval_setval(posr,v0);
1663
     for(k=0; k<fcnt; k++) {
7847 bpr 1664
         dd=checked_eval(f[k]);
7673 bpr 1665
         switch(type) {
1666
          case 1: { /* values */
1667
              float2str(dd,vbuf);
1668
              if(pp-p+strlen(vbuf)<MAX_LINELEN-1) {
1669
               if(pp>p) *pp++=','; ovlstrcpy(pp,vbuf);
1670
               pp+=strlen(pp);
1671
              }
1672
              v0=dd; break;
1673
          }
1674
          case 2: { /* sum */
1675
              v0=v0+dd; break;
1676
          }
1677
          case 3: { /* product */
1678
              v0=v0*dd; break;
1679
          }
1680
          case 4: { /* recursion */
1681
              v0=dd; break;
1682
          }
1683
         }
1684
     }
10 reyssat 1685
    }
1686
    if(type!=1) float2str(v0,p);
1687
}
1688
 
7673 bpr 1689
/* cut a function into values */
10 reyssat 1690
void calc_values(char *p)
1691
{ _values(p,1); }
1692
 
7673 bpr 1693
/* compute sum */
10 reyssat 1694
void calc_sum(char *p)
1695
{ _values(p,2); }
1696
 
7673 bpr 1697
/* compute product */
10 reyssat 1698
void calc_product(char *p)
1699
{ _values(p,3); }
1700
 
7673 bpr 1701
/* simple recursion */
10 reyssat 1702
void calc_recursion(char *p)
1703
{ _values(p,4); }
1704
 
7673 bpr 1705
/* List substitution */
10 reyssat 1706
void calc_makelist(char *p)
1707
{ _values(p,5); }
1708
 
7673 bpr 1709
/* level curve data */
10 reyssat 1710
void calc_leveldata(char *p)
1711
{
1712
    leveldata ld;
1713
    char *sizep, *rangep, *fp, *levelp, *stepp;
1714
    char *pp,*p2,fbuf[MAX_LINELEN+1],buf[MAX_LINELEN+1];
1715
    double d[4];
1716
    int i;
7404 bpr 1717
 
10 reyssat 1718
    sizep=wordchr(p,"size");
1719
    rangep=wordchr(p,"ranges");
1720
    fp=wordchr(p,"function");
1721
    levelp=wordchr(p,"levels");
1722
    stepp=wordchr(p,"step");
1723
    if(sizep==NULL || rangep==NULL || fp==NULL) {
7673 bpr 1724
     syntax: module_error("syntax_error"); *p=0; return;
10 reyssat 1725
    }
1726
    *sizep=0; sizep+=strlen("size");
1727
    *rangep=0; rangep+=strlen("ranges");
1728
    *fp=0; fp+=strlen("function");
1729
    if(levelp!=NULL) {*levelp=0; levelp+=strlen("levels");}
1730
    else levelp="0";
1731
    if(stepp!=NULL) {*stepp=0; stepp+=strlen("step");}
1732
    else stepp="0";
1733
    mystrncpy(fbuf,fp,sizeof(fbuf)); substitute(fbuf);
1734
    ld.fn=fbuf;
1735
    ld.xname="x"; ld.yname="y"; ld.grain=evalue(stepp);
1736
    mystrncpy(buf,sizep,sizeof(buf)); substitute(buf);
1737
    for(i=0,pp=buf;i<2;i++,pp=p2) {
7673 bpr 1738
     if(*pp==0) goto syntax;
1739
     p2=find_item_end(pp); if(*p2) *p2++=0;
1740
     d[i]=evalue(pp);
10 reyssat 1741
    }
1742
    ld.xsize=d[0]; ld.ysize=d[1];
1743
    mystrncpy(buf,rangep,sizeof(buf)); substitute(buf);
1744
    for(i=0,pp=buf;i<4;i++,pp=p2) {
7673 bpr 1745
     if(*pp==0) goto syntax;
1746
     p2=find_item_end(pp); if(*p2) *p2++=0;
1747
     d[i]=evalue(pp);
10 reyssat 1748
    }
1749
    ld.xrange[0]=d[0]; ld.xrange[1]=d[1]; ld.yrange[0]=d[3]; ld.yrange[1]=d[2];
1750
    mystrncpy(buf,levelp,sizeof(buf)); substitute(buf);
1751
    ld.levelcnt=itemnum(buf); if(ld.levelcnt>LEVEL_LIM) ld.levelcnt=LEVEL_LIM;
1752
    for(i=0,pp=buf;i<ld.levelcnt;i++,pp=p2) {
7673 bpr 1753
     if(*pp==0) goto syntax;
1754
     p2=find_item_end(pp); if(*p2) *p2++=0;
1755
     ld.levels[i]=evalue(pp);
10 reyssat 1756
    }
1757
    levelcurve(&ld);
1758
    for(i=0, pp=p; i<ld.datacnt && pp<p+MAX_LINELEN-16; i++) {
7673 bpr 1759
     float2str(ld.xdata[i],buf);
1760
     if(pp-p+strlen(buf)<MAX_LINELEN-1) {
1761
         if(pp>p) *pp++=';'; ovlstrcpy(pp,buf); pp+=strlen(pp);
1762
     }
1763
     float2str(ld.ydata[i],buf);
1764
     if(pp-p+strlen(buf)<MAX_LINELEN-1) {
1765
         if(pp>p) *pp++=','; ovlstrcpy(pp,buf); pp+=strlen(pp);
1766
     }
10 reyssat 1767
    }
1768
}
1769
 
7673 bpr 1770
/* internal routine with no security check */
10 reyssat 1771
void _lookup(char *p, char *fname)
1772
{
1773
    char buf1[MAX_LINELEN+1];
1774
    char *p1, *p2, *mbuf;
1775
 
1776
    mbuf=readfile(fname,NULL,WORKFILE_LIMIT);
1777
    if(mbuf==NULL) {abort: *p=0; return;}
1778
    p1=find_word_start(p); strip_trailing_spaces(p1);
1779
    snprintf(buf1,sizeof(buf1),"%s:",p1); substit(buf1);
1780
    for(p1=strstr(mbuf,buf1);
7673 bpr 1781
     p1!=NULL && p1>mbuf && *(p1-1)!='\n';
1782
     p1=strstr(p1+1,buf1));
10 reyssat 1783
    if(p1==NULL) {free(mbuf); goto abort;}
1784
    p1+=strlen(buf1);
1785
    for(p2=strchr(p1,'\n'); p2!=NULL; p2=strchr(p2+1,'\n')) {
7673 bpr 1786
     if(p2>p1 && *(p2-1)=='\\') {*(p2-1)=' '; continue;}
1787
     else break;
10 reyssat 1788
    }
1789
    if(p2==NULL) p2=p1+strlen(p1); else *p2=0;
1790
    mystrncpy(p,p1,MAX_LINELEN); free(mbuf);
1791
}
1792
 
7673 bpr 1793
/* lookup a definition in a definition file */
10 reyssat 1794
void calc_lookup(char *p)
1795
{
1796
    char buf2[MAX_LINELEN+1], buf3[MAX_FNAME+1];
1797
    char *p2;
7404 bpr 1798
 
10 reyssat 1799
    p2=wordchr(p,"in"); if(p2==NULL) {abort: *p=0; return;}
1800
    *p2=0;p2=find_word_start(p2+2);
1801
    mystrncpy(buf2,p2,sizeof(buf2)); substit(buf2);
1802
    *find_word_end(buf2)=0;
1803
    if(strstr(buf2,parent_dir_string)!=NULL) {
7673 bpr 1804
     force_setvar("wims_error_data",buf2); module_error("illegal_cmd");
10 reyssat 1805
    }
1806
    if(strncmp(buf2,"bases/",strlen("bases/"))!=0) {
7673 bpr 1807
     if(datafile_check(buf2)!=0 || find_module_file(buf2,buf3,0)!=0)
1808
       goto abort;
1809
     _lookup(p,buf3);
10 reyssat 1810
    }
7404 bpr 1811
    else _lookup(p,buf2);
10 reyssat 1812
}
1813
 
7673 bpr 1814
/* Hide name of a file. Only in module directory or in gifs/ */
10 reyssat 1815
void calc_rename(char *p)
1816
{
1817
    char buf1[MAX_LINELEN+1], buf2[MAX_LINELEN+1];
1818
    char *p1, *ext, *s;
6790 bpr 1819
    int t;
7404 bpr 1820
 
10 reyssat 1821
    if(robot_access || strstr(p,"getfile")!=NULL) return;
1822
    p1=find_word_start(p); *find_word_end(p1)=0;
1823
    if(strncmp(p1,ref_name,strlen(ref_name))==0) p1+=strlen(ref_name);
3718 reyssat 1824
    if(p1>p) ovlstrcpy(p,p1);
10 reyssat 1825
    if(strstr(p,parent_dir_string)!=NULL ||
1826
       strncmp(p,"modules/adm/",strlen("modules/adm/"))==0) {
7673 bpr 1827
     badfile: force_setvar("wims_error_data",p); module_error("illegal_cmd");
10 reyssat 1828
    }
1829
    if(strncmp(p,module_dir,strlen(module_dir))!=0 &&
1830
       strncmp(p,"modules/data/",strlen("modules/data/"))!=0 &&
382 bpr 1831
       strncmp(p,"scripts/data/",strlen("scripts/data/"))!=0 &&
10 reyssat 1832
       strncmp(p,"gifs",strlen("gifs"))!=0) goto badfile;
1833
    mkfname(buf1,"%s/getfile",session_prefix); mkdirs(buf1);
1834
    mkfname(buf1,"%s/.rename",session_prefix);
1835
    mystrncpy(buf2,p,sizeof(buf2)); _lookup(buf2,buf1);
7673 bpr 1836
    if(buf2[0]!=0) { /* already */
1837
     mystrncpy(p,buf2,MAX_LINELEN); return;
10 reyssat 1838
    }
1839
    if(cwdbuf[0]==0) return;
1840
    p1=p+strlen(p)-1;
1841
    while(p1>p && isalnum(*p1)) p1--;
1842
    if(p1>p && *p1=='.') ext=p1; else ext="";
1843
    rerand: t=random();
1844
    mkfname(buf1,"%s/%s",cwdbuf,p);
1845
    mkfname(buf2,"%s/getfile/rename-%u%s",session_prefix,t,ext);
1846
    if(ftest(buf2)>=0) goto rerand;
6790 bpr 1847
    (void) symlink(buf1,buf2);
10 reyssat 1848
    s=getvar("wims_session"); if(s==NULL) return;
1849
    if(good_httpd) snprintf(buf1,sizeof(buf1),
7673 bpr 1850
                   "getfile/rename-%u%s?session=%s", t,ext,s);
1082 bpr 1851
    else snprintf(buf1,sizeof(buf1),"%s?cmd=getfile&+session=%s&+special_parm=rename-%u%s",
7673 bpr 1852
            ref_name, s, t,ext);
10 reyssat 1853
    snprintf(buf2,sizeof(buf2),"%s:%s\n",p,buf1);
1854
    accessfile(buf2,"a","%s/.rename",session_prefix);
1855
    mystrncpy(p,buf1,MAX_LINELEN);
1856
}
1857
 
7673 bpr 1858
/* Pick up and translate imgrename(...) within a string */
10 reyssat 1859
void calc_imgrename(char *p)
1860
{
1861
    char buf[MAX_LINELEN+1], buf2[MAX_LINELEN+1];
1862
    char *p1, *p2, *p3, *p4;
7404 bpr 1863
 
10 reyssat 1864
    for(p1=varchr(p,"imgrename"); p1!=NULL; p1=varchr(p1,"imgrename")) {
7673 bpr 1865
     p2=find_word_start(p1+strlen("imgrename"));
1866
     if(*p2!='(') {p1=p2; continue;}
1867
     p2++; p3=find_matching(p2,')');
1868
     if(*p3!=')') {p1=p2-1; continue;}
1869
     p2=find_word_start(p2); p4=find_word_end(p2);
1870
     memmove(buf,p2,p4-p2); buf[p4-p2]=0;
1871
     calc_rename(buf); *p3=0;
1872
     snprintf(buf2,sizeof(buf2),"<img src=\"%s\"%s alt=\"\" />",buf, p4);
1873
     *p3=')'; p3++;
1874
     string_modify(p,p1,p3,"%s",buf2);
1875
     p1+=strlen(buf2);
10 reyssat 1876
    }
7404 bpr 1877
 
10 reyssat 1878
}
1879
 
7673 bpr 1880
/* internal use only */
10 reyssat 1881
void calc_unhttp(char *p)
1882
{
1883
    _http2env(tmplbuf,p); mystrncpy(p,tmplbuf,MAX_LINELEN);
1884
}
1885
 
1886
/*
1887
char *saltchar="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./";
1888
*/
1889
 
1890
void calc_passcheck(char *p)
1891
{
7404 bpr 1892
 
10 reyssat 1893
}
1894
 
1895
void calc_passcrypt(char *p)
1896
{
1897
#ifdef HAVE_CRYPT
1898
    char saltstr[4];
1899
    char *p1, *p2, *pp, *s, buf[MAX_LINELEN+1];
1900
    saltstr[0]='N'; saltstr[1]='v'; saltstr[2]=0; buf[0]=0; pp=buf;
1901
    for(p1=find_word_start(p);*p1;p1=find_word_start(p2)) {
7673 bpr 1902
     p2=find_word_end(p1); if(*p2) *p2++=0;
1903
     pp=pp+strlen(pp);
1904
     if(pp>buf) s=" "; else s="";
1905
     if(*p1=='*')
1906
       snprintf(pp,MAX_LINELEN-(pp-buf),"%s%s",s,p1);
1907
     else
1908
       snprintf(pp,MAX_LINELEN-(pp-buf),"%s*%s",s,crypt(p1,saltstr));
10 reyssat 1909
    }
3718 reyssat 1910
    ovlstrcpy(p,buf);
10 reyssat 1911
#endif
1912
}
1913
 
1914
void exec_readproc(char *p);
1915
 
7673 bpr 1916
/* crypted mail interface */
10 reyssat 1917
void calc_mailurl(char *p)
1918
{
1919
    char *p0, buf[MAX_LINELEN+1];
7404 bpr 1920
 
10 reyssat 1921
    if(robot_access) {*p=0; return;}
1922
    snprintf(buf,sizeof(buf),"mailurl.proc %s",p);
1923
    exec_readproc(buf);
1924
    p0=getvar("mailurl_"); if(p0==NULL) p0="";
1925
    mystrncpy(p,p0,MAX_LINELEN);
1926
}
1927
 
7673 bpr 1928
/* get option word in a string */
10 reyssat 1929
void calc_getopt(char *p)
1930
{
1931
    char *p1, *p2, *p3, *p4;
1932
    char buf1[MAX_LINELEN+1], buf2[MAX_LINELEN+1];
7404 bpr 1933
 
10 reyssat 1934
    p1=wordchr(p,"in"); if(p1==NULL) module_error("syntax error");
1935
    *p1=0; p1=find_word_start(p1+3);
1936
    mystrncpy(buf1,p,MAX_LINELEN); mystrncpy(buf2,p1,MAX_LINELEN);
1937
    substitute(buf1); substitute(buf2);
1938
    p1=find_word_start(buf1); *find_word_end(p1)=0;
1939
    for(p2=buf2;*p2;p2++) {
7673 bpr 1940
     if(myisspace(*p2)) *p2=' ';
1941
     if(*p2=='=') *p2=' ';
10 reyssat 1942
    }
1943
    *p=0;
1944
    p2=wordchr(buf2,p1); if(p2==NULL) return;
1945
    for(p3=find_word_end(p2);myisspace(*p3);p3++) {
7673 bpr 1946
     if(*p3=='  ') {
1947
         p3=find_word_start(p3);
1948
         switch(*p3) {
1949
          case '"': {
1950
              p4=strchr(p3+1,'"');
1951
              goto tested;
1952
          }
1953
          case '(': {
1954
              p4=find_matching(p3+1,')');
1955
              goto tested;
1956
          }
1957
          case '[': {
1958
              p4=find_matching(p3+1,']');
1959
              goto tested;
1960
          }
1961
          case '{': {
1962
              p4=find_matching(p3+1,'}');
1963
              tested:
1964
              if(p4) {
1965
               p3++; *p4=0; break;
1966
              }
1967
              else goto nomatch;
1968
          }
1969
          default: {
1970
              nomatch:
1971
              *find_word_end(p3)=0;
1972
          }
1973
         }
1974
         mystrncpy(p,p3,MAX_LINELEN);
1975
         return;
1976
     }
10 reyssat 1977
    }
1978
    *find_word_end(p2)=0;
1979
    mystrncpy(p,p2,MAX_LINELEN);
1980
}
1981
 
7673 bpr 1982
/* internal */
10 reyssat 1983
void _embraced(char buf[], void (app)(char *p))
1984
{
1985
    char *p1, *p2, buf2[MAX_LINELEN+1];
1986
    for(p1=strchr(buf,'{'); p1; p1=strchr(p1,'{')) {
7673 bpr 1987
     p2=find_matching(p1+1,'}');
1988
     if(p2==NULL) module_error("unmatched_parentheses");
1989
     *p2=0; mystrncpy(buf2,p1+1,sizeof(buf2)); app(buf2);
1990
     string_modify(buf,p1,p2+1,buf2);
10 reyssat 1991
    }
1992
}
1993
 
7673 bpr 1994
/* embraced operations */
10 reyssat 1995
void calc_embraced(char *p)
1996
{
1997
    char *p1, *p2, buf[MAX_LINELEN+1];
1998
 
1999
    p1=find_word_start(p); p2=find_word_end(p1);
2000
    if(*p2==0) {*p=0; return;}
2001
    *p2++=0; p2=find_word_start(p2);
2002
    mystrncpy(buf,p2,sizeof(buf)); substit(buf);
3718 reyssat 2003
    if(p1>p) ovlstrcpy(p,p1); substit(p);
10 reyssat 2004
    if(strcmp(p,"randitem")==0) {_embraced(buf,calc_randitem); goto end;}
2005
    if(strcmp(p,"extract")==0) {
7673 bpr 2006
     p1=strchr(buf,'{'); if(p1!=NULL) {
2007
         p2=find_matching(++p1,'}');
2008
         if(p2!=NULL) {
2009
          memmove(buf,p1,p2-p1); buf[p2-p1]=0;
2010
         }
2011
         else buf[0]=0;
2012
     }
2013
     else buf[0]=0;
2014
     goto end;
10 reyssat 2015
    }
2016
    if(strcmp(p,"delete")==0) {
7673 bpr 2017
     for(p1=strchr(buf,'{'); p1; p1=strchr(p1,'{')) {
2018
         p2=find_matching(p1+1,'}');
2019
         if(p2) ovlstrcpy(p1,p2+1); else p1++;
2020
     }
2021
     goto end;
10 reyssat 2022
    }
2023
    module_error("syntax_error");
7404 bpr 2024
 
10 reyssat 2025
    end:
2026
    mystrncpy(p,buf,MAX_LINELEN);
2027
}
2028
 
2029
void calc_rows2lines(char *p)
7673 bpr 2030
{     rows2lines(p); }
10 reyssat 2031
 
2032
void calc_lines2rows(char *p)
7673 bpr 2033
{     lines2rows(p);     }
10 reyssat 2034
 
7673 bpr 2035
/* check whether datamodules exist */
10 reyssat 2036
void calc_checkdata(char *p)
2037
{
2038
    char *p1, *p2, buf[MAX_LINELEN+1], nbuf[MAX_FNAME+1];
2039
    struct stat st;
7404 bpr 2040
 
10 reyssat 2041
    memmove(p,"yes",4);
2042
    p1=getvar("module_data");
2043
    if(p1==NULL || *p1==0) return;
2044
    snprintf(buf,sizeof(buf),"%s",p1);
2045
    for(p2=buf; *p2; p2++) if(*p2==',' || *p2==';') *p2=' ';
2046
    if(strstr(buf,"..")!=NULL) {
7673 bpr 2047
     snprintf(p,MAX_LINELEN,"badly_defined_data_module");
2048
     return;
10 reyssat 2049
    }
2050
    for(p1=find_word_start(buf); *p1; p1=find_word_start(p2)) {
7673 bpr 2051
     p2=find_word_end(p1); if(*p2) *p2++=0;
2052
     snprintf(nbuf,sizeof(nbuf),"%s/%s/INDEX",module_dir,p1);
2053
     if(stat(nbuf,&st)<0) {
2054
         snprintf(nbuf,sizeof(nbuf),"%s/%s/index",module_dir,p1);
2055
         if(stat(nbuf,&st)<0) {
2056
          snprintf(p,MAX_LINELEN,"%s",p1);
2057
          return;
2058
         }
2059
     }
10 reyssat 2060
    }
2061
}
2062
 
7673 bpr 2063
/* tag!=0 if we don't want automatic substit(). */
10 reyssat 2064
MYFUNCTION calc_routine[]={
7673 bpr 2065
      {"TeXmath", 0, texmath},
2066
      {"add",  1, calc_sum},
2067
      {"append", 1, calc_append},
2068
      {"call",   0, calc_exec},
2069
      {"char",  1, calc_charof},
2070
      {"charcnt", 0,      calc_lengthof},
2071
      {"charcount", 0,      calc_lengthof},
2072
      {"charno", 0,      calc_lengthof},
2073
      {"charnum", 0,      calc_lengthof},
2074
      {"chars",  1, calc_charof},
2075
      {"checkdata", 0, calc_checkdata},
2076
      {"checkdatamodule",0, calc_checkdata},
2077
      {"checkhost", 0, calc_checkhost},
2078
      {"column", 1, calc_columnof},
2079
      {"columns", 1, calc_columnof},
2080
      {"daemon", 0, calc_daemon},
2081
      {"date",  0, calc_date},
2082
      {"deaccent", 0, deaccent},
2083
      {"debug",  0, calc_debug},
2084
      {"declosing", 0, calc_declosing},
2085
      {"definitionof", 1, calc_defof},
2086
      {"defof",  1, calc_defof},
2087
      {"detag",  0, calc_detag},
2088
/*      {"dictionary", 1, calc_dictionary}, */
2089
      {"dir",  0, calc_listfile},
2090
      {"embraced", 1, calc_embraced},
2091
      {"encyclo", 0, pedia},
2092
      {"encyclopedia", 0, pedia},
2093
      {"eval",  0, calc_evalue},
2094
      {"evalsubst", 1, calc_evalsubst},
2095
      {"evalsubstit", 1, calc_evalsubst},
2096
      {"evalsubstitute",1, calc_evalsubst},
2097
      {"evalue", 0, calc_evalue},
2098
      {"evaluesubst", 1, calc_evalsubst},
2099
      {"evaluesubstit", 1, calc_evalsubst},
2100
      {"evaluesubstitute",1, calc_evalsubst},
2101
      {"examdep", 0, calc_examdep},
2102
      {"examscore", 0, calc_examscore},
2103
      {"exec",   0, calc_exec},
2104
      {"execute", 0, calc_exec},
2105
      {"filelist", 0, calc_listfile},
2106
      {"getdef", 1, calc_defof},
2107
      {"getopt", 1, calc_getopt},
2108
      {"getscore", 0, calc_getscore},
2109
      {"getscorebest", 0, calc_getscorebest},
2110
      {"getscorelast", 0, calc_getscorelast},
2111
      {"getscorelevel", 0, calc_getscorelevel},
2112
      {"getscoremean",0, calc_getscoremean},
2113
      {"getscorepercent",0, calc_getscorepercent},
2114
      {"getscorequality",0, calc_getscoremean},
2115
      {"getscoreremain",0, calc_getscoreremain},
2116
      {"getscorerequire",0, calc_getscorerequire},
2117
      {"getscorestatus",0, calc_getscorestatus},
2118
      {"getscoretry", 0, calc_getscoretry},
2119
      {"getscoreweight",0, calc_getscoreweight},
2120
      {"hex",  0, calc_hex},
2121
      {"htmlmath", 0, htmlmath},
2122
      {"httpquery", 0, tohttpquery},
2123
      {"imgrename", 0, calc_imgrename},
2124
      {"instexst", 1, calc_instexst},
2125
      {"instexstatic", 1, calc_instexst},
2126
      {"item",  1, calc_itemof},
2127
      {"itemcnt", 0,      calc_itemnum},
2128
      {"itemcount", 0,      calc_itemnum},
2129
      {"itemno", 0,      calc_itemnum},
2130
      {"itemnum", 0,      calc_itemnum},
2131
      {"items",  1, calc_itemof},
2132
      {"items2lines", 0,      items2lines},
2133
      {"items2words", 0,      items2words},
2134
      {"itemstolines", 0,      items2lines},
2135
      {"itemstowords", 0,      items2words},
2136
      {"lengthof", 0,      calc_lengthof},
2137
      {"leveldata", 1, calc_leveldata},
2138
      {"levelpoints", 1, calc_leveldata},
2139
      {"line",  1, calc_lineof},
2140
      {"linecnt", 0,      calc_linenum},
2141
      {"linecount", 0,      calc_linenum},
2142
      {"lineno", 0,      calc_linenum},
2143
      {"linenum", 0,      calc_linenum},
2144
      {"lines",  1, calc_lineof},
2145
      {"lines2items", 0,      lines2items},
2146
      {"lines2list", 0,      lines2items},
2147
      {"lines2rows", 0,      calc_lines2rows},
2148
      {"lines2words", 0,      lines2words},
2149
      {"linestoitems", 0,      lines2items},
2150
      {"linestolist", 0,      lines2items},
2151
      {"linestowords", 0,      lines2words},
2152
      {"list2lines", 0,      items2lines},
2153
      {"list2words", 0,      items2words},
2154
      {"listcomplement",1, calc_listcomplement},
2155
      {"listfile", 0, calc_listfile},
2156
      {"listfiles", 0, calc_listfile},
2157
      {"listintersect", 1, calc_listintersect},
2158
      {"listintersection",1, calc_listintersect},
2159
      {"listtolines", 0,      items2lines},
2160
      {"listtowords", 0,      items2words},
2161
      {"listunion", 1, calc_listunion},
2162
      {"listuniq", 0, calc_listuniq},
2163
      {"listunique", 0, calc_listuniq},
2164
      {"listvar", 0, mathvarlist},
2165
      {"lookup", 1, calc_lookup},
2166
      {"lower",  0, calc_tolower},
2167
      {"lowercase", 0, calc_tolower},
2168
      {"ls",  0, calc_listfile},
2169
      {"mailurl", 0, calc_mailurl},
2170
      {"makelist", 1, calc_makelist},
2171
      {"math2html", 0, htmlmath},
2172
      {"math2mathml", 0,mathmlmath},
2173
      {"math2tex", 0, texmath},
2174
      {"mathmlmath", 0, mathmlmath},
2175
      {"mathsubst", 1, calc_mathsubst},
2176
      {"mathsubstit", 1, calc_mathsubst},
2177
      {"mathsubstitute",1, calc_mathsubst},
2178
      {"mexec",  0, calc_mexec},
2179
      {"module", 0, calc_module},
2180
      {"multiply", 1, calc_product},
2181
      {"non_empty", 0, calc_nonempty},
2182
      {"nonempty", 0, calc_nonempty},
2183
      {"nospace", 0, nospace},
2184
      {"nosubst", 1, calc_subst},
2185
      {"nosubstit", 1, calc_subst},
2186
      {"nosubstitute", 1, calc_subst},
2187
      {"passcheck", 0, calc_passcheck},
2188
      {"passcrypt", 0, calc_passcrypt},
2189
      {"pedia",  0, pedia},
2190
      {"perl",  0, calc_perl},
2191
      {"position", 1, calc_pos},
2192
      {"positionof", 1, calc_pos},
2193
      {"positions", 1, calc_pos},
2194
      {"prod",  1, calc_product},
2195
      {"product", 1, calc_product},
2196
      {"randchar", 0, calc_randchar},
2197
      {"randdouble", 0, calc_randdouble},
2198
      {"randfile", 0, calc_randfile},
2199
      {"randfloat", 0, calc_randdouble},
2200
      {"randint",  0, calc_randint},
2201
      {"randitem", 0, calc_randitem},
2202
      {"randline", 0, calc_randline},
2203
      {"random", 0, calc_randdouble},
2204
      {"randperm", 0, calc_randperm},
2205
      {"randpermute", 0, calc_randperm},
2206
      {"randreal", 0, calc_randdouble},
2207
      {"randrecord", 0, calc_randfile},
2208
      {"randrow", 0, calc_randrow},
2209
      {"randword", 0, calc_randword},
2210
      {"rawmath", 0, rawmath},
2211
      {"rawmatrix", 0, rawmatrix},
2212
      {"reaccent", 0, reaccent},
2213
      {"record", 1, calc_recordof},
2214
      {"recordcnt", 0, calc_recordnum},
2215
      {"recordcount", 0, calc_recordnum},
2216
      {"recordno", 0, calc_recordnum},
2217
      {"recordnum", 0, calc_recordnum},
2218
      {"records", 1, calc_recordof},
2219
      {"recursion", 1, calc_recursion},
2220
      {"reinput", 0, calc_reinput},
2221
      {"rename", 0, calc_rename},
2222
      {"replace", 1, calc_replace},
2223
      {"rootof", 1, calc_solve},
2224
      {"row",  1, calc_rowof},
2225
      {"rowcnt", 0,      calc_rownum},
2226
      {"rowcount", 0,      calc_rownum},
2227
      {"rowno",  0,      calc_rownum},
2228
      {"rownum", 0,      calc_rownum},
2229
      {"rows",  1, calc_rowof},
2230
      {"rows2lines", 0, calc_rows2lines},
2231
      {"run",   0, calc_exec},
2232
      {"select", 1, calc_select},
2233
      {"sh",  0, calc_sh},
2234
      {"shuffle", 0, calc_randperm},
2235
      {"singlespace", 0, singlespace},
2236
      {"slashsubst", 0, slashsubst},
2237
      {"solve",  1, calc_solve},
2238
      {"sort",  1, calc_sort},
2239
/*      {"sql",  0, calc_sql}, */
2240
      {"staticinstex", 1, calc_instexst},
2241
      {"stinstex", 1, calc_instexst},
2242
      {"subst",  0, calc_subst},
2243
      {"substit", 0, calc_subst},
2244
      {"substitute", 0, calc_subst},
2245
      {"sum",  1, calc_sum},
2246
      {"system", 0, calc_sh},
2247
      {"texmath", 0, texmath},
2248
      {"text",  1, text},
2249
      {"tohex",  0, calc_hex},
2250
      {"tolower", 0, calc_tolower},
2251
      {"toupper", 0, calc_toupper},
2252
      {"translate", 1, calc_translate},
2253
      {"trim",  0, calc_trim},
2254
      {"unhttp", 0, calc_unhttp},
2255
      {"upper",  0, calc_toupper},
2256
      {"uppercase", 0, calc_toupper},
2257
      {"values", 1, calc_values},
2258
      {"varlist", 0, mathvarlist},
2259
      {"word",  1,      calc_wordof},
2260
      {"wordcnt", 0,      calc_wordnum},
2261
      {"wordcount", 0,      calc_wordnum},
2262
      {"wordno", 0,      calc_wordnum},
2263
      {"wordnum", 0,      calc_wordnum},
2264
      {"words",  1,      calc_wordof},
2265
      {"words2items", 0,      words2items},
2266
      {"words2lines", 0,      words2lines},
2267
      {"words2list", 0,      words2items},
2268
      {"wordstoitems", 0,      words2items},
2269
      {"wordstolines", 0,      words2lines},
2270
      {"wordstolist", 0,      words2items}
10 reyssat 2271
};
8185 bpr 2272
int CALC_FN_NO=(sizeof(calc_routine)/sizeof(calc_routine[0]));
10 reyssat 2273