#include #include #include #include #include #include #include "Capa/capaCommon.h" #include "bubbler.h" /* scantron control program 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. */ int serportfd; int readportfd; FILE * readport; int CheckPIN; int CompareClassName; int Anon; int CheckSpaces; int SurveyMode; int SurveyHeader; int formNumber; int GetProblems(Question questions[MAXQUEST],char * class,int * setId) { int i,q,length; char clear[100]; printf("What is the class name?"); scanf("%s",class); printf("What is the SetId?"); scanf("%d",setId); printf("Is this a survey or exam/quiz?(s or e)"); scanf("%s",clear); if (clear[0]=='s' || clear[0]=='S') { SurveyMode=1; printf("Does the form include a Header?(y or n)"); scanf("%s",clear); if (clear[0]=='n' || clear[0]=='N') { SurveyHeader=0; } else { SurveyHeader=1; } printf("How many Questions are on the form?"); scanf("%d",&q); for (i=0;iPIN)==PIDandPINlist[i].PIN) { matches[j]=i; j++; } } matches[j]=-1; switch(j) { case 0: printf("No match for PIN %s\n",student->PIN); error=ENOONE; break; case 1: printf("Only one match assuming PID %s\n",PIDandPINlist[matches[0]].PID); strcpy(student->questionPID,PIDandPINlist[matches[0]].PID); break; default: printf("Please press\n"); for(i=0;i<30;i++) { if (matches[i]!=-1) { printf("%d) for student number %s\n",i, PIDandPINlist[matches[i]].PID); } else { i=30; } } scanf("%d",&selection); if ((selection < j) && (selection > 0)) { strcpy(student->questionPID,PIDandPINlist[matches[selection]].PID); } break; } return error; } Student * getForm(int * status,FILE ** serport, Question questions[MAXQUEST]) { Student *newStudent; char buffer[1024],buf[1024],buf2[1024]; int readamount=0,done=0,i=0,j=0,h=0,q=0,space=0; sprintf(buffer,".read 2\015"); print(serport,buffer,1); while(!done) { readamount=read(readportfd,buf,100); buf[readamount]='\0'; for(i=0;ianswerPID,"a%08d",formNumber++); else strncpy(newStudent->answerPID,&buf2[10],9); newStudent->answerPID[9]='\0'; strncpy(newStudent->class,&buf2[2],8); newStudent->class[8]='\0'; strncpy(newStudent->SetId,&buf2[0],2); newStudent->SetId[2]='\0'; strncpy(newStudent->PIN,&buf2[19],4); newStudent->PIN[4]='\0'; i=23;h=0; while(buf2[i]!='\0') { switch(questions[h].type) { case 'a': case 'd': case 'f': newStudent->Answers[h][0]=buf2[i]; newStudent->Answers[h][1]='\0'; if (isspace(buf2[i])) space++; i++; break; case 'b': /*loop through each leaf*/ for(j=0;jAnswers[h][j]=buf2[i]; if (isspace(buf2[i])) space++; i++; } newStudent->Answers[h][j]='\0'; break; case 'c': /*loop through each leaf*/ for(j=0;jAnswers[h][j]=buf2[i]; if (isspace(buf2[i])) space++; i++; } newStudent->Answers[h][j]='\0'; break; case 'e': case 'g': for (j=0,q=0;j<8;j++) { if (buf2[i]!=' ') { newStudent->Answers[h][q]=buf2[i]; q++; } i++; } if (isspace(buf2[i])) space++; newStudent->Answers[h][q]='\0'; break; default: fprintf(stderr,"Wha? %c",questions[h].type); i++; break; } h++; } *status=GFSUCCESS; break; } if (space!=0) *status=GFSPACES; return newStudent; } int checkForm(Student * student,int numQuestions,char *class,int setId) { int error,pin; student_t capaStudent; #ifdef DEBUG printf("PID:\t%s\nclass:\t%s\nSetId:\t%s\nPIN:\t%s\n", student->answerPID,student->class,student->SetId,student->PIN); for(i=0,j=0;iAnswers[i]); } #endif /*DEBUG*/ if (CompareClassName) { if (strncasecmp(student->class,class,8)) { printf("Class: The Scantron reported:%s, You typed in:%s\n", student->class,class); return ECLASS; } } else { strcpy(student->class,class); sprintf(student->SetId,"%2d",setId); } error=capa_get_student_info(student->answerPID, &capaStudent); switch(error) { case 1: printf("%s %d\n\n",capaStudent.name,capaStudent.section); break; case 0: printf("PID: The Scantron reported:%s\n",student->answerPID); return ESTID; break; case -1: return ECLASSL; break; default: fprintf(stderr,"capa_get_student returned an invalid result "); fprintf(stderr,"in CheckForm.\n"); break; } if (CheckPIN && !Anon) { pin=capa_PIN(student->answerPID,atoi(student->SetId),0); if (pin!=atoi(student->PIN)) { printf("PIN: The Scantron reported:%s, The Classl file has:%d\n", student->PIN,pin); return EPIN; } } return 0; } long getBubblerEntry(FILE ** outputFile,char *PID) { char oneline[512],fmtbuf[16],a_sn[32]; int done=0,found=0,offset=0,len=0,next_r=0; rewind(*outputFile); sprintf(fmtbuf,"%%%dc",MAX_STUDENT_NUMBER); while(!done) { done=!fgets(oneline,511,*outputFile); len=strlen(oneline); if (!done) { sscanf(oneline,fmtbuf,a_sn); if (!strncasecmp(a_sn,PID,MAX_STUDENT_NUMBER)) { next_r=ftell(*outputFile); offset = next_r-len; done=1; found=1; } else { } } else { fseek(*outputFile,0L,SEEK_END); offset=ftell(*outputFile); fseek(*outputFile,-1L,SEEK_END); while (fgetc(*outputFile)=='\n') { offset--; fseek(*outputFile,offset,SEEK_SET); } offset= offset+2; found=0; done=1; } } if(!found) { offset=-offset; } return offset; } void setBubblerEntry(FILE ** outputFile,char* answerPID,char* name, char* answers,int score, int section, char* answerstring,char* questionPID, int offset) { int len=0; char buf[1024]; rewind(*outputFile); sprintf(buf,"%s %s %s %3d %2d %s %s\n",answerPID,name,answers,score,section, answerstring,questionPID); len=strlen(buf); fseek(*outputFile,abs(offset),0); if(!fwrite(buf,len,1,*outputFile)) { fprintf(stderr,"Failed write.\n"); } } /* Checks if answers are right and gives a point for each right.*/ void writeForm(Student * student,FILE ** outputFile, Question questions[MAXQUEST],int numQuestions) { int result,capaQuestions,questionIndex,leafs,numRight,error,total=0; int offset2; char one=1,zero=0; char *ansOn[20],*stuOn[20]; Problem_t *problems,*oldproblem; char answerstring[1024],grade[1024]; student_t capaStudent; if (!SurveyMode) { error=capa_get_student_info(student->answerPID, &capaStudent); result=capa_parse(atoi(student->SetId),&problems,student->questionPID, &capaQuestions); oldproblem=problems; if (result==0) { fprintf(stderr,"Parse failed: %d\n",result); return; } } else { strcpy(capaStudent.name,"Unknown "); capaStudent.section=0; oldproblem=problems=NULL; } offset2=getBubblerEntry(outputFile,student->answerPID); for(questionIndex=0;questionIndexanswer,student->Answers[questionIndex]); for(leafs=0;problems->answer[leafs]!='\0';leafs++) { if (problems->answer[leafs]== student->Answers[questionIndex][leafs]) { numRight++; } } total+=numRight; grade[questionIndex]='0'+(char)numRight; break; case 'd': printf("%s\n",student->Answers[questionIndex]); grade[questionIndex]=student->Answers[questionIndex][0]; if (isspace(student->Answers[questionIndex][0])) total+=0; else total+=(int)(student->Answers[questionIndex][0]-'0'); break; case 'e': printf("%s %s\n",problems->answer,student->Answers[questionIndex]); numRight=0; for(leafs=0;questions[questionIndex].leafs>leafs;leafs++) { ansOn[leafs]=strchr(problems->answer,('A'+(char)leafs)); } for(leafs=0;questions[questionIndex].leafs>leafs;leafs++) { if (ansOn[leafs] != NULL ) { ansOn[leafs]=&one;} else { ansOn[leafs]=&zero;} } for(leafs=0;questions[questionIndex].leafs>leafs;leafs++) { stuOn[leafs]=strchr(student->Answers[questionIndex], ('A'+(char)leafs)); } for(leafs=0;questions[questionIndex].leafs>leafs;leafs++) { if (stuOn[leafs] != NULL) {stuOn[leafs]=&one;} else {stuOn[leafs]=&zero;} } for(leafs=0;questions[questionIndex].leafs>leafs;leafs++) { if (ansOn[leafs] == stuOn[leafs]) numRight++; } fprintf(stderr,"%d\n",numRight); total+=numRight; grade[questionIndex]='0'+(char)numRight; break; case 'g': printf("%s %s\n",problems->answer,student->Answers[questionIndex]); if (!(strcasecmp(problems->answer,student->Answers[questionIndex]))) { total+=questions[questionIndex].points; grade[questionIndex]='0'+questions[questionIndex].points; } else { grade[questionIndex]='0'; } break; default: printf("No points since don't know question type.\n"); break; } if (!SurveyMode) problems=problems->next; } answerstring[0]='\0'; for(questionIndex=0;questionIndexAnswers[questionIndex]); } setBubblerEntry(outputFile,student->answerPID,capaStudent.name,grade, total,capaStudent.section,answerstring,student->questionPID, offset2); if (!SurveyMode) { problems=oldproblem; for(questionIndex=0;problems!=NULL;questionIndex++) { oldproblem=problems; problems=problems->next; free(oldproblem); } #ifdef DEBUG fprintf(stderr,"Freed: %d\n",questionIndex); #endif /*DEBUG*/ } } void processForms(FILE ** serport,int numQuestions, Question questions[MAXQUEST],char* class,int setId) { int done=0,error,i,numOfStudents=0; int status; char buf[128],filename[128]; Student * student; FILE * outputFile; PIDPINlist PIDandPINlist[MAX_SECTION_SIZE]; sprintf(filename,"bubbler.output.%d",setId); outputFile=fopen(filename,"r+"); if (outputFile != NULL) { rewind(outputFile); fscanf(outputFile,"%s",buf); } if (outputFile==NULL || buf[0]=='\0') { outputFile=fopen(filename,"w+"); fprintf(outputFile,"%s %d ",class,setId); for(i=0;iquestionPID,student->answerPID); } switch(error) { case ENONE: writeForm(student,&outputFile,questions,numQuestions); break; case ENOONE: break; default: fprintf(stderr,"Unimplemented error in findPID %d\n", error); break; } } break; case GFFAILED: printf("The Scantron has returned an error.\n"); printf("Are there still more forms to process?"); scanf("%s",buf); if (buf[0]=='n') { done=1; } else { printf("Please put that last read form to the side.\n"); printf("Enter start to continue\n"); scanf("%s",buf); } break; case GFEOF: done=1; break; default: printf("Unimplened return code in GetForm %d\n",status); break; } if (student != NULL) { free(student); } } } void CloseScantron(FILE ** serport) { fprintf(*serport,".srst\r"); fclose(*serport); } int main(int argc, char *argv[]) { FILE * serport; Question questions[MAXQUEST]; char class[10]; int numQuestions,setId; printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); printf("Welcome to Bubbler, the Automated CAPA grader.\n"); printf("Version 0.05.02\n\n\n"); numQuestions=GetProblems(questions,class,&setId); SetupScantron(&serport,numQuestions,questions); processForms(&serport,numQuestions,questions,class,setId); CloseScantron(&serport); return 0; }