File:  [LON-CAPA] / capa / capa51 / Historic / Scorer / scorer.c
Revision 1.1: download - view: text, annotated - select for diffs
Wed Aug 30 15:02:30 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_5, 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, 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
- documentation updates

    1: /*
    2:  * scorer.c
    3:  * Copyright Guy Albertelli II 1997
    4:  */
    5: #include <stdio.h>
    6: #include <stdlib.h>
    7: #include <ctype.h>
    8: #include <string.h>
    9: #ifdef NeXT
   10: #endif
   11: #ifdef linux
   12: #include <sys/types.h>
   13: #include <sys/stat.h>
   14: #include <fcntl.h>
   15: #include <termios.h>
   16: #include <unistd.h>
   17: #endif
   18: #include "Capa/capaCommon.h"
   19: #include "scorer.h"
   20: 
   21: extern int Parsemode_f;
   22: 
   23: void initScreen()
   24: {
   25:   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");
   26:   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");
   27:   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");
   28:   printf("Welcome to Scorer, the Automated Scoring Office converter.\n");
   29:   printf("By: Guy Albertelli II\n");
   30:   printf("Version %s.%s for %s\n\n\n",MAJORVER,MINORVER,ARCHSTR);
   31: }
   32: 
   33: void getClassInfo(Flags *flags,FILE** scantron)
   34: {
   35:   char buffer[MAX_LINE_LENGTH],buffer2[MAX_LINE_LENGTH];
   36:   int done=FALSE;
   37: 
   38:   printf("What is the class name?");
   39:   scanf("%s",flags->Class);
   40:   flags->Class[8]='\0';
   41:   printf("What is the SetId?");
   42:   scanf("%d",&(flags->SetId));
   43:   
   44:   while(!done)
   45:     {
   46:       printf("What is the name of the scoring offices report file?");
   47:       scanf("%s",buffer);
   48:       *scantron=fopen(buffer,"r");
   49:       if (*scantron != NULL)
   50: 	{
   51: 	  rewind(*scantron);
   52: 	  if (EOF == fscanf(*scantron,"%s",buffer2))
   53: 	    printf("This file appears to be empty. Please enter a new name.\n");
   54: 	  else
   55: 	    {
   56: 	      rewind(*scantron);
   57: 	      done=1;
   58: 	    }
   59: 	}
   60:       else
   61: 	printf("Unable to open the report file %s\n",buffer);
   62:     }
   63: }
   64: 
   65: int openOutputFile(char filename[MAX_LINE_LENGTH], FILE ** outputFile)
   66: {
   67:   char buf[MAX_LINE_LENGTH];
   68: 
   69:   *outputFile=fopen(filename,"r+");
   70: 
   71:   if (*outputFile != NULL)
   72:     {
   73:       rewind(*outputFile);
   74:       if (EOF == fscanf(*outputFile,"%s",buf))
   75: 	  buf[0]='\0';
   76:     }
   77:   
   78:   if (*outputFile==NULL || buf[0]=='\0')
   79:     {
   80:       if (*outputFile != NULL)
   81: 	fclose(*outputFile);
   82:       *outputFile=fopen(filename,"w+");
   83:       if (*outputFile==NULL)
   84: 	{
   85: 	  fprintf(stderr,"Unable to open the output file %s\n",filename);
   86: 	  return SCO_FATALERROR;
   87: 	}
   88:       else
   89: 	return SCO_NEW;
   90:     }
   91:   else
   92:     {
   93:       rewind(*outputFile);
   94:       return SCO_EXIST;
   95:     }  
   96: }
   97: 
   98: void initValues(Question questions[MAX_QUEST],Flags *flags)
   99: {
  100:   int i;
  101:   flags->NumQuestions=0;
  102:   flags->CheckPIN=TRUE;
  103:   flags->AnonMode=FALSE;
  104:   flags->CheckSpaces=FALSE;
  105:   flags->SurveyMode=FALSE;
  106:   flags->SurveyHeader=FALSE;
  107:   flags->Pause=FALSE;
  108:   flags->PauseTime=0.0;
  109:   flags->IdFormat=ANUMBER_FORMAT;
  110:   flags->CheckMultipleMarks=FALSE;
  111:   flags->QueryAboutPID=FALSE;
  112:   flags->log=TRUE;
  113:   for(i=0;i<MAX_QUEST;i++)
  114:     {
  115:       questions[i].type='\0';
  116:       questions[i].points=0;
  117:       questions[i].leafs=0;
  118:     }
  119: }
  120: 
  121: int getPreviousValues(FILE *outputFile, Question questions[MAX_QUEST],
  122: 		      Flags *flags)
  123: 
  124: {
  125:   char prevClass[MAX_LINE_LENGTH],prevFlags[MAX_LINE_LENGTH],
  126:     prevQuestions[MAX_LINE_LENGTH],buf[MAX_LINE_LENGTH];
  127:   int prevSetId,prevNumQuestions,done,i;
  128:   float pauseTime;
  129: 
  130:   rewind(outputFile);
  131:   fscanf(outputFile,"%s %d %d %s %f %s",prevClass,&prevSetId,&prevNumQuestions,
  132: 	 prevFlags,&pauseTime,prevQuestions);
  133:   if ( strcmp(prevClass,flags->Class)!=0)
  134:     {
  135:       printf("Classname as found in the current scorer.output file: %s\n",
  136: 	     prevClass);
  137:       printf("Classname as entered: %s\n",flags->Class);
  138:       printf("Please select one as correct. previous or new (p/n).\n");
  139:       done=FALSE;
  140:       while(!done)
  141: 	{
  142: 	  scanf("%s",buf);
  143: 	  switch(buf[0])
  144: 	    {
  145: 	    case 'n':case'N':
  146: 	      done=TRUE;
  147: 	      break;
  148: 	    case 'p':case'P':
  149: 	      done=TRUE;
  150: 	      strcpy(flags->Class,prevClass);
  151: 	      break;
  152: 	    default:
  153: 	      printf("Please enter one of previous(p) or new(n).\n");
  154: 	      break;
  155: 	    }
  156: 	}
  157:     }
  158:   if ( prevSetId != flags->SetId )
  159:     {
  160:       printf("SetId as found in the current scorer.output file: %d\n",
  161: 	     prevSetId);
  162:       printf("SetId as entered: %d\n",flags->SetId);
  163:       printf("Please select one as correct. previous or new (p/n).\n");
  164:       done=FALSE;
  165:       while(!done)
  166: 	{
  167: 	  scanf("%s",buf);
  168: 	  switch(buf[0])
  169: 	    {
  170: 	    case 'n':case'N':
  171: 	      done=TRUE;
  172: 	      break;
  173: 	    case 'p':case'P':
  174: 	      done=TRUE;
  175: 	      flags->SetId=prevSetId;
  176: 	      break;
  177: 	    default:
  178: 	      printf("Please enter one of previous(p) or new(n).\n");
  179: 	      break;
  180: 	    }
  181: 	}
  182:     }
  183:   flags->NumQuestions=prevNumQuestions;
  184:   flags->CheckPIN=(int)(prevFlags[0]-'0');
  185:   flags->AnonMode=(int)(prevFlags[1]-'0');
  186:   flags->CheckSpaces=(int)(prevFlags[2]-'0');
  187:   flags->SurveyMode=(int)(prevFlags[3]-'0');
  188:   flags->SurveyHeader=(int)(prevFlags[4]-'0');
  189:   flags->Pause=(int)(prevFlags[5]-'0');
  190:   flags->PauseTime=pauseTime;
  191:   flags->IdFormat=(int)(prevFlags[6]-'0');
  192:   flags->CheckMultipleMarks=(int)(prevFlags[7]-'0');
  193:   flags->QueryAboutPID=(int)(prevFlags[8]-'0');
  194:   flags->log=(int)(prevFlags[9]-'0');
  195:   for(i=0;i<flags->NumQuestions;i++)
  196:     {
  197:       questions[i].type=prevQuestions[3*i];
  198:       questions[i].points=(int)(prevQuestions[3*i+1]-'0');
  199:       questions[i].leafs=(int)(prevQuestions[3*i+2]-'0');
  200:     }
  201:   for(i=flags->NumQuestions;i<MAX_QUEST;i++)
  202:     {
  203:       questions[i].type='\0';
  204:       questions[i].points=0;
  205:       questions[i].leafs=0;
  206:     }
  207:   return 0;
  208: }
  209: 
  210: int printFlagMenu(Flags *flags, int *flagToModify)
  211: {
  212:   int i=0;
  213:   if(flags->SurveyMode)
  214:     {
  215:       printf("%d. The Paper being graded is a Survey.\n",++i);
  216:       flagToModify[i]=SURVEY_MODE;
  217:       if(flags->SurveyHeader)
  218: 	printf("%d. The Survey has a header.\n",++i);
  219:       else
  220: 	printf("%d. The Survey does not have a header.\n",++i);
  221:       flagToModify[i]=SURVEY_HEADER;
  222:     }
  223:   else
  224:     {
  225:       printf("%d. The paper being graded is an Exam or Quiz.\n",++i);
  226:       flagToModify[i]=SURVEY_MODE;
  227:       if(flags->CheckPIN)
  228: 	{
  229: 	  printf("%d. The coded CAPA ID will be checked for validity.\n",++i);
  230: 	  flagToModify[i]=CHECK_PIN;
  231: 	  if(flags->AnonMode)
  232: 	    {
  233: 	      printf("%d. Scorer will run in Anonymous Mode. (search for \n\tthe correct Student Number based on the CAPA ID)\n",++i);
  234: 	      flagToModify[i]=ANON_MODE;
  235: 	      if(flags->QueryAboutPID)
  236: 		printf("%d. Scorer will ask which PID to use if multiple are found.\n",++i);
  237: 	      else
  238: 		printf("%d. Scorer will pick highest score if multiple PIDs found.\n",++i);
  239: 	      flagToModify[i]=QUERY_ABOUT_PID;
  240: 	    }
  241: 	  else
  242: 	    {
  243: 	      printf("%d. Scorer will not run in Anonymous Mode. (Bubbled \n\tstudent number is correct for the CAPA ID.)\n",++i);
  244: 	      flagToModify[i]=ANON_MODE;
  245: 	    }
  246: 	}
  247:       else
  248: 	{
  249: 	  printf("%d. The coded CAPA ID will be ignored.\n",++i);
  250: 	  flagToModify[i]=CHECK_PIN;
  251: 	}
  252:       if(flags->CheckSpaces)
  253: 	{
  254: 	  if (flags->log)
  255: 	    printf("%d. Scorer will log sheets containing blank answers.\n",++i);
  256: 	  else
  257: 	    printf("%d. Scorer will issue a warning and pause when encountering blank answers.\n",++i);
  258: 	}
  259:       else
  260: 	{
  261: 	  printf("%d. Scorer will ignore blank answers.\n",++i);
  262: 	}
  263:       flagToModify[i]=CHECK_SPACES;
  264:       if(flags->CheckMultipleMarks)
  265: 	{
  266: 	  if (flags->log)
  267: 	    printf("%d. Scorer will log answer sheets containing multiple marks.\n",++i);
  268: 	  else
  269: 	    printf("%d. Scorer will issue a warning and pause when encountering multiple marks.\n",++i);
  270: 	}
  271:       else
  272: 	{
  273: 	  printf("%d. Scorer will mark multiple marks wrong.\n",++i);
  274: 	}
  275:       flagToModify[i]=MULTIPLE_MARKS;
  276:       switch(flags->IdFormat)
  277: 	{
  278: 	case ANUMBER_FORMAT:
  279: 	  printf("%d. The StudentId is in A<number> format.\n",++i);
  280: 	  break;
  281: 	case SOC_SEC_FORMAT:
  282: 	  printf("%d. The StudentId is in Social Security format.\n",++i);
  283: 	  break;
  284: 	default:
  285: 	  flags->IdFormat=ANUMBER_FORMAT;
  286: 	  printf("%d. The StudentId is in A<number> format.\n",++i);
  287: 	  break;
  288: 	}
  289:       flagToModify[i]=ID_FORMAT;
  290:     }
  291:   if (flags->Pause)
  292:     printf("%d. The program will pause %.2f seconds between papers.\n",++i,
  293: 	   flags->PauseTime);
  294:   else
  295:     printf("%d. The program will process papers as quickly as possible.\n",
  296: 	   ++i);
  297:   flagToModify[i]=PAUSE_TIME;
  298:   if (flags->log)
  299:     printf("%d. The program will log all errors.\n",++i);
  300:   else
  301:     printf("%d. The program will query user on all errors.\n",++i);
  302:   flagToModify[i]=LOGGING;
  303:   return i;
  304: }
  305: 
  306: int getYesOrNo()
  307: {
  308:   int done=FALSE;
  309:   char buf[MAX_LINE_LENGTH];
  310:   while(!done)
  311:     {
  312:       scanf("%s",buf);
  313:       switch(buf[0])
  314: 	{
  315: 	case 'n':case'N':
  316: 	  return NO;
  317: 	  done=TRUE;
  318: 	  break;
  319: 	case 'y':case'Y':
  320: 	  return YES;
  321: 	  done=TRUE;
  322: 	  break;
  323: 	default:
  324: 	  printf("Please enter y or n.");
  325: 	  done=FALSE;
  326: 	  break;
  327: 	}
  328:     }
  329:   exit(E_GETYESNO);
  330:   return -1;
  331: }
  332:   
  333: void modifyFlag(Flags *flags,int *flagToModify,int i)
  334: {
  335:   int valid=FALSE;
  336:   int done=FALSE;
  337:   char buf[MAX_LINE_LENGTH];
  338:   switch(flagToModify[i])
  339:     {
  340:     case CHECK_PIN:
  341:       printf("Should the student coded CAPA ID be checked for correctness?\n");
  342:       printf("(y or n)");
  343:       flags->CheckPIN=getYesOrNo();
  344:       break;
  345:     case ANON_MODE:
  346:       printf("Should scorer run in Anonymous mode (search for correct \n");
  347:       printf("Student Number based on the CAPA ID)? (y or n)");
  348:       flags->AnonMode=getYesOrNo();
  349:       break;
  350:     case QUERY_ABOUT_PID:
  351:       printf("Should scorer Query you when multiple PIDs match a single PIN.(y or n)\n");
  352:       flags->QueryAboutPID=getYesOrNo();
  353:       break;
  354:     case CHECK_SPACES:
  355:       printf("Should scorer check for blank answers and issue a warning \n");
  356:       printf("when one is encountered? (y or n)");
  357:       flags->CheckSpaces=getYesOrNo();
  358:       break;
  359:     case MULTIPLE_MARKS:
  360:       printf("Should scorer check for multiple marks and issue a warning \n");
  361:       printf("when encountered? (y or n)");
  362:       flags->CheckMultipleMarks=getYesOrNo();
  363:       break;
  364:     case SURVEY_MODE:
  365:       printf("Is this a survey?(y or n)");
  366:       flags->SurveyMode=getYesOrNo();
  367:       break;
  368:     case SURVEY_HEADER:
  369:       printf("Does the form include a Header?(y or n)");
  370:       flags->SurveyHeader=getYesOrNo();
  371:       break;
  372:     case PAUSE_TIME:
  373:       printf("Do you wish for there to be a pause between papers?(y or n)");
  374:       flags->Pause=getYesOrNo();
  375:       if (flags->Pause)
  376: 	{
  377: 	  printf("Please enter the minimum delay between papers in seconds.\n");
  378: 	  valid=FALSE;
  379: 	  while(!valid)
  380: 	    {
  381: 	      scanf("%s",buf);
  382: 	      flags->PauseTime=(float)atof(buf);
  383: 	      if (flags->PauseTime < 0.00001)
  384: 		{
  385: 		  printf("You have entered a rather short time, are you sure you meant %f seconds?",flags->PauseTime);
  386: 		  switch(getYesOrNo())
  387: 		    {
  388: 		    case NO:
  389: 		      printf("Please enter the minimum delay between papers.\n");
  390: 		      break;
  391: 		    case YES:
  392: 		      valid=TRUE;
  393: 		      break;
  394: 		    default:
  395: 		      fprintf(stderr,"getYesOrNo returned a bad result\n");
  396: 		      exit(E_GETYESNO);
  397: 		      break;
  398: 		    }
  399: 		}
  400: 	      else
  401: 		valid=TRUE;
  402: 	    }
  403: 	}
  404:       else
  405: 	flags->PauseTime=0.0;
  406:       break;
  407:     case ID_FORMAT:
  408:       printf("Is the StudentID Format A<number> or Social Security? (a or s)");
  409:       while(!done)
  410: 	{
  411: 	  scanf("%s",buf);
  412: 	  switch(buf[0])
  413: 	    {
  414: 	    case 'a':case'A':
  415: 	      flags->IdFormat=ANUMBER_FORMAT;
  416: 	      done=TRUE;
  417: 	      break;
  418: 	    case 's':case'S':
  419: 	      flags->IdFormat=SOC_SEC_FORMAT;
  420: 	      done=TRUE;
  421: 	      break;
  422: 	    default:
  423: 	      printf("Please enter a or s.");
  424: 	      done=FALSE;
  425: 	      break;
  426: 	    }
  427: 	}
  428:       break;
  429:     case LOGGING:
  430:       printf("Should Scorer log errors?(y or n)");
  431:       flags->log=getYesOrNo();
  432:       break;
  433:     default:
  434:       fprintf(stderr,"Corrupted information in modifyFlag, i=%d\n",i);
  435:       fprintf(stderr,"flagToModify[i]=%d",flagToModify[i]);
  436:       exit(E_MODIFYFLAG);
  437:       break;
  438:     }
  439: }
  440: 
  441: void checkFlagConsistency(Flags *flags)
  442: {
  443:   if(flags->SurveyMode)
  444:     {
  445:       flags->CheckPIN=FALSE;
  446:       flags->AnonMode=FALSE;
  447:       flags->QueryAboutPID=FALSE;
  448:       flags->CheckSpaces=FALSE;
  449:       flags->CheckMultipleMarks=FALSE;
  450:     }
  451:   else
  452:     {
  453:       flags->SurveyHeader=FALSE;
  454:       if(flags->CheckPIN);
  455:       else
  456: 	flags->AnonMode=FALSE;
  457:     }
  458:   if (!flags->AnonMode) flags->QueryAboutPID=FALSE;
  459: }
  460:   
  461: void getFlags(Flags *flags)
  462: {
  463:   int done=FALSE,valid=FALSE,i,flagToModify[MAX_NUM_FLAG];
  464:   char buf[MAX_LINE_LENGTH];
  465:   while(!done)
  466:     {
  467:       i=printFlagMenu(flags,flagToModify);
  468:       printf("Please select which one of the above (1-%d) you wish to \n",i);
  469:       printf("change. Otherwise enter 0 (zero) to continue.\n");
  470:       valid=FALSE;
  471:       while(!valid)
  472: 	{
  473: 	  scanf("%s",buf);
  474: 	  if (isdigit(buf[0]))
  475: 	    {
  476: 	      i=atoi(buf);
  477: 	      valid=TRUE;
  478: 	    }
  479: 	  else
  480: 	    printf("Please enter a number between (0-%d)\n",i);
  481: 	}
  482:       if (i)
  483: 	modifyFlag(flags,flagToModify,i);
  484:       else
  485: 	done=TRUE;
  486:     }
  487:   checkFlagConsistency(flags);
  488: }
  489: 
  490: void printQuestions(Question questions[MAX_QUEST],int numQuestions)
  491: {
  492:   int i;
  493:   for(i=0;i<numQuestions;i++)
  494:     {
  495:       printf("%d. ",i+1);
  496:       switch(questions[i].type)
  497: 	{
  498: 	case ONE_OUT_OF_8:
  499: 	  printf("One out of 8.                                 ");
  500: 	  break;
  501: 	case GLE:
  502: 	  printf("Choose one of >, <, =,                        ");
  503: 	  break;
  504: 	case TF:
  505: 	  printf("True or False.                                ");
  506: 	  break;
  507: 	case ASSIGNED:
  508: 	  printf("Assigned Score.                               ");
  509: 	  break;
  510: 	case N_OUT_OF_M:
  511: 	  printf("Pick N out of M.                              ");
  512: 	  break;
  513: 	case SINGLE_DIGIT:
  514: 	  printf("Single digit answer.                          ");
  515: 	  break;
  516: 	case STRING_MATCH:
  517: 	  printf("Exact string matching.(10 or less bubbles)    ");
  518: 	  break;
  519: 	default:
  520: 	  fprintf(stderr,"\nCorrupt data in Questions struct while inside printQuestions. Dying\n");
  521: 	  exit(E_PRINTQUESTIONS);
  522: 	  break;
  523: 	}
  524:       printf(" %d leafs, Worth: %d points\n",questions[i].leafs,
  525: 	     questions[i].points);
  526:     }  
  527: }
  528: 
  529: int wantToChangeQuestions()
  530: {
  531:   int done=FALSE;
  532:   char buf[MAX_LINE_LENGTH];
  533:   printf("Do you want to change any of the above?(y or n)\n");
  534:   while(!done)
  535:     {
  536:       scanf("%s",buf);
  537:       switch(buf[0])
  538: 	{
  539: 	case 'n':case'N':
  540: 	  return 0;
  541: 	  done=TRUE;
  542: 	  break;
  543: 	case 'y':case 'Y':
  544: 	  return 1;
  545: 	  done=TRUE;
  546: 	  break;
  547: 	default:
  548: 	  printf("Please enter either (y or n).\n");
  549: 	  break;
  550: 	}
  551:     }
  552:   return -1;
  553: }
  554: 
  555: void printQuestionMenu()
  556: {
  557:   printf("For Each Question enter \"%c\" for a one out of 8\n",ONE_OUT_OF_8);
  558:   printf("                        \"%c\" for a GLE type\n",GLE);
  559:   printf("                        \"%c\" for a TF type.\n",TF);
  560:   printf("                        \"%c\" for an assigned score.\n",ASSIGNED);
  561:   printf("                        \"%c\" for an n out of m.\n",N_OUT_OF_M);
  562:   printf("                        \"%c\" for single digit answer.\n",
  563: 	 SINGLE_DIGIT);
  564:   printf("                        \"%c\" for exact string matching (8 or less bubbles)\n",
  565: 	 STRING_MATCH);
  566:   printf("                        \"%c\" to print this menu again\n",
  567: 	 QUESTION_MENU);
  568:   printf("                        \"%c\" to stop entering questions\n",
  569: 	 QUESTION_STOP);
  570: }
  571: 
  572: int getSingleDigit()
  573: {  
  574:   int done=FALSE;
  575:   char buf[MAX_LINE_LENGTH];
  576:   while(!done)
  577:     {
  578:       scanf("%s",buf);
  579:       if (isdigit(buf[0]) && (atoi(buf) >=1) && (atoi(buf) <=9))
  580: 	{
  581: 	  done=TRUE;
  582: 	  return atoi(buf);
  583: 	}
  584:       else
  585: 	printf("Please enter a digit between 1 and 9\n");
  586:     }
  587:   return 0;
  588: }
  589: 
  590: int getNewQuestion(Question questions[MAX_QUEST],int numQuestions)
  591: {
  592:   int done=FALSE;
  593:   char buf[MAX_LINE_LENGTH];
  594:   printf("Question#%2d: (enter %c to see menu): ",numQuestions+1,QUESTION_MENU);
  595:   while(!done)
  596:     {
  597:       scanf("%s",buf);
  598:       questions[numQuestions].leafs=1;
  599:       switch(buf[0])
  600: 	{
  601: 	case GLE:
  602: 	case TF:
  603: 	  printf("How many parts to the problem?");
  604: 	  if (!(questions[numQuestions].leafs=getSingleDigit())) 
  605: 	    {
  606: 	      fprintf(stderr,"Weird result from getSingleDigit\n");
  607: 	      exit(E_SINGLEDIGIT);
  608: 	    }
  609: 	case ONE_OUT_OF_8:
  610: 	case ASSIGNED:
  611: 	case SINGLE_DIGIT:
  612: 	case STRING_MATCH:
  613: 	  printf("How many points are possible?");
  614: 	  done=TRUE;
  615: 	  break;
  616: 	case N_OUT_OF_M:
  617: 	  printf("What is m in the problem?");
  618: 	  if (!(questions[numQuestions].leafs=getSingleDigit())) 
  619: 	    {
  620: 	      fprintf(stderr,"Weird result from getSingleDigit\n");
  621: 	      exit(E_SINGLEDIGIT);
  622: 	    }
  623: 	  printf("How many points are possible?");
  624: 	  done=TRUE;
  625: 	  break;
  626: 	case QUESTION_MENU:
  627: 	  printQuestionMenu();
  628: 	  printf("Question#%2d: ",numQuestions+1);
  629: 	  break;
  630: 	case QUESTION_STOP:
  631: 	  return 0;
  632: 	  break;
  633: 	default:
  634: 	  printf("Please enter one of %c,%c,%c,%c,%c,%c,%c,%c,%c.\n",
  635: 		 ONE_OUT_OF_8,GLE,TF,ASSIGNED,N_OUT_OF_M,SINGLE_DIGIT,
  636: 		 STRING_MATCH,QUESTION_MENU,QUESTION_STOP);
  637: 	  printf("Question#%2d: ",numQuestions+1);
  638: 	  break;
  639: 	}
  640:     }
  641:   questions[numQuestions].type=buf[0];
  642:   if (!(questions[numQuestions].points=getSingleDigit())) 
  643:     {
  644:       fprintf(stderr,"Weird result from getSingleDigit\n");
  645:       exit(E_SINGLEDIGIT);
  646:     }
  647:   return 1;
  648: }
  649: 
  650: void printModifyQuestionMenu()
  651: {
  652:   printf("(a)dd a question\n");
  653:   printf("(c)hange a question\n");
  654:   printf("(d)elete a question\n");
  655:   printf("(f)inished changing\n");
  656: }
  657: 
  658: void addQuestion(Question questions[MAX_QUEST],int *numQuestions)
  659: {
  660:   printQuestionMenu();
  661:   if (getNewQuestion(questions,*numQuestions))
  662:     (*numQuestions)=(*numQuestions)+1;
  663: }
  664: 
  665: void changeQuestion(Question questions[MAX_QUEST],int numQuestions)
  666: {
  667:   int done=FALSE;
  668:   char buf[MAX_LINE_LENGTH];
  669:   printf("Which question do you wish to change?(1-%d) ",numQuestions);
  670:   printf("Or 0 for none\n");
  671:   while(!done)
  672:     {
  673:       scanf("%s",buf);
  674:       if(isdigit(buf[0]) && (atoi(buf) >= 0) && (atoi(buf) <= numQuestions))
  675: 	  done=TRUE;
  676:       else
  677: 	  printf("Please enter a number between 0 and %d.\n",numQuestions);
  678:     }
  679:   if (atoi(buf) !=0)
  680:     {
  681:       printQuestionMenu();
  682:       getNewQuestion(questions,atoi(buf)-1);
  683:     }
  684: }
  685: 
  686: void deleteQuestion(Question questions[MAX_QUEST],int *numQuestions)
  687: {
  688:   int done=FALSE,i;
  689:   char buf[MAX_LINE_LENGTH];
  690:   printf("Which question do you wish to delete?(1-%d) ",*numQuestions);
  691:   printf("Or 0 for none\n");
  692:   while(!done)
  693:     {
  694:       scanf("%s",buf);
  695:       if(isdigit(buf[0]) && (atoi(buf) >= 0) && (atoi(buf) <= (*numQuestions)))
  696: 	done=TRUE;
  697:       else
  698: 	printf("Please enter a number between 0 and %d.\n",*numQuestions);
  699:     }
  700:   if (atoi(buf) !=0)
  701:     {
  702:       for(i=atoi(buf)-1;i<(*numQuestions)-1;i++)
  703: 	{
  704: 	  questions[i].type=questions[i+1].type;
  705: 	  questions[i].points=questions[i+1].points;
  706: 	  questions[i].leafs=questions[i+1].leafs;
  707: 	}
  708:       (*numQuestions)=(*numQuestions)-1;
  709:     }
  710: }
  711: 
  712: void modifyQuestions(Question questions[MAX_QUEST],int *numQuestions)
  713: {
  714:   int done=FALSE;
  715:   char buf[MAX_LINE_LENGTH];
  716:   while(!done)
  717:     {
  718:       printQuestions(questions,*numQuestions);
  719:       printModifyQuestionMenu();
  720:       scanf("%s",buf);
  721:       switch(buf[0])
  722: 	{
  723: 	case 'a':
  724: 	  addQuestion(questions,numQuestions);
  725: 	  break;
  726: 	case 'c':
  727: 	  changeQuestion(questions,*numQuestions);
  728: 	  break;
  729: 	case 'd':
  730: 	  deleteQuestion(questions,numQuestions);
  731: 	  break;
  732: 	case 'f':
  733: 	  done=TRUE;
  734: 	  break;
  735: 	default:
  736: 	  printf("Please enter one of a, c, d, f\n");
  737: 	  break;
  738: 	}
  739:     }
  740: }
  741: 
  742: int getNumSurveyQuest()
  743: {
  744:   int numQuestions=0,done=FALSE;
  745:   char buf[MAX_LINE_LENGTH];
  746: 
  747:   printf("Please enter the number of questions on the Survey.\n");
  748:   while(!done)
  749:     {
  750:       scanf("%s",buf);
  751:       if(isdigit(buf[0]))
  752: 	{
  753: 	  numQuestions=atoi(buf);
  754: 	  done=TRUE;
  755: 	}
  756:       else
  757: 	{
  758: 	  printf("Please enter a number.\n");
  759: 	}
  760:     }
  761:   return numQuestions;
  762: }
  763: 
  764: void getQuestionInfo(Question questions[MAX_QUEST],Flags *flags)
  765: {
  766:   int done=FALSE,i;
  767:   if (flags->SurveyMode)
  768:     {
  769:       flags->NumQuestions=getNumSurveyQuest();
  770:       for (i=0;i<flags->NumQuestions;i++)
  771: 	{
  772: 	  questions[i].type=ASSIGNED;
  773: 	  questions[i].points=9;
  774: 	  questions[i].leafs=1;
  775: 	}
  776:     }
  777:   else
  778:     {
  779:       if (flags->NumQuestions!=0)
  780: 	{
  781: 	  printQuestions(questions,flags->NumQuestions);
  782: 	  if (!wantToChangeQuestions())
  783: 	    return;
  784: 	}
  785:       else
  786: 	{
  787: 	  printQuestionMenu();
  788: 	  while(!done)
  789: 	    if (getNewQuestion(questions,flags->NumQuestions))
  790: 	      flags->NumQuestions++;
  791: 	    else
  792: 	      done=TRUE;
  793: 	}
  794:       modifyQuestions(questions,&(flags->NumQuestions));
  795:     }
  796: } 
  797: 
  798: void getInfo(FILE ** outputFile,FILE **scantron,
  799: 	     Question questions[MAX_QUEST],Flags *flags)
  800: {
  801:   char filename[MAX_LINE_LENGTH];
  802: 
  803:   getClassInfo(flags,scantron);
  804:   sprintf(filename,"records/scorer.output.%d",flags->SetId);
  805:   switch(openOutputFile(filename,outputFile))
  806:     {
  807:     case SCO_FATALERROR:
  808:       exit (E_OPENOUTPUT);
  809:       break;
  810:     case SCO_NEW:
  811:       initValues(questions,flags);
  812:       break;
  813:     case SCO_EXIST:
  814:       getPreviousValues(*outputFile,questions,flags);
  815:       break;
  816:     default:
  817:       fprintf(stderr,"openOutputFile returned an invalid code. Dying\n");
  818:       exit(E_OPENOUTPUTRETURN);
  819:       break;
  820:     }
  821:   getFlags(flags);
  822:   getQuestionInfo(questions,flags);
  823: }
  824: 
  825: void saveInfo(FILE *outputFile,Question questions[MAX_QUEST],Flags *flags)
  826: {
  827:   char configLine[CONFIG_LINE_LENGTH+2],buf[MAX_LINE_LENGTH],
  828:     buf2[MAX_LINE_LENGTH],logname[MAX_LINE_LENGTH];
  829:   int i;
  830:   for(i=0;i<flags->NumQuestions;i++)
  831:     {
  832:       buf[3*i]=questions[i].type;
  833:       buf[3*i+1]=((char)questions[i].points)+'0';
  834:       buf[3*i+2]=((char)questions[i].leafs)+'0';
  835:     }
  836:   buf[3*i]='\0';
  837:   buf2[0]=((char)flags->CheckPIN)+'0';
  838:   buf2[1]=((char)flags->AnonMode)+'0';
  839:   buf2[2]=((char)flags->CheckSpaces)+'0';
  840:   buf2[3]=((char)flags->SurveyMode)+'0';
  841:   buf2[4]=((char)flags->SurveyHeader)+'0';
  842:   buf2[5]=((char)flags->Pause)+'0';
  843:   buf2[6]=((char)flags->IdFormat)+'0';
  844:   buf2[7]=((char)flags->CheckMultipleMarks)+'0';
  845:   buf2[8]=((char)flags->QueryAboutPID)+'0';
  846:   buf2[9]=((char)flags->log)+'0';
  847:   buf2[10]='\0';
  848:   sprintf(configLine,"%s %d %d %s %f %s",flags->Class,flags->SetId,
  849: 	  flags->NumQuestions,buf2,flags->PauseTime,buf);
  850:   for(i=strlen(configLine);i<CONFIG_LINE_LENGTH;i++)
  851:     configLine[i]=' ';
  852:   configLine[CONFIG_LINE_LENGTH]='\n';
  853:   configLine[CONFIG_LINE_LENGTH+1]='\0';
  854:   rewind(outputFile);
  855:   fprintf(outputFile,configLine);
  856: 
  857:   if(flags->log)
  858:     {
  859:       sprintf(logname,"records/scorer.log.%d",flags->SetId);
  860:       
  861:       flags->logFile=fopen(logname,"w");
  862:       if (flags->logFile == NULL)
  863: 	{
  864: 	  fprintf(stderr,"Unable to open the logFile %s\n",logname);
  865: 	  exit(E_LOGERROR);
  866: 	}
  867:     }
  868: }
  869: 
  870: void logMultipleAnon(PIDPINlist PIDandPINlist[MAX_SECTION_SIZE],
  871: 		     int matches[MAX_PID_MATCHES],Student* student,
  872: 		     Flags* flags,int maxTotal,int total[MAX_PID_MATCHES])
  873: {
  874:   int i;
  875: 
  876:   fprintf(flags->logFile,"#Multiple matching PINs for PID %s :",
  877: 	  student->answerPID);
  878:   for(i=0;i<MAX_PID_MATCHES;i++)
  879:     {
  880:       if (matches[i]==-1) break;
  881:       fprintf(flags->logFile," %s score: %d,",
  882: 	      PIDandPINlist[matches[i]].PID,total[i]);
  883:     }
  884:   
  885:   flags->loggedErrors++;
  886:   fprintf(flags->logFile," picked: %s, serialNumber: %s\n",
  887: 	  PIDandPINlist[matches[maxTotal]].PID,student->serialNumber);
  888:   fprintf(flags->logFile,"%s",student->origString);  
  889: }
  890: 
  891: void logError(Student *student,Flags *flags,int errorCode)
  892: {
  893:   flags->loggedErrors++;
  894:   student->error=1;
  895:   switch(errorCode)
  896:     {
  897:     case LOG_NOPINFOUND:
  898:       fprintf(flags->logFile,"#In Anonymous Mode no Student ID could be found for the PIN encoded, PIN=%s (not graded)",student->PIN);
  899:       break;
  900:     case LOG_PINWRONG:
  901:       if (flags->AnonMode)
  902: 	fprintf(flags->logFile,"#The coded PIN had errors (not graded)");
  903:       else
  904: 	fprintf(flags->logFile,"#The coded PIN had errors, assumed zero for bad responses");
  905:       break;
  906:     case LOG_STUDENTNOTEXIST:
  907:       fprintf(flags->logFile,"#The Student ID %s was not found in the classl file(not graded)",student->answerPID);
  908:       break;
  909:     case LOG_PINNOTMATCH:
  910:       fprintf(flags->logFile,"#The student coded an incorrect PIN(%s) for the specified PID(%s) using the classl PIN, %04d",student->PIN,student->answerPID,student->classlPIN); 
  911:       break;
  912:     case LOG_BADPID:
  913:       fprintf(flags->logFile,"#The coded Student ID(%s) was not found in the classl file (not graded)",student->answerPID);
  914:       break;
  915:     case LOG_BADPIN:
  916:       fprintf(flags->logFile,"#The coded PIN (%s) was incorrect(notGraded)",student->PIN);
  917:       break;
  918:     case LOG_SPACES:
  919:       fprintf(flags->logFile,"#The student had blank answers");
  920:       break;
  921:     case LOG_MULTIPLEMARKS:
  922:       fprintf(flags->logFile,"#The student had multiple marks on single mark questions");
  923:       break;
  924:     default:
  925:       fprintf(flags->logFile,"#And unknown error %d occured with this student",errorCode);
  926:       break;
  927:     }
  928:   fprintf(flags->logFile," serialNumber: %s.\n",student->serialNumber);
  929: }
  930: 
  931: /* stolen from allpin.c and modified by Guy Albertelli*/
  932: int buildPIDandPINlist(int setId, PIDPINlist PIDandPINlist[MAX_SECTION_SIZE] )
  933: {
  934:   int i=0,numStudents;
  935:   T_student *curStudent,*headStudent;
  936: 
  937:   printf("Building lists of CapaIDs and PIDs\n");
  938:   numStudents=capa_get_section(&headStudent, 0);
  939:   curStudent=headStudent;
  940:   for(i=0;curStudent;curStudent=curStudent->s_next,i++)
  941:     {
  942:       strcpy(PIDandPINlist[i].PID,curStudent->s_sn);
  943:       PIDandPINlist[i].PIN=capa_PIN(curStudent->s_sn,setId,0);
  944:     }
  945:   free_students(headStudent);
  946:   printf("\nDone\n");
  947:   return numStudents;
  948: }
  949: 
  950: int getForm(Student **newStudent,FILE *scantron,
  951: 		  Question questions[MAX_QUEST],Flags *flags)
  952: {
  953:   char buffer[MAX_LINE_LENGTH];
  954:   char *eof;
  955:   int i=0,h=0,j=0,q=0,space=0,found,stepsize,pin,result=0,multiplemarks=0;
  956:   int done=FALSE,pinWrong=FALSE;
  957:   static int formNumber;
  958:   char * array;
  959: 
  960:   if (flags->Pause)
  961:       usleep(flags->PauseTime*1000000);
  962:   while(!done)
  963:     {
  964:       eof=fgets(buffer,MAX_LINE_LENGTH,scantron);
  965:       if (eof==NULL) return GF_EOF;
  966:       if (buffer[0]!='#') done=TRUE;
  967:     }
  968:   flags->linesRead++;
  969:   if (!flags->log)
  970:     printf("The Next line is:\n%s\n",buffer);
  971: 
  972: #ifdef DEBUG
  973:   printf("Interpreting the line.\n");
  974: #endif
  975: 
  976:   *newStudent=(Student *)malloc(sizeof(Student));
  977:   if (flags->SurveyMode) 
  978:     /* assign a unique student number since there isn't one on the sheet*/
  979:     switch(flags->IdFormat)
  980:       {
  981:       case ANUMBER_FORMAT:
  982: 	sprintf((*newStudent)->answerPID,"a%08d",formNumber++);
  983: 	break;
  984:       case SOC_SEC_FORMAT:
  985: 	sprintf((*newStudent)->answerPID,"%09d",formNumber++);
  986: 	break;
  987:       default:
  988: 	fprintf(stderr,"Invalid IdFormat data in interpretForm,%d\n",
  989: 		flags->IdFormat);
  990: 	exit(E_INVALIDIDFORMAT);
  991: 	break;
  992:       }
  993:   else
  994:     strncpy((*newStudent)->answerPID,&buffer[56],9);
  995:   (*newStudent)->answerPID[9]='\0';
  996:   strncpy((*newStudent)->Name,&buffer[40],16);
  997:   (*newStudent)->Name[16]='\0';
  998:   strncpy((*newStudent)->serialNumber,&buffer[3],6);
  999:   (*newStudent)->serialNumber[6]='\0';
 1000:   strncpy((*newStudent)->origString,buffer,SCAN_INPUT_LENGTH);
 1001:   (*newStudent)->origString[SCAN_INPUT_LENGTH]='\0';
 1002:   (*newStudent)->error=0;
 1003:   /* i is the current position in buffer and h is the current question*/
 1004:   for(i=0;i<flags->NumQuestions;i++)
 1005:     {
 1006:       array=LETTER;
 1007:       stepsize=2;
 1008:       switch(questions[i].type)
 1009: 	{
 1010: 	case ASSIGNED:
 1011: 	case SINGLE_DIGIT:
 1012: 	  /*the first 5 are special for Anon mode, only first 4 for 
 1013: 	   *otherwise
 1014: 	   */
 1015: 	  if (flags->AnonMode) 
 1016: 	    if (i > 4)
 1017: 	      array=NUMBER;
 1018: 	  else
 1019: 	    if (i > 3)
 1020: 	      array=NUMBER;
 1021: 	case ONE_OUT_OF_8:
 1022: 	  found=0;
 1023: 	  for(j=(i*10)+76;j<((i+1)*10)+76;j++)
 1024: 	    {
 1025: 	      if (buffer[j]=='1') 
 1026: 		{
 1027: 		  h=j;
 1028: 		  found++;
 1029: 		}
 1030: 	    }
 1031: 	  if (found > 1)
 1032: 	    {
 1033: 	      (*newStudent)->Answers[i][0]=' ';
 1034: 	      multiplemarks++;
 1035: 	    }
 1036: 	  if (found < 1)
 1037: 	    {
 1038: 	      (*newStudent)->Answers[i][0]=' ';
 1039: 	      space++;
 1040: 	    }
 1041: 	  if (found == 1)
 1042: 	    (*newStudent)->Answers[i][0]=array[h-(i*10+76)];
 1043: 	  (*newStudent)->Answers[i][1]='\0';
 1044: 	  break;
 1045: 	case GLE:
 1046: 	  stepsize=3;
 1047: 	case TF:
 1048: 	  for(j=0; j<questions[i].leafs; j++)
 1049: 	    {
 1050: 	      found=0;
 1051: 	      for(h = (i*10+76)+j*stepsize; h<(i*10+76)+(j+1)*stepsize; h++)
 1052: 		{
 1053: 		  if (buffer[h]=='1')
 1054: 		    {
 1055: 		      q=h;
 1056: 		      found++;
 1057: 		    }
 1058: 		  if (found > 1)
 1059: 		    {
 1060: 		      (*newStudent)->Answers[i][j]=' ';
 1061: 		      multiplemarks++;
 1062: 		    }
 1063: 		  if (found < 1)
 1064: 		    {
 1065: 		      (*newStudent)->Answers[i][j]=' ';
 1066: 		      space++;
 1067: 		    }
 1068: 		  if (found == 1)
 1069: 		    (*newStudent)->Answers[i][j]=array[q-(i*10+76)];
 1070: 		}
 1071: 	    }
 1072: 	  (*newStudent)->Answers[i][questions[i].leafs]='\0';
 1073: 	  break;
 1074: 	case N_OUT_OF_M:
 1075: 	case STRING_MATCH:
 1076: 	  found=0;
 1077: 	  for(j=(i*10)+76;j<((i+1)*10)+76;j++)
 1078: 	    {
 1079: 	      if (buffer[j]=='1')
 1080: 		{
 1081: 		  (*newStudent)->Answers[i][found]=array[j-(i*10+76)];
 1082: 		  found++;
 1083: 		}
 1084: 	    }
 1085: 	  if (found==0) space++;
 1086: 	  (*newStudent)->Answers[i][found]='\0';
 1087: 	  break;
 1088: 	default:
 1089: 	  fprintf(stderr,"Invalid question type %c for question %d in Interpret form.\n Dying\n",questions[h].type,h);
 1090: 	  exit(E_INTREPRETFORM);
 1091: 	  break;
 1092: 	}
 1093:     }
 1094:   pin=0;
 1095:   for(i=0;i<4;i++)
 1096:     {
 1097:       pin*=10;
 1098:       switch((*newStudent)->Answers[i][0])
 1099: 	{
 1100: 	case 'A': pin+=1;break;
 1101: 	case 'B': pin+=2;break;
 1102: 	case 'C': pin+=3;break;
 1103: 	case 'D': pin+=4;break;
 1104: 	case 'E': pin+=5;break;
 1105: 	case 'F': pin+=6;break;
 1106: 	case 'G': pin+=7;break;
 1107: 	case 'H': pin+=8;break;
 1108: 	case 'I': pin+=9;break;
 1109: 	case 'J': pin+=0;break;
 1110: 	case ' ':
 1111: 	default: 
 1112: 	  if (!flags->log)
 1113: 	    fprintf(stderr,"Garbage answer '%c' for PIN question %d",
 1114: 		    (*newStudent)->Answers[i][0],i);
 1115: 	  result|=GF_PINWRONG;
 1116: 	  pinWrong=TRUE;
 1117: 	  pin+=0;break;
 1118: 	}
 1119:     }
 1120:   if (pinWrong && flags->log)
 1121:     logError((*newStudent),flags,LOG_PINWRONG);
 1122:   sprintf((*newStudent)->PIN,"%04d",pin);
 1123:   if (space!=0) result|=GF_SPACES;
 1124:   if (multiplemarks!=0) result|=GF_MULTIPLEMARKS;
 1125:   return result;
 1126: }
 1127: 
 1128: int gradeQuestion(Question questions[MAX_QUEST],int questionIndex,
 1129: 		  Problem_t *problem,Student *student,Flags* flags)
 1130: {
 1131:   int numRight=0,leafs;
 1132:   char one=1,zero=0;
 1133:   char *ansOn[20],*stuOn[20];
 1134:   int i,j;
 1135:   int sortArray[256]; 
 1136:   char newAnswer[MAX_LINE_LENGTH],*oldAnswer;
 1137: 
 1138:   switch(questions[questionIndex].type)
 1139:     {
 1140:     case ONE_OUT_OF_8:
 1141:     case GLE:
 1142:     case TF:
 1143:     case SINGLE_DIGIT:
 1144:       if (!flags->log)
 1145: 	printf("The correct answer:%10s  The student's answer:%10s, \t",
 1146: 	       problem->answer,student->Answers[questionIndex]);
 1147:       for(leafs=0;problem->answer[leafs]!='\0';leafs++)
 1148: 	if (problem->answer[leafs]==student->Answers[questionIndex][leafs])
 1149: 	  numRight++;
 1150:       if (!flags->log)
 1151: 	printf("%d right\n",numRight);
 1152:       break;
 1153:     case ASSIGNED:
 1154:       if (!flags->log)
 1155: 	printf("The student got a %s out of %d\n",
 1156: 	       student->Answers[questionIndex],
 1157: 	       questions[questionIndex].points);
 1158:       if (isspace(student->Answers[questionIndex][0]))
 1159: 	numRight=0;
 1160:       else
 1161: 	numRight=(int)(student->Answers[questionIndex][0]-'0');
 1162:       break;
 1163:     case N_OUT_OF_M:
 1164:       if (!flags->log)
 1165: 	printf("The correct answer:%10s  The student's answer:%10s, \t",
 1166: 	       problem->answer,student->Answers[questionIndex]);
 1167:       if (problem->ans_type == ANSWER_IS_CHOICE) {
 1168: 	for(i=0;i<255;i++) sortArray[i]=0;
 1169: 	for(i=0;i< strlen(problem->answer);i++)
 1170: 	  sortArray[(int)problem->answer[i]]=1;
 1171: 	for(i=0,j=0;i<255;i++) {
 1172: 	  if (sortArray[i]) {
 1173: 	    newAnswer[j]=i;
 1174: 	    j++;
 1175: 	  }
 1176: 	}
 1177: 	newAnswer[j]='\0';
 1178: 	if (!flags->log) 
 1179: 	  printf("\nThe sorted correct answer:%10s\t\t\t",newAnswer);
 1180: 	oldAnswer=problem->answer;
 1181: 	problem->answer=newAnswer;
 1182:       }
 1183:       for(leafs=0;questions[questionIndex].leafs>leafs;leafs++)
 1184: 	{
 1185: 	  ansOn[leafs]=strchr(problem->answer,('A'+(char)leafs));
 1186: 	}
 1187:       for(leafs=0;questions[questionIndex].leafs>leafs;leafs++)
 1188: 	{
 1189: 	  if (ansOn[leafs] != NULL ) 
 1190: 	    ansOn[leafs]=&one; 
 1191: 	  else
 1192: 	    ansOn[leafs]=&zero;
 1193: 	}
 1194:       for(leafs=0;questions[questionIndex].leafs>leafs;leafs++)
 1195: 	{
 1196: 	  stuOn[leafs]=strchr(student->Answers[questionIndex],
 1197: 			      ('A'+(char)leafs));
 1198: 	}
 1199:       for(leafs=0;questions[questionIndex].leafs>leafs;leafs++)
 1200: 	{
 1201: 	  if (stuOn[leafs] != NULL)
 1202: 	    stuOn[leafs]=&one; 
 1203: 	  else 
 1204: 	    stuOn[leafs]=&zero;
 1205: 	}
 1206:       for(leafs=0;questions[questionIndex].leafs>leafs;leafs++)
 1207: 	if (ansOn[leafs] == stuOn[leafs]) 
 1208: 	  numRight++;
 1209:       if (!flags->log)
 1210: 	printf("%d right\n",numRight);
 1211:       if (problem->ans_type == ANSWER_IS_CHOICE) problem->answer=oldAnswer;
 1212:       break;
 1213:     case STRING_MATCH:
 1214:       if (!flags->log)
 1215: 	printf("The correct answer:%10s  The student's answer:%10s, ",
 1216: 	       problem->answer,student->Answers[questionIndex]);
 1217:       if (problem->ans_type == ANSWER_IS_CHOICE) {
 1218: 	for(i=0;i<255;i++) sortArray[i]=0;
 1219: 	for(i=0;i< strlen(problem->answer);i++)
 1220: 	  sortArray[(int)problem->answer[i]]=1;
 1221: 	for(i=0,j=0;i<255;i++) {
 1222: 	  if (sortArray[i]) {
 1223: 	    newAnswer[j]=i;
 1224: 	    j++;
 1225: 	  }
 1226: 	}
 1227: 	newAnswer[j]='\0';
 1228: 	if (!flags->log) 
 1229: 	  printf("\nThe sorted correct answer:%10s\t\t\t",newAnswer);
 1230: 	oldAnswer=problem->answer;
 1231: 	problem->answer=newAnswer;
 1232:       }
 1233:       if (!(strcasecmp(problem->answer,student->Answers[questionIndex]))) {
 1234: 	if (!flags->log) printf("Answer is correct\n");
 1235: 	numRight=questions[questionIndex].points;
 1236:       } else {
 1237: 	if (!flags->log) printf("Answer is wrong\n");
 1238: 	numRight=0;
 1239:       }
 1240:       if (problem->ans_type == ANSWER_IS_CHOICE) problem->answer=oldAnswer;
 1241:       break;
 1242:     default:
 1243:       fprintf(stderr,"Unknown question type while grading, %c.\nDying.\n",
 1244: 	      questions[questionIndex].type);
 1245:       exit(E_UNKNOWN_QTYPE);
 1246:       break;
 1247:     }
 1248:   return numRight;
 1249: }
 1250: 
 1251: int surveyQuestion(Question questions[MAX_QUEST],int questionIndex,
 1252: 		  Problem_t *problem,Student *student,Flags* flags)
 1253: {
 1254:   int numRight=0;
 1255: 
 1256:   switch(questions[questionIndex].type)
 1257:     {
 1258:     case ASSIGNED:
 1259:       if (!flags->log)
 1260: 	printf("The student responded with %s\n",student->Answers[questionIndex]);
 1261:       if (isspace(student->Answers[questionIndex][0]))
 1262: 	numRight=0;
 1263:       else
 1264: 	numRight=(int)(student->Answers[questionIndex][0]-'0');
 1265:       break;
 1266:     case ONE_OUT_OF_8:
 1267:     case GLE:
 1268:     case TF:
 1269:     case SINGLE_DIGIT:
 1270:     case N_OUT_OF_M:
 1271:     case STRING_MATCH:
 1272:     default:
 1273:       fprintf(stderr,"Illegal question type while in SurveyMode, %c.\nDying.\n",
 1274: 	      questions[questionIndex].type);
 1275:       exit(E_UNKNOWN_QTYPE);
 1276:       break;
 1277:     }
 1278:   return numRight;
 1279: }
 1280: 
 1281: long getScorerEntry(FILE *outputFile,char *PID)
 1282: {
 1283:   char oneline[MAX_LINE_LENGTH],fmtbuf[MAX_LINE_LENGTH],
 1284:     studentNumber[MAX_STUDENT_NUMBER];
 1285:   int done=FALSE,found=FALSE,offset=0,len=0,next_r=0;
 1286: 
 1287:   rewind(outputFile);
 1288:   sprintf(fmtbuf,"%%%dc",MAX_STUDENT_NUMBER);
 1289:   while(!done)
 1290:     {
 1291:       done=!fgets(oneline,MAX_LINE_LENGTH-1,outputFile);
 1292:       len=strlen(oneline);
 1293:       if (!done)
 1294: 	{
 1295: 	  sscanf(oneline,fmtbuf,studentNumber);
 1296: 	  if (strncasecmp(studentNumber,PID,MAX_STUDENT_NUMBER)==0)
 1297: 	    {
 1298: 	      next_r=ftell(outputFile);
 1299: 	      offset = next_r-len;
 1300: 	      done=TRUE;
 1301: 	      found=TRUE;
 1302: 	    }
 1303: 	}
 1304:       else
 1305: 	{
 1306: 	  fseek(outputFile,0L,SEEK_END);
 1307: 	  offset=ftell(outputFile);
 1308: 	  fseek(outputFile,-1L,SEEK_END);
 1309: 	  while (fgetc(outputFile)=='\n')
 1310: 	    {
 1311: 	      offset--;
 1312: 	      fseek(outputFile,offset,SEEK_SET);
 1313: 	    }
 1314: 	  offset= offset+2;
 1315: 	  found=FALSE;
 1316: 	  done=TRUE;
 1317: 	}
 1318:     }
 1319:   if(!found) offset=-offset;
 1320:   return offset;
 1321: }
 1322: 	  
 1323: void setScorerEntry(FILE * outputFile,char* answerPID,char* name,
 1324: 		    char* answers,int score, int section, 
 1325: 		    char* answerstring,char* questionPID, 
 1326: 		    char* serialNumber,int offset)
 1327: {
 1328:   int len=0;
 1329:   char buf[MAX_LINE_LENGTH];
 1330:   
 1331:   rewind(outputFile);
 1332:   sprintf(buf,"%s %-30s %s %3d %2d %s %s %s\n",answerPID,name,answers,
 1333: 	  score,section,answerstring,questionPID,serialNumber);
 1334:   len=strlen(buf);
 1335:   fseek(outputFile,abs(offset),0);
 1336:   if(!fwrite(buf,len,1,outputFile))
 1337:     fprintf(stderr,"Failed write.\n");
 1338: }
 1339: 
 1340: void saveForm(Student *student,FILE *outputFile,
 1341: 	       Question questions[MAX_QUEST],Flags *flags)
 1342: {
 1343:   int result,capaQuestions,questionIndex,numRight,total=0;
 1344:   int offset;
 1345:   Problem_t *curProblem,*headProblem;
 1346:   char answerstring[MAX_LINE_LENGTH],grade[MAX_LINE_LENGTH];
 1347:   char buf[MAX_LINE_LENGTH];
 1348:   T_student capaStudent;
 1349: 
 1350:   if (!flags->SurveyMode)
 1351:     {
 1352:       switch(capa_get_student(student->answerPID, &capaStudent))
 1353: 	{
 1354: 	case 1: break;
 1355: 	case 0:
 1356: 	  if (flags->log)
 1357: 	    logError(student,flags,LOG_STUDENTNOTEXIST);
 1358: 	  else
 1359: 	    {
 1360: 	      fprintf(stderr,"Student %s was not found.\n",student->answerPID);
 1361: 	      printf("Type start to continue");
 1362: 	      scanf("%s",buf);
 1363: 	    }
 1364: 	  return;
 1365: 	  break;
 1366: 	case -1:
 1367: 	  fprintf(stderr,"Unable to find the classl file while grading\n");
 1368: 	  exit(E_CAPA_GET_STUDENT); break;
 1369: 	default:
 1370: 	  fprintf(stderr,"Unknow error from capa_get_student while grading\n");
 1371: 	  exit(E_CAPA_GET_STUDENT); break;
 1372: 	}	
 1373:       result=capa_parse(flags->SetId,&headProblem,student->questionPID,
 1374: 			&capaQuestions);
 1375:       curProblem=headProblem;
 1376:       if (result==0 || result == -1)
 1377: 	{
 1378: 	  fprintf(stderr,"The Parse failed: %d\nDying\n",result);
 1379: 	  exit(E_PARSER);
 1380: 	}
 1381:       else if (result != flags->NumQuestions)
 1382: 	{
 1383: 	  fprintf(stderr,"The parser found %d questions, there were supposed to be %d questions.\nDying\n",result,flags->NumQuestions);
 1384: 	  exit(E_PARSER_DIFFERENT);
 1385: 	}
 1386:       for(questionIndex=0;questionIndex<flags->NumQuestions;questionIndex++)
 1387: 	{
 1388: 	  numRight=gradeQuestion(questions,questionIndex,curProblem,
 1389: 				 student,flags);
 1390: 	  total+=numRight;
 1391: 	  grade[questionIndex]='0'+(char)numRight;
 1392: 	  curProblem=curProblem->next;
 1393: 	}
 1394:       grade[questionIndex]='\0';
 1395:       printf("Total right for student %s is %d\n\n",capaStudent.s_nm,total);
 1396:       free_problems(headProblem);
 1397:     }
 1398:   else
 1399:     {
 1400:       strcpy(capaStudent.s_nm,"Unknown                       ");
 1401:       capaStudent.s_sec=0;
 1402:       headProblem=curProblem=NULL;      
 1403:       for(questionIndex=0;questionIndex<flags->NumQuestions;questionIndex++)
 1404: 	{
 1405: 	  numRight=surveyQuestion(questions,questionIndex,curProblem,
 1406: 				  student,flags);
 1407: 	  total+=numRight;
 1408: 	  grade[questionIndex]='0'+(char)numRight;
 1409: 	} 
 1410:       grade[questionIndex]='\0';
 1411:     }
 1412:   
 1413:   answerstring[0]='\0';
 1414: 
 1415:   for(questionIndex=0;questionIndex<flags->NumQuestions;questionIndex++)
 1416:     strcat(answerstring,student->Answers[questionIndex]);
 1417: 
 1418:   offset=getScorerEntry(outputFile,student->answerPID);  
 1419:      
 1420:   setScorerEntry(outputFile,student->answerPID,capaStudent.s_nm,grade,
 1421: 		  total,capaStudent.s_sec,answerstring,student->questionPID,
 1422: 		  student->serialNumber,offset);
 1423: }
 1424: 
 1425: int getScore(Student *student,Question questions[MAX_QUEST],Flags *flags,
 1426: 	     char* grade,int gradingMethod)
 1427: {
 1428:   int score=0,numRight=0,tempScore,i,leafs,points,unit;
 1429:   for(i=0;i<flags->NumQuestions;i++)
 1430:     {
 1431:       switch(questions[i].type)
 1432: 	{
 1433: 	case ONE_OUT_OF_8:
 1434: 	case SINGLE_DIGIT:
 1435: 	  numRight= (int) (grade[i]-'0');
 1436: 	  score+=numRight*questions[i].points;
 1437: 	  break;
 1438: 	case STRING_MATCH:
 1439: 	  /*for STRING_MATCH the score is stroed as the NumRight*/
 1440: 	  numRight= (int) (grade[i]-'0');
 1441: 	  score+=numRight;
 1442: 	  break;
 1443: 	case GLE:
 1444: 	case TF:
 1445: 	case N_OUT_OF_M:
 1446: 	  numRight=(int) (grade[i]-'0');
 1447: 	  leafs=questions[i].leafs;
 1448: 	  points=questions[i].points;
 1449: 	  unit=(int)ceil((double)points/(double)leafs);
 1450: 	  if (unit==0) unit=points;
 1451: 	  switch (gradingMethod)
 1452: 	    {
 1453: 	    case CAPA_METHOD:
 1454: 	      tempScore=points-(2*unit*(leafs-numRight));
 1455: 	      break;
 1456: 	    case LENIENT_METHOD:
 1457: 	      tempScore=points-(unit*(leafs-numRight));
 1458: 	      break;
 1459: 	    case STRICT:
 1460: 	      if (numRight==leafs) tempScore=points;
 1461: 	      else tempScore=0;
 1462: 	      break;
 1463: 	    default:
 1464: 	      fprintf(stderr,"Unknown grading Method. %d\n",gradingMethod);
 1465: 	      exit(E_GRADINGMETHOD);
 1466: 	      break;
 1467: 	    }
 1468: 	  if (tempScore<0)
 1469: 	    tempScore=0;
 1470: 	  score+=tempScore;
 1471: 	  break;
 1472: 	case ASSIGNED:
 1473: 	  numRight= (int) (grade[i]-'0');
 1474: 	  score+=numRight;
 1475: 	  break;
 1476: 	default:
 1477: 	  fprintf(stderr,"Unknown question type %c\n",questions[i].type);
 1478: 	  break;
 1479: 	}
 1480:     }
 1481:   return score;
 1482: }
 1483: 
 1484: void saveAnonForm(Student *student,FILE *outputFile,
 1485: 		  Question questions[MAX_QUEST],
 1486: 		  PIDPINlist PIDandPINlist[MAX_SECTION_SIZE],
 1487: 		  Flags *flags)
 1488: {
 1489:   int i,j=0,matches[MAX_PID_MATCHES],done=FALSE;
 1490:   int result,capaQuestions,questionIndex,numRight,total[MAX_PID_MATCHES];
 1491:   int offset,maxTotal=0,score,correctID=-1;
 1492:   Problem_t *curProblem,*headProblem;
 1493:   char answerstring[MAX_LINE_LENGTH],buf[MAX_LINE_LENGTH],
 1494:     grade[MAX_PID_MATCHES][MAX_LINE_LENGTH],buffer[MAX_LINE_LENGTH];
 1495:   T_student capaStudent;
 1496: 
 1497:   if (!flags->log)
 1498:     printf("Attempting to find a student with CAPA PIN %s.\n",student->PIN);
 1499: 
 1500:   for(i=0;i<flags->NumOfStudents;i++)
 1501:     {
 1502:       if (atoi(student->PIN)==PIDandPINlist[i].PIN)
 1503: 	{
 1504: 	  matches[j]=i;
 1505: 	  j++;
 1506: 	}
 1507:     }
 1508:   matches[j]=-1;
 1509:   switch(j)
 1510:     {
 1511:     case 0:
 1512:       if(flags->log)
 1513: 	logError(student,flags,LOG_NOPINFOUND);  
 1514:       else
 1515: 	{
 1516: 	  printf("No match for PIN %s\n",student->PIN);
 1517: 	  printf("The current form's PIN is incorrect.\n");
 1518: 	  printf("Please type start to continue.\n");
 1519: 	  scanf("%s",buf);
 1520: 	}
 1521:       return;
 1522:       break;
 1523:     case 1:
 1524:       if (!flags->log)
 1525: 	printf("Only one match assuming PID %s\n",
 1526: 	       PIDandPINlist[matches[0]].PID);
 1527:       strcpy(student->questionPID,PIDandPINlist[matches[0]].PID);
 1528:       saveForm(student,outputFile,questions,flags);
 1529:       return;
 1530:       break;
 1531:     default:
 1532:       break;
 1533:     }
 1534: 
 1535:   /* Only get here if there is more than one valid PID*/
 1536:   if (!flags->log)
 1537:     printf("Found %d matches.\n",j);
 1538: 
 1539:   maxTotal=-1;
 1540:   for(i=0;i<MAX_PID_MATCHES;i++)
 1541:     {
 1542:       total[i]=0;
 1543:       if (matches[i]==-1) break;
 1544:       switch(capa_get_student(student->answerPID, &capaStudent))
 1545: 	{
 1546: 	case 1: break;
 1547: 	case 0:
 1548: 	  if (flags->log)
 1549: 	    logError(student,flags,LOG_STUDENTNOTEXIST);
 1550: 	  else
 1551: 	    {
 1552: 	      fprintf(stderr,"Student %s was not found.\n",student->answerPID);
 1553: 	      printf("Type start to continue");
 1554: 	      scanf("%s",buf);
 1555: 	    }
 1556: 	  return;
 1557: 	  break;
 1558: 	case -1:
 1559: 	  fprintf(stderr,"Unable to find the classl file while grading\n");
 1560: 	  exit(E_CAPA_GET_STUDENT); break;
 1561: 	default:
 1562: 	  fprintf(stderr,"Unknown error from capa_get_student while grading\n");
 1563: 	  exit(E_CAPA_GET_STUDENT); break;
 1564: 	}	
 1565:       strcpy(student->questionPID,PIDandPINlist[matches[i]].PID);
 1566:       result=capa_parse(flags->SetId,&headProblem,student->questionPID,
 1567: 			&capaQuestions);
 1568:       curProblem=headProblem;
 1569:       if (result==0 || result == -1)
 1570: 	{
 1571: 	  fprintf(stderr,"The Parse failed: %d\nDying\n",result);
 1572: 	  exit(E_PARSER);
 1573: 	}
 1574:       else if (result != flags->NumQuestions)
 1575: 	{
 1576: 	  fprintf(stderr,"The parser found %d questions, there were supposed to be %d questions.\nDying\n",result,flags->NumQuestions);
 1577: 	  exit(E_PARSER_DIFFERENT);
 1578: 	}
 1579:       for(questionIndex=0;questionIndex<flags->NumQuestions;questionIndex++)
 1580: 	{
 1581: 	  numRight=gradeQuestion(questions,questionIndex,curProblem,
 1582: 				 student,flags);
 1583: 	  if (questionIndex==4) 
 1584: 	    if (numRight==1)
 1585: 	      correctID=i;
 1586: 
 1587: 	  total[i]+=numRight;
 1588: 	  grade[i][questionIndex]='0'+(char)numRight;
 1589: 	  curProblem=curProblem->next;
 1590: 	}
 1591:       if (total[i] > total[maxTotal]) maxTotal=i;
 1592:       grade[i][questionIndex]='\0';
 1593:       
 1594:       /*printf("Total right for PID %s is %d\n",PIDandPINlist[matches[i]].PID,
 1595: 	     total[i]);*/
 1596:       free_problems(headProblem);  
 1597:     }
 1598: 
 1599:   if (correctID!=-1)
 1600:     {
 1601:       answerstring[0]='\0';
 1602:       for(questionIndex=0;questionIndex<flags->NumQuestions;questionIndex++)
 1603: 	strcat(answerstring,student->Answers[questionIndex]);
 1604:       
 1605:       offset=getScorerEntry(outputFile,student->answerPID);  
 1606: 
 1607:       printf("Total right for student %s is %d\n\n",capaStudent.s_nm,
 1608: 	     total[correctID]);
 1609:       setScorerEntry(outputFile,student->answerPID,capaStudent.s_nm,
 1610: 		     grade[correctID],total[correctID],capaStudent.s_sec,
 1611: 		     answerstring,student->questionPID,student->serialNumber,
 1612: 		     offset);
 1613:       return;
 1614:     }
 1615: 
 1616:   if (!flags->QueryAboutPID && flags->log) 
 1617:     {
 1618:       logMultipleAnon(PIDandPINlist,matches,student,flags,maxTotal,total);
 1619: 
 1620:       answerstring[0]='\0';
 1621:       for(questionIndex=0;questionIndex<flags->NumQuestions;questionIndex++)
 1622: 	strcat(answerstring,student->Answers[questionIndex]);
 1623:       
 1624:       offset=getScorerEntry(outputFile,student->answerPID);  
 1625: 
 1626:       printf("Total right for student %s is %d\n\n",capaStudent.s_nm,
 1627: 	     total[maxTotal]);
 1628:       setScorerEntry(outputFile,student->answerPID,capaStudent.s_nm,
 1629: 		     grade[maxTotal],total[maxTotal],capaStudent.s_sec,
 1630: 		     answerstring,student->questionPID,student->serialNumber,
 1631: 		     offset);
 1632:     }
 1633:   else
 1634:     {
 1635:       while(!done)
 1636: 	{
 1637: 	  printf("Please press\n");
 1638: 	  for(i=0;i<MAX_PID_MATCHES;i++)
 1639: 	    {
 1640: 	      if (matches[i]==-1)
 1641: 		break;
 1642: 	      
 1643: 	      printf("%d) for student number %s ",i+1,
 1644: 		     PIDandPINlist[matches[i]].PID);
 1645: 	      strcpy(student->questionPID,PIDandPINlist[matches[i]].PID);
 1646: 	      score=getScore(student,questions,flags,grade[i],
 1647: 			     LENIENT_METHOD);
 1648: 	      printf(" Lenient: %3d ",score);
 1649: 	      score=getScore(student,questions,flags,grade[i],
 1650: 			     CAPA_METHOD);
 1651: 	      printf(" CAPA: %3d ",score);
 1652: 	      score=getScore(student,questions,flags,grade[i],
 1653: 			     STRICT);
 1654: 	      printf(" Strict: %3d \n",score);
 1655: 	      
 1656: 	    }
 1657: 	  scanf("%s",buffer);
 1658: 	  if (isdigit(buffer[0]) && (atoi(buffer) < (j+1)) && 
 1659: 	      (atoi(buffer) > 0))
 1660: 	    {
 1661: 	      strcpy(student->questionPID,
 1662: 		     PIDandPINlist[matches[atoi(buffer)-1]].PID);
 1663: 	      saveForm(student,outputFile,questions,flags);
 1664: 	      done=TRUE;
 1665: 	    }
 1666: 	}
 1667:     }
 1668: }
 1669: 
 1670: int checkForm(Student * student,Flags *flags)
 1671: {
 1672:   int error,pin;
 1673:   T_student capaStudent;
 1674: 
 1675: #ifdef DEBUG
 1676:   int i,j;
 1677:   printf("PID:\t%s\nPIN:\t%s\nName:\t%s\n",
 1678: 	 student->answerPID,student->PIN,student->Name);
 1679: 
 1680:   for(i=0,j=0;i<flags->NumQuestions;i++)
 1681:     {
 1682:       printf("Answer %d: %s\n",i+1,student->Answers[i]);
 1683:     }
 1684: #endif /*DEBUG*/
 1685: 
 1686:   error=capa_get_student(student->answerPID, &capaStudent);
 1687:   switch(error)
 1688:     {
 1689:     case 1:
 1690:       if (!flags->log)
 1691: 	printf("The current student is %s from section %d\n",
 1692: 	       capaStudent.s_nm,capaStudent.s_sec);
 1693:       break;
 1694:     case 0:
 1695:       if (!flags->log)
 1696: 	{
 1697: 	  printf("Error Finding the student.\n");
 1698: 	  printf("The Scantron reported the PID:%s\n",student->answerPID);
 1699: 	  printf("But this was not found in the classl file.\n");
 1700: 	}
 1701:       return CF_STID;
 1702:       break;
 1703:     case -1:
 1704:       return CF_CLASSL;
 1705:       break;
 1706:     default:
 1707:       fprintf(stderr,"capa_get_student returned an invalid result");
 1708:       fprintf(stderr,"in CheckForm.\n Error=%d. Dying\n",error);
 1709:       exit(E_CAPA_GET_STUDENT);
 1710:       break;
 1711:     }
 1712:   
 1713:   if (flags->CheckPIN && !flags->AnonMode)
 1714:     {
 1715:       pin=capa_PIN(student->answerPID,flags->SetId,0);
 1716:       if (pin!=atoi(student->PIN))
 1717: 	{
 1718: 	  if (flags->log)
 1719: 	    {
 1720: 	      student->classlPIN=pin;
 1721: 	      logError(student,flags,LOG_PINNOTMATCH);
 1722: 	      sprintf(student->PIN,"%04d",pin);
 1723: 	    }
 1724: 	  else
 1725: 	    {
 1726: 	      printf("There is an error with the students PIN:\n");
 1727: 	      printf("The Scantron reported:%s, The Classl file has:%d\n",
 1728: 		     student->PIN,pin);
 1729: 	      fprintf(stderr,"If you wish to use what the Classl file reports\n");
 1730: 	      fprintf(stderr,"enter y, else enter n.\n");
 1731: 	      if (getYesOrNo()==YES)
 1732: 		sprintf(student->PIN,"%04d",pin);
 1733: 	      else
 1734: 		return CF_PIN;
 1735: 	    }
 1736: 	}
 1737:     }
 1738:   return CF_NOERROR;
 1739: }
 1740: 
 1741: int handleCheckForm(Student *student,FILE *outputFile,
 1742: 		   PIDPINlist PIDandPINlist[MAX_SECTION_SIZE],
 1743: 		   Question questions[MAX_QUEST],Flags *flags)
 1744: {
 1745:   int done=FALSE,error;
 1746:   char buf[MAX_LINE_LENGTH];
 1747: 
 1748:   switch(error=checkForm(student,flags))
 1749:     {
 1750:     case CF_STID:
 1751:       if (flags->log)
 1752: 	logError(student,flags,LOG_BADPID);
 1753:       else
 1754: 	{
 1755: 	  printf("The current form's Student Id is incorrect.\n");
 1756: 	  printf("Please type start to continue.\n");
 1757: 	  scanf("%s",buf);
 1758: 	}
 1759:       break;
 1760:     case CF_CLASSL:
 1761:       fprintf(stderr,"The classl file was not found in the");
 1762:       fprintf(stderr," current directory.\n");
 1763:       fprintf(stderr,"Please try again.\n");
 1764:       done=TRUE;
 1765:       break;
 1766:     case CF_PIN:
 1767:       if (flags->log)
 1768: 	logError(student,flags,LOG_BADPIN);
 1769:       else
 1770: 	{
 1771: 	  fprintf(stderr,"The current form's PIN is incorrect.\n");
 1772: 	  fprintf(stderr,"Please type start to continue.\n");
 1773: 	  scanf("%s",buf);
 1774: 	}
 1775:       break;
 1776:     case CF_NOERROR:
 1777:       printf("Grading and Saving Student %s Serial#: %s\n",
 1778: 	     student->answerPID,student->serialNumber);
 1779:       if (flags->AnonMode) 
 1780: 	saveAnonForm(student,outputFile,questions,PIDandPINlist,flags);
 1781:       else
 1782: 	{
 1783: 	  strcpy(student->questionPID,student->answerPID);
 1784: 	  saveForm(student,outputFile,questions,flags);
 1785: 	}
 1786:       break;
 1787:     default:
 1788:       fprintf(stderr,"Unimplemented error in checkForm %d\n",error);
 1789:       exit(E_CHECKFORM);
 1790:       break;
 1791:     }
 1792:   return done;
 1793: }
 1794: 
 1795: int handleGetFormStatus(int status,Student *student,FILE *outputFile,
 1796: 		   PIDPINlist PIDandPINlist[MAX_SECTION_SIZE],
 1797: 		   Question questions[MAX_QUEST],Flags *flags)
 1798: {
 1799:   int done=FALSE,save=TRUE;
 1800:   if (status & GF_SPACES)
 1801:     if (flags->CheckSpaces)
 1802:       {
 1803: 	if (flags->log)
 1804: 	  logError(student,flags,LOG_SPACES);
 1805: 	else
 1806: 	  {
 1807: 	    printf("The current form appears to have some questions left\n");
 1808: 	    printf("blank. Please enter yes if you wish to continue \n");
 1809: 	    printf("grading of this form.\n");
 1810: 	    if (getYesOrNo()==YES)
 1811: 	      ;
 1812: 	    else 
 1813: 	      save=FALSE;
 1814: 	  }
 1815:       }
 1816: 
 1817:   if(status & GF_MULTIPLEMARKS)
 1818:     if (flags->CheckMultipleMarks)
 1819:       {
 1820: 	if (flags->log)
 1821: 	  logError(student,flags,LOG_MULTIPLEMARKS);
 1822: 	else
 1823: 	  {
 1824: 	    printf("The current form appears to have some questions with\n");
 1825: 	    printf("multiple marks on lines that should have only one.\n");
 1826: 	    printf("Please enter yes if you wish to continue grading of this form.\n");
 1827: 	    if (getYesOrNo()==YES)
 1828: 	      ;
 1829: 	    else 
 1830: 	      save=FALSE;
 1831: 	  }
 1832:       }
 1833:   
 1834:   if (status == GF_EOF)
 1835:     done=TRUE;
 1836: 
 1837:   if ((status & GF_PINWRONG) && flags->AnonMode) return done;
 1838:    
 1839:   if (!done && save) 
 1840:     if (!flags->SurveyMode)
 1841:       {
 1842: #ifdef DEBUG
 1843: 	printf("Checking form.\n");
 1844: #endif
 1845: 	done=handleCheckForm(student,outputFile,PIDandPINlist,questions,
 1846: 			     flags);
 1847:       }
 1848:     else
 1849:       if (flags->AnonMode)
 1850: 	saveAnonForm(student,outputFile,questions,PIDandPINlist,flags);
 1851:       else
 1852: 	{
 1853: 	  strcpy(student->questionPID,student->answerPID);
 1854: 	  saveForm(student,outputFile,questions,flags);
 1855: 	}
 1856:   return done;
 1857: }
 1858: 
 1859: void processForms(FILE *outputFile, FILE *scantron,
 1860: 		  Question questions[MAX_QUEST], Flags *flags)
 1861: {
 1862: 
 1863:   int done=FALSE;
 1864:   int status;
 1865:   Student *student=NULL;
 1866:   PIDPINlist PIDandPINlist[MAX_SECTION_SIZE];
 1867: 
 1868:   if (flags->AnonMode)
 1869:     {
 1870:       flags->NumOfStudents=buildPIDandPINlist(flags->SetId,PIDandPINlist);
 1871:       if (flags->NumOfStudents==0)
 1872: 	{
 1873: 	  fprintf(stderr,"buildPIDandPINlists returned 0 students.");
 1874: 	  exit(E_BUILDPIDPIN);
 1875: 	}
 1876:     }
 1877:   
 1878:   while(!done)
 1879:     {
 1880: #ifdef DEBUG
 1881:       printf("Reading in a new form.\n");
 1882: #endif
 1883:       status=getForm(&student,scantron,questions,flags);
 1884:       done=handleGetFormStatus(status,student,outputFile,PIDandPINlist,
 1885: 			       questions,flags);
 1886:       if (student != NULL)
 1887: 	{
 1888: 	  if (student->error) 
 1889: 	    fprintf(flags->logFile,"%s",student->origString);
 1890: 	  free(student);
 1891: 	}
 1892:       student=NULL;
 1893:     }
 1894: }
 1895: 
 1896: void printResults(Flags* flags)
 1897: {
 1898:   printf("Number scanned %d, number errors logged %d\n.",
 1899: 	 flags->linesRead,flags->loggedErrors);
 1900: }
 1901: 
 1902: int main(int argc, char **argv)
 1903: {
 1904:   FILE *outputFile;
 1905:   Question questions[MAX_QUEST];
 1906:   Flags flags;
 1907:   FILE *scantron;
 1908:   
 1909:   Parsemode_f=ASCII_MODE;
 1910:   flags.linesRead=0;
 1911:   flags.loggedErrors=0;
 1912: 
 1913:   initScreen();
 1914:   getInfo(&outputFile,&scantron,questions,&flags);
 1915:   saveInfo(outputFile,questions,&flags);
 1916:   processForms(outputFile,scantron,questions,&flags);
 1917:   printResults(&flags);
 1918:   return 0;
 1919: }

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