Subversion Repositories wimsdev

Rev

Rev 8171 | Rev 8214 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  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.  
  18. /* this is part of wims server source.
  19.  * This file does execution commands.
  20.  */
  21. #include "wims.h"
  22.  
  23. static void _skip_contents(int isif);
  24.  
  25.     /* common routine for the two if's. */
  26. static void _exec_if_while(char *p, int numerical, int isif)
  27. {
  28.     if(compare(p,numerical,0)==0) _skip_contents(isif); /* skip if false */
  29.     else if(!isif) m_file.for_idx++;
  30.     return;
  31. }
  32.  
  33.     /* 'if' non-numerical (unless comparisons are < or >, etc.) */
  34. void exec_if(char *p)
  35. {
  36.     _exec_if_while(p,0,1);
  37. }
  38.  
  39.     /* 'if' numerical. */
  40. void exec_ifval(char *p)
  41. {
  42.     _exec_if_while(p,1,1);
  43. }
  44.  
  45. void _exec_while(char *p, int numerical)
  46. {
  47.     FOR_STACK *stk;
  48.     if(m_file.for_idx>=MAX_FOR_LEVEL) module_error("too_many_fors");
  49.     stk=&(m_file.for_stack[m_file.for_idx]);
  50.     stk->lineno=m_file.l;
  51.     memmove(stk->varname,"?",2);
  52.     _exec_if_while(p,numerical,0);
  53. }
  54.  
  55.     /* 'while' non-numerical (unless comparisons are < or >, etc.) */
  56. void exec_while(char *p)
  57. {
  58.     _exec_while(p,0);
  59. }
  60.  
  61.     /* 'while' numerical. */
  62. void exec_whileval(char *p)
  63. {
  64.     _exec_while(p,1);
  65. }
  66.  
  67. void exec_endwhile(char *p)
  68. {
  69.     FOR_STACK *stk;
  70.     if(m_file.for_idx<=0) module_error("next_without_for");
  71.     stk=&(m_file.for_stack[m_file.for_idx-1]);
  72.     if(stk->varname[0]!='?') module_error("next_without_for");
  73.     m_file.for_idx--; *p=0;
  74.     m_file.linepointer=stk->lineno;
  75.     executed_gotos++;
  76.     if(executed_gotos>=GOTO_LIMIT) module_error("too_many_gotos");
  77. }
  78.  
  79.     /* Should provide a method to stop infinite loop. */
  80. void exec_goto(char *p)
  81. {
  82.     char lbuf[MAX_NAMELEN+17];
  83.     char *label_start, *line_start;
  84.     int old_line;
  85.     int i;
  86.     executed_gotos++;
  87.     if(executed_gotos>=GOTO_LIMIT) module_error("too_many_gotos");
  88.     old_line=m_file.l;
  89.     label_start=find_word_start(p);
  90.     *find_word_end(label_start)=0;
  91.     m_file.l=m_file.linepointer=0;
  92.     for(i=0;i<m_file.linecnt;i++) {
  93.       if(((m_file.lines[i].isstart)&4)==0) continue;
  94.       line_start=find_word_start((m_file.lines[i]).address);
  95.       if(line_start>(m_file.lines[i+1]).address && i<m_file.linecnt)
  96.         continue;
  97.       m_file.linepointer=i;
  98.       wgetline(lbuf,MAX_NAMELEN+8,&m_file);
  99.       line_start=find_word_start(lbuf);
  100.       if(*line_start!=label_prefix_char) continue;
  101.       line_start++;*find_word_end(line_start)=0;
  102.       if(line_start[0]!='*' && strcmp(line_start,label_start)!=0) continue;
  103.       *p=0; i++; return;
  104.     }
  105.     m_file.l=old_line;
  106.     setvar(error_data_string,label_start); module_error("label_not_found");
  107. /*    m_file.linepointer=m_file.linecnt; *p=0;
  108.     return;
  109. */}
  110.  
  111.     /* 'else' with or without 'if'.
  112.      * Philosophy: we implement a loosely checked grammar.
  113.      * We cannot check 'if' grammar if we want to use 'goto'
  114.      * together with 'if'. */
  115. void exec_else(char *p)
  116. {
  117.     _skip_contents(1); return;
  118. }
  119.  
  120.     /* 'endif': nothing needs to be done here. */
  121. void exec_endif(char *p)
  122. {
  123.     return;
  124. }
  125.  
  126.     /* find out the end of a for loop */
  127. void goto_for_end(void)
  128. {
  129.     int inner;
  130.     char buf[16];
  131.     inner=0;
  132.     while(m_file.linepointer<m_file.linecnt) {
  133.       if((m_file.lines[m_file.linepointer].isstart&2)==0) {
  134.         m_file.linepointer++; continue;
  135.       }
  136.       if(wgetline(buf,8,&m_file)==EOF) break;
  137.       *find_word_end(buf)=0;
  138.       if(strcmp(buf,"!for")==0) {
  139.         inner++; continue;
  140.       }
  141.       if(strcmp(buf,"!next")==0) {
  142.         if(inner>0) {
  143.           inner--; continue;
  144.         }
  145.         else break;
  146.       }
  147.     }
  148. }
  149.  
  150.     /* for */
  151. void exec_for(char *p)
  152. {
  153.     char *p1, *p2, *p3;
  154.     double v1, v2, step;
  155.     char buf[MAX_LINELEN+1];
  156.     FOR_STACK *stk;
  157.  
  158.     if(m_file.for_idx>=MAX_FOR_LEVEL) module_error("too_many_fors");
  159.     stk=&(m_file.for_stack[m_file.for_idx]);
  160.     stk->lineno=m_file.l;
  161.     p1=find_word_start(p);
  162.     for(p2=p1; !isspace(*p2) && *p2!=0 && *p2!='=' ; p2++);
  163.     if(*p2==0) syntax: module_error("for_syntax");
  164.     if(p2-p1>MAX_NAMELEN) module_error("name_too_long");
  165.     memmove(stk->varname,p1,p2-p1);
  166.     stk->varname[p2-p1]=0;
  167.     p1=find_word_start(p2); if(*p1==0) goto syntax;
  168.     if(*p1=='=') {
  169.       p1++;
  170.      assign:
  171.      stk->from=0;
  172.      p2=wordchr(p1,"to");
  173.      if(p2==NULL) p2=strstr(p1,"..");
  174.      if(p2==NULL) goto syntax;
  175.      *p2=0; p2+=2;
  176.      p3=wordchr(p2,"step");
  177.      if(p3!=NULL) {
  178.         *p3=0; p3+=strlen("step");
  179.         step=evalue(p3);
  180.         if(step==0) module_error("zero_step");
  181.      }
  182.      else step=1;
  183.      v1=evalue(p1); v2=evalue(p2);
  184.      float2str(v1,buf); setvar(stk->varname, buf);
  185.      if((step>0 && v1>v2) || (step<0 && v1<v2) ) {  /* condition not met */
  186.   loop_out:
  187.         goto_for_end();
  188.       }
  189.      else {
  190.         stk->varval=v1; stk->varend=v2; stk->step=step;
  191.         stk->lineno=m_file.linepointer;
  192.         m_file.for_idx++;
  193.      }
  194.      *p=0; return;
  195.     }
  196.     if(memcmp(p1,"from",strlen("from"))==0 && isspace(*(p1+strlen("from")))) {
  197.       p1+=strlen("from"); goto assign;
  198.     }
  199.     if(memcmp(p1,"in",strlen("in"))==0 && isspace(*(p1+strlen("in")))) {
  200.       stk->from=1; p1+=strlen("in");
  201.       p1=find_word_start(p1); if(*p1==0) goto loop_out;
  202.       p2=xmalloc(MAX_LINELEN+1);
  203.       mystrncpy(p2,p1,MAX_LINELEN);
  204.       substit(p2);
  205.       strip_trailing_spaces(p2);
  206.       if(*p2==0) goto loop_out;
  207.       p1=strparchr(p2,','); stk->bufpt=p2;
  208.       if(p1!=NULL) {
  209.         *p1=0; stk->list_pt=find_word_start(p1+1);
  210.       }
  211.       else stk->list_pt=NULL;
  212.       strip_trailing_spaces(p2); setvar(stk->varname,p2);
  213.       stk->lineno=m_file.linepointer;
  214.       m_file.for_idx++; *p=0; return;
  215.     }
  216.     goto syntax;
  217. }
  218.  
  219.     /* break a for loop */
  220. void exec_break(char *p)
  221. {
  222.     FOR_STACK *stk;
  223.     if(m_file.for_idx>0) {
  224.       stk=&(m_file.for_stack[m_file.for_idx-1]);
  225.       if(stk->varname[0]=='?') _skip_contents(0);
  226.       else goto_for_end();
  227.       m_file.for_idx--;
  228.     }
  229.     *p=0; return;
  230. }
  231.  
  232.     /* next */
  233. void exec_next(char *p)
  234. {
  235.     double v1, v2, step;
  236.     char *p1, *p2;
  237.     char buf[MAX_LINELEN+1];
  238.     FOR_STACK *stk;
  239.     if(m_file.for_idx<=0) module_error("next_without_for");
  240.     stk=&(m_file.for_stack[m_file.for_idx-1]);
  241.     if(stk->varname[0]=='?') module_error("next_without_for");
  242.     if(stk->from) { /* list style */
  243.       if(stk->list_pt==NULL) {
  244.         free(stk->bufpt);
  245.         m_file.for_idx--;
  246.         *p=0; return;
  247.       }
  248.       p1=strchr(stk->list_pt,',');
  249.       if(p1!=NULL) {
  250.         *p1=0; p2=find_word_start(p1+1);
  251.       }
  252.       else p2=NULL;
  253.       strip_trailing_spaces(stk->list_pt);
  254.       setvar(stk->varname,stk->list_pt);
  255.       stk->list_pt=p2; goto loop_back;
  256.     }
  257.     v1=stk->varval; v2=stk->varend; step=stk->step;
  258.     v1+=step; stk->varval=v1;
  259.     float2str(v1,buf);
  260.     setvar(stk->varname, buf);
  261.     if((step>0 && v1<=v2) || (step<0 && v1>=v2)) { /* loop */
  262.   loop_back:
  263.       m_file.linepointer=stk->lineno;
  264.       executed_gotos++;
  265.       if(executed_gotos>=GOTO_LIMIT) module_error("too_many_gotos");
  266.     }
  267.     else m_file.for_idx--;
  268.     *p=0; return;
  269. }
  270.  
  271.     /* Execution of a file in the module directory,
  272.      * only for trusted modules. */
  273. void exec_mexec(char *p)
  274. {
  275.     direct_exec=1;
  276.     calc_mexec(p);
  277.     direct_exec=0;
  278. }
  279.  
  280.     /* call shell. */
  281. void _exec_ex(char *p, char *arg0, char *arg1, int n)
  282. {
  283.     char *abuf[8];
  284.     char errorfname[MAX_FNAME+1];
  285.  
  286.     if(robot_access) {
  287.       *p=0; return;
  288.     }
  289.     if(!noout || !trusted_module() || is_class_module) {
  290.       _calc_exec(p,arg0,arg1,n); if(outputing) output0(p);
  291.       return;
  292.     }
  293.     mkfname(errorfname,"%s/exec.err",tmp_dir);
  294.     abuf[0]=arg0; abuf[1]=arg1; abuf[n]=p; abuf[n+1]=NULL;
  295.     wrapexec=1; exportall();
  296.     execredirected(abuf[0],NULL,NULL,errorfname,abuf);
  297. }
  298.  
  299.     /* call shell. */
  300. void exec_sh(char *p)
  301. {
  302.     _exec_ex(p,"sh","-c",2);
  303. }
  304.  
  305.     /* call perl. */
  306. void exec_perl(char *p)
  307. {
  308.     _exec_ex(p,"perl","-e",2);
  309. }
  310.  
  311.     /* file should not be cached */
  312. void exec_nocache(char *p)
  313. {    m_file.nocache|=1; *p=0; }
  314.  
  315.     /* Read another file. */
  316. void exec_read(char *p)
  317. {
  318.     WORKING_FILE save;
  319.     char parmsave[MAX_LINELEN+1];
  320.     char *pp,*ps;
  321.     int t,cache;
  322.  
  323.     strip_trailing_spaces(p);p=find_word_start(p);
  324.     if(*p==0) return;
  325.     pp=find_word_end(p); if(*pp) *pp++=0;
  326.     pp=find_word_start(pp);
  327.     ps=getvar("wims_read_parm"); if(ps==NULL) ps="";
  328.     mystrncpy(parmsave,ps,sizeof(parmsave));
  329.     setvar("wims_read_parm",pp);
  330.     memmove(&save,&m_file,sizeof(WORKING_FILE));
  331.     cache=1; if(p[0]=='.' && p[1]=='/') {p+=2; cache=0;}
  332.     t=untrust;
  333.     if(strncmp(p,"wimshome/",9)==0) {
  334.       if((untrust&255)!=0 &&
  335.         (m_file.name[0]=='/' || strncmp(m_file.name,"wimshome/",9)==0))
  336.         module_error("Illegal_file_access");
  337.         untrust|=0x200;
  338.     }
  339.     if((untrust&0x202)!=0) {
  340.       pp=getvar("wims_trustfile");
  341.       if(pp!=NULL && *pp!=0 && wordchr(pp,p)!=NULL)
  342.         untrust&=0xfdfd;
  343.     }
  344.     readnest++; if(readnest>MAX_READNEST) module_error("too_many_nested_read");
  345.     if(outputing) phtml_put(p,cache); else var_proc(p,cache);
  346.     readnest--; untrust=t;
  347.     memmove(&m_file,&save,sizeof(WORKING_FILE));
  348.     setvar("wims_read_parm",parmsave);
  349. }
  350.  
  351.     /* read a variable processing file */
  352. void exec_readproc(char *p)
  353. {
  354.     int o=outputing; outputing=0; exec_read(p); outputing=o;
  355. }
  356.  
  357. void exec_defread(char *p)
  358. {
  359.     int t,o;
  360.     secure_exec();
  361.     t=untrust; untrust|=0x400;
  362.     o=outputing; outputing=0;
  363.     exec_read(p); untrust=t; outputing=o;
  364. }
  365.  
  366.     /* Change to another file (no return) */
  367. void exec_changeto(char *p)
  368. {
  369.     m_file.linepointer=m_file.linecnt;
  370.     exec_read(p);
  371. }
  372.  
  373. int header_executed=0, tail_executed=0;
  374.  
  375.     /* internal routine: get other language versions */
  376. void other_langs(void)
  377. {
  378.     int i,j,k;
  379.     char *p, lbuf[4], pbuf[MAX_FNAME+1], *phtml;
  380.     char namebuf[MAX_FNAME+1], listbuf[4*MAX_LANGUAGES];
  381.     static int otherlangs_got=0;
  382.  
  383.     if(otherlangs_got) return;
  384.     mystrncpy(namebuf,module_prefix,sizeof(namebuf));
  385.     listbuf[0]=0;j=strlen(namebuf)-3; p=listbuf;
  386.     if(j>=2 && strcmp("light",namebuf+j-2)==0) {
  387.       setvar("wims_light_module","yes");
  388.       phtml=getvar("phtml");
  389.       if(phtml==NULL || *phtml==0) return;
  390.       mystrncpy(pbuf,phtml,sizeof(pbuf));
  391.       j=strlen(pbuf)-3;
  392.       if(pbuf[j]!='.') return;
  393.       j++; ovlstrcpy(lbuf,pbuf+j); pbuf[j]=0;
  394.       j=strlen(namebuf);
  395.       snprintf(namebuf+j,MAX_FNAME-j-10,"/pages/%s",pbuf);
  396.       j=strlen(namebuf);
  397.       for(i=k=0;i<available_lang_no;i++) {
  398.         if(strcmp(lbuf,available_lang[i])==0) continue;
  399.         mystrncpy(namebuf+j,available_lang[i],MAX_FNAME-j);
  400.         if(ftest(namebuf)<0) continue;
  401.         if(k>0) *p++=',';
  402.         mystrncpy(p,available_lang[i],sizeof(listbuf)-4-(p-listbuf));
  403.         p+=strlen(p);
  404.         k++;
  405.       }
  406.     goto end;
  407.     }
  408.     if(j>0 && namebuf[j]=='.') {
  409.       setvar("wims_light_module","");
  410.       j++; ovlstrcpy(lbuf,namebuf+j); namebuf[j]=0;
  411.       for(i=k=0;i<available_lang_no;i++) {
  412.         if(strcmp(lbuf,available_lang[i])==0) continue;
  413.         snprintf(namebuf+j,MAX_FNAME-j,"%s/main.phtml",
  414.              available_lang[i]);
  415.         if(ftest(namebuf)<0) continue;
  416.         if(k>0) *p++=',';
  417.         mystrncpy(p,available_lang[i],sizeof(listbuf)-4-(p-listbuf));
  418.         p+=strlen(p);
  419.         k++;
  420.       }
  421.     }
  422.     end: setvar("wims_otherlangs",listbuf); otherlangs_got=1;
  423. }
  424.  
  425.     /* Standardised reference to wims home */
  426. void exec_homeref(char *p)
  427. {
  428.     char *ref, *user;
  429.  
  430.     if(ismhelp || tail_executed) return;
  431.     setvar("wims_homeref_parm",p); *p=0;
  432.     user=getvar("wims_user");
  433.     if(user==NULL) user="";
  434.     if(*user==0 || robot_access) ref=home_referer;
  435.     else {
  436.       if(strcmp(user,"supervisor")==0) ref=home_referer_supervisor;
  437.       else ref=home_referer_user;
  438.     }
  439.     if(user[0]==0 && !robot_access) other_langs();
  440.     phtml_put_base(ref,0); tail_executed=1;
  441. }
  442.  
  443.     /* Standardised header menu */
  444. void exec_headmenu(char *p)
  445. {
  446.     char *ref, *user;
  447.  
  448.     if(header_executed) return;
  449.     setvar("wims_headmenu_parm",p); *p=0;
  450.     user=getvar("wims_user");
  451.     if(user==NULL) user="";
  452.     if(*user==0 || robot_access) ref=header_menu;
  453.     else {
  454.       if(strcmp(user,"supervisor")==0) ref=header_menu_supervisor;
  455.       else ref=header_menu_user;
  456.     }
  457.     if(user[0]==0 && !robot_access) other_langs();
  458.     phtml_put_base(ref,0); header_executed=1;
  459. }
  460.  
  461.     /* uniformized title */
  462. void exec_title(char *p)
  463. {
  464.     char *s;
  465.     *p=0;
  466.     if(!outputing) return;
  467.     s=getvar("wims_title_title");
  468.     if(s==NULL || *s==0) {
  469.       s=getvar("module_title");
  470.       if(s==NULL || *s==0) return;
  471.       force_setvar("wims_title_title",s);
  472.     }
  473.     phtml_put_base(title_page,0);
  474. }
  475.  
  476.     /* standardized html tail */
  477. void exec_tail(char *p)
  478. {
  479.     if(!outputing || tail_executed) {
  480.       *p=0; return;
  481.     }
  482.     if(!ismhelp) exec_homeref(p); *p=0;
  483.     _output_("</body></html>");
  484.     tail_executed=1;
  485. }
  486.  
  487. void exec_formend(char *p)
  488. {
  489.     _output_("\n</div></form>");
  490. }
  491.  
  492. void determine_font(char *l);
  493.  
  494. void _headmathjax ( char *p)
  495. {
  496.    _output_("\n<script type=\"text/javascript\">/*<![CDATA[*/if(\
  497. navigator.userAgent.toLowerCase().indexOf(\"firefox\") == -1 &&\
  498. navigator.userAgent.toLowerCase().indexOf(\"opera\") == -1 &&\
  499. (navigator.userAgent.toLowerCase().indexOf(\"safari\") == -1 || navigator.userAgent.toLowerCase().indexOf(\"chrome\") > 0)\
  500. ){var script = document.createElement(\"script\");\
  501. script.type = \"text/javascript\";\
  502. script.src  = \"scripts/js/mathjax/MathJax.js?config=MML_HTMLorMML-full.js\";\
  503. document.body.appendChild(script);\
  504. }/*]]>*/</script>\n");
  505. }
  506.  
  507.    /* standardized header */
  508. void _header(char *p, int option)
  509. {
  510.     char *s1, *s2, hbuf[MAX_LINELEN+1], *ws="", *ws2="", *bo, *ol;
  511.     char wsbuf[MAX_LINELEN+1],wsbuf2[MAX_LINELEN+1];
  512.     setvar("wims_header_parm",p); *p=0;
  513.     if(!outputing || header_executed) return;
  514.     s1=getvar("wims_window");
  515.     if(mode==mode_popup) {
  516.       if(s1!=NULL && *s1!=0) {
  517.         char *p1, *p2;
  518.         int t1,t2/*,t3,t4*/;
  519.         p1=find_word_start(s1);
  520.         for(p2=p1; myisdigit(*p2); p2++);
  521.         *p2=0; t1=atoi(p1); p1=p2+1;
  522.         while(!myisdigit(*p1) && *p1) p1++;
  523.         for(p2=p1; myisdigit(*p2); p2++);
  524.         *p2=0; t2=atoi(p1); p1=p2+1;
  525. /*        while(!myisdigit(*p1) && *p1) p1++;
  526.         for(p2=p1; myisdigit(*p2); p2++);
  527.         *p2=0; t3=atoi(p1); p1=p2+1;
  528.         while(!myisdigit(*p1) && *p1) p1++;
  529.         for(p2=p1; myisdigit(*p2); p2++);
  530.         *p2=0; t4=atoi(p1); p1=p2+1;
  531.         while(!myisdigit(*p1) && *p1) p1++;
  532.         for(p2=p1; myisdigit(*p2); p2++);
  533.         if(t3<5) t3=5; if(t4<20) t4=20;
  534. */      snprintf(wsbuf,sizeof(wsbuf),
  535.           "window.focus();window.resizeTo(%d,%d);",t1,t2); ws=wsbuf;
  536. /*      snprintf(wsbuf,sizeof(wsbuf),
  537.              "window.focus();window.resizeto(%d,%d);window.moveto(%d,%d);",
  538.              t1,t2,t3,t4); ws=wsbuf;
  539. */    }
  540.     }
  541.     else {
  542.      if(s1!=NULL && strcmp(s1,"new")==0)
  543.       ws="window.focus();window.resizeTo(800,640);window.moveTo(15,35);";
  544.     }
  545.     if(strstr(session_prefix,"_exam")!=NULL) {
  546. /*    char buf[64]; */
  547.       if(*ws==0) ws="window.focus();";
  548.       else ws= "window.focus();window.moveTo(5,70);";
  549. /*    snprintf(buf,sizeof(buf),"name.phtml.%s",lang);
  550.       phtml_put_base(buf);
  551.       phtml_put_base("jsclock.phtml"); */
  552.     }
  553.     s1=getvar("wims_html_header"); if(s1==NULL) s1="";
  554.     determine_font(getvar("module_language"));
  555.     s2=getvar("module_title"); if(s2!=NULL && *s2!=0) {
  556.       mystrncpy(hbuf,s2,sizeof(hbuf)); calc_detag(hbuf);
  557.       setvar("module_title2",hbuf);
  558.     }
  559.     mystrncpy(hbuf,s1,sizeof(hbuf)); substit(hbuf);
  560.     s2=getvar("wims_htmlbody"); if(s2==NULL) s2="";
  561.     bo=getvar("wims_html_bodyoption"); if(bo==NULL) bo="";
  562.     ws2=getvar("wims_html_onload"); if(ws2==NULL) ws2="";
  563.     snprintf(wsbuf2,sizeof(wsbuf2),"%s%s",ws,ws2);
  564.     setvar("wims_html_onload",wsbuf2);
  565.     if(wsbuf2[0]) ol=" onload="; else ol="";
  566. /*    output("<html xmlns=\"http://www.w3.org/1999/xhtml\"><head>%s\n\
  567. </head><body %s %s%s %s>\n", */
  568. /*    output("<html>\n\
  569. <head>%s\n\
  570. </head><body %s %s%s %s>\n",
  571.        hbuf,s2,ol,wsbuf2,bo);*/
  572.        /*http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd*/
  573.      if(ol[0]) {
  574.         output("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN\" \"http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd\">\
  575.        \n<html xml:lang=\"%s\"\
  576.        xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:mathml=\"http://www.w3.org/1998/Math/MathML\"><head>%s\n\
  577.     </head>\n<body %s %s\"%s\" %s>", lang,hbuf,s2,ol,wsbuf2,bo);}
  578.      else {
  579.        output("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN\" \"http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd\">\
  580.        \n<html xml:lang=\"%s\" xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:mathml=\"http://www.w3.org/1998/Math/MathML\"><head>%s\n\
  581.        </head>\n<body %s %s%s %s>", lang,hbuf,s2,ol,wsbuf2,bo);
  582.     }
  583.     _headmathjax(p);
  584.     exec_headmenu(p);
  585.     if(option) exec_title(p);
  586.     if(cmd_type==cmd_help) {
  587.       char *s=getvar("special_parm");
  588.       if(s==NULL) s="";
  589.       m_file.linepointer=m_file.linecnt;
  590.       if(strcmp(s,"about")==0) ovlstrcpy(hbuf,"about.phtml");
  591.       else ovlstrcpy(hbuf,"help.phtml");
  592.       exec_read(hbuf); exec_tail(p); /* param of exec_...() must be readable */
  593.      return;
  594.     }
  595.     header_executed=1;
  596. }
  597.  
  598. void exec_header(char *p) { _header(p,1);}
  599. void exec_header1(char *p) { _header(p,0);}
  600.  
  601. char href_target[128];
  602. char jsbuf[512];
  603. #define jsstr " onclick=\"%s=window.open('','%s','status=no,toolbar=no,location=no,menubar=no,scrollbars=yes,resizable=yes')\""
  604. int ref_mhelp=0;
  605. int follow_list[]={
  606.     ro_session, ro_lang, ro_useropts, ro_module
  607. };
  608. #define follow_no (sizeof(follow_list)/sizeof(follow_list[0]))
  609.  
  610. void _httpfollow(char b1[], char *wn, int new)
  611. {
  612.     int i;
  613.     char *p1, *s, *ss, sb[MAX_LINELEN+1], qbuf[MAX_LINELEN+1];
  614.  
  615.     sb[0]=0;
  616.     for(i=0;i<follow_no;i++) {
  617.       if(robot_access && follow_list[i]==ro_session) continue;
  618.       if(!new && follow_list[i]!=ro_session
  619.        && follow_list[i]!=ro_module && follow_list[i]!=ro_lang)
  620.        continue;
  621.       if(follow_list[i]==ro_module) {
  622.         char *pp;
  623.         if(new) continue;
  624.         pp=strstr(b1,"cmd=");
  625.         if(pp==NULL) continue;
  626.         pp+=strlen("cmd=");
  627.         if(memcmp(pp,"intro",strlen("intro"))==0 ||
  628.            memcmp(pp,"new",strlen("new"))==0) continue;
  629.       }
  630.       s=getvar(ro_name[follow_list[i]]);
  631.       ss=strstr(b1,ro_name[follow_list[i]]);
  632.       if(s!=NULL && *s!=0 &&
  633.         (ss==NULL || (ss>b1 && *(ss-1)!='&')
  634.          || *(ss+strlen(ro_name[follow_list[i]]))!='=')) {
  635.         if(follow_list[i]==ro_session && memcmp(href_target,"wims_",5)==0) {
  636.          char st[MAX_LINELEN+1];
  637.          char *s1;
  638.          s1=getvar("wims_session");
  639.          if(s1==NULL) internal_error("exec_href() error.\n");
  640.          if(ref_mhelp) {
  641.             if(strstr(s1,"_mhelp")!=0)
  642.               snprintf(st,sizeof(st),"%s",s1);
  643.             else
  644.               snprintf(st,sizeof(st),"%s_mhelp",s1);
  645.             }
  646.         else snprintf(st,sizeof(st),"%.10s%s",s1,href_target+4);
  647.           s=st;
  648.         }
  649.         snprintf(sb+strlen(sb),MAX_LINELEN-strlen(sb),"%s=%s&",
  650.              ro_name[follow_list[i]],s);
  651.         if(ismhelp && follow_list[i]==ro_session &&
  652.            strstr(sb,"_mhelp")==NULL)
  653.           snprintf(sb+strlen(sb)-1,MAX_LINELEN-strlen(sb)+1,"_mhelp&");
  654.        }
  655.     }
  656.     snprintf(qbuf,MAX_LINELEN,"%s%s%s",wn,sb,b1);
  657.     /* cleaning up query string */
  658.     for(p1=qbuf;*p1;p1++) {
  659.       if(*p1=='"') string_modify(qbuf,p1,p1+1,"%22");
  660.       if(*p1=='&' && isalpha(*(p1+1))) {
  661.         p1++; string_modify(qbuf,p1,p1,"+");
  662.       }
  663.     }
  664.     mystrncpy(b1,qbuf,MAX_LINELEN);
  665. }
  666.  
  667.     /* Restart with a new module, using http code 302. */
  668. void exec_restart(char *p)
  669. {
  670.     char buf[MAX_LINELEN+1], *rfn, buf2[MAX_LINELEN+1];
  671. /*    long int t; */
  672.  
  673.     if(robot_access || outputing || !trusted_module() || is_class_module) return;
  674. /*    accessfile(buf,"r","%s/restart.time",s2_prefix);
  675.     t=atoi(buf); if(t==nowtime) return;    */ /* possible looping */
  676.     mystrncpy(buf,find_word_start(p),sizeof(buf));
  677.     *find_word_end(buf)=0;
  678.     _httpfollow(buf,"",0);
  679.     nph_header(301);
  680.     rfn=strchr(ref_name,':'); if(rfn==NULL) {
  681.       usual: snprintf(buf2,sizeof(buf2),"%s?%s",ref_name,buf);
  682.     }
  683.     else {
  684.       char *p;
  685.       p=getvar("wims_protocol");
  686.       if(p!=NULL && strcmp(p,"https")==0) {
  687.         snprintf(buf2,sizeof(buf2),"https%s?%s",rfn,buf);
  688.       }
  689.       else goto usual;
  690.     }
  691.     printf("Location: %s\r\n\r\n\
  692. <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\
  693. <html><body><a href=\"%s\">%s</a></body></html>",buf2,buf2,buf2);
  694.     close_working_file(&m_file,0); write_logs();
  695.     snprintf(buf,sizeof(buf),"%ld",nowtime);
  696. /*    accessfile(buf,"w","%s/restart.time",s2_prefix);
  697. */    delete_pid(); exit(0);
  698. }
  699.  
  700.     /* extract target tag from parm string. */
  701. void href_find_target(char *p)
  702. {
  703.     char *pp, *pe,buf1[MAX_LINELEN+1];
  704.     href_target[0]=0; jsbuf[0]=0; ref_mhelp=0;
  705.     for(pp=find_word_start(p);*pp!=0;pp=find_word_start(pe)) {
  706.       pe=find_word_end(pp);
  707.       if(strncasecmp(pp,"target=wims_",strlen("target=wims_"))!=0) continue;
  708.       memmove(buf1,pp,pe-pp); buf1[pe-pp]=0; substit(buf1);
  709.       if(strncasecmp(buf1,"target=wims_mhelp",strlen("target=wims_mhelp"))==0) {
  710.         if(*pe!=0) *pe++=0; ovlstrcpy(href_target,"wims_help");
  711.         ref_mhelp=1;
  712.       }
  713.       else {
  714.         if(*pe!=0) *pe++=0;
  715.           mystrncpy(href_target,buf1+strlen("target="),sizeof(href_target));
  716.       }
  717.       snprintf(jsbuf,sizeof(jsbuf),jsstr,href_target,href_target);
  718.       ovlstrcpy(pp,pe);return;
  719.     }
  720.     pp=getvar("module_help");
  721.     if(href_target[0]==0 && pp!=NULL && strcmp(pp,"popup")==0 &&
  722.        (pe=strstr(p,"cmd=help"))!=NULL) {
  723.       if(pe==p || *(pe-1)=='&') {
  724.         ovlstrcpy(href_target,"wims_help"); ref_mhelp=1;
  725.         snprintf(jsbuf,sizeof(jsbuf),jsstr,href_target,href_target);
  726.       }
  727.     }
  728. }
  729.  
  730. void _href_getdef(char src[], char vname[], char buf[], int buflen)
  731. {
  732.     char *p1, *p2, *p3;
  733.     buf[0]=0;
  734.     for(p1=strstr(src,vname); p1; p1=strstr(p2,vname)) {
  735.       p2=p1+strlen(vname); if(*p2!='=') continue;
  736.       if(p1>src && *(p1-1)!='&') continue;
  737.       p2++; p3=strchr(p2,'&'); if(p3==NULL) p3=p2+strlen(p2);
  738.       if(p3-p2>=buflen) return; /* too long */
  739.       memmove(buf,p2, p3-p2); buf[p3-p2]=0; return;
  740.     }
  741. }
  742.  
  743.  
  744.     /* Create href to wims requests. subst() is not done. */
  745. void exec_href(char *p)
  746. {
  747.     char *s, st[128], sti[128], stc[128], stt[128], *p1, *p2, *p3, *wn="";
  748.     char *U="<span style=\"color:#A0A0C0;text-decoration:underline;\">%s</span>";
  749.     char b1[MAX_LINELEN+1], b2[MAX_LINELEN+1];
  750.     int new=0;
  751.     if(!outputing) return;
  752.     href_find_target(p);
  753.     p1=find_word_start(p);
  754.     p2=find_word_end(p1); if(*p2) *(p2++)=0;
  755.     mystrncpy(b1,p1,sizeof(b1));
  756.     mystrncpy(b2,find_word_start(p2),sizeof(b2));
  757.     substit(b1); substit(b2);
  758.     /* standard reference */
  759.     if(*b2==0 && strchr(b1,'=')==NULL) {
  760.       char b[MAX_LINELEN+1], *ll;
  761.       p1=find_word_start(b1); *find_word_end(p1)=0;
  762.       if(*p1==0 || strlen(p1)>64) return;
  763.       ll=getvar("module_language");
  764.       if(ll==NULL || *ll==0 || *(ll+1)==0 || *(ll+2)!=0) ll=lang;
  765.       accessfile(b,"r","html/href.%s",ll);
  766.       memmove(p1+1,p1,64); *p1='\n'; strcat(p1,"        ");
  767.       p2=strstr(b,p1); if(p2==NULL) return;
  768.       p1=find_word_start(p2+strlen(p1)); p2=find_word_end(p1);
  769.       if(*p2) *(p2++)=0;
  770.       p3=strchr(p2,'\n'); if(p3!=NULL) *p3=0;
  771.       mystrncpy(b1,p1,sizeof(b1));
  772.       mystrncpy(b2,find_word_start(p2),sizeof(b2));
  773.       substit(b1); substit(b2);
  774.     }
  775.     /* for robots: only references without defining cmd. */
  776.     if(robot_access && strstr(b1,"cmd=")!=NULL &&
  777.        strstr(b1,"module=adm/doc")==NULL) {
  778.       _output_(b2); return;
  779.     }
  780.     if(robot_access && strstr(aliased_cgi,"yes")!=NULL) {
  781.       char mbuf[256], lbuf[16];
  782.       _href_getdef(b1,"module",mbuf,sizeof(mbuf));
  783.       if(mbuf[0]==0) mystrncpy(mbuf,home_module,sizeof(mbuf));
  784.       _href_getdef(b1,"lang",lbuf,sizeof(lbuf));
  785.       if(strlen(lbuf)!=2) {mystrncpy(lbuf,lang,4);lbuf[2]=0;}
  786.       if(strncmp(mbuf,"adm/doc",strlen("adm/doc"))==0) {
  787.         char dbuf[256], bbuf[256];
  788.         _href_getdef(b1,"doc",dbuf,sizeof(dbuf));
  789.         _href_getdef(b1,"block",bbuf,sizeof(bbuf));
  790.         if(!myisdigit(dbuf[0])) dbuf[0]=0;
  791.         if(dbuf[0]!=0 && bbuf[0]==0) snprintf(bbuf,sizeof(bbuf),"main");
  792.         if(dbuf[0]==0)
  793.           output("<a href=\"%s%s_doc~.html\">%s</a>", ref_base,lbuf,b2);
  794.         else
  795.           output("<a href=\"%s%s_doc~%s~%s.html\">%s</a>",
  796.              ref_base,lbuf,dbuf,bbuf,b2);
  797.       }
  798.       else {
  799.         for(s=strchr(mbuf,'/'); s!=NULL; s=strchr(s+1,'/')) *s='~';
  800.         output("<a href=\"%s%s_%s.html\">%s</a>", ref_base,lbuf,mbuf,b2);
  801.       }
  802.     return;
  803.     }
  804.     s=getvar("wims_ref_id");
  805.     if(s!=NULL && *s!=0 && !isspace(*s)) {
  806.       snprintf(sti,sizeof(sti)," id=\"%s\"",s);
  807.     }
  808.     else sti[0]=0;
  809.  
  810.     s=getvar("wims_ref_class");
  811.     if(s!=NULL && *s!=0 && !isspace(*s)) {
  812.       snprintf(stc,sizeof(stc)," class=\"%s\"",s);
  813.     }
  814.     else stc[0]=0;
  815.  
  816.     s=getvar("wims_ref_title");
  817.     if(s!=NULL && *s!=0 && !isspace(*s)) {
  818.       snprintf(stt,sizeof(stt)," title=\"%s\"",s);
  819.     }
  820.     else stt[0]=0;
  821.  
  822.     s=getvar("wims_ref_target");
  823.     if(href_target[0]!=0) s=href_target;
  824.     if(s!=NULL && *s!=0 && !isspace(*s)) {
  825.       snprintf(st,sizeof(st)," target=\"%s\"",s);
  826.       if(strcmp(s,"_parent")!=0) {
  827.          new=1; wn="wims_window=new&";
  828.       }
  829.     }
  830.     else st[0]=0;
  831.     _httpfollow(b1,wn,new);
  832.     tohttpquery(b1);
  833.     if(strstr(session_prefix,"_check")!=NULL) {
  834.       if(*b2) output(U,b2);
  835.     else _output_("<a id=\"0\"></a>");
  836.       return;
  837.     }
  838.     if(jsbuf[0]==0 && st[0]==0 && strstr(session_prefix,"_exam")!=NULL) {
  839.       p1=strstr(b1,"cmd=");
  840.       if(p1!=NULL) {
  841.         p1+=strlen("cmd=");
  842.         if(strncmp(p1,"new",3)==0 || strncmp(p1,"renew",5)==0 ||
  843.            strncmp(p1,"intro",5)==0) {
  844.          if(*b2) output(U,b2);
  845.          else _output_("<a id=\"#\"></a>");
  846.           return;
  847.         }
  848.       }
  849.     }
  850.     if(*b2)
  851.       output("<a href=\"%s?%s\"%s%s %s %s %s>%s</a>",
  852.          ref_name, b1, st, jsbuf,sti,stc,stt,b2);
  853.     else
  854.       output("<a href=\"%s?%s\"%s%s %s %s %s>",ref_name, b1, st, jsbuf,sti,stc,stt);
  855.     setvar("wims_ref_id","");
  856.     setvar("wims_ref_class","");
  857.     setvar("wims_ref_title","");
  858. }
  859.  
  860.     /* Create form refering to the page. */
  861. void exec_form(char *p)
  862. {
  863.     char *s, *p1, *p2, *a, *m, *opt, st[128], *wn="";
  864.     char abuf[128];
  865.     int i, new=0;
  866.     if(!outputing) return;
  867.     href_find_target(p);
  868.     s=getvar("wims_ref_target");
  869.     if(href_target[0]!=0) s=href_target;
  870.     if(s!=NULL && *s!=0 && !isspace(*s)) {
  871.       snprintf(st,sizeof(st)," target=\"%s\"",s);
  872.       if(strcmp(s,"_parent")!=0) {
  873.         new=1; wn="<input type=\"hidden\" name=\"wims_window\" value=\"yes\" />\n";
  874.       }
  875.     }
  876.     else st[0]=0;
  877.     a=getvar("wims_ref_anchor"); if(a==NULL) a="";
  878.     opt=find_word_start(find_word_end(find_word_start(p)));
  879.     m=getvar("wims_form_method");
  880.     if(m!=NULL) {
  881.       m=find_word_start(m);
  882.       if(strncasecmp(m,"post",4)==0) m="post";
  883.       else if(strncasecmp(m,"get",3)==0) m="get";
  884.         else if(strncasecmp(m,"file",4)==0) {
  885.          m="post\" enctype=\"multipart/form-data";
  886.         snprintf(abuf,sizeof(abuf),"?form-data%ld%s",random(),a); a=abuf;
  887.         force_setvar("wims_form_method","");
  888.      }
  889.       else m=default_form_method;
  890.     }
  891.     else m=default_form_method;
  892.     if(strstr(session_prefix,"_check")!=NULL) {
  893.       output("<form action=\"NON_EXISTING_PAGE\" onsubmit=\"window.close();\" %s>\n",
  894.            opt);
  895.       return;
  896.     }
  897.     output("<form action=\"%s%s\"%s method=\"%s\" %s>\n<div class='wims_form'>%s",ref_name,a,st,m,opt,wn);
  898.     if(a!=abuf && a[0]) force_setvar("wims_ref_anchor","");
  899.     for(i=0;i<follow_no;i++) {
  900.       if(robot_access && follow_list[i]==ro_session) continue;
  901.       if(!new && follow_list[i]!=ro_session
  902.        && follow_list[i]!=ro_module && follow_list[i]!=ro_lang)
  903.         continue;
  904.       if(follow_list[i]==ro_module) continue;
  905.       s=getvar(ro_name[follow_list[i]]);
  906.       if(s!=NULL && *s!=0) {
  907.         if(follow_list[i]==ro_session && memcmp(href_target,"wims_",5)==0) {
  908.           char st[MAX_LINELEN+1];
  909.           char *s1;
  910.           s1=getvar("wims_session");
  911.           if(s1==NULL) internal_error("exec_form() error.\n");
  912.           snprintf(st,sizeof(st),"%.10s%s",s1,href_target+4);
  913.           s=st;
  914.         }
  915.         output("<input type=\"hidden\" name=\"%s\" value=\"%s\" />\n",
  916.            ro_name[follow_list[i]],s);
  917.       }
  918.     }
  919.     p1=find_word_start(p);p2=find_word_end(p1);
  920.     if(p2>p1) {
  921.       char buf[64];
  922.       int i;
  923.       i=p2-p1; if(i>60) i=60;
  924.       memmove(buf,p1,i);buf[i]=0;
  925.       for(i=0;i<CMD_NO && strcmp(buf,commands[i]);i++);
  926.       if(i<CMD_NO) {
  927.         output("<input type=\"hidden\" name=\"cmd\" value=\"%s\" />\n",buf);
  928.         if(i!=cmd_intro && i!=cmd_new)
  929.           output("<input type=\"hidden\" name=\"module\" value=\"%s\" />\n",
  930.              getvar(ro_name[ro_module]));
  931.       }
  932.    }
  933. }
  934.  
  935.     /* Creat link to trap robot access, an internal command
  936.      * which should not be documented */
  937. void exec_robottrap(char *p)
  938. {
  939.     char buf[MAX_LINELEN+1];
  940.     if(robot_access) return;
  941.     ovlstrcpy(buf,"session=$wims_session.1&module=adm/trap");
  942.     _output_("<!-- "); exec_href(buf);_output_("Robot trapper, do not click!</a> -->");
  943.     _output_("<div class='wimstrap'>");exec_href(buf); _output_("<span></span></a></div>");
  944. }
  945.  
  946.     /* set definitions in a file. Trusted modules only. */
  947. void exec_setdef(char *p)
  948. {
  949.     char *p1, *pp;
  950.     char nbuf[MAX_LINELEN+1], fbuf[MAX_LINELEN+1], tbuf[MAX_LINELEN+1];
  951.     if(robot_access || !trusted_module() || is_class_module) return;
  952.     p1=wordchr(p,"in"); if(p1==NULL) module_error("syntax_error");
  953.     *p1=0; p1=find_word_start(p1+strlen("in"));
  954.     ovlstrcpy(nbuf,p);
  955.     mystrncpy(tbuf,p1,sizeof(tbuf));
  956.     substit(nbuf); substit(tbuf);
  957.     if(find_module_file(tbuf,fbuf,1)) return;
  958.     pp=find_word_start(nbuf); p1=find_word_start(fbuf); *find_word_end(p1)=0;
  959.     strip_trailing_spaces(pp);
  960.     setdef(p1,pp);
  961. }
  962.  
  963.     /* Set a variable. */
  964. void exec_set(char *name)
  965. {
  966.     char *p, *defn, *parm;
  967.     char tbuf2[MAX_LINELEN+1], namebuf[MAX_LINELEN+1];
  968.     int i;
  969.  
  970.     p=strchr(name,'=');
  971.     if(p==NULL) return; /* warning or error! */
  972.     *p=0; defn=find_word_start(p+1);
  973.     *find_word_end(name)=0;
  974.     mystrncpy(namebuf,find_word_start(name),sizeof(namebuf));
  975.         /* we allow substit in names, to implement array */
  976.     substit(namebuf); *find_word_end(namebuf)=0;
  977.     if(*defn!=calc_prefix_char) {
  978.     /* substitute by default */
  979.       mystrncpy(tbuf2,defn,sizeof(tbuf2));
  980.       substit(tbuf2); setvar(namebuf,tbuf2); return;
  981.     }
  982.     /* called from !readdef */
  983.     if((untrust&4)!=0) module_error("not_trusted");
  984.     /* definition is a command  */
  985.     parm=find_word_end(defn+1);
  986.     if( *parm != 0 ) { *parm=0; parm=find_word_start(parm+1); }
  987.     i=m_file.lines[m_file.l].varcode;
  988.     if(i<0) {
  989.       i=search_list(calc_routine,CALC_FN_NO,sizeof(calc_routine[0]),defn+1);
  990.       m_file.lines[m_file.l].varcode=i;
  991.     }
  992.     if(i<0) {
  993.         /* replace by warning? */
  994.       setvar(error_data_string,defn+1); module_error("bad_cmd");
  995.       return;
  996.     }
  997.     mystrncpy(tbuf2,parm,sizeof(tbuf2)); execnt++;
  998.     if(calc_routine[i].tag==0) substit(tbuf2);
  999.     tbuf2[sizeof(tbuf2)-1]=0; calc_routine[i].routine(tbuf2);
  1000.         /* remove trailing new line */
  1001.     tbuf2[sizeof(tbuf2)-1]=0;
  1002.     if(tbuf2[strlen(tbuf2)-1]=='\n') tbuf2[strlen(tbuf2)-1]=0;
  1003.     setvar(namebuf,tbuf2);
  1004. }
  1005.  
  1006.     /* set but do not overwrite. */
  1007. void exec_default(char *p)
  1008. {
  1009.     char *start, *end, c, *pp;
  1010.     char namebuf[MAX_LINELEN+1];
  1011.     start=find_word_start(p);
  1012.     for(end=start;*end!=0 && !isspace(*end) && *end!='='; end++);
  1013.     c=*end; *end=0;
  1014.     if(end-start<=MAX_LINELEN-1) {
  1015.       memmove(namebuf,start,end-start+1); substit(namebuf);
  1016.       pp=getvar(namebuf);
  1017.       if(pp!=NULL && *pp!=0) return;
  1018.     }
  1019.     *end=c; exec_set(p);
  1020. }
  1021.  
  1022.     /* Does nothing; just a comment. */
  1023. void exec_comment(char *p)
  1024. {
  1025.     return;
  1026. }
  1027.  
  1028.     /* Exit the file under interpretation */
  1029. void exec_exit(char *p)
  1030. {
  1031.     m_file.linepointer=m_file.linecnt;
  1032.     return;
  1033. }
  1034.  
  1035.     /* output a file. Undocumented. Aliases:
  1036.      * getfile, outfile, fileout */
  1037. void exec_getfile(char *p)
  1038. {
  1039.     char *s, *p1, url[MAX_LINELEN+1];
  1040.     char *prompt;
  1041.  
  1042.     p=find_word_start(p); prompt=find_word_end(p);
  1043.     if(*prompt!=0) *prompt++=0;
  1044.     prompt=find_word_start(prompt);
  1045.     if(*p==0 || !outputing) return;
  1046.     if(!trusted_module() || is_class_module) return;
  1047.     s=getvar(ro_name[ro_session]);
  1048.     if(s==NULL || *s==0 || strstr(s,"robot")!=NULL) return;
  1049.     mystrncpy(url,ref_name,sizeof(url));
  1050.     for(p1=url+strlen(url);p1>url && *(p1-1)!='/'; p1--);
  1051.     if(good_httpd) snprintf(p1,sizeof(url)+p1-url,
  1052.                 "getfile/%s?&+session=%s&+modif=%ld",
  1053.                 p,s,nowtime);
  1054.     else snprintf(url,sizeof(url),
  1055.           "%s?cmd=getfile&+session=%s&+special_parm=%s&+modif=%ld",
  1056.           ref_name,s,p,nowtime);
  1057.     snprintf(jsbuf,sizeof(jsbuf),jsstr,"wims_file","wims_file");
  1058.     if(*prompt) output("<a href=\"%s\">%s</a>\n", url,prompt);
  1059.     else output("<a href=\"%s\"></a>",url);
  1060. }
  1061.  
  1062.     /* internal */
  1063. void count_insert(void)
  1064. {
  1065.     insert_no++;
  1066.     if(insert_no>=INS_LIMIT) module_error("too_many_ins");
  1067. }
  1068.  
  1069. int animated_ins=0;
  1070. int grouped_ins=0;
  1071.  
  1072. /* generic insertion */
  1073. void _exec_ins(char *p, char *script_name,char *format)
  1074. {
  1075.     char *s, *b, *at, *tag, *tag2, *al, *fmt, *mh;
  1076.     char *p1, *pt;
  1077.     char buf[1024],buf2[1024],url[MAX_LINELEN+1],altbuf[1024];
  1078.     char outbuf[1024];
  1079.     int border, middle, vspace;
  1080.     long int tel;
  1081.  
  1082.     if(robot_access) return;
  1083.     count_insert(); outbuf[0]=0;
  1084.     setenv("ins_source",p,1); /* value kept from user tamper */
  1085.     if(animated_ins) fmt=getvar("anim_format"); else fmt=format;
  1086.     if(fmt==NULL) fmt="gif";
  1087.     if(ismhelp) mh="mh"; else mh="";
  1088.     snprintf(buf,sizeof(buf),"%s/insert%s-%d.%s",s2_prefix,mh,insert_no,fmt);
  1089.     if(grouped_ins) {unlink(buf); goto grouped;}
  1090.     exportall();
  1091.     call_ssh("%s/%s %d %s >%s/ins.out 2>%s/ins.err",
  1092.         bin_dir,script_name,insert_no,tmp_dir,tmp_dir,tmp_dir);
  1093.     unlink(buf); wrapexec=1;
  1094.     if(trusted_module()) setenv("trusted_module","yes",1);
  1095.     else if(untrust) setenv("trusted_module","no",1);
  1096.     call_ssh("mv %s/insert%s-%d.%s %s >/dev/null 2>/dev/null",
  1097.          tmp_dir,mh,insert_no,fmt,s2_prefix);
  1098.     tel=filelength("%s", buf);
  1099.     if(tel<=5) {
  1100.       char bbuf[MAX_LINELEN+1];
  1101.       accessfile(bbuf,"r","%s/ins.err",tmp_dir);
  1102.       snprintf(url,sizeof(url),"gifs/badins.gif");
  1103.       for(p1=bbuf;p1<bbuf+512 && *p1;p1++)
  1104.       if(*p1=='<' || *p1=='>') *p1='?';
  1105.       *p1=0;
  1106.       if(bbuf[0]==0) snprintf(bbuf,sizeof(bbuf),"Fail");
  1107.       snprintf(outbuf+strlen(outbuf),sizeof(outbuf)-strlen(outbuf),
  1108.          " <img src=\"%s\" alt=\"Error\" /> <small><pre>%s</pre></small> <br /> ",
  1109.          url,bbuf);
  1110.       setvar("ins_warn","fail");
  1111.       setvar("ins_cnt","0");
  1112.       goto reset;
  1113.     }
  1114.     grouped:
  1115.     s=getvar(ro_name[ro_session]);
  1116.     b=getvar("ins_border"); at=getvar("ins_attr");
  1117.     tag=getvar("ins_tag");  al=getvar("ins_align");
  1118.     if(at==NULL) at="";
  1119.     if(tag==NULL) tag="";
  1120.     if(al==NULL) al="";al=find_word_start(al);
  1121.     if(*al!=0) snprintf(buf2,sizeof(buf2),"vertical-align:%s",al); else buf2[0]=0;
  1122.     if(strcasecmp(al,"middle")==0) middle=1; else middle=0;
  1123.     tag2=""; vspace=0;
  1124.     if(*tag!=0) {
  1125.       mystrncpy(buf,tag,sizeof(buf)); tag=find_word_start(buf);
  1126.       tag2=find_word_end(tag);
  1127.       if(*tag2!=0) *tag2++=0;
  1128.       tag2=find_word_start(tag2);
  1129.     }
  1130.     if(b==NULL || *b==0) border=0;
  1131.     else border=atoi(b);
  1132.     if(border<0) border=0; if(border>100) border=100;
  1133.     if(middle) {
  1134.       snprintf(outbuf+strlen(outbuf),
  1135.          sizeof(outbuf)-strlen(outbuf),"%s",mathalign_sup1);
  1136.       vspace=2;
  1137.     }
  1138.     mystrncpy(url,ref_name,sizeof(url));
  1139.     for(p1=url+strlen(url);p1>url && *(p1-1)!='/'; p1--);
  1140.     snprintf(p1,sizeof(url)+p1-url,
  1141.          "wims.%s?cmd=getins&+session=%s&+special_parm=insert%s-%d.%s&+modif=%ld",
  1142.          fmt,s,mh,insert_no,fmt,nowtime);
  1143.     if(strchr(ins_alt,'"')!=NULL || strlen(ins_alt)>256) ins_alt[0]=0;
  1144.     pt=getvar("wims_ins_alt"); if(pt==NULL) pt="";
  1145.     if(ins_alt[0] && strcmp(pt,"none")!=0)
  1146.       snprintf(altbuf,sizeof(altbuf)," alt=\"%s\"",ins_alt);
  1147.     else snprintf(altbuf,sizeof(altbuf)," alt=\"\"");
  1148.     if(strcasecmp(tag,"form")!=0) {
  1149.       snprintf(outbuf+strlen(outbuf),sizeof(outbuf)-strlen(outbuf),
  1150.          "<img src=\"%s\" style=\"border:solid;border-width:%dpx;margin-bottom:%dpx;%s\" %s %s />",
  1151.          url, border, vspace, buf2, at, altbuf);
  1152.     }
  1153.     else {
  1154.       char *n, *nend;
  1155. /* fix: add quotes at name=" " */
  1156.       if(*tag2!=0) {n="name=\"" ; nend="\"";} else {n=""; nend="";}
  1157.       snprintf(outbuf+strlen(outbuf),sizeof(outbuf)-strlen(outbuf),
  1158.          "<input type=\"image\" %s%s%s src=\"%s\" style=\"border:solid;border-width:%dpx;margin-bottom:%dpx;%s\" %s %s />",
  1159.          n,tag2,nend,url,border,vspace,buf2,at,altbuf);
  1160.     }
  1161.     if(middle) snprintf(outbuf+strlen(outbuf),
  1162.             sizeof(outbuf)-strlen(outbuf),"%s",mathalign_sup2);
  1163.     setvar("ins_warn",""); ins_alt[0]=0;
  1164.     setvar("ins_cnt",int2str(insert_no));
  1165.     reset:
  1166.     if(outputing) _output_(outbuf);
  1167.     setvar("ins_out",outbuf);
  1168.     setvar("ins_attr",""); setvar("ins_tag","");
  1169.     setvar("ins_url",url);
  1170.     snprintf(buf2,sizeof(buf2),"insert%s-%d.%s",mh,insert_no,fmt);
  1171.     setvar("ins_filename",buf2);
  1172.     animated_ins=0;
  1173. }
  1174.  
  1175. /* instex: dynamically insert tex outputs */
  1176. void exec_instex(char *p)
  1177. {
  1178.     char *ts, *tc, *f, *mh, buf[MAX_FNAME+1];
  1179.  
  1180.     if(robot_access) {
  1181.       *p=0; return;
  1182.     }
  1183.     f=instex_check_static(p); substit(p);
  1184.     if(f==NULL) {
  1185. /* Use static instex if there is no real substitution
  1186.  * and the source file is not in sessions directory.
  1187.  */
  1188.       calc_instexst(p); if(outputing) _output_(p);
  1189.       return;
  1190.     }
  1191.     if(ismhelp) mh="mh"; else mh="";
  1192.     fix_tex_size(); f="gif";
  1193.     setenv("texgif_style",instex_style,1);
  1194.     tc=getvar("instex_texheader"); if (tc) { setenv("texgif_texheader",tc,1);}
  1195.     setenv("texgif_tmpdir",tmp_dir,1);
  1196.     setenv("texgif_src",p,1);
  1197.     if(ins_alt[0]==0) mystrncpy(ins_alt,p,sizeof(ins_alt));
  1198.     mkfname(buf,"%s/insert%s-%d.gif",tmp_dir,mh,insert_no+1);
  1199.     setenv("texgif_outfile",buf,1);
  1200.     ts=getvar("wims_texsize"); tc=getvar("instex_color");
  1201.     if(lastout_file!=-1 && (tc==NULL || *tc==0) &&
  1202.        (ts==NULL || *ts==0 || strcmp(ts,"0")==0) &&
  1203.        strstr(p,"\\begin{")==NULL) {
  1204.       int ls, ln;
  1205.       char *pagebreak;
  1206.       ls=strlen(instex_src); ln=strlen(instex_fname);
  1207.       if(ls+strlen(p)>=MAX_LINELEN-256 ||
  1208.        ln+strlen(buf)>=MAX_LINELEN-16) {
  1209.         instex_flush(); ls=ln=0;
  1210.       }
  1211.       if(instex_cnt>0) pagebreak="\\pagebreak\n"; else pagebreak="";
  1212.       snprintf(instex_src+ls,MAX_LINELEN-ls,"%s %s %s %s\n",
  1213.          pagebreak,instex_style,p,instex_style);
  1214.       snprintf(instex_fname+ln,MAX_LINELEN-ln,"%s\n",buf);
  1215.       grouped_ins=1;
  1216.     }
  1217.     mkfname(buf,"%s/texgif.dvi",tmp_dir); unlink(buf);
  1218.     wrapexec=0; _exec_ins(p,instex_processor,f);
  1219.     if(grouped_ins) instex_cnt++;
  1220.     grouped_ins=0;
  1221. }
  1222.  
  1223. /* patches the gnuplot integer division (mis)feature. */
  1224. void gnuplot_patch(char *p,int oneline)
  1225. {
  1226.     char *pp;
  1227.     for(pp=strchr(p,'/');pp!=NULL;pp=strchr(pp+1,'/')) {
  1228.       char *p1;
  1229.       if(pp<=p || !myisdigit(*(pp-1)) || !myisdigit(*(pp+1))) continue;
  1230.       for(p1=pp-2;p1>=p && myisdigit(*p1);p1--);
  1231.       if(p1>=p && *p1=='.') continue;
  1232.       for(p1=pp+2;*p1 && myisdigit(*p1);p1++);
  1233.       if(*p1=='.') continue;
  1234.       string_modify(p,p1,p1,".0");
  1235.     }
  1236.     for(pp=strchr(p,'^');pp!=NULL;pp=strchr(pp+1,'^'))
  1237.       string_modify(p,pp,pp+1,"**");
  1238. /* disallow new lines and ';' */
  1239.     if(oneline)
  1240.       for(pp=p;*pp!=0;pp++) if(*pp==';' || *pp=='\n') *pp=' ';
  1241. }
  1242.  
  1243. /* This is to disable pipe in the gnuplot plotting function.
  1244.  * We do not allow ' followed by < .
  1245.  */
  1246. void prepare_insplot_parm(char *p)
  1247. {
  1248.     int i,j,multanim; char *pp, *s;
  1249.     double d;
  1250.     char setbuf[MAX_LINELEN+10],buf[MAX_LINELEN+1];
  1251.  
  1252.     j=strlen(p);
  1253. /* pipe in plot command */
  1254.     for(i=0;i<j;i++) {
  1255.       if(*(p+i)!='\'' && *(p+i)!='"') continue;
  1256.       pp=find_word_start(p+i+1); if(*pp=='<') module_error("illegal_plot_cmd");
  1257.     }
  1258.     gnuplot_patch(p,1);
  1259. /* multiplot */
  1260.     multanim=0;
  1261.     pp=getvar("insplot_split");
  1262.     if(pp!=NULL) i=linenum(pp); else i=0;
  1263. /* arbitrary limit: 16 multiplots */
  1264.     if(i>16) i=16;
  1265.     if(i>1) {
  1266.       char tbuf[MAX_LINELEN*(i+1)+100], bbuf[MAX_LINELEN+1];
  1267.       tbuf[0]=0;
  1268.       if(*p!=0) snprintf(tbuf,sizeof(tbuf),"%s\n",p);
  1269.       snprintf(buf,sizeof(buf),"%d",i); setenv("multiplot",buf,1);
  1270.       for(j=1;j<=i;j++) {
  1271.         snprintf(buf,sizeof(buf),"insplot_parm_%d",j);
  1272.         pp=getvar(buf);
  1273.         if(pp==NULL || *pp==0) {
  1274.           if(j==1 && *p!=0) continue;
  1275.           pp="";
  1276.         }
  1277.         else {
  1278.           mystrncpy(bbuf,pp,sizeof(bbuf));
  1279.           gnuplot_patch(bbuf,1);
  1280.         }
  1281.         strcat(tbuf,bbuf);strcat(tbuf,"\n");
  1282.      }
  1283.     setenv("insplot_source",tbuf,1);
  1284.     if(varchr(tbuf,"s")!=NULL) multanim=1;
  1285.     }
  1286. /* no illegal chaining */
  1287.     pp=getvar("insplot_font"); if(pp!=NULL) {
  1288.       for(s=pp;s<pp+MAX_LINELEN && *s;s++)
  1289.       if(*s==';' || *s=='\n' || *s==' ') *s=0;
  1290.       if(s>=pp+MAX_LINELEN) *s=0;
  1291.       setvar("insplot_font",pp);
  1292.     }
  1293.     pp=getvar("insplot_set"); if(pp!=NULL) {
  1294.       char tbuf[MAX_LINELEN+1];
  1295.       mystrncpy(tbuf,pp,sizeof(tbuf));
  1296.       i=strlen(tbuf)-1;
  1297.       while(i>0 && isspace(tbuf[i])) i--;
  1298.       if(tbuf[i]==';') tbuf[i]=0;
  1299.       gnuplot_patch(tbuf,0);pp=tbuf;
  1300.       ovlstrcpy(setbuf,"set "); j=strlen("set ");
  1301.       for(i=0; *(pp+i)!=0 && j<MAX_LINELEN; i++) {
  1302.         if(*(pp+i)=='\n') {setbuf[j++]=' '; continue;}
  1303.         if(*(pp+i)!=';') {setbuf[j++]=*(pp+i); continue;}
  1304.         ovlstrcpy(setbuf+j,"\nset "); j+=strlen("\nset ");
  1305.       }
  1306.       setbuf[j]=0;
  1307.       setenv("insplot_set",setbuf,1);
  1308.     }
  1309.     else setenv("insplot_set","",1);
  1310. /* frames of animation */
  1311.     pp=getvar("ins_anim_frames");
  1312.     if(pp!=NULL) i=evalue(pp); else i=1;
  1313.     if(i>=ANIM_LIMIT) i=ANIM_LIMIT-1; if(i<1) i=1;
  1314.     if(strstr(setbuf,"step")==NULL && strstr(p,"step")==NULL
  1315.        && varchr(setbuf,"s")==NULL && varchr(p,"s")==NULL && !multanim) i=1;
  1316.     setenv("ins_anim_frames",int2str(i),1);
  1317.     setvar("ins_anim_frames","");
  1318.     if(i>1) {setvar("ins_animation","yes");animated_ins=1;}
  1319.     else setvar("ins_animation","no");
  1320. /* delay of animation */
  1321.     pp=getvar("ins_anim_delay");
  1322.     if(pp!=NULL) d=evalue(pp); else d=0;
  1323.     if(d>=10) d=10; if(d<0) d=0;
  1324.     setenv("ins_anim_delay",int2str(d*100),1);
  1325. }
  1326.  
  1327. /* Insert dynamic 2d plot */
  1328. void exec_insplot(char *p)
  1329. {
  1330.     char *fmt;
  1331.     if(robot_access) {
  1332.       *p=0; return;
  1333.     }
  1334.     fmt=getvar("ins_format"); if(fmt==NULL || *fmt==0) fmt=DEFAULT_INS_FORMAT;
  1335.     prepare_insplot_parm(p); setenv("insplot_method","2D",1);
  1336.     _exec_ins(p,insplot_processor,fmt);
  1337.     wrapexec=1;
  1338. /*    call_ssh("mv %s/insplot_cmd %s 2>/dev/null",tmp_dir,s2_prefix); */
  1339.     unsetenv("multiplot"); setvar("insplot_split","");
  1340. }
  1341.  
  1342.     /* Insert dynamic 3d plot */
  1343. void exec_insplot3d(char *p)
  1344. {
  1345.     char *fmt;
  1346.     if(robot_access) {
  1347.      *p=0; return;
  1348.     }
  1349.     fmt=getvar("ins_format"); if(fmt==NULL || *fmt==0) fmt=DEFAULT_INS_FORMAT;
  1350.     prepare_insplot_parm(p); setenv("insplot_method","3D",1);
  1351.     _exec_ins(p,insplot_processor,fmt);
  1352.     wrapexec=1;
  1353. /*     call_ssh("mv %s/insplot_cmd %s 2>/dev/null",tmp_dir,s2_prefix); */
  1354.     unsetenv("multiplot");setvar("insplot_split","");
  1355. }
  1356.  
  1357. /* Insert dynamic gif draw. The parm preparation is specific to fly. */
  1358. void exec_insdraw(char *p)
  1359. {
  1360.     char *pp, *fmt;
  1361.     int i;
  1362.     double d;
  1363.  
  1364.     if(robot_access) {
  1365.       *p=0; return;
  1366.     }
  1367. /*    calc_tolower(p);*/
  1368.     fmt=getvar("ins_format"); if(fmt==NULL || *fmt==0) fmt=DEFAULT_INS_FORMAT;
  1369.     while((pp=wordchr(p,"output"))!=NULL) memmove(pp,"zqkwfx",6);
  1370. /* frames of animation */
  1371.     pp=getvar("ins_anim_frames");
  1372.     if(pp!=NULL) i=evalue(pp); else i=1;
  1373.     if(i>=ANIM_LIMIT) i=ANIM_LIMIT-1; if(i<1) i=1;
  1374.     if(i>1 && varchr(p,"s")==NULL && varchr(p,"animstep")==NULL
  1375.        && varchr(p,"step")==NULL) i=1;
  1376.     setenv("ins_anim_frames",int2str(i),1);
  1377.     setvar("ins_anim_frames","");
  1378.     if(i>1) {setvar("ins_animation","yes");animated_ins=1;}
  1379.     else setvar("ins_animation","no");
  1380. /* delay of animation */
  1381.     pp=getvar("ins_anim_delay");
  1382.     if(pp!=NULL) d=evalue(pp); else d=0;
  1383.     if(d>=10) d=10; if(d<0) d=0;
  1384.     setenv("ins_anim_delay",int2str(d*100),1);
  1385.     pp=getvar("insdraw_filebase");
  1386.     if(pp!=NULL && strstr(pp,parent_dir_string)!=NULL)
  1387.       setvar("insdraw_filebase","");
  1388.     _exec_ins(p,insdraw_processor,fmt);
  1389. }
  1390.  
  1391. void exec_increase(char *p)
  1392. {
  1393.     char *p1, *p2;
  1394.     p1=find_word_start(p); p2=find_word_end(p1);
  1395.     if(p2<=p1) {
  1396.       *p=0; return;
  1397.     }
  1398.     *p2=0;p2=getvar(p1);
  1399.     if(p2==NULL) p2="";
  1400.     setvar(p1,int2str(atoi(p2)+1)); *p=0;
  1401. }
  1402.  
  1403. /* bound a variable */
  1404. void exec_bound(char *p)
  1405. {
  1406.     char *p1, *p2, *p3;
  1407.     int doub,i,bcnt,defaulted;
  1408.     double d1,d2,dd,val;
  1409.     char nbuf[MAX_LINELEN+1],lbuf[MAX_LINELEN+1],dbuf[MAX_LINELEN+1];
  1410.     char vbuf[MAX_LINELEN+1];
  1411.     char *blist[2048];
  1412.  
  1413.     p1=find_word_start(p); p2=find_word_end(p1);
  1414.     if(*p2==0) {
  1415.       syntax: module_error("syntax_error");
  1416.     }
  1417.     *p2=0; ovlstrcpy(nbuf,p1);substit(nbuf); p1=find_word_start(p2+1);
  1418.     p2=getvar(nbuf);if(p2==NULL) p2="";
  1419.     mystrncpy(vbuf,find_word_start(p2),sizeof(vbuf));
  1420.     strip_trailing_spaces(vbuf);
  1421.     p2=find_word_end(p1); if(*p2==0) goto syntax;
  1422.     *p2=0;p2++;
  1423.     p3=wordchr(p2,"default");
  1424.     if(p3!=NULL) {
  1425.       *p3=0; defaulted=1;
  1426.       p3=find_word_start(p3+strlen("default"));
  1427.       ovlstrcpy(dbuf,p3); substit(dbuf);
  1428.     }
  1429.     else defaulted=0;
  1430.     if(strcmp(p1,"between")==0) {
  1431.       p1=find_word_start(p2);
  1432.       i=strlen("integer");
  1433.       if(strncmp(p1,"integer",i)==0 &&
  1434.        (isspace(*(p1+i)) || (*(p1+i)=='s' && isspace(*(p1+i+1))))) {
  1435.         doub=0; p1=find_word_start(find_word_end(p1));
  1436.         val=rint(evalue(vbuf));
  1437.         if(vbuf[0]) float2str(val,vbuf);
  1438.       }
  1439.       else {
  1440.         doub=1;val=evalue(vbuf);
  1441.       }
  1442.       p2=wordchr(p1,"and"); p3=p2+strlen("and");
  1443.       if(p2==NULL) {
  1444.        p2=strchr(p1,','); p3=p2+1;
  1445.       }
  1446.      if(p2==NULL) goto syntax;
  1447.      *p2=0;p2=find_word_start(p3);
  1448.      if(*p1==0 || *p2==0) goto syntax;
  1449.      d1=evalue(p1);d2=evalue(p2);
  1450.      if(!isfinite(d1) || !isfinite(d2) ||
  1451.        abs(d1)>(double)(1E10) || abs(d2)>(double)(1E10)) goto syntax;
  1452.      if(d1>d2) {
  1453.         dd=d1;d1=d2;d2=dd;
  1454.      }
  1455.      if(vbuf[0] && val<=d2 && val>=d1) {
  1456.         if(!doub) setvar(nbuf,vbuf);
  1457.         *p=0; return;
  1458.      }
  1459.      if(defaulted) ovlstrcpy(p,dbuf);
  1460.      else {
  1461.       if(!doub) {
  1462.        d1=ceil(d1);d2=floor(d2);
  1463.       }
  1464.       if(vbuf[0]==0 || val<d1) val=d1;
  1465.       else val=d2;
  1466.       float2str(val,p);
  1467.      }
  1468.      setvar(nbuf,p); *p=0; return;
  1469.     }
  1470.     else {
  1471.     if(strcmp(p1,"within")==0 || strcmp(p1,"among")==0) {
  1472.         ovlstrcpy(lbuf,p2);substit(lbuf);
  1473.         bcnt=cutitems(lbuf,blist,2048);
  1474.         if(bcnt<=0) {
  1475.           *p=0; return;
  1476.         }
  1477.         for(i=0;i<bcnt;i++) {
  1478.           if(strcmp(blist[i],vbuf)==0) {
  1479.             *p=0; return;
  1480.           }
  1481.         }
  1482.         if(defaulted) ovlstrcpy(p,dbuf); else ovlstrcpy(p,blist[0]);
  1483.         setvar(nbuf,p); *p=0;
  1484.         return;
  1485.     }
  1486.     else goto syntax;
  1487.     }
  1488. }
  1489.  
  1490. /* detrust the module. */
  1491. void exec_detrust(char *p)
  1492. {    untrust|=1; *p=0; }
  1493.  
  1494. void exec_warn(char *p)
  1495. {
  1496.     char *p1,*p2;
  1497.     char buf[MAX_FNAME+1];
  1498.     WORKING_FILE save;
  1499.  
  1500.     if(!outputing) goto end;
  1501.     p1=find_word_start(p);p2=find_word_end(p1);
  1502.     if(p2<=p1) goto end;
  1503.     *p2=0;
  1504.     snprintf(buf,sizeof(buf),"wims_warn_%s",p1);
  1505.     p2=getvar(buf);
  1506.     if(p2==NULL || *p2==0) goto end;
  1507.     p2=getvar("module_language");if(p2==NULL) p2="en";
  1508.     mkfname(buf,"msg/warn_%s.phtml.%s",p1,p2);
  1509.     memmove(&save,&m_file,sizeof(WORKING_FILE));
  1510.     if(open_working_file(&m_file,buf)==0) phtml_put(NULL,0);
  1511.     memmove(&m_file,&save,sizeof(WORKING_FILE));
  1512.     end:
  1513.     *p=0; return;
  1514. }
  1515.  
  1516. /* write an error message. */
  1517. void exec_msg(char *p)
  1518. {
  1519.     char *p1,*p2, buf[64], *l;
  1520.     secure_exec();
  1521.     p1=find_word_start(p); p2=find_word_end(p1);
  1522.     if(*p2) {
  1523.       *p2=0; p2=find_word_start(p2+1);
  1524.     }
  1525.     force_setvar("wims_error",p1); force_setvar("wims_error_parm",p2);
  1526.     l=getvar("module_language");
  1527.     if(l!=NULL && strlen(l)==2) {
  1528.       snprintf(buf,sizeof(buf),"msg.phtml.%s",l);
  1529.       phtml_put_base(buf,0);
  1530.     }
  1531.     *p=0;
  1532. }
  1533.  
  1534. struct distr_cmd distr_cmd[]={
  1535.       {"char",      NULL},
  1536.       {"charof",    NULL},
  1537.       {"chars",     NULL},
  1538.       {"charsof",   NULL},
  1539.       {"item",      cutitems},
  1540.       {"itemof",    cutitems},
  1541.       {"items",     cutitems},
  1542.       {"itemsof",   cutitems},
  1543.       {"line",      cutlines},
  1544.       {"lineof",    cutlines},
  1545.       {"lines",     cutlines},
  1546.       {"linesof",   cutlines},
  1547.       {"list",      cutitems},
  1548.       {"word",      cutwords},
  1549.       {"wordof",    cutwords},
  1550.       {"words",     cutwords},
  1551.       {"wordsof",   cutwords}
  1552. };
  1553.  
  1554. int distr_cmd_no=(sizeof(distr_cmd)/sizeof(distr_cmd[0]));
  1555.  
  1556. /* distribute a number of lines, items, etc. into a list of vars. */
  1557. void exec_distribute(char *p)
  1558. {
  1559.     int i,k,n;
  1560.     char *p1, *p2;
  1561.     char bf1[MAX_LINELEN+1],bf2[MAX_LINELEN+1];
  1562.     char *names[4096],*vals[4096];
  1563.     p1=find_word_start(p); p2=find_word_end(p1);
  1564.     if(p2<=p1 || *p2==0) module_error("syntax_error");
  1565.     *p2++=0;
  1566.     i=search_list(distr_cmd,distr_cmd_no,sizeof(distr_cmd[0]),p1);
  1567.     if(i<0) module_error("syntax_error");
  1568.     p2=find_word_start(p2); p1=wordchr(p2,"into");
  1569.     if(p1==NULL) module_error("syntax_error");
  1570.     *p1=0;mystrncpy(bf1,p2,sizeof(bf1));
  1571.     p1=find_word_start(p1+strlen("into"));
  1572.     mystrncpy(bf2,p1,sizeof(bf2));
  1573.     substit(bf1);substit(bf2);
  1574.     strip_trailing_spaces(bf1);
  1575.     items2words(bf2); n=cutwords(bf2,names,4096);
  1576.     if(distr_cmd[i].routine!=NULL) {
  1577.       k=distr_cmd[i].routine(bf1,vals,n);
  1578.       for(i=0;i<k;i++) setvar(names[i],vals[i]);
  1579.       for(;i<n;i++) setvar(names[i],"");
  1580.     }
  1581.     else {
  1582.       char buf[2];
  1583.       buf[1]=0;
  1584.       for(p1=bf1,i=0;i<n;i++) {
  1585.         buf[0]=*p1; if(*p1) p1++;
  1586.         setvar(names[i],buf);
  1587.       }
  1588.     }
  1589. }
  1590.  
  1591. /* reset variables */
  1592. void exec_reset(char *p)
  1593. {
  1594.     char *p1, *p2;
  1595.  
  1596.     items2words(p);
  1597.     for(p1=find_word_start(p); *p1; p1=find_word_start(p2)) {
  1598.       p2=find_word_end(p1); if(*p2) *p2++=0;
  1599.       setvar(p1,"");
  1600.     }
  1601. }
  1602.  
  1603. /* exchange the values of two variables */
  1604. void exec_exchange(char *p)
  1605. {
  1606.     char buf[MAX_LINELEN+1],b1[MAX_LINELEN+1],b2[MAX_LINELEN+1];
  1607.     char *p1,*p2,*pb;
  1608.     p1=wordchr(p,"and");
  1609.     if(p1!=NULL) {
  1610.       *p1=0; p2=find_word_start(p1+strlen("and"));
  1611.     }
  1612.     else {
  1613.       p1=strchr(p,',');
  1614.       if(p1==NULL) module_error("syntax_error");
  1615.       *p1=0; p2=find_word_start(p1+1);
  1616.     }
  1617.     p1=find_word_start(p);
  1618.     mystrncpy(b1,p1,sizeof(b1)); substit(b1); *find_word_end(b1)=0;
  1619.     mystrncpy(b2,p2,sizeof(b2)); substit(b2); *find_word_end(b2)=0;
  1620.     if(*b1==0 || *b2==0) module_error("syntax_error");
  1621.     pb=getvar(b1);if(pb==NULL) pb="";
  1622.     mystrncpy(buf,pb,sizeof(buf));
  1623.     pb=getvar(b2);if(pb==NULL) pb="";
  1624.     setvar(b1,pb); setvar(b2,buf);
  1625. }
  1626.  
  1627. /* Send a mail */
  1628. void exec_mailto(char *p)
  1629. {
  1630.     char *p1,*p2,*pp;
  1631.  
  1632.     if(!trusted_module() || is_class_module) return;
  1633.     p1=strchr(p,'\n'); if(p1==NULL) return;
  1634.     *p1++=0; p=find_word_start(p);
  1635.     if(*p==0) return;
  1636.     p2=strchr(p1,'\n'); if(p2==NULL) return;
  1637.     *p2++=0;
  1638.     for(pp=p1;*pp;pp++) if(*pp=='"' || *pp=='\n') *pp=' ';
  1639.     accessfile(p2,"w","%s/mail.body",tmp_dir);
  1640.     wrapexec=1;
  1641.     call_sh("mail %s -s \" %s \" %s <%s/mail.body; chmod og-rwx %s/mail.body",
  1642.         mail_opt, p1,p,tmp_dir,tmp_dir);
  1643.     mail_log(p);
  1644.     *p=0;
  1645. }
  1646.  
  1647. /* Generates a user error. Internal and undocumented. */
  1648. void exec_usererror(char *p)
  1649. {
  1650.     if(trusted_module()) user_error(p);
  1651. }
  1652.  
  1653. /* stop output. */
  1654. void exec_directout(char *p)
  1655. {
  1656.     if(outputing || !trusted_module()) return;
  1657.     printf("%s",p);
  1658.     noout=1;
  1659. }
  1660.  
  1661. enum {
  1662.       EXEC_IF, EXEC_JUMP, EXEC_ELSE, EXEC_ENDIF, EXEC_EXEC,
  1663.       EXEC_WHILE, EXEC_ENDWHILE,
  1664.       EXEC_FOR, EXEC_VAR, EXEC_DEBUG, EXEC_DAEMON,
  1665.       EXEC_SET, EXEC_DEFAULT, EXEC_COMMENT, EXEC_READ, EXEC_HREF,
  1666.       EXEC_INS, EXEC_STRING, EXEC_PEDIA, EXEC_DIR,
  1667.       EXEC_TRUST, EXEC_WARN, EXEC_ERROR, EXEC_SQL, EXEC_SCORE,
  1668.       EXEC_MAIL, EXEC_OTHER
  1669. } EXEC_TYPES;
  1670. #define EXEC_SUBST 0x1000
  1671. #define EXEC_USECALC 0x2000
  1672. #define EXEC_PROCTOO 0x4000
  1673. MYFUNCTION exec_routine[]={
  1674.       {"!",        EXEC_COMMENT,        exec_comment},
  1675.       {"TeXmath",  EXEC_STRING|EXEC_SUBST|EXEC_USECALC,texmath},
  1676.       {"add",      EXEC_STRING|EXEC_USECALC,calc_sum},
  1677.       {"advance",  EXEC_VAR|EXEC_SUBST,   exec_increase},
  1678.       {"append",   EXEC_STRING|EXEC_USECALC,calc_append},
  1679.       {"appendfile",EXEC_DIR|EXEC_SUBST,    fileappend},
  1680.       {"bound",     EXEC_STRING,       exec_bound},
  1681.       {"break",     EXEC_FOR,        exec_break},
  1682.       {"call",      EXEC_EXEC|EXEC_SUBST|EXEC_PROCTOO|EXEC_USECALC,    calc_exec},
  1683.       {"changeto",  EXEC_READ|EXEC_SUBST,    exec_changeto},
  1684.       {"char",      EXEC_STRING|EXEC_USECALC,calc_charof},
  1685.       {"chars",     EXEC_STRING|EXEC_USECALC,calc_charof},
  1686.       {"checkhost", EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_checkhost},
  1687.       {"column",    EXEC_STRING|EXEC_USECALC,calc_columnof},
  1688.       {"columns",   EXEC_STRING|EXEC_USECALC,calc_columnof},
  1689.       {"comment",   EXEC_COMMENT,        exec_comment},
  1690.       {"daemon",    EXEC_DAEMON|EXEC_USECALC|EXEC_SUBST,calc_daemon},
  1691.       {"date",      EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_date},
  1692.       {"deaccent",  EXEC_STRING|EXEC_USECALC|EXEC_SUBST,deaccent},
  1693.       {"debug",     EXEC_DEBUG,        calc_debug},
  1694.       {"declosing", EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_declosing},
  1695.       {"def",       EXEC_SET,        exec_set},
  1696.       {"default",   EXEC_SET,        exec_default},
  1697.       {"define",    EXEC_SET,        exec_set},
  1698.       {"definitionof", EXEC_SCORE|EXEC_USECALC,calc_defof},
  1699.       {"defof",     EXEC_SCORE|EXEC_USECALC,calc_defof},
  1700.       {"defread",   EXEC_READ|EXEC_SUBST,    exec_defread},
  1701.       {"detag",     EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_detag},
  1702.       {"detrust",   EXEC_TRUST,        exec_detrust},
  1703. /*      {"dictionary",EXEC_STRING|EXEC_USECALC,calc_dictionary},    */
  1704.       {"dir",       EXEC_DIR|EXEC_SUBST|EXEC_USECALC,calc_listfile},
  1705.       {"distribute",EXEC_STRING,        exec_distribute},
  1706.       {"distrust",  EXEC_TRUST,        exec_detrust},
  1707.       {"else",      EXEC_ELSE,        exec_else},
  1708.       {"embraced",  EXEC_STRING|EXEC_USECALC,calc_embraced},
  1709.       {"encyclo",   EXEC_PEDIA|EXEC_SUBST|EXEC_USECALC,pedia},
  1710.       {"encyclopedia",EXEC_PEDIA|EXEC_SUBST|EXEC_USECALC,pedia},
  1711.       {"endif",     EXEC_ENDIF,        exec_endif},
  1712.       {"endwhile",  EXEC_ENDWHILE,        exec_endwhile},
  1713.       {"evalsubst", EXEC_STRING|EXEC_USECALC,calc_evalsubst},
  1714.       {"evalsubstit",EXEC_STRING|EXEC_USECALC,calc_evalsubst},
  1715.       {"evalsubstitute",EXEC_STRING|EXEC_USECALC,calc_evalsubst},
  1716.       {"evaluesubst",EXEC_STRING|EXEC_USECALC,calc_evalsubst},
  1717.       {"evaluesubstit",EXEC_STRING|EXEC_USECALC,calc_evalsubst},
  1718.       {"evaluesubstitute",EXEC_STRING|EXEC_USECALC,calc_evalsubst},
  1719.       {"examscore", EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_examscore},
  1720.       {"exchange",  EXEC_STRING,        exec_exchange},
  1721.       {"exec",      EXEC_EXEC|EXEC_SUBST|EXEC_PROCTOO|EXEC_USECALC,    calc_exec},
  1722.       {"execute",   EXEC_EXEC|EXEC_SUBST|EXEC_PROCTOO|EXEC_USECALC,    calc_exec},
  1723.       {"exit",      EXEC_JUMP,        exec_exit},
  1724.       {"fileappend",EXEC_DIR|EXEC_SUBST,    fileappend},
  1725.       {"filelist",  EXEC_DIR|EXEC_SUBST|EXEC_USECALC,calc_listfile},
  1726.       {"fileout",   EXEC_HREF|EXEC_SUBST,    exec_getfile},
  1727.       {"filewrite", EXEC_DIR|EXEC_SUBST,    filewrite},
  1728.       {"for",       EXEC_FOR,        exec_for},
  1729.       {"form",      EXEC_HREF|EXEC_SUBST,    exec_form},
  1730.       {"formbar",   EXEC_HREF,        exec_formbar},
  1731.       {"formcheckbox",EXEC_HREF,        exec_formcheckbox},
  1732.       {"formend",   EXEC_STRING,    exec_formend},
  1733.       {"formradio", EXEC_HREF,        exec_formradio},
  1734.       {"formradiobar",EXEC_HREF,        exec_formbar},
  1735.       {"formselect",EXEC_HREF,        exec_formselect},
  1736.       {"getdef",    EXEC_SCORE|EXEC_USECALC,calc_defof},
  1737.       {"getfile",   EXEC_HREF|EXEC_SUBST,    exec_getfile},
  1738.       {"getscore",  EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscore},
  1739.       {"getscorebest",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscorebest},
  1740.       {"getscorelast",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscorelast},
  1741.       {"getscorelevel",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscorelevel},
  1742.       {"getscoremean",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscoremean},
  1743.       {"getscorepercent",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscorepercent},
  1744.       {"getscorequality",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscoremean},
  1745.       {"getscoreremain",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscoreremain},
  1746.       {"getscorerequire",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscorerequire},
  1747.       {"getscoretry",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscoretry},
  1748.       {"getscoreweight",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscoreweight},
  1749.       {"goto",      EXEC_JUMP|EXEC_SUBST,    exec_goto},
  1750.       {"header",    EXEC_HREF,        exec_header},
  1751.       {"header1",   EXEC_HREF,        exec_header1},
  1752.       {"headmenu",  EXEC_HREF,        exec_headmenu},
  1753.       {"hex",       EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_hex},
  1754.       {"homeref",   EXEC_HREF,        exec_homeref},
  1755.       {"href",      EXEC_HREF,        exec_href},
  1756.       {"htmlbar",   EXEC_HREF,        exec_formbar},
  1757.       {"htmlcheckbox",EXEC_HREF,        exec_formcheckbox},
  1758.       {"htmlheader",EXEC_HREF,        exec_header},
  1759.       {"htmlmath",  EXEC_STRING|EXEC_SUBST|EXEC_USECALC,htmlmath},
  1760.       {"htmlradio", EXEC_HREF,        exec_formradio},
  1761.       {"htmlradiobar",EXEC_HREF,        exec_formbar},
  1762.       {"htmlselect",EXEC_HREF,        exec_formselect},
  1763.       {"htmltail",  EXEC_HREF,        exec_tail},
  1764.       {"htmltitle", EXEC_HREF,        exec_title},
  1765.       {"if",        EXEC_IF,        exec_if},
  1766.       {"ifval",     EXEC_IF,        exec_ifval},
  1767.       {"ifvalue",   EXEC_IF,        exec_ifval},
  1768.       {"imgrename", EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_imgrename},
  1769.       {"include",   EXEC_READ|EXEC_SUBST,   exec_read},
  1770.       {"increase",  EXEC_VAR|EXEC_SUBST,    exec_increase},
  1771.       {"input",     EXEC_READ|EXEC_SUBST,    exec_read},
  1772.       {"insdraw",   EXEC_INS|EXEC_SUBST,    exec_insdraw},
  1773.       {"insmath",   EXEC_INS,        insmath},
  1774.       {"inspaint",  EXEC_INS|EXEC_SUBST,    exec_insdraw},
  1775.       {"insplot",   EXEC_INS|EXEC_SUBST,    exec_insplot},
  1776.       {"insplot3d", EXEC_INS|EXEC_SUBST,    exec_insplot3d},
  1777.       {"instex",    EXEC_INS,        exec_instex},
  1778.       {"instexst",  EXEC_INS|EXEC_USECALC,    calc_instexst},
  1779.       {"instexstatic",EXEC_INS|EXEC_USECALC,    calc_instexst},
  1780.       {"item",        EXEC_STRING|EXEC_USECALC,calc_itemof},
  1781.       {"items",     EXEC_STRING|EXEC_USECALC,calc_itemof},
  1782.       {"items2lines", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2lines},
  1783.       {"items2words",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2words},
  1784.       {"itemstolines",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2lines},
  1785.       {"itemstowords",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2words},
  1786.       {"let",        EXEC_SET,        exec_set},
  1787.       {"leveldata",  EXEC_STRING|EXEC_USECALC,calc_leveldata},
  1788.       {"levelpoints",EXEC_STRING|EXEC_USECALC,calc_leveldata},
  1789.       {"line",       EXEC_STRING|EXEC_USECALC,calc_lineof},
  1790.       {"lines",      EXEC_STRING|EXEC_USECALC,calc_lineof},
  1791.       {"lines2items",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,lines2items},
  1792.       {"lines2list", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,lines2items},
  1793.       {"lines2words",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,lines2words},
  1794.       {"linestoitems",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,lines2items},
  1795.       {"linestolist",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,lines2items},
  1796.       {"linestowords",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,lines2words},
  1797.       {"list2lines", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2lines},
  1798.       {"list2words", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2words},
  1799.       {"listfile",   EXEC_DIR|EXEC_SUBST|EXEC_USECALC,calc_listfile},
  1800.       {"listfiles",  EXEC_DIR|EXEC_SUBST|EXEC_USECALC,calc_listfile},
  1801.       {"listintersect",EXEC_STRING|EXEC_USECALC,calc_listintersect},
  1802.       {"listintersection", EXEC_STRING|EXEC_USECALC,calc_listintersect},
  1803.       {"listtolines",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2lines},
  1804.       {"listtowords",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2words},
  1805.       {"listunion",  EXEC_STRING|EXEC_USECALC,calc_listunion},
  1806.       {"listuniq",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_listuniq},
  1807.       {"listunique", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_listuniq},
  1808.       {"listvar",    EXEC_STRING|EXEC_SUBST|EXEC_USECALC,mathvarlist},
  1809.       {"lookup",     EXEC_STRING|EXEC_USECALC,    calc_lookup},
  1810.       {"lower",      EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_tolower},
  1811.       {"lowercase",  EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_tolower},
  1812.       {"ls",         EXEC_DIR|EXEC_SUBST|EXEC_USECALC,calc_listfile},
  1813.       {"mailto",     EXEC_MAIL|EXEC_SUBST,    exec_mailto},
  1814.       {"mailurl",    EXEC_MAIL|EXEC_SUBST|EXEC_USECALC,calc_mailurl},
  1815.       {"makelist",   EXEC_STRING|EXEC_USECALC,calc_makelist},
  1816.       {"math2html",  EXEC_STRING|EXEC_SUBST|EXEC_USECALC,htmlmath},
  1817.       {"math2mathml",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,mathmlmath},
  1818.       {"math2tex",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,texmath},
  1819.       {"mathmlmath", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,mathmlmath},
  1820.       {"mathsubst",  EXEC_STRING|EXEC_USECALC,calc_mathsubst},
  1821.       {"mathsubstit",EXEC_STRING|EXEC_USECALC,calc_mathsubst},
  1822.       {"mathsubstitute",EXEC_STRING|EXEC_USECALC,calc_mathsubst},
  1823.       {"mexec",     EXEC_EXEC|EXEC_SUBST,    exec_mexec},
  1824.       {"module",    EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_module},
  1825.       {"msg",       EXEC_EXEC|EXEC_SUBST,exec_msg},
  1826.       {"multiply",  EXEC_STRING|EXEC_USECALC,calc_product},
  1827.       {"next",      EXEC_FOR,        exec_next},
  1828.       {"nocache",   EXEC_READ,        exec_nocache},
  1829.       {"non_empty", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_nonempty},
  1830.       {"nonempty",  EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_nonempty},
  1831.       {"nospace",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,nospace},
  1832.       {"outfile",   EXEC_HREF|EXEC_SUBST,    exec_getfile},
  1833.       {"pedia",     EXEC_PEDIA|EXEC_SUBST|EXEC_USECALC,pedia},
  1834.       {"perl",      EXEC_EXEC|EXEC_PROCTOO|EXEC_SUBST,exec_perl},
  1835.       {"position",  EXEC_STRING|EXEC_USECALC,calc_pos},
  1836.       {"positionof",EXEC_STRING|EXEC_USECALC,calc_pos},
  1837.       {"positions", EXEC_STRING|EXEC_USECALC,calc_pos},
  1838.       {"prod",      EXEC_STRING|EXEC_USECALC,calc_product},
  1839.       {"product",   EXEC_STRING|EXEC_USECALC,calc_product},
  1840.       {"rawmath",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,rawmath},
  1841.       {"rawmatrix", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,rawmatrix},
  1842.       {"reaccent",  EXEC_STRING|EXEC_USECALC|EXEC_SUBST,reaccent},
  1843.       {"read",      EXEC_READ|EXEC_SUBST,    exec_read},
  1844.       {"readdef",   EXEC_READ|EXEC_SUBST,    exec_defread},
  1845.       {"readproc",  EXEC_READ|EXEC_SUBST,    exec_readproc},
  1846.       {"record",    EXEC_STRING|EXEC_USECALC,calc_recordof},
  1847.       {"records",   EXEC_STRING|EXEC_USECALC,calc_recordof},
  1848.       {"recursion", EXEC_STRING|EXEC_USECALC,calc_recursion},
  1849.       {"reinput",   EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_reinput},
  1850.       {"rem",       EXEC_COMMENT,        exec_comment},
  1851.       {"remark",    EXEC_COMMENT,        exec_comment},
  1852.       {"replace",   EXEC_STRING|EXEC_USECALC,calc_replace},
  1853.       {"reset",     EXEC_SET|EXEC_SUBST,    exec_reset},
  1854.       {"restart",   EXEC_JUMP|EXEC_SUBST,    exec_restart},
  1855.       {"return",    EXEC_JUMP,        exec_exit},
  1856.       {"robotrap",  EXEC_HREF|EXEC_SUBST,    exec_robottrap},
  1857.       {"robottrap", EXEC_HREF|EXEC_SUBST,    exec_robottrap},
  1858.       {"rootof",    EXEC_STRING|EXEC_USECALC,calc_solve},
  1859.       {"row",       EXEC_STRING|EXEC_USECALC,calc_rowof},
  1860.       {"rows",      EXEC_STRING|EXEC_USECALC,calc_rowof},
  1861.       {"rows2lines",EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_rows2lines},
  1862.       {"run",       EXEC_EXEC|EXEC_SUBST|EXEC_PROCTOO|EXEC_USECALC,    calc_exec},
  1863.       {"select",    EXEC_STRING|EXEC_USECALC,calc_select},
  1864.       {"set",       EXEC_SET,        exec_set},
  1865.       {"setdef",    EXEC_OTHER,        exec_setdef},
  1866.       {"sh",        EXEC_EXEC|EXEC_PROCTOO|EXEC_SUBST,exec_sh},
  1867.       {"shortout",  EXEC_JUMP|EXEC_SUBST,    exec_directout},
  1868.       {"singlespace",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,singlespace},
  1869.       {"solve",     EXEC_STRING|EXEC_USECALC,calc_solve},
  1870.       {"sort",      EXEC_STRING|EXEC_USECALC, calc_sort},
  1871. /*      {"sql",     EXEC_SQL|EXEC_SUBST|EXEC_USECALC, calc_sql}, */
  1872.       {"staticinstex",EXEC_INS|EXEC_USECALC,    calc_instexst},
  1873.       {"stinstex",  EXEC_INS|EXEC_USECALC,    calc_instexst},
  1874.       {"sum",       EXEC_STRING|EXEC_USECALC,calc_sum},
  1875.       {"system",    EXEC_EXEC|EXEC_PROCTOO|EXEC_SUBST,exec_sh},
  1876.       {"tail",      EXEC_HREF,        exec_tail},
  1877.       {"test",      EXEC_DEBUG,        exec_test},
  1878.       {"texmath",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,texmath},
  1879.       {"text",      EXEC_STRING|EXEC_USECALC,text},
  1880.       {"title",     EXEC_HREF,        exec_title},
  1881.       {"tohex",     EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_hex},
  1882.       {"tolower",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_tolower},
  1883.       {"toupper",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_toupper},
  1884.       {"translate", EXEC_STRING|EXEC_USECALC,calc_translate},
  1885.       {"trim",      EXEC_STRING|EXEC_USECALC,calc_trim},
  1886.       {"upper",     EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_toupper},
  1887.       {"uppercase", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_toupper},
  1888.       {"usererror", EXEC_WARN|EXEC_SUBST,    exec_usererror},
  1889.       {"values",    EXEC_STRING|EXEC_USECALC,calc_values},
  1890.       {"varlist",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,mathvarlist},
  1891.       {"warn",      EXEC_WARN|EXEC_SUBST,    exec_warn},
  1892.       {"warning",   EXEC_WARN|EXEC_SUBST,    exec_warn},
  1893.       {"while",     EXEC_WHILE,        exec_while},
  1894.       {"whileval",  EXEC_WHILE,        exec_whileval},
  1895.       {"whilevalue",EXEC_WHILE,        exec_whileval},
  1896.       {"wimsheader",EXEC_HREF,        exec_header},
  1897.       {"wimsref",   EXEC_HREF,        exec_homeref},
  1898.       {"wimstail",  EXEC_HREF,        exec_tail},
  1899.       {"wimstitle", EXEC_HREF,        exec_title},
  1900.       {"word",      EXEC_STRING|EXEC_USECALC,calc_wordof},
  1901.       {"words",     EXEC_STRING|EXEC_USECALC,calc_wordof},
  1902.       {"words2items",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,words2items},
  1903.       {"words2lines",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,words2lines},
  1904.       {"words2list",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,words2items},
  1905.       {"wordstoitems",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,words2items},
  1906.       {"wordstolines",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,words2lines},
  1907.       {"wordstolist",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,words2items},
  1908.       {"writefile", EXEC_DIR|EXEC_SUBST,    filewrite},
  1909. };
  1910. int EXEC_FN_NO=(sizeof(exec_routine)/sizeof(exec_routine[0]));
  1911.  
  1912. /* internal: to skip the content of a false if/while. */
  1913. static void _skip_contents(int isif)
  1914. {
  1915.     char buf[MAX_NAMELEN+8], *p1;
  1916.     int i,j,loop;
  1917.     loop=0;
  1918.     while(m_file.linepointer<m_file.linecnt) {
  1919.       j=m_file.linepointer;
  1920.       if((m_file.lines[j].isstart&2)==0) {
  1921.         m_file.linepointer++; continue;
  1922.       }
  1923.       i=m_file.lines[j].execcode;
  1924.       if(i<0) {
  1925.         if(wgetline(buf,MAX_NAMELEN+4,&m_file)==EOF) return;
  1926.         p1=buf+1; if(*p1!='i' && *p1!='e' && *p1!='w') continue;
  1927.         *find_word_end(p1)=0;
  1928.         i=search_list(exec_routine,EXEC_FN_NO,sizeof(exec_routine[0]),p1);
  1929.         if(i>=0) m_file.lines[j].execcode=i;
  1930.       }
  1931.       else m_file.linepointer++;
  1932.       if(i<0) continue;
  1933.       switch(exec_routine[i].tag & 0xffff) {
  1934.         case EXEC_WHILE:
  1935.           if(!isif) loop++; break;
  1936.         case EXEC_IF:
  1937.           if(isif) loop++; break;
  1938.         case EXEC_ELSE: {
  1939.           if(!isif) break;
  1940.           if(loop<=0) return; else break;
  1941.         }
  1942.         case EXEC_ENDIF: {
  1943.           if(!isif) break;
  1944.           if(loop>0) {
  1945.             loop--; break;
  1946.           }
  1947.          else return;
  1948.         }
  1949.         case EXEC_ENDWHILE: {
  1950.           if(isif) break;
  1951.           if(loop>0) {
  1952.               loop--; break;
  1953.           }
  1954.           else return;
  1955.         }
  1956.         default: break;
  1957.       }
  1958.     }
  1959. }
  1960.  
  1961. /* Execute a command defined by !. Returns 0 if OK. */
  1962. void exec_main(char *p)
  1963. {
  1964.     int i,j;
  1965.     char *pp;
  1966.     char tbuf2[MAX_LINELEN+1];
  1967.  
  1968.     pp=find_word_end(p);
  1969.     if(*pp!=0) {
  1970.       *(pp++)=0; pp=find_word_start(pp);
  1971.     }
  1972.     i=m_file.lines[m_file.l].execcode;
  1973.     if(i<0) {
  1974.       i=search_list(exec_routine,EXEC_FN_NO,sizeof(exec_routine[0]),p);
  1975.       m_file.lines[m_file.l].execcode=i;
  1976.     }
  1977.     if(i<0) {
  1978.       setvar(error_data_string,p); module_error("bad_cmd");
  1979.     }
  1980. /* called from !readdef, no right other than set; bail out */
  1981.     execnt++;
  1982.     if((untrust&4)!=0 && (j=(exec_routine[i].tag&0xffff))!=EXEC_SET) {
  1983.       tbuf2[0]=0; exec_exit(tbuf2);
  1984.     }
  1985.     ovlstrcpy(tbuf2,pp); j=exec_routine[i].tag;
  1986.     if(j&EXEC_SUBST) substit(tbuf2);
  1987.     if(j&EXEC_USECALC) {
  1988.       if(!outputing && (j&EXEC_PROCTOO)==0) return;
  1989.       exec_routine[i].routine(tbuf2); if(outputing) output0(tbuf2);
  1990.     }
  1991.     else exec_routine[i].routine(tbuf2);
  1992.     return;
  1993. }
  1994.  
  1995.