File:  [LON-CAPA] / capa / capa51 / Historic / bubbler.c
Revision 1.3: download - view: text, annotated - select for diffs
Mon Aug 7 20:47:29 2000 UTC (23 years, 10 months ago) by albertel
Branches: MAIN
CVS tags: version_2_9_X, version_2_9_99_0, version_2_9_1, version_2_9_0, version_2_8_X, version_2_8_99_1, version_2_8_99_0, version_2_8_2, version_2_8_1, version_2_8_0, version_2_7_X, version_2_7_99_1, version_2_7_99_0, version_2_7_1, version_2_7_0, version_2_6_X, version_2_6_99_1, version_2_6_99_0, version_2_6_3, version_2_6_2, version_2_6_1, version_2_6_0, version_2_5_X, version_2_5_99_1, version_2_5_99_0, version_2_5_2, version_2_5_1, version_2_5_0, version_2_4_X, version_2_4_99_0, version_2_4_2, version_2_4_1, version_2_4_0, version_2_3_X, version_2_3_99_0, version_2_3_2, version_2_3_1, version_2_3_0, version_2_2_X, version_2_2_99_1, version_2_2_99_0, version_2_2_2, version_2_2_1, version_2_2_0, version_2_1_X, version_2_1_99_3, version_2_1_99_2, version_2_1_99_1, version_2_1_99_0, version_2_1_3, version_2_1_2, version_2_1_1, version_2_1_0, version_2_12_X, version_2_11_X, version_2_11_4_uiuc, version_2_11_4_msu, version_2_11_4, version_2_11_3_uiuc, version_2_11_3_msu, version_2_11_3, version_2_11_2_uiuc, version_2_11_2_msu, version_2_11_2_educog, version_2_11_2, version_2_11_1, version_2_11_0_RC3, version_2_11_0_RC2, version_2_11_0_RC1, version_2_11_0, version_2_10_X, version_2_10_1, version_2_10_0_RC2, version_2_10_0_RC1, version_2_10_0, version_2_0_X, version_2_0_99_1, version_2_0_2, version_2_0_1, version_2_0_0, version_1_99_3, version_1_99_2, version_1_99_1_tmcc, version_1_99_1, version_1_99_0_tmcc, version_1_99_0, version_1_3_X, version_1_3_3, version_1_3_2, version_1_3_1, version_1_3_0, version_1_2_X, version_1_2_99_1, version_1_2_99_0, version_1_2_1, version_1_2_0, version_1_1_X, version_1_1_99_5, version_1_1_99_4, version_1_1_99_3, version_1_1_99_2, version_1_1_99_1, version_1_1_99_0, version_1_1_3, version_1_1_2, version_1_1_1, version_1_1_0, version_1_0_99_3, version_1_0_99_2, version_1_0_99_1, version_1_0_99, version_1_0_3, version_1_0_2, version_1_0_1, version_1_0_0, version_0_99_5, version_0_99_4, version_0_99_3, version_0_99_2, version_0_99_1, version_0_99_0, version_0_6_2, version_0_6, version_0_5_1, version_0_5, version_0_4, stable_2002_spring, stable_2002_july, stable_2002_april, stable_2001_fall, release_5-1-3, loncapaMITrelate_1, language_hyphenation_merge, language_hyphenation, conference_2003, bz6209-base, bz6209, STABLE, HEAD, GCI_3, GCI_2, GCI_1, CAPA_5-1-6, CAPA_5-1-5, CAPA_5-1-4_RC1, BZ4492-merge, BZ4492-feature_horizontal_radioresponse, BZ4492-feature_Support_horizontal_radioresponse, BZ4492-Support_horizontal_radioresponse
- fixed license notices the reference the GNU GPL rather than the GNU LGPL

    1: #include <stdio.h>
    2: #include <sgtty.h>
    3: #include <libc.h>
    4: #include <sys/types.h>
    5: #include <sys/uio.h>
    6: #include <ctype.h>
    7: #include "Capa/capaCommon.h"
    8: #include "bubbler.h"
    9: /* scantron control program
   10:    Copyright (C) 1992-2000 Michigan State University
   11: 
   12:    The CAPA system is free software; you can redistribute it and/or
   13:    modify it under the terms of the GNU General Public License as
   14:    published by the Free Software Foundation; either version 2 of the
   15:    License, or (at your option) any later version.
   16: 
   17:    The CAPA system is distributed in the hope that it will be useful,
   18:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   19:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   20:    General Public License for more details.
   21: 
   22:    You should have received a copy of the GNU General Public
   23:    License along with the CAPA system; see the file COPYING.  If not,
   24:    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   25:    Boston, MA 02111-1307, USA.
   26: 
   27:    As a special exception, you have permission to link this program
   28:    with the TtH/TtM library and distribute executables, as long as you
   29:    follow the requirements of the GNU GPL in regard to all of the
   30:    software in the executable aside from TtH/TtM.
   31: */
   32: 
   33: int serportfd;
   34: int readportfd;
   35: FILE * readport;
   36: int CheckPIN;
   37: int CompareClassName;
   38: int Anon;
   39: int CheckSpaces;
   40: int SurveyMode;
   41: int SurveyHeader;
   42: int formNumber;
   43: 
   44: int GetProblems(Question questions[MAXQUEST],char * class,int * setId)
   45: {
   46:   int i,q,length;
   47:   char clear[100];
   48: 
   49:   printf("What is the class name?");
   50:   scanf("%s",class);
   51:   
   52:   printf("What is the SetId?");
   53:   scanf("%d",setId);
   54: 
   55:   printf("Is this a survey or exam/quiz?(s or e)");
   56:   scanf("%s",clear);
   57:   if (clear[0]=='s' || clear[0]=='S')
   58:     {
   59:       SurveyMode=1;
   60:       printf("Does the form include a Header?(y or n)");
   61:       scanf("%s",clear);
   62:       if (clear[0]=='n' || clear[0]=='N')
   63: 	{
   64: 	  SurveyHeader=0;
   65: 	}
   66:       else
   67: 	{
   68: 	  SurveyHeader=1;
   69: 	}
   70:       printf("How many Questions are on the form?");
   71:       scanf("%d",&q);
   72:       
   73:       for (i=0;i<q;i++)
   74: 	{
   75: 	  questions[i].type='d';
   76: 	  questions[i].leafs=questions[i].points=9;
   77: 	}
   78:     }
   79:   else
   80:     {
   81:       SurveyMode=0;
   82: 
   83:       printf("Should bubbler compare the entered class name and SetId with \n");
   84:       printf("the encoded information on each paper?(y or n)");
   85:       scanf("%s",clear);
   86:       if (clear[0]=='N' || clear[0]=='n')
   87: 	CompareClassName=0;
   88:       else
   89: 	CompareClassName=1;
   90:       
   91:       printf("Should the student coded CAPA ID be checked for correctness?\n");
   92:       printf("(y or n)");
   93:       scanf("%s",clear);
   94:       if (clear[0]=='N' || clear[0]=='n')
   95: 	CheckPIN=0;
   96:       else
   97: 	{
   98: 	  CheckPIN=1;
   99: 	  
  100: 	  printf("Should bubbler run in Anonymous mode (search for correct \n");
  101: 	  printf("Student Number based on the CAPA ID)? (y or n)");
  102: 	  scanf("%s",clear);
  103: 	  
  104: 	  if (clear[0]=='N' || clear[0]=='n')
  105: 	    Anon=0;
  106: 	  else
  107: 	    Anon=1;
  108: 	}
  109:       
  110:       printf("Should bubbler check for blank answers and issue a warning when \n");
  111:       printf("one is encountered? (y or n)");
  112:       scanf("%s",clear);
  113:       if (clear[0]=='N' || clear[0]=='n')
  114: 	CheckSpaces=0;
  115:       else
  116: 	CheckSpaces=1;
  117:       
  118:       length=strlen(class);
  119:       if (length < 8)
  120: 	{
  121: 	  for(;length<8;length++)
  122: 	    {
  123: 	      class[length]=' ';
  124: 	    }
  125: 	  class[length]='\0';
  126: 	}
  127:       printf("How many Questions are on the form?");
  128:       scanf("%d",&q);
  129:       
  130:       printf("For Each Question enter \"a\" for a one out of 8\n");
  131:       printf("                        \"b\" for a GLE type\n");
  132:       printf("                        \"c\" for a TF type.\n");
  133:       printf("                        \"d\" for an assigned score.\n");
  134:       printf("                        \"e\" for a multiple out of 8.\n");
  135:       printf("                        \"f\" for single digit string matching.\n");
  136:       printf("                        \"g\" for exact string matching/\n");
  137:       
  138:       for (i=0;i<q;i++)
  139: 	{
  140: 	  printf("Question#%2d: ",i+1);
  141: 	  scanf("%1s",&questions[i].type);
  142: 	  fflush(stdin);
  143: 	  switch(questions[i].type)
  144: 	    {
  145: 	    case 'a':
  146: 	    case 'd':
  147: 	    case 'g':
  148: 	    case 'f':
  149: 	      printf("How many Points are possible?");
  150: 	      scanf("%d",&questions[i].points);
  151: 	      questions[i].leafs=questions[i].points;
  152: 	      break;
  153: 	    case 'b':
  154: 	    case 'c':
  155: 	      printf("How many parts to the problem?");
  156: 	      scanf("%d",&questions[i].points);
  157: 	      questions[i].leafs=questions[i].points;
  158: 	      break;
  159: 	    case 'e':
  160: 	      printf("How many possible answers are there?");
  161: 	      scanf("%d",&questions[i].points);
  162: 	      questions[i].leafs=questions[i].points;
  163: 	      break;
  164: 	    default:
  165: 	      printf("Unknown choice.\n");
  166: 	      break;
  167: 	    }
  168: 	  fflush(stdin);
  169: 	}
  170:     }
  171:   return q;
  172: }
  173:  
  174: void serial_open(FILE ** streamserport,char * device)
  175: {
  176:   struct sgttyb one;
  177:   
  178:   if ((serportfd=open(device,O_WRONLY,O_CREAT))==-1)
  179:     {
  180:       fprintf(stderr,"Unable to open serial port.\n");
  181:       exit(-1);
  182:     }
  183: 
  184:   if ((readportfd=open(device,O_RDONLY,O_CREAT))==-1)
  185:     {
  186:       fprintf(stderr,"Unable to open serial port for reading.\n");
  187:       exit(-1);
  188:     }
  189:   
  190:   one.sg_ispeed='\015';
  191:   one.sg_ospeed='\015';
  192:   one.sg_erase='\177';
  193:   one.sg_kill='\024';
  194:   one.sg_flags= (short) 3;
  195: 
  196: #ifdef DEBUG  
  197:   ioctl(serportfd,TIOCGETP,&two);
  198:   printf("%d %d %d %d %d\n",two.sg_ispeed,two.sg_ospeed,
  199: 	 two.sg_erase,two.sg_kill,two.sg_flags);
  200: #endif
  201:   
  202:   ioctl(serportfd,TIOCSETN,&one);
  203:   ioctl(readportfd,TIOCSETN,&one);
  204: 
  205: #ifdef DEBUG
  206:   ioctl(serportfd,TIOCGETP,&two);
  207:   printf("%d %d %d %d %d\n",two.sg_ispeed,two.sg_ospeed,
  208: 	 two.sg_erase,two.sg_kill,two.sg_flags);
  209:   printf("%d %d %d %d %d\n",one.sg_ispeed,one.sg_ospeed,
  210: 	 one.sg_erase,one.sg_kill,one.sg_flags);
  211: #endif
  212:   *streamserport=fdopen(serportfd,"w");
  213:   readport=fdopen(readportfd,"r");
  214: }
  215: 
  216: 
  217: void print(FILE** serport,char * out,int shouldread)
  218: {
  219:   int readamount;
  220:   char buf[100];
  221: 
  222: #ifdef DEBUG
  223:   printf("%s\n",out);
  224: #endif /*DEBUG*/
  225: 
  226:   write(serportfd,out,strlen(out));
  227:   if (shouldread)
  228:     {
  229:       readamount=read(readportfd,buf,1);
  230: #ifdef DEBUG
  231:       printf("%d %d\n",readamount,buf[0]);
  232: #endif
  233:     }
  234: }
  235: 
  236: void send_initform_strings(FILE ** serport,int numQuestions,
  237: 			   Question questions[MAXQUEST])
  238: {
  239:   int i, scan,j,Points;
  240:   /* this sets up kermit and then sends the correct strings to the scantron 
  241:      to define what the sheet looks like 
  242:      */
  243:   char buffer[1024],answerString[1024];
  244:   
  245:   for(i=0;i<1000;i++) 
  246:     {
  247:       buffer[i]='\0';
  248:     }
  249:   
  250:   scan=11+numQuestions;
  251:   
  252:   /* resets the scantron*/
  253:   sprintf(buffer,".srst\015");
  254:   print(serport,buffer, 1);
  255:   
  256:   /* sets the error character to be the '"' character */
  257:   sprintf(buffer,".err=34\015");
  258:   print(serport,buffer, 1);
  259:  
  260:   /* tell scantron how many scanlines there are*/
  261:   sprintf(buffer,".frm=fs %d 0 48 n n n\015",scan);
  262:   print(serport,buffer, 1);
  263:  
  264:   /* encoded class info*/
  265:   sprintf(buffer,".frm=pa 1 2 44 11 32 l 10 7\015");
  266:   print(serport,buffer, 1);
  267:  
  268:   /* the first letter of the student number*/
  269:   sprintf(buffer,".frm=mc n n 1 1 3 4 4 4 c 1 2 ab\015");
  270:   print(serport,buffer, 1);
  271:  
  272:   /* the remaining digits of the student number*/
  273:   sprintf(buffer,".frm=mc n n 1 1 2 6 11 20 c 8 10 0123456789\015");
  274:   print(serport,buffer, 1);
  275:  
  276:   /* the PIN number*/
  277:   sprintf(buffer,".frm=mc n n 1 1 2 24 11 30 c 4 10 0123456789\015");
  278:   print(serport,buffer, 1);
  279: 
  280: #ifdef DEBUG
  281:   printf("%d\n",numQuestions);
  282: #endif /*DEBUG*/
  283: 
  284:   /*sets each question line*/
  285:   for (i=0;i<numQuestions;i++)
  286:     {
  287: 
  288: #ifdef DEBUG
  289:       printf("%c\n",questions[i].type);
  290: #endif /*DEBUG*/
  291: 
  292:       switch (questions[i].type)
  293: 	{
  294: 	case 'a':
  295: 	  sprintf(buffer,".frm=mc n m 1 1 %d 6 %d 20 l 1 8 ABCDEFGH\015",
  296: 		  i+12,i+12);
  297: 	  print(serport,buffer,1);
  298: 	  break;
  299: 	case 'b':
  300: 	  for(j=0;j<questions[i].points;j++)
  301: 	    {
  302: 	      sprintf(buffer,
  303: 		      ".frm=mc n m 1 1 %d %d %d %d l 1 3 GLE\015",
  304: 		      i+12,(j*8)+6,i+12,(j*8)+10);
  305: 	      print(serport,buffer,1);
  306: 	    }
  307: 	  break;
  308: 	case 'c':
  309: 	  for(j=0;j<questions[i].points;j++)
  310: 	    {
  311: 	      sprintf(buffer,
  312: 		      ".frm=mc n m 1 1 %d %d %d %d l 1 2 TF\015",
  313: 		      i+12,(j*6)+6,i+12,(j*6)+8);
  314: 	      print(serport,buffer,1);
  315: 	    }
  316: 	  break;
  317: 	case 'd':
  318: 	  answerString[0]='\0';
  319: 	  Points=questions[i].points;
  320: 	  for(j=0;j<=Points;j++)
  321: 	    {
  322: 	      sprintf(buffer,"%d",j);
  323: 	      strcat(answerString,buffer);
  324: 	    }
  325: 	  sprintf(buffer,".frm=mc n m 1 1 %d 6 %d %d l 1 %d %s\015",
  326: 		  i+12,i+12,(Points*2)+6,Points+1,answerString);
  327: 	  print(serport,buffer,1);
  328: 	  break;
  329: 	case 'e':
  330: 	case 'g':
  331: 	  sprintf(buffer,".frm=mc y n 1 1 %d 6 %d 20 l 1 8 ABCDEFGH\015",
  332: 		  i+12,i+12);
  333: 	  print(serport,buffer,1);
  334: 	  break;
  335: 	case 'f':
  336: 	  sprintf(buffer,".frm=mc n m 1 1 %d 6 %d 24 l 1 10 0123456789\015",
  337: 		  i+12,i+12);
  338: 	  print(serport,buffer,1);
  339: 	  break;
  340: 	default:
  341: 	  fprintf(stderr,"Booga Booga, couldn't find that question type to");
  342: 	  fprintf(stderr," tell Scantron about\n %c \n",questions[i].type);
  343: 	  break;
  344: 	}
  345:     }
  346: 
  347:   /* end of the form*/
  348:   sprintf(buffer,".frm=ls\015");
  349:   print(serport,buffer, 1);
  350: #ifdef DEBUG
  351:   fprintf(stderr,"We have sent the data\n");
  352: #endif /*DEBUG*/
  353: }
  354: 
  355: void SetupScantron(FILE ** serport,int problems,
  356: 		   Question questions[MAXQUEST])
  357: {
  358:   serial_open(serport,"/dev/ttyfb");
  359:   send_initform_strings(serport,problems,questions);
  360: }
  361: 
  362: /* stolen from allpin.c and modified by Guy Albertelli*/
  363: int buildPIDandPINlist(int setId, PIDPINlist PIDandPINlist[MAX_SECTION_SIZE] )
  364: {
  365:   int i=0,j=0,count=0,numStudents;
  366:   int SecCntArry[MAX_SECTION_COUNT], sectionIdx;
  367:   student_t Students[2048];
  368: 
  369:   if (count = capa_get_section_count(SecCntArry) != 0)
  370:     {
  371:       for (sectionIdx=1; sectionIdx <= SecCntArry[0]; sectionIdx++)
  372: 	{
  373: 	  numStudents=0;
  374: 	  get_section(Students, &numStudents, sectionIdx);
  375: 	  for(i=0;i<numStudents;i++,j++)
  376: 	    {
  377: 	      strcpy(PIDandPINlist[j].PID,Students[i].student_number);
  378: 	      PIDandPINlist[j].PIN=
  379: 		capa_PIN(Students[i].student_number,setId,0);
  380: 	    }
  381: 	}
  382:     }
  383:   return j;
  384: }
  385: 
  386: /*searches all the possible PIN's for all matches and then asks for 
  387:   confirmation of which PID to use*/
  388: int findPID(Student* student,PIDPINlist PIDandPINlist[MAX_SECTION_SIZE],
  389: 	    int numOfStudents)
  390: {
  391:   int i,j=0,matches[30],selection,error=ENONE;
  392:   
  393:   for(i=0;i<numOfStudents;i++)
  394:     {
  395:       if (atoi(student->PIN)==PIDandPINlist[i].PIN)
  396: 	{
  397: 	  matches[j]=i;
  398: 	  j++;
  399: 	}
  400:     }
  401:   matches[j]=-1;
  402:   switch(j)
  403:     {
  404:     case 0:
  405:       printf("No match for PIN %s\n",student->PIN);
  406:       error=ENOONE;
  407:       break;
  408:     case 1:
  409:       printf("Only one match assuming PID %s\n",PIDandPINlist[matches[0]].PID);
  410:       strcpy(student->questionPID,PIDandPINlist[matches[0]].PID);
  411:       break;
  412:     default:
  413:       printf("Please press\n");
  414:       for(i=0;i<30;i++)
  415: 	{
  416: 	  if (matches[i]!=-1)
  417: 	    {
  418: 	      printf("%d) for student number %s\n",i,
  419: 		     PIDandPINlist[matches[i]].PID);
  420: 	    }
  421: 	  else
  422: 	    {
  423: 	      i=30;
  424: 	    }
  425: 	}
  426:       scanf("%d",&selection);
  427:       if ((selection < j) && (selection > 0))
  428: 	{
  429: 	  strcpy(student->questionPID,PIDandPINlist[matches[selection]].PID);
  430: 	}
  431:       break;
  432:     }
  433:   return error;
  434: }
  435: 
  436: Student * getForm(int * status,FILE ** serport,
  437: 		  Question questions[MAXQUEST])
  438: {
  439:   Student *newStudent;
  440:   char buffer[1024],buf[1024],buf2[1024];
  441:   int readamount=0,done=0,i=0,j=0,h=0,q=0,space=0;
  442: 
  443:   sprintf(buffer,".read 2\015");
  444:   print(serport,buffer,1);
  445:   while(!done)
  446:     {
  447:       readamount=read(readportfd,buf,100);
  448:       buf[readamount]='\0';
  449:       for(i=0;i<readamount;i++,j++)
  450: 	{
  451: 	  if (buf[i]==13)
  452: 	    {
  453: 	      done=1;
  454: 	      break;
  455: 	    }
  456: 	  buf2[j]=buf[i];
  457: 	}
  458:       buf2[j]='\0';
  459:     }
  460: 
  461:   printf("%s\n",buf2);
  462: 
  463:   switch(buf2[0])
  464:     {
  465:     case '\"':
  466:       *status=GFFAILED;
  467:       return NULL;
  468:       break;
  469:     default:
  470:       newStudent=(Student *)malloc(sizeof(Student));
  471:       if (SurveyMode) 
  472: 	sprintf(newStudent->answerPID,"a%08d",formNumber++);
  473:       else
  474: 	strncpy(newStudent->answerPID,&buf2[10],9);
  475:       newStudent->answerPID[9]='\0';
  476:       strncpy(newStudent->class,&buf2[2],8);
  477:       newStudent->class[8]='\0';
  478:       strncpy(newStudent->SetId,&buf2[0],2);
  479:       newStudent->SetId[2]='\0';
  480:       strncpy(newStudent->PIN,&buf2[19],4);
  481:       newStudent->PIN[4]='\0';
  482:       i=23;h=0;
  483:       while(buf2[i]!='\0')
  484: 	{
  485: 	  switch(questions[h].type)
  486: 	    {
  487: 	    case 'a':
  488: 	    case 'd':
  489: 	    case 'f':
  490: 	      newStudent->Answers[h][0]=buf2[i];
  491: 	      newStudent->Answers[h][1]='\0';
  492: 	      if (isspace(buf2[i])) space++;
  493: 	      i++;
  494: 	      break;
  495: 	    case 'b':
  496: 	      /*loop through each leaf*/
  497: 	      for(j=0;j<questions[h].points;j++)
  498: 		{
  499: 		  newStudent->Answers[h][j]=buf2[i];
  500: 		  if (isspace(buf2[i])) space++;
  501: 		  i++;
  502: 		}
  503: 	      newStudent->Answers[h][j]='\0';
  504: 	      break;
  505: 	    case 'c':
  506: 	      /*loop through each leaf*/
  507: 	      for(j=0;j<questions[h].points;j++)
  508: 		{
  509: 		  newStudent->Answers[h][j]=buf2[i];
  510: 		  if (isspace(buf2[i])) space++;
  511: 		  i++;
  512: 		}
  513: 	      newStudent->Answers[h][j]='\0';
  514: 	      break;
  515: 	    case 'e':
  516: 	    case 'g':
  517: 	      for (j=0,q=0;j<8;j++)
  518: 		{
  519: 		  if (buf2[i]!=' ')
  520: 		    {
  521: 		      newStudent->Answers[h][q]=buf2[i];
  522: 		      q++;
  523: 		    }
  524: 		  i++;
  525: 		}
  526: 	      if (isspace(buf2[i])) space++;
  527: 	      newStudent->Answers[h][q]='\0';
  528: 	      break;
  529: 	    default:
  530: 	      fprintf(stderr,"Wha? %c",questions[h].type);
  531: 	      i++;
  532: 	      break;
  533: 	    }
  534: 	  h++;
  535: 	}
  536:       *status=GFSUCCESS;
  537:       break;
  538:     }
  539:   if (space!=0) *status=GFSPACES;
  540:   return newStudent;
  541: }
  542: 
  543: int checkForm(Student * student,int numQuestions,char *class,int setId)
  544: {
  545:   int error,pin;
  546:   student_t capaStudent;
  547: 
  548: #ifdef DEBUG
  549:   printf("PID:\t%s\nclass:\t%s\nSetId:\t%s\nPIN:\t%s\n",
  550: 	 student->answerPID,student->class,student->SetId,student->PIN);
  551: 
  552:   for(i=0,j=0;i<numQuestions;i++)
  553:     {
  554:       printf("Answer %d: %s\n",i,student->Answers[i]);
  555:     }
  556: #endif /*DEBUG*/
  557: 
  558:   if (CompareClassName)
  559:     {
  560:       if (strncasecmp(student->class,class,8))
  561: 	{
  562: 	  printf("Class: The Scantron reported:%s, You typed in:%s\n",
  563: 		 student->class,class);
  564: 	  return ECLASS;
  565: 	}
  566:     }
  567:   else
  568:     {
  569:       strcpy(student->class,class);
  570:       sprintf(student->SetId,"%2d",setId);
  571:     }
  572: 
  573:   error=capa_get_student_info(student->answerPID, &capaStudent);
  574:   switch(error)
  575:     {
  576:     case 1:
  577:       printf("%s %d\n\n",capaStudent.name,capaStudent.section);
  578:       break;
  579:     case 0:
  580:       printf("PID: The Scantron reported:%s\n",student->answerPID);
  581:       return ESTID;
  582:       break;
  583:     case -1:
  584:       return ECLASSL;
  585:       break;
  586:     default:
  587:       fprintf(stderr,"capa_get_student returned an invalid result ");
  588:       fprintf(stderr,"in CheckForm.\n");
  589:       break;
  590:     }
  591:   
  592:   if (CheckPIN && !Anon)
  593:     {
  594:       pin=capa_PIN(student->answerPID,atoi(student->SetId),0);
  595:       if (pin!=atoi(student->PIN))
  596: 	{
  597: 	  printf("PIN: The Scantron reported:%s, The Classl file has:%d\n",
  598: 		 student->PIN,pin);
  599: 	  return EPIN;
  600: 	}
  601:     }
  602:   return 0;
  603: }
  604: 
  605: long getBubblerEntry(FILE ** outputFile,char *PID)
  606: {
  607:   char oneline[512],fmtbuf[16],a_sn[32];
  608:   int done=0,found=0,offset=0,len=0,next_r=0;
  609: 
  610:   rewind(*outputFile);
  611:   sprintf(fmtbuf,"%%%dc",MAX_STUDENT_NUMBER);
  612:   while(!done)
  613:     {
  614:       done=!fgets(oneline,511,*outputFile);
  615:       len=strlen(oneline);
  616:       if (!done)
  617: 	{
  618: 	  sscanf(oneline,fmtbuf,a_sn);
  619: 	  if (!strncasecmp(a_sn,PID,MAX_STUDENT_NUMBER))
  620: 	    {
  621: 	      next_r=ftell(*outputFile);
  622: 	      offset = next_r-len;
  623: 	      done=1;
  624: 	      found=1;
  625: 	    }
  626: 	  else
  627: 	    {
  628: 	    }
  629: 	}
  630:       else
  631: 	{
  632: 	  fseek(*outputFile,0L,SEEK_END);
  633: 	  offset=ftell(*outputFile);
  634: 	  fseek(*outputFile,-1L,SEEK_END);
  635: 	  while (fgetc(*outputFile)=='\n')
  636: 	    {
  637: 	      offset--;
  638: 	      fseek(*outputFile,offset,SEEK_SET);
  639: 	    }
  640: 	  offset= offset+2;
  641: 	  found=0;
  642: 	  done=1;
  643: 	}
  644:     }
  645:   if(!found)
  646:     {
  647:       offset=-offset;
  648:     }
  649:   return offset;
  650: }
  651: 	  
  652: 
  653: void setBubblerEntry(FILE ** outputFile,char* answerPID,char* name,
  654: 		     char* answers,int score, int section, 
  655: 		     char* answerstring,char* questionPID, int offset)
  656: {
  657:   int len=0;
  658:   char buf[1024];
  659:   
  660:   rewind(*outputFile);
  661:   sprintf(buf,"%s %s %s %3d %2d %s %s\n",answerPID,name,answers,score,section,
  662: 	  answerstring,questionPID);
  663:   len=strlen(buf);
  664:   fseek(*outputFile,abs(offset),0);
  665:   if(!fwrite(buf,len,1,*outputFile))
  666:     {
  667:       fprintf(stderr,"Failed write.\n");
  668:     }
  669: }
  670:      
  671: 
  672: /* Checks if answers are right and gives a point for each right.*/
  673: void writeForm(Student * student,FILE ** outputFile,
  674: 	       Question questions[MAXQUEST],int numQuestions)
  675: {
  676:   int result,capaQuestions,questionIndex,leafs,numRight,error,total=0;
  677:   int offset2;
  678:   char one=1,zero=0;
  679:   char *ansOn[20],*stuOn[20];
  680:   Problem_t *problems,*oldproblem;
  681:   char answerstring[1024],grade[1024];
  682:   student_t capaStudent;
  683: 
  684:   if (!SurveyMode)
  685:     {
  686:       error=capa_get_student_info(student->answerPID, &capaStudent);
  687:       result=capa_parse(atoi(student->SetId),&problems,student->questionPID,
  688: 			&capaQuestions);
  689:       oldproblem=problems;
  690:       if (result==0)
  691: 	{
  692: 	  fprintf(stderr,"Parse failed: %d\n",result);
  693: 	  return;
  694: 	}
  695:     }
  696:   else
  697:     {
  698:       strcpy(capaStudent.name,"Unknown                       ");
  699:       capaStudent.section=0;
  700:       oldproblem=problems=NULL;      
  701:     }
  702:   offset2=getBubblerEntry(outputFile,student->answerPID);
  703:   for(questionIndex=0;questionIndex<numQuestions;questionIndex++)
  704:     {
  705:       switch(questions[questionIndex].type)
  706: 	{
  707: 	case 'a':
  708: 	case 'b':
  709: 	case 'c':
  710: 	case 'f':
  711: 	  numRight=0;
  712: 	  printf("%s %s\n",problems->answer,student->Answers[questionIndex]);
  713: 	  for(leafs=0;problems->answer[leafs]!='\0';leafs++)
  714: 	    {
  715: 	      if (problems->answer[leafs]==
  716: 		  student->Answers[questionIndex][leafs])
  717: 		{
  718: 		  numRight++;
  719: 		}
  720: 	    }
  721: 	  total+=numRight;
  722: 	  grade[questionIndex]='0'+(char)numRight;
  723: 	  break;
  724: 	case 'd':
  725: 	  printf("%s\n",student->Answers[questionIndex]);
  726: 	  grade[questionIndex]=student->Answers[questionIndex][0];
  727: 	  if (isspace(student->Answers[questionIndex][0]))
  728: 	    total+=0;
  729: 	  else
  730: 	    total+=(int)(student->Answers[questionIndex][0]-'0');
  731: 	  break;
  732: 	case 'e':
  733: 	  printf("%s %s\n",problems->answer,student->Answers[questionIndex]);
  734: 	  numRight=0;
  735: 	  for(leafs=0;questions[questionIndex].leafs>leafs;leafs++)
  736: 	    {
  737: 	      ansOn[leafs]=strchr(problems->answer,('A'+(char)leafs));
  738: 	    }
  739: 	  for(leafs=0;questions[questionIndex].leafs>leafs;leafs++)
  740: 	    {
  741: 	      if (ansOn[leafs] != NULL ) { ansOn[leafs]=&one;} 
  742: 	      else { ansOn[leafs]=&zero;}
  743: 	    }
  744: 	  for(leafs=0;questions[questionIndex].leafs>leafs;leafs++)
  745: 	    {
  746: 	      stuOn[leafs]=strchr(student->Answers[questionIndex],
  747: 				  ('A'+(char)leafs));
  748: 	    }
  749: 	  for(leafs=0;questions[questionIndex].leafs>leafs;leafs++)
  750: 	    {
  751: 	      if (stuOn[leafs] != NULL) {stuOn[leafs]=&one;} 
  752: 	      else {stuOn[leafs]=&zero;}
  753: 	    }
  754: 	  for(leafs=0;questions[questionIndex].leafs>leafs;leafs++)
  755: 	    {
  756: 	      if (ansOn[leafs] == stuOn[leafs]) numRight++;
  757: 	    }
  758: 	  fprintf(stderr,"%d\n",numRight);
  759: 	  total+=numRight;
  760: 	  grade[questionIndex]='0'+(char)numRight;
  761: 	  break;
  762: 	case 'g':
  763: 	  printf("%s %s\n",problems->answer,student->Answers[questionIndex]);
  764: 	  if (!(strcasecmp(problems->answer,student->Answers[questionIndex])))
  765: 	    {
  766: 	      total+=questions[questionIndex].points;
  767: 	      grade[questionIndex]='0'+questions[questionIndex].points;
  768: 	    }
  769: 	  else
  770: 	    {
  771: 	      grade[questionIndex]='0';
  772: 	    }
  773: 	  break;
  774: 	default:
  775: 	  printf("No points since don't know question type.\n");
  776: 	  break;
  777: 	}
  778:       if (!SurveyMode) problems=problems->next;
  779:     }
  780: 
  781:   answerstring[0]='\0';
  782: 
  783:   for(questionIndex=0;questionIndex<numQuestions;questionIndex++)
  784:     {
  785:       strcat(answerstring,student->Answers[questionIndex]);
  786:     }
  787:      
  788:   setBubblerEntry(outputFile,student->answerPID,capaStudent.name,grade,
  789: 		  total,capaStudent.section,answerstring,student->questionPID,
  790: 		  offset2);
  791: 
  792:   if (!SurveyMode)
  793:     {
  794:       problems=oldproblem;
  795:       for(questionIndex=0;problems!=NULL;questionIndex++)
  796: 	{
  797: 	  oldproblem=problems;
  798: 	  problems=problems->next;
  799: 	  free(oldproblem);
  800: 	}
  801: #ifdef DEBUG
  802:       fprintf(stderr,"Freed: %d\n",questionIndex);
  803: #endif /*DEBUG*/
  804:     }
  805: }
  806: 
  807: void processForms(FILE ** serport,int numQuestions,
  808: 		  Question questions[MAXQUEST],char* class,int setId)
  809: {
  810: 
  811:   int done=0,error,i,numOfStudents=0;
  812:   int status;
  813:   char buf[128],filename[128];
  814:   Student * student;
  815:   FILE * outputFile;
  816:   PIDPINlist PIDandPINlist[MAX_SECTION_SIZE];
  817: 
  818:   sprintf(filename,"bubbler.output.%d",setId);
  819:   outputFile=fopen(filename,"r+");
  820:   if (outputFile != NULL)
  821:     {
  822:       rewind(outputFile);
  823:       fscanf(outputFile,"%s",buf);
  824:     }
  825:   if (outputFile==NULL || buf[0]=='\0')
  826:     {
  827:       outputFile=fopen(filename,"w+");
  828:       fprintf(outputFile,"%s %d ",class,setId);
  829:       for(i=0;i<numQuestions;i++)
  830: 	{
  831: 	  fprintf(outputFile,"%c%d",questions[i].type,questions[i].points);
  832: 	}
  833:       fprintf(outputFile,"\n");
  834:     }
  835:   if (Anon)
  836:     {
  837:       numOfStudents=buildPIDandPINlist(setId,PIDandPINlist);
  838:       if (numOfStudents==0)
  839: 	{
  840: 	  fprintf(stderr,"buildPIDandPINlists returned 0 students.");
  841: 	  exit(-2);
  842: 	}
  843:     }
  844:   
  845:   while(!done)
  846:     {
  847:       student=getForm(&status,serport,questions);
  848:       switch (status)
  849: 	{
  850: 	case GFSPACES:
  851: 	  if (CheckSpaces)
  852: 	    {
  853: 	      printf("The current form appears to have some questions left\n");
  854: 	      printf("blank. Please enter yes if you wish to continue \n");
  855: 	      printf("grading of this form.\n");
  856: 	      scanf("%s",buf);
  857: 	      if (buf[0]=='y' || buf[0]=='Y') ;
  858: 	      else break;
  859: 	    }
  860: 	case GFSUCCESS:
  861: 	  if ((!SurveyMode) && 
  862: 	      (error=checkForm(student,numQuestions,class,setId))) 
  863: 	    {
  864: 	      switch(error)
  865: 		{
  866: 		case ECLASS:
  867: 		  printf("The current form has a class string that is \n");
  868: 		  printf("different from the one entered at the start.\n");
  869: 		  printf("Please place that form to the side and type ");
  870: 		  printf("start to continue.\n");
  871: 		  scanf("%s",buf);
  872: 		  break;
  873: 		case ESTID:
  874: 		  printf("The current form's Student Id is incorrect.\n");
  875: 		  printf("Please set the form aside and type start to ");
  876: 		  printf("continue.\n");
  877: 		  scanf("%s",buf);
  878: 		  break;
  879: 		case ECLASSL:
  880: 		  fprintf(stderr,"The classl file was not found in the");
  881: 		  fprintf(stderr," current directory.\n");
  882: 		  fprintf(stderr,"Please try again.\n");
  883: 		  done=1;
  884: 		  break;
  885: 		case EPIN:
  886: 		  fprintf(stderr,"The current form's PIN is incorrect.\n");
  887: 		  fprintf(stderr,"Please set the form aside and type ");
  888: 		  fprintf(stderr,"start to continue.\n");
  889: 		  scanf("%s",buf);
  890: 		  break;
  891: 		default:
  892: 		  fprintf(stderr,"Unimplemented error in checkForm %d\n",
  893: 			  error);
  894: 		  break;
  895: 		}
  896: 	    }
  897: 	  else
  898: 	    {
  899: 	      if (Anon)
  900: 		{
  901: 		  error=findPID(student,PIDandPINlist,numOfStudents);
  902: 		}
  903: 	      else
  904: 		{
  905: 		  error=ENONE;
  906: 		  strcpy(student->questionPID,student->answerPID);
  907: 		}
  908: 	      switch(error)
  909: 		{
  910: 		case ENONE:
  911: 		  writeForm(student,&outputFile,questions,numQuestions);
  912: 		  break;
  913: 		case ENOONE:
  914: 		  break;
  915: 		default:
  916: 		  fprintf(stderr,"Unimplemented error in findPID %d\n",
  917: 			  error);
  918: 		  break;
  919: 		}
  920: 	    }
  921: 	  break;
  922: 	case GFFAILED:
  923: 	  printf("The Scantron has returned an error.\n");
  924: 	  printf("Are there still more forms to process?");
  925: 	  scanf("%s",buf);
  926: 	  if (buf[0]=='n')
  927: 	    {
  928: 	      done=1;
  929: 	    }
  930: 	  else
  931: 	    {
  932: 	      printf("Please put that last read form to the side.\n");
  933: 	      printf("Enter start to continue\n");
  934: 	      scanf("%s",buf);
  935: 	    }
  936: 	  break;
  937: 	case GFEOF:
  938: 	  done=1;
  939: 	  break;
  940: 	default:
  941: 	  printf("Unimplened return code in GetForm %d\n",status);
  942: 	  break;
  943: 	}
  944:       if (student != NULL)
  945: 	{
  946: 	  free(student);
  947: 	}
  948:     }
  949: }
  950: 
  951: void CloseScantron(FILE ** serport)
  952: {
  953:   fprintf(*serport,".srst\r");
  954:   fclose(*serport);
  955: }
  956: 
  957: int main(int argc, char *argv[])
  958: {
  959:   FILE * serport;
  960:   Question questions[MAXQUEST];
  961:   char class[10];
  962:   int numQuestions,setId;
  963: 
  964:   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");
  965:   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");
  966:   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");
  967:   printf("Welcome to Bubbler, the Automated CAPA grader.\n");
  968:   printf("Version 0.05.02\n\n\n");
  969:   numQuestions=GetProblems(questions,class,&setId);
  970:   SetupScantron(&serport,numQuestions,questions);
  971:   processForms(&serport,numQuestions,questions,class,setId);
  972:   CloseScantron(&serport);
  973:   return 0;
  974: }
  975: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>