/*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
 
 *
 
 *  This program is free software; you can redistribute it and/or modify
 
 *  it under the terms of the GNU General Public License as published by
 
 *  the Free Software Foundation; either version 2 of the License, or
 
 *  (at your option) any later version.
 
 *
 
 *  This program is distributed in the hope that it will be useful,
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 *  GNU General Public License for more details.
 
 *
 
 *  You should have received a copy of the GNU General Public License
 
 *  along with this program; if not, write to the Free Software
 
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 */
 
 
 
/* this is part of wims server source.
 
 * This file does execution commands.
 
 */
 
#include "wims.h"
 
 
 
static void _skip_contents(int isif);
 
 
 
/* common routine for the two if's. */
 
static void _exec_if_while(char *p, int numerical, int isif)
 
{
 
  if(compare(p,numerical,0)==0) _skip_contents(isif); /* skip if false */
 
  else if(!isif) m_file.for_idx++;
 
  return;
 
}
 
 
 
    /* 'if' non-numerical (unless comparisons are < or >, etc.) */
 
void exec_if(char *p)
 
{
 
   _exec_if_while(p,0,1);
 
}
 
 
 
/* 'if' numerical. */
 
void exec_ifval(char *p)
 
{
 
  _exec_if_while(p,1,1);
 
}
 
 
 
void _exec_while(char *p, int numerical)
 
{
 
  FOR_STACK *stk;
 
  if(m_file.for_idx>=MAX_FOR_LEVEL) module_error("too_many_fors");
 
  stk=&(m_file.for_stack[m_file.for_idx]);
 
  stk->lineno=m_file.l;
 
  _exec_if_while(p,numerical,0);
 
}
 
 
 
/* 'while' non-numerical (unless comparisons are < or >, etc.) */
 
void exec_while(char *p)
 
{
 
  _exec_while(p,0);
 
}
 
 
 
/* 'while' numerical. */
 
void exec_whileval(char *p)
 
{
 
  _exec_while(p,1);
 
}
 
 
 
void exec_endwhile(char *p)
 
{
 
  FOR_STACK *stk;
 
  if(m_file.for_idx<=0) module_error("next_without_for");
 
  stk=&(m_file.for_stack[m_file.for_idx-1]);
 
  if(stk->varname[0]!='?') module_error("next_without_for");
 
  m_file.for_idx--; *p=0;
 
  m_file.linepointer=stk->lineno;
 
  executed_gotos++;
 
  if(executed_gotos>=GOTO_LIMIT) module_error("too_many_gotos");
 
}
 
 
 
/* Should provide a method to stop infinite loop. */
 
void exec_goto(char *p)
 
{
 
  char lbuf[MAX_NAMELEN+17];
 
  char *label_start, *line_start;
 
  int old_line;
 
  int i;
 
  executed_gotos++;
 
  if(executed_gotos>=GOTO_LIMIT) module_error("too_many_gotos");
 
  old_line=m_file.l;
 
  label_start=find_word_start(p);
 
  *find_word_end(label_start)=0;
 
  m_file.l=m_file.linepointer=0;
 
  for(i=0;i<m_file.linecnt;i++) {
 
    if(((m_file.lines[i].isstart)&4)==0) continue;
 
    line_start=find_word_start((m_file.lines[i]).address);
 
    if(line_start>(m_file.lines[i+1]).address && i<m_file.linecnt)
 
      continue;
 
    m_file.linepointer=i;
 
    wgetline(lbuf,MAX_NAMELEN+8,&m_file);
 
    line_start=find_word_start(lbuf);
 
    if(*line_start!=label_prefix_char) continue;
 
    line_start++;*find_word_end(line_start)=0;
 
    if(line_start
[0]!='*' && strcmp(line_start
,label_start
)!=0) continue;  
    *p=0; i++; return;
 
  }
 
  m_file.l=old_line;
 
  setvar(error_data_string,label_start); module_error("label_not_found");
 
/*    m_file.linepointer=m_file.linecnt; *p=0; return;
 
*/
 
}
 
 
 
/* 'else' with or without 'if'.
 
 * Philosophy: we implement a loosely checked grammar.
 
 * We cannot check 'if' grammar if we want to use 'goto'
 
 * together with 'if'.
 
 */
 
void exec_else(char *p)
 
{
 
  _skip_contents(1); return;
 
}
 
 
 
/* 'endif': nothing needs to be done here. */
 
void exec_endif(char *p)
 
{
 
  return;
 
}
 
 
 
/* find out the end of a for loop */
 
void goto_for_end(void)
 
{
 
  int inner;
 
  char buf[16];
 
  inner=0;
 
  while(m_file.linepointer<m_file.linecnt) {
 
    if((m_file.lines[m_file.linepointer].isstart&2)==0) {
 
      m_file.linepointer++; continue;
 
    }
 
    if(wgetline(buf,8,&m_file)==EOF) break;
 
    *find_word_end(buf)=0;
 
      inner++; continue;
 
    }
 
      if(inner>0) {
 
        inner--; continue;
 
      }
 
      else break;
 
    }
 
  }
 
}
 
 
 
/* for */
 
void exec_for(char *p)
 
{
 
  char *p1, *p2, *p3;
 
  double v1, v2, step;
 
  char buf[MAX_LINELEN+1];
 
  FOR_STACK *stk;
 
 
 
  if(m_file.for_idx>=MAX_FOR_LEVEL) module_error("too_many_fors");
 
  stk=&(m_file.for_stack[m_file.for_idx]);
 
  stk->lineno=m_file.l;
 
  p1=find_word_start(p);
 
  for(p2
=p1
; !isspace(*p2
) && *p2
!=0 && *p2
!='=' ; p2
++);  
  if(*p2==0) syntax: module_error("for_syntax");
 
  if(p2-p1>MAX_NAMELEN) module_error("name_too_long");
 
  stk->varname[p2-p1]=0;
 
  p1=find_word_start(p2); if(*p1==0) goto syntax;
 
  if(*p1=='=') {
 
    p1++;
 
    assign:
 
    stk->from=0;
 
    p2=wordchr(p1,"to");
 
    if(p2
==NULL
) p2
=strstr(p1
,"..");  
    if(p2==NULL) goto syntax;
 
    *p2=0; p2+=2;
 
    p3=wordchr(p2,"step");
 
    if(p3!=NULL) {
 
      step=evalue(p3);
 
      if(step==0) module_error("zero_step");
 
    }
 
    else step=1;
 
      v1=evalue(p1); v2=evalue(p2);
 
      float2str(v1,buf); setvar(stk->varname, buf);
 
      if((step>0 && v1>v2) || (step<0 && v1<v2) ) {  /* condition not met */
 
  loop_out:
 
        goto_for_end();
 
      }
 
    else {
 
      stk->varval=v1; stk->varend=v2; stk->step=step;
 
      stk->lineno=m_file.linepointer;
 
      m_file.for_idx++;
 
    }
 
    *p=0; return;
 
  }
 
    p1
+=strlen("from"); goto assign
; 
  }
 
    stk
->from
=1; p1
+=strlen("in"); 
    p1=find_word_start(p1); if(*p1==0) goto loop_out;
 
    p2=xmalloc(MAX_LINELEN+1);
 
    mystrncpy(p2,p1,MAX_LINELEN);
 
    substit(p2);
 
    strip_trailing_spaces(p2);
 
    if(*p2==0) goto loop_out;
 
    p1=strparchr(p2,','); stk->bufpt=p2;
 
    if(p1!=NULL) {
 
      *p1=0; stk->list_pt=find_word_start(p1+1);
 
    }
 
    else stk->list_pt=NULL;
 
    strip_trailing_spaces(p2); setvar(stk->varname,p2);
 
    stk->lineno=m_file.linepointer;
 
    m_file.for_idx++; *p=0; return;
 
  }
 
  goto syntax;
 
}
 
 
 
/* break a for loop */
 
void exec_break(char *p)
 
{
 
  FOR_STACK *stk;
 
  if(m_file.for_idx>0) {
 
    stk=&(m_file.for_stack[m_file.for_idx-1]);
 
    if(stk->varname[0]=='?') _skip_contents(0);
 
    else goto_for_end();
 
    m_file.for_idx--;
 
  }
 
  *p=0; return;
 
}
 
 
 
/* next */
 
void exec_next(char *p)
 
{
 
  double v1, v2, step;
 
  char *p1, *p2;
 
  char buf[MAX_LINELEN+1];
 
  FOR_STACK *stk;
 
  if(m_file.for_idx<=0) module_error("next_without_for");
 
  stk=&(m_file.for_stack[m_file.for_idx-1]);
 
  if(stk->varname[0]=='?') module_error("next_without_for");
 
  if(stk->from) { /* list style */
 
    if(stk->list_pt==NULL) {
 
      m_file.for_idx--;
 
      *p=0; return;
 
    }
 
    if(p1!=NULL) {
 
      *p1=0; p2=find_word_start(p1+1);
 
    }
 
    else p2=NULL;
 
    strip_trailing_spaces(stk->list_pt);
 
    setvar(stk->varname,stk->list_pt);
 
    stk->list_pt=p2; goto loop_back;
 
  }
 
  v1=stk->varval; v2=stk->varend; step=stk->step;
 
  v1+=step; stk->varval=v1;
 
  float2str(v1,buf);
 
  setvar(stk->varname, buf);
 
  if((step>0 && v1<=v2) || (step<0 && v1>=v2)) { /* loop */
 
    loop_back:
 
    m_file.linepointer=stk->lineno;
 
    executed_gotos++;
 
    if(executed_gotos>=GOTO_LIMIT) module_error("too_many_gotos");
 
  }
 
  else m_file.for_idx--;
 
  *p=0; return;
 
}
 
 
 
/* Execution of a file in the module directory,
 
 * only for trusted modules.
 
 */
 
void exec_mexec(char *p)
 
{
 
  direct_exec=1;
 
  calc_mexec(p);
 
  direct_exec=0;
 
}
 
 
 
/* call shell. */
 
void _exec_ex(char *p, char *arg0, char *arg1, int n)
 
{
 
  char *abuf[8];
 
  char errorfname[MAX_FNAME+1];
 
 
 
  if(robot_access) {
 
    *p=0; return;
 
  }
 
  if(!noout || !trusted_module() || is_class_module) {
 
    _calc_exec(p,arg0,arg1,n); if(outputing) output0(p);
 
    return;
 
  }
 
  mkfname(errorfname,"%s/exec.err",tmp_dir);
 
  abuf[0]=arg0; abuf[1]=arg1; abuf[n]=p; abuf[n+1]=NULL;
 
  wrapexec=1; exportall();
 
  execredirected(abuf[0],NULL,NULL,errorfname,abuf);
 
}
 
 
 
/* call shell. */
 
void exec_sh(char *p)
 
{
 
  _exec_ex(p,"sh","-c",2);
 
}
 
 
 
/* call perl. */
 
void exec_perl(char *p)
 
{
 
  _exec_ex(p,"perl","-e",2);
 
}
 
 
 
/* file should not be cached */
 
void exec_nocache(char *p)
 
{    m_file.nocache|=1; *p=0; }
 
 
 
/*
 
 * Read another file.
 
 * Read a file in order to perform tests.
 
 * Relevant global variables:
 
 * - m_file, a WORKING_FILE structure (should be restored to its original
 
 *   value at the end of the procedure)
 
 * - untrust, an integer (should be restored to its original
 
 *   value at the end of the procedure)
 
 * - outputing, an integer; its value is juste read.
 
 * - readnest, an integer, which is incremented during the function
 
 *   and decremented when it finishes.
 
 * Relevant global variables used in subprograms:
 
 * - module_prefix, a const char * which will be preprended before
 
 *   the filename, (see lines.c, label = openit).
 
 * Relevant wims_environment parameters:
 
 * - wims_read_parm  (should be restored to its original
 
 *   value at the end of the procedure)
 
 * - wims_trustfile: this parameter is only read.
 
 * Important procedures called by this one:
 
 * - phtml_put(char*, int)
 
 * - var_proc(char*, int)
 
 * - module_error(const char*)
 
 * @param p pointer to the filename, possibly followed by parameters
 
 */
 
 
 
void exec_read(char *p)
 
{
 
  WORKING_FILE save;
 
  char parmsave[MAX_LINELEN+1];
 
  char *pp,*ps;
 
  int t,cache;
 
 
 
  strip_trailing_spaces(p);p=find_word_start(p);
 
  if(*p==0) return;
 
  pp=find_word_end(p); if(*pp) *pp++=0;
 
  pp=find_word_start(pp);
 
  ps=getvar("wims_read_parm"); if(ps==NULL) ps="";
 
  mystrncpy(parmsave,ps,sizeof(parmsave));
 
  setvar("wims_read_parm",pp);
 
  memmove(&save
,&m_file
,sizeof(WORKING_FILE
));  
  cache=1; if(p[0]=='.' && p[1]=='/') {p+=2; cache=0;}
 
  t=untrust;
 
    if((untrust&255)!=0 &&
 
        (m_file.
name[0]=='/' || strncmp(m_file.
name,"wimshome/",9)==0))  
      module_error("Illegal_file_access");
 
    untrust|=0x200;
 
  }
 
  if((untrust&0x202)!=0) {
 
    pp=getvar("wims_trustfile");
 
    if(pp!=NULL && *pp!=0 && wordchr(pp,p)!=NULL)
 
      untrust&=0xfdfd;
 
  }
 
  readnest++; if(readnest>MAX_READNEST) module_error("too_many_nested_read");
 
  if(outputing) phtml_put(p,cache); else var_proc(p,cache);
 
  readnest--; untrust=t;
 
  memmove(&m_file
,&save
,sizeof(WORKING_FILE
));  
  if (trace_file){
 
    int i;
 
    for(i
=1; i
<=2*trace_indent
-2; i
++) putc(' ',trace_file
);  
  }
 
  setvar("wims_read_parm",parmsave);
 
}
 
 
 
/* read a variable processing file */
 
void exec_readproc(char *p)
 
{
 
  int o=outputing; outputing=0; exec_read(p); outputing=o;
 
}
 
 
 
void exec_defread(char *p)
 
{
 
  int t,o;
 
  secure_exec();
 
  t=untrust; untrust|=0x400;
 
  o=outputing; outputing=0;
 
  exec_read(p); untrust=t; outputing=o;
 
}
 
 
 
/* Change to another file (no return) */
 
void exec_changeto(char *p)
 
{
 
  m_file.linepointer=m_file.linecnt;
 
  exec_read(p);
 
}
 
 
 
int header_executed=0, tail_executed=0;
 
 
 
/* internal routine: get other language versions */
 
void other_langs(void)
 
{
 
  int i,j,k;
 
  char *p, lbuf[4], pbuf[MAX_FNAME+1], *phtml;
 
  char namebuf[MAX_FNAME+1], listbuf[4*MAX_LANGUAGES];
 
  static int otherlangs_got=0;
 
 
 
  if(otherlangs_got) return;
 
  mystrncpy(namebuf,module_prefix,sizeof(namebuf));
 
  listbuf
[0]=0;j
=strlen(namebuf
)-3; p
=listbuf
; 
  if(j
>=2 && strcmp("light",namebuf
+j
-2)==0) {  
    setvar("wims_light_module","yes");
 
    phtml=getvar("phtml");
 
    if(phtml==NULL || *phtml==0) return;
 
    mystrncpy(pbuf,phtml,sizeof(pbuf));
 
    if(pbuf[j]!='.') return;
 
    j++; ovlstrcpy(lbuf,pbuf+j); pbuf[j]=0;
 
    snprintf(namebuf
+j
,MAX_FNAME
-j
-10,"/pages/%s",pbuf
);  
    for(i=k=0;i<available_lang_no;i++) {
 
      if(strcmp(lbuf
,available_lang
[i
])==0) continue;  
      mystrncpy(namebuf+j,available_lang[i],MAX_FNAME-j);
 
      if(ftest(namebuf)<0) continue;
 
      if(k>0) *p++=',';
 
      mystrncpy(p,available_lang[i],sizeof(listbuf)-4-(p-listbuf));
 
      k++;
 
    }
 
  goto end;
 
  }
 
  if(j>0 && namebuf[j]=='.') {
 
    setvar("wims_light_module","");
 
    j++; ovlstrcpy(lbuf,namebuf+j); namebuf[j]=0;
 
    for(i=k=0;i<available_lang_no;i++) {
 
      if(strcmp(lbuf
,available_lang
[i
])==0) continue;  
      snprintf(namebuf
+j
,MAX_FNAME
-j
,"%s/main.phtml",  
           available_lang[i]);
 
      if(ftest(namebuf)<0) continue;
 
      if(k>0) *p++=',';
 
      mystrncpy(p,available_lang[i],sizeof(listbuf)-4-(p-listbuf));
 
      k++;
 
    }
 
  }
 
  end: setvar("wims_otherlangs",listbuf); otherlangs_got=1;
 
}
 
 
 
/* Standardised reference to wims home */
 
void exec_homeref(char *p)
 
{
 
  char *ref, *user;
 
 
 
  if(ismhelp || tail_executed) return;
 
  setvar("wims_homeref_parm",p); *p=0;
 
  user=getvar("wims_user");
 
  if(user==NULL) user="";
 
  if(*user==0 || robot_access) ref=home_referer;
 
  else {
 
    if(strcmp(user
,"supervisor")==0) ref
=home_referer_supervisor
;  
    else ref=home_referer_user;
 
  }
 
  if(user[0]==0 && !robot_access) other_langs();
 
  phtml_put_base(ref,0); tail_executed=1;
 
}
 
 
 
/* Standardised header menu */
 
void exec_headmenu(char *p)
 
{
 
  char *ref, *user;
 
 
 
  if(header_executed) return;
 
  setvar("wims_headmenu_parm",p); *p=0;
 
  user=getvar("wims_user");
 
  if(user==NULL) user="";
 
  if(*user==0 || robot_access) ref=header_menu;
 
  else {
 
    if(strcmp(user
,"supervisor")==0) ref
=header_menu_supervisor
;  
    else ref=header_menu_user;
 
  }
 
  if(user[0]==0 && !robot_access) other_langs();
 
  phtml_put_base(ref,0); header_executed=1;
 
}
 
 
 
/* uniformized title */
 
void exec_title(char *p)
 
{
 
  char *s;
 
  *p=0;
 
  if(!outputing) return;
 
  s=getvar("wims_title_title");
 
  if(s==NULL || *s==0) {
 
    s=getvar("module_title");
 
    if(s==NULL || *s==0) return;
 
    force_setvar("wims_title_title",s);
 
  }
 
  phtml_put_base(title_page,0);
 
}
 
 
 
/* standardized html tail */
 
void exec_tail(char *p)
 
{
 
  if(!outputing || tail_executed) {
 
    *p=0; return;
 
  }
 
  if(!ismhelp) exec_homeref(p);
 
  *p=0;
 
  _output_("</body></html>");
 
  tail_executed=1;
 
}
 
 
 
void exec_formend(char *p)
 
{
 
  _output_("\n</div></form>");
 
}
 
 
 
void determine_font(char *l);
 
 
 
/* see changelog wims_mathml for history */
 
void _headmathjax (char *p)
 
{
 
  _output_("\n<script>/*<![CDATA[*/\
 
function wims_mathml_zoom(id){\
 
var math = document.getElementById(id);\
 
if(math.getAttribute(\"mathsize\") == \"100%\"){\
 
  math.setAttribute(\"mathsize\",\"200%\");}else{\
 
  math.setAttribute(\"mathsize\",\"100%\");};\
 
};\
 
window.addEventListener(\"load\", function() {\
 
  var ua = navigator.userAgent.toLowerCase();\
 
  var gecko = ua.indexOf(\"gecko\") > -1 && ua.indexOf(\"khtml\") === -1 && ua.indexOf(\"trident\") === -1;\
 
  if(! gecko ){\
 
    var script = document.createElement(\"script\");\
 
    script.src  = \"scripts/js/mathjax/MathJax.js?config=TeX-MML-AM_HTMLorMML\";\
 
    document.head.appendChild(script);\
 
  };\
 
});/*]]>*/</script>\n");
 
 
 
  // Safari/MathJax bugfix : refresh display when document ready.
 
  _output_("\n<script>\
 
reload_mathML=function(){var t=document.getElementsByClassName(\"wims_mathml\");Array.prototype.filter.call(t,function(t){var e=t.style.display;t.style.display=\"none\",t.style.opacity=\"0\",setTimeout(function(){t.style.display=e},1e3),setTimeout(function(){t.style.opacity=\"1\"},1100)})},document.onreadystatechange=function(){\"complete\"===document.readyState&&(/^((?!chrome|android).)*safari/i.test(navigator.userAgent)&&reload_mathML())};\
 
</script>");
 
}
 
 
 
/* standardized header */
 
void _header(char *p, int option)
 
{
 
  char *s1, *s2, hbuf[MAX_LINELEN+1], *ws="", *ws2="", *bo, *ol;
 
  char wsbuf[MAX_LINELEN+1],wsbuf2[MAX_LINELEN+1];
 
  setvar("wims_header_parm",p); *p=0;
 
  if(!outputing || header_executed) return;
 
  s1=getvar("wims_window");
 
  if(mode==mode_popup) {
 
    if(s1!=NULL && *s1!=0) {
 
      char *p1, *p2;
 
      int t1,t2/*,t3,t4*/;
 
      p1=find_word_start(s1);
 
      for(p2=p1; myisdigit(*p2); p2++);
 
      *p2
=0; t1
=atoi(p1
); p1
=p2
+1;  
      while(!myisdigit(*p1) && *p1) p1++;
 
      for(p2=p1; myisdigit(*p2); p2++);
 
      *p2
=0; t2
=atoi(p1
); p1
=p2
+1;  
/*        while(!myisdigit(*p1) && *p1) p1++;
 
        for(p2=p1; myisdigit(*p2); p2++);
 
        *p2=0; t3=atoi(p1); p1=p2+1;
 
        while(!myisdigit(*p1) && *p1) p1++;
 
        for(p2=p1; myisdigit(*p2); p2++);
 
        *p2=0; t4=atoi(p1); p1=p2+1;
 
        while(!myisdigit(*p1) && *p1) p1++;
 
        for(p2=p1; myisdigit(*p2); p2++);
 
        if(t3<5) t3=5; if(t4<20) t4=20;
 
          "window.focus();window.resizeTo(%d,%d);",t1,t2); ws=wsbuf;
 
/*      snprintf(wsbuf,sizeof(wsbuf),
 
             "window.focus();window.resizeto(%d,%d);window.moveto(%d,%d);",
 
             t1,t2,t3,t4); ws=wsbuf;
 
*/   }
 
  }
 
  else {
 
    if(s1
!=NULL 
&& strcmp(s1
,"new")==0)  
      ws="window.focus();window.resizeTo(800,640);window.moveTo(15,35);";
 
  }
 
  if(strstr(session_prefix
,"_exam")!=NULL
) {  
/*    char buf[64]; */
 
    if(*ws==0) ws="window.focus();";
 
    else ws= "window.focus();window.moveTo(5,70);";
 
/*    snprintf(buf,sizeof(buf),"name.phtml.%s",lang);
 
      phtml_put_base(buf);
 
      phtml_put_base("jsclock.phtml"); */
 
  }
 
  s1=getvar("wims_html_header"); if(s1==NULL) s1="";
 
  determine_font(getvar("module_language"));
 
  s2=getvar("module_title"); if(s2!=NULL && *s2!=0) {
 
    mystrncpy(hbuf,s2,sizeof(hbuf)); calc_detag(hbuf);
 
    setvar("module_title2",hbuf);
 
  }
 
  mystrncpy(hbuf,s1,sizeof(hbuf)); substit(hbuf);
 
  s2=getvar("wims_htmlbody"); if(s2==NULL) s2="";
 
  bo=getvar("wims_html_bodyoption"); if(bo==NULL) bo="";
 
  ws2=getvar("wims_html_onload"); if(ws2==NULL) ws2="";
 
  snprintf(wsbuf2
,sizeof(wsbuf2
),"%s%s",ws
,ws2
);  
  setvar("wims_html_onload",wsbuf2);
 
  if(wsbuf2[0]) ol=" onload="; else ol="";
 
 
 
  output("<!DOCTYPE html>\
 
    \n<html lang=\"%s\"><head>\n\
 
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0\"/>\n\
 
    %s\n", lang, hbuf);
 
  if(robot_access){
 
    output("<link rel=\"stylesheet\" href=\"html/themes/_css/robots.css\" />");
 
  }
 
 
 
  _headmathjax(p);
 
 
 
  if(ol[0]) {
 
    output("</head>\n<body %s %s\"%s\" %s>", s2, ol, wsbuf2, bo);}
 
  else {
 
    output("</head>\n<body %s %s%s %s>", s2, ol, wsbuf2, bo);
 
  }
 
  exec_headmenu(p);
 
  if(option) exec_title(p);
 
  if(cmd_type==cmd_help) {
 
    char *s=getvar("special_parm");
 
    if(s==NULL) s="";
 
    m_file.linepointer=m_file.linecnt;
 
    if(strcmp(s
,"about")==0) ovlstrcpy
(hbuf
,"about.phtml");  
    else ovlstrcpy(hbuf,"help.phtml");
 
    exec_read(hbuf); exec_tail(p); /* param of exec_...() must be readable */
 
    return;
 
  }
 
  header_executed=1;
 
}
 
 
 
void exec_header(char *p) { _header(p,1);}
 
void exec_header1(char *p) { _header(p,0);}
 
 
 
char href_target[128];
 
char jsbuf[512];
 
#define jsstr " onclick=\"%s=window.open('','%s','status=no,toolbar=no,location=no,menubar=no,scrollbars=yes,resizable=yes')\""
 
int ref_mhelp=0;
 
int follow_list[]={
 
  ro_session, ro_lang, ro_useropts, ro_module
 
};
 
#define follow_no (sizeof(follow_list)/sizeof(follow_list[0]))
 
 
 
void _httpfollow(char b1[], char *wn, int new)
 
{
 
  int i;
 
  char *p1, *s, *ss, sb[MAX_LINELEN+1], qbuf[MAX_LINELEN+1];
 
 
 
  sb[0]=0;
 
  for(i=0;i<follow_no;i++) {
 
    if(robot_access && follow_list[i]==ro_session) continue;
 
    if(!new && follow_list[i]!=ro_session
 
        && follow_list[i]!=ro_module && follow_list[i]!=ro_lang)
 
      continue;
 
    if(follow_list[i]==ro_module) {
 
      char *pp;
 
      if(new) continue;
 
      if(pp==NULL) continue;
 
    }
 
    s=getvar(ro_name[follow_list[i]]);
 
    ss
=strstr(b1
,ro_name
[follow_list
[i
]]); 
    if(s!=NULL && *s!=0 &&
 
      (ss==NULL || (ss>b1 && *(ss-1)!='&')
 
       || *(ss
+strlen(ro_name
[follow_list
[i
]]))!='=')) {  
      if(follow_list
[i
]==ro_session 
&& memcmp(href_target
,"wims_",5)==0) {  
        char st[MAX_LINELEN+1];
 
        char *s1;
 
        s1=getvar("wims_session");
 
        if(s1==NULL) internal_error("exec_href() error.\n");
 
        if(ref_mhelp) {
 
          else
 
        }
 
        else snprintf(st
,sizeof(st
),"%.10s%s",s1
,href_target
+4);  
          s=st;
 
      }
 
             ro_name[follow_list[i]],s);
 
      if(ismhelp && follow_list[i]==ro_session &&
 
      }
 
  }
 
  snprintf(qbuf
,MAX_LINELEN
,"%s%s%s",wn
,sb
,b1
);  
  /* cleaning up query string */
 
  for(p1=qbuf;*p1;p1++) {
 
    if(*p1=='"') string_modify(qbuf,p1,p1+1,"%22");
 
      p1++; string_modify(qbuf,p1,p1,"+");
 
    }
 
  }
 
  mystrncpy(b1,qbuf,MAX_LINELEN);
 
}
 
 
 
/* Restart with a new module, using http code 302. */
 
void exec_restart(char *p)
 
{
 
  /* buf will contain all the url parameters*/
 
  /* buf2 will be the final URL */
 
  char buf[MAX_LINELEN+1], *rfn, buf2[MAX_LINELEN+1];
 
  /* long int t; */
 
 
 
  if(robot_access || outputing || !trusted_module() || is_class_module) return;
 
  /* accessfile(buf,"r","%s/restart.time",s2_prefix);
 
    t=atoi(buf); if(t==nowtime) return;    */ /* possible looping */
 
  mystrncpy(buf,find_word_start(p),sizeof(buf));
 
  *find_word_end(buf)=0;
 
  _httpfollow(buf,"",0);
 
  nph_header(302);
 
  if(rfn==NULL) {
 
    usual
: snprintf(buf2
,sizeof(buf2
),"%s?%s",ref_name
,buf
); 
  }
 
  else {
 
    char *p;
 
    p=getvar("wims_protocol");
 
    if(p
!=NULL 
&& strcmp(p
,"https")==0) {  
      snprintf(buf2
,sizeof(buf2
),"https%s?%s",rfn
,buf
);  
    }
 
    else goto usual;
 
  }
 
<!DOCTYPE html>\
 
<html><body><a href=\"%s\">%s</a></body></html>",buf2,buf2,buf2);
 
  close_working_file(&m_file,0); write_logs();
 
  snprintf(buf
,sizeof(buf
),"%ld",(long)nowtime
);  
/*    accessfile(buf,"w","%s/restart.time",s2_prefix);*/
 
}
 
 
 
/*  extract target tag from parm string. */
 
void href_find_target(char *p)
 
{
 
  char *pp, *pe,buf1[MAX_LINELEN+1];
 
  href_target[0]=0; jsbuf[0]=0; ref_mhelp=0;
 
  for(pp=find_word_start(p);*pp!=0;pp=find_word_start(pe)) {
 
    pe=find_word_end(pp);
 
    if(strncasecmp
(pp
,"target=wims_",strlen("target=wims_"))!=0) continue;  
    memmove(buf1
,pp
,pe
-pp
); buf1
[pe
-pp
]=0; substit
(buf1
);  
    if(strncasecmp
(buf1
,"target=wims_mhelp",strlen("target=wims_mhelp"))==0) {  
      if(*pe!=0) *pe++=0;
 
      ovlstrcpy(href_target,"wims_help");
 
      ref_mhelp=1;
 
    }
 
    else {
 
      if(*pe!=0) *pe++=0;
 
        mystrncpy
(href_target
,buf1
+strlen("target="),sizeof(href_target
)); 
    }
 
    snprintf(jsbuf
,sizeof(jsbuf
),jsstr
,href_target
,href_target
);  
    ovlstrcpy(pp,pe);return;
 
  }
 
  pp=getvar("module_help");
 
  if(href_target
[0]==0 && pp
!=NULL 
&& strcmp(pp
,"popup")==0 &&  
     (pe
=strstr(p
,"cmd=help"))!=NULL
) {  
    if(pe==p || *(pe-1)=='&') {
 
      ovlstrcpy(href_target,"wims_help"); ref_mhelp=1;
 
      snprintf(jsbuf
,sizeof(jsbuf
),jsstr
,href_target
,href_target
);  
    }
 
  }
 
}
 
 
 
void _href_getdef(char src[], char vname[], char buf[], int buflen)
 
{
 
  char *p1, *p2, *p3;
 
  buf[0]=0;
 
    p2
=p1
+strlen(vname
); if(*p2
!='=') continue; 
    if(p1>src && *(p1-1)!='&') continue;
 
    if(p3-p2>=buflen) return; /* too long */
 
    memmove(buf
,p2
, p3
-p2
); buf
[p3
-p2
]=0; return;  
  }
 
}
 
 
 
/* Create href to wims requests. subst() is not done. */
 
void exec_href(char *p)
 
{
 
  char *s, st[128], sti[128], stc[128], stt[128], *p1, *p2, *p3, *wn="";
 
  char *U="<span class=\"disabled_link\">%s</span>";
 
  char b1[MAX_LINELEN+1], b2[MAX_LINELEN+1];
 
  int new=0;
 
  if(!outputing) return;
 
  href_find_target(p);
 
  p1=find_word_start(p);
 
  p2=find_word_end(p1); if(*p2) *(p2++)=0;
 
  mystrncpy(b1,p1,sizeof(b1));
 
  mystrncpy(b2,find_word_start(p2),sizeof(b2));
 
  substit(b1); substit(b2);
 
  /* standard reference */
 
  if(*b2
==0 && strchr(b1
,'=')==NULL
) {  
    char b[MAX_LINELEN+1], *ll;
 
    p1=find_word_start(b1); *find_word_end(p1)=0;
 
    if(*p1
==0 || strlen(p1
)>64) return;  
    ll=getvar("module_language");
 
    if(ll==NULL || *ll==0 || *(ll+1)==0 || *(ll+2)!=0) ll=lang;
 
    accessfile(b,"r","html/href.%s",ll);
 
    p2
=strstr(b
,p1
); if(p2
==NULL
) return; 
    p1
=find_word_start
(p2
+strlen(p1
)); p2
=find_word_end
(p1
); 
    if(*p2) *(p2++)=0;
 
    p3
=strchr(p2
,'\n'); if(p3
!=NULL
) *p3
=0; 
    mystrncpy(b1,p1,sizeof(b1));
 
    mystrncpy(b2,find_word_start(p2),sizeof(b2));
 
    substit(b1); substit(b2);
 
  }
 
  /* for robots: only references without defining cmd. */
 
  if(robot_access 
&& strstr(b1
,"cmd=")!=NULL 
&&  
      strstr(b1
,"module=adm/doc")==NULL
) {  
    _output_(b2); return;
 
  }
 
  if(robot_access 
&& strstr(aliased_cgi
,"yes")!=NULL
) {  
    char mbuf[256], lbuf[16];
 
    _href_getdef(b1,"module",mbuf,sizeof(mbuf));
 
    if(mbuf[0]==0) mystrncpy(mbuf,home_module,sizeof(mbuf));
 
    _href_getdef(b1,"lang",lbuf,sizeof(lbuf));
 
    if(strlen(lbuf
)!=2) {mystrncpy
(lbuf
,lang
,4);lbuf
[2]=0;}  
      char dbuf[256], bbuf[256];
 
      _href_getdef(b1,"doc",dbuf,sizeof(dbuf));
 
      _href_getdef(b1,"block",bbuf,sizeof(bbuf));
 
      if(!myisdigit(dbuf[0])) dbuf[0]=0;
 
      if(dbuf
[0]!=0 && bbuf
[0]==0) snprintf(bbuf
,sizeof(bbuf
),"main");  
      if(dbuf[0]==0)
 
        output("<a href=\"%s%s_doc~.html\">%s</a>", ref_base,lbuf,b2);
 
      else
 
        output("<a href=\"%s%s_doc~%s~%s.html\">%s</a>",
 
           ref_base,lbuf,dbuf,bbuf,b2);
 
    }
 
    else {
 
      output("<a href=\"%s%s_%s.html\">%s</a>", ref_base,lbuf,mbuf,b2);
 
    }
 
    return;
 
  }
 
  s=getvar("wims_ref_id");
 
  if(s
!=NULL 
&& *s
!=0 && !isspace(*s
)) {  
    snprintf(sti
,sizeof(sti
)," id=\"%s\"",s
);  
  }
 
  else sti[0]=0;
 
 
 
  s=getvar("wims_ref_class");
 
  if(s
!=NULL 
&& *s
!=0 && !isspace(*s
)) {  
    snprintf(stc
,sizeof(stc
)," class=\"%s\"",s
);  
  }
 
  else stc[0]=0;
 
 
 
  s=getvar("wims_ref_title");
 
  if(s
!=NULL 
&& *s
!=0 && !isspace(*s
)) {  
    snprintf(stt
,sizeof(stt
)," title=\"%s\"",s
);  
  }
 
  else stt[0]=0;
 
 
 
  s=getvar("wims_ref_target");
 
  if(href_target[0]!=0) s=href_target;
 
  if(s
!=NULL 
&& *s
!=0 && !isspace(*s
)) {  
    snprintf(st
,sizeof(st
)," target=\"%s\"",s
);  
      new=1; wn="wims_window=new&";
 
    }
 
  }
 
  else st[0]=0;
 
  _httpfollow(b1,wn,new);
 
  tohttpquery(b1);
 
  if(strstr(session_prefix
,"_check")!=NULL
) {  
    if(*b2) output(U,b2);
 
  else _output_("<a id=\"0\"></a>");
 
  return;
 
  }
 
  if(jsbuf
[0]==0 && st
[0]==0 && strstr(session_prefix
,"_exam")!=NULL
) {  
    if(p1!=NULL) {
 
        if(*b2) output(U,b2);
 
        else _output_("<a id=\"#\"></a>");
 
        return;
 
      }
 
    }
 
  }
 
  if(*b2)
 
    output("<a href=\"%s?%s\"%s%s %s %s %s>%s</a>",
 
       ref_name, b1, st, jsbuf,sti,stc,stt,b2);
 
  else
 
    output("<a href=\"%s?%s\"%s%s %s %s %s>",ref_name, b1, st, jsbuf,sti,stc,stt);
 
  setvar("wims_ref_id","");
 
  setvar("wims_ref_class","");
 
  setvar("wims_ref_title","");
 
}
 
 
 
/* Create form refering to the page. */
 
void exec_form(char *p)
 
{
 
  char *s, *p1, *p2, *a, *m, *opt, st[128], *wn="", *form_id;
 
  char abuf[128], idbuf[128];
 
  int i, new=0;
 
  if(!outputing) return;
 
  href_find_target(p);
 
  s=getvar("wims_ref_target");
 
  if(href_target[0]!=0) s=href_target;
 
  if(s
!=NULL 
&& *s
!=0 && !isspace(*s
)) {  
    snprintf(st
,sizeof(st
)," target=\"%s\"",s
);  
      new=1; wn="<input type=\"hidden\" name=\"wims_window\" value=\"yes\" />\n";
 
    }
 
  }
 
  else st[0]=0;
 
  a=getvar("wims_ref_anchor"); if(a==NULL) a="";
 
  opt=find_word_start(find_word_end(find_word_start(p)));
 
  m=getvar("wims_form_method");
 
  if(m!=NULL) {
 
    m=find_word_start(m);
 
    if(strncasecmp(m,"post",4)==0) m="post";
 
    else if(strncasecmp(m,"get",3)==0) m="get";
 
      else if(strncasecmp(m,"file",4)==0) {
 
       m="post\" enctype=\"multipart/form-data";
 
      snprintf(abuf
,sizeof(abuf
),"?form-data%ld%s",random
(),a
); a
=abuf
;  
      force_setvar("wims_form_method","");
 
    }
 
    else m=default_form_method;
 
  }
 
  else m=default_form_method;
 
 
 
  if(strstr(session_prefix
,"_check")!=NULL
) {  
    output("<form action=\"NON_EXISTING_PAGE\" onsubmit=\"window.close();\" %s>\n",
 
           opt);
 
    return;
 
  }
 
 
 
  form_id=getvar("wims_form_id");
 
  if(form_id
==NULL 
|| *form_id
==0 || isspace(*form_id
)){  
    form_id="";
 
  } else {
 
    snprintf(idbuf
,sizeof(idbuf
),"id=\"%s\"",find_word_start
(form_id
));form_id
=idbuf
;  
  }
 
  force_setvar("wims_form_id","");
 
 
 
  output("<form action=\"%s%s\"%s method=\"%s\" %s %s>\n<div class='wims_form'>%s",ref_name,a,st,m,opt,form_id,wn);
 
  if(a!=abuf && a[0]) force_setvar("wims_ref_anchor","");
 
  for(i=0;i<follow_no;i++) {
 
    if(robot_access && follow_list[i]==ro_session) continue;
 
    if(!new && follow_list[i]!=ro_session
 
     && follow_list[i]!=ro_module && follow_list[i]!=ro_lang)
 
      continue;
 
    if(follow_list[i]==ro_module) continue;
 
    s=getvar(ro_name[follow_list[i]]);
 
    if(s!=NULL && *s!=0) {
 
      if(follow_list
[i
]==ro_session 
&& memcmp(href_target
,"wims_",5)==0) {  
        char st[MAX_LINELEN+1];
 
        char *s1;
 
        s1=getvar("wims_session");
 
        if(s1==NULL) internal_error("exec_form() error.\n");
 
        snprintf(st
,sizeof(st
),"%.10s%s",s1
,href_target
+4);  
        s=st;
 
      }
 
      output("<input type=\"hidden\" name=\"%s\" value=\"%s\" />\n",
 
           ro_name[follow_list[i]],s);
 
    }
 
  }
 
  p1=find_word_start(p);p2=find_word_end(p1);
 
  if(p2>p1) {
 
    char buf[64];
 
    int i;
 
    i=p2-p1; if(i>60) i=60;
 
    for(i
=0;i
<CMD_NO 
&& strcmp(buf
,commands
[i
]);i
++);  
    if(i<CMD_NO) {
 
      output("<input type=\"hidden\" name=\"cmd\" value=\"%s\" />\n",buf);
 
      if(i!=cmd_intro && i!=cmd_new)
 
        output("<input type=\"hidden\" name=\"module\" value=\"%s\" />\n",
 
            getvar(ro_name[ro_module]));
 
    }
 
  }
 
}
 
 
 
/* Creat link to trap robot access, an internal command
 
 * which should not be documented
 
 */
 
void exec_robottrap(char *p)
 
{
 
  char buf[MAX_LINELEN+1];
 
  if(robot_access) return;
 
  ovlstrcpy(buf,"session=$wims_session.1&module=adm/trap");
 
  _output_("<!-- "); exec_href(buf);_output_("Robot trapper, do not click!</a> -->");
 
  _output_("<div class='wimstrap hide'>");exec_href(buf); _output_("<span>Robot trapper, do not click!</span></a></div>");
 
}
 
 
 
/* set definitions in a file. Trusted modules only. */
 
void exec_setdef(char *p)
 
{
 
   char *p1, *pp;
 
   char nbuf[MAX_LINELEN+1], fbuf[MAX_LINELEN+1], tbuf[MAX_LINELEN+1];
 
   if(robot_access || !trusted_module() || is_class_module) return;
 
   p1=wordchr(p,"in"); if(p1==NULL) module_error("syntax_error");
 
   *p1
=0; p1
=find_word_start
(p1
+strlen("in"));  
   ovlstrcpy(nbuf,p);
 
   mystrncpy(tbuf,p1,sizeof(tbuf));
 
   substit(nbuf); substit(tbuf);
 
   if(find_module_file(tbuf,fbuf,1)) return;
 
   pp=find_word_start(nbuf); p1=find_word_start(fbuf); *find_word_end(p1)=0;
 
   strip_trailing_spaces(pp);
 
   setdef(p1,pp);
 
}
 
 
 
/* Set a variable. */
 
void exec_set(char *name)
 
{
 
  char *p, *defn, *parm;
 
  char tbuf2[MAX_LINELEN+1], namebuf[MAX_LINELEN+1];
 
  int i;
 
 
 
  if(p==NULL) return; /* warning or error! */
 
  *p=0; defn=find_word_start(p+1);
 
  *find_word_end(name)=0;
 
  mystrncpy(namebuf,find_word_start(name),sizeof(namebuf));
 
  /* we allow substit in names, to implement array */
 
  substit(namebuf); *find_word_end(namebuf)=0;
 
  if(*defn!=calc_prefix_char) {
 
  /* substitute by default */
 
    mystrncpy(tbuf2,defn,sizeof(tbuf2));
 
    substit(tbuf2); setvar(namebuf,tbuf2); return;
 
  }
 
  /* called from !readdef */
 
  if((untrust&4)!=0) module_error("not_trusted");
 
  /* definition is a command  */
 
  parm=find_word_end(defn+1);
 
  if( *parm != 0 ) { *parm=0; parm=find_word_start(parm+1); }
 
  i=m_file.lines[m_file.l].varcode;
 
  if(i<0) {
 
    i=search_list(calc_routine,CALC_FN_NO,sizeof(calc_routine[0]),defn+1);
 
    m_file.lines[m_file.l].varcode=i;
 
  }
 
  if(i<0) {
 
      /* replace by warning? */
 
    setvar(error_data_string,defn+1); module_error("bad_cmd");
 
    return;
 
  }
 
  mystrncpy(tbuf2,parm,sizeof(tbuf2)); execnt++;
 
  if(calc_routine[i].tag==0) substit(tbuf2);
 
  tbuf2[sizeof(tbuf2)-1]=0; calc_routine[i].routine(tbuf2);
 
      /* remove trailing new line */
 
  tbuf2[sizeof(tbuf2)-1]=0;
 
    setvar(namebuf,tbuf2);
 
}
 
 
 
/* set but do not overwrite. */
 
void exec_default(char *p)
 
{
 
  char *start, *end, c, *pp;
 
  char namebuf[MAX_LINELEN+1];
 
  start=find_word_start(p);
 
  for(end
=start
;*end
!=0 && !isspace(*end
) && *end
!='='; end
++);  
  c=*end; *end=0;
 
  if(end-start<=MAX_LINELEN-1) {
 
    memmove(namebuf
,start
,end
-start
+1); substit
(namebuf
);  
    pp=getvar(namebuf);
 
    if(pp!=NULL && *pp!=0) return;
 
  }
 
  *end=c; exec_set(p);
 
}
 
 
 
/* Does nothing; just a comment. */
 
void exec_comment(char *p)
 
{
 
  return;
 
}
 
 
 
/* Exit the file under interpretation */
 
void exec_exit(char *p)
 
{
 
  m_file.linepointer=m_file.linecnt;
 
  return;
 
}
 
 
 
/* output a file. Aliases:
 
     * getfile, outfile, fileout */
 
void exec_getfile(char *p)
 
{
 
  char *s, sti[128], stc[128], stt[128], sgf[128], *p1, url[MAX_LINELEN+1];
 
  char *prompt;
 
 
 
  p=find_word_start(p); prompt=find_word_end(p);
 
  if(*prompt!=0) *prompt++=0;
 
  prompt=find_word_start(prompt);
 
  if(*p==0 || !outputing) return;
 
  if(!trusted_module() || is_class_module) return;
 
  s=getvar(ro_name[ro_session]);
 
  if(s
==NULL 
|| *s
==0 || strstr(s
,"robot")!=NULL
) return;  
  mystrncpy(url,ref_name,sizeof(url));
 
  for(p1
=url
+strlen(url
);p1
>url 
&& *(p1
-1)!='/'; p1
--);  
  if(good_httpd
) snprintf(p1
,sizeof(url
)+p1
-url
,  
              "getfile/%s?&+session=%s&+modif=%ld",
 
              p,s,(long)nowtime);
 
      "%s?cmd=getfile&+session=%s&+special_parm=%s&+modif=%ld",
 
          ref_name,s,p,(long)nowtime);
 
  snprintf(jsbuf
,sizeof(jsbuf
),jsstr
,"wims_file","wims_file");  
 
 
  s=getvar("wims_ref_id");
 
  if(s
!=NULL 
&& *s
!=0 && !isspace(*s
)) {  
    snprintf(sti
,sizeof(sti
)," id=\"%s\"",s
);  
  }
 
  else sti[0]=0;
 
 
 
  s=getvar("wims_ref_class");
 
  if(s
!=NULL 
&& *s
!=0 && !isspace(*s
)) {  
    snprintf(stc
,sizeof(stc
)," class=\"%s\"",s
);  
  }
 
  else stc[0]=0;
 
 
 
  s=getvar("wims_ref_title");
 
  if(s
!=NULL 
&& *s
!=0 && !isspace(*s
)) {  
    snprintf(stt
,sizeof(stt
)," title=\"%s\"",s
);  
  }
 
  else stt[0]=0;
 
 
 
  s=getvar("wims_getfile_fname");
 
  if(s
!=NULL 
&& *s
!=0 && !isspace(*s
)) {  
    snprintf(sgf
,sizeof(sgf
)," download=\"%s\"",s
);  
  }
 
  else sgf[0]=0;
 
 
 
  if(*prompt) output("<a href=\"%s\" %s %s %s %s>%s</a>\n", url,sti,stc,stt,sgf,prompt);
 
  else output("<a href=\"%s\" %s %s %s></a>",url,sti,stc,stt);
 
 
 
  setvar("wims_ref_id","");
 
  setvar("wims_ref_class","");
 
  setvar("wims_ref_title","");
 
  setvar("wims_getfile_fname","");
 
}
 
 
 
/* internal */
 
void count_insert(void)
 
{
 
  insert_no++;
 
  if(insert_no>=INS_LIMIT) module_error("too_many_ins");
 
}
 
 
 
int animated_ins=0;
 
int grouped_ins=0;
 
 
 
/* generic insertion */
 
void _exec_ins(char *p, char *script_name,char *format)
 
{
 
  char *s, *b, *at, *tag, *tag2, *al, *fmt, *mh;
 
  char *p1, *pt;
 
  char buf[1024],buf2[1024],url[MAX_LINELEN+1],altbuf[1024];
 
  char outbuf[1024];
 
  int border, middle, vspace;
 
  long int tel;
 
 
 
  if(robot_access) return;
 
  count_insert(); outbuf[0]=0;
 
  setenv("ins_source",p,1); /* value kept from user tamper */
 
  if(animated_ins) fmt=getvar("anim_format"); else fmt=format;
 
  if(fmt==NULL) fmt="gif";
 
  if(ismhelp) mh="mh"; else mh="";
 
  snprintf(buf
,sizeof(buf
),"%s/insert%s-%d.%s",s2_prefix
,mh
,insert_no
,fmt
);  
  if(grouped_ins) {unlink(buf); goto grouped;}
 
  exportall();
 
  call_ssh("%s/%s %d %s >%s/ins.out 2>%s/ins.err",
 
      bin_dir,script_name,insert_no,tmp_dir,tmp_dir,tmp_dir);
 
  unlink(buf); wrapexec=1;
 
  if(trusted_module()) setenv("trusted_module","yes",1);
 
  else if(untrust) setenv("trusted_module","no",1);
 
  call_ssh("mv %s/insert%s-%d.%s %s >/dev/null 2>/dev/null",
 
       tmp_dir,mh,insert_no,fmt,s2_prefix);
 
  tel=filelength("%s", buf);
 
  if(tel<=5) {
 
    char bbuf[MAX_LINELEN+1];
 
    accessfile(bbuf,"r","%s/ins.err",tmp_dir);
 
    snprintf(url
,sizeof(url
),"gifs/badins.gif");  
    for(p1=bbuf;p1<bbuf+512 && *p1;p1++)
 
      if(*p1=='<' || *p1=='>') *p1='?';
 
    *p1=0;
 
    if(bbuf
[0]==0) snprintf(bbuf
,sizeof(bbuf
),"Fail");  
       " <img src=\"%s\" alt=\"Error\" /> <small><pre>%s</pre></small> <br /> ",
 
       url,bbuf);
 
    setvar("ins_warn","fail");
 
    setvar("ins_cnt","0");
 
    goto reset;
 
  }
 
  grouped:
 
  s=getvar(ro_name[ro_session]);
 
  b=getvar("ins_border"); at=getvar("ins_attr");
 
  tag=getvar("ins_tag");  al=getvar("ins_align");
 
  if(at==NULL) at="";
 
  if(tag==NULL) tag="";
 
  if(al==NULL) al="";
 
  al=find_word_start(al);
 
  if(*al
!=0) snprintf(buf2
,sizeof(buf2
),"vertical-align:%s",al
); else buf2
[0]=0;  
  if(strcasecmp(al,"middle")==0) middle=1; else middle=0;
 
  tag2=""; vspace=0;
 
  if(*tag!=0) {
 
    mystrncpy(buf,tag,sizeof(buf)); tag=find_word_start(buf);
 
    tag2=find_word_end(tag);
 
    if(*tag2!=0) *tag2++=0;
 
    tag2=find_word_start(tag2);
 
  }
 
  if(b==NULL || *b==0) border=0;
 
  if(border<0) border=0;
 
  if(border>100) border=100;
 
  if(middle) {
 
       sizeof(outbuf
)-strlen(outbuf
),"%s",mathalign_sup1
);  
    vspace=2;
 
  }
 
  mystrncpy(url,ref_name,sizeof(url));
 
  for(p1
=url
+strlen(url
);p1
>url 
&& *(p1
-1)!='/'; p1
--);  
         "wims.%s?cmd=getins&+session=%s&+special_parm=insert%s-%d.%s&+modif=%ld",
 
         fmt,s,mh,insert_no,fmt,(long)nowtime);
 
  if(strchr(ins_alt
,'"')!=NULL 
|| strlen(ins_alt
)>256) ins_alt
[0]=0;  
  pt=getvar("wims_ins_alt"); if(pt==NULL) pt="";
 
  if(strcmp(pt
,"empty")==0) altbuf
[0]=0;  
  else
 
    if(ins_alt
[0] && strcmp(pt
,"none")!=0)  
      snprintf(altbuf
,sizeof(altbuf
)," alt=\"\"");  
    else
 
      snprintf(altbuf
,sizeof(altbuf
)," alt=\"%s\"",ins_alt
);  
  if(strcasecmp(tag,"form")!=0) {
 
       "<img src=\"%s\" style=\"border:solid;border-width:%dpx;margin-bottom:%dpx;%s\" %s %s />",
 
       url, border, vspace, buf2, at, altbuf);
 
  }
 
  else {
 
    char *n, *nend;
 
/* fix: add quotes at name=" " */
 
    if(*tag2!=0) {n="name=\"" ; nend="\"";} else {n=""; nend="";}
 
        "<input type=\"image\" %s%s%s src=\"%s\" style=\"border:solid;border-width:%dpx;margin-bottom:%dpx;%s\" %s %s />",
 
        n,tag2,nend,url,border,vspace,buf2,at,altbuf);
 
  }
 
           sizeof(outbuf
)-strlen(outbuf
),"%s",mathalign_sup2
);  
  setvar("ins_warn",""); ins_alt[0]=0;
 
  setvar("ins_cnt",int2str(insert_no));
 
  reset:
 
  if(outputing) _output_(outbuf);
 
  setvar("ins_out",outbuf);
 
  setvar("ins_attr",""); setvar("ins_tag","");
 
  setvar("ins_url",url);
 
  snprintf(buf2
,sizeof(buf2
),"insert%s-%d.%s",mh
,insert_no
,fmt
);  
  setvar("ins_filename",buf2);
 
  animated_ins=0;
 
}
 
 
 
/* instex: dynamically insert tex outputs */
 
void exec_instex(char *p)
 
{
 
  char *ts, *tc, *f, *mh, buf[MAX_FNAME+1];
 
 
 
  if(robot_access) {
 
    *p=0; return;
 
  }
 
  f=instex_check_static(p); substit(p);
 
  if(f==NULL) {
 
/* Use static instex if there is no real substitution
 
 * and the source file is not in sessions directory.
 
 */
 
    calc_instexst(p); if(outputing) _output_(p);
 
    return;
 
  }
 
  if(ismhelp) mh="mh"; else mh="";
 
  fix_tex_size(); f="gif";
 
  setenv("texgif_style",instex_style,1);
 
  tc=getvar("instex_texheader"); if (tc) { setenv("texgif_texheader",tc,1);}
 
  setenv("texgif_tmpdir",tmp_dir,1);
 
  setenv("texgif_src",p,1);
 
  if(ins_alt[0]==0) mystrncpy(ins_alt,p,sizeof(ins_alt));
 
  mkfname(buf,"%s/insert%s-%d.gif",tmp_dir,mh,insert_no+1);
 
  setenv("texgif_outfile",buf,1);
 
  ts=getvar("wims_texsize"); tc=getvar("instex_color");
 
  if(lastout_file!=-1 && (tc==NULL || *tc==0) &&
 
      (ts
==NULL 
|| *ts
==0 || strcmp(ts
,"0")==0) &&  
    int ls, ln;
 
    char *pagebreak;
 
    if(ls
+strlen(p
)>=MAX_LINELEN
-256 ||  
     ln
+strlen(buf
)>=MAX_LINELEN
-16) { 
        instex_flush(); ls=ln=0;
 
    }
 
    if(instex_cnt>0) pagebreak="\\pagebreak\n"; else pagebreak="";
 
    snprintf(instex_src
+ls
,MAX_LINELEN
-ls
,"%s %s %s %s\n",  
         pagebreak,instex_style,p,instex_style);
 
    snprintf(instex_fname
+ln
,MAX_LINELEN
-ln
,"%s\n",buf
);  
      grouped_ins=1;
 
  }
 
  mkfname(buf,"%s/texgif.dvi",tmp_dir); unlink(buf);
 
  wrapexec=0; _exec_ins(p,instex_processor,f);
 
  if(grouped_ins) instex_cnt++;
 
  grouped_ins=0;
 
}
 
 
 
/* patches the gnuplot integer division (mis)feature. */
 
void gnuplot_patch(char *p,int oneline)
 
{
 
  char *pp;
 
    char *p1;
 
    if(pp<=p || !myisdigit(*(pp-1)) || !myisdigit(*(pp+1))) continue;
 
    for(p1=pp-2;p1>=p && myisdigit(*p1);p1--);
 
    if(p1>=p && *p1=='.') continue;
 
    for(p1=pp+2;*p1 && myisdigit(*p1);p1++);
 
    if(*p1=='.') continue;
 
    string_modify(p,p1,p1,".0");
 
  }
 
    string_modify(p,pp,pp+1,"**");
 
/* disallow new lines and ';' */
 
  if(oneline)
 
    for(pp=p;*pp!=0;pp++) if(*pp==';' || *pp=='\n') *pp=' ';
 
}
 
 
 
/* This is to disable pipe in the gnuplot plotting function.
 
 * We do not allow ' followed by < .
 
 */
 
void prepare_insplot_parm(char *p)
 
{
 
  int i,j,multanim; char *pp, *s;
 
  double d;
 
  char setbuf[MAX_LINELEN
+10],buf
[MAX_LINELEN
+1];  
 
 
/* pipe in plot command */
 
  for(i=0;i<j;i++) {
 
    if(*(p+i)!='\'' && *(p+i)!='"') continue;
 
    pp=find_word_start(p+i+1); if(*pp=='<') module_error("illegal_plot_cmd");
 
  }
 
  gnuplot_patch(p,1);
 
/* multiplot */
 
  multanim=0;
 
  pp=getvar("insplot_split");
 
  if(pp!=NULL) i=linenum(pp); else i=0;
 
/* arbitrary limit: 16 multiplots */
 
  if(i>16) i=16;
 
  if(i>1) {
 
    char tbuf[MAX_LINELEN*(i+1)+100], bbuf[MAX_LINELEN+1];
 
    tbuf[0]=0;
 
    if(*p
!=0) snprintf(tbuf
,sizeof(tbuf
),"%s\n",p
);  
    snprintf(buf
,sizeof(buf
),"%d",i
); setenv
("multiplot",buf
,1);  
    for(j=1;j<=i;j++) {
 
      snprintf(buf
,sizeof(buf
),"insplot_parm_%d",j
);  
      pp=getvar(buf);
 
      if(pp==NULL || *pp==0) {
 
        if(j==1 && *p!=0) continue;
 
        pp="";
 
      }
 
      else {
 
        mystrncpy(bbuf,pp,sizeof(bbuf));
 
        gnuplot_patch(bbuf,1);
 
      }
 
    }
 
    setenv("insplot_source",tbuf,1);
 
    if(varchr(tbuf,"s")!=NULL) multanim=1;
 
  }
 
/* no illegal chaining */
 
  pp=getvar("insplot_font"); if(pp!=NULL) {
 
    for(s=pp;s<pp+MAX_LINELEN && *s;s++)
 
    if(*s==';' || *s=='\n' || *s==' ') *s=0;
 
    if(s>=pp+MAX_LINELEN) *s=0;
 
    setvar("insplot_font",pp);
 
  }
 
  pp=getvar("insplot_set");
 
  if(pp!=NULL) {
 
    char tbuf[MAX_LINELEN+1];
 
    mystrncpy(tbuf,pp,sizeof(tbuf));
 
    while(i
>0 && isspace(tbuf
[i
])) i
--;  
    if(tbuf[i]==';') tbuf[i]=0;
 
    gnuplot_patch(tbuf,0);pp=tbuf;
 
    for(i=0; *(pp+i)!=0 && j<MAX_LINELEN; i++) {
 
      if(*(pp
+i
)=='\n') {setbuf[j
++]=' '; continue;}  
      if(*(pp
+i
)!=';') {setbuf[j
++]=*(pp
+i
); continue;}  
    }
 
    setenv
("insplot_set",setbuf,1); 
  }
 
  else setenv("insplot_set","",1);
 
/* frames of animation */
 
  pp=getvar("ins_anim_frames");
 
  if(pp!=NULL) i=evalue(pp); else i=1;
 
  if(i>=ANIM_LIMIT) i=ANIM_LIMIT-1;
 
  if(i<1) i=1;
 
     && varchr
(setbuf,"s")==NULL 
&& varchr
(p
,"s")==NULL 
&& !multanim
) i
=1;  
  setenv("ins_anim_frames",int2str(i),1);
 
  setvar("ins_anim_frames","");
 
  if(i>1) {setvar("ins_animation","yes");animated_ins=1;}
 
  else setvar("ins_animation","no");
 
/* delay of animation */
 
  pp=getvar("ins_anim_delay");
 
  if(pp!=NULL) d=evalue(pp); else d=0;
 
  if(d>=10) d=10;
 
  if(d<0) d=0;
 
  setenv("ins_anim_delay",int2str(d*100),1);
 
}
 
 
 
/* Insert dynamic 2d plot */
 
void exec_insplot(char *p)
 
{
 
  char *fmt;
 
  if(robot_access) {
 
    *p=0; return;
 
  }
 
  fmt=getvar("ins_format"); if(fmt==NULL || *fmt==0) fmt=DEFAULT_INS_FORMAT;
 
  prepare_insplot_parm(p); setenv("insplot_method","2D",1);
 
  _exec_ins(p,insplot_processor,fmt);
 
  wrapexec=1;
 
/*    call_ssh("mv %s/insplot_cmd %s 2>/dev/null",tmp_dir,s2_prefix); */
 
   unsetenv("multiplot"); setvar("insplot_split","");
 
}
 
 
 
/* Insert dynamic 3d plot */
 
void exec_insplot3d(char *p)
 
{
 
  char *fmt;
 
  if(robot_access) {
 
    *p=0; return;
 
  }
 
  fmt=getvar("ins_format"); if(fmt==NULL || *fmt==0) fmt=DEFAULT_INS_FORMAT;
 
  prepare_insplot_parm(p); setenv("insplot_method","3D",1);
 
  _exec_ins(p,insplot_processor,fmt);
 
  wrapexec=1;
 
/*     call_ssh("mv %s/insplot_cmd %s 2>/dev/null",tmp_dir,s2_prefix); */
 
  unsetenv("multiplot");setvar("insplot_split","");
 
}
 
 
 
/* Insert dynamic gif draw. The parm preparation is specific to fly. */
 
void exec_insdraw(char *p)
 
{
 
  char *pp, *fmt;
 
  int i;
 
  double d;
 
 
 
  if(robot_access) {
 
    *p=0; return;
 
  }
 
/*    calc_tolower(p);*/
 
  fmt=getvar("ins_format"); if(fmt==NULL || *fmt==0) fmt=DEFAULT_INS_FORMAT;
 
  while((pp
=wordchr
(p
,"output"))!=NULL
) memmove(pp
,"zqkwfx",6);  
/* frames of animation */
 
  pp=getvar("ins_anim_frames");
 
  if(pp!=NULL) i=evalue(pp); else i=1;
 
  if(i>=ANIM_LIMIT) i=ANIM_LIMIT-1;
 
  if(i<1) i=1;
 
  if(i>1 && varchr(p,"s")==NULL && varchr(p,"animstep")==NULL
 
     && varchr(p,"step")==NULL) i=1;
 
  setenv("ins_anim_frames",int2str(i),1);
 
  setvar("ins_anim_frames","");
 
  if(i>1) {setvar("ins_animation","yes");animated_ins=1;}
 
  else setvar("ins_animation","no");
 
/* delay of animation */
 
  pp=getvar("ins_anim_delay");
 
  if(pp!=NULL) d=evalue(pp); else d=0;
 
  if(d>=10) d=10;
 
  if(d<0) d=0;
 
  setenv("ins_anim_delay",int2str(d*100),1);
 
  pp=getvar("insdraw_filebase");
 
  if(pp
!=NULL 
&& strstr(pp
,parent_dir_string
)!=NULL
)  
    setvar("insdraw_filebase","");
 
  _exec_ins(p,insdraw_processor,fmt);
 
}
 
 
 
void exec_increase(char *p)
 
{
 
  char *p1, *p2;
 
  p1=find_word_start(p); p2=find_word_end(p1);
 
  if(p2<=p1) {
 
    *p=0; return;
 
  }
 
  *p2=0;p2=getvar(p1);
 
  if(p2==NULL) p2="";
 
  setvar
(p1
,int2str
(atoi(p2
)+1)); *p
=0; 
}
 
 
 
void exec_setseed(char *p)
 
{
 
  char buf[64];
 
  force_setvar("wims_seed",buf);
 
  double d=evalue(p);
 
  srandom(d); *p=0;
 
}
 
 
 
/* bound a variable */
 
void exec_bound(char *p)
 
{
 
  char *p1, *p2, *p3;
 
  int doub,i,bcnt,defaulted;
 
  double d1,d2,dd,val;
 
  char nbuf[MAX_LINELEN+1],lbuf[MAX_LINELEN+1],dbuf[MAX_LINELEN+1];
 
  char vbuf[MAX_LINELEN+1];
 
  char *blist[2048];
 
 
 
  p1=find_word_start(p); p2=find_word_end(p1);
 
  if(*p2==0) {
 
    syntax: module_error("syntax_error");
 
  }
 
  *p2=0; ovlstrcpy(nbuf,p1);substit(nbuf); p1=find_word_start(p2+1);
 
  p2=getvar(nbuf);if(p2==NULL) p2="";
 
  mystrncpy(vbuf,find_word_start(p2),sizeof(vbuf));
 
  strip_trailing_spaces(vbuf);
 
  p2=find_word_end(p1); if(*p2==0) goto syntax;
 
  *p2=0;p2++;
 
  p3=wordchr(p2,"default");
 
  if(p3!=NULL) {
 
    *p3=0; defaulted=1;
 
    p3
=find_word_start
(p3
+strlen("default")); 
    ovlstrcpy(dbuf,p3); substit(dbuf);
 
  }
 
  else defaulted=0;
 
    p1=find_word_start(p2);
 
      doub=0; p1=find_word_start(find_word_end(p1));
 
      val=rint(evalue(vbuf));
 
      if(vbuf[0]) float2str(val,vbuf);
 
    }
 
    else {
 
      doub=1;val=evalue(vbuf);
 
    }
 
    p2
=wordchr
(p1
,"and"); p3
=p2
+strlen("and"); 
    if(p2==NULL) {
 
    }
 
    if(p2==NULL) goto syntax;
 
   *p2=0;p2=find_word_start(p3);
 
    if(*p1==0 || *p2==0) goto syntax;
 
    d1=evalue(p1);d2=evalue(p2);
 
    if(!isfinite(d1) || !isfinite(d2) ||
 
      fabs(d1
)>(double)(1E10) || fabs(d2
)>(double)(1E10)) goto syntax
;  
    if(d1>d2) {
 
      dd=d1;d1=d2;d2=dd;
 
    }
 
    if(vbuf[0] && val<=d2 && val>=d1) {
 
      if(!doub) setvar(nbuf,vbuf);
 
      *p=0; return;
 
    }
 
    if(defaulted) ovlstrcpy(p,dbuf);
 
    else {
 
      if(!doub) {
 
      }
 
      if(vbuf[0]==0 || val<d1) val=d1;
 
      else val=d2;
 
      float2str(val,p);
 
    }
 
    setvar(nbuf,p); *p=0; return;
 
  }
 
  else {
 
      ovlstrcpy(lbuf,p2);substit(lbuf);
 
      bcnt=cutitems(lbuf,blist,2048);
 
      if(bcnt<=0) {
 
        *p=0; return;
 
      }
 
      for(i=0;i<bcnt;i++) {
 
        if(strcmp(blist
[i
],vbuf
)==0) {  
          *p=0; return;
 
        }
 
      }
 
      if(defaulted) ovlstrcpy(p,dbuf); else ovlstrcpy(p,blist[0]);
 
      setvar(nbuf,p); *p=0;
 
      return;
 
    }
 
  else goto syntax;
 
  }
 
}
 
 
 
/* detrust the module. */
 
void exec_detrust(char *p)
 
{
 
  untrust|=1; *p=0;
 
}
 
 
 
void exec_warn(char *p)
 
{
 
  char *p1,*p2;
 
  char buf[MAX_FNAME+1];
 
  WORKING_FILE save;
 
 
 
  if(!outputing) goto end;
 
  p1=find_word_start(p);p2=find_word_end(p1);
 
  if(p2<=p1) goto end;
 
  *p2=0;
 
  snprintf(buf
,sizeof(buf
),"wims_warn_%s",p1
);  
  p2=getvar(buf);
 
  if(p2==NULL || *p2==0) goto end;
 
  p2=getvar("module_language");if(p2==NULL) p2="en";
 
  mkfname(buf,"msg/warn_%s.phtml.%s",p1,p2);
 
  memmove(&save
,&m_file
,sizeof(WORKING_FILE
));  
  if(open_working_file(&m_file,buf)==0) phtml_put(NULL,0);
 
  memmove(&m_file
,&save
,sizeof(WORKING_FILE
));  
  end:
 
  *p=0; return;
 
}
 
 
 
/* write an error message. */
 
void exec_msg(char *p)
 
{
 
  char *p1,*p2, buf[64], *l;
 
  secure_exec();
 
  p1=find_word_start(p); p2=find_word_end(p1);
 
  if(*p2) {
 
    *p2=0; p2=find_word_start(p2+1);
 
  }
 
  force_setvar("wims_error",p1); force_setvar("wims_error_parm",p2);
 
  l=getvar("module_language");
 
    snprintf(buf
,sizeof(buf
),"msg.phtml.%s",l
);  
    phtml_put_base(buf,0);
 
  }
 
  *p=0;
 
}
 
 
 
struct distr_cmd distr_cmd[]={
 
  {"char",      NULL},
 
  {"charof",    NULL},
 
  {"chars",     NULL},
 
  {"charsof",   NULL},
 
  {"item",      cutitems},
 
  {"itemof",    cutitems},
 
  {"items",     cutitems},
 
  {"itemsof",   cutitems},
 
  {"line",      cutlines},
 
  {"lineof",    cutlines},
 
  {"lines",     cutlines},
 
  {"linesof",   cutlines},
 
  {"list",      cutitems},
 
  {"word",      cutwords},
 
  {"wordof",    cutwords},
 
  {"words",     cutwords},
 
  {"wordsof",   cutwords}
 
};
 
 
 
int distr_cmd_no=(sizeof(distr_cmd)/sizeof(distr_cmd[0]));
 
 
 
/* distribute a number of lines, items, etc. into a list of vars. */
 
void exec_distribute(char *p)
 
{
 
  int i,k,n;
 
  char *p1, *p2;
 
  char bf1[MAX_LINELEN+1],bf2[MAX_LINELEN+1];
 
  char *names[4096],*vals[4096];
 
  p1=find_word_start(p); p2=find_word_end(p1);
 
  if(p2<=p1 || *p2==0) module_error("syntax_error");
 
  *p2++=0;
 
  i=search_list(distr_cmd,distr_cmd_no,sizeof(distr_cmd[0]),p1);
 
  if(i<0) module_error("syntax_error");
 
  p2=find_word_start(p2); p1=wordchr(p2,"into");
 
  if(p1==NULL) module_error("syntax_error");
 
  *p1=0;mystrncpy(bf1,p2,sizeof(bf1));
 
  p1
=find_word_start
(p1
+strlen("into")); 
  mystrncpy(bf2,p1,sizeof(bf2));
 
  substit(bf1);substit(bf2);
 
  strip_trailing_spaces(bf1);
 
  items2words(bf2); n=cutwords(bf2,names,4096);
 
  if(distr_cmd[i].routine!=NULL) {
 
    k=distr_cmd[i].routine(bf1,vals,n);
 
    for(i=0;i<k;i++) setvar(names[i],vals[i]);
 
    for(;i<n;i++) setvar(names[i],"");
 
  }
 
  else {
 
    char buf[2];
 
    buf[1]=0;
 
    for(p1=bf1,i=0;i<n;i++) {
 
      buf[0]=*p1; if(*p1) p1++;
 
      setvar(names[i],buf);
 
    }
 
  }
 
}
 
 
 
/* reset variables */
 
void exec_reset(char *p)
 
{
 
  char *p1, *p2;
 
 
 
  items2words(p);
 
  for(p1=find_word_start(p); *p1; p1=find_word_start(p2)) {
 
    p2=find_word_end(p1); if(*p2) *p2++=0;
 
    setvar(p1,"");
 
  }
 
}
 
 
 
/* exchange the values of two variables */
 
void exec_exchange(char *p)
 
{
 
  char buf[MAX_LINELEN+1],b1[MAX_LINELEN+1],b2[MAX_LINELEN+1];
 
  char *p1,*p2,*pb;
 
  p1=wordchr(p,"and");
 
  if(p1!=NULL) {
 
    *p1
=0; p2
=find_word_start
(p1
+strlen("and"));  
  }
 
  else {
 
    if(p1==NULL) module_error("syntax_error");
 
    *p1=0; p2=find_word_start(p1+1);
 
  }
 
  p1=find_word_start(p);
 
  mystrncpy(b1,p1,sizeof(b1)); substit(b1); *find_word_end(b1)=0;
 
  mystrncpy(b2,p2,sizeof(b2)); substit(b2); *find_word_end(b2)=0;
 
  if(*b1==0 || *b2==0) module_error("syntax_error");
 
  pb=getvar(b1);if(pb==NULL) pb="";
 
  mystrncpy(buf,pb,sizeof(buf));
 
  pb=getvar(b2);if(pb==NULL) pb="";
 
  setvar(b1,pb); setvar(b2,buf);
 
}
 
 
 
/* Send a mail */
 
void exec_mailto(char *p)
 
{
 
  char *p1,*p2,*pp;
 
 
 
  if(!trusted_module() || is_class_module) return;
 
  p1
=strchr(p
,'\n'); if(p1
==NULL
) return; 
  *p1++=0; p=find_word_start(p);
 
  if(*p==0) return;
 
  p2
=strchr(p1
,'\n'); if(p2
==NULL
) return; 
  *p2++=0;
 
  for(pp=p1;*pp;pp++) if(*pp=='"' || *pp=='\n') *pp=' ';
 
  accessfile(p2,"w","%s/mail.body",tmp_dir);
 
  wrapexec=1;
 
  call_sh("mail %s -s \" %s \nContent-Type: text/html\" %s <%s/mail.body; chmod og-rwx %s/mail.body",
 
      mail_opt, p1,p,tmp_dir,tmp_dir);
 
  mail_log(p);
 
  *p=0;
 
}
 
 
 
/* Generates a user error. Internal and undocumented. */
 
void exec_usererror(char *p)
 
{
 
  if(trusted_module()) user_error(p);
 
}
 
 
 
/* stop output. */
 
void exec_directout(char *p)
 
{
 
  if(outputing || !trusted_module()) return;
 
  noout=1;
 
}
 
 
 
enum {
 
  EXEC_IF, EXEC_JUMP, EXEC_ELSE, EXEC_ENDIF, EXEC_EXEC,
 
  EXEC_WHILE, EXEC_ENDWHILE,
 
  EXEC_FOR, EXEC_VAR, EXEC_DEBUG, EXEC_DAEMON,
 
  EXEC_SET, EXEC_DEFAULT, EXEC_COMMENT, EXEC_READ, EXEC_HREF,
 
  EXEC_INS, EXEC_STRING, EXEC_PEDIA, EXEC_DIR,
 
  EXEC_TRUST, EXEC_WARN, EXEC_ERROR, EXEC_SQL, EXEC_SCORE,
 
  EXEC_MAIL, EXEC_OTHER
 
} EXEC_TYPES;
 
#define EXEC_SUBST 0x1000
 
#define EXEC_USECALC 0x2000
 
#define EXEC_PROCTOO 0x4000
 
MYFUNCTION exec_routine[]={
 
  {"!",        EXEC_COMMENT,        exec_comment},
 
  {"TeXmath",  EXEC_STRING|EXEC_SUBST|EXEC_USECALC,texmath},
 
  {"add",      EXEC_STRING|EXEC_USECALC,calc_sum},
 
  {"advance",  EXEC_VAR|EXEC_SUBST,   exec_increase},
 
  {"append",   EXEC_STRING|EXEC_USECALC,calc_append},
 
  {"appendfile",EXEC_DIR|EXEC_SUBST,    fileappend},
 
  {"bound",     EXEC_STRING,       exec_bound},
 
  {"break",     EXEC_FOR,        exec_break},
 
  {"call",      EXEC_EXEC|EXEC_SUBST|EXEC_PROCTOO|EXEC_USECALC,    calc_exec},
 
  {"changeto",  EXEC_READ|EXEC_SUBST,    exec_changeto},
 
  {"char",      EXEC_STRING|EXEC_USECALC,calc_charof},
 
  {"chars",     EXEC_STRING|EXEC_USECALC,calc_charof},
 
  {"checkhost", EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_checkhost},
 
  {"column",    EXEC_STRING|EXEC_USECALC,calc_columnof},
 
  {"columns",   EXEC_STRING|EXEC_USECALC,calc_columnof},
 
  {"comment",   EXEC_COMMENT,        exec_comment},
 
  {"daemon",    EXEC_DAEMON|EXEC_USECALC|EXEC_SUBST,calc_daemon},
 
  {"date",      EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_date},
 
  {"deaccent",  EXEC_STRING|EXEC_USECALC|EXEC_SUBST,deaccent},
 
  {"debug",     EXEC_DEBUG,        calc_debug},
 
  {"declosing", EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_declosing},
 
  {"def",       EXEC_SET,        exec_set},
 
  {"default",   EXEC_SET,        exec_default},
 
  {"define",    EXEC_SET,        exec_set},
 
  {"definitionof", EXEC_SCORE|EXEC_USECALC,calc_defof},
 
  {"defof",     EXEC_SCORE|EXEC_USECALC,calc_defof},
 
  {"defread",   EXEC_READ|EXEC_SUBST,    exec_defread},
 
  {"detag",     EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_detag},
 
  {"detrust",   EXEC_TRUST,        exec_detrust},
 
/*      {"dictionary",EXEC_STRING|EXEC_USECALC,calc_dictionary},    */
 
  {"dir",       EXEC_DIR|EXEC_SUBST|EXEC_USECALC,calc_listfile},
 
  {"distribute",EXEC_STRING,        exec_distribute},
 
  {"distrust",  EXEC_TRUST,        exec_detrust},
 
  {"else",      EXEC_ELSE,        exec_else},
 
  {"embraced",  EXEC_STRING|EXEC_USECALC,calc_embraced},
 
  {"encyclo",   EXEC_PEDIA|EXEC_SUBST|EXEC_USECALC,pedia},
 
  {"encyclopedia",EXEC_PEDIA|EXEC_SUBST|EXEC_USECALC,pedia},
 
  {"endif",     EXEC_ENDIF,        exec_endif},
 
  {"endwhile",  EXEC_ENDWHILE,        exec_endwhile},
 
  {"evalsubst", EXEC_STRING|EXEC_USECALC,calc_evalsubst},
 
  {"evalsubstit",EXEC_STRING|EXEC_USECALC,calc_evalsubst},
 
  {"evalsubstitute",EXEC_STRING|EXEC_USECALC,calc_evalsubst},
 
  {"evaluesubst",EXEC_STRING|EXEC_USECALC,calc_evalsubst},
 
  {"evaluesubstit",EXEC_STRING|EXEC_USECALC,calc_evalsubst},
 
  {"evaluesubstitute",EXEC_STRING|EXEC_USECALC,calc_evalsubst},
 
  {"examscore", EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_examscore},
 
  {"exchange",  EXEC_STRING,        exec_exchange},
 
  {"exec",      EXEC_EXEC|EXEC_SUBST|EXEC_PROCTOO|EXEC_USECALC,    calc_exec},
 
  {"execute",   EXEC_EXEC|EXEC_SUBST|EXEC_PROCTOO|EXEC_USECALC,    calc_exec},
 
  {"exit",      EXEC_JUMP,        exec_exit},
 
  {"fileappend",EXEC_DIR|EXEC_SUBST,    fileappend},
 
  {"fileexists",EXEC_STRING|EXEC_USECALC, calc_fileexists},
 
  {"filelist",  EXEC_DIR|EXEC_SUBST|EXEC_USECALC,calc_listfile},
 
  {"fileout",   EXEC_HREF|EXEC_SUBST,    exec_getfile},
 
  {"filewrite", EXEC_DIR|EXEC_SUBST,    filewrite},
 
  {"filexists",EXEC_STRING|EXEC_USECALC, calc_fileexists},
 
  {"for",       EXEC_FOR,        exec_for},
 
  {"form",      EXEC_HREF|EXEC_SUBST,    exec_form},
 
  {"formbar",   EXEC_HREF,        exec_formbar},
 
  {"formcheckbox",EXEC_HREF,        exec_formcheckbox},
 
  {"formend",   EXEC_STRING,    exec_formend},
 
  {"formradio", EXEC_HREF,        exec_formradio},
 
  {"formradiobar",EXEC_HREF,        exec_formbar},
 
  {"formselect",EXEC_HREF,        exec_formselect},
 
  {"getdef",    EXEC_SCORE|EXEC_USECALC,calc_defof},
 
  {"getfile",   EXEC_HREF|EXEC_SUBST,    exec_getfile},
 
  {"getscore",  EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscore},
 
  {"getscorebest",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscorebest},
 
  {"getscorelast",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscorelast},
 
  {"getscorelevel",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscorelevel},
 
  {"getscoremean",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscoremean},
 
  {"getscorepercent",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscorepercent},
 
  {"getscorequality",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscoremean},
 
  {"getscoreremain",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscoreremain},
 
  {"getscorerequire",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscorerequire},
 
  {"getscoretry",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscoretry},
 
  {"getscoreweight",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscoreweight},
 
  {"goto",      EXEC_JUMP|EXEC_SUBST,    exec_goto},
 
  {"header",    EXEC_HREF,        exec_header},
 
  {"header1",   EXEC_HREF,        exec_header1},
 
  {"headmenu",  EXEC_HREF,        exec_headmenu},
 
  {"hex",       EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_hex},
 
  {"homeref",   EXEC_HREF,        exec_homeref},
 
  {"href",      EXEC_HREF,        exec_href},
 
  {"html2iso",  EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_html2iso},
 
  {"htmlbar",   EXEC_HREF,        exec_formbar},
 
  {"htmlcheckbox",EXEC_HREF,        exec_formcheckbox},
 
  {"htmlheader",EXEC_HREF,        exec_header},
 
  {"htmlmath",  EXEC_STRING|EXEC_SUBST|EXEC_USECALC,htmlmath},
 
  {"htmlradio", EXEC_HREF,        exec_formradio},
 
  {"htmlradiobar",EXEC_HREF,        exec_formbar},
 
  {"htmlselect",EXEC_HREF,        exec_formselect},
 
  {"htmltail",  EXEC_HREF,        exec_tail},
 
  {"htmltitle", EXEC_HREF,        exec_title},
 
  {"if",        EXEC_IF,        exec_if},
 
  {"ifval",     EXEC_IF,        exec_ifval},
 
  {"ifvalue",   EXEC_IF,        exec_ifval},
 
  {"imgrename", EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_imgrename},
 
  {"include",   EXEC_READ|EXEC_SUBST,   exec_read},
 
  {"increase",  EXEC_VAR|EXEC_SUBST,    exec_increase},
 
  {"input",     EXEC_READ|EXEC_SUBST,    exec_read},
 
  {"insdraw",   EXEC_INS|EXEC_SUBST,    exec_insdraw},
 
  {"insmath",   EXEC_INS,        insmath},
 
  {"inspaint",  EXEC_INS|EXEC_SUBST,    exec_insdraw},
 
  {"insplot",   EXEC_INS|EXEC_SUBST,    exec_insplot},
 
  {"insplot3d", EXEC_INS|EXEC_SUBST,    exec_insplot3d},
 
  {"instex",    EXEC_INS,        exec_instex},
 
  {"instexst",  EXEC_INS|EXEC_USECALC,    calc_instexst},
 
  {"instexstatic",EXEC_INS|EXEC_USECALC,    calc_instexst},
 
  {"item",        EXEC_STRING|EXEC_USECALC,calc_itemof},
 
  {"items",     EXEC_STRING|EXEC_USECALC,calc_itemof},
 
  {"items2lines", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2lines},
 
  {"items2words",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2words},
 
  {"itemstolines",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2lines},
 
  {"itemstowords",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2words},
 
  {"let",        EXEC_SET,        exec_set},
 
  {"leveldata",  EXEC_STRING|EXEC_USECALC,calc_leveldata},
 
  {"levelpoints",EXEC_STRING|EXEC_USECALC,calc_leveldata},
 
  {"line",       EXEC_STRING|EXEC_USECALC,calc_lineof},
 
  {"lines",      EXEC_STRING|EXEC_USECALC,calc_lineof},
 
  {"lines2items",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,lines2items},
 
  {"lines2list", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,lines2items},
 
  {"lines2words",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,lines2words},
 
  {"linestoitems",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,lines2items},
 
  {"linestolist",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,lines2items},
 
  {"linestowords",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,lines2words},
 
  {"list2lines", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2lines},
 
  {"list2words", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2words},
 
  {"listfile",   EXEC_DIR|EXEC_SUBST|EXEC_USECALC,calc_listfile},
 
  {"listfiles",  EXEC_DIR|EXEC_SUBST|EXEC_USECALC,calc_listfile},
 
  {"listintersect",EXEC_STRING|EXEC_USECALC,calc_listintersect},
 
  {"listintersection", EXEC_STRING|EXEC_USECALC,calc_listintersect},
 
  {"listtolines",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2lines},
 
  {"listtowords",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,items2words},
 
  {"listunion",  EXEC_STRING|EXEC_USECALC,calc_listunion},
 
  {"listuniq",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_listuniq},
 
  {"listunique", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_listuniq},
 
  {"listvar",    EXEC_STRING|EXEC_SUBST|EXEC_USECALC,mathvarlist},
 
  {"lookup",     EXEC_STRING|EXEC_USECALC,    calc_lookup},
 
  {"lower",      EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_tolower},
 
  {"lowercase",  EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_tolower},
 
  {"ls",         EXEC_DIR|EXEC_SUBST|EXEC_USECALC,calc_listfile},
 
  {"mailto",     EXEC_MAIL|EXEC_SUBST,    exec_mailto},
 
  {"mailurl",    EXEC_MAIL|EXEC_SUBST|EXEC_USECALC,calc_mailurl},
 
  {"makelist",   EXEC_STRING|EXEC_USECALC,calc_makelist},
 
  {"math2html",  EXEC_STRING|EXEC_SUBST|EXEC_USECALC,htmlmath},
 
  {"math2mathml",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,mathmlmath},
 
  {"math2tex",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,texmath},
 
  {"mathmlmath", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,mathmlmath},
 
  {"mathsubst",  EXEC_STRING|EXEC_USECALC,calc_mathsubst},
 
  {"mathsubstit",EXEC_STRING|EXEC_USECALC,calc_mathsubst},
 
  {"mathsubstitute",EXEC_STRING|EXEC_USECALC,calc_mathsubst},
 
  {"mexec",     EXEC_EXEC|EXEC_SUBST,    exec_mexec},
 
  {"module",    EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_module},
 
  {"msg",       EXEC_EXEC|EXEC_SUBST,exec_msg},
 
  {"multiply",  EXEC_STRING|EXEC_USECALC,calc_product},
 
  {"next",      EXEC_FOR,        exec_next},
 
  {"nocache",   EXEC_READ,        exec_nocache},
 
  {"non_empty", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_nonempty},
 
  {"nonempty",  EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_nonempty},
 
  {"nospace",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,nospace},
 
  {"outfile",   EXEC_HREF|EXEC_SUBST,    exec_getfile},
 
  {"pedia",     EXEC_PEDIA|EXEC_SUBST|EXEC_USECALC,pedia},
 
  {"perl",      EXEC_EXEC|EXEC_PROCTOO|EXEC_SUBST,exec_perl},
 
  {"position",  EXEC_STRING|EXEC_USECALC,calc_pos},
 
  {"positionof",EXEC_STRING|EXEC_USECALC,calc_pos},
 
  {"positions", EXEC_STRING|EXEC_USECALC,calc_pos},
 
  {"prod",      EXEC_STRING|EXEC_USECALC,calc_product},
 
  {"product",   EXEC_STRING|EXEC_USECALC,calc_product},
 
  {"rawmath",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,rawmath},
 
  {"rawmatrix", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,rawmatrix},
 
  {"reaccent",  EXEC_STRING|EXEC_USECALC|EXEC_SUBST,reaccent},
 
  {"read",      EXEC_READ|EXEC_SUBST,    exec_read},
 
  {"readdef",   EXEC_READ|EXEC_SUBST,    exec_defread},
 
  {"readproc",  EXEC_READ|EXEC_SUBST,    exec_readproc},
 
  {"record",    EXEC_STRING|EXEC_USECALC,calc_recordof},
 
  {"records",   EXEC_STRING|EXEC_USECALC,calc_recordof},
 
  {"recursion", EXEC_STRING|EXEC_USECALC,calc_recursion},
 
  {"reinput",   EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_reinput},
 
  {"rem",       EXEC_COMMENT,        exec_comment},
 
  {"remark",    EXEC_COMMENT,        exec_comment},
 
  {"replace",   EXEC_STRING|EXEC_USECALC,calc_replace},
 
  {"reset",     EXEC_SET|EXEC_SUBST,    exec_reset},
 
  {"restart",   EXEC_JUMP|EXEC_SUBST,    exec_restart},
 
  {"return",    EXEC_JUMP,        exec_exit},
 
  {"robotrap",  EXEC_HREF|EXEC_SUBST,    exec_robottrap},
 
  {"robottrap", EXEC_HREF|EXEC_SUBST,    exec_robottrap},
 
  {"rootof",    EXEC_STRING|EXEC_USECALC,calc_solve},
 
  {"row",       EXEC_STRING|EXEC_USECALC,calc_rowof},
 
  {"rows",      EXEC_STRING|EXEC_USECALC,calc_rowof},
 
  {"rows2lines",EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_rows2lines},
 
  {"run",       EXEC_EXEC|EXEC_SUBST|EXEC_PROCTOO|EXEC_USECALC,    calc_exec},
 
  {"select",    EXEC_STRING|EXEC_USECALC,calc_select},
 
  {"set",       EXEC_SET,        exec_set},
 
  {"setdef",    EXEC_OTHER,        exec_setdef},
 
  {"setseed",   EXEC_STRING|EXEC_SUBST,        exec_setseed},
 
  {"sh",        EXEC_EXEC|EXEC_PROCTOO|EXEC_SUBST,exec_sh},
 
  {"shortout",  EXEC_JUMP|EXEC_SUBST,    exec_directout},
 
  {"singlespace",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,singlespace},
 
  {"solve",     EXEC_STRING|EXEC_USECALC,calc_solve},
 
  {"sort",      EXEC_STRING|EXEC_USECALC, calc_sort},
 
/*      {"sql",     EXEC_SQL|EXEC_SUBST|EXEC_USECALC, calc_sql}, */
 
  {"staticinstex",EXEC_INS|EXEC_USECALC,    calc_instexst},
 
  {"stinstex",  EXEC_INS|EXEC_USECALC,    calc_instexst},
 
  {"sum",       EXEC_STRING|EXEC_USECALC,calc_sum},
 
  {"system",    EXEC_EXEC|EXEC_PROCTOO|EXEC_SUBST,exec_sh},
 
  {"tail",      EXEC_HREF,        exec_tail},
 
  {"test",      EXEC_DEBUG,        exec_test},
 
  {"texmath",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,texmath},
 
  {"text",      EXEC_STRING|EXEC_USECALC,text},
 
  {"title",     EXEC_HREF,        exec_title},
 
  {"tohex",     EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_hex},
 
  {"tolower",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_tolower},
 
  {"toupper",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_toupper},
 
  {"translate", EXEC_STRING|EXEC_USECALC,calc_translate},
 
  {"trim",      EXEC_STRING|EXEC_USECALC,calc_trim},
 
  {"upper",     EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_toupper},
 
  {"uppercase", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,calc_toupper},
 
  {"usererror", EXEC_WARN|EXEC_SUBST,    exec_usererror},
 
  {"values",    EXEC_STRING|EXEC_USECALC,calc_values},
 
  {"varlist",   EXEC_STRING|EXEC_SUBST|EXEC_USECALC,mathvarlist},
 
  {"warn",      EXEC_WARN|EXEC_SUBST,    exec_warn},
 
  {"warning",   EXEC_WARN|EXEC_SUBST,    exec_warn},
 
  {"while",     EXEC_WHILE,        exec_while},
 
  {"whileval",  EXEC_WHILE,        exec_whileval},
 
  {"whilevalue",EXEC_WHILE,        exec_whileval},
 
  {"wimsheader",EXEC_HREF,        exec_header},
 
  {"wimsref",   EXEC_HREF,        exec_homeref},
 
  {"wimstail",  EXEC_HREF,        exec_tail},
 
  {"wimstitle", EXEC_HREF,        exec_title},
 
  {"word",      EXEC_STRING|EXEC_USECALC,calc_wordof},
 
  {"words",     EXEC_STRING|EXEC_USECALC,calc_wordof},
 
  {"words2items",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,words2items},
 
  {"words2lines",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,words2lines},
 
  {"words2list",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,words2items},
 
  {"wordstoitems",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,words2items},
 
  {"wordstolines",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,words2lines},
 
  {"wordstolist",EXEC_STRING|EXEC_SUBST|EXEC_USECALC,words2items},
 
  {"writefile", EXEC_DIR|EXEC_SUBST,    filewrite},
 
};
 
int EXEC_FN_NO=(sizeof(exec_routine)/sizeof(exec_routine[0]));
 
 
 
/* internal: to skip the content of a false if/while. */
 
static void _skip_contents(int isif)
 
{
 
  char buf[MAX_NAMELEN+8], *p1;
 
  int i,j,loop;
 
  loop=0;
 
  while(m_file.linepointer<m_file.linecnt) {
 
    j=m_file.linepointer;
 
    if((m_file.lines[j].isstart&2)==0) {
 
      m_file.linepointer++; continue;
 
    }
 
    i=m_file.lines[j].execcode;
 
    if(i<0) {
 
      if(wgetline(buf,MAX_NAMELEN+4,&m_file)==EOF) return;
 
      p1=buf+1; if(*p1!='i' && *p1!='e' && *p1!='w') continue;
 
      *find_word_end(p1)=0;
 
      i=search_list(exec_routine,EXEC_FN_NO,sizeof(exec_routine[0]),p1);
 
      if(i>=0) m_file.lines[j].execcode=i;
 
    }
 
    else m_file.linepointer++;
 
    if(i<0) continue;
 
    switch(exec_routine[i].tag & 0xffff) {
 
      case EXEC_WHILE:
 
        if(!isif) loop++;
 
        break;
 
      case EXEC_IF:
 
        if(isif) loop++;
 
        break;
 
      case EXEC_ELSE: {
 
        if(!isif) break;
 
        if(loop<=0) return; else break;
 
      }
 
      case EXEC_ENDIF: {
 
        if(!isif) break;
 
        if(loop>0) {
 
          loop--; break;
 
        }
 
        else return;
 
      }
 
      case EXEC_ENDWHILE: {
 
        if(isif) break;
 
        if(loop>0) {
 
          loop--; break;
 
        }
 
        else return;
 
      }
 
      default: break;
 
    }
 
  }
 
}
 
 
 
/* Execute a command defined by !. Returns 0 if OK. */
 
void exec_main(char *p)
 
{
 
  int i,j;
 
  char *pp;
 
  char tbuf2[MAX_LINELEN+1];
 
 
 
  pp=find_word_end(p);
 
  if(*pp!=0) {
 
    *(pp++)=0; pp=find_word_start(pp);
 
  }
 
  i=m_file.lines[m_file.l].execcode;
 
  if(i<0) {
 
    i=search_list(exec_routine,EXEC_FN_NO,sizeof(exec_routine[0]),p);
 
    m_file.lines[m_file.l].execcode=i;
 
  }
 
  if(i<0) {
 
    setvar(error_data_string,p); module_error("bad_cmd");
 
  }
 
/* called from !readdef, no right other than set; bail out */
 
  execnt++;
 
  if((untrust&4)!=0 && (j=(exec_routine[i].tag&0xffff))!=EXEC_SET) {
 
    tbuf2[0]=0; exec_exit(tbuf2);
 
  }
 
  ovlstrcpy(tbuf2,pp); j=exec_routine[i].tag;
 
  if(j&EXEC_SUBST) substit(tbuf2);
 
  if(j&EXEC_USECALC) {
 
    if(!outputing && (j&EXEC_PROCTOO)==0) return;
 
    exec_routine[i].routine(tbuf2); if(outputing) output0(tbuf2);
 
  }
 
  else exec_routine[i].routine(tbuf2);
 
  return;
 
}