Logo Search packages:      
Sourcecode: wims version File versions  Download package

exec.c

/*    Copyright (C) 1998 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. */

/* format pour les animations */
char *ANIM_FMT = "mng";

static void _skip_if_contents(void);

      /* common routine for the two if's. */
static void _exec_if(char *p, int numerical)
{
    if(compare(p,numerical)==0) _skip_if_contents(); /* skip if false */
    return;
}

      /* 'if' non-numerical (unless comparisons are < or >, etc.) */
void exec_if(char *p)
{
    _exec_if(p,0);
}

      /* 'if' numerical. */
void exec_ifval(char *p)
{
    _exec_if(p,1);    
}

      /* Should provide a method to stop infinite loop. */
void exec_goto(char *p)
{
    char lbuf[MAX_LINELEN+1];
    char *label_start, *line_start;
    int line_end,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;
      line_end=wgetline(lbuf,MAX_LINELEN,&m_file);
      line_start=find_word_start(lbuf);
      if(*line_start!=label_prefix_char) continue;
      line_start++;*find_word_end(line_start)=0;
      if(strcmp(line_start,label_start)!=0) continue;
      *p=0; i++; return;
    }
    m_file.l=old_line;
    setenv(error_data_string,label_start,1);
    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_if_contents(); 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 *p1, buf[MAX_LINELEN+1];
    inner=0;
    while(wgetline(buf,MAX_LINELEN,&m_file)!=EOF) {
      p1=find_word_start(buf);
      if(*p1!=exec_prefix_char) continue;
      *find_word_end(p1)=0;
      if(strcmp(p1,"!for")==0) {
          inner++; continue;
      }
      if(strcmp(p1,"!next")==0) {
          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");
    memmove(stk->varname,p1,p2-p1);
    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) goto syntax;
      *p2=0; p2+=strlen("to");
      p3=wordchr(p2,"step");
      if(p3!=NULL) {
          *p3=0; p3+=strlen("step");
          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;
    }
    if(memcmp(p1,"from",strlen("from"))==0 && isspace(*(p1+strlen("from")))) {
      p1+=strlen("from"); goto assign;
    }
    if(memcmp(p1,"in",strlen("in"))==0 && isspace(*(p1+strlen("in")))) {
      stk->from=1; p1+=strlen("in");
      p1=find_word_start(p1); if(*p1==0) goto loop_out;
      p2=xmalloc(MAX_LINELEN+1);
      strncpy(p2,p1,MAX_LINELEN); *(p2+MAX_LINELEN)=0;
      substit(p2);
      strip_trailing_spaces(p2);
      if(*p2==0) goto loop_out;
      p1=strchr(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)
{
    if(m_file.for_idx>0) {
      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->from) { /* list style */
      if(stk->list_pt==NULL) {
          free(stk->bufpt);
          m_file.for_idx--;
          *p=0; return;
      }
      p1=strchr(stk->list_pt,',');
      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)
{
    char tbuf[MAX_LINELEN+1];
      /* Silent trancation. */
    strncpy(tbuf,p,MAX_LINELEN); tbuf[MAX_LINELEN]=0;
    direct_exec=1;
    calc_mexec(tbuf);
    direct_exec=0;
    if(outputing) output("%s",tbuf);
}

      /* call shell. */
void exec_sh(char *p)
{
    char *abuf[8];
    char errorfname[230];

    if(robot_access || !trusted_module()) {
      *p=0; return;
    }
    if(!noout) {
      calc_sh(p); if(outputing) output("%s",p);
      return;
    }
    snprintf(errorfname,sizeof(errorfname),"%s/exec.err",session_prefix);
    abuf[0]="sh"; abuf[1]="-c"; abuf[2]=p; abuf[3]=NULL;
    wrapexec=1; exportall();
    execredirected(abuf[0],NULL,NULL,errorfname,abuf);
}

      /* Read another file. */
void exec_read(char *p)
{
    WORKING_FILE save;
    char parmsave[MAX_LINELEN+1];
    char *pp,*ps;
    int t;
    
    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="";
    strncpy(parmsave,ps,MAX_LINELEN);parmsave[MAX_LINELEN]=0;
    setvar("wims_read_parm",pp);
    memmove(&save,&m_file,sizeof(WORKING_FILE));
    t=untrust;
    if(strchr(p,'/')!=NULL) {
      if(user_file(p)) {
          if((untrust&6)!=0 && user_file(m_file.name))
            module_error("Illegal_file_access");
          untrust|=2;
      }
    }
    if(outputing) phtml_put(p);
    else var_proc(p);
    untrust=t;
    memmove(&m_file,&save,sizeof(WORKING_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;
    secure_exec();
    t=untrust; 
    untrust|=4;
    exec_read(p); untrust=t;
}

      /* 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(char *namebuf, char listbuf[])
{
    int i,j,k;
    char lbuf[4], pbuf[MAX_LINELEN+1], *phtml;
    struct stat stt;
    
    listbuf[0]=0;j=strlen(namebuf)-3;
    if(j>=2 && strcmp("light",namebuf+j-2)==0) {
      setvar("wims_light_module","yes");
      phtml=getvar("phtml");
      if(phtml==NULL || *phtml==0) return;
      snprintf(pbuf,sizeof(pbuf),"%s",phtml);
      j=strlen(pbuf)-3;
      if(pbuf[j]!='.') return;
      j++; strcpy(lbuf,pbuf+j); pbuf[j]=0;
      j=strlen(namebuf);
      snprintf(namebuf+j,MAX_LINELEN-j-10,"/pages/%s",pbuf);
      j=strlen(namebuf);
      for(i=k=0;i<available_lang_no;i++) {
          if(strcmp(lbuf,available_lang[i])==0) continue;
          snprintf(namebuf+j,MAX_LINELEN-j,"%s",available_lang[i]);
          if(stat(namebuf,&stt)) continue;
          if(k>0) strcat(listbuf,",");
          strcat(listbuf,available_lang[i]);
          k++;        
      }
      return;
    }
    if(j>=0 && namebuf[j]=='.') {
      setvar("wims_light_module","");
      j++; strcpy(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_LINELEN-j,"%s/main.phtml",
                 available_lang[i]);
          if(stat(namebuf,&stt)) continue;
          if(k>0) strcat(listbuf,",");
          strcat(listbuf,available_lang[i]);
          k++;        
      }
    }
}

      /* Standardised reference to wims home */
void exec_homeref(char *p)
{
    char mbuf[MAX_LINELEN+1], listbuf[MAX_LINELEN+1];
    char *ref, *user;
    
    if(ismhelp) return;
    setvar("wims_homeref_parm",p); *p=0;
    user=getvar("wims_user");
    if(user==NULL) user="";
    if(*user==0 || robot_access!=0) ref=home_referer;
    else {
      if(strcmp(user,"supervisor")==0) ref=home_referer_supervisor;
      else ref=home_referer_user;
    }
    snprintf(mbuf,sizeof(mbuf),"%s",module_prefix);
    other_langs(mbuf,listbuf); setvar("wims_homeref_languages",listbuf);
    phtml_put_base(ref);
    tail_executed=1;
    if(robot_access || strcasecmp(tmp_debug,"yes")!=0) return;
    if(checkhost(manager_site)<1) return;
    debug_output();
}

      /* Standardised header menu */
void exec_headmenu(char *p)
{
    char mbuf[MAX_LINELEN+1], listbuf[MAX_LINELEN+1];
    char *ref, *user;
    
    setvar("wims_headmenu_parm",p); *p=0;
    user=getvar("wims_user");
    if(user==NULL) user="";
    if(*user==0 || robot_access!=0) ref=header_menu;
    else {
      if(strcmp(user,"supervisor")==0) ref=header_menu_supervisor;
      else ref=header_menu_user;
    }
    snprintf(mbuf,sizeof(mbuf),"%s",module_prefix);
    other_langs(mbuf,listbuf); setvar("wims_headmenu_languages",listbuf);
    phtml_put_base(ref);
    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;
      setvar("wims_title_title",s);
    }
    phtml_put_base(title_page);
}

      /* 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 determine_font(char *l);

      /* standardized header */
void exec_header(char *p)
{
    char *s1, *s2, hbuf[MAX_LINELEN+1], *ws="", *bo;
    char wsbuf[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; isdigit(*p2); p2++);
          *p2=0; t1=atoi(p1); p1=p2+1;
          while(!isdigit(*p1) && *p1) p1++;
          for(p2=p1; isdigit(*p2); p2++);
          *p2=0; t2=atoi(p1); p1=p2+1;
/*        while(!isdigit(*p1) && *p1) p1++;
          for(p2=p1; isdigit(*p2); p2++);
          *p2=0; t3=atoi(p1); p1=p2+1;
          while(!isdigit(*p1) && *p1) p1++;
          for(p2=p1; isdigit(*p2); p2++);
          *p2=0; t4=atoi(p1); p1=p2+1;
          while(!isdigit(*p1) && *p1) p1++;
          for(p2=p1; isdigit(*p2); p2++);
          if(t3<5) t3=5; if(t4<20) t4=20;
*/        snprintf(wsbuf,sizeof(wsbuf),
                 " onload=window.focus();window.resizeTo(%d,%d);",
                 t1,t2); ws=wsbuf;
/*        snprintf(wsbuf,sizeof(wsbuf),
                 " onload=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=" onload=window.focus();window.resizeTo(600,500);window.moveTo(15,35);";
    }
    if(strstr(session_prefix,"_exam")!=NULL) {
      char buf[64];
      if(*ws==0) ws=" onload=window.focus();clock();";
      else ws= " onload=window.focus();window.moveTo(5,70);clock();";
      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"));
    snprintf(hbuf,sizeof(hbuf),"%s",s1); substit(hbuf);
    s2=getvar("wims_htmlbody"); if(s2==NULL) s2="";
    bo=getvar("wims_html_bodyoption"); if(bo==NULL) bo="";
    output("<HTML><HEAD>%s\n\
</HEAD><BODY %s %s %s>\n",hbuf,s2,ws,bo);
    exec_headmenu(p);
    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) exec_read("about.phtml");
      else exec_read("help.phtml");
      exec_tail(p);
      return;
    }
    header_executed=1;
}

char href_target[128];
char jsbuf[512];
#define jsstr " onClick=\"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;
          pp=strstr(b1,"cmd="); 
          if(pp==NULL) continue;
          pp+=strlen("cmd=");
          if(memcmp(pp,"intro",strlen("intro"))==0 ||
             memcmp(pp,"new",strlen("new"))==0) 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) snprintf(st,sizeof(st),"%s_mhelp",s1);
            else snprintf(st,sizeof(st),"%.10s%s",s1,href_target+4);
            s=st;
          }
          snprintf(sb+strlen(sb),MAX_LINELEN-strlen(sb),"%s=%s&",
                 ro_name[follow_list[i]],s);
          if(ismhelp && follow_list[i]==ro_session &&
             strstr(sb,"_mhelp")==NULL) 
            snprintf(sb+strlen(sb)-1,MAX_LINELEN-strlen(sb)+1,"_mhelp&");
      }
    }
    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");
      if(*p1=='&' && isalpha(*(p1+1))) {
          p1++; string_modify(qbuf,p1,p1,"+");
      }
    }
    snprintf(b1,MAX_LINELEN,"%s",qbuf);
}

      /* Restart with a new module, using http code 302. */
void exec_restart(char *p)
{
    char buf[MAX_LINELEN+1], *rfn;
    long int t;
    
    if(robot_access || outputing || !trusted_module()) return;
    accessfile(buf,"r","%s/restart.time",session_prefix);
    t=atoi(buf); if(t==nowtime) return;   /* possible looping */
    snprintf(buf,sizeof(buf),"%s",find_word_start(p));
    *find_word_end(buf)=0;
    _httpfollow(buf,"",0);
    rfn=strchr(ref_name,':'); if(rfn==NULL) {
      usual: printf("Location: %s?%s\r\n\r\n",ref_name,buf);
    }
    else {
      char *p;
      p=getvar("wims_protocol");
      if(p!=NULL && strcmp(p,"https")==0) {
          printf("Location: https%s?%s\r\n\r\n",rfn,buf);
      }
      else goto usual;
    }
    close_working_file(&m_file); write_logs();
    snprintf(buf,sizeof(buf),"%ld",nowtime);
    accessfile(buf,"w","%s/restart.time",session_prefix);
    delete_pid(); exit(0);
}

      /* extract target tag from parm string. */
void href_find_target(char *p)
{
    char *pp, *pe;
    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;
      if(strncasecmp(pp,"target=wims_mhelp",strlen("target=wims_mhelp"))==0) {
          if(strstr(p,"cmd=help")==NULL) continue;
          if(*pe!=0) *pe++=0; strcpy(href_target,"wims_help");
          ref_mhelp=1;
      }
      else {
          if(*pe!=0) *pe++=0;
          snprintf(href_target,sizeof(href_target),"%s",pp+strlen("target="));
      }
      snprintf(jsbuf,sizeof(jsbuf),jsstr,href_target);
      strcpy(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)=='&') {
          strcpy(href_target,"wims_help"); ref_mhelp=1;
          snprintf(jsbuf,sizeof(jsbuf),jsstr,href_target);
      }
    }
}

      /* Create href to wims requests. subst() is not done. */
void exec_href(char *p)
{
    char *s, st[128], *p1, *p2, *p3, *wn="";
    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;
    strncpy(b1,p1,MAX_LINELEN); strncpy(b2,find_word_start(p2),MAX_LINELEN);
    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);
      memmove(p1+1,p1,64); *p1='\n'; strcat(p1,"      ");
      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;
      strncpy(b1,p1,MAX_LINELEN); strncpy(b2,find_word_start(p2),MAX_LINELEN);
      substit(b1); substit(b2);
    }
      /* for robots: only references without defining cmd. */
    if(robot_access && strstr(b1,"cmd=")!=NULL) {
      output("%s",b2); return;
    }
    if(robot_access && strstr(aliased_cgi,"yes")!=NULL) {
      char mbuf[MAX_LINELEN+1], lbuf[16];
      strcpy(mbuf,home_module);
      p1=strstr(b1,"module=");
      if(p1!=NULL && (p1<=b1 || *(p1-1)=='&')) {
          p2=p1+strlen("module=");
          p3=strchr(p2,'&'); if(p3==NULL) p3=p2+strlen(p2);
          strncpy(mbuf,p2,p3-p2);mbuf[p3-p2]=0;
          while((p1=strchr(mbuf,'/'))!=NULL) *p1='~';
      }
      p1=strstr(b1,"lang="); strncpy(lbuf,lang,2);
      if(p1!=NULL && (p1<=b1 || *(p1-1)=='&')) {
          p2=p1+strlen("lang=");
          if(islower(*p2) && islower(*(p2+1)) &&
             (*(p2+2)=='&' || *(p2+2)==0)) {
            lbuf[0]=*p2;lbuf[1]=*(p2+1);
          }
      }
      lbuf[2]=0;
      output("<a href=\"%s%s_%s.html\">%s</a>", ref_base,lbuf,mbuf,b2);
      return;
    }
    tohttpquery(b1);
    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);
      if(strcmp(s,"_parent")!=0) {
          new=1; wn="wims_window=new&";
      }
    }
    else st[0]=0;
    _httpfollow(b1,wn,new);
    if(*b2)
      output("<a href=\"%s?%s\"%s%s>%s</a>",
           ref_name, b1, st, jsbuf, b2);
    else
      output("<a href=\"%s?%s\"%s%s>",ref_name, b1, st, jsbuf);
}

      /* Create form refering to the page. */
void exec_form(char *p)
{
    char *s, *p1, *p2, *a, *m, st[128], *wn="";
    char abuf[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);
      if(strcmp(s,"_parent")!=0) {
          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="";
    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;
          setvar("wims_form_method","");
      }
      else m=default_form_method;
    }
    else m=default_form_method;
    output("<p><form action=\"%s%s\"%s method=%s>\n%s",ref_name,a,st,m,wn);
    if(a!=abuf && a[0]) 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;
      memmove(buf,p1,i);buf[i]=0;
      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;
    strcpy(buf,"session=$wims_session.1&module=adm/trap");
    output("<!-- >"); exec_href(buf);
    output("Robot trapper, do not click!</a> < -->");
    exec_href(buf); output("<font></font></a>");
}

      /* 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];
    if(robot_access || !trusted_module()) return;
    p1=wordchr(p,"in"); if(p1==NULL) module_error("syntax_error");
    *p1=0; p1=find_word_start(p1+strlen("in"));
    strcpy(nbuf,p);
    snprintf(fbuf,sizeof(fbuf),"%s/%s",module_prefix,p1);
    substit(nbuf); substit(fbuf);
    pp=find_word_start(nbuf); p1=find_word_start(fbuf);
    *find_word_end(p1)=0; if(strstr(p1,parent_dir_string)!=NULL) {
      setenv(error_data_string,p1,1);     module_error("illegal_fname");
    }
    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;

    p=strchr(name,'=');
    if(p==NULL) return; /* warning or error! */
    *p=0; defn=find_word_start(p+1);
    *find_word_end(name)=0;
    snprintf(namebuf,sizeof(namebuf),"%s",find_word_start(name));
      /* we allow substit in names, to implement array */
    substit(namebuf); *find_word_end(namebuf)=0;    
    if(*defn!=calc_prefix_char) {
      /* substitute by default */
      snprintf(tbuf2,sizeof(tbuf2),"%s",defn);
      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? */
      setenv(error_data_string,defn+1,1); module_error("bad_cmd");
      return;
    }
    strcpy(tbuf2,parm);
    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;
    if(tbuf2[strlen(tbuf2)-1]=='\n') tbuf2[strlen(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;
    strcpy(namebuf,start); 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. Undocumented. Aliases:
       * getfile, outfile, fileout */
void exec_getfile(char *p)
{
    char *s, *p1, url[MAX_LINELEN+1];
    char *prompt, *ap, *ap2;
    
    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()) return;
    s=getvar(ro_name[ro_session]);
    if(s==NULL || *s==0 || strstr(s,"robot")!=NULL) return;
    snprintf(url,sizeof(url),"%s",ref_name);
    for(p1=url+strlen(url);p1>url && *(p1-1)!='/'; p1--);
    ap=getenv("SERVER_SOFTWARE");
    if(ap!=NULL && (ap2=strstr(ap,"Apache"))!=NULL &&
       strcmp(ap2,"Apache/1.3")>=0) 
      snprintf(p1,sizeof(url)+p1-url,
             "getfile/%s?&session=%s&modif=%ld",
             p,s,nowtime);
    else snprintf(url,sizeof(url),
              "%s?cmd=getfile&session=%s&special_parm=%s&modif=%ld",
              ref_name,s,p,nowtime);
    snprintf(jsbuf,sizeof(jsbuf),jsstr,"wims_file");
    if(*prompt) output("<A HREF=\"%s\">%s</A>\n", url,prompt);
    else output("<A HREF=%s>",url);
}

      /* 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, p0[256];
    char buf[1024],buf2[1024],url[MAX_LINELEN+1];
    char outbuf[1024];
    int border, middle, vspace;
    long int tel;

    strncpy(p0,p,256-4);
    if (strlen(p)>256-4){
      p0[252]=p0[253]=p0[254]='.'; p0[255]=0;
    }
    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){
      if(animated_ins) fmt="mng"; else fmt="png";
    }
    if(ismhelp) mh="mh"; else mh="";
    snprintf(buf,sizeof(buf),"%s/insert%s-%d.%s",session_prefix,mh,insert_no,fmt);
    unlink(buf); 
    if(grouped_ins) goto grouped;
    exportall();
    call_ssh("%s/%s %d %s >%s/ins.out 2>%s/ins.err",
          bin_dir,script_name,insert_no,tmp_dir,
          session_prefix,session_prefix);
    wrapexec=1;
    call_ssh("mv %s/insert%s-%d.%s %s >/dev/null 2>/dev/null",
           tmp_dir,mh,insert_no,fmt,session_prefix);
    tel=filelength("%s/insert%s-%d.%s", session_prefix,mh,insert_no,fmt);
    if(tel<=5) {
      char bbuf[MAX_LINELEN+1];
      accessfile(bbuf,"r","%s/ins.err",session_prefix);
      snprintf(url,sizeof(url),"images/badins.png");
      for(p1=bbuf;p1<bbuf+512 && *p1;p1++)
        if(*p1=='<' || *p1=='>') *p1='?';
      *p1=0;
      if(bbuf[0]==0) snprintf(bbuf,sizeof(bbuf),"Fail");
      snprintf(outbuf+strlen(outbuf),sizeof(outbuf)-strlen(outbuf),
             " <IMG SRC=%s alt=\"Error\"> <p><small><pre>%s</pre></small> <p> ",
             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),"align=%s",al); else buf2[0]=0;
    if(strcasecmp(al,"middle")==0) middle=1; else middle=0;
    tag2=""; vspace=0;
    if(*tag!=0) {
      snprintf(buf,sizeof(buf),"%s",tag); 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;
    else border=atoi(b);
    if(border<0) border=0; if(border>100) border=100;
    if(middle) {
      snprintf(outbuf+strlen(outbuf),
             sizeof(outbuf)-strlen(outbuf),mathalign_sup1);
      vspace=5;
    }
    snprintf(url,sizeof(url),"%s",ref_name);
    for(p1=url+strlen(url);p1>url && *(p1-1)!='/'; p1--);
    snprintf(p1,sizeof(url)+p1-url,
           "wims.%s?cmd=getins&session=%s&special_parm=insert%s-%d.%s&modif=%ld",
           fmt,s,mh,insert_no,fmt,nowtime);
    if(strchr(ins_alt,'"')!=NULL || strlen(ins_alt)>256) ins_alt[0]=0;
    if(strcasecmp(tag,"form")!=0) {
      snprintf(outbuf+strlen(outbuf),sizeof(outbuf)-strlen(outbuf),
             "<IMG SRC=\"%s\" ALT=\"%s\" border=%d vspace=%d %s %s alt=\"%s\">",
             url, p0, border, vspace, at, buf2, ins_alt);
    }
    else {
      char *n;
      if(*tag2!=0) n="name="; else n="";
      snprintf(outbuf+strlen(outbuf),sizeof(outbuf)-strlen(outbuf),
             "<input type=image %s%s src=\"%s\" border=%d vspace=%d %s %s alt=\"%s\">",
             n,tag2,url,border,vspace, at,buf2, ins_alt);
    }
    if(middle) snprintf(outbuf+strlen(outbuf),
                  sizeof(outbuf)-strlen(outbuf),mathalign_sup2);
    setvar("ins_warn",""); ins_alt[0]=0;
    snprintf(buf2,sizeof(buf2),"%d",insert_no);
    setvar("ins_cnt",buf2);
    reset:
    if(outputing) output("%s",outbuf);
    setvar("ins_out",outbuf);
    setvar("ins_attr",""); setvar("ins_tag","");
    setvar("ins_url",url);
    animated_ins=0;
}

      /* instex: dynamically insert tex outputs */
void exec_instex(char *p)
{
    char *ts, *tc, *f, *mh, buf[4096];
    
    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. */
        strncpy(ptex,p,1023); /* save TeX expression for ALT attribute */
      calc_instexst(p); if(outputing) output("%s",p);
      return;
    }
    if(ismhelp) mh="mh"; else mh="";
    fix_tex_size(); f="png";
    setenv("texgd_style",instex_style,1);
    setenv("texgd_tmpdir",tmp_dir,1);
    setenv("texgd_src",p,1);
    if(ins_alt[0]==0) snprintf(ins_alt,sizeof(ins_alt),"%s",p);
    snprintf(buf,sizeof(buf),"%s/insert%s-%d.png",tmp_dir,mh,insert_no+1);
    setenv("texgd_outfile",buf,1);
    ts=getvar("wims_texsize"); tc=getvar("instex_color");
    if(lastout_file!=NULL && (tc==NULL || *tc==0) &&
       (ts==NULL || *ts==0 || strcmp(ts,"0")==0)) {
      int ls, ln;
      char *pagebreak;
      ls=strlen(instex_src); ln=strlen(instex_fname);
      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;
    }
    snprintf(buf,sizeof(buf),"%s/texgd.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;
    for(pp=strchr(p,'/');pp!=NULL;pp=strchr(pp+1,'/')) {
      char *p1;
      if(pp<=p || !isdigit(*(pp-1)) || !isdigit(*(pp+1))) continue;
      for(p1=pp-2;p1>=p && isdigit(*p1);p1--);
      if(p1>=p && *p1=='.') continue;
      for(p1=pp+2;*p1 && isdigit(*p1);p1++);
      if(*p1=='.') continue;
      string_modify(p,p1,p1,".0");
    }
    for(pp=strchr(p,'^');pp!=NULL;pp=strchr(pp+1,'^'))
      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];
    
    j=strlen(p);
      /* 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 {
            snprintf(bbuf,sizeof(bbuf),"%s",pp);
            gnuplot_patch(bbuf,1);
          }
          strcat(tbuf,bbuf);strcat(tbuf,"\n");
      }
      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];
      snprintf(tbuf,sizeof(tbuf),"%s",pp);
      i=strlen(tbuf)-1;
      while(i>0 && isspace(tbuf[i])) i--;
      if(tbuf[i]==';') tbuf[i]=0;
      gnuplot_patch(tbuf,0);pp=tbuf;
      strcpy(setbuf,"set "); j=strlen("set ");
      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;}
          strcpy(setbuf+j,"\nset "); j+=strlen("\nset ");
      }
      setbuf[j]=0;
      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;
    if(strstr(setbuf,"step")==NULL && strstr(p,"step")==NULL
       && varchr(setbuf,"s")==NULL && varchr(p,"s")==NULL && !multanim) i=1;
    snprintf(buf,sizeof(buf),"%d",i);
    setenv("ins_anim_frames",buf,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;
    i=d*100;
    snprintf(buf,sizeof(buf),"%d",i);
    setenv("ins_anim_delay",buf,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,session_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,session_prefix);
    unsetenv("multiplot");setvar("insplot_split","");
}

      /* Insert dynamic png draw. The parm preparation is specific to fly. */
void exec_insdraw(char *p)
{
    char *pp, buf[256], *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;
    snprintf(buf,sizeof(buf),"%d",i);
    setenv("ins_anim_frames",buf,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;
    i=d*100;
    snprintf(buf,sizeof(buf),"%d",i);
    setenv("ins_anim_delay",buf,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, buf[256];
    int i;
    p1=find_word_start(p); p2=find_word_end(p1);
    if(p2<=p1) {
      *p=0; return;
    }
    *p2=0;p1=getvar(p1);
    if(p1==NULL) p1="";
    i=atoi(p1)+1;
    snprintf(buf,sizeof(buf),"%d",i);
    setvar(p,buf); *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; strcpy(nbuf,p1);substit(nbuf); p1=find_word_start(p2+1);
    p2=getvar(nbuf);if(p2==NULL) p2="";
    snprintf(vbuf,sizeof(vbuf),"%s",find_word_start(p2));
    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"));
      strcpy(dbuf,p3); substit(dbuf);
    }
    else defaulted=0;
    if(strcmp(p1,"between")==0) {
      p1=find_word_start(p2);
      i=strlen("integer");
      if(strncmp(p1,"integer",i)==0 &&
         (isspace(*(p1+i)) || (*(p1+i)=='s' && isspace(*(p1+i+1))))) {
          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) {
        p2=strchr(p1,','); p3=p2+1;
      }
      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(!finite(d1) || !finite(d2) || 
         abs(d1)>(double)(1E10) || abs(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) strcpy(p,dbuf);
      else {
          if(!doub) {
            d1=ceil(d1);d2=floor(d2);
          }
          if(vbuf[0]==0 || val<d1) val=d1;
          else val=d2;
          float2str(val,p);
      }
      setvar(nbuf,p); *p=0; return;
    }
    else {
      if(strcmp(p1,"within")==0 || strcmp(p1,"among")==0) {
          strcpy(lbuf,p2);substit(lbuf);
          bcnt=separate_item(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) strcpy(p,dbuf); else strcpy(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_LINELEN+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";
    snprintf(buf,sizeof(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);
    memmove(&m_file,&save,sizeof(WORKING_FILE));
    end:
    *p=0; return;
}

      /* write message of the day (for classes).
       * Reserved to trusted modules */
void exec_writemotd(char *p)
{
    char *cl, *sup;
    char namebuf[1024];
    FILE *motdf;
    if(!trusted_module()) module_error("not_trusted");
    sup=getvar("wims_user");
    if(sup==NULL || strcmp(sup,"supervisor")!=0 ||
       (cl=getvar("wims_class"))==NULL || *cl==0) {
      *p=0; return;
    }
    snprintf(namebuf,sizeof(namebuf),"%s/classes/%s/.motd",log_dir,cl);
    motdf=fopen(namebuf,"w");
    if(motdf!=NULL) {
      fputs(p,motdf); fclose(motdf);
    }
    *p=0;
}

      /* 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);
    }
    setvar("wims_error",p1); setvar("wims_error_parm",p2);
    l=getvar("module_language");
    if(l!=NULL && strlen(l)==2) {
      snprintf(buf,sizeof(buf),"msg.phtml.%s",l);
      phtml_put_base(buf);
    }
    *p=0;
}

struct {
    char *name;
    char *(*routine) (char *p, int n, char buf[]);
} distr_cmd[]={
      {"char",          fnd_char},
      {"charof",  fnd_char},
      {"chars",         fnd_char},
      {"charsof", fnd_char},
      {"item",          fnd_item},
      {"itemof",  fnd_item},
      {"items",         fnd_item},
      {"itemsof", fnd_item},
      {"line",          fnd_line},
      {"lineof",  fnd_line},
      {"lines",         fnd_line},
      {"linesof", fnd_line},
      {"list",          fnd_item},
      {"word",          fnd_word},
      {"wordof",  fnd_word},
      {"words",         fnd_word},
      {"wordsof", fnd_word}
};

#define 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 vbuf[MAX_LINELEN+1], nbuf[MAX_LINELEN+1],
      bf1[MAX_LINELEN+1],bf2[MAX_LINELEN+1];
    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;strncpy(bf1,p2,MAX_LINELEN);bf1[MAX_LINELEN]=0;
    p1=find_word_start(p1+strlen("into"));
    strncpy(bf2,p1,MAX_LINELEN); bf2[MAX_LINELEN]=0;
    strip_trailing_spaces(bf1);
    substit(bf1);substit(bf2);
    items2words(bf2);
    n=wordnum(bf2);
    for(k=1;k<=n;k++) {
      fnd_word(bf2,k,nbuf);
      distr_cmd[i].routine(bf1,k,vbuf);
      setvar(nbuf,vbuf);
    }
}

      /* reset variables */
void exec_reset(char *p)
{
    int i,n;
    char nbuf[MAX_LINELEN+1];

    items2words(p);
    n=wordnum(p);
    for(i=1;i<=n;i++) {
      fnd_word(p,i,nbuf); setvar(nbuf,"");
    }
}

      /* 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 {
      p1=strchr(p,',');
      if(p1==NULL) module_error("syntax_error");
      *p1=0; p2=find_word_start(p1+1);
    }
    p1=find_word_start(p);
    snprintf(b1,sizeof(b1),"%s",p1); substit(b1); *find_word_end(b1)=0;
    snprintf(b2,sizeof(b2),"%s",p2); substit(b2); *find_word_end(b2)=0;
    if(*b1==0 || *b2==0) module_error("syntax_error");
    pb=getvar(b1);if(pb==NULL) pb="";
    strncpy(buf,pb,MAX_LINELEN);buf[MAX_LINELEN]=0;
    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()) return;
    p1=strchr(p,'\n'); if(p1==NULL) return;
    *p1++=0; p=find_word_start(p);
    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",session_prefix);
    wrapexec=1;
    call_sh("mail -s \" %s \" %s <%s/mail.body", p1,p,session_prefix);
    *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;
    printf("%s",p);
    noout=1;
}

enum {
      EXEC_IF, EXEC_JUMP, EXEC_ELSE, EXEC_ENDIF, EXEC_EXEC,
      EXEC_FOR, EXEC_VAR, EXEC_DEBUG,
      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_MOTD,
      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},
      {"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},
      {"date",          EXEC_STRING|EXEC_USECALC|EXEC_SUBST,calc_date},
      {"deaccent",      EXEC_STRING|EXEC_USECALC|EXEC_SUBST,deaccent},
      {"debug",         EXEC_DEBUG|EXEC_SUBST,  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},
      {"encyclo", EXEC_PEDIA|EXEC_SUBST|EXEC_USECALC,pedia},
      {"encyclopedia",  EXEC_PEDIA|EXEC_SUBST|EXEC_USECALC,pedia},
      {"endif",         EXEC_ENDIF,       exec_endif},
      {"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},
      {"filelist",      EXEC_DIR|EXEC_SUBST|EXEC_USECALC,calc_listfile},
      {"fileout", EXEC_HREF|EXEC_SUBST,   exec_getfile},
      {"filewrite",     EXEC_DIR|EXEC_SUBST,    filewrite},
      {"for",           EXEC_FOR,         exec_for},
      {"form",          EXEC_HREF|EXEC_SUBST,   exec_form},
      {"formbar", EXEC_HREF,        exec_formbar},
      {"formcheckbox",  EXEC_HREF,        exec_formcheckbox},
      {"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},
      {"getscoremean",  EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscoremean},
      {"getscorepercent",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscorepercent},
      {"getscoreremain",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscoreremain},
      {"getscorerequire",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscorerequire},
      {"getscoreweight",EXEC_SCORE|EXEC_SUBST|EXEC_USECALC,calc_getscoreweight},
      {"goto",          EXEC_JUMP|EXEC_SUBST,   exec_goto},
      {"header",  EXEC_HREF,        exec_header},
      {"headmenu",      EXEC_HREF,        exec_headmenu},
      {"homeref", EXEC_HREF,        exec_homeref},
      {"href",          EXEC_HREF,        exec_href},
      {"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},
      {"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},
      {"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},
      {"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},
      {"next",          EXEC_FOR,         exec_next},
      {"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},
      {"position",      EXEC_STRING|EXEC_USECALC,calc_pos},
      {"positionof",    EXEC_STRING|EXEC_USECALC,calc_pos},
      {"positions",     EXEC_STRING|EXEC_USECALC,calc_pos},
      {"rawmath", EXEC_STRING|EXEC_SUBST|EXEC_USECALC,rawmath},
      {"rawmatrix",     EXEC_STRING|EXEC_SUBST|EXEC_USECALC,rawmatrix},
      {"read",          EXEC_READ|EXEC_SUBST,   exec_read},
      {"readdef", EXEC_READ|EXEC_SUBST,   exec_defread},
      {"readmotd",      EXEC_MOTD|EXEC_SUBST|EXEC_USECALC,calc_readmotd},
      {"readproc",      EXEC_READ|EXEC_SUBST,   exec_readproc},
      {"record",  EXEC_STRING|EXEC_USECALC,calc_recordof},
      {"records", EXEC_STRING|EXEC_USECALC,calc_recordof},
      {"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},
      {"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},
      {"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},
      {"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},
      {"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},
      {"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},
      {"writemotd",     EXEC_MOTD|EXEC_SUBST,   exec_writemotd}
};
#define EXEC_FN_NO (sizeof(exec_routine)/sizeof(exec_routine[0]))

      /* internal: to skip the content of a false if. */
static void _skip_if_contents(void)
{
    char buf[MAX_LINELEN+1], *p1, *p2;
    int i,j, loop;
    loop=0;
    for(j=m_file.linepointer;j<m_file.linecnt;j++) {
      if((m_file.lines[j].isstart&2)==0) continue;
      m_file.linepointer=j; wgetline(buf,MAX_LINELEN,&m_file);
      p1=find_word_start(buf);
      if(*p1!=exec_prefix_char || (*(p1+1)!='i' && *(p1+1)!='e')) continue;
      p2=find_word_end(p1); p1++; *p2=0;
      i=search_list(exec_routine,EXEC_FN_NO,sizeof(exec_routine[0]),p1);
      if(i<0) continue;
      switch(exec_routine[i].tag & 0xffff) {
          case EXEC_IF:
            loop++; break;
          case EXEC_ELSE:
            if(loop<=0) return; else break;
          case EXEC_ENDIF:
            if(loop>0) {
                loop--; break;
            }
            else return;
          default: break;
      }
    }
}

      /* Execute a command defined by !. Returns 0 if OK. */
int exec_main(char *p)
{
    int i,j;
    char *pp,*name;
    char tbuf2[MAX_LINELEN+1];

    if(*p==exec_prefix_char || isspace(*p) || *p==0) return 0; /* comment */
    name=p;
    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]),name);
      m_file.lines[m_file.l].execcode=i;
    }
    if(i<0) {
      setenv(error_data_string,name,1); module_error("bad_cmd");
    }
      /* called from !readdef, no right other than set; bail out */
    if((untrust&4)!=0 && (j=(exec_routine[i].tag&0xffff))!=EXEC_SET) {
      tbuf2[0]=0; exec_exit(tbuf2);
    }
    strcpy(tbuf2,pp); j=exec_routine[i].tag;
    if(j&EXEC_SUBST) substit(tbuf2);
    if(j&EXEC_USECALC) {
      if(!outputing && (j&EXEC_PROCTOO)==0) return 0;
      exec_routine[i].routine(tbuf2); if(outputing) output("%s",tbuf2);
    }
    else exec_routine[i].routine(tbuf2);
    return 0;
}


Generated by  Doxygen 1.6.0   Back to index