/* interfaces to the C portions of CAPA for grader
Copyright (C) 1992-2000 Michigan State University
The CAPA system 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.
The CAPA system 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 the CAPA system; see the file COPYING. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
As a special exception, you have permission to link this program
with the TtH/TtM library and distribute executables, as long as you
follow the requirements of the GNU GPL in regard to all of the
software in the executable aside from TtH/TtM.
*/
/*
* grader.funct.c
* Guy Albertelli II 1996
*/
#include <stdio.h>
#include <tk.h>
#include <pProj/capaCommon.h>
#include <grader.h>
#include <common.h>
#include <ctype.h>
#include <time.h>
/*
* used to remeber the weights and partial credit from a parse for when
* setting a DBHeader
*/
/* Reads a header form the file and sets up the time and date variables
*/
int capaGetHeader(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
T_header header;
char * setNumber,buf[BUFFER_SIZE],*sectionNumber,dateStr[BUFFER_SIZE];
int set,section,result;
setNumber=Tcl_GetVar(interp,"gSetLoad",TCL_GLOBAL_ONLY);
sectionNumber=Tcl_GetVar(interp,"gSectionLoad",TCL_GLOBAL_ONLY);
if ( setNumber[0] == '\0' ) return TCL_OK;
if ( sectionNumber[0] == '\0' ) return TCL_OK;
set=atoi(setNumber);
section=atoi(sectionNumber);
result=capa_get_header(&header,set);
if ( result == -1 )
{
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,"0");
return TCL_OK;
}
result=capa_get_date(CHECK_OPEN_DATE,NULL,section,set,dateStr);
if (result<0) {
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,"-1");
return TCL_OK;
}
sscanf(dateStr,"%10c",buf);
buf[10]='\0';
Tcl_SetVar(interp,"gOpenDate",buf,TCL_GLOBAL_ONLY);
sscanf((dateStr)+11,"%5c",buf);
buf[5]='\0';
Tcl_SetVar(interp,"gOpenTime",buf,TCL_GLOBAL_ONLY);
result=capa_get_date(CHECK_DUE_DATE,NULL,section,set,dateStr);
if (result<0) {
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,"-1");
return TCL_OK;
}
sscanf(dateStr,"%10c",buf);
buf[10]='\0';
Tcl_SetVar(interp,"gDueDate",buf,TCL_GLOBAL_ONLY);
sscanf((dateStr)+11,"%5c",buf);
buf[5]='\0';
Tcl_SetVar(interp,"gDueTime",buf,TCL_GLOBAL_ONLY);
result=capa_get_date(CHECK_ANS_DATE,NULL,section,set,dateStr);
if (result<0) {
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,"-1");
return TCL_OK;
}
sscanf(dateStr,"%10c",buf);
buf[10]='\0';
Tcl_SetVar(interp,"gAnswerDate",buf,TCL_GLOBAL_ONLY);
sscanf((dateStr)+11,"%5c",buf);
buf[5]='\0';
Tcl_SetVar(interp,"gAnswerTime",buf,TCL_GLOBAL_ONLY);
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,"1");
capa_mfree(header.weight);
capa_mfree(header.partial_credit);
return TCL_OK;
}
/* get the information for all of the students in the current section
* and puts them into the listbox.
* Arguments: the name of the variable the widget name of the listbox
* is in.
*/
int capaGetStudents(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
T_student *headStudent,*currentStudent;
int result,section,set,setScore,maxScore,num=0;
char buf[BUFFER_SIZE],buf2[BUFFER_SIZE],*answers,*listWidget;
section=atoi(Tcl_GetVar(interp,"gSectionLoad",TCL_GLOBAL_ONLY));
set=atoi(Tcl_GetVar(interp,"gSetLoad",TCL_GLOBAL_ONLY));
if ( (listWidget = Tcl_GetVar(interp,argv[1],
TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)) == NULL)
{
fprintf(stderr,"Tcl_GetVar error\n");
fprintf(stderr,"%s\n",interp->result);
return TCL_ERROR;
}
result=capa_sorted_section(&headStudent,section);
if (result == -1 || result == 0)
{
Tcl_Eval(interp,"displayError \"Invalid section\"");
Tcl_ResetResult(interp);
return TCL_OK;
}
currentStudent=headStudent;
while(currentStudent!=NULL)
{
num++;
setScore = capa_get_score(currentStudent->s_sn,set,&maxScore,&answers);
if ( setScore == -1 ) setScore=0;
sprintf(buf,"%s %s %2d/%2d %2d ",currentStudent->s_nm,
currentStudent->s_sn,setScore,maxScore,
capa_PIN(currentStudent->s_sn,set,0));
capaPrepareBuffer(buf,buf2,0);
sprintf(buf,"%s insert end \"%s\" ",listWidget,buf2);
if (Tcl_Eval(interp,buf) != TCL_OK)
{
fprintf(stderr,"Tcl_Eval error\n");
fprintf(stderr,"%s\n",interp->result);
free_students(headStudent);
return TCL_ERROR;
}
if (!(num%10)) {
if (Tcl_Eval(interp,"update") != TCL_OK)
{
fprintf(stderr,"Tcl_Eval error\n");
fprintf(stderr,"%s\n",interp->result);
free_students(headStudent);
return TCL_ERROR;
}
}
currentStudent=currentStudent->s_next;
capa_mfree(answers);
}
free_students(headStudent);
if (!(num%5)) {
if (Tcl_Eval(interp,"update") != TCL_OK)
{
fprintf(stderr,"Tcl_Eval error\n");
fprintf(stderr,"%s\n",interp->result);
return TCL_ERROR;
}
}
return TCL_OK;
}
/* searches for the section a student is in by either name or number
* Arguments: one of (name or number) and then the name or number to
* search for.
*/
int capaFindSection(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
int errorNm;
char searchStr[MAX_NAME_CHAR+1],buf[MAX_NAME_CHAR+1];
T_student student;
switch(argv[1][1])
{
case 'a':
strncpy(searchStr,argv[2],MAX_NAME_CHAR+1);
if ( (errorNm = capa_student_byname(searchStr,&student ))==0 )
{
sprintf(buf,"%d",0);
}
else
{
sprintf(buf,"%d",student.s_sec);
}
break;
case 'u':
strncpy(searchStr,argv[2],MAX_NAME_CHAR+1);
if ( (errorNm = capa_get_student(searchStr,&student ))==0 )
{
sprintf(buf,"%d",0);
}
else
{
sprintf(buf,"%d",student.s_sec);
}
break;
default:
break;
}
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,buf);
return TCL_OK;
}
/* makes a student report
* Arguments: the student number
*/
int capaGetReportInfo(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
char studentNumber[MAX_STUDENT_NUMBER+1],
lineOne[BUFFER_SIZE],*wgt,*partialCredit;
T_header header;
T_entry entry;
int ii, setIdx, setScores, setValids,
totalSet, totalProbs, neverLogin;
int termScores, termValids;
strncpy(studentNumber,argv[1], MAX_STUDENT_NUMBER+1);
totalSet = howManySetDBFile();
Tcl_ResetResult(interp);
for(termScores=0,termValids=0,setIdx=1;setIdx <= totalSet ;setIdx++)
{
capa_get_entry(&entry, studentNumber, setIdx);
totalProbs = entry.e_probs;
if( capa_get_header( &header, setIdx ) == -1 )
{
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,"File Error");
return TCL_OK;
}
wgt=header.weight;
partialCredit=header.partial_credit;
for(setScores=0, setValids=0,neverLogin=1,ii=0;ii<totalProbs;ii++)
{
switch(entry.answers[ii])
{
case 'Y': case 'y':
neverLogin = 0;
setScores += (wgt[ii] - '0');
setValids += (wgt[ii] - '0');
break;
case '-': case 'N': case 'n':
setValids += (wgt[ii] - '0');
break;
case 'E': case 'e':
break;
default :
if( entry.answers[ii] >= '0' && entry.answers[ii] <= '9' )
{
setScores += (entry.answers[ii] - '0');
setValids += (wgt[ii] - '0');
neverLogin = 0;
}
break;
}
}
entry.answers[totalProbs]='\0'; /* get rid of last unknown chars */
entry.tries[3*totalProbs]='\0';
termScores += setScores;
termValids += setValids;
if(neverLogin)
{
sprintf(lineOne,"%3d -/%3d %s\n",setIdx,setValids,entry.answers);
}
else
{
sprintf(lineOne,"%3d %3d/%3d %s\n",setIdx,setScores,setValids,entry.answers);
}
Tcl_AppendResult(interp,lineOne,NULL);
sprintf(lineOne," %s\n",entry.tries);
Tcl_AppendResult(interp,lineOne,NULL);
capa_mfree(entry.answers);
capa_mfree(entry.tries);
}
sprintf(lineOne,"========================\n Total = %3d/%3d",termScores,termValids);
Tcl_AppendResult(interp,lineOne,NULL);
capa_mfree(header.weight);
capa_mfree(header.partial_credit);
return TCL_OK;
}
int compare_string( a, b)
char *a, *b;
{
return( strcasecmp(a, b) );
}
/* Builds a set summary
* Argument: the filename to write to
*/
int capaGetSetSummary(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
T_student *stuPtr, *currentStudentPtr;
T_header a_header;
int section, set;
int studentCount,currentStudent, setScores, validScores;
char fmt1[64], fmt2[64],buf[BUFFER_SIZE],*str1="Student Name",*str2=" ";
char *answersPtr;
FILE *outputFile;
section=atoi(Tcl_GetVar(interp,"gSectionLoad",TCL_GLOBAL_ONLY));
set=atoi(Tcl_GetVar(interp,"gSetLoad",TCL_GLOBAL_ONLY));
Tcl_ResetResult(interp);
studentCount = capa_sorted_section(&stuPtr, section);
if( studentCount > 0 )
{
if( capa_get_header( &a_header, set) == -1 )
{
Tcl_Eval(interp,"displayerror \"Cannot open set.db file\"");
Tcl_ResetResult(interp);
free_students(stuPtr);
return TCL_OK;
}
capa_mfree(a_header.weight);
capa_mfree(a_header.partial_credit);
sprintf(fmt1,"%%-%ds\t%%%ss\t Score\n", MAX_NAME_CHAR,a_header.num_questions);
outputFile=fopen(argv[1],"w");
fprintf(outputFile, "Section %-3d, Set %-3d Score Report\n",section, set);
fprintf(outputFile, fmt1,str1,str2);
sprintf(fmt1,"%%-%ds\t%%s\t -/%%3d\n", MAX_NAME_CHAR);
sprintf(fmt2,"%%-%ds\t%%s\t%%3d/%%3d\n", MAX_NAME_CHAR);
for(currentStudentPtr=stuPtr,currentStudent=0;currentStudentPtr;
currentStudentPtr=currentStudentPtr->s_next,currentStudent++)
{
sprintf(buf,"updateStatusBar %f",(float)currentStudent/(float)studentCount);
Tcl_Eval(interp,buf);
if( (setScores = capa_get_score(currentStudentPtr->s_sn,
set,&validScores,&answersPtr) ) == -2 )
{
Tcl_Eval(interp,"displayerror \"Cannot open set.db file\"");
Tcl_ResetResult(interp);
free_students(stuPtr);
capa_mfree(answersPtr);
fclose(outputFile);
return TCL_OK;
}
if( setScores < 0 )
{
fprintf(outputFile,fmt1,currentStudentPtr->s_nm,answersPtr,validScores );
}
else
{
fprintf(outputFile,fmt2,currentStudentPtr->s_nm,answersPtr,setScores,validScores );
}
capa_mfree(answersPtr);
}
free_students(stuPtr);
fclose(outputFile);
}
return TCL_OK;
}
/* builds a term summary
* Arguments: filename
*/
int capaGetTermSummary(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
T_student *studentPtr, *currentStudentPtr;
int section, totalSet;
int setIndex, setScores, termScores, validScores, termValids;
int studentCount,currentStudent=1;
char fmt[64];
char *answersPtr,buf[BUFFER_SIZE];
FILE *outputFile;
outputFile=fopen(argv[1],"w");
section=atoi(Tcl_GetVar(interp,"gSectionLoad",TCL_GLOBAL_ONLY));
totalSet = howManySetDBFile();
Tcl_ResetResult(interp);
studentCount = capa_sorted_section(&studentPtr, section);
if( studentCount > 0 )
{
for(currentStudentPtr=studentPtr,currentStudent=1;currentStudentPtr;
currentStudentPtr=currentStudentPtr->s_next,currentStudent++)
{
sprintf(buf,"updateStatusBar %f",(float)currentStudent/(float)studentCount);
Tcl_Eval(interp,buf);
sprintf(fmt,"%%-%ds\n", MAX_NAME_CHAR);
fprintf(outputFile,fmt,currentStudentPtr->s_nm);
for( termScores = 0, termValids = 0, setIndex = 1; setIndex <= totalSet; setIndex++)
{
if( (setScores = capa_get_score(currentStudentPtr->s_sn,
setIndex,&validScores,&answersPtr) ) == -2 )
{
sprintf(buf,"displayerror \"Cannot open set%d.db file\"",setIndex);
Tcl_Eval(interp,buf);
Tcl_ResetResult(interp);
capa_mfree(answersPtr);
free_students(studentPtr);
fclose(outputFile);
return TCL_OK;
}
if( setScores < 0 )
{
fprintf(outputFile,"Set %-3d\t%s\t -/%3d\n", setIndex,answersPtr, validScores);
}
else
{
fprintf(outputFile, "Set %-3d\t%s\t%3d/%3d\n",
setIndex,answersPtr,setScores,validScores );
termScores += setScores;
}
capa_mfree(answersPtr);
termValids += validScores;
}
fprintf(outputFile,"\t\t\tTerm Score = %3d/%3d\n", termScores,termValids);
fprintf(outputFile, "-----------------------------------------------------------------------\n");
}
free_students(studentPtr);
}
fclose(outputFile);
return TCL_OK;
}
extern int Parsemode_f;
/* runs capaParse and puts the results into a text widget
* Arguments: the name it is registered under (enscriptParse, texParse,
* webParse, bubblerParse); what results of the parse to show
* 0 (Problem Only), 1 (Question and Answer), 2 (Answer Only);
* the set number; either (Random or Specific) student; section;
* student Number; student Name ; the name of the variable to
* find the widget name of the text widget to put the text into
*/
int capaTclParse (ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
extern char *EndText_p;
T_student student;
Problem_t *headProblem,*currentProblem;
int numOfQuestions,numAnswers,problemNumber=0;
int result,i=1,j,length;
char *buf, *buf2, *temp, *previewText=NULL;
char lower[32],upper[32],ans[32], unit[32];
double targetAns;
int c_set;
#ifdef GRADER_UPDATE
char *update=";update";
#else
char *update=" ";
#endif
switch(argv[0][0])
{
case 'e':Parsemode_f = ASCII_MODE;break;
case 't':Parsemode_f = TeX_MODE;break;
case 'w':Parsemode_f = HTML_MODE;break;
case 'b':Parsemode_f = BUBBLE_MODE;break;
default:
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,"Invalid call to capaTclParse\n");
return TCL_ERROR;
break;
}
if ( (previewText = Tcl_GetVar(interp,argv[7],
TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)) == NULL)
{
fprintf(stderr,"Tcl_GetVar error\n");
fprintf(stderr,"%s\n",interp->result);
return TCL_ERROR;
}
c_set = atoi(argv[2]);
switch (argv[3][0])
{
case 'R':
result = capa_pick_student(atoi(argv[4]),&student);
if (result == -1)
{
buf=capa_malloc(BUFFER_SIZE,1);
sprintf(buf,"displayError \"There are no students in section %d.\"",
atoi(argv[4]));
Tcl_Eval(interp,buf);
capa_mfree(buf);
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,"-1");
return TCL_OK;
}
result = capa_parse(atoi(argv[2]),&headProblem,student.s_sn,&numOfQuestions,NULL);
break;
case 'S':
result = capa_get_student(argv[5],&student);
if ((result == -1) || (result == 0))
{
buf=capa_malloc(BUFFER_SIZE,1);
sprintf(buf,"displayError \"The student %s does not exist.\"",
argv[5]);
Tcl_Eval(interp,buf);
capa_mfree(buf);
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,"-1");
return TCL_OK;
}
result = capa_parse(atoi(argv[2]),&headProblem,argv[5],&numOfQuestions,NULL);
break;
default:
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,"Invalid 2nd argument to capaTclParse\n");
return TCL_ERROR;
break;
}
if (result==-1)
{
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,"-1");
return TCL_OK;
}
currentProblem=headProblem;
if(argv[1][0] == Q_ANSWER)
{
/*
switch(Parsemode_f)
{
case ASCII_MODE:
sprintf(buf,"Section %d Set %d\n Name: %s PIN: %d\n\n",
student.s_sec, atoi(argv[2]), student.s_nm,
capa_PIN(student.s_sn, atoi(argv[2]),0));
break;
case TeX_MODE:
sprintf(buf,"{\\bf Section %d\\qquad Set %d}\\\\\\medskip \n{\\bf Name: \
%s\\qquad PIN: %d}\\\\ \\bigskip\n\n", student.s_sec, atoi(argv[2]), student.s_nm,
capa_PIN(student.s_sn, atoi(argv[2]),0));
break;
case HTML_MODE:
sprintf(buf,"Section %d Set %d\n Name: %s PIN: %d\n\n",
student.s_sec, atoi(argv[2]), student.s_nm,
capa_PIN(student.s_sn, atoi(argv[2]),0));
break;
case BUBBLE_MODE:
break;
}
j=capaPrepareBuffer(buf,buf2,0);
sprintf(buf,"%s insert end \" %s \" header",previewText,buf2);
if (Tcl_Eval(interp,buf) != TCL_OK)
{
fprintf(stderr,"Tcl_Eval error\n");
fprintf(stderr,"%s\n",interp->result);
return TCL_ERROR;
}
*/
}
while (currentProblem!=NULL)
{
switch (argv[1][0])
{
case Q_PROBLEM:
if (currentProblem->question) {
length=strlen(currentProblem->question);
} else {
length=0;
}
buf=capa_malloc(BUFFER_SIZE+(2*length),1);
buf2=capa_malloc(BUFFER_SIZE+(2*length),1);
if(currentProblem->question) {
j=capaPrepareBuffer(currentProblem->question,buf2,0);
buf2[j-1]='\n';
buf2[j]='\0';
} else {
buf2[0]='\n';buf2[1]='\0';
}
if(currentProblem->question) {
j=capaPrepareBuffer(currentProblem->question,buf2,0);
buf2[j-1]='\n';
buf2[j]='\0';
} else {
buf2[0]='\n';buf2[1]='\0';
}
switch(Parsemode_f)
{
case ASCII_MODE:
sprintf(buf,"%s insert end \"%s \n-----------\n\n\" problem",
previewText,buf2);
break;
case TeX_MODE:
sprintf(buf,"%s insert end \"%s\" problem",previewText,buf2);
break;
case HTML_MODE:
sprintf(buf,"%s insert end \"%s\" problem",previewText,buf2);
break;
case BUBBLE_MODE:
break;
}
if (Tcl_Eval(interp,buf) != TCL_OK)
{
fprintf(stderr,"Tcl_Eval error\n");
fprintf(stderr,"%s\n",interp->result);
return TCL_ERROR;
}
capa_mfree(buf);
capa_mfree(buf2);
break;
case Q_PROBLEM_AND_ANSWER:
if (currentProblem->question) {
length=strlen(currentProblem->question);
} else {
length=0;
}
buf=capa_malloc(BUFFER_SIZE+(2*length),1);
buf2=capa_malloc(BUFFER_SIZE+(2*length),1);
temp=capa_malloc(BUFFER_SIZE+(2*length),1);
j=capaPrepareBuffer(currentProblem->question,buf2,0);
switch(Parsemode_f)
{
case ASCII_MODE:
sprintf(buf,"%s insert end \"%s \n-----------\n\n\" problem",
previewText,buf2);
break;
case TeX_MODE:
sprintf(buf,"%s insert end \"%s\" problem",previewText,buf2);
break;
case HTML_MODE:
sprintf(buf,"%s insert end \"%s\" problem",previewText,buf2);
break;
case BUBBLE_MODE:
break;
}
if (Tcl_Eval(interp,buf) != TCL_OK)
{
fprintf(stderr,"Tcl_Eval error\n");
fprintf(stderr,"%s\n",interp->result);
return TCL_ERROR;
}
capa_mfree(buf);
capa_mfree(buf2);
capa_mfree(temp);
capaInsertAnswer(currentProblem,interp,previewText);
break;
case Q_ANSWER:
print_begin_item(Parsemode_f,interp,previewText,problemNumber+1);
capaInsertAnswer(currentProblem,interp,previewText);
break;
}
currentProblem=currentProblem->next;
problemNumber++;
}
if( ( EndText_p != NULL) )
{
buf=capa_malloc(BUFFER_SIZE+(2*strlen(EndText_p)),1);
buf2=capa_malloc(BUFFER_SIZE+(2*strlen(EndText_p)),1);
temp=capa_malloc(BUFFER_SIZE+(2*strlen(EndText_p)),1);
sprintf(temp,"%s", EndText_p);
j=capaPrepareBuffer(temp,buf2,0);
sprintf(buf,"%s insert end \"%s\" answer%s",previewText,buf2,update);
if (Tcl_Eval(interp,buf) != TCL_OK)
{
fprintf(stderr,"Tcl_Eval error 7\n");
fprintf(stderr,"%s\n",interp->result);
return TCL_ERROR;
}
capa_mfree(buf);
capa_mfree(buf2);
capa_mfree(temp);
}
free_problems(headProblem);
if (result==0)
{
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,"0");
}
else
{
buf=capa_malloc(BUFFER_SIZE,1);
sprintf(buf,"%d",result);
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,buf);
capa_mfree(buf);
}
return TCL_OK;
}
/* setup gQuestionType for all of the questions
* Arguments: number of Questions
*/
int capaGetQuestionTypes(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
int numQuestions,result,i;
T_header header;
char buf[BUFFER_SIZE], buf2[BUFFER_SIZE],*weight;
if (argc != 2)
{
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,"Wrong number of arguments to getQuestionTypes",
NULL);
return TCL_ERROR;
}
numQuestions=atoi(argv[1]);
result = capa_get_header(&header,atoi(Tcl_GetVar(interp,"gSetLoad",
TCL_GLOBAL_ONLY)));
weight=header.weight;
if (result == -1)
{
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,"capa_get_header returned error.",NULL);
return TCL_ERROR;
}
for(i=1;i<=numQuestions;i++)
{
sprintf(buf,"%d",i);
switch(header.partial_credit[i-1])
{
case '0':
Tcl_SetVar2(interp,"gQuestionType",buf,"autoGrade",TCL_GLOBAL_ONLY);
break;
case '1':
Tcl_SetVar2(interp,"gQuestionType",buf,"handGrade",TCL_GLOBAL_ONLY);
sprintf(buf,"max%d",i);
sprintf(buf2,"%c",weight[i-1]);
Tcl_SetVar2(interp,"gAnswer",buf,buf2,TCL_GLOBAL_ONLY);
break;
default:
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,"Header for the set.db file is incorrect.",
NULL);
return TCL_ERROR;
break;
}
}
capa_mfree(header.weight);
capa_mfree(header.partial_credit);
Tcl_ResetResult(interp);
return TCL_OK;
}
/* setup gAnswer for all of the questions
* Arguments: number of Questions
*/
T_entry graderEntry;
int capaSetupGAnswer (ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
int numQuestions,i,result;
char buf[BUFFER_SIZE],buf2[BUFFER_SIZE],*questionType;
if (argc != 2)
{
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,"Incorrect number of arguments to setup gAnswer",
NULL);
return TCL_ERROR;
}
numQuestions=atoi(argv[1]);
result = capa_get_entry(&graderEntry,Tcl_GetVar2(interp,"gGrading","number",
TCL_GLOBAL_ONLY),
atoi(Tcl_GetVar(interp,"gSetLoad",TCL_GLOBAL_ONLY)));
if (result == 0)
{
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,"capa_get_entry returned error.",NULL);
return TCL_ERROR;
}
for(i=1;i<=numQuestions;i++)
{
sprintf(buf,"%d.tries",i);
buf2[0]=graderEntry.tries[(i-1)*3];buf2[1]=graderEntry.tries[(i-1)*3+1];
buf2[2]='\0';
Tcl_SetVar2(interp,"gAnswer",buf,buf2,TCL_GLOBAL_ONLY);
sprintf(buf,"%d",i);
switch(graderEntry.answers[i-1])
{
case '-':
Tcl_SetVar2(interp,"gAnswer",buf,"-",TCL_GLOBAL_ONLY);
break;
case 'y':
case 'n':
case 'E':
sprintf(buf2,"%c",graderEntry.answers[i-1]);
Tcl_SetVar2(interp,"gAnswer",buf,buf2,TCL_GLOBAL_ONLY);
break;
case 'Y':
sprintf(buf2,"%c",graderEntry.answers[i-1]);
Tcl_SetVar2(interp,"gAnswer",buf,buf2,TCL_GLOBAL_ONLY);
questionType=Tcl_GetVar2(interp,"gQuestionType",buf,
TCL_GLOBAL_ONLY);
switch(questionType[0])
{
case 'a':
sprintf(buf,"$gGradeCanvas.dash%d configure -state disabled",i);
if (Tcl_Eval(interp,buf)!=TCL_OK)
return TCL_ERROR;
sprintf(buf,"$gGradeCanvas.y%d configure -state disabled",i);
if (Tcl_Eval(interp,buf)!=TCL_OK)
return TCL_ERROR;
sprintf(buf,"$gGradeCanvas.n%d configure -state disabled",i);
if (Tcl_Eval(interp,buf)!=TCL_OK)
return TCL_ERROR;
sprintf(buf,"$gGradeCanvas.e%d configure -state disabled",i);
if (Tcl_Eval(interp,buf)!=TCL_OK)
return TCL_ERROR;
break;
case 'h':
sprintf(buf,"$gGradeCanvas.hand%d configure -state disabled",i);
if (Tcl_Eval(interp,buf)!=TCL_OK)
return TCL_ERROR;
break;
default:
Tcl_ResetResult(interp);
Tcl_AppendElement(interp,"questionType contains invlaid data in capaSetupGAnswer.");
return TCL_ERROR;
break;
}
break;
default:
sprintf(buf2,"%c",graderEntry.answers[i-1]);
Tcl_SetVar2(interp,"gAnswer",buf,buf2,TCL_GLOBAL_ONLY);
break;
}
}
Tcl_ResetResult(interp);
return TCL_OK;
}
/* save gAnswer to the set.db file
* Arguments: number of Questions
*/
int capaSaveGAnswer (ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
T_entry entry;
int numQuestions,i,result;
char buf[BUFFER_SIZE],*gAnswer;
if (argc != 2)
{
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,"Incorrect number of arguments to save gAnswer",NULL);
return TCL_ERROR;
}
numQuestions=atoi(argv[1]);
entry.answers=capa_malloc(numQuestions+1,1);
entry.tries=capa_malloc(3*numQuestions+1,1);
for(i=0;i<numQuestions;i++) {
sprintf(buf,"%d",i+1);
gAnswer=Tcl_GetVar2(interp,"gAnswer",buf,TCL_GLOBAL_ONLY);
if ( gAnswer[0] != graderEntry.answers[i] ) {
entry.answers[i]=gAnswer[0];
} else {
entry.answers[i]='?';
}
sprintf(buf,"%d.tries",i+1);
gAnswer=Tcl_GetVar2(interp,"gAnswer",buf,TCL_GLOBAL_ONLY);
if (atoi(gAnswer) != atoi(&(graderEntry.tries[i*3]))) {
sprintf(&(entry.tries[i*3]),"%2d",atoi(gAnswer));
if (i<numQuestions-1) entry.tries[i*3+2]=',';
} else {
entry.tries[i*3]='-';entry.tries[i*3+1]='1';
if (i<numQuestions-1) entry.tries[i*3+2]=',';
}
}
entry.answers[numQuestions]='\0';
entry.tries[numQuestions*3]='\0';
sprintf(entry.student_number,Tcl_GetVar2(interp,"gGrading","number",TCL_GLOBAL_ONLY));
entry.e_probs=numQuestions;
result = capa_change_entry(&entry,Tcl_GetVar2(interp,"gGrading","number",
TCL_GLOBAL_ONLY),
atoi(Tcl_GetVar(interp,"gSetLoad",TCL_GLOBAL_ONLY)));
if (result == -1) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,"capa_change_entry returned an error.",NULL);
return TCL_ERROR;
}
Tcl_ResetResult(interp);
return TCL_OK;
}
/* a wrapper for capa_excuse
* Arguments: set; problem; section
*/
int capaExcuse (ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
int result;
result = capa_excuse(atoi(argv[1]),atoi(argv[2]),atoi(argv[3]));
if (result == -1)
{
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,"capa_excuse returned error.",NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/* creates a summary report
* Arguments: the filename
*/
int capaCreateSummary (ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
int section = atoi(Tcl_GetVar2(interp,"gSummary","section",TCL_GLOBAL_ONLY)),
set = atoi(Tcl_GetVar2(interp,"gSummary","set",TCL_GLOBAL_ONLY));
int studentCount,currentStudent;
int setScores, termScores, validScores, termValids;
int setIndex, maxSet=0;
int whatSection;
char fmt[64];
char grades[4], sectionChar[4], *answersPtr, buf[BUFFER_SIZE], *who,*which,*sortOne,*sortTwo;
T_student *studentPtr, *currentStudentPtr;
FILE *outputFile;
who=Tcl_GetVar2(interp,"gSummary","who",TCL_GLOBAL_ONLY);
which=Tcl_GetVar2(interp,"gSummary","which",TCL_GLOBAL_ONLY);
sortOne=Tcl_GetVar2(interp,"gSummary","first",TCL_GLOBAL_ONLY);
sortTwo=Tcl_GetVar2(interp,"gSummary","second",TCL_GLOBAL_ONLY);
maxSet=howManySetDBFile();
if ( ( ( strcmp(which,"upto") == 0 )
&&
( ( set <= 0 )
||
( set >= NUM_SET_LIMIT ) ) )
||
( set > maxSet ) )
{
sprintf(buf,"displayError \"The set number (%d) doesn't exist.\"",set);
Tcl_Eval(interp,buf);
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,"Error",NULL);
return TCL_ERROR;
}
outputFile=fopen(argv[1],"w");
if ( strcmp(who,"all") == 0 )
whatSection = GET_ALL_SECTIONS;
else
whatSection = section;
studentCount = capa_get_section(&studentPtr, whatSection);
if (Tcl_Eval(interp,"updateStatusMessage \"Creating primary sort key\"") != TCL_OK)
{
free_students(studentPtr);
fclose(outputFile);
return TCL_ERROR;
}
if( studentCount > 0 )
{
switch (sortOne[1])
{
case 'a': /*BY_NAME*/
for(currentStudentPtr=studentPtr,currentStudent=1;currentStudentPtr;
currentStudentPtr=currentStudentPtr->s_next,currentStudent++)
{
sprintf(buf,"updateStatusBar %f",(float)currentStudent/(float)studentCount);
Tcl_Eval(interp,buf);
sprintf(currentStudentPtr->s_key,"%s",currentStudentPtr->s_nm);
}
break;
case 'u': /*BY_NUMBER*/
for(currentStudentPtr=studentPtr,currentStudent=1;currentStudentPtr;
currentStudentPtr=currentStudentPtr->s_next,currentStudent++)
{
sprintf(buf,"updateStatusBar %f",(float)currentStudent/(float)studentCount);
Tcl_Eval(interp,buf);
sprintf(currentStudentPtr->s_key,"%s",currentStudentPtr->s_sn);
}
break;
case 'e': /*BY_SECTION*/
for(currentStudentPtr=studentPtr,currentStudent=1;currentStudentPtr;
currentStudentPtr=currentStudentPtr->s_next,currentStudent++)
{
sprintf(buf,"updateStatusBar %f",(float)currentStudent/(float)studentCount);
Tcl_Eval(interp,buf);
sprintf(currentStudentPtr->s_key,"%03d",currentStudentPtr->s_sec);
}
break;
case 'r': /*BY_GRADE*/
if(strcmp(which,"specific") == 0 )
{
for(currentStudentPtr=studentPtr,currentStudent=1;currentStudentPtr;
currentStudentPtr=currentStudentPtr->s_next,currentStudent++)
{
sprintf(buf,"updateStatusBar %f",(float)currentStudent/(float)studentCount);
Tcl_Eval(interp,buf);
if( (setScores = capa_get_score(currentStudentPtr->s_sn,set,
&validScores,&answersPtr)) == -2 )
break;
if( setScores < 0 )
sprintf(currentStudentPtr->s_key,"-");
else
sprintf(currentStudentPtr->s_key,"%03d",setScores);
capa_mfree(answersPtr);
}
}
else
{
for(currentStudentPtr=studentPtr,currentStudent=1;currentStudentPtr;
currentStudentPtr=currentStudentPtr->s_next,currentStudent++)
{
sprintf(buf,"updateStatusBar %f",(float)currentStudent/(float)studentCount);
Tcl_Eval(interp,buf);
for( termScores = 0, termValids = 0, setIndex = 1;
setIndex <= set; setIndex++)
{
if( (setScores = capa_get_score(currentStudentPtr->s_sn,setIndex,
&validScores,&answersPtr)) >= 0 )
termScores += setScores;
capa_mfree(answersPtr);
termValids += validScores;
}
sprintf(currentStudentPtr->s_key,"%03d",termScores);
}
}
break;
}
if (Tcl_Eval(interp,"updateStatusMessage \"Creating secondary sort key\"") != TCL_OK)
{
free_students(studentPtr);
fclose(outputFile);
return TCL_ERROR;
}
switch (sortTwo[1])
{
case 'a':/*BY_NAME*/
for(currentStudentPtr=studentPtr,currentStudent=1;currentStudentPtr;
currentStudentPtr=currentStudentPtr->s_next,currentStudent++)
{
sprintf(buf,"updateStatusBar %f",(float)currentStudent/(float)studentCount);
Tcl_Eval(interp,buf);
strcat(currentStudentPtr->s_key,currentStudentPtr->s_nm);
}
break;
case 'u':/*BY_NUMBER*/
for(currentStudentPtr=studentPtr,currentStudent=1;currentStudentPtr;
currentStudentPtr=currentStudentPtr->s_next,currentStudent++)
{
sprintf(buf,"updateStatusBar %f",(float)currentStudent/(float)studentCount);
Tcl_Eval(interp,buf);
strcat(currentStudentPtr->s_key,currentStudentPtr->s_sn);
}
break;
case 'e':/*BY_SECTION*/
for(currentStudentPtr=studentPtr,currentStudent=1;currentStudentPtr;
currentStudentPtr=currentStudentPtr->s_next,currentStudent++)
{
sprintf(buf,"updateStatusBar %f",(float)currentStudent/(float)studentCount);
Tcl_Eval(interp,buf);
sprintf(sectionChar,"%03d",currentStudentPtr->s_sec);
strcat(currentStudentPtr->s_key,sectionChar);
}
break;
case 'r':/*BY_GRADE*/
if(strcmp(which,"specific") == 0 )
{
for(currentStudentPtr=studentPtr,currentStudent=1;currentStudentPtr;
currentStudentPtr=currentStudentPtr->s_next,currentStudent++)
{
sprintf(buf,"updateStatusBar %f",(float)currentStudent/(float)studentCount);
Tcl_Eval(interp,buf);
if( (setScores = capa_get_score(currentStudentPtr->s_sn,set,&validScores,
&answersPtr) ) == -2 )
break;
if( setScores < 0 )
strcat(currentStudentPtr->s_key,"-");
else
{
sprintf(grades,"%03d",setScores);
strcat(currentStudentPtr->s_key,grades);
}
capa_mfree(answersPtr);
}
}
else
{
for(currentStudentPtr=studentPtr,currentStudent=1;currentStudentPtr;
currentStudentPtr=currentStudentPtr->s_next,currentStudent++)
{
sprintf(buf,"updateStatusBar %f",(float)currentStudent/(float)studentCount);
Tcl_Eval(interp,buf);
for( termScores = 0, termValids = 0, setIndex = 1;
setIndex <= set; setIndex++)
{
if( (setScores = capa_get_score(currentStudentPtr->s_sn,setIndex,
&validScores,&answersPtr) ) >= 0 )
termScores += setScores;
capa_mfree(answersPtr);
termValids += validScores;
}
sprintf(grades,"%03d",termScores);
strcat(currentStudentPtr->s_key,grades);
}
}
break;
}
if (Tcl_Eval(interp,"updateStatusMessage \"Sorting\"") != TCL_OK)
{
free_students(studentPtr);
fclose(outputFile);
return TCL_ERROR;
}
msort_main(&studentPtr);
Tcl_ResetResult(interp);
sprintf(fmt,"%%-%ds\t%%-%ds %%2d\t", MAX_NAME_CHAR,MAX_STUDENT_NUMBER);
if (Tcl_Eval(interp,"updateStatusMessage \"Creating Report\"") != TCL_OK)
{
free_students(studentPtr);
fclose(outputFile);
return TCL_ERROR;
}
for(currentStudentPtr=studentPtr,currentStudent=1;currentStudentPtr;
currentStudentPtr=currentStudentPtr->s_next,currentStudent++)
{
sprintf(buf,"updateStatusBar %f",(float)currentStudent/(float)studentCount);
Tcl_Eval(interp,buf);
fprintf(outputFile,fmt,currentStudentPtr->s_nm,currentStudentPtr->s_sn,
currentStudentPtr->s_sec);
if( strcmp(which,"specific") == 0)
{
setScores = 0; validScores = 0;
if( (setScores =
capa_get_score(currentStudentPtr->s_sn,set,&validScores,&answersPtr) ) == -2 )
break;
if( setScores < 0 )
{
fprintf(outputFile, " -\t%3d\n", validScores);
}
else
{
fprintf(outputFile, "%3d\t%3d\n",setScores, validScores);
}
capa_mfree(answersPtr);
}
else
{
for( setScores=0, validScores=0, termScores = 0, termValids = 0, setIndex = 1;
setIndex <= set; setIndex++)
{
if( (setScores = capa_get_score(currentStudentPtr->s_sn,setIndex,
&validScores,&answersPtr) ) >= 0 )
termScores += setScores;
capa_mfree(answersPtr);
termValids += validScores;
if( setScores >= 0 )
{
fprintf(outputFile, "%3d ",setScores);
}
else
{
fprintf(outputFile, " - ");
}
}
fprintf(outputFile, "\t %3d\t%3d\n",termScores,termValids);
}
}
free_students(studentPtr);
}
fclose(outputFile);
return TCL_OK;
}
/* set the gAnswer score to what ever the user entered
* Arguments: problemNumber
*/
int capaSetHandGrade (ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
int problemNumber=atoi(argv[1]),handGrade,maxGrade;
char *handGradeChar,buf[BUFFER_SIZE];
handGradeChar=Tcl_GetVar(interp,"gNewHandGrade",TCL_GLOBAL_ONLY);
sprintf(buf,"max%d",problemNumber);
maxGrade=atoi(Tcl_GetVar2(interp,"gAnswer",buf,TCL_GLOBAL_ONLY));
if (isdigit(handGradeChar[0])) {
handGrade=atoi(handGradeChar);
if (handGrade > maxGrade) {
sprintf(buf,"displayError \"Invalid response, you must enter a number between 0 and %d, or an E to excuse the problem.\"",maxGrade);
if (Tcl_Eval(interp,buf)!=TCL_OK) {
return TCL_ERROR;
}
} else {
sprintf(buf,"%d",handGrade);
Tcl_SetVar2(interp,"gAnswer",argv[1],buf,TCL_GLOBAL_ONLY);
}
} else {
if (handGradeChar[0]=='E') {
Tcl_SetVar2(interp,"gAnswer",argv[1],"E",TCL_GLOBAL_ONLY);
} else {
sprintf(buf,"displayError \"Invalid response, you must enter a number between 0 and %d, or an E to excuse the problem.\"",maxGrade);
if (Tcl_Eval(interp,buf)!=TCL_OK) return TCL_ERROR;
}
}
Tcl_ResetResult(interp);
return TCL_OK;
}
/* save gAnswer to the set.db file
* Arguments: setNum, questNum, stuId, score
*/
int capaSetScore (ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
T_entry entry;
int score,i,result,question,numQuest,set;
char buf[BUFFER_SIZE],*gAnswer,*stuId;
T_header header;
if (argc != 5)
{
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,"Incorrect number of arguments to save gAnswer",NULL);
return TCL_ERROR;
}
set=atoi(argv[1]);
question=atoi(argv[2]);
stuId=argv[3];
score=atoi(argv[4]);
result=capa_get_header(&header,set);
numQuest=atoi(header.num_questions);
result = capa_get_entry(&entry,stuId,set);
entry.answers=capa_malloc(numQuest+1,1);
entry.tries=capa_malloc(3*numQuest+1,1);
for(i=0;i<numQuest;i++) {
if ( i==(question-1) ) {
entry.answers[i]=score+'0';
} else {
entry.answers[i]='-';
}
entry.tries[i*3]='-';entry.tries[i*3+1]='1';
if (i<numQuest-1) entry.tries[i*3+2]=',';
}
entry.answers[numQuest]='\0';
entry.tries[(numQuest)*3]='\0';
sprintf(entry.student_number,stuId);
entry.e_probs=numQuest;
result = capa_change_entry(&entry,stuId,set);
if (result == -1) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,"capa_change_entry returned an error.",NULL);
return TCL_ERROR;
}
Tcl_ResetResult(interp);
return TCL_OK;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>