Back to index

wims  3.65+svn20090927
score.c
Go to the documentation of this file.
00001 /*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
00002  *
00003  *  This program is free software; you can redistribute it and/or modify
00004  *  it under the terms of the GNU General Public License as published by
00005  *  the Free Software Foundation; either version 2 of the License, or
00006  *  (at your option) any later version.
00007  *
00008  *  This program is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  *  GNU General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU General Public License
00014  *  along with this program; if not, write to the Free Software
00015  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00016  */
00017 
00018        /* Routines treating user scores. */
00019 
00020 double oldfactor=0.85;      /* quality factor, should remain stable. */
00021 
00022 enum{ sr_require, sr_weight, sr_score, sr_mean, sr_remain};
00023 char scorebuf[MAX_CLASSEXOS*sizeof(scoreresult)+32];
00024 struct scoreresult *rscore;
00025 int scorecnt;
00026 double scoresum[MAX_SHEETS];
00027 int sheetstart[MAX_SHEETS], shexocnt[MAX_SHEETS];
00028 int examstart, examcnt;
00029 char rscore_class[MAX_CLASSLEN+1];
00030 char rscore_user[MAX_NAMELEN+1];
00031 
00032 int totsheets=0;
00033 int score_ispublic=0;
00034 int score_status=-1;        /* save of score status */
00035 int score_statussheet=-1;
00036 int score_statusisexam=-1;
00037 double scorerecfactor=0.9;
00038 
00039        /* gather user score, core routine. */
00040 int getscoreuser(char *classe, char *user)
00041 {
00042     int i, j, osh, sh;
00043     double s;
00044     char *nowuser, *nowsheet, *nowexo, *nowscore;
00045     char *pp;
00046     if(*user==0) {
00047        user=getvar("wims_user");
00048        if(user==NULL || *user==0) return -1;
00049     }
00050     if(strcmp(classe,rscore_class)==0 && strcmp(user,rscore_user)==0) return 0;
00051     nowsheet=nowexo=nowscore="";
00052     nowuser=getvar("wims_user"); if(nowuser!=NULL && strcmp(user,nowuser)==0) {
00053        nowscore=getvar("module_score"); if(nowscore!=NULL && *nowscore!=0) {
00054            nowsheet=getvar("wims_sheet"); if(nowsheet==NULL) nowsheet="";
00055            nowexo=getvar("wims_exo"); if(nowexo==NULL) nowexo="";
00056        }
00057        else nowscore="";
00058     }
00059     snprintf(scorebuf+sizeof(int),sizeof(scorebuf)-sizeof(int),
00060             "-c%s -u%s getscore %s %s %s",
00061             classe,user,nowsheet,nowexo,nowscore);
00062     i=kerneld(scorebuf,sizeof(scorebuf)); if(i<0) 
00063       internal_error("getscoreuser(): daemon failure.");
00064     if(memcmp(scorebuf+sizeof(int),"OK",2)!=0) {
00065        if(memcmp(scorebuf+sizeof(int),"ERROR",5)==0) {
00066            module_error(find_word_start(scorebuf+sizeof(int)+8));
00067        }
00068        else internal_error("getscoreuser(): communication error with wimslogd.");
00069     }
00070     pp=scorebuf+sizeof(int)+3; rscore=(struct scoreresult *) pp;
00071     scorecnt=(i-sizeof(int)-3)/sizeof(scoreresult);
00072     if(scorecnt>MAX_CLASSEXOS) module_error("too_many_exercises");
00073     s=0; for(i=osh=0;i<scorecnt;i++) {
00074        sh=(rscore[i].num>>8)+1;
00075        if(sh<1 || sh>MAX_SHEETS) break;
00076        if(osh>0 && osh<sh) {scoresum[osh-1]=s; s=0;}
00077        for(;osh<sh && osh<MAX_SHEETS;osh++) sheetstart[osh]=i;
00078        s+=rscore[i].require*rscore[i].weight;
00079     }
00080     if(osh>0) scoresum[osh-1]=s; totsheets=osh;
00081     for(j=0;j<totsheets-1;j++) shexocnt[j]=sheetstart[j+1]-sheetstart[j];
00082     shexocnt[totsheets-1]=i-sheetstart[totsheets-1];
00083     examstart=i; examcnt=scorecnt-examstart;
00084     mystrncpy(rscore_class,classe,sizeof(rscore_class));
00085     mystrncpy(rscore_user,user,sizeof(rscore_user));
00086     return 0;
00087 }
00088 
00089 char *scorepname[]={
00090      "class","user","sheet","work","exam"
00091 };
00092 #define scorepname_no (sizeof(scorepname)/sizeof(scorepname[0]))
00093 char score_class[MAX_CLASSLEN+1];
00094 int score_sheet,score_exo,score_isexam;
00095 char score_user[256];
00096 
00097        /* Uniformed treatment of score command parameters
00098         * format: class=? user=? sheet=? work=?
00099         * all are optional. */
00100 void _scoreparm(char *p)
00101 {
00102     int i;
00103     char *pn, *pe, *pd, *pf;
00104     char sav;
00105     
00106     score_sheet=score_exo=score_isexam=score_ispublic=0; *score_class=0;
00107     score_user[0]=0;
00108     for(i=0;i<scorepname_no;i++) {
00109        pf=p;
00110        ahead:
00111        pn=strstr(pf,scorepname[i]); pf=pn+1;
00112        if(pn==NULL) continue;
00113        if(pn>p && !isspace(*(pn-1))) goto ahead;
00114        pe=find_word_start(pn+strlen(scorepname[i]));
00115        if(*pe!='=') goto ahead;
00116        pd=find_word_start(pe+1);
00117        pf=find_word_end(pd);
00118        if(pf<=pd) continue;
00119        sav=*pf; *pf=0;
00120        switch(i) {
00121            case 0: /* class */
00122              mystrncpy(score_class,pd,sizeof(score_class)); break;
00123            case 1: /* user */
00124              mystrncpy(score_user,pd,sizeof(score_user)); break;
00125            case 2: { /* sheet */
00126               if(*pd=='P') {pd++; score_ispublic=1;}
00127               score_sheet=atoi(pd);
00128               break;
00129            }
00130            case 3: /* work */
00131              score_exo=atoi(pd); break;
00132            case 4: /* exam */
00133              score_isexam=1; break;
00134        }
00135        *pf=sav; strcpy(pn, pf);
00136     }
00137     *p=0;
00138     if((*score_class!=0 || score_user[0]!=0) && !trusted_module()) {
00139        module_error("not_trusted"); return;
00140     }
00141     if(*score_class==0) {
00142        char *classe;
00143        classe=getvar("wims_class");
00144        if(classe==NULL || *classe==0) return;
00145        else mystrncpy(score_class,classe,sizeof(score_class));
00146     }
00147     if(score_user[0]==0) {
00148        char *user;
00149        user=getvar("wims_user");
00150        if(user!=NULL) mystrncpy(score_user,user,sizeof(score_user));
00151     }
00152 }
00153 
00154        /* gather user score. */
00155 void _getscore(char *p,int dtype)
00156 {
00157     int i,sh,ex,osh;
00158     float d;
00159     char *p1;
00160 
00161     _scoreparm(p);
00162     if(score_class==0 || *score_user==0) return;
00163     if(getscoreuser(score_class,score_user)<0) return;
00164     for(i=osh=0,p1=p;i<scorecnt && p1-p<MAX_LINELEN-32;i++) {
00165        sh=(rscore[i].num>>8)+1; if(sh<1 || sh>MAX_SHEETS) break;
00166        if(score_sheet!=0) {
00167            if(sh<score_sheet) continue;
00168            if(sh>score_sheet || sh>MAX_SHEETS) break;
00169        }
00170        ex=((rscore[i].num)&255)+1;
00171        if(score_exo!=0 && ex!=score_exo) continue;
00172        if(osh!=0 && sh!=osh) *p1++='\n';
00173        switch(dtype) {
00174            case sr_require: {d=rscore[i].require; break;}
00175            case sr_weight: {d=rscore[i].weight; break;}
00176            case sr_score: {d=rscore[i].score; break;}
00177            case sr_mean: {d=rscore[i].mean; break;}
00178            case sr_remain: {d=rscore[i].require-rscore[i].score; break;}
00179            default: {d=0; break;}
00180        }
00181        p1=moneyprint(p1,d); *p1++=' ';
00182        osh=sh;
00183     }
00184     *p1++='\n'; *p1=0;
00185 }
00186 
00187        /* gather user score. */
00188 void calc_getscore(char *p)
00189 {
00190     _getscore(p,sr_score);
00191 }
00192 
00193        /* gather user score average. */
00194 void calc_getscoremean(char *p)
00195 {
00196     _getscore(p,sr_mean);
00197 }
00198 
00199        /* gather remaining of score to get for user. */
00200 void calc_getscoreremain(char *p)
00201 {
00202     _getscore(p,sr_remain);
00203 }
00204 
00205        /* Require score table. */
00206 void calc_getscorerequire(char *p)
00207 {
00208     _getscore(p,sr_require);
00209 }
00210 
00211        /* Score weight table. */
00212 void calc_getscoreweight(char *p)
00213 {
00214     _getscore(p,sr_weight);
00215 }
00216 
00217        /* percentage of work done for each sheet. */
00218 void calc_getscorepercent(char *p)
00219 {
00220     int i,j,jend;
00221     double tot, mean, d;
00222     char *p1;
00223 
00224     _scoreparm(p);
00225     if(score_class==0 || *score_user==0) return;
00226     if(getscoreuser(score_class,score_user)<0) return;
00227     for(p1=p,i=0;i<totsheets && p1-p<MAX_LINELEN-32;i++) {
00228        if(scoresum[i]==0) {
00229            strcpy(p1,"0 0\n"); p1+=strlen(p1); continue;
00230        }
00231        if(score_sheet!=0 && i!=score_sheet-1) continue;
00232        if(scoresum[i]<=0) *p1++='\n';
00233        tot=mean=0; jend=sheetstart[i]+shexocnt[i];
00234        for(j=sheetstart[i];j<jend;j++) {
00235               /* if mean<1 then ignore score.
00236                * if mean<2 then half score. */
00237            if(rscore[j].mean>=1) {
00238               double dt=rscore[j].score;
00239               if(rscore[j].mean<2) dt=dt/2;
00240               d=dt*rscore[j].weight;
00241               mean+=rscore[j].mean*d; tot+=d;
00242            }
00243        }
00244        if(tot>0) d=mean/tot; else d=0;
00245        p1=moneyprint(p1,rint(100*tot/scoresum[i])); *p1++=' ';
00246        p1=moneyprint(p1,d); *p1++='\n';
00247     }
00248     *p1=0;
00249 }
00250 
00251        /* Returns the status of a sheet, or -1 if error */
00252 int getsheetstatus(char *classe, int sheet)
00253 {
00254     char *p, *st, buf[MAX_LINELEN+1], namebuf[MAX_FNAME+1];
00255     int i;
00256 
00257     if(isexam || score_isexam) st="exam"; else st="sheet";
00258     mkfname(namebuf,"%s/%s/%ss/.%ss",class_base,classe,st,st);
00259     direct_datafile=1;datafile_fnd_record(namebuf,sheet,buf);direct_datafile=0;
00260     p=find_word_start(buf); if(*p==0) return -1;
00261     i=*p-'0'; if(i>5 || i<0) i=-1;
00262     if((isexam || score_isexam) && i==0) {
00263        p=getvar("wims_user"); if(p!=NULL && strcmp(p,"supervisor")==0) i=1;
00264     }
00265     return i;
00266 }
00267 
00268        /* return 1 if a word of bf2 is a substring of host.
00269         * Content of bf2 is destroyed. */
00270 int _subword(char bf2[])
00271 {
00272     char *p1, *p2;
00273     for(p1=strchr(bf2,'\\'); p1!=NULL; p1=strchr(p1+1,'\\')) {
00274        char buf[MAX_LINELEN+1], buf2[MAX_LINELEN+1], fbuf[MAX_FNAME+1];
00275        char *classp, *classp2, *userp, *scp;
00276        classp=getvar("wims_class"); userp=getvar("wims_user");
00277        if(classp==NULL || userp==NULL || *classp==0 || *userp==0) break;
00278        scp=getvar("wims_superclass");
00279        if(scp!=NULL && *scp!=0) classp2=scp; else classp2=classp;
00280        if(p1>bf2 && !isspace(*(p1-1))) continue;
00281        if(!isalnum(*(p1+1))) continue;
00282        p2=find_word_end(p1); if(p2>=p1+MAX_NAMELEN) continue;
00283        memmove(buf2, p1+1, p2-p1-1); buf2[p2-p1-1]=0;
00284        snprintf(buf,sizeof(buf),"user__%s",buf2);
00285        if(strcmp(userp,"supervisor")==0)
00286          mkfname(fbuf,"%s/%s/supervisor",class_base,classp);
00287        else
00288          mkfname(fbuf,"%s/%s/.users/%s",class_base,classp2,userp);
00289        getdef(fbuf,buf,buf2); if(buf2[0]==0) strcpy(buf2,"none");
00290        string_modify(bf2,p1,p2,buf2);
00291        p1+=strlen(buf2);
00292     }
00293     if((isexam || score_isexam) && bf2[0]=='#') return 1;
00294     if(wordchr(bf2,"none")!=NULL) return 0;
00295     if(wordchr(bf2,"all")!=NULL) return 1;
00296     p1=find_word_start(bf2); if(*p1==0) return 1;
00297     return checkhostt(p1);
00298 }
00299 
00300        /* Returns 1 if score registration is open, 0 otherwise. */
00301 int _getscorestatus(char *classe, int sheet)
00302 {
00303     char nbuf[MAX_LINELEN+1], gbuf[MAX_LINELEN+1];
00304     char *es;
00305 
00306     if(classe==NULL || *classe==0 || sheet<=0) return 1;
00307     if(getsheetstatus(classe,sheet)!=1) return 0;
00308     if(*remote_addr==0) return 0;
00309     if(isexam || score_isexam) {   /* exam simulation */
00310        accessfile(nbuf,"r","%s/%s/.E%d",class_base,classe,sheet);
00311        if(nbuf[0]=='#') return 1;
00312     }
00313        /* Global restriction data */
00314     accessfile(nbuf,"r","%s/%s/.security",class_base,classe);
00315     if(nbuf[0]) {
00316        _getdef(nbuf,"allow",gbuf);
00317        if(*find_word_start(gbuf)!=0 && _subword(gbuf)==0)
00318          return 0;
00319        _getdef(nbuf,"except",gbuf);
00320        if(*find_word_start(gbuf)!=0 && _subword(gbuf)==1)
00321          return 0;
00322     }
00323 
00324        /* Sheet restriction data */
00325     if(isexam || score_isexam) es="E"; else es="";
00326     accessfile(nbuf,"r","%s/%s/.%s%d",class_base,classe,es,sheet);
00327     if(*find_word_start(nbuf)==0) return 1;
00328     return _subword(nbuf);
00329 }
00330 
00331        /* Returns 1 if score registration is open, 0 otherwise. */
00332 int getscorestatus(char *classe, int sheet)
00333 {
00334     if(score_status<0 || score_statussheet!=sheet
00335        || score_statusisexam!=isexam) {
00336        score_statussheet=sheet; score_statusisexam=isexam;
00337        score_status=_getscorestatus(classe,sheet); score_isexam=0;
00338        if(score_status==1 && (cmd_type==cmd_new || cmd_type==cmd_renew
00339                             || isexam)) {
00340            char *p;
00341            p=getvar("wims_scorereg");
00342            if(p==NULL || strcmp(p,"suspend")!=0)
00343              setvar("wims_scoring","pending");
00344            else setvar("wims_scoring","");
00345        }
00346     }
00347     if(isexam && score_status==0) {
00348        char *p;
00349        p=getvar("wims_user"); if(p==NULL || strcmp(p,"supervisor")!=0)
00350          user_error("exam_closed");
00351     }
00352     return score_status;
00353 }
00354 
00355        /* Whether score registering is open */
00356 void calc_getscorestatus(char *p)
00357 {
00358     _scoreparm(p);
00359     if(score_class==0 || score_sheet==0 || *score_user==0) {
00360         *p=0; return;
00361     }
00362     if(getscorestatus(score_class, score_sheet))
00363       strcpy(p,"yes");
00364     else strcpy(p,"no");
00365 }
00366 
00367 double exam_scoredata[64];
00368 
00369        /* get current exam score */
00370 void exam_currscore(int esh)
00371 {
00372     char *p, *bf, pb[MAX_FNAME+1];
00373     char *s, *p1, *p2, *e1, *e2;
00374     int i;
00375     
00376     for(i=0;i<MAX_EXOS;i++) exam_scoredata[i]=-1000;
00377        /* session_prefix is not yet defined here */
00378     s=getvar("wims_session"); if(s==NULL || *s==0) return;
00379     mystrncpy(pb,s,sizeof(pb));
00380     p=strchr(pb,'_'); if(p!=NULL) *p=0;
00381     bf=readfile(mkfname(NULL,"%s/%s/examscore.%d",session_dir,pb,esh),NULL,WORKFILE_LIMIT);
00382     if(bf==NULL) return;
00383     for(p1=bf;*p1;p1=p2) {
00384        p2=strchr(p1,'\n'); if(*p2) *p2++=0;
00385        else p2=p1+strlen(p1);
00386        p1=find_word_start(find_word_end(find_word_start(p1)));
00387        e1=find_word_end(p1); if(*e1) *e1++=0;
00388        e1=find_word_start(e1); e2=find_word_start(find_word_end(e1));
00389        *find_word_end(e1)=0;
00390        i=atoi(p1);
00391        if(i>=1 && i<=MAX_EXOS && 
00392           exam_scoredata[i-1]==-1000 && strcmp(e1,"score")==0) {
00393            *find_word_end(e2)=0;
00394            exam_scoredata[i-1]=atof(e2);
00395        }
00396     }
00397     free(bf);
00398 }
00399 
00400        /* Gather exam score. */
00401 void calc_examscore(char *p)
00402 {
00403     char *p1;
00404     int i;
00405     
00406     _scoreparm(p); *p=0;
00407     if(*score_class==0 || *score_user==0) return;
00408     if(getscoreuser(score_class,score_user)<0) return;
00409     p1=p;
00410     for(i=0; i<examcnt && p1-p<MAX_LINELEN-32; i++) {
00411        p1=moneyprint(p1,rscore[examstart+i].score); *p1++=' ';
00412     }
00413     *p1++='\n';
00414     for(i=0; i<examcnt && p1-p<MAX_LINELEN-32; i++) {
00415        p1=moneyprint(p1,rscore[examstart+i].require); *p1++=' ';
00416        p1=moneyprint(p1,floor(rscore[examstart+i].mean/2)); *p1++=' ';
00417        p1=moneyprint(p1,(int) rscore[examstart+i].mean%2); *p1++='\n';
00418     }
00419     *p1=0;
00420 }
00421 
00422        /* check score dependency.
00423         * returns 1 if requirements are met. */
00424 int _depcheck(char *ds, struct scoreresult *rs, int ecnt)
00425 {
00426     char *p1, *p2, *p3, *p4, *pp;
00427     int perc, t, sum;
00428     double tgot, ttot, tmean;
00429     
00430     for(p1=ds; *p1; p1=p3) {
00431        p2=strchr(p1,':'); if(p2==NULL) break;
00432        *p2++=0; p2=find_word_start(p2);
00433        for(p3=p2; myisdigit(*p3); p3++);
00434        if(p3<=p2) break;
00435        *p3++=0; perc=atoi(p2);
00436        if(perc<=0 || perc>100) break;
00437        for(pp=p1; *pp; pp++) if(!myisdigit(*pp)) *pp=' ';
00438        tgot=ttot=tmean=0; sum=0;
00439        for(pp=find_word_start(p1); *pp; pp=find_word_start(p4)) {
00440            p4=find_word_end(pp); if(*p4) *p4++=0;
00441            t=atoi(pp); if(t<=0 || t>ecnt) goto lend;
00442            t--;
00443            ttot+=rs[t].require; tgot+=rs[t].score; tmean+=rs[t].mean;
00444            sum++;
00445        }
00446        if(ttot<10) continue;
00447        if(tgot/ttot*sqrt(tmean/(sum*10))*100<perc) {
00448            for(pp=p1;pp<p2-1;pp++) if(!*pp) *pp=',';
00449            *pp=0; setvar("dep_list",p1);
00450            return 0;
00451        }
00452        lend: ;
00453     }
00454     return 1;
00455 }
00456 
00457 int depcheck(char *sh, int exo, char *deps)
00458 {
00459     char buf[MAX_LINELEN+1];
00460     char *s, sbuf[64];
00461     int i, is;
00462     
00463     s=getvar("wims_session");
00464     if(s==NULL || *s==0 || strstr(s,"robot")!=NULL) return 0;
00465     mystrncpy(sbuf,s,sizeof(sbuf));
00466     s=strchr(sbuf,'_'); if(s) *s=0;
00467     accessfile(buf,"r","../sessions/%s/exodep.%s",sbuf,sh);
00468     if(buf[0]==0) {  /* no dep file found */
00469        is=atoi(sh); if(is<=0 || is>totsheets) return 0;
00470        s=getvar("wims_class"); if(s==NULL || *s==0) return 0;
00471        getscoreuser(s,"");
00472        return _depcheck(deps,rscore+sheetstart[is-1],shexocnt[is-1]);
00473     }
00474     for(i=1,s=strchr(buf,':'); s && i<exo; i++, s=strchr(s+1,':'));
00475     if(s==NULL) return 0;   /* bad file or exo number */
00476     if(myisdigit(*++s)) return 0; else return 1;
00477 }
00478 
00479 int exam_depcheck(char *deps, int exam)
00480 {
00481     struct scoreresult esc[MAX_EXOS];
00482     int i;
00483     exam_currscore(exam);
00484     for(i=0;i<MAX_EXOS;i++) {
00485        esc[i].require=esc[i].mean=10;
00486        if(exam_scoredata[i]==-1000) esc[i].score=0;
00487        else esc[i].score=exam_scoredata[i];
00488     }
00489     return _depcheck(deps,esc,MAX_EXOS);
00490 }
00491