Subversion Repositories wimsdev

Rev

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