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, 11 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_msu,
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>