Subversion Repositories wimsdev

Rev

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

  1. /*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
  2.  *
  3.  *  This program is free software; you can redistribute it and/or modify
  4.  *  it under the terms of the GNU General Public License as published by
  5.  *  the Free Software Foundation; either version 2 of the License, or
  6.  *  (at your option) any later version.
  7.  *
  8.  *  This program is distributed in the hope that it will be useful,
  9.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  *  GNU General Public License for more details.
  12.  *
  13.  *  You should have received a copy of the GNU General Public License
  14.  *  along with this program; if not, write to the Free Software
  15.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  */
  17.  
  18. /* Routines treating user scores. */
  19. #include "wims.h"
  20.  
  21. double oldfactor=0.85;     /* quality factor, should remain stable. */
  22.  
  23. enum {sr_require, sr_weight, sr_score, sr_mean, sr_remain,
  24.   sr_last, sr_try, sr_best, sr_level, sr_new, sr_seedlast, sr_seedscorelast,
  25.   sr_seedscores, sr_seedlastcnt};
  26. char scorebuf[MAX_CLASSEXOS*sizeof(scoreresult)+32];
  27. struct scoreresult *rscore;
  28. int scorecnt;
  29. double scoresum[MAX_SHEETS];
  30. int sheetstart[MAX_SHEETS], shexocnt[MAX_SHEETS];
  31. int examstart, examcnt;
  32. char rscore_class[MAX_CLASSLEN+1];
  33. char rscore_user[MAX_NAMELEN+1];
  34.  
  35. int totsheets=0;
  36. int score_ispublic=0;
  37. int score_status=-1;          /* save of score status */
  38. int score_statussheet=-1;
  39. int score_statusisexam=-1;
  40. double scorerecfactor=0.9;
  41.  
  42. /* gather user score, core routine.
  43.   rscore data is created (table of structures).
  44.   according to the value of wims_sheet or wims_exo
  45. */
  46. int getscoreuser(char *classe, char *user)
  47. {
  48.   int i, osh, sh;
  49.   char *nowuser, *nowsheet, *nowexo, *nowscore;
  50.   char *pp;
  51.   if(user==NULL || *user==0) {
  52.     user=getvar("wims_user");
  53.     if(user==NULL || *user==0) return -1;
  54.   }
  55.   if(strcmp(classe,rscore_class)==0 && strcmp(user,rscore_user)==0) return 0;
  56.   nowsheet=nowexo=nowscore="";
  57.   nowuser=getvar("wims_user");
  58.   if(nowuser!=NULL && strcmp(user,nowuser)==0) {
  59.     nowscore=getvar("module_score");
  60.     if(nowscore!=NULL && *nowscore!=0) {
  61.       nowsheet=getvar("wims_sheet");
  62.       if(nowsheet==NULL) nowsheet="";
  63.       nowexo=getvar("wims_exo");
  64.       if(nowexo==NULL) nowexo="";
  65.     }
  66.     else nowscore="";
  67.   }
  68.   snprintf(scorebuf+sizeof(int),sizeof(scorebuf)-sizeof(int),
  69.        "-c%s -u%s getscore %s %s %s",
  70.        classe,user,nowsheet,nowexo,nowscore);
  71.   i=kerneld(scorebuf,sizeof(scorebuf));
  72.   if(i<0)  internal_error("getscoreuser(): daemon failure.");
  73.   if(memcmp(scorebuf+sizeof(int),"OK",2)!=0) {
  74.     if(memcmp(scorebuf+sizeof(int),"ERROR",5)==0) {
  75.       module_error(find_word_start(scorebuf+sizeof(int)+8));
  76.     }
  77.     else internal_error("getscoreuser(): communication error with wimslogd.");
  78.   }
  79. /* 3 is here the length of "OK " */
  80.   pp=scorebuf+sizeof(int)+3; rscore=(struct scoreresult *) pp;
  81.   scorecnt=(i-sizeof(int)-3)/sizeof(scoreresult);
  82.   if(scorecnt>MAX_CLASSEXOS) module_error("too_many_exercises");
  83.   osh=-1;
  84.   for(i=totsheets=0;i<scorecnt;i++) {
  85.     sh=rscore[i].sh;
  86.     if (sh >= MAX_SHEETS) break;
  87.     while(osh<sh)
  88.       {++osh; scoresum[osh]=shexocnt[osh]=0; sheetstart[osh]=i;}
  89.     scoresum[sh]+=rscore[i].require*rscore[i].weight*rscore[i].active;
  90.     shexocnt[sh]++;
  91.   }
  92.   totsheets=osh+1;
  93.  
  94.   examstart=i;  examcnt=scorecnt-examstart;
  95.   mystrncpy(rscore_class,classe,sizeof(rscore_class));
  96.   mystrncpy(rscore_user,user,sizeof(rscore_user));
  97.   return 0;
  98. }
  99. /* work : exo */
  100. char *scorepname[]={
  101.   "class","user","sheet","work","exam"
  102. };
  103. #define scorepname_no (sizeof(scorepname)/sizeof(scorepname[0]))
  104. char score_class[MAX_CLASSLEN+1];
  105. int score_sheet,score_exo,score_isexam,score_exam;
  106. char score_user[256];
  107.  
  108. /* Uniformed treatment of score command parameters
  109.  * format: class=? user=? sheet=? work=?
  110.  * all are optional.
  111.  */
  112. void _scoreparm(char *p)
  113. {
  114.     int i;
  115.     char *pn, *pe, *pd, *pf;
  116.     char sav;
  117.  
  118.     score_sheet=score_exo=score_isexam=score_exam=score_ispublic=0; *score_class=0;
  119.     score_user[0]=0;
  120.     for(i=0;i<scorepname_no;i++) {
  121.       pf=p;
  122.       ahead:
  123.       pn=strstr(pf,scorepname[i]); pf=pn+1;
  124.       if(pn==NULL) continue;
  125.       if(pn>p && !isspace(*(pn-1))) goto ahead;
  126.       pe=find_word_start(pn+strlen(scorepname[i]));
  127.       if(*pe!='=') goto ahead;
  128.       pd=find_word_start(pe+1);
  129.       pf=find_word_end(pd);
  130.       if(pf<=pd) continue;
  131.       sav=*pf; *pf=0;
  132.       switch(i) {
  133.         case 0: /* class */
  134.           mystrncpy(score_class,pd,sizeof(score_class)); break;
  135.         case 1: /* user */
  136.           mystrncpy(score_user,pd,sizeof(score_user)); break;
  137.         case 2: { /* sheet */
  138.           if(*pd=='P') {pd++; score_ispublic=1;}
  139.           score_sheet=atoi(pd);
  140.           break;
  141.         }
  142.         case 3: /* work=exo */
  143.           score_exo=atoi(pd); break;
  144.         case 4: /* exam */
  145.           score_isexam=1;score_exam=atoi(pd); break;
  146.      }
  147.      *pf=sav; ovlstrcpy(pn, pf);
  148.     }
  149.     *p=0;
  150.     /* the commands are OK from a non trusted module if the user and the
  151.     class are not precised, so it can be only the user in his class */
  152.     if((*score_class!=0 || score_user[0]!=0) && !trusted_module()) {
  153.       module_error("not_trusted"); return;
  154.     }
  155.     if(*score_class==0) {
  156.       char *classe;
  157.       classe=getvar("wims_class");
  158.       if(classe==NULL || *classe==0) return;
  159.       else mystrncpy(score_class,classe,sizeof(score_class));
  160.     }
  161.     if(score_user[0]==0) {
  162.      char *user;
  163.      user=getvar("wims_user");
  164.      if(user!=NULL) mystrncpy(score_user,user,sizeof(score_user));
  165.     }
  166. }
  167.  
  168. /* gather score: relatif to some of the
  169.  *  user class work sheet exam
  170.  *  dtype can be require weight score mean remain best last level try
  171.  */
  172.  
  173. void _getscore(char *p,int dtype)
  174. {
  175.   int i,sh,ex,osh;
  176.   float d;
  177.   char dc[SEEDSIZE];
  178.   char ds[SEEDSCORES];
  179.   char *p1;
  180.  
  181.   _scoreparm(p);
  182.   if(*score_class==0 || *score_user==0) return;
  183.   if(getscoreuser(score_class,score_user)<0) return;
  184.   for(i=osh=0,p1=p;i<scorecnt && p1-p<MAX_LINELEN-32;i++) {
  185.     sh=rscore[i].sh+1; if(sh<1 || sh>MAX_SHEETS) break;
  186.     if(score_sheet!=0) {
  187.       if(sh<score_sheet) continue;
  188.       if(sh>score_sheet || sh>MAX_SHEETS) break;
  189.     }
  190.     ex=rscore[i].exo+1;
  191.     if(score_exo!=0 && ex!=score_exo) continue;
  192.     if(osh!=0 && sh!=osh) *p1++='\n';
  193.     switch(dtype) {
  194.       case sr_require: {d=rscore[i].require; break;}
  195.       case sr_weight: {d=rscore[i].weight; break;}
  196.       case sr_score: {d=rscore[i].score; break;}
  197.       case sr_mean: {d=rscore[i].mean; break;}
  198.       case sr_remain: {d=rscore[i].require-rscore[i].score; break;}
  199.       case sr_last: {d=rscore[i].last; break;}
  200.       case sr_try: {d=rscore[i].try; break;}
  201.       case sr_new: {d=rscore[i].new; break;}
  202.       case sr_best: {d=rscore[i].best; break;}
  203.       case sr_level: {d=rscore[i].level; break;}
  204.       case sr_seedscorelast: {d=rscore[i].seedscorelast; break;}
  205.       case sr_seedlastcnt: {d=rscore[i].seedlastcnt; break;}
  206.       case sr_seedlast: { mystrncpy(dc,rscore[i].seedlast,SEEDSIZE);
  207.         break;
  208.       }
  209.       case sr_seedscores: {
  210.         mystrncpy(ds,rscore[i].seedscores,SEEDSCORES); break;
  211.       }
  212.       default: {d=0; break;}
  213.     }
  214.     switch(dtype) {
  215.       case sr_seedlast:
  216.         { snprintf(p1,SEEDSIZE, "%s", dc); p1+=strlen(p1); break; }
  217.        case sr_seedscores:
  218.         { snprintf(p1,SEEDSCORES, "%s", ds); p1+=strlen(p1); break; }
  219.       default:
  220.         { p1=moneyprint(p1,d); }
  221.     }
  222.     *p1++=' ';
  223.     osh=sh;
  224.   }
  225.   *p1++='\n'; *p1=0;
  226. }
  227.  
  228. /* gather user score. */
  229. void calc_getscore(char *p)
  230. {
  231.   _getscore(p,sr_score);
  232. }
  233.  
  234. /* gather user score average. */
  235. void calc_getscoremean(char *p)
  236. {
  237.   _getscore(p,sr_mean);
  238. }
  239.  
  240. /* gather remaining of score to get for user. */
  241. void calc_getscoreremain(char *p)
  242. {
  243.   _getscore(p,sr_remain);
  244. }
  245.  
  246. /* Require score table. */
  247. void calc_getscorerequire(char *p)
  248. {
  249.   _getscore(p,sr_require);
  250. }
  251.  
  252. /* Score weight table. */
  253. void calc_getscoreweight(char *p)
  254. {
  255.   _getscore(p,sr_weight);
  256. }
  257. /* user last score */
  258. void calc_getscorelast(char *p)
  259. {
  260.   _getscore(p,sr_last);
  261. }
  262. /* gather user score try numbers with score activated. */
  263. void calc_getscoretry(char *p)
  264. {
  265.   _getscore(p,sr_try);
  266. }
  267. /* gather all user try numbers (terminated or not, but with notation activated)*/
  268. void calc_getscorealltries(char *p)
  269. {
  270.   _getscore(p,sr_new);
  271. }
  272.  
  273. /* if the required points are 10* N, gather N user best scores */
  274. void calc_getscorebest(char *p)
  275. {
  276.   _getscore(p,sr_best);
  277. }
  278.  
  279. /* gather user score average. */
  280. void calc_getscorelevel(char *p)
  281. {
  282.   _getscore(p,sr_level);
  283. }
  284.  
  285. /* percentage of work done for each sheet:
  286.  * score mean best level
  287.  * as follows
  288.  * score=100*cumulative_points/required_points (< 100)
  289.  * mean=quality (<10)
  290.  * best=10*(required/10 best_scores)/required_points (< 100)
  291.  * level=minimum of the required/10 best_scores (< 100)
  292.  */
  293.  
  294.  void calc_getscorepercent(char *p)
  295. {
  296.   int i,j,jend;
  297.   double tot, mean, totb, totl, totw, d;
  298.   char *p1;
  299.  
  300.   _scoreparm(p);
  301.   if(*score_class==0 || *score_user==0) return;
  302.   if(getscoreuser(score_class,score_user)<0) return;
  303.   for(p1=p,i=0;i<totsheets && p1-p<MAX_LINELEN-32;i++) {
  304.     if(scoresum[i]==0) {
  305.       ovlstrcpy(p1,"0 0 0 0\n"); p1+=strlen(p1); continue;
  306.     }
  307.     if(score_sheet!=0 && i!=score_sheet-1) continue;
  308.     if(scoresum[i]<=0) *p1++='\n';
  309.     tot=mean=totb=totl=totw=0; jend=sheetstart[i]+shexocnt[i];
  310.     for(j=sheetstart[i];j<jend;j++) {
  311.       /* if mean<1 then ignore score.
  312.       * if mean<2 then half score.
  313.       */
  314.       if(rscore[j].mean>=1) {
  315.         double dt=rscore[j].score;
  316.         float db=rscore[j].best;
  317.         float dl=rscore[j].level;
  318.         if(rscore[j].mean<2) {dt=dt/2; db=db/2; dl=dl/2;}
  319.         d=dt*rscore[j].weight*rscore[j].active;
  320.         /* quality; barycenter with coefficients d */
  321.         mean+=rscore[j].mean*d;
  322.         /* cumulative score */
  323.         tot+=d;
  324.         /* best */
  325.         totb+=db*rscore[j].weight*rscore[j].active;
  326.         /* level */
  327.         totl+=dl*rscore[j].weight*rscore[j].active;
  328.         totw+=rscore[j].weight*rscore[j].active;
  329.       }
  330.     }
  331.     if(tot>0) {d=mean/tot;} else d=0;
  332.     /* cumulative score */
  333.     p1=moneyprint(p1,rint(100*tot/scoresum[i])); *p1++=' ';
  334.     /* quality */
  335.     p1=moneyprint(p1,d); *p1++=' ';
  336.     /* best */
  337.     p1=moneyprint(p1,rint(100*totb/scoresum[i])); *p1++=' ';
  338.     /* level */
  339.     p1=moneyprint(p1,rint(10*totl/totw));
  340.  
  341.    *p1++='\n';
  342.   }
  343.   *p1=0;
  344. }
  345. /* [seed1,score1;seed2,score2;...] at most MAX_SCORESEED */
  346. void calc_getseedscores(char *p)
  347. {
  348.   _getscore(p,sr_seedscores);
  349. }
  350. /* last seed (0 if there is no seed)*/
  351. void calc_getseedlast(char *p)
  352. {
  353.   _getscore(p,sr_seedlast);
  354. }
  355. /* last score (-1 if does not exist) */
  356. void calc_getseedscorelast(char *p)
  357. {
  358.   _getscore(p,sr_seedscorelast);
  359. }
  360.  
  361. /* number of occurences of the last seed */
  362. void calc_getseedlastcnt(char *p)
  363. {
  364.   _getscore(p,sr_seedlastcnt);
  365. }
  366.  
  367. /* Returns the status of a sheet, or -1 if error */
  368. int getsheetstatus(char *classe, int sheet)
  369. {
  370.   char *p, *st, buf[MAX_LINELEN+1], namebuf[MAX_FNAME+1];
  371.   int i,j,res,lnb;
  372.   char *p1,buf1[MAX_LINELEN],buf2[MAX_LINELEN];
  373.   char buf3[MAX_LINELEN],buf4[MAX_LINELEN];
  374.   if(isexam || score_isexam) {st="exam"; lnb=8;} else {st="sheet";lnb=9;};
  375.   mkfname(namebuf,"%s/%s/%ss/.%ss",class_base,classe,st,st);
  376.   direct_datafile=1;datafile_fnd_record(namebuf,sheet,buf);direct_datafile=0;
  377.   p=find_word_start(buf); if(*p==0) return -1;
  378.   i=*p-'0'; if(i>5 || i<0) i=-1;
  379.   if((isexam || score_isexam) && i==0) {
  380.     p=getvar("wims_user"); if(p!=NULL && strcmp(p,"supervisor")==0) i=1;
  381.   }
  382.   res=i;
  383.   if (res == 0 || res > 2)
  384.     goto ret;
  385.   if (strcmp(score_user,"supervisor")==0 || score_user[0]==0)
  386.     goto ret;
  387.   fnd_line(buf,lnb,buf1);
  388.   rows2lines(buf1);
  389.   mkfname(namebuf,"%s/%s/.users/%s",class_base,classe,score_user);
  390.   for(i=1;;++i){
  391.     fnd_line(buf1,i,buf);
  392.     if(*buf==0) break;
  393.     for (j=1;;++j){
  394.             fnd_item(buf,j,buf2);
  395.             if (buf2[0]==0) {res = 3; goto ret;}
  396.             p1=strchr(buf2,'=');
  397.             if(p1==NULL) break;
  398.             *p1=0;
  399.             snprintf(buf3,sizeof(buf3),"%s_%s","user_techvar",buf2);
  400.             getdef(namebuf,buf3,buf4);
  401.             if(strcmp(buf4,p1+1)) break;
  402.           }
  403.   }
  404.   ret:
  405.   return res;
  406. }
  407.  
  408. /* return 1 if a word of bf2 is a substring of host
  409.   and if time restrictions are verified for wims_user
  410.  * Content of bf2 is destroyed.
  411.  */
  412. int _subword(char bf2[],char *ftbuf)
  413. {
  414.   char *p1, *p2;
  415.   for(p1=strchr(bf2,'\\'); p1!=NULL; p1=strchr(p1+1,'\\')) {
  416.     char buf[MAX_LINELEN+1], buf2[MAX_LINELEN+1], fbuf[MAX_FNAME+1];
  417.     char *classp, *classp2, *userp, *scp;
  418.     classp=getvar("wims_class"); userp=getvar("wims_user");
  419.     if(classp==NULL || userp==NULL || *classp==0 || *userp==0) break;
  420.     scp=getvar("wims_superclass");
  421.     if(scp!=NULL && *scp!=0) classp2=scp; else classp2=classp;
  422.     if(p1>bf2 && !isspace(*(p1-1))) continue;
  423.     if(!isalnum(*(p1+1))) continue;
  424.     p2=find_word_end(p1); if(p2>=p1+MAX_NAMELEN) continue;
  425.     memmove(buf2, p1+1, p2-p1-1); buf2[p2-p1-1]=0;
  426.     /* get value of technical variable for user */
  427.     snprintf(buf,sizeof(buf),"user_techvar_%s",buf2);
  428.     if(strcmp(userp,"supervisor")==0)
  429.       mkfname(fbuf,"%s/%s/supervisor",class_base,classp);
  430.     else
  431.       mkfname(fbuf,"%s/%s/.users/%s",class_base,classp2,userp);
  432.     getdef(fbuf,buf,buf2);
  433.     /* end value for the user */
  434.     if(buf2[0]==0) ovlstrcpy(buf2,"EMPTY"); /* in case of no value defined for the user*/
  435.     /* get time restriction for this value */
  436.     snprintf(buf,sizeof(buf),"techvar_%s",buf2);
  437.     /* mkfname(fbuf,"%s/%s/.E%s",class_base,classp,sheet);
  438.      * read time restriction corresponding to the value of
  439.      * technical variable in the file of the sheet or exam
  440.     */
  441.     getdef(ftbuf,buf,buf2);
  442.     /* value for techvar */
  443.     if(buf2[0]==0) ovlstrcpy(buf2,"none");
  444.     /*string_modify(bf2,p1,p2,buf2);*/
  445.     bf2=buf2;
  446.     p1+=strlen(buf2);
  447.   }
  448.   if((isexam || score_isexam) && bf2[0]=='#') return 1;
  449.   if(wordchr(bf2,"none")!=NULL) return 0;
  450.   if(wordchr(bf2,"all")!=NULL) return 1;
  451.   p1=find_word_start(bf2); if(*p1==0) return 1;
  452.   /* check host and time */
  453.   return checkhostt(p1);
  454. }
  455.  
  456. /* Returns 1 if score registration is open for the user
  457.  * in variable wims_user, 0 otherwise.
  458.  */
  459. int _getscorestatus(char *classe, int sheet)
  460. {
  461.   char nbuf[MAX_LINELEN+1], gbuf[MAX_LINELEN+1];
  462.   char ftbuf[MAX_FNAME+1]="";
  463.   char *es;
  464.  
  465.   if(classe==NULL || *classe==0 || sheet<=0) return 1;
  466.   if(getsheetstatus(classe,sheet)!=1) return 0;
  467.   if(*remote_addr==0) return 0;
  468.   if(isexam || score_isexam) {     /* exam simulation */
  469.     accessfile(nbuf,"r","%s/%s/.E%d",class_base,classe,sheet);
  470.     if(nbuf[0]=='#') return 1;
  471.   }
  472.   /* Global restriction data */
  473.   accessfile(nbuf,"r","%s/%s/.security",class_base,classe);
  474.   if(nbuf[0]) {
  475.     _getdef(nbuf,"allow",gbuf);
  476.     if(*find_word_start(gbuf)!=0 && _subword(gbuf,ftbuf)==0)
  477.       return 0;
  478.     _getdef(nbuf,"except",gbuf);
  479.     if(*find_word_start(gbuf)!=0 && _subword(gbuf,ftbuf)==1)
  480.       return 0;
  481.   }
  482.   /* Sheet restriction data; take in account the technical variables */
  483.   if(isexam || score_isexam) es="E"; else es="";
  484.   accessfile(nbuf,"r","%s/%s/.%s%d",class_base,classe,es,sheet);
  485.   if(*find_word_start(nbuf)==0) return 1;
  486.   /* preparing score restriction file name :*/
  487.   mkfname(ftbuf,"%s/%s/.%s%d",class_base,classe,es,sheet);
  488.   return _subword(nbuf,ftbuf);
  489. }
  490.  
  491. /* Returns 1 if score registration is open for wims_user, 0 otherwise.*/
  492. int getscorestatus(char *classe, int sheet)
  493. {
  494.   if(score_status<0 || score_statussheet!=sheet
  495.      || score_statusisexam!=isexam) {
  496.     score_statussheet=sheet; score_statusisexam=isexam;
  497.     score_status=_getscorestatus(classe,sheet); score_isexam=0;
  498.     if(score_status!=0 && (cmd_type==cmd_new || cmd_type==cmd_renew
  499.                || isexam)) {
  500.       char *p;
  501.       p=getvar("wims_scorereg");
  502.       if(p==NULL || strcmp(p,"suspend")!=0)
  503.          setvar("wims_scoring","pending");
  504.       else setvar("wims_scoring","");
  505.     }
  506.   }
  507.   if(isexam && score_status==0) {
  508.     char *p;
  509.     p=getvar("wims_user");
  510.     if(p==NULL || strcmp(p,"supervisor")!=0)
  511.       user_error("exam_closed");
  512.   }
  513.   return score_status;
  514. }
  515.  
  516. /* Whether score registering is open */
  517. void calc_getscorestatus(char *p)
  518. {
  519.   _scoreparm(p);
  520.   if(*score_class==0 || score_sheet==0 || *score_user==0) {
  521.     *p=0; return;
  522.   }
  523.   if(getscorestatus(score_class, score_sheet))
  524.     ovlstrcpy(p,"yes");
  525.   else ovlstrcpy(p,"no");
  526. }
  527.  
  528. /* get status of a sheet in a class: can be 0, 1, 2 or 3
  529.   (in preparation, active, expired or hidden) */
  530. void calc_getsheetstatus(char *p)
  531. {
  532.   _scoreparm(p);
  533.   if(*score_class==0 || (score_sheet==0 && score_isexam==0)) {
  534.     *p=0; return;
  535.   }
  536.   snprintf(p,20,"%d",getsheetstatus(score_class, score_sheet?score_sheet:score_exam));
  537. }
  538.  
  539. /* whether there are too much tries for the exo return yes or no */
  540. void calc_getscoremaxexotry(char *p)
  541. {
  542.   _scoreparm(p);
  543.   if(*score_class==0 || *score_user==0 || score_sheet==0 || score_exo==0) return;
  544.   if(gettrycheck(score_class, score_user, score_sheet, score_exo)==1)
  545.     ovlstrcpy(p,"yes");
  546.   else ovlstrcpy(p,"no");
  547. }
  548.  
  549. double exam_scoredata[MAX_EXAMS];
  550.  
  551. /* get current exam score */
  552. void exam_currscore(int esh)
  553. {
  554.   char *p, *bf, pb[MAX_FNAME+1];
  555.   char *s, *p1, *p2, *e1, *e2;
  556.   int i;
  557.   for(i=0;i<MAX_EXAMS;i++) exam_scoredata[i]=-1000;
  558.   /* session_prefix is not yet defined here */
  559.   s=getvar("wims_session"); if(s==NULL || *s==0) return;
  560.   mystrncpy(pb,s,sizeof(pb));
  561.   p=strchr(pb,'_'); if(p!=NULL) *p=0;
  562.   bf=readfile(mkfname(NULL,"%s/%s/examscore.%d",session_dir,pb,esh),NULL,WORKFILE_LIMIT);
  563.   if(bf==NULL) return;
  564.   for(p1=bf;*p1;p1=p2) {
  565.     p2=strchr(p1,'\n'); if(*p2) *p2++=0;
  566.     else p2=p1+strlen(p1);
  567.     p1=find_word_start(find_word_end(find_word_start(p1)));
  568.     e1=find_word_end(p1); if(*e1) *e1++=0;
  569.     e1=find_word_start(e1); e2=find_word_start(find_word_end(e1));
  570.     *find_word_end(e1)=0;
  571.     i=atoi(p1);
  572.     if(i>=1 && i<=MAX_EXAMS &&
  573.        exam_scoredata[i-1]==-1000 && strcmp(e1,"score")==0) {
  574.       *find_word_end(e2)=0;
  575.       exam_scoredata[i-1]=atof(e2);
  576.     }
  577.   }
  578.   free(bf);
  579. }
  580.  
  581. /* Gather exam score. */
  582. void calc_examscore(char *p)
  583. {
  584.   char *p1;
  585.   int i;
  586.   char *withoutip;
  587.  
  588.   _scoreparm(p); *p=0;
  589.   withoutip=getvar("wims_examscore_withoutip");
  590.  
  591.   if(*score_class==0 || *score_user==0) return;
  592.   if(getscoreuser(score_class,score_user)<0) return;
  593.   p1=p;
  594.   if(withoutip!=NULL && strcmp(withoutip,"yes")==0) {
  595.     for(i=0; i<examcnt && p1-p<MAX_LINELEN-32; i++) {
  596.     p1=moneyprint(p1,rscore[examstart+i].best); *p1++=' ';
  597.     }
  598.   } else {
  599.     for(i=0; i<examcnt && p1-p<MAX_LINELEN-32; i++) {
  600.       p1=moneyprint(p1,rscore[examstart+i].score); *p1++=' ';
  601.     }
  602.   }
  603.   *p1++='\n';
  604.   for(i=0; i<examcnt && p1-p<MAX_LINELEN-32; i++) {
  605.     p1=moneyprint(p1,rscore[examstart+i].require); *p1++=' ';
  606.     p1=moneyprint(p1,floor(rscore[examstart+i].mean/2)); *p1++=' ';
  607.     p1=moneyprint(p1,(int) rscore[examstart+i].mean%2); *p1++='\n';
  608.   }
  609.   *p1=0;
  610. }
  611.  
  612. /* check score dependency.
  613.  * returns 1 if requirements are met.
  614.  */
  615. int _depcheck(char *ds, struct scoreresult *rs, int ecnt)
  616. {
  617.   char *p1, *p2, *p3, *p4, *pp;
  618.   int perc, t, sum;
  619.   double tgot, ttot, tmean;
  620.  
  621.   for(p1=ds; *p1; p1=p3) {
  622.     p2=strchr(p1,':'); if(p2==NULL) break;
  623.     *p2++=0; p2=find_word_start(p2);
  624.     for(p3=p2; myisdigit(*p3); p3++);
  625.     if(p3<=p2) break;
  626.     if(*p3) *p3++=0;
  627.     perc=atoi(p2);
  628.     if(perc<=0 || perc>100) break;
  629.     for(pp=p1; *pp; pp++) if(!myisdigit(*pp)) *pp=' ';
  630.     tgot=ttot=tmean=0; sum=0;
  631.     for(pp=find_word_start(p1); *pp; pp=find_word_start(p4)) {
  632.       p4=find_word_end(pp); if(*p4) *p4++=0;
  633.       t=atoi(pp); if(t<=0 || t>ecnt) goto lend;
  634.       t--;
  635.       ttot+=rs[t].require; tgot+=rs[t].score; tmean+=rs[t].mean;
  636.       sum++;
  637.     }
  638.     if(ttot<10) continue;
  639.     if(tgot/ttot*sqrt(tmean/(sum*10))*100<perc) {
  640.       for(pp=p1;pp<p2-1;pp++) if(!*pp) *pp=',';
  641.       *pp=0; setvar("dep_list",p1);
  642.       return 0;
  643.     }
  644.   lend: ;
  645.   }
  646.   return 1;
  647. }
  648.  
  649. int depcheck(char *sh, int exo, char *deps)
  650. {
  651.   char buf[MAX_LINELEN+1];
  652.   char *s, sbuf[64];
  653.   int i, is;
  654.  
  655.   s=getvar("wims_session");
  656.   if(s==NULL || *s==0 || strstr(s,"robot")!=NULL) return 0;
  657.   mystrncpy(sbuf,s,sizeof(sbuf));
  658.   s=strchr(sbuf,'_'); if(s) *s=0;
  659.   accessfile(buf,"r","../sessions/%s/exodep.%s",sbuf,sh);
  660.   if(buf[0]==0) {     /* no dep file found */
  661.     is=atoi(sh); if(is<=0 || is>totsheets) return 0;
  662.     s=getvar("wims_class"); if(s==NULL || *s==0) return 0;
  663.     getscoreuser(s,"");
  664.     return _depcheck(deps,rscore+sheetstart[is-1],shexocnt[is-1]);
  665.   }
  666.   for(i=1,s=strchr(buf,':'); s && i<exo; i++, s=strchr(s+1,':'));
  667.   if(s==NULL) return 0;     /* bad file or exo number */
  668.   if(myisdigit(*++s)) return 0; else return 1;
  669. }
  670.  
  671. int exam_depcheck(char *deps, int exam)
  672. {
  673.   static struct scoreresult esc[MAX_EXAMS];
  674.   int i;
  675.   exam_currscore(exam);
  676.   for(i=0;i<MAX_EXAMS;i++) {
  677.     esc[i].require=esc[i].mean=10;
  678.     if(exam_scoredata[i]==-1000) esc[i].score=0;
  679.     else esc[i].score=exam_scoredata[i];
  680.   }
  681.   return _depcheck(deps,esc,MAX_EXAMS);
  682. }
  683.  
  684. /* public sheet gives she=0 */
  685. /* return 1 if score is no more taken in account because of exotrymax */
  686. int gettrycheck(char *classe, char *user, int she, int exo) {
  687.   char *s;
  688.   int sh, ex, i;
  689.   if(classe==NULL || *classe==0 || user==NULL || *user==0) return 0;
  690.   if (she<=0) return 0;
  691.     if(strcmp(user,"supervisor")==0) return 0;
  692.   s=getvar("exotrymax");
  693.   if(s==NULL || *s==0) return 0;
  694.   getscoreuser(classe,user);
  695.   char *p=getvar("wims_scorereg");
  696.   for(i=0;i<scorecnt;i++) {
  697.     sh=rscore[i].sh+1;
  698.     if (she!=sh) continue;
  699.     ex=rscore[i].exo+1;
  700.     if(exo!=ex) continue;
  701.     if(cmd_type==cmd_new || cmd_type==cmd_renew)
  702.       if(rscore[i].new >= atoi(s)) {
  703.         if(strcmp(p,"suspend")!=0) setvar("wims_scorereg","exotrymax");
  704.         return 1;
  705.     }
  706.     if(rscore[i].new > atoi(s)){
  707.       if(strcmp(p,"suspend")!=0) setvar("wims_scorereg","exotrymax");
  708.       return 1;
  709.     }
  710.   }
  711.   return 0;
  712. }
  713.  
  714. /* return seed if the seed should be kept and NULL if not */
  715. char *getseedscore(char *classe, char *user, int she, int exo) {
  716.   char *s;
  717.   int sh, ex, i;
  718.   if (she<=0) return NULL;
  719.   if(strcmp(user,"supervisor")==0) return NULL;
  720.   s=getvar("seedrepeat");
  721.   if(s==NULL || *s==0 || atoi(s)<=0) return NULL;
  722.   getscoreuser(classe,user);
  723.   for(i=0;i<scorecnt;i++) {
  724.     sh=rscore[i].sh+1;
  725.     if (she!=sh) continue;
  726.     ex=rscore[i].exo+1;
  727.     if(exo!=ex) continue;
  728.     if(atoi(rscore[i].seedlast)==0) {
  729.       char *seed=getvar("wims_seed");
  730.       return seed;
  731.     }
  732.     if(rscore[i].seedlastcnt > MAX_SEEDSCORE) return NULL;
  733.     if(atoi(s)>0 && rscore[i].seedlastcnt >= atoi(s) && cmd_type!=cmd_next) return NULL;
  734.     if(rscore[i].seedscorelast < 10) return rscore[i].seedlast;
  735.   };
  736.   return NULL;
  737. }
  738.