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, 8 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

#include <stdio.h>
#include <sgtty.h>
#include <libc.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <ctype.h>
#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;i<q;i++)
	{
	  questions[i].type='d';
	  questions[i].leafs=questions[i].points=9;
	}
    }
  else
    {
      SurveyMode=0;

      printf("Should bubbler compare the entered class name and SetId with \n");
      printf("the encoded information on each paper?(y or n)");
      scanf("%s",clear);
      if (clear[0]=='N' || clear[0]=='n')
	CompareClassName=0;
      else
	CompareClassName=1;
      
      printf("Should the student coded CAPA ID be checked for correctness?\n");
      printf("(y or n)");
      scanf("%s",clear);
      if (clear[0]=='N' || clear[0]=='n')
	CheckPIN=0;
      else
	{
	  CheckPIN=1;
	  
	  printf("Should bubbler run in Anonymous mode (search for correct \n");
	  printf("Student Number based on the CAPA ID)? (y or n)");
	  scanf("%s",clear);
	  
	  if (clear[0]=='N' || clear[0]=='n')
	    Anon=0;
	  else
	    Anon=1;
	}
      
      printf("Should bubbler check for blank answers and issue a warning when \n");
      printf("one is encountered? (y or n)");
      scanf("%s",clear);
      if (clear[0]=='N' || clear[0]=='n')
	CheckSpaces=0;
      else
	CheckSpaces=1;
      
      length=strlen(class);
      if (length < 8)
	{
	  for(;length<8;length++)
	    {
	      class[length]=' ';
	    }
	  class[length]='\0';
	}
      printf("How many Questions are on the form?");
      scanf("%d",&q);
      
      printf("For Each Question enter \"a\" for a one out of 8\n");
      printf("                        \"b\" for a GLE type\n");
      printf("                        \"c\" for a TF type.\n");
      printf("                        \"d\" for an assigned score.\n");
      printf("                        \"e\" for a multiple out of 8.\n");
      printf("                        \"f\" for single digit string matching.\n");
      printf("                        \"g\" for exact string matching/\n");
      
      for (i=0;i<q;i++)
	{
	  printf("Question#%2d: ",i+1);
	  scanf("%1s",&questions[i].type);
	  fflush(stdin);
	  switch(questions[i].type)
	    {
	    case 'a':
	    case 'd':
	    case 'g':
	    case 'f':
	      printf("How many Points are possible?");
	      scanf("%d",&questions[i].points);
	      questions[i].leafs=questions[i].points;
	      break;
	    case 'b':
	    case 'c':
	      printf("How many parts to the problem?");
	      scanf("%d",&questions[i].points);
	      questions[i].leafs=questions[i].points;
	      break;
	    case 'e':
	      printf("How many possible answers are there?");
	      scanf("%d",&questions[i].points);
	      questions[i].leafs=questions[i].points;
	      break;
	    default:
	      printf("Unknown choice.\n");
	      break;
	    }
	  fflush(stdin);
	}
    }
  return q;
}
 
void serial_open(FILE ** streamserport,char * device)
{
  struct sgttyb one;
  
  if ((serportfd=open(device,O_WRONLY,O_CREAT))==-1)
    {
      fprintf(stderr,"Unable to open serial port.\n");
      exit(-1);
    }

  if ((readportfd=open(device,O_RDONLY,O_CREAT))==-1)
    {
      fprintf(stderr,"Unable to open serial port for reading.\n");
      exit(-1);
    }
  
  one.sg_ispeed='\015';
  one.sg_ospeed='\015';
  one.sg_erase='\177';
  one.sg_kill='\024';
  one.sg_flags= (short) 3;

#ifdef DEBUG  
  ioctl(serportfd,TIOCGETP,&two);
  printf("%d %d %d %d %d\n",two.sg_ispeed,two.sg_ospeed,
	 two.sg_erase,two.sg_kill,two.sg_flags);
#endif
  
  ioctl(serportfd,TIOCSETN,&one);
  ioctl(readportfd,TIOCSETN,&one);

#ifdef DEBUG
  ioctl(serportfd,TIOCGETP,&two);
  printf("%d %d %d %d %d\n",two.sg_ispeed,two.sg_ospeed,
	 two.sg_erase,two.sg_kill,two.sg_flags);
  printf("%d %d %d %d %d\n",one.sg_ispeed,one.sg_ospeed,
	 one.sg_erase,one.sg_kill,one.sg_flags);
#endif
  *streamserport=fdopen(serportfd,"w");
  readport=fdopen(readportfd,"r");
}


void print(FILE** serport,char * out,int shouldread)
{
  int readamount;
  char buf[100];

#ifdef DEBUG
  printf("%s\n",out);
#endif /*DEBUG*/

  write(serportfd,out,strlen(out));
  if (shouldread)
    {
      readamount=read(readportfd,buf,1);
#ifdef DEBUG
      printf("%d %d\n",readamount,buf[0]);
#endif
    }
}

void send_initform_strings(FILE ** serport,int numQuestions,
			   Question questions[MAXQUEST])
{
  int i, scan,j,Points;
  /* this sets up kermit and then sends the correct strings to the scantron 
     to define what the sheet looks like 
     */
  char buffer[1024],answerString[1024];
  
  for(i=0;i<1000;i++) 
    {
      buffer[i]='\0';
    }
  
  scan=11+numQuestions;
  
  /* resets the scantron*/
  sprintf(buffer,".srst\015");
  print(serport,buffer, 1);
  
  /* sets the error character to be the '"' character */
  sprintf(buffer,".err=34\015");
  print(serport,buffer, 1);
 
  /* tell scantron how many scanlines there are*/
  sprintf(buffer,".frm=fs %d 0 48 n n n\015",scan);
  print(serport,buffer, 1);
 
  /* encoded class info*/
  sprintf(buffer,".frm=pa 1 2 44 11 32 l 10 7\015");
  print(serport,buffer, 1);
 
  /* the first letter of the student number*/
  sprintf(buffer,".frm=mc n n 1 1 3 4 4 4 c 1 2 ab\015");
  print(serport,buffer, 1);
 
  /* the remaining digits of the student number*/
  sprintf(buffer,".frm=mc n n 1 1 2 6 11 20 c 8 10 0123456789\015");
  print(serport,buffer, 1);
 
  /* the PIN number*/
  sprintf(buffer,".frm=mc n n 1 1 2 24 11 30 c 4 10 0123456789\015");
  print(serport,buffer, 1);

#ifdef DEBUG
  printf("%d\n",numQuestions);
#endif /*DEBUG*/

  /*sets each question line*/
  for (i=0;i<numQuestions;i++)
    {

#ifdef DEBUG
      printf("%c\n",questions[i].type);
#endif /*DEBUG*/

      switch (questions[i].type)
	{
	case 'a':
	  sprintf(buffer,".frm=mc n m 1 1 %d 6 %d 20 l 1 8 ABCDEFGH\015",
		  i+12,i+12);
	  print(serport,buffer,1);
	  break;
	case 'b':
	  for(j=0;j<questions[i].points;j++)
	    {
	      sprintf(buffer,
		      ".frm=mc n m 1 1 %d %d %d %d l 1 3 GLE\015",
		      i+12,(j*8)+6,i+12,(j*8)+10);
	      print(serport,buffer,1);
	    }
	  break;
	case 'c':
	  for(j=0;j<questions[i].points;j++)
	    {
	      sprintf(buffer,
		      ".frm=mc n m 1 1 %d %d %d %d l 1 2 TF\015",
		      i+12,(j*6)+6,i+12,(j*6)+8);
	      print(serport,buffer,1);
	    }
	  break;
	case 'd':
	  answerString[0]='\0';
	  Points=questions[i].points;
	  for(j=0;j<=Points;j++)
	    {
	      sprintf(buffer,"%d",j);
	      strcat(answerString,buffer);
	    }
	  sprintf(buffer,".frm=mc n m 1 1 %d 6 %d %d l 1 %d %s\015",
		  i+12,i+12,(Points*2)+6,Points+1,answerString);
	  print(serport,buffer,1);
	  break;
	case 'e':
	case 'g':
	  sprintf(buffer,".frm=mc y n 1 1 %d 6 %d 20 l 1 8 ABCDEFGH\015",
		  i+12,i+12);
	  print(serport,buffer,1);
	  break;
	case 'f':
	  sprintf(buffer,".frm=mc n m 1 1 %d 6 %d 24 l 1 10 0123456789\015",
		  i+12,i+12);
	  print(serport,buffer,1);
	  break;
	default:
	  fprintf(stderr,"Booga Booga, couldn't find that question type to");
	  fprintf(stderr," tell Scantron about\n %c \n",questions[i].type);
	  break;
	}
    }

  /* end of the form*/
  sprintf(buffer,".frm=ls\015");
  print(serport,buffer, 1);
#ifdef DEBUG
  fprintf(stderr,"We have sent the data\n");
#endif /*DEBUG*/
}

void SetupScantron(FILE ** serport,int problems,
		   Question questions[MAXQUEST])
{
  serial_open(serport,"/dev/ttyfb");
  send_initform_strings(serport,problems,questions);
}

/* stolen from allpin.c and modified by Guy Albertelli*/
int buildPIDandPINlist(int setId, PIDPINlist PIDandPINlist[MAX_SECTION_SIZE] )
{
  int i=0,j=0,count=0,numStudents;
  int SecCntArry[MAX_SECTION_COUNT], sectionIdx;
  student_t Students[2048];

  if (count = capa_get_section_count(SecCntArry) != 0)
    {
      for (sectionIdx=1; sectionIdx <= SecCntArry[0]; sectionIdx++)
	{
	  numStudents=0;
	  get_section(Students, &numStudents, sectionIdx);
	  for(i=0;i<numStudents;i++,j++)
	    {
	      strcpy(PIDandPINlist[j].PID,Students[i].student_number);
	      PIDandPINlist[j].PIN=
		capa_PIN(Students[i].student_number,setId,0);
	    }
	}
    }
  return j;
}

/*searches all the possible PIN's for all matches and then asks for 
  confirmation of which PID to use*/
int findPID(Student* student,PIDPINlist PIDandPINlist[MAX_SECTION_SIZE],
	    int numOfStudents)
{
  int i,j=0,matches[30],selection,error=ENONE;
  
  for(i=0;i<numOfStudents;i++)
    {
      if (atoi(student->PIN)==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;i<readamount;i++,j++)
	{
	  if (buf[i]==13)
	    {
	      done=1;
	      break;
	    }
	  buf2[j]=buf[i];
	}
      buf2[j]='\0';
    }

  printf("%s\n",buf2);

  switch(buf2[0])
    {
    case '\"':
      *status=GFFAILED;
      return NULL;
      break;
    default:
      newStudent=(Student *)malloc(sizeof(Student));
      if (SurveyMode) 
	sprintf(newStudent->answerPID,"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;j<questions[h].points;j++)
		{
		  newStudent->Answers[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;j<questions[h].points;j++)
		{
		  newStudent->Answers[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;i<numQuestions;i++)
    {
      printf("Answer %d: %s\n",i,student->Answers[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;questionIndex<numQuestions;questionIndex++)
    {
      switch(questions[questionIndex].type)
	{
	case 'a':
	case 'b':
	case 'c':
	case 'f':
	  numRight=0;
	  printf("%s %s\n",problems->answer,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;questionIndex<numQuestions;questionIndex++)
    {
      strcat(answerstring,student->Answers[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;i<numQuestions;i++)
	{
	  fprintf(outputFile,"%c%d",questions[i].type,questions[i].points);
	}
      fprintf(outputFile,"\n");
    }
  if (Anon)
    {
      numOfStudents=buildPIDandPINlist(setId,PIDandPINlist);
      if (numOfStudents==0)
	{
	  fprintf(stderr,"buildPIDandPINlists returned 0 students.");
	  exit(-2);
	}
    }
  
  while(!done)
    {
      student=getForm(&status,serport,questions);
      switch (status)
	{
	case GFSPACES:
	  if (CheckSpaces)
	    {
	      printf("The current form appears to have some questions left\n");
	      printf("blank. Please enter yes if you wish to continue \n");
	      printf("grading of this form.\n");
	      scanf("%s",buf);
	      if (buf[0]=='y' || buf[0]=='Y') ;
	      else break;
	    }
	case GFSUCCESS:
	  if ((!SurveyMode) && 
	      (error=checkForm(student,numQuestions,class,setId))) 
	    {
	      switch(error)
		{
		case ECLASS:
		  printf("The current form has a class string that is \n");
		  printf("different from the one entered at the start.\n");
		  printf("Please place that form to the side and type ");
		  printf("start to continue.\n");
		  scanf("%s",buf);
		  break;
		case ESTID:
		  printf("The current form's Student Id is incorrect.\n");
		  printf("Please set the form aside and type start to ");
		  printf("continue.\n");
		  scanf("%s",buf);
		  break;
		case ECLASSL:
		  fprintf(stderr,"The classl file was not found in the");
		  fprintf(stderr," current directory.\n");
		  fprintf(stderr,"Please try again.\n");
		  done=1;
		  break;
		case EPIN:
		  fprintf(stderr,"The current form's PIN is incorrect.\n");
		  fprintf(stderr,"Please set the form aside and type ");
		  fprintf(stderr,"start to continue.\n");
		  scanf("%s",buf);
		  break;
		default:
		  fprintf(stderr,"Unimplemented error in checkForm %d\n",
			  error);
		  break;
		}
	    }
	  else
	    {
	      if (Anon)
		{
		  error=findPID(student,PIDandPINlist,numOfStudents);
		}
	      else
		{
		  error=ENONE;
		  strcpy(student->questionPID,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;
}


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