Annotation of capa/capa51/pProj/capaCommon.c, revision 1.12
1.12 ! albertel 1: /* Library of useful functions
! 2: Copyright (C) 1992-2000 Michigan State University
! 3:
! 4: The CAPA system is free software; you can redistribute it and/or
! 5: modify it under the terms of the GNU Library General Public License as
! 6: published by the Free Software Foundation; either version 2 of the
! 7: License, or (at your option) any later version.
! 8:
! 9: The CAPA system is distributed in the hope that it will be useful,
! 10: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 12: Library General Public License for more details.
! 13:
! 14: You should have received a copy of the GNU Library General Public
! 15: License along with the CAPA system; see the file COPYING. If not,
! 16: write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
! 17: Boston, MA 02111-1307, USA. */
! 18:
1.1 albertel 19: /* =||>|===================== capaCommon.c =====================|<||= */
20: /* created 1994 by Isaac Tsai */
21: /* 1994, 1995, 1996, 1997, 1998, 1999 copyrighted by Isaac Tsai */
22: /* TODO: restructure capa_check_ans*() calls into one */
23: /* =||>|===================== capaCommon.c =====================|<||= */
24: #include <ctype.h>
25: #if defined(__sun) || defined(linux) || defined(__alpha) || defined(hpux) || defined(AIX) || defined(IRIX)
26: #include <unistd.h> /* lockf() */
27: #endif
28: #include <sys/types.h>
29: #include <sys/stat.h>
30: #include <fcntl.h>
31: #include "capaParser.h"
32: #include "capaToken.h"
33: #include "capaCommon.h"
34: #include "ranlib.h"
35:
36:
37: /*----------------------------------------------------------*/
38: /* flock() in SUN is in BSD compatibility lib */
39: /* #include <sys/file.h> */
40: /*----------------------------------------------------------*/
41:
42: int yyparse();
43: extern FILE *yyin;
44: extern void yyrestart();
45:
46: /*----------------------------------------------------------*/
47: /* RETURN: -1 file error */
48: /* 0 success */
49: /* INPUT: if section == 0, for all students in class */
50: /* set : 1, 2, 3, ... */
51: /* prob: 1, 2, 3, ... */
52: /*----------------------------------------------------------*/
53: int
54: capa_excuse(int set,int prob,int section)
55: {
56: int nq;
57: T_header header;
58: T_entry entry;
59: T_student *student_p, *s1_p;
60: char tmp_number[MAX_STUDENT_NUMBER+1];
61: long offset;
62: int num_students;
63:
64: /* Calculate parameters */
65: if (capa_get_header(&header,set)) return (-1);
66: sscanf(header.num_questions,"%d", &nq);
67:
68: if( ( prob > nq ) || (section < 0 ) || (section > MAX_SECTION_COUNT) ) return (-1);
69: num_students= 0;
70: if ( (num_students = capa_get_section(&student_p, section))== -1 ) return (-1);
71: for ( s1_p = student_p ; s1_p ; s1_p = (s1_p->s_next)) {
72: sprintf(tmp_number,"%s",s1_p->s_sn);
73: offset = capa_get_entry(&entry,tmp_number,set);
74: if(offset < 0 ) offset = -offset;
75: switch(entry.answers[prob-1]) {
1.2 albertel 76: case '0':
1.1 albertel 77: case '-': entry.answers[prob-1] = 'E'; break;
78: case 'N': entry.answers[prob-1] = 'E'; break;
79: case 'n': entry.answers[prob-1] = 'e'; break;
1.2 albertel 80: case '1': case '2': case '3': case '4': case '5':
81: case '6': case '7': case '8': case '9':
82: if (entry.answers[prob-1] < header.weight[prob-1]) {
83: entry.answers[prob-1] = 'E';
84: }
85: break;
1.1 albertel 86: default : break;
87: }
88: capa_set_entry(&entry,tmp_number,set,offset);
89: capa_mfree(entry.answers); entry.answers = NULL;
90: capa_mfree(entry.tries); entry.tries = NULL;
91: }
1.2 albertel 92: capa_mfree(header.weight);
93: capa_mfree(header.partial_credit);
1.1 albertel 94: free_students(student_p);
95: return (0);
96: }
97:
98: /*----------------------------------------------------------*/
99: /* Lock file shared */
100: /* lock the file specified by file stream pointer sp */
101: /*----------------------------------------------------------*/
102: int
103: flockstream_sh(sp) FILE *sp;
104: {
105: int fd;
106:
107: fd = fileno(sp);
108:
109: #if defined(__sun) || defined(hpux) || defined(AIX)
110: return ( lockf(fd,F_LOCK, 0L) );
111: #else
112: return (flock(fd,LOCK_SH));
113: #endif
114: }
115: /*----------------------------------------------------------*/
116: int
117: flockstream(sp) FILE *sp;
118: {
119: int fd;
120:
121: fd = fileno(sp);
122:
123: #if defined(__sun) || defined(hpux) || defined(AIX)
124: return ( lockf(fd,F_LOCK, 0L) );
125: #else
126: return (flock(fd,LOCK_EX));
127: #endif
128: }
129: /*----------------------------------------------------------*/
130: int
131: funlockstream(sp) FILE *sp;
132: {
133: int fd;
134:
135: fd = fileno(sp);
136:
137: #if defined(__sun) || defined(hpux) || defined(AIX)
138: return ( lockf(fd,F_ULOCK, 0L) );
139: #else
140: return ( flock(fd,LOCK_UN) );
141: #endif
142: }
143:
144: int
145: inquery_a_lock(sp,cmd,type,offset,whence,len)
146: FILE *sp;int cmd;off_t offset;int whence;off_t len;
147: {
148: struct flock lock;
149: int fd;
150: lock.l_type = type; lock.l_start = offset;
151: lock.l_whence = whence; lock.l_len = len;
152: fd=fileno(sp);
153: return (fcntl(fd,cmd,&lock));
154: }
155: #define Blocked_Write_Lock(sp) \
156: inquery_a_lock(sp,F_SETLK,F_WRLCK,0,0,0)
157:
158: #define Blocked_Write_Lock(sp) \
159: inquery_a_lock(sp,F_SETLK,F_WRLCK,0,0,0)
160:
161: #define Un_Lock(sp) \
162: inquery_a_lock(sp,F_SETLK,F_UNLCK,0,0,0)
163:
164:
165: /*----------------------------------------------------------*/
166: /* INPUT: set problem set number */
167: /* RETURN: -1 no records/setX.db file or file error */
168: /* 0 success */
169: /* OUTPUT: header pointer to T_header structure */
170: /*----------------------------------------------------------*/
171: int
172: capa_set_header(header, set) T_header *header;int set;
173: {
174: FILE *fp;
175: char *big_buf=NULL, filename[FILE_NAME_LENGTH], cr=0, oneline[TMP_LINE_LENGTH];
176: int nq, len, errcode, fd, item_cnt, exists=1;
177: T_header oldheader;
178: long orig_size, new_size, big_buf_size;
179:
180: sprintf(filename,"records/set%d.db",set);
181: if ((fp=fopen(filename,"r+"))==NULL) {
182: exists=0;
183: if ((fp=fopen(filename,"w"))==NULL) { /* create if non-existant */
184: /*printf("Error: can't open %s\n",filename);*/ return (-1);
185: }
186: }
187: sscanf(header->num_questions,"%d",&nq);
188: /* sprintf(oneline,"%d,%s,%s,%s\n",nq,header->open_date,header->due_date,header->answer_date); */
189: sprintf(oneline,"%d\n",nq);
190: len = strlen(oneline);
191: flockstream(fp); errcode = 0;
192:
193: if (exists) {
194: /*get file size*/
195: fseek(fp,0L,SEEK_END);
196: orig_size = ftell(fp);
197: big_buf_size = orig_size; /*the amt we need to read is less then the file's size*/
198: big_buf = capa_malloc(big_buf_size,1);
199: fseek(fp,0L,SEEK_SET);
200:
201: /*read in old header*/
202: fscanf(fp,"%d",&nq);
203: while ( cr != '\n' && cr != EOF ) { cr=fgetc(fp); }
204: oldheader.weight=capa_malloc(nq+1,1);
205: oldheader.partial_credit=capa_malloc(nq+1,1);
206: if (!fread(oldheader.weight, sizeof(char), nq, fp)) errcode = -2;
207: if (EOF==(cr=fgetc(fp))) errcode = -3;
208: if (!fread(oldheader.partial_credit, sizeof(char), nq, fp)) errcode = -4;
209: if (EOF==(cr=fgetc(fp))) errcode = -5;
210: capa_mfree(oldheader.weight);
211: capa_mfree(oldheader.partial_credit);
212:
213: /*read rest of file*/
214: item_cnt=fread(big_buf,1,big_buf_size, fp);
215: }
216:
217: /*write new header*/
218: fseek(fp,0L,SEEK_SET);
219: if (!fwrite(oneline, len, 1, fp)) {errcode = -6;}
220: if ( header->weight != NULL ) {
221: if (!fwrite((char *)(header->weight), strlen(header->weight), 1, fp)) errcode=-7;
222: }
223:
224: if (EOF==(!fputc('\n', fp))) errcode = -8;
225: if (header->partial_credit != NULL) {
226: if (!fwrite((char *)(header->partial_credit), strlen(header->partial_credit),
227: 1, fp)) { errcode = -9; }
228: }
229: if (EOF==(!fputc('\n', fp))) errcode = -10;
230:
231: if (exists) {
232: /*write out rest of file*/
233: if (item_cnt >= 0 ) {
234: big_buf[item_cnt]=0;
235: if (!fwrite(big_buf,item_cnt,1,fp) ) errcode= -11;
236: new_size = ftell(fp);
237: if (new_size < orig_size ) {
238: fd = fileno(fp);
239: ftruncate(fd,new_size);
240: }
241: }
242: }
243:
244: fflush(fp);
245: funlockstream(fp); fclose(fp);
246: if (big_buf!=NULL) capa_mfree(big_buf);
247: return (errcode);
248: }
249:
250: /*----------------------------------------------------------*/
251: /* INPUT: set problem set number */
252: /* RETURN: -1 file error */
253: /* 0 success */
254: /* OUTPUT: header pointer to T_header structure */
255: /* Note: allocates space for the partial_credit and weight */
256: /* fields of the passed in header, caller needs to */
257: /* eventually free them with capa_mfree */
258: /*----------------------------------------------------------*/
259: int
260: capa_get_header(header, set) T_header *header;int set;
261: {
262: FILE *fp;
263: char filename[FILE_NAME_LENGTH];
264: char cr;
265: int nq=0, errcode;
266:
267: sprintf(filename,"records/set%d.db",set);
268: if ((fp=fopen(filename,"r"))==NULL) {
269: /*printf("Error capa_get_header(): can't open %s\n",filename);*/
270: return (-1);
271: }
272:
273: flockstream(fp); errcode = 0;
274: fscanf(fp,"%d",&nq);
275: cr='\0';
276: while ( cr != '\n' && cr != EOF ) { cr=fgetc(fp); }
277: header->weight=capa_malloc(nq+1,1);
278: header->partial_credit=capa_malloc(nq+1,1);
279: if (nq > 0 ) {
280: if (!fread(header->weight, sizeof(char), nq, fp)) errcode = -1;
281: }
282: if (EOF==(cr=fgetc(fp))) errcode = -1;
283: if (nq > 0 ) {
284: if (!fread(header->partial_credit, sizeof(char), nq, fp)) errcode = -1;
285: }
286:
287: funlockstream(fp); fclose(fp);
288: header->weight[nq]='\0'; header->partial_credit[nq]='\0';
289: sprintf(header->num_questions,"%d",nq);
290: return (errcode);
291: }
292: /*----------------------------------------------------------*/
293: /* ----------- previous version, obsolete as of May 1997
294: int
295: capa_set_entry(entry, student_number, set, offset)
296: T_entry *entry;
297: char *student_number;
298: int set;
299: long offset;
300: {
301: FILE *fp;
302: int errcode=0;
303: int len;
304: char filename[FILE_NAME_LENGTH];
305: char a_line[TMP_LINE_LENGTH];
306:
307: sprintf(filename,"records/set%d.db",set);
308: if ((fp=fopen(filename,"r+"))==NULL) {
309: return (-1);
310: }
311: sprintf(a_line,"%s %s,%s\n",entry->student_number,entry->answers,entry->tries);
312: len = strlen(a_line);
313: flockstream(fp);
314: fseek(fp,offset,0);
315: if (!fwrite(a_line,len,1,fp) ) {
316: printf("Error writing data to file\n");
317: errcode= (-1);
318: }
319: fflush(fp);
320: funlockstream(fp);
321: fclose(fp);
322: return (errcode);
323: }
324: ---------- */
325:
326: int
327: capa_set_entry(entry, student_number, set, offset)
328: T_entry *entry;
329: char *student_number;
330: int set;
331: long offset;
332: {
333: FILE *fp;
334: int fd;
335: int errcode=0;
336: int done, len, new_len, item_cnt;
337: long next_r, orig_size, new_size, big_buf_size;
338: char filename[FILE_NAME_LENGTH];
339: char *a_line, tmpline[TMP_LINE_LENGTH],
340: tmp_sn[MAX_STUDENT_NUMBER+1], fmtbuf[SMALL_LINE_BUFFER];
341: char *big_buf;
342:
343: sprintf(filename,"records/set%d.db",set);
344: if ((fp=fopen(filename,"r+"))==NULL) {
345: /* printf("Error capa_set_entry(): can't open %s\n",filename); */ return (-1);
346: }
347: /* entry->answers*3 == entry->tries, + fudge factor*/
348: a_line=capa_malloc(strlen(entry->tries)*5+MAX_STUDENT_NUMBER,1);
349: sprintf(a_line,"%s %s,%s\n",entry->student_number,entry->answers,entry->tries);
350: new_len = strlen(a_line);
351: sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER);
352: flockstream(fp); /* <==== lock the setX.db file */
353: fseek(fp,0L,SEEK_END);
354: orig_size = ftell(fp);
355: big_buf_size = orig_size + new_len;
356: big_buf = capa_malloc(big_buf_size,1);
357: fseek(fp,0L,SEEK_SET); /* rewind to beginning of file */
358: fgets(tmpline,TMP_LINE_LENGTH-1,fp); /* skip weight line, including \n */
359: fgets(tmpline,TMP_LINE_LENGTH-1,fp); /* hand grading */
360: done = 0;
361: while(!done) {
362: done = !fgets(tmpline,TMP_LINE_LENGTH-1,fp); len = strlen(tmpline);
363: if( !done ) {
364: sscanf(tmpline,fmtbuf,tmp_sn);
365: if( !strncasecmp(tmp_sn,student_number,MAX_STUDENT_NUMBER) ) { /* Found */
366: next_r = ftell(fp); offset = next_r - len; done = 1;
367: item_cnt=fread(big_buf,1,big_buf_size, fp); /* read remaining lines into buffer */
368: if(item_cnt >= 0 ) { /* no error reading remaining lines */
369: big_buf[item_cnt]=0; /* terminate the buffer, for sure */
370: fseek(fp,offset,SEEK_SET); /* reposition file pointer to the record */
371: if (!fwrite(a_line,new_len,1,fp) ) { /* write out the records */
372: /* printf("Error writing data to file\n"); */
373: errcode= (-1);
374: }
375: if (item_cnt != 0) {
376: if (!fwrite(big_buf,item_cnt,1,fp) ){/*write out the remainings*/
377: /* printf("Error writing data to file\n"); */
378: errcode= (-1);
379: }
380: }
381: new_size = ftell(fp);
382: if(new_size < orig_size ) {
383: fd = fileno(fp);
384: ftruncate(fd,new_size);
385: }
386: }
387: }
388: } else { /* end of file */
389: fseek(fp,0L,SEEK_END);
390: offset = ftell(fp); /* last byte, if last byte is cr, back up one */
391: fseek(fp,-1L,SEEK_END);
392: while(fgetc(fp) == '\n' ) { offset--; fseek(fp,offset,SEEK_SET); }
393: offset = offset +2; /* last char and cr */
394: done=1;
395: fseek(fp,offset,SEEK_SET);
396: if (!fwrite(a_line,new_len,1,fp) ) { /* write out the records */
397: /* printf("Error writing data to file\n"); */
398: errcode= (-1);
399: }
400: }
401: }
402: fflush(fp);
403: funlockstream(fp); /* <======= unlock the file */
404: fclose(fp);
405: capa_mfree(big_buf); /* free up the buffer */
406: return (errcode);
407: }
408:
409: /* for all elements in entry->answers that aren't ? it changes the
410: file to have the new values (except if student has a Y and for all
411: entries in entry->tries that don't have the value -1 it changes the
412: file to have the new value */
413:
414: int
415: capa_change_entry(entry, student_number, set)
416: T_entry *entry;
417: char *student_number;
418: int set;
419: {
420: FILE *fp;
421: int fd;
422: int errcode=0,offset=0;
423: int done, len, new_len, item_cnt,i,j;
424: long next_r, orig_size, new_size, big_buf_size;
425: char filename[FILE_NAME_LENGTH];
426: char *a_line, tmpline[TMP_LINE_LENGTH],
427: tmp_sn[MAX_STUDENT_NUMBER+1], fmtbuf[SMALL_LINE_BUFFER];
428: char *big_buf;
429:
430: sprintf(filename,"records/set%d.db",set);
431: if ((fp=fopen(filename,"r+"))==NULL) {
432: /* printf("Error capa_set_entry(): can't open %s\n",filename); */ return (-1);
433: }
434: /* entry->answers*3 == entry->tries, + fudge factor*/
435: a_line=capa_malloc(strlen(entry->tries)*5+MAX_STUDENT_NUMBER,1);
436: sprintf(a_line,"%s %s,%s\n",entry->student_number,entry->answers,entry->tries);
437: new_len = strlen(a_line);
438: sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER);
439: flockstream(fp); /* <==== lock the setX.db file */
440: fseek(fp,0L,SEEK_END);
441: orig_size = ftell(fp);
442: big_buf_size = orig_size + new_len;
443: big_buf = capa_malloc(big_buf_size,1);
444: fseek(fp,0L,SEEK_SET); /* rewind to beginning of file */
445: fgets(tmpline,TMP_LINE_LENGTH-1,fp); /* skip weight line, including \n */
446: fgets(tmpline,TMP_LINE_LENGTH-1,fp); /* hand grading */
447: done = 0;
448: while(!done) {
449: done = !fgets(tmpline,TMP_LINE_LENGTH-1,fp); len = strlen(tmpline);
450: if( !done ) {
451: sscanf(tmpline,fmtbuf,tmp_sn);
452: if( !strncasecmp(tmp_sn,student_number,MAX_STUDENT_NUMBER) ) { /* Found */
453: next_r = ftell(fp); offset = next_r - len; done = 1;
454: item_cnt=fread(big_buf,1,big_buf_size,fp); /*read remaining lines into buffer*/
455: if(item_cnt >= 0 ) { /* no error reading remaining lines */
456: big_buf[item_cnt]=0; /* terminate the buffer, for sure */
457: fseek(fp,offset,SEEK_SET); /* reposition file pointer to the record */
458: for(i=0;i<entry->e_probs;i++) {
459: /*if entry has been updated, and student doesn't have a Y yet*/
460: if ((entry->answers[i]!='?') &&
461: (tmpline[MAX_STUDENT_NUMBER+1+i]!='Y'))
462: tmpline[MAX_STUDENT_NUMBER+1+i]=entry->answers[i];
463: j = atoi(&(entry->tries[i*3]));
464: if ( j > -1 ) {
465: tmpline[MAX_STUDENT_NUMBER+1+entry->e_probs+1+i*3]=entry->tries[i*3];
466: tmpline[MAX_STUDENT_NUMBER+1+entry->e_probs+1+i*3+1]=entry->tries[i*3+1];
467: }
468: }
469: if (!fwrite(tmpline,new_len,1,fp) ) { errcode= (-1); }
470: if (item_cnt != 0) {
471: if (!fwrite(big_buf,item_cnt,1,fp) ){/*write out the remainings*/
472: /* printf("Error writing data to file\n"); */
473: errcode= (-1);
474: }
475: }
476: new_size = ftell(fp);
477: if(new_size < orig_size ) {
478: fd = fileno(fp);
479: ftruncate(fd,new_size);
480: }
481: }
482: }
483: } else { /* end of file */
484: fseek(fp,0L,SEEK_END);
485: offset = ftell(fp); /* last byte, if last byte is cr, back up one */
486: fseek(fp,-1L,SEEK_END);
487: while(fgetc(fp) == '\n' ) { offset--; fseek(fp,offset,SEEK_SET); }
488: offset = offset +2; /* last char and cr */
489: done=1;
490: fseek(fp,offset,SEEK_SET);
491: if (!fwrite(a_line,new_len,1,fp) ) { /* write out the records */
492: /* printf("Error writing data to file\n"); */
493: errcode= (-1);
494: }
495: }
496: }
497: fflush(fp);
498: funlockstream(fp); /* <======= unlock the file */
499: fclose(fp);
500: capa_mfree(big_buf); /* free up the buffer */
501: return (errcode);
502: }
503:
504: /* -------------------------------------------------- */
505: /* append a entry record to the very end of the file */
506: long
507: capa_append_entry(entry, student_number, set)
508: T_entry *entry;
509: char *student_number;
510: int set;
511: {
512: FILE *fp;
513: int len;
514: char filename[FILE_NAME_LENGTH];
515: char a_line[TMP_LINE_LENGTH];
516: long offset;
517:
518: sprintf(filename,"records/set%d.db",set);
519: if ((fp=fopen(filename,"r+"))==NULL) {
520: /* printf("Error capa_set_entry(): can't open %s\n",filename); */
521: return (-1);
522: }
523: sprintf(a_line,"%s %s,%s\n",entry->student_number,entry->answers,entry->tries);
524: len = strlen(a_line);
525:
526: flockstream(fp); /* <==== lock the setX.db file */
527: fseek(fp,0L,SEEK_END);
528: offset = ftell(fp);
529: fseek(fp,-1L,SEEK_END);
530: while(fgetc(fp) == '\n' ) { offset--; fseek(fp,offset,SEEK_SET); }
531: offset = offset +2;
532: fseek(fp,offset,SEEK_SET);
533: if (!fwrite(a_line,len,1,fp) ) {
534: /* printf("Error writing data to file\n"); */
535: return (-1);
536: }
537: fflush(fp);
538: funlockstream(fp);
539: fclose(fp);
540: return (offset);
541: }
542:
543: /*----------------------------------------------------------*/
544:
545: long /* RETURNS: byte offset to start of record, 0 if error,
546: -offset if not found & newly created */
547: capa_get_entry(entry, student_number, set)
548: T_entry *entry;
549: char *student_number;
550: int set;
551: {
552: char filename[FILE_NAME_LENGTH];
553: FILE *fp;
554: int len, nq;
555: char *ans_p, *tries_p, oneline[TMP_LINE_LENGTH],fmtbuf[SMALL_LINE_BUFFER];
556: long offset = 0, next_r;
557: int ii, done, found = 0;
558: char a_sn[MAX_STUDENT_NUMBER+1];
559:
560: sprintf(filename,"records/set%d.db",set);
561: if ((fp=fopen(filename,"r"))==NULL) {
562: /*printf("Error capa_get_entry(): can't open %s\n",filename);*/
563: return (0);
564: }
565: sprintf(entry->student_number,"%s",student_number);
566: sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER);
567: flockstream(fp);
568: fgets(oneline,TMP_LINE_LENGTH-1,fp); len = strlen(oneline); sscanf(oneline,"%d",&nq);
569: fgets(oneline,TMP_LINE_LENGTH-1,fp); /* skip weight line, including \n */
570: fgets(oneline,TMP_LINE_LENGTH-1,fp); /* hand grading */
571: done = 0;
572: while(!done) {
573: done = !fgets(oneline,TMP_LINE_LENGTH-1,fp); len = strlen(oneline);
574: if( !done ) {
575: sscanf(oneline,fmtbuf,a_sn);
576: if( !strncasecmp(a_sn,student_number,MAX_STUDENT_NUMBER) ) { /* Found */
577: next_r = ftell(fp); offset = next_r - len; done = 1; found = 1;
578: }
579: } else { /* end of file */
580: fseek(fp,0L,SEEK_END);
581: offset = ftell(fp); /* last byte, if last bye is cr, back up one */
582: fseek(fp,-1L,SEEK_END);
583: while(fgetc(fp) == '\n' ) { offset--; fseek(fp,offset,SEEK_SET); }
584: offset = offset +2; /* last char and cr */
585: found = 0; done=1;
586: }
587: }
588: funlockstream(fp); fclose(fp);
589: if(!found) {
1.6 albertel 590: ans_p = capa_malloc(nq+2,1);
591: tries_p = capa_malloc(3*nq+3,1); /* space and \0 */
1.1 albertel 592: for(ii=0;ii<nq;ii++) { /* Initialize answer string and tries string */
593: ans_p[ii] = '-'; tries_p[3*ii] = ' '; tries_p[3*ii + 1] = '0';
594: if(ii < nq-1) tries_p[3*ii + 2] = ',';
595: }
596: entry->answers = ans_p;
597: entry->tries = tries_p;
598: entry->e_probs = nq;
599: offset = capa_append_entry(entry,student_number,set);
600: } else { /* grows records shorter than nq to nq in length*/
601: char *comma;
602: int length;
603: comma=index(oneline,',');
604: length=((int)(comma-oneline))-(MAX_STUDENT_NUMBER+1);
605: if (length < nq) {
1.6 albertel 606: ans_p = capa_malloc(nq+2,1);
607: tries_p = capa_malloc(3*nq+3,1); /* space and \0 */
1.1 albertel 608: } else {
1.6 albertel 609: ans_p = capa_malloc(length+2,1);
610: tries_p = capa_malloc(3*length+3,1); /* space and \0 */
1.1 albertel 611: }
612: sprintf(fmtbuf, "%%%dc",length);
613: sscanf(oneline + MAX_STUDENT_NUMBER+1,fmtbuf,ans_p);
1.6 albertel 614: ans_p[length]='\0';
1.1 albertel 615: sprintf(fmtbuf, "%%%dc",(3*length-1));
616: sscanf(oneline + MAX_STUDENT_NUMBER+1+length+1,fmtbuf,tries_p);
1.10 albertel 617: tries_p[3*length-1]='\0';
1.1 albertel 618: entry->answers = ans_p;
619: entry->tries = tries_p;
620: entry->e_probs = nq;
621: if (length < nq) {
622: for(ii=length;ii<nq;ii++) {
623: ans_p[ii] = '-'; tries_p[3*ii] = ' '; tries_p[3*ii + 1] = '0';
624: if(ii < nq-1) tries_p[3*ii + 2] = ',';
625: }
626: ans_p[nq]='\0';tries_p[3*(nq)+2]='\0';tries_p[3*length-1]=',';
627: }
628: }
629: return (offset);
630: }
631: /*----------------------------------------------------------*/
632: /* Constants defining the column number for each fields */
633: /* in classl file */
634: /*----------------------------------------------------------*/
635: #define SECTION_BEGIN_COLUMN 10
636: #define SN_BEGIN_COLUMN 14
637: #define NAME_BEGIN_COLUMN 24
638: #define EMAIL_BEGIN_COLUMN 60
639: #define CAPAID_BEGIN_COLUMN 100
640: /*----------------------------------------------------------*/
641: /* Retrieve a linked list of students with specified */
642: /* section in classl file */
643: /* If the input section number is 0, students in the whole */
644: /* classl will be retrieved. */
645: /* The resulting linked list is ordered according to the */
646: /* order in classl */
647: /* Remember to use free_students() to free up the linked */
648: /* list once done with it. */
649: /*----------------------------------------------------------*/
650: /* INPUT: section section number */
651: /* 0 means to load the whole class */
652: /* OUTPUT: student_pp */
653: /* pointer to pointer of structure T_student */
654: /* RETURN: number of students in specified section */
655: /*----------------------------------------------------------*/
656: int
657: capa_get_section(student_pp, section)
658: T_student **student_pp;
659: int section;
660: {
661: FILE *fp;
662: char line[SMALL_LINE_BUFFER],fmtbuf[SMALL_LINE_BUFFER], *cp;
663: int i, line_len;
664: int tmp_sec, student_cnt, tmp_capaid;
665: T_student *s1_p, *s2_p, *s3_p;
666:
667: if ((fp=fopen("classl","r"))==NULL) {
668: /*printf("Error: Can't open classlist file\n");*/
669: return (-1);
670: }
671: student_cnt = 0; s1_p = s2_p = s3_p = (T_student *)NULL;
672: while (fgets(line,SMALL_LINE_BUFFER-1,fp)) {
673: line_len = strlen(line);
674: if(line_len > 25 ) { /* contains valid information, instead of only cr */
675: sscanf(line+SECTION_BEGIN_COLUMN,"%d", &tmp_sec);
676: if (!section || tmp_sec == section) {
677: s3_p = (T_student *)capa_malloc(sizeof(T_student),1);
678: s3_p->s_sec = tmp_sec;
679: sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER);
680: sscanf(line+SN_BEGIN_COLUMN,fmtbuf,s3_p->s_sn);
681: cp = (char *)&line[NAME_BEGIN_COLUMN];
682: for(i=0;i<MAX_NAME_CHAR;i++) s3_p->s_nm[i]=' ';
683: i=0;
684: while( (i < MAX_NAME_CHAR) &&
685: ( isalnum(cp[i]) || cp[i] == ',' || cp[i] == '.' || cp[i] == '\'' ||
686: cp[i] == ' ' || cp[i] == '\t'|| cp[i] == '-' ) ) {
687: s3_p->s_nm[i]=cp[i]; i++;
688: }
689: s3_p->s_nm[MAX_NAME_CHAR]='\0';
690: s3_p->s_email[0]=0;
691: if( line_len > EMAIL_BEGIN_COLUMN ) { /* contains email */
692: cp = (char *)&line[EMAIL_BEGIN_COLUMN];
693: for(i=0;i<MAX_EMAIL_CHAR;i++) s3_p->s_email[i]=' ';
694: i=0;
695: while( (i < MAX_EMAIL_CHAR) &&
696: ( isalnum(cp[i]) || cp[i] == '@' || cp[i] == '.' ) ) {
697: s3_p->s_email[i]=cp[i]; i++;
698: }
699: s3_p->s_email[i]='\0'; /* terminate the email string with the string length */
700: if( line_len > CAPAID_BEGIN_COLUMN ) { /* contains capa id */
701: sscanf(line+CAPAID_BEGIN_COLUMN,"%d", &tmp_capaid);
702: if(tmp_capaid > 0 ) {
703: s3_p->s_capaid = tmp_capaid;
704: }
705: }
706: }
707: if( student_cnt == 0 ) {
708: s1_p = s3_p;
709: s3_p->s_prev = s3_p; s3_p->s_next = (T_student *)NULL;
710: s2_p = s3_p;
711: } else {
712: s3_p->s_prev = s2_p; s3_p->s_next = (T_student *)NULL;
713: s2_p->s_next = s3_p;
714: s2_p = s3_p;
715: }
716: student_cnt++;
717: }
718: }
719: }
720: fclose(fp);
721: *student_pp = s1_p;
722: return (student_cnt);
723: }
724: /*----------------------------------------------------------*/
725: /*----------------------------------------------------------*/
726: /* Retrieve a linked list of students with specified */
727: /* section in classl file */
728: /* If the input section number is 0, students in the whole */
729: /* classl will be retrieved. */
730: /* The resulting linked list is ordered according to */
731: /* student name */
732: /* Remember to use free_students() to free up the linked */
733: /* list once done with it. */
734: /*----------------------------------------------------------*/
735: /* INPUT: section section number */
736: /* 0 means to load the whole class */
737: /* OUTPUT: student_pp */
738: /* pointer to pointer of structure T_student */
739: /* RETURN: number of students in specified section */
740: /*----------------------------------------------------------*/
741:
742: int
743: capa_sorted_section(student_pp, section)
744: T_student **student_pp;
745: int section;
746: {
747: int student_cnt;
748: T_student *student_p, *c_sp;
749:
750: student_cnt = capa_get_section(&student_p,section);
751: if( student_cnt > 1 ) {
752: for(c_sp=student_p;c_sp;c_sp=c_sp->s_next){
753: strcpy(c_sp->s_key,c_sp->s_nm);
754: }
755: msort_main(&student_p);
756: }
757: *student_pp = student_p;
758: return (student_cnt);
759: }
760:
761: /*----------------------------------------------------------*/
762: /* INPUT: address of a pointer to T_student structure */
763: /* OUTPUT: address of a pointer to T_student structure */
764: /* */
765: /* RETURN: none */
766: /*----------------------------------------------------------*/
767: void
768: msort_main(head_pp) T_student **head_pp;
769: {
770: T_student *right_p, *out_sp;
771:
772: if( (*head_pp != NULL) && ((*head_pp)->s_next != NULL) ) {
773: msort_split( *head_pp, &right_p);
774: msort_main(head_pp); msort_main(&right_p);
775: msort_merge(*head_pp, right_p, &out_sp);
776: *head_pp = out_sp;
777: }
778: }
779: /*----------------------------------------------------------*/
780: /* INPUT: a_sp pointer to T_student structur */
781: /* OUTPUT: a_sp */
782: /* b_pp address of a pointer to T_student structure */
783: /* */
784: /* RETURN: none */
785: /*----------------------------------------------------------*/
786: void
787: msort_split(a_sp, b_pp) T_student *a_sp; T_student **b_pp;
788: {
789: T_student *c_sp;
790:
791: *b_pp = a_sp;
792: c_sp = a_sp->s_next;
793: c_sp = c_sp->s_next;
794: while( c_sp != NULL ) {
795: c_sp = c_sp->s_next;
796: *b_pp = (*b_pp)->s_next;
797: if( c_sp != NULL ) c_sp = c_sp->s_next;
798: }
799: c_sp = (*b_pp)->s_next;
800: (*b_pp)->s_next = NULL;
801: *b_pp = c_sp;
802: }
803: /*----------------------------------------------------------*/
804: /* INPUT: a_sp pointer to T_student structur */
805: /* b_sp pointer to T_student structur */
806: /* OUTPUT: c_pp address of a pointer to T_student structure */
807: /* */
808: /* RETURN: none */
809: /*----------------------------------------------------------*/
810: void
811: msort_merge(a_sp, b_sp, c_pp) T_student *a_sp, *b_sp, **c_pp;
812: {
813: T_student *d_sp;
814:
815: if( a_sp == NULL || b_sp == NULL ) {
816:
817: } else {
818: if( strcmp(a_sp->s_key, b_sp->s_key) <= 0 ) {
819: *c_pp = a_sp;
820: a_sp = a_sp->s_next;
821: } else {
822: *c_pp = b_sp;
823: b_sp = b_sp->s_next;
824: }
825: d_sp = *c_pp;
826: while( (a_sp != NULL) && (b_sp != NULL) ) {
827: if( strcmp(a_sp->s_key, b_sp->s_key) <= 0) {
828: d_sp->s_next = a_sp;
829: d_sp = a_sp;
830: a_sp = a_sp->s_next;
831: } else {
832: d_sp->s_next = b_sp;
833: d_sp = b_sp;
834: b_sp = b_sp->s_next;
835: }
836: }
837: if( a_sp == NULL ) {
838: d_sp->s_next = b_sp;
839: } else {
840: d_sp->s_next = a_sp;
841: }
842: }
843: }
844:
845: /*----------------------------------------------------------*/
846: /* INPUT: head_p pointer to T_student structure */
847: /* OUTPUT: head_p pointed to sorted linked list */
848: /* */
849: /* RETURN: none */
850: /*----------------------------------------------------------*/
851: void
852: insert_sort(head_p) T_student *head_p;
853: {
854: T_student *tail_p, *i_p, *p_p, *r_p;
855:
856: if( head_p != NULL ) {
857: tail_p = head_p;
858: while( tail_p->s_next != NULL ) {
859: i_p = tail_p->s_next;
860: if( strcmp( i_p->s_key, head_p->s_key) < 0 ) {
861: tail_p->s_next = i_p->s_next;
862: i_p->s_next = head_p;
863: head_p = i_p;
864: } else {
865: r_p = head_p;
866: p_p = r_p->s_next;
867: while( strcmp(i_p->s_key, p_p->s_key) > 0 ) {
868: r_p = p_p;
869: p_p = r_p->s_next;
870: }
871: if( i_p == p_p ) {
872: tail_p = i_p;
873: } else {
874: tail_p->s_next = i_p->s_next;
875: i_p->s_next = p_p;
876: r_p->s_next = i_p;
877: }
878: }
879: }
880: }
881: }
882: /*----------------------------------------------------------*/
883: /* The purpose of this routine is to free up all spaces */
884: /* in the linked list */
885: /*----------------------------------------------------------*/
886: /* INPUT: student_p pointer to T_student structure */
887: /* OUTPUT: none */
888: /* */
889: /* RETURN: none */
890: /*----------------------------------------------------------*/
891:
892: void
893: free_students(student_p) T_student *student_p;
894: {
895: T_student *s_p,*next_p;
896:
897: for (s_p=student_p; s_p; s_p=next_p) {
898: next_p = (s_p->s_next);
899: capa_mfree((char *)s_p);
900: }
901: }
902:
903: /*----------------------------------------------------------*/
904: /* The purpose of this routine is to free up all spaces */
905: /* in the linked list */
906: /*----------------------------------------------------------*/
907: /* INPUT: student_p pointer to T_student structur */
908: /* OUTPUT: none */
909: /* */
910: /* RETURN: -2 file error */
911: /* -1 never login */
912: /* >= 0 score for that set */
913: /*----------------------------------------------------------*/
914: int
915: capa_get_score(student_number,set,valid_scores,answers_pp)
916: char *student_number;int set;int *valid_scores;char **answers_pp;
917: {
918: T_entry a_record;
919: T_header a_header;
920: long offset;
921: int set_scores, set_valids=0, probs_cnt;
922: int ii=0, never_login=1;
923:
924: if( (offset = capa_get_entry(&a_record,student_number,set) ) == 0 ) {
925: return (-2);
926: }
927: probs_cnt = a_record.e_probs;
928: if( capa_get_header(&a_header,set) < 0 ) { return (-2); }
929: if( offset < 0 ) {
930: for(set_valids=0,ii=0;ii<probs_cnt;ii++) {
931: set_valids += (a_header.weight[ii] - '0');
932: }
933: set_scores = -1;
934: *answers_pp = a_record.answers;
935: capa_mfree(a_record.tries); a_record.tries = NULL;
936: } else {
937: for(set_scores=0,ii=0, never_login=1;ii<probs_cnt;ii++) {
938: switch(a_record.answers[ii]) {
939: case 'Y': case 'y': never_login = 0;
940: set_scores += (a_header.weight[ii] - '0');
941: set_valids += (a_header.weight[ii] - '0'); break;
942: case '-': case 'N': case 'n':
943: set_valids += (a_header.weight[ii] - '0'); break;
944: case 'E': case 'e': break;
945: default : if( a_record.answers[ii] >= '0' &&
946: a_record.answers[ii] <= '9' ) {
947: set_scores += (a_record.answers[ii] - '0');
948: set_valids += (a_header.weight[ii] - '0');
949: never_login = 0;
950: } break;
951: }
952: }
953: *answers_pp = a_record.answers;
954: capa_mfree(a_record.tries); a_record.tries = NULL;
955: }
956: capa_mfree(a_header.weight);
957: capa_mfree(a_header.partial_credit);
958: *valid_scores = set_valids;
959: if(never_login) set_scores = -1;
960: return (set_scores);
961: }
962: /*----------------------------------------------------------*/
963: /* Reads the classl file and returns the number of students */
964: /* for each section in cnt_arry[] */
965: /* In cnt_arry[0] is the maximum section number that */
966: /* has at least one student */
967: /*----------------------------------------------------------*/
968: /* INPUT: cnt_arry[] integer array */
969: /* OUTPUT: cnt_arry[] */
970: /* */
971: /* */
972: /* RETURN: -1 file error */
973: /*----------------------------------------------------------*/
974: int
975: capa_get_section_count(cnt_arry) int cnt_arry[];
976: {
977: FILE *fp;
978: char filename[FILE_NAME_LENGTH];
979: char line[TMP_LINE_LENGTH];
980: int sec_num, cnt, i, max;
981:
982: sprintf(filename,"classl");
983: if ((fp=fopen(filename,"r"))==NULL) {
984: /*printf("Error: can't open %s\n",filename);*/
985: return (-1);
986: }
987: for(i=0;i<MAX_SECTION_COUNT;i++) cnt_arry[i]=0;
988: max = 0;
989: while ( fgets(line,TMP_LINE_LENGTH-1,fp) && (strlen(line) != 0) ) {
990: sec_num=0;
991: sscanf(line+SECTION_BEGIN_COLUMN,"%d", &sec_num);
992: if( sec_num != 0 ) {
993: max = MAX(sec_num,max);
994: cnt_arry[sec_num]++;
995: }
996: }
997: fclose(fp);
998: cnt = 0;
999: for(i=1; i <= max; i++) {
1000: if(cnt_arry[i]) cnt++;
1001: }
1002: cnt_arry[0] = max;
1003: return (cnt);
1004: }
1005: /*----------------------------------------------------------*/
1006: /* lookup student information from classl file by */
1007: /* student number */
1008: /*----------------------------------------------------------*/
1009: /* INPUT: student_number char array of student number */
1010: /* OUTPUT: student_p pointer to a T_student structure */
1011: /* that contains the student name, */
1012: /* student number, section number */
1013: /* of the student inquired */
1014: /* */
1015: /* RETURN: -1 file error */
1016: /* 0 no such student */
1017: /* >0 success (line number in classl of student)*/
1018: /*----------------------------------------------------------*/
1019: int
1020: capa_get_student(student_number, student_p)
1021: char *student_number;
1022: T_student *student_p;
1023: {
1024: FILE *fp;
1025: char line[SMALL_LINE_BUFFER],fmtbuf[SMALL_LINE_BUFFER],
1026: sNumber[MAX_STUDENT_NUMBER+1],
1027: aNumber[MAX_STUDENT_NUMBER+1];
1028: int i,found,line_len,tmp_capaid,linenum=0;
1029: char *cp;
1030:
1031: strncpy(sNumber, student_number,MAX_STUDENT_NUMBER+1);
1032: if ((fp=fopen("classl","r"))==NULL) {
1033: /*printf("Error: Can't open classlist file\n");*/
1034: return (-1);
1035: }
1036: found = 0;
1037: while (!found && fgets(line,SMALL_LINE_BUFFER-1,fp)) {
1038: linenum++;
1039: line_len = strlen(line);
1040: sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER);
1041: sscanf(line+SN_BEGIN_COLUMN,fmtbuf,aNumber);
1042: if(!strncasecmp(sNumber,aNumber, MAX_STUDENT_NUMBER)) {
1043: found = 1;
1044: i=0;
1045: strncpy(student_p->s_sn, student_number,MAX_STUDENT_NUMBER+1);
1046: cp = (char *)&line[NAME_BEGIN_COLUMN];
1047: while( (i< MAX_NAME_CHAR) &&
1048: (isalnum(cp[i]) || cp[i] == ',' || cp[i] == '.' || cp[i] == '\'' ||
1049: cp[i] == ' ' || cp[i] == '\t'|| cp[i] == '-' || cp[i] == '_' || cp[i] == '~' ) ) {
1050: student_p->s_nm[i]=cp[i]; i++;
1051: }
1052: student_p->s_nm[i]='\0';
1053: sscanf(line+SECTION_BEGIN_COLUMN,"%d", &(student_p->s_sec));
1054: student_p->s_email[0]=0;
1055: if( line_len > EMAIL_BEGIN_COLUMN ) { /* contains email */
1056: cp = (char *)&line[EMAIL_BEGIN_COLUMN];
1057: for(i=0;i<MAX_EMAIL_CHAR;i++) student_p->s_email[i]=' ';
1058: i=0;
1059: while( (i < MAX_EMAIL_CHAR) &&
1060: ( isalnum(cp[i]) || cp[i] == '@' || cp[i] == '.' || cp[i] == '!' || cp[i] == '=' ||
1061: cp[i] == '_' || cp[i] == '-' || cp[i] == '+' || cp[i] == '^' || cp[i] == '|' ) ) {
1062: student_p->s_email[i]=cp[i]; i++;
1063: }
1064: student_p->s_email[i]='\0'; /* terminate the email string with the string length */
1065: if( line_len > CAPAID_BEGIN_COLUMN ) { /* contains capa id */
1066: sscanf(line+CAPAID_BEGIN_COLUMN,"%d", &tmp_capaid);
1067: if(tmp_capaid > 0 ) {
1068: student_p->s_capaid = tmp_capaid;
1069: }
1070: }
1071: }
1072: }
1073: }
1074: fclose(fp);
1075: if (found > 0) found=linenum;
1076: return (found);
1077: }
1078: /*----------------------------------------------------------*/
1079: /* lookup student information from classl file by */
1080: /* student name */
1081: /*----------------------------------------------------------*/
1082: /* INPUT: student_name char array of student name */
1083: /* OUTPUT: student_p pointer to a T_student structure */
1084: /* that contains the student name, */
1085: /* student number, section number */
1086: /* of the student inquired */
1087: /* */
1088: /* RETURN: -1 file error */
1089: /* 0 no such student */
1090: /* 1 success */
1091: /*----------------------------------------------------------*/
1092: int
1093: capa_student_byname(student_name, student_p)
1094: char *student_name;
1095: T_student *student_p;
1096: {
1097: FILE *fp;
1098: char line[SMALL_LINE_BUFFER],fmtbuf[SMALL_LINE_BUFFER],
1099: sName[MAX_NAME_CHAR+1],
1100: aName[MAX_NAME_CHAR+1];
1101: int i,found, len, line_len,tmp_capaid;
1102: char *cp;
1103:
1104: len = strlen(student_name);
1105: strncpy(sName, student_name,MAX_NAME_CHAR+1);
1106: if ((fp=fopen("classl","r"))==NULL) {
1107: /*printf("Error: Can't open classlist file\n");*/
1108: return (-1);
1109: }
1110: found = 0;
1111: while (fgets(line,SMALL_LINE_BUFFER-1,fp)) {
1112: i=0;
1113: cp = (char *)&line[NAME_BEGIN_COLUMN];
1114: while( (i < MAX_NAME_CHAR) &&
1115: (isalnum(cp[i]) || cp[i] == ',' || cp[i] == '.' || cp[i] == '\'' ||
1116: cp[i] == ' ' || cp[i] == '\t' || cp[i] == '-' || cp[i] == '_' || cp[i] == '~') ) {
1117: aName[i]=cp[i]; i++;
1118: }
1119: aName[i]='\0';
1120: if(!strncasecmp(sName,aName,len)) {
1121: found = 1;
1122: strcpy(student_p->s_nm,aName);
1123: sscanf(line+SECTION_BEGIN_COLUMN,"%d", &(student_p->s_sec));
1124: sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER);
1125: sscanf(line+SN_BEGIN_COLUMN,fmtbuf,student_p->s_sn);
1126: student_p->s_email[0]=0;
1127: line_len=strlen(line);
1128: if( line_len > EMAIL_BEGIN_COLUMN ) { /* contains email */
1129: cp = (char *)&line[EMAIL_BEGIN_COLUMN];
1130: for(i=0;i<MAX_EMAIL_CHAR;i++) student_p->s_email[i]=' ';
1131: i=0;
1132: while( (i < MAX_EMAIL_CHAR) &&
1133: ( isalnum(cp[i]) || cp[i] == '@' || cp[i] == '.' || cp[i] == '!' || cp[i] == '=' ||
1134: cp[i] == '_' || cp[i] == '-' || cp[i] == '+' || cp[i] == '^' || cp[i] == '|' ) ) {
1135: student_p->s_email[i]=cp[i]; i++;
1136: }
1137: student_p->s_email[i]='\0'; /* terminate the email string with the string length */
1138: if( line_len > CAPAID_BEGIN_COLUMN ) { /* contains capa id */
1139: sscanf(line+CAPAID_BEGIN_COLUMN,"%d", &tmp_capaid);
1140: if(tmp_capaid > 0 ) {
1141: student_p->s_capaid = tmp_capaid;
1142: }
1143: }
1144: }
1145: }
1146: }
1147: fclose(fp);
1148: return (found);
1149: }
1150: /*----------------------------------------------------------*/
1151: /* Randomly selected a student from classl file specified */
1152: /* by section */
1153: /*----------------------------------------------------------*/
1154: /* INPUT: section section number */
1155: /* OUTPUT: student_p pointer to a T_student structure */
1156: /* that contains the student name, */
1157: /* student number, section number */
1158: /* of the student inquired */
1159: /* */
1160: /* RETURN: -1 file error */
1161: /* 0 no such student */
1162: /* 1 success */
1163: /*----------------------------------------------------------*/
1164: int
1165: capa_pick_student(section, student_p)
1166: int section;
1167: T_student *student_p;
1168: {
1169: T_student *s1_p, *s2_p;
1170: int student_cnt, idx, pick=-1;
1171:
1172: student_cnt = capa_get_section(&s1_p,section);
1173: if(student_cnt > 0 ) {
1174: srand(time(NULL));
1175: pick = rand() % student_cnt;
1176: for(s2_p = s1_p, idx=0; s2_p && idx < pick; idx++) {
1177: s2_p = s2_p->s_next;
1178: }
1179: strcpy(student_p->s_sn,s2_p->s_sn);
1180: strcpy(student_p->s_nm,s2_p->s_nm);
1181: strcpy(student_p->s_email,s2_p->s_email);
1182: student_p->s_capaid=s2_p->s_capaid;
1183: student_p->s_sec = s2_p->s_sec;
1184: free_students(s1_p);
1185: }
1186: return (pick);
1187: }
1188: /* -------------------------------------------------- */
1189: /* add a student to the class file */
1190: /* check duplicated student id */
1191: /* student name? */
1192: /* Returns: 0 success */
1193: /* 1 there is an duplicate entry */
1194: /* -------------------------------------------------- */
1195: int
1196: capa_add_student(student_p)
1197: T_student *student_p;
1198: {
1199: FILE *fp;
1200: char line[SMALL_LINE_BUFFER], fmtbuf1[SMALL_LINE_BUFFER],
1201: tmp_nm[MAX_STUDENT_NUMBER+1],
1202: tmp_nu[MAX_NAME_CHAR+1];
1203: int i,found, len;
1204: char *class, *cp;
1205: char cid[4],cn[4];
1206: #if defined(NeXT)
1207: char cwd[FILE_NAME_LENGTH];
1208: #endif
1209:
1210: #if defined(NeXT)
1211: class = getwd(cwd);
1212: if( class == NULL ) { class = cwd; }
1213: #else
1214: class = getcwd(NULL,255);
1215: #endif
1216:
1217: if( class == NULL ) { printf("capa_add_student(): Current working directory unknown!\n"); }
1218: len=strlen(class); cp=class; cp=cp+(len-8);
1219: for(i=0;i<3;i++) {
1220: cid[i] = cp[i+3];
1221: cn[i] = cp[i];
1222: }
1223: cid[3]=cn[3]=0;
1224: if ((fp=fopen("classl","r+"))==NULL) {
1225: /*printf("Error: Can't open classlist file\n");*/
1226: return (-1);
1227: }
1228: found = 0;
1229: sprintf(fmtbuf1, "%%%dc",MAX_STUDENT_NUMBER);
1230: while (fgets(line,SMALL_LINE_BUFFER-1,fp)) {
1231: sscanf(line+SN_BEGIN_COLUMN,fmtbuf1,tmp_nu);
1232: tmp_nu[MAX_STUDENT_NUMBER]='\0';
1233: if(!strncasecmp(student_p->s_sn,tmp_nu, MAX_STUDENT_NUMBER)) {
1234: found = 1; break;
1235: }
1236: i=0; cp = (char *)&line[NAME_BEGIN_COLUMN];
1237: while( (i < MAX_NAME_CHAR) &&
1238: (isalnum(cp[i]) || cp[i] == ',' || cp[i] == '.' || cp[i] == '\'' ||
1239: cp[i] == ' ' || cp[i] == '\t'|| cp[i] == '-' || cp[i] == '_' || cp[i] == '~') ) {
1240: tmp_nm[i]=cp[i]; i++;
1241: }
1242: tmp_nm[i]='\0';
1243: len=strlen(tmp_nm);
1244: if(!strncasecmp(student_p->s_nm,tmp_nm,len)) {
1245: found = 1; break;
1246: }
1247: }
1248: if(!found) {
1249: sprintf(line,"%s %s %03d %s %s\n",
1250: cn,cid,student_p->s_sec,student_p->s_sn,student_p->s_nm);
1251: len = strlen(line);
1252: fseek(fp,0L,SEEK_END);
1253: if (!fwrite(line,len,1,fp) ) {
1254: /*printf("Error writing data to file\n");*/
1255: found = -1;
1256: }
1257: fflush(fp);
1258: }
1259: fclose(fp);
1260: free(class);
1261: return (found);
1262: }
1263: /*----------------------------------------------------------*/
1264: /* INPUT: student_number char array of student number */
1265: /* set the X in logX.db */
1266: /* OUTPUT: none */
1267: /* */
1268: /* RETURN: -1 file error */
1269: /* 0 no login */
1270: /* >0 number of logins in that logX.db file */
1271: /*----------------------------------------------------------*/
1272: int
1273: capa_get_login_count(student_number,set)
1274: char *student_number;
1275: int set;
1276: {
1277: char filename[FILE_NAME_LENGTH],
1278: sNumber[MAX_STUDENT_NUMBER+1],
1279: aNumber[MAX_STUDENT_NUMBER+1];
1280: FILE *fp;
1281: char line[MAX_BUFFER_SIZE],fmtbuf[MAX_BUFFER_SIZE];
1282: int num;
1283:
1284: strncpy(sNumber, student_number,MAX_STUDENT_NUMBER+1);
1285: sprintf(filename,"records/log%d.db",set);
1286: if( !capa_access(filename, F_OK) ) {
1287: if ((fp=fopen(filename,"r"))==NULL) {
1288: /*printf("Error: can't open %s\n",filename);*/
1289: return (-1);
1290: }
1291: } else {
1292: return (-1);
1293: }
1294: num = 0;
1295: while (fgets(line,MAX_BUFFER_SIZE-1,fp)) {
1296: sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER);
1297: sscanf(line,fmtbuf,aNumber);
1298: if(!strncasecmp(sNumber,aNumber, MAX_STUDENT_NUMBER)) num++;
1299: }
1300: fclose(fp);
1301: return (num);
1302: }
1303: /*----------------------------------------------------------*/
1304: /* INPUT: set the X in logX.db */
1305: /* OUTPUT: none */
1306: /* */
1307: /* RETURN: -1 file error */
1308: /* 0 no login */
1309: /* >0 number of logins in that logX.db file */
1310: /*----------------------------------------------------------*/
1311: #define ANSWER_BEGIN_COLUMN 35
1312: int
1313: capa_get_login_db(login_item,num_probs,set)
1314: T_entry login_item[];
1315: int *num_probs;
1316: int set;
1317: {
1318: FILE *fp;
1319: char filename[FILE_NAME_LENGTH];
1320: char line[MAX_BUFFER_SIZE],fmtbuf[SMALL_LINE_BUFFER];
1321: T_header header;
1322: int num_q, count, len;
1323:
1324: if(capa_get_header(&header,set)) return (0);
1325: sscanf(header.num_questions,"%d",&num_q);
1326: *num_probs = num_q;
1327: capa_mfree(header.weight);
1328: capa_mfree(header.partial_credit);
1329:
1330: sprintf(filename,"records/log%d.db",set);
1331: if((fp=fopen(filename,"r"))==NULL) {
1332: /*printf("Error: can't open %s\n",filename);*/
1333: return (-1);
1334: }
1335: count=0;
1336: while ( fgets(line,MAX_BUFFER_SIZE,fp) && (strlen(line) != 0 )) {
1337: len = strlen(line);
1338: if(len > ANSWER_BEGIN_COLUMN ) {
1339: sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER);
1340: sscanf(line,fmtbuf, login_item[count].student_number);
1341: login_item[count].answers = capa_malloc(num_q,1);
1342: sprintf(fmtbuf, "%%%dc",num_q);
1343: sscanf(line+ANSWER_BEGIN_COLUMN,fmtbuf, login_item[count].answers);
1344: count++;
1345: }
1346: }
1347: fclose(fp);
1348: return (count);
1349: }
1350:
1351: /*----------------------------------------------------------*/
1352: /* INPUT: option the option the check */
1353: /* set the X in dateX.db */
1354: /* section which section to check for */
1355: /* */
1356: /* OUTPUT: none */
1357: /* */
1358: /* RETURN: -2 invalid option */
1359: /* -1 capa_get_section_dates error */
1360: /* 0 no */
1361: /* 1 yes */
1362: /*----------------------------------------------------------*/
1363: int capa_check_option(int option,int set,int section)
1364: {
1365: T_dates* dates;
1366: int result;
1367:
1368: result=capa_get_section_dates(section,set,&dates);
1369: if (result < 0) return -1;
1370: switch(option) {
1371: case OPTION_INHIBIT_RESPONSE: result=dates->inhibit_response;break;
1372: case OPTION_VIEW_PROBLEMS_AFTER_DUE: result=dates->view_problems_after_due;break;
1373: default: result=-2;
1374: }
1375: capa_mfree((char*)dates);
1376: return result;
1377: }
1378:
1379: /*----------------------------------------------------------*/
1.3 albertel 1380: /* INPUT: time the current time */
1381: /* datetime the datetime string to compare */
1.1 albertel 1382: /* OUTPUT: none */
1383: /* */
1.3 albertel 1384: /* RETURN: -1 time is earlier then datetime */
1385: /* 1 time is later than datetime */
1.1 albertel 1386: /*----------------------------------------------------------*/
1387: int
1388: compare_datetime(time,datetime)
1389: time_t time;
1390: char *datetime;
1391: {
1392: char dateStr[16], timeStr[16];
1393: time_t time2;
1394: char *t_ptr;
1395: int idx;
1396:
1397: /* sscanf(datetime,"%s %s",dateStr,timeStr); */
1398: t_ptr = index(datetime,' '); t_ptr++; /*** hpux complained */
1399: for(idx=0;idx<10;idx++) dateStr[idx] = datetime[idx];
1400: dateStr[10] = 0;
1401: for(idx=0;idx<5;idx++) timeStr[idx] = t_ptr[idx];
1402: timeStr[5] = 0;
1403: time2 = convertTime(dateStr,timeStr);
1404: if(time == time2 ) return (0);
1405: return ( (time > time2)? 1 : -1 );
1406: }
1407:
1408: /* --------------------------------- */
1409: /* check if records/dateX.db exists */
1410: /* read the section open date, answer date, due date info */
1411: /* What if: [7,3] date_info */
1412: /* [3,7] date_info */
1413: /* 4 date_info */
1.3 albertel 1414: /* RETURN: -1 if not pass time */
1415: /* 1 if pass time (or no time available */
1.1 albertel 1416: int capa_check_date(int which,char *student_number, int section,int set)
1417: {
1418: int result;
1419: char date_str[TMP_LINE_LENGTH];
1420: time_t curtime;
1421:
1422: time(&curtime);
1423:
1424: result = capa_get_date(which,student_number,section,set,date_str);
1425: if ( result == 1 ) { result = compare_datetime(curtime,date_str); }
1426: return result;
1427: }
1428:
1429: time_t capa_convert_duration(char *duration)
1430: {
1431: int hour, minute;
1432: sscanf(duration,"%d:%d",&hour,&minute);
1433: return ((hour*60)+minute)*60;
1434: }
1435:
1436: void capa_get_due_date(char *date_str,T_dates *current,char *student_number,int set)
1437: {
1438: time_t duration=capa_convert_duration(current->duration);
1439: time_t duetime=0;
1440: time_t logintime;
1441: struct tm *due_time_tm;
1442: if ((duration > 0) && (student_number!=NULL)) {
1443: if (capa_get_login_time(student_number,set,&logintime)==1) {
1444: duetime=logintime+duration;
1445: due_time_tm=localtime(&duetime);
1446: sprintf(date_str,"%04d/%02d/%02d %02d:%02d",((due_time_tm->tm_year)+1900),
1447: due_time_tm->tm_mon+1,due_time_tm->tm_mday,due_time_tm->tm_hour,
1448: due_time_tm->tm_min);
1449: return;
1450: }
1451: }
1452: strncpy(date_str,current->due_date,DATE_BUFFER);
1453: }
1454:
1455: /* student_number can be NULL, if it isn't NULL it is used by get_due_date */
1456: /* to assign a due date based on the time the student first accessed the */
1457: /* set if duration is non-zero */
1458: int
1459: capa_get_date(int which,char *student_number,int section,int set,char *date_str)
1460: {
1461: T_dates *current;
1462: int result;
1463: result=capa_get_section_dates(section,set,¤t);
1464: if (result<0) return result;
1465: result=1;
1466: switch(which) {
1467: case CHECK_OPEN_DATE: strncpy(date_str,current->open_date,DATE_BUFFER); break;
1468: case CHECK_DUE_DATE: capa_get_due_date(date_str,current,student_number,set); break;
1469: case CHECK_ANS_DATE: strncpy(date_str,current->answer_date,DATE_BUFFER); break;
1470: default: strncpy(date_str,current->open_date,DATE_BUFFER); result=-4;break;
1471: }
1472: capa_mfree((char*)current);
1473: return result;
1474: }
1475:
1476: int
1477: capa_get_duration(char *student_number,int section,int set)
1478: {
1479: T_dates *current;
1480: int duration=0,result;
1481: result=capa_get_section_dates(section,set,¤t);
1482: if (result<0) return result;
1483: duration=capa_convert_duration(current->duration);
1484: capa_mfree((char*)current);
1485: return duration;
1486: }
1487:
1488: int
1489: capa_get_section_dates(int section,int set,T_dates** dates)
1490: {
1491: register int c;
1492: FILE *fp;
1493: int result = 0, done;
1494: int tmp_low, tmp_high, sec_mode;
1495: char filename[FILE_NAME_LENGTH], tmpline[TMP_LINE_LENGTH],
1496: default_line[TMP_LINE_LENGTH];
1497:
1498: sprintf(filename,"records/date%d.db",set);
1499: if( capa_access(filename, F_OK) != 0 ) { result = -2; } else {
1500: if ((fp=fopen(filename,"r")) == NULL) { result = -2; } else {
1501: done = 0; result = -3;
1502: /* first non-comment line is assumed to be the default line */
1503: c_gettype(fp); c_ignorewhite(fp); fgets(default_line,TMP_LINE_LENGTH-1,fp);
1504: do {
1505: c_ignorewhite(fp); c = getc(fp); ungetc(c,fp);
1506: if( c != EOF ) {
1507: sec_mode = c_getsec_range(fp,&tmp_low,&tmp_high);
1508: if( sec_mode > 0 ) { /* no error */
1509: c_ignorewhite(fp); fgets(tmpline,TMP_LINE_LENGTH-1,fp);
1510: if( sec_mode == 1 ) { /* form: sec date_info */
1511: if((result == -3) && (tmp_low == section)) {
1512: result=-4;
1513: *dates=add_date_info(tmp_low,tmp_low,tmpline);
1514: if ( *dates != NULL ) { done = 1; result = 1; }
1515: }
1516: } else { /* form : [low,high] date_info */
1517: if( (result == -3) && ((section>=tmp_low)&&(section<=tmp_high)) ) {
1518: result = -4;
1519: *dates=add_date_info(tmp_low,tmp_high,tmpline);
1520: if ( *dates != NULL ) { done = 1; result = 1; }
1521: }
1522: }
1523: } else { /* error in specify section date */
1524: while ( ((c = getc(fp)) != '\n') && ( c != EOF) ); /* skip to end of line */
1525: }
1526: } else { /* EOF encountered */
1527: done = 1;
1528: }
1529: } while (!done);
1530: /* need to deal with those sections not show up in the dateX.db file */
1531: if( result == -3 ) { /* section not in the dateX.db file, use default */
1532: result = -4;
1533: *dates=add_date_info(DATE_DEFAULTS,DATE_DEFAULTS,default_line);
1534: if ( *dates != NULL ) { result = 1; }
1535: }
1536: }
1537: fclose(fp);
1538: }
1539: return (result);
1540: }
1541:
1542: T_dates* add_date_info(int lowsec,int highsec, char *dateinfo)
1543: {
1544: T_dates *dates;
1545: int result;
1546: dates=(T_dates*)capa_malloc(sizeof(T_dates),1);
1547: result=sscanf(dateinfo,"%16c,%16c,%16c,%s %d,%d",dates->open_date,dates->due_date,
1548: dates->answer_date,dates->duration,&(dates->inhibit_response),
1549: &(dates->view_problems_after_due));
1550: if (result != 6) {
1551: capa_mfree((char*)dates);
1552: dates=NULL;
1553: } else {
1554: dates->section_start=lowsec;
1555: dates->section_end=highsec;
1556: dates->s_next=NULL;
1557: }
1558: return dates;
1559: }
1560: /*----------------------------------------------------------*/
1561: /* INPUT: set the X in dateX.db */
1562: /* dates a pointer to the dates pointer */
1563: /* ACTION: builds a linked list of T_dates containing */
1564: /* the login information */
1565: /* RETURN: <0 file error */
1566: /* >0 success (number of lines successfully */
1567: /* proccessed) */
1568: /*----------------------------------------------------------*/
1569: int capa_get_all_dates (int set,T_dates **dates)
1570: {
1571: T_dates *current;
1572: FILE *fp;
1573: int result = 0, done, tmp_low, tmp_high, sec_mode, c, num=0;
1574: char filename[FILE_NAME_LENGTH], tmpline[TMP_LINE_LENGTH];
1575:
1576: sprintf(filename,"records/date%d.db",set);
1577: if ( ((fp=fopen(filename,"r")) == NULL)) { result = -2; } else {
1578: done = 0; result = -3;
1579: /* first non-comment line is assumed to be the default line */
1580: c_gettype(fp); c_ignorewhite(fp); fgets(tmpline,TMP_LINE_LENGTH-1,fp);
1581: *dates=add_date_info(DATE_DEFAULTS,DATE_DEFAULTS,tmpline);
1582: num++;
1583: if ( NULL == (current=*dates) ) {
1584: result = -3;
1585: } else {
1586: while(1) {
1587: c_ignorewhite(fp); c = getc(fp); ungetc(c,fp);
1588: if( c == EOF ) { break; }
1589: sec_mode = c_getsec_range(fp,&tmp_low,&tmp_high);
1590: if( sec_mode > 0 ) { /* no error */
1591: c_ignorewhite(fp); fgets(tmpline,TMP_LINE_LENGTH-1,fp);
1592: if( sec_mode == 1 ) { /* form: sec date_info */
1593: current->s_next=add_date_info(tmp_low,tmp_low,tmpline);
1594: } else { /* form : [low,high] date_info */
1595: current->s_next=add_date_info(tmp_low,tmp_high,tmpline);
1596: }
1597: current=current->s_next;
1598: num++;
1599: } else { /* error in specify section date */
1600: while ( ((c = getc(fp)) != '\n') && ( c != EOF) ); /* skip to end of line */
1601: }
1602: }
1603: result=num;
1604: }
1605: fclose(fp);
1606: }
1607: return (result);
1608: }
1609:
1610: /*----------------------------------------------------------*/
1611: /* INPUT: dates a pointer to the dates pointer */
1612: /* ACTION: frees a linked list of T_dates */
1613: /*----------------------------------------------------------*/
1614: void free_dates(T_dates *dates)
1615: {
1616: T_dates *current = dates,*next;
1617: while ( current != NULL ) {
1618: next = current->s_next;
1619: capa_mfree((char*)current);
1620: current = next;
1621: }
1622: }
1623:
1624: /*----------------------------------------------------------*/
1625: /* INPUT: set the X in dateX.db */
1626: /* dates a pointer to the dates pointer */
1627: /* ACTION: takes a linked list of date information and */
1628: /* and writes the info to a file */
1629: /* RETURN: -1 file error */
1630: /* 1 success */
1631: /*----------------------------------------------------------*/
1632: int capa_set_all_dates (int set,T_dates *dates)
1633: {
1634: T_dates *current = dates;
1635: int result;
1636: FILE* fp;
1637: char filename[FILE_NAME_LENGTH];
1638:
1639: sprintf(filename,"records/date%d.db",set);
1640: if ( ((fp=fopen(filename,"w")) == NULL) ) { result = -1; } else {
1641: result=1;
1642: while ( current != NULL ) {
1643: if ( current->section_start == DATE_DEFAULTS ) {
1644: fprintf(fp,"<< DEFAULTS >> ");
1645: } else {
1646: fprintf(fp,"[%d, %d] ", current->section_start,current->section_end);
1647: }
1648: fprintf(fp,"%s,%s,%s,%s %d,%d\n", current->open_date,current->due_date,
1649: current->answer_date,current->duration,current->inhibit_response,
1650: current->view_problems_after_due);
1651: current = current->s_next;
1652: }
1653: fclose(fp);
1654: }
1655: return result;
1656: }
1657:
1658: /*----------------------------------------------------------*/
1659: /* INPUT: set the X in logX.db */
1660: /* OUTPUT: none */
1661: /* */
1662: /* RETURN: -1 file error */
1663: /* 0 no login */
1664: /* >0 number of logins in that logX.db file */
1665: /*----------------------------------------------------------*/
1666:
1667: #define FIFTEEN_MINUTES (15*60)
1668: #define TEN_MINUTES (600)
1669: #define ONE_DAY (86400)
1670: int /* RETURNS: 1 first time login, 2 second time login, 0 not ok, -1 file error */
1671: login_check(student_number) /* ARGUMENTS: */
1672: char *student_number; /* Student # */
1673: { /* LOCALS: */
1674: FILE *fp;
1675:
1676: int errcode=0;
1677: int found;
1678: char filename[FILE_NAME_LENGTH];
1679: char line[SMALL_LINE_BUFFER], new_line[SMALL_LINE_BUFFER];
1680: struct tm *theDT;
1681: time_t login_time, record_time;
1682: long offsetL, offsetR, offsetEnd,left_leng;
1683: char s_number[MAX_STUDENT_NUMBER+1];
1684: char tty_name[FILE_NAME_LENGTH];
1685: int log_tries, p_id;
1686: int month, day, year, hour, min, sec;
1687: char *tmp_buffer;
1688:
1689: sprintf(filename,"records/active.log");
1690:
1691: if( capa_access(filename,F_OK) < 0 ) { /*<------------- File not exist */
1692: if ((fp=fopen(filename,"w"))==NULL) { /* create if non-existant */
1693: /*printf("Error: can't create %s\n",filename);*/
1694: return (-1);
1695: }
1696: fclose(fp);
1697: }
1698: if ((fp=fopen(filename,"r"))==NULL) {
1699: /*printf("Error: can't open %s\n",filename);*/
1700: return (-1);
1701: }
1702: flockstream(fp); /* lock exclusively and perform read/write operation */
1703:
1704: found = 0;
1705: while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) {
1706: if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1;
1707: }
1708: offsetR = ftell(fp);
1709: offsetL = offsetR - strlen(line);
1710: funlockstream(fp); fclose(fp);
1711:
1712: if( found && (strlen(line) != 0) ) {
1713: /* printf("FOUND:%slen=%d\n",line,strlen(line)); */
1714: sscanf(line,"%s , %d , %d , /dev/%s ,(%d/%d/%d %d:%d:%d)\n", s_number,&log_tries,&p_id,tty_name,&month,&day,&year,&hour,&min,&sec);
1715: record_time = time(NULL);
1716: theDT = localtime(&record_time);
1717: theDT->tm_sec = sec; theDT->tm_min = min;
1718: theDT->tm_hour = hour; theDT->tm_mday = day;
1719: theDT->tm_mon = month-1; theDT->tm_year = year;
1720: theDT->tm_wday = weekday(year,month,day);
1721: theDT->tm_yday = julianday(year,month,day);
1722: record_time = mktime( theDT );
1723: time(&login_time); theDT = localtime(&login_time);
1724: switch(log_tries) {
1725: case 0: log_tries = 1; errcode = 1; break;
1726: case 1: log_tries = 2; errcode = 2;
1727: break;
1728: case 2: log_tries = 3; errcode = 0; break;
1729: case 3: if( (login_time - record_time) >= TEN_MINUTES ) {
1730: log_tries = 1; errcode = 1;
1731: } else {
1732: log_tries = 3; errcode = 2;
1733: return (0);
1734: }
1735: break;
1736: default: printf("ERROR: Number of logins UNKNOWN\n");
1737: log_tries = 1; errcode = 1;
1738: break;
1739: }
1740: sprintf(new_line,"%s , %2d , %5d , %s ,(%02d/%02d/%02d %02d:%02d:%02d)\n", student_number, log_tries, getpid(),ttyname(0), theDT->tm_mon + 1, theDT->tm_mday, theDT->tm_year, theDT->tm_hour, theDT->tm_min ,theDT->tm_sec);
1741: if ((fp=fopen(filename,"r+"))==NULL) {
1742: /*printf("Error: can't open %s\n",filename);*/
1743: return (-1);
1744: }
1745: flockstream(fp);
1746: tmp_buffer = (char *)malloc(8*1024*56);
1747: found = 0;
1748: while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) {
1749: if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1;
1750: }
1751: offsetR = ftell(fp); offsetL = offsetR - strlen(line);
1752: fseek(fp,0L,SEEK_END); offsetEnd = ftell(fp);
1753: left_leng = offsetEnd - offsetR;
1754: fseek(fp,offsetR,SEEK_SET);
1755: left_leng = fread(tmp_buffer, 1, left_leng+1, fp);
1756: tmp_buffer[left_leng] = 0;
1757: fseek(fp,offsetL,SEEK_SET);
1758: if ( fprintf(fp,"%s%s",new_line,tmp_buffer) < 0 ) {
1759: /*printf("Error: cannot write active.log\n");*/
1760: errcode = -1;
1761: }
1762: fflush(fp);
1763: free( (char *)tmp_buffer);
1764: funlockstream(fp);
1765: fclose(fp);
1766: } else { /********************************** First time login */
1767: if ((fp=fopen(filename,"a+"))==NULL) {
1768: /*printf("Error: can't open %s\n",filename);*/
1769: return (-1);
1770: }
1771: log_tries = 1;
1772: time(&login_time);
1773: theDT = localtime(&login_time);
1774: sprintf(line,"%s , %2d , %5d , %s ,(%02d/%02d/%02d %02d:%02d:%02d)\n", student_number, log_tries, getpid(),ttyname(0), theDT->tm_mon + 1, theDT->tm_mday, theDT->tm_year, theDT->tm_hour, theDT->tm_min ,theDT->tm_sec);
1775: /*
1776: leng = strlen(line);
1777: for(idx = 0, len_idx = 0; idx<(leng-1); idx++) {
1778: if(line[idx] == '\n' && line[idx+1] == '\n') {
1779: line[idx+1] = 0;
1780: }
1781: }
1782: */
1783: flockstream(fp);
1784: if ( !fwrite((char *)line, strlen(line), 1, fp) ) {
1785: /*printf("ERROR: cannot write active.log\n");*/
1786: errcode = -1;
1787: } else {
1788: errcode = 1;
1789: }
1790: fflush(fp);
1791: funlockstream(fp);
1792: fclose(fp);
1793: }
1794: return (errcode);
1795:
1796: }
1797:
1798: /******************************************************************************/
1799: /* Logout check */
1800: /******************************************************************************/
1801: int /* RETURNS: 1 successful, 0 otherwise, -1 file error */
1802: logout_check(student_number) /* ARGUMENTS: */
1803: char *student_number; /* Student # */
1804: { /* LOCALS: */
1805: FILE *fp;
1806:
1807: int errcode=0;
1808: int found;
1809: char filename[FILE_NAME_LENGTH];
1810: char line[SMALL_LINE_BUFFER];
1811: long offsetL, offsetR, offsetEnd,left_leng;
1812: char s_number[MAX_STUDENT_NUMBER+1];
1813: char tty_name[FILE_NAME_LENGTH];
1814: int log_tries, p_id;
1815: int month, day, year, hour, min, sec;
1816: char *tmp_buffer;
1817:
1818:
1819: sprintf(filename,"records/active.log");
1820: if ((fp=fopen(filename,"r"))==NULL) {
1821: /*printf("Error: can't open %s\n",filename);*/
1822: return (-1);
1823: }
1824: flockstream(fp); /* lock exclusively and perform read/write operation */
1825:
1826: found = 0;
1827: while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) {
1828: if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1;
1829: }
1830: offsetR = ftell(fp);
1831: offsetL = offsetR - strlen(line);
1832:
1833: funlockstream(fp);
1834: fclose(fp);
1835:
1836: if( found ) {
1837: #ifdef __alpha
1838: sscanf(line,"%s , %d , %d , /dev/%s ,(%d/%d/%d %d:%d:%d)\n", s_number,&log_tries,&p_id,tty_name,&month,&day,&year,&hour,&min,&sec);
1839: #else
1840: sscanf(line,"%s , %d , %d , /dev/%s ,(%d/%d/%d %d:%d:%d)\n", \
1841: s_number,&log_tries,&p_id,tty_name,&month,&day,&year,&hour,&min,&sec);
1842: #endif
1843: switch(log_tries) {
1844: case 0: log_tries = 0;
1845: break;
1846: case 1: log_tries = 0;
1847: break;
1848: case 2: log_tries = 0;
1849: break;
1850: default: printf("ERROR: Number of logins UNKNOWN\n");
1851: log_tries = 0;
1852: break;
1853: }
1854: #ifdef __alpha
1855: sprintf(line,"%s , %2d , %5d , /dev/%s ,(%02d/%02d/%02d %02d:%02d:%02d)\n", s_number,log_tries, p_id, tty_name, month, day, year, hour, min, sec);
1856: #else
1857: sprintf(line,"%s , %2d , %5d , /dev/%s ,(%02d/%02d/%02d %02d:%02d:%02d)\n", \
1858: s_number,log_tries, p_id, tty_name, month, day, year, hour, min, sec);
1859: #endif
1860:
1861: if ((fp=fopen(filename,"r+"))==NULL) {
1862: /*printf("Error: can't open %s\n",filename);*/
1863: return (-1);
1864: }
1865: flockstream(fp);
1866: tmp_buffer = (char *)malloc(8*1024*56);
1867: fseek(fp,0L,SEEK_END);
1868: offsetEnd = ftell(fp);
1869: left_leng = offsetEnd - offsetR;
1870: fseek(fp,offsetR,SEEK_SET);
1871: fread(tmp_buffer, left_leng, 1, fp);
1872: tmp_buffer[left_leng] = 0;
1873: /*
1874: for(idx=0, l_idx = 0; idx< (left_leng-1); idx++) {
1875: if( tmp_buffer[idx] == '/n' && tmp_buffer[idx+1] == '/n' ) {
1876: }
1877: }
1878: */
1879: fseek(fp,offsetL,SEEK_SET);
1880: if ( fprintf(fp,"%s%s",line,tmp_buffer) < 0 ) {
1881: /*printf("Error: write error\n");*/
1882: errcode = -1;
1883: } else {
1884: errcode = 1;
1885: }
1886: fflush(fp);
1887: free( (char *)tmp_buffer);
1888: funlockstream(fp);
1889: fclose(fp);
1890: } else {
1891: errcode = -1;
1892: }
1893: return (errcode);
1894:
1895: }
1896: /*********************************************/
1897: /* SIZE of char =1, int=4, long=4, double=8 */
1898: void
1899: capa_seed(seed1,seed2,student_number)long *seed1;long *seed2;char *student_number;
1900: {
1901: int class_pin1, class_pin2;
1902: int s_pin1, s_pin2, s_pin3;
1903: int i;
1904: char dest[16], tmpSN[MAX_STUDENT_NUMBER+1];
1905: char *class,*capadefault="capadefault";
1906: long part1, part2;
1907: #if defined(NeXT)
1908: char cwd[FILE_NAME_LENGTH];
1909: #endif
1910: int big_endian;
1911:
1912: big_endian = endian(); /* determine what type of CPU we are on */
1913:
1914: #if defined(NeXT)
1915: class = getwd(cwd);
1916: if( class == NULL ) { class = cwd; }
1917: #else
1918: class = getcwd(NULL,255);
1919: #endif
1920: class_pin1 = class_pin2 = 2;
1921: s_pin1 = s_pin2 = s_pin3 = 2;
1922:
1923: if( class == NULL ) {
1924: printf("capa_seed(): Current working directory unknown! Using capadefault\n");
1925: class=capa_malloc(strlen(capadefault)+1,1);
1926: strcpy(class,capadefault);
1927: }
1928: if( big_endian ) {
1929: for(i=0;i<4;i++) dest[i] = class[strlen(class)-8+i];
1930: for(i=4;i<8;i++) dest[i] = 0;
1931: memcpy((char *)(&class_pin1), dest, 4);
1932: for(i=0;i<4;i++) dest[i] = class[strlen(class)-4+i];
1933: for(i=4;i<8;i++) dest[i] = 0;
1934: memcpy((char *)(&class_pin2), dest, 4);
1935: } else {
1936: for(i=0;i<4;i++) dest[i] = class[strlen(class)-i-5];
1937: for(i=4;i<8;i++) dest[i] = 0;
1938: memcpy((char *)(&class_pin1), dest, 4);
1939: for(i=0;i<4;i++) dest[i] = class[strlen(class)-i-1];
1940: for(i=4;i<8;i++) dest[i] = 0;
1941: memcpy((char *)(&class_pin2), dest, 4);
1942: }
1943: for(i=0;i<MAX_STUDENT_NUMBER;i++) {
1944: if(islower(student_number[i])) {
1945: tmpSN[i] = toupper(student_number[i]);
1946: } else {
1947: tmpSN[i] = student_number[i];
1948: }
1949: }
1950: tmpSN[MAX_STUDENT_NUMBER] = 0;
1951:
1952: if( big_endian ) { /* big endian ** SUN, BlackNeXT 68xxx , PowerPC */
1953: for(i=0;i<4;i++) dest[i] = tmpSN[i];
1954: for(i=4;i<8;i++) dest[i] = 0;
1955: memcpy((char *)(&s_pin1), dest, 4); /* 012345678 -> "0123" */
1956: for(i=0;i<4;i++) dest[i] = tmpSN[i+2];
1957: for(i=4;i<8;i++) dest[i] = 0;
1958: memcpy((char *)(&s_pin2), dest, 4); /* 012345678 -> "2345" */
1959: for(i=0;i<4;i++) dest[i] = tmpSN[i+5];
1960: for(i=4;i<8;i++) dest[i] = 0;
1961: memcpy((char *)(&s_pin3), dest, 4); /* 012345678 -> "5678" */
1962: } else { /* Intel 386, 486 */
1963: for(i=0;i<4;i++) dest[i] = tmpSN[3-i];
1964: for(i=4;i<8;i++) dest[i] = 0;
1965: memcpy((char *)(&s_pin1), dest, 4); /* 012345678 -> "0123" */
1966: for(i=0;i<4;i++) dest[i] = tmpSN[5-i];
1967: for(i=4;i<8;i++) dest[i] = 0;
1968: memcpy((char *)(&s_pin2), dest, 4); /* 012345678 -> "2345" */
1969: for(i=0;i<4;i++) dest[i] = tmpSN[8-i];
1970: for(i=4;i<8;i++) dest[i] = 0;
1971: memcpy((char *)(&s_pin3), dest, 4); /* 012345678 -> "5678" */
1972: }
1973:
1974:
1975: part1 = s_pin1 + s_pin3+ class_pin2; if(part1 < 0) part1 = part1 * (-1);
1976: part2 = s_pin2 + class_pin1; if(part2 < 0) part2 = part2 * (-1);
1977:
1978: #ifdef SEED_DBG
1979: printf("S_PIN(%d,%d, %d) C_PIN(%d,%d)\n",s_pin1, s_pin2, s_pin3, class_pin1, class_pin2);
1980: printf("SEED(%ld,%ld)\n",part1, part2);
1981: #endif
1982: {
1983: extern void gsrgs(long getset,long *qvalue);
1984: static long qrgnin;
1985: gsrgs(0L,&qrgnin);
1986: if(!qrgnin)
1987: setall(part1, part2);
1988: }
1989: (*seed1) = part1;
1990: (*seed2) = part2;
1991: free(class);
1992: }
1993: /* ======================================================= PIN number */
1994: /* pin should only called once for each student. */
1995: /* if not called at the beginning of problem set, try to call it automatically */
1996:
1997: int /* RETURNS: pin number for login set */
1998: capa_PIN(student_number, set, guess) /* ARGUMENTS: */
1999: char *student_number;
2000: int set; /* Problem set number */
2001: int guess;
2002: { /* LOCALS: */
2003: int current=0, /* Current pin for set */
2004: i,j, /* Array indices */
2005: nope,
2006: correct=0,
2007: all_pins[ONE_K];
2008: long part1, part2;
2009: long orig_gen, new_gen;
2010:
2011: capa_seed(&part1, &part2, student_number);
2012: gscgn(GET_GENERATOR, &orig_gen);
2013: new_gen = PIN_G;
2014: gscgn(SET_GENERATOR, &new_gen);
2015: setsd(part1, part2);
2016: /* Generate 4-digit pin (1000-9999) */
2017: for (i=1; i<=set; i++) {
2018: current=1000+ignlgi()%9000;
2019: do {
2020: nope=0;
2021: for (j=1; j<i; j++) {
2022: if (current == all_pins[j]) {
2023: current=1000+ignlgi()%9000;
2024: nope++;
2025: }
2026: }
2027: } while (nope);
2028: all_pins[i]=current;
2029: if (guess && guess==current) correct=i;
2030: }
2031: gscgn(SET_GENERATOR, &orig_gen);
2032: if (guess) return (correct);
2033: return (current);
2034: }
2035:
2036: /* -------------------------------------------------------------------- */
2037: /* returns a longer pin, the first four characters are the same as the */
2038: /* normal capaId, additionally the result is a capa_malloc string */
2039: /* containing the number */
2040: /* NOTE!-> the result is a string of letters where A=1..I=9,J=0 */
2041: /* -------------------------------------------------------------------- */
2042: char*
2043: capa_id_plus(student_number, set, plus)
2044: char *student_number;
2045: int set;
2046: int plus;
2047: {
2048: long part1,part2,orig_gen,new_gen,pin,rout,k,i;
2049: char *result;
2050: char letters[10]={'J','A','B','C','D','E','F','G','H','I'};
2051: capa_seed(&part1, &part2, student_number);
2052: gscgn(GET_GENERATOR, &orig_gen);
2053: new_gen = PIN_G;
2054: gscgn(SET_GENERATOR, &new_gen);
2055: setsd(part1, part2);
2056: pin=capa_PIN(student_number,set,0);
2057: result=(char *)capa_malloc(sizeof(char), plus+MAX_PIN_CHAR+1);
2058: k=1;
2059: for(i=1;i<=MAX_PIN_CHAR;i++) {
2060: result[MAX_PIN_CHAR-i] = letters[(pin%(k*10))/k];
2061: k*=10;
2062: }
2063: for(i=MAX_PIN_CHAR;i<MAX_PIN_CHAR+plus;i++) {
2064: rout = ignlgi()%10;
2065: result[i] = letters[rout];
2066: }
2067: result[i] = '\0';
2068: gscgn(SET_GENERATOR, &orig_gen);
2069: return result;
2070: }
2071: /* -------------------------------------------------------------------- */
2072: /* need to set problem_p = NULL after this call */
2073: /* -------------------------------------------------------------------- */
2074: void
2075: free_problems(problem_p) Problem_t *problem_p;
2076: {
2077: Problem_t *p, *next;
2078:
2079: for (p=problem_p; p!=NULL ; p=next) {
2080: next=p->next;
2081: if (p->question != NULL) capa_mfree(p->question);
2082: if (p->answer != NULL) capa_mfree(p->answer);
2083: if (p->ans_cnt > 1 ) { AnswerInfo_t *a,*b;
2084: for(a = p->ans_list; a != NULL ; a = b) {
2085: b = a->ans_next;
2086: if (a->ans_str != NULL) capa_mfree(a->ans_str);
2087: if (a->ans_id_list != NULL ) capa_mfree(a->ans_id_list);
2088: if (a->ans_pts_list) {
2089: free_ptslist(a->ans_pts_list);
2090: }
2091: if (a->ans_unit) {
2092: freelist_unit_e(a->ans_unit->u_list);
2093: if (a->ans_unit != NULL) capa_mfree((char *)a->ans_unit);
2094: }
2095: capa_mfree((char *)a);
2096: }
2097: }
2098: if (p->id_list != NULL ) capa_mfree(p->id_list);
2099: if (p->pts_list!= NULL ) {
2100: free_ptslist(p->pts_list);
2101: }
2102: if (p->hint != NULL ) capa_mfree(p->hint);
2103: if (p->explain != NULL ) capa_mfree(p->explain);
2104: if (p->ans_unit !=NULL ) {
2105: freelist_unit_e(p->ans_unit->u_list);
2106: capa_mfree((char *)p->ans_unit);
2107: }
2108: capa_mfree((char *)p);
2109: p=NULL;
2110: }
2111: problem_p=NULL;
2112: }
2113:
2114: /******************************************************************************/
2115: /* PARSE SOURCE FILE AND RETURN BLOCKS OF TEXT */
2116: /******************************************************************************/
2117: int
2118: capa_parse(set,problem,student_number,num_questions,func_ptr)
2119: int set;Problem_t **problem;char *student_number;int *num_questions;
2120: void (*func_ptr)();
2121: {
2122: char filename[QUARTER_K];
2123: int errcode;
2124: FILE *fp;
2125: extern FILE *Input_stream[MAX_OPENED_FILE];
2126: extern char Opened_filename[MAX_OPENED_FILE][QUARTER_K];
2127: extern int Lexi_line;
2128: extern int Lexi_qnum;
2129: extern Problem_t *FirstProblem_p;
2130: extern Problem_t *LastProblem_p;
2131: extern Problem_t *LexiProblem_p;
2132: extern char *StartText_p;
2133: extern char *EndText_p;
2134: extern char *ErrorMsg_p;
2135: extern int ErrorMsg_count;
2136: extern char Parse_class[QUARTER_K];
2137: extern int Parse_section;
2138: extern int Parse_set;
2139: extern char Parse_name[MAX_NAME_CHAR+1];
2140: extern char Parse_student_number[MAX_STUDENT_NUMBER+1];
2141: extern int Symb_count;
2142: extern int first_run;
2143: extern int Stop_Parser;
2144: extern void (*Status_Func)();
1.11 albertel 2145: #ifdef TTH
2146: extern void tth_restart();
2147: extern char* tth_err;
2148: #endif /*TTH*/
1.1 albertel 2149: long seed1, seed2;
2150: T_student a_student;
2151: char *class, *classname, warn_msg[WARN_MSG_LENGTH];
2152: #if defined(NeXT)
2153: char cwd[FILE_NAME_LENGTH];
2154:
2155: class = getwd(cwd);
2156: if( class == NULL ) { class = cwd; }
2157: #else
2158: class = getcwd(NULL,255);
2159:
2160: #endif
2161:
2162: if(class == NULL) { /* printf("capa_parse(): Current working directory unknown!"); */ return (-1); }
2163: classname = rindex(class,'/'); classname++; /*** hpux complained */
2164: sprintf(Parse_class,"%s", classname);
2165: free(class);
2166: if( capa_get_student(student_number, &a_student) < 1 ) {
2167: /*printf("Error: capa_parse() encountered a student which is not in classl file\n"); */
2168: return (-1);
2169: }
2170: sprintf(filename,"capa.config");
2171: if ((fp=fopen(filename,"r"))==NULL) {
2172: /* printf("Error: can't open %s\n",filename);*/
2173: return (-1);
2174: }
2175: u_getunit(fp);
2176: fclose(fp);
1.11 albertel 2177: #ifdef TTH
2178: if(tth_err) { free(tth_err); tth_err=NULL; }
2179: tth_restart();
2180: #endif /*TTH*/
1.1 albertel 2181: strncpy(Parse_name,a_student.s_nm,MAX_NAME_CHAR+1);
2182: strncpy(Parse_student_number,student_number,MAX_STUDENT_NUMBER+1);
2183: Parse_section = a_student.s_sec;
2184: if(ErrorMsg_p) { capa_mfree(ErrorMsg_p); ErrorMsg_p = NULL; }
2185: if(EndText_p) { capa_mfree(EndText_p); EndText_p = NULL; }
2186: if(StartText_p) { capa_mfree(StartText_p); StartText_p = NULL; }
2187: ErrorMsg_p = NULL; first_run = 1; EndText_p = NULL;
2188: free_symtree(); Symb_count = ErrorMsg_count = Lexi_line = Lexi_qnum = 0;
2189: FirstProblem_p = LastProblem_p = NULL;
2190: LexiProblem_p = (Problem_t *)capa_malloc(sizeof(Problem_t),1);
2191: problem_default(LexiProblem_p);
2192: /*LexiProblem_p->capaidplus=NULL;*/
2193: Parse_set = set;
2194: Status_Func=func_ptr;
2195: sprintf(filename,"set%d.qz",set);
2196: #ifdef AVOIDYYINPUT
2197: yyin=fopen(filename,"r");
2198: #else
2199: if ( (Input_stream[0]=fopen(filename,"r")) == NULL) {
2200: /* printf("Error: can't open %s\n",filename);*/
2201: sprintf(warn_msg,"capa_parse(): CANNOT OPEN FILE\"%s\", file does not exist or is not readable.\n", filename);
2202: capa_msg(MESSAGE_ERROR,warn_msg);
2203: return (-1);
2204: }
2205: #endif
2206: sprintf(Opened_filename[0],"%s",filename);
2207:
2208: capa_seed(&seed1, &seed2, student_number); setall(seed1,seed2);
2209:
2210: yyrestart(yyin);
2211: Stop_Parser=0;
2212: if ( !yyparse() ) { errcode = Lexi_qnum; } else { errcode = 0; }
2213: /* fclose(Input_stream[0]);*/ /* The Lexer handles closing this */
2214: /* print_symb_stat(); */
2215: free_symtree();
2216: /*
2217: capa_mfree((char *)LexiProblem_p);
2218: LexiProblem_p = NULL;
2219: */
2220: (*problem) = FirstProblem_p;
2221: (*num_questions) = Lexi_qnum;
2222: return (errcode);
2223: }
2224:
2225: /******************************************************************************/
2226: /* PARSE SOURCE FILE AND RETURN BLOCKS OF TEXT, unlike capa_parse_student */
2227: /******************************************************************************/
2228: int
2229: capa_parse_student(set,problem,a_student,num_questions,func_ptr)
2230: int set;Problem_t **problem;T_student *a_student;int *num_questions;
2231: void (*func_ptr)();
2232: {
2233: char filename[QUARTER_K];
2234: int errcode;
2235: FILE *fp;
2236: extern FILE *Input_stream[MAX_OPENED_FILE];
2237: extern char Opened_filename[MAX_OPENED_FILE][QUARTER_K];
2238: extern int Lexi_line;
2239: extern int Lexi_qnum;
2240: extern Problem_t *FirstProblem_p;
2241: extern Problem_t *LastProblem_p;
2242: extern Problem_t *LexiProblem_p;
2243: extern char *StartText_p;
2244: extern char *EndText_p;
2245: extern char *ErrorMsg_p;
2246: extern int ErrorMsg_count;
2247: extern char Parse_class[QUARTER_K];
2248: extern int Parse_section;
2249: extern int Parse_set;
2250: extern char Parse_name[MAX_NAME_CHAR+1];
2251: extern char Parse_student_number[MAX_STUDENT_NUMBER+1];
2252: extern int Symb_count;
2253: extern int first_run;
2254: extern void (*Status_Func)();
2255: long seed1, seed2;
2256: char *class, *classname, warn_msg[WARN_MSG_LENGTH];
2257:
2258: #if defined(NeXT)
2259: char cwd[FILE_NAME_LENGTH];
2260:
2261: class = getwd(cwd);
2262: if( class == NULL ) { class = cwd; }
2263: #else
2264: class = getcwd(NULL,255);
2265:
2266: #endif
2267:
2268: if(class == NULL) { /* printf("capa_parse(): Current working directory unknown!"); */ return (-1); }
2269: classname = rindex(class,'/'); classname++; /*** hpux complained */
2270: sprintf(Parse_class,"%s", classname);
2271: free(class);
2272:
2273: sprintf(filename,"capa.config");
2274: if ((fp=fopen(filename,"r"))==NULL) {
2275: /* printf("Error: can't open %s\n",filename);*/
2276: sprintf(warn_msg,"capa_parse(): CANNOT OPEN FILE\"%s\", file does not exist or is not readable.\n", filename);
2277: capa_msg(MESSAGE_ERROR,warn_msg);
2278: return (-1);
2279: }
2280: u_getunit(fp);
2281: fclose(fp);
2282: strncpy(Parse_name,a_student->s_nm,MAX_NAME_CHAR+1);
2283: strncpy(Parse_student_number,a_student->s_sn,MAX_STUDENT_NUMBER+1);
2284: Parse_section = a_student->s_sec;
2285: if(ErrorMsg_p) { capa_mfree(ErrorMsg_p); ErrorMsg_p = NULL; }
2286: if(EndText_p) { capa_mfree(EndText_p); EndText_p = NULL; }
2287: if(StartText_p) { capa_mfree(StartText_p); StartText_p = NULL; }
2288: ErrorMsg_p = NULL; first_run = 1; EndText_p = NULL;
2289: free_symtree(); Symb_count = ErrorMsg_count = Lexi_line = Lexi_qnum = 0;
2290: FirstProblem_p = LastProblem_p = NULL;
2291: LexiProblem_p = (Problem_t *)capa_malloc(sizeof(Problem_t),1);
2292: problem_default(LexiProblem_p);
2293: /*LexiProblem_p->capaidplus=NULL;*/
2294: Parse_set = set;
2295: Status_Func=func_ptr;
2296: sprintf(filename,"set%d.qz",set);
2297: #ifdef AVOIDYYINPUT
2298: yyin=fopen(filename,"r");
2299: #else
2300: if ( (Input_stream[0]=fopen(filename,"r")) == NULL) {
2301: /* printf("Error: can't open %s\n",filename);*/
2302: sprintf(warn_msg,"capa_parse(): CANNOT OPEN FILE\"%s\", file does not exist or is not readable.\n", filename);
2303: capa_msg(MESSAGE_ERROR,warn_msg);
2304: return (-1);
2305: }
2306: #endif
2307: sprintf(Opened_filename[0],"%s",filename);
2308:
2309: capa_seed(&seed1, &seed2, a_student->s_sn); setall(seed1,seed2);
2310:
2311: yyrestart(yyin);
2312: if ( !yyparse() ) { errcode = Lexi_qnum; } else { errcode = 0; }
2313: /* fclose(Input_stream[0]);*/ /*The Lexer handles closing this*/
2314: /* print_symb_stat(); */
2315: free_symtree();
2316: /*
2317: capa_mfree((char *)LexiProblem_p);
2318: LexiProblem_p = NULL;
2319: */
2320: (*problem) = FirstProblem_p;
2321: (*num_questions) = Lexi_qnum;
2322: return (errcode);
2323: }
2324:
2325: /* =================================================================== */
2326: /* A utility method to convert a date string and time string to time_t */
2327: /* dateStr: yyyy/mm/dd */
2328: /* timeStr: hh:mm */
2329: time_t
2330: convertTime(dateStr,timeStr)char *dateStr; char *timeStr;
2331: {
2332: struct tm *theTimeData;
2333: time_t result;
2334: int dateTime[5];
2335: int year, month, day, mm, hh;
2336:
2337: sscanf(dateStr,"%4d/%2d/%2d",&year,&month,&day);
2338: dateTime[0] = month;
2339: dateTime[1] = day;
2340: dateTime[2] = year;
2341: sscanf(timeStr,"%2d:%2d",&hh,&mm);
2342: dateTime[3] = hh;
2343: dateTime[4] = mm;
2344: result = time(NULL);
2345: theTimeData = localtime(&result);
2346: theTimeData->tm_sec = 0;
2347: theTimeData->tm_min = dateTime[4];
2348: theTimeData->tm_hour = dateTime[3];
2349: theTimeData->tm_mday = dateTime[1];
2350: theTimeData->tm_mon = dateTime[0]-1;
2351: theTimeData->tm_year = dateTime[2]-1900;/* tm_year is years since 1900 */
2352: /* these fields are ignored by mktime
2353: theTimeData->tm_wday = weekday(year,month,day);
2354: theTimeData->tm_yday = julianday(year,month,day);
2355: */
2356: result = mktime( theTimeData );
2357: return (result);
2358: }
2359:
2360: int
2361: weekday( year, month, day) int year; int month; int day;
2362: {
2363: register int dow;
2364: #if defined(hpux)
2365: int juldays[13];
2366: juldays[0]=0;juldays[1]=0;juldays[2]=31;juldays[3]=59;
2367: juldays[4]=90;juldays[5]=120;juldays[6]=151;juldays[7]=181;
2368: juldays[8]=212;juldays[9]=243;juldays[10]=273;juldays[11]=304;juldays[12]=334;
2369: #else
2370: int juldays[13] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
2371: #endif
2372:
2373: dow = 7 + year + year/4 - year/100 + year/400 + juldays[month] + day;
2374: if( (month < 3) && ( leap_year(year) ) ) dow--;
2375: dow %= 7;
2376: return (dow);
2377: } /* weekday */
2378:
2379: int
2380: julianday( year, month, day)int year;int month;int day;
2381: {
2382: register int doy;
2383: #if defined(hpux)
2384: int juldays[13];
2385: juldays[0]=0;juldays[1]=0;juldays[2]=31;juldays[3]=59;
2386: juldays[4]=90;juldays[5]=120;juldays[6]=151;juldays[7]=181;
2387: juldays[8]=212;juldays[9]=243;juldays[10]=273;juldays[11]=304;juldays[12]=334;
2388: #else
2389: int juldays[13] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
2390: #endif
2391:
2392: doy = juldays[month];
2393: if((month > 2) && (leap_year(year)) ) doy++;
2394: doy += day;
2395: return (doy);
2396: } /* julianday */
2397:
2398: int
2399: check_int( an_int ) char *an_int;
2400: {
2401: int ii, leng;
2402: int result=0;
2403:
2404: if( (an_int[0] == '-') || (an_int[0]== '+') ) an_int++;
2405: leng = strlen(an_int);
2406: for(ii=0;ii<leng;ii++) {
2407: if( !isdigit(an_int[ii]) ) result = 1;
2408: }
2409: return (result);
2410: }
2411: /* --------------------------- */
2412: /* 0 OK , 1 NOT a real number */
2413: int
2414: check_real( a_real ) char *a_real;
2415: {
2416: int ii, leng;
2417: int result=0;
2418:
2419: if( (a_real[0] == '-') || (a_real[0]== '+') ) a_real++;
2420: leng = strlen(a_real);
2421: for(ii=0;ii<leng;ii++) {
2422: if( (!isdigit(a_real[ii])) && (a_real[ii]!='e') && (a_real[ii]!='E') &&
2423: (a_real[ii]!='.') && (a_real[ii]!='+') && (a_real[ii]!='-') ) result = 1;
2424: }
2425: return (result);
2426: }
2427:
2428: int
2429: check_input_usymb(u_symb)char *u_symb;
2430: {
2431: int result=0;
2432:
2433:
2434: return (result);
2435: }
2436:
2437: /* <== This routine determine emperically where to split a character */
2438: /* string into two portions, one for numerical answer and the */
2439: /* other for units */
2440: /* ----------------------------------------------------------------- */
2441: /* inputs : buf : answer string */
2442: /* outputs: num : the numerical part */
2443: /* num_p : the numerical part in string */
2444: /* unit_p : the unit string */
2445: /* num_p is used to calculate sig figs */
2446: /* return : 0 empty string */
2447: /* 1 number without units */
2448: /* 2 empty number with units */
2449: /* 3 number with units */
2450: /* */
2451: int split_num_unit(buf,num,num_p,unit_p)
2452: char *buf;double *num; char *num_p; char *unit_p;
2453: {
2454: char num_str[ANSWER_STRING_LENG], unit_str[ANSWER_STRING_LENG];
2455: char base_str[ANSWER_STRING_LENG], exp_str[ANSWER_STRING_LENG];
2456: int idx=0, errcode=0;
2457: int len, ii, n_idx=0, b_idx=0, e_idx=0, u_idx=0;
2458: double n_part, x_part, b_part, e_part, result;
2459:
2460: unit_str[0]=0; /* initialize unit_str[] */
2461: len = strlen(buf);
2462: while( isspace(buf[idx]) ) { idx++; } /* ignore white spaces */
2463: num_str[n_idx]=0; /* initialize number string */
2464: if( buf[idx] == '+' || buf[idx] == '-' ) {
2465: /* the first char is either '+' or '-' */
2466: num_str[n_idx++]= buf[idx++];
2467: }
2468: /* skip over alphabet char and those that are not '.' */
2469: while( (!isdigit( buf[idx] )) && buf[idx] != '.' ) { idx++; }
2470: while( isdigit( buf[idx] ) || buf[idx] == '.' ) { /* collect decimal numbers */
2471: num_str[n_idx++]= buf[idx++];
2472: }
2473: num_str[n_idx] = 0; /* end the string with a '\0' */
2474: sprintf(num_p,"%s",num_str); /* put the collected numerical string in num_p */
2475: /* skip over white spaces */
2476: while( isspace(buf[idx]) ) { idx++; }
2477: if( buf[idx] == 'e' || buf[idx] == 'E' ) { /* optional e or E part */
2478: /* peek further one char to see if it belongs to one of the following */
2479: if( buf[idx+1] == '-' || buf[idx+1] == '+' || isspace(buf[idx+1]) || isdigit(buf[idx+1])) {
2480: num_str[n_idx++] = buf[idx++]; /* should be 'e' or 'E' */
2481: while( isspace(buf[idx]) ) { idx++; } /* skip over spaces */
2482: num_str[n_idx++] = buf[idx++]; /* the second char '-', '+' or digit */
2483: while( isdigit(buf[idx]) ) { /* only integer is allowed, not '.' */
2484: num_str[n_idx++] = buf[idx++];
2485: }
2486: }
2487: num_str[n_idx] = 0; /* terminiate the numerical string */
2488: while( isspace(buf[idx]) ) { idx++; }
2489: sscanf(num_str, "%lg", &result); /* put the numerical value into a double variable */
2490: errcode = errcode | 1;
2491: } else if( buf[idx] == 'x' || buf[idx] == 'X') { /* optional x or X part */
2492: idx++; /* skip x or X */
2493: while( isspace(buf[idx]) ) { idx++; }
2494:
2495: e_part = 1.0; /* default power */
2496: base_str[b_idx] = 0; /* initialize base_str[] */
2497: while( isdigit(buf[idx]) || buf[idx] == '.' ) { /* should start with a digit or . */
2498: base_str[b_idx++] = buf[idx++];
2499: }
2500: base_str[b_idx] = 0; /* terminate base_str[] */
2501: while( isspace(buf[idx]) ) { idx++; } /* skip over white spaces */
2502: if( buf[idx] == '^' ) { /* power */
2503: idx++;
2504: exp_str[e_idx] = 0; /* initialize exp_str[] */
2505: while( isspace(buf[idx]) ) { idx++; }
2506: if( buf[idx] == '{'|| buf[idx] == '(' ) { /* matching right bracket */
2507: idx++;
2508: }
2509: while( isspace(buf[idx]) ) { idx++; }
2510: if( isdigit(buf[idx]) || buf[idx] == '+' || buf[idx] == '-' ) {
2511: exp_str[e_idx] = 0; /* initialize exp_str[], again */
2512: while( isdigit(buf[idx]) || buf[idx] == '.' || buf[idx] == '+' || buf[idx] == '-' ) {
2513: exp_str[e_idx++] = buf[idx++];
2514: }
2515: exp_str[e_idx] = 0; /* terminate exp_str[] */
2516: }
2517: while( isspace(buf[idx]) ) { idx++; }
2518: if( buf[idx] == '}' || buf[idx] == ')' ) {
2519: idx++;
2520: }
2521: sscanf(exp_str, "%lg", &e_part);
2522: }
2523: if( strlen(base_str) > 0 ) {
2524: sscanf(base_str, "%lg", &b_part);
2525: x_part = pow(b_part, e_part);
2526: } else {
2527: x_part = 0.0;
2528: }
2529: if( strlen(num_str) > 0 ) {
2530: sscanf(num_str, "%lg", &n_part);
2531: } else {
2532: n_part=0.0;
2533: }
2534: result = n_part * x_part;
2535: errcode = errcode | 1;
2536: } else if ( buf[idx] == '^' ) { /* number ^ */
2537: idx++;
2538: e_part = 1.0;
2539: while( isspace(buf[idx]) ) { idx++; }
2540: if( buf[idx] == '{'|| buf[idx] == '(' ) { /* matching right bracket */
2541: idx++;
2542: }
2543: while( isspace(buf[idx]) ) { idx++; }
2544: if( isdigit(buf[idx]) || buf[idx] == '+' || buf[idx] == '-' ) {
2545: exp_str[e_idx] = 0;
2546: while( isdigit(buf[idx]) || buf[idx] == '.' || buf[idx] == '+' || buf[idx] == '-' ) {
2547: exp_str[e_idx++] = buf[idx++];
2548: }
2549: exp_str[e_idx] = 0;
2550: }
2551: while( isspace(buf[idx]) ) { idx++; }
2552: if( buf[idx] == '}' || buf[idx] == ')' ) {
2553: idx++;
2554: }
2555: sscanf(exp_str, "%lg", &e_part);
2556: sscanf(num_str, "%lg", &n_part);
2557: result = pow(n_part,e_part);
2558: errcode = errcode | 1;
2559: } else { /* number unit */
2560: if( strlen(num_str) > 0 ) {
2561: sscanf(num_str, "%lg", &result);
2562: errcode = errcode | 1;
2563: }
2564: }
2565:
2566: if( idx < len ) { /* collect the rest as unit string */
2567: for(ii=idx;ii< len; ii++ ) {
2568:
2569: unit_str[u_idx++] = buf[ii];
2570: }
2571: unit_str[u_idx]=0; /* terminate unit_str[] */
2572: if(u_idx>0) {
2573: errcode = errcode | 2;
2574: }
2575: }
2576: if( strlen(num_str) > 0 ) {
2577: *num = result;
2578: } else { /* empty number string */
2579: *num = 0.0;
2580: }
2581: sprintf(unit_p,"%s", unit_str);
2582: return (errcode);
2583: }
2584:
2585: char *
2586: answers_string(mode, p)int mode;Problem_t *p;
2587: {
2588: char *fmted_ans, lower[ANSWER_STRING_LENG], upper[ANSWER_STRING_LENG];
2589: char *str_aa, *str_bb, *str_cc, *ans_str, *sub_ans_str, *tmp_str;
2590: int len_aa=0, len_bb=0, len_cc=0,len_dd=0, total_len, num_answer;
2591: double d_answer;
2592:
2593: if( p->ans_type == ANSWER_IS_SUBJECTIVE ) {
2594: char *a="Subjective Answer\n";
2595: ans_str = (char *)capa_malloc(strlen(a)+1,1);
2596: strcpy(ans_str,a);
2597: return (ans_str);
2598: }
2599: num_answer = calc_ansrange(p->ans_type,p->calc, p->answer, p->ans_fmt, p->tol_type,
2600: p->tolerance, lower, upper);
2601:
2602: if( p->ans_type == ANSWER_IS_FLOAT ) {
2603: fmted_ans = capa_malloc(SMALL_LINE_BUFFER,1);
2604: d_answer = (double)atof(p->answer);
2605: sprintf(fmted_ans,p->ans_fmt,d_answer);
2606: } else {
2607: fmted_ans = capa_malloc(strlen(p->answer)+2,1);
2608: strcpy(fmted_ans,p->answer);
2609: }
2610:
2611: len_aa = strlen(fmted_ans);
2612: if (lower != NULL ) len_bb = strlen(lower); else len_bb = 0;
2613: if (upper != NULL ) len_cc = strlen(upper); else len_cc = 0;
2614: if ( p->unit_str != NULL ) len_dd = strlen(p->unit_str); else len_dd = 0;
2615:
2616: switch(mode) {
2617: case TeX_MODE:
2618: if(num_answer==2) {
2619: /* 16 is by adding up characters ' [,] \n\n' and others */
2620: str_aa = format_toTeX(fmted_ans);
2621: total_len = strlen(str_aa) + len_dd + 16;
2622: str_bb = format_toTeX(lower);
2623: total_len += strlen(str_bb);
2624: str_cc = format_toTeX(upper);
2625: total_len += strlen(str_cc);
2626: ans_str = (char *)capa_malloc(total_len,1);
2627: if(len_dd == 0 ) { /* no unit_str */
2628: sprintf(ans_str," %s [%s,%s]\n\n", str_aa,str_bb,str_cc);
2629: } else {
2630: sprintf(ans_str," %s [%s,%s] $%s$\n\n", str_aa,str_bb,str_cc,p->unit_str);
2631: }
2632: capa_mfree((char *)str_aa);
2633: capa_mfree((char *)str_bb);
2634: capa_mfree((char *)str_cc);
2635: } else { /* only one answer */
2636: if ( (p->ans_type == ANSWER_IS_INTEGER) ||
2637: (p->ans_type == ANSWER_IS_FLOAT )) {
2638: str_bb = format_toTeX(lower);
2639: } else { /* answer could be string, choice */
2640: str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1);
1.10 albertel 2641: if (p->verbatim == DO_VERBATIM)
1.1 albertel 2642: sprintf(str_bb,"\\begin{verbatim}%s\\end{verbatim}",lower);
2643: else
2644: strcpy(str_bb,lower);
2645: }
2646: total_len = strlen(str_bb) + len_dd + 8;
2647: /* 4 is by adding up characters ' \\\n' plus four */
2648: ans_str = (char *)capa_malloc(sizeof(char),total_len);
2649: if(len_dd == 0 ) { /* no unit_str */
2650: sprintf(ans_str," %s\n", str_bb);
2651: } else {
2652: sprintf(ans_str," %s $%s$\n", str_bb,p->unit_str);
2653: }
2654: capa_mfree((char *)str_bb);
2655: }
2656: break;
2657: case ASCII_MODE:
2658: total_len = len_aa + len_bb + len_cc + len_dd + 8;
2659: /* 8 is by adding up characters ' [,] \n\n' plus one */
2660: ans_str = (char *)capa_malloc(sizeof(char),total_len);
2661: if(num_answer==2) {
2662: if(len_dd == 0 ) { /* no unit_str */
2663: sprintf(ans_str,"%s [%s,%s]\n\n", fmted_ans,lower,upper);
2664: } else {
2665: sprintf(ans_str,"%s [%s,%s] %s\n\n", fmted_ans,lower,upper,p->unit_str);
2666: }
2667: } else {
2668: if(len_dd == 0 ) { /* no unit_str */
2669: sprintf(ans_str,"%s\n\n", lower);
2670: } else {
2671: sprintf(ans_str,"%s %s\n\n", lower,p->unit_str);
2672: }
2673: }
2674: break;
2675: case ANSWER_STRING_MODE:
2676: total_len = len_aa + len_bb + len_cc + len_dd + 8;
2677: /* 8 is by adding up characters ' [,] \n\n' plus one */
2678: ans_str = (char *)capa_malloc(sizeof(char),total_len);
2679: if(num_answer==2) {
2680: if(len_dd == 0 ) { /* no unit_str */
2681: sprintf(ans_str,"%s", fmted_ans);
2682: } else {
2683: sprintf(ans_str,"%s %s", fmted_ans,p->unit_str);
2684: }
2685: } else {
2686: if(len_dd == 0 ) { /* no unit_str */
2687: sprintf(ans_str,"%s", lower);
2688: } else {
2689: sprintf(ans_str,"%s %s", lower,p->unit_str);
2690: }
2691: }
2692: break;
2693: case HTML_MODE:
2694: if(num_answer==2) { /* this indicates that answer should be either float or int
2695: */
2696: str_aa = format_toHTML(fmted_ans);
2697: total_len = strlen(str_aa) + len_dd + 8;
2698: str_bb = format_toHTML(lower);
2699: total_len += strlen(str_bb);
2700: str_cc = format_toHTML(upper);
2701: total_len += strlen(str_cc);
2702: /* 8 is by adding up characters ' [,] \n\n' plus one */
2703: ans_str = (char *)capa_malloc(sizeof(char),total_len);
2704: if(len_dd == 0 ) { /* no unit_str */
2705: sprintf(ans_str,"%s [%s,%s]\n\n", str_aa,str_bb,str_cc);
2706: } else {
2707: sprintf(ans_str,"%s [%s,%s] %s\n\n", str_aa,str_bb,str_cc,p->unit_str);
2708: }
2709: capa_mfree((char *)str_aa); capa_mfree((char *)str_bb); capa_mfree((char
2710: *)str_cc);
2711: } else {
2712: if ( (p->ans_type == ANSWER_IS_INTEGER) ||
2713: (p->ans_type == ANSWER_IS_FLOAT )) {
2714: str_bb = format_toHTML(lower);
2715: } else { /* answer could be string, choice */
2716: str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1);
2717: if (p->ans_type == ANSWER_IS_FORMULA || 1)
2718: sprintf(str_bb,"<PRE>\n%s\n</PRE>",lower);
2719: else
2720: strcpy(str_bb,lower);
2721: }
2722: total_len = strlen(str_bb) + len_dd + 4;
2723: /* 4 is by adding up characters ' \n\n' plus one */
2724: ans_str = (char *)capa_malloc(sizeof(char),total_len);
2725: if(len_dd == 0 ) { /* no unit_str */
2726: sprintf(ans_str,"%s\n\n", str_bb);
2727: } else {
2728: sprintf(ans_str,"%s %s\n\n", str_bb,p->unit_str);
2729: }
2730: capa_mfree((char *)str_bb);
2731: }
2732: break;
2733: }
2734: capa_mfree(fmted_ans);
2735:
2736: if( p->ans_cnt > 1 ) {
2737: AnswerInfo_t *ai;
2738: for( ai = p->ans_list; ai; ai = ai->ans_next) {
2739: num_answer = calc_ansrange(ai->ans_type,ai->ans_calc, ai->ans_str, ai->ans_fmt,
2740: ai->ans_tol_type,ai->ans_tol,lower,upper);
2741: if( ai->ans_type == ANSWER_IS_FLOAT ) {
2742: fmted_ans = capa_malloc(SMALL_LINE_BUFFER,1);
2743: d_answer = (double)atof(ai->ans_str);
2744: sprintf(fmted_ans,ai->ans_fmt,d_answer);
2745: } else {
2746: fmted_ans = capa_malloc(strlen(ai->ans_str)+2,1);
2747: strcpy(fmted_ans,ai->ans_str);
2748: }
2749: len_aa = strlen(fmted_ans);
2750: len_bb = strlen(lower);
2751: len_cc = strlen(upper);
2752: len_dd = strlen(ai->ans_unit_str);
2753: switch(mode) {
2754: case TeX_MODE:
2755: if(num_answer==2) {
2756: /* 16 is by adding up characters ' [,] \n\n' and others */
2757:
2758: str_aa = format_toTeX(fmted_ans);
2759: total_len = strlen(str_aa) + len_dd + 16;
2760: str_bb = format_toTeX(lower);
2761: total_len += strlen(str_bb);
2762: str_cc = format_toTeX(upper);
2763: total_len += strlen(str_cc);
2764:
2765: sub_ans_str = (char *)capa_malloc(sizeof(char),total_len);
2766:
2767: if(len_dd == 0 ) { /* no unit_str */
2768: sprintf(sub_ans_str," %s [%s,%s]\n\n", str_aa,str_bb,str_cc);
2769: } else {
2770: sprintf(sub_ans_str," %s [%s,%s] $%s$\n\n",
2771: str_aa,str_bb,str_cc,ai->ans_unit_str);
2772: }
2773: capa_mfree((char *)str_aa); capa_mfree((char *)str_bb); capa_mfree((char *)str_cc);
2774: } else { /* only one answer */
2775: if ( (ai->ans_type == ANSWER_IS_INTEGER) ||
2776: (ai->ans_type == ANSWER_IS_FLOAT )) {
2777: str_bb = format_toTeX(lower);
2778: } else { /* answer could be string, choice */
2779: str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1);
2780: if (ai->ans_type == ANSWER_IS_FORMULA || 1)
2781: sprintf(str_bb,"\\begin{verbatim}%s\\end{verbatim}",lower);
2782: else
2783: strcpy(str_bb,lower);
2784: }
2785: total_len = strlen(str_bb) + len_dd + 8;
2786: /* 4 is by adding up characters ' \\\n' plus four */
2787: sub_ans_str = (char *)capa_malloc(sizeof(char),total_len);
2788: if(len_dd == 0 ) { /* no unit_str */
2789: sprintf(sub_ans_str," %s\n", str_bb);
2790: } else {
2791: sprintf(sub_ans_str," %s $%s$\n", str_bb,ai->ans_unit_str);
2792: }
2793: capa_mfree((char *)str_bb);
2794: }
2795: break;
2796: case ASCII_MODE:
2797: total_len = len_aa + len_bb + len_cc + len_dd + 8;
2798: /* 8 is by adding up characters ' [,] \n\n' plus one */
2799: sub_ans_str = (char *)capa_malloc(sizeof(char),total_len);
2800: if(num_answer==2) {
2801: if(len_dd == 0 ) { /* no unit_str */
2802: sprintf(sub_ans_str,"%s [%s,%s]\n\n", fmted_ans,lower,upper);
2803: } else {
2804: sprintf(sub_ans_str,"%s [%s,%s] %s\n\n",
2805: fmted_ans,lower,upper,ai->ans_unit_str);
2806: }
2807: } else {
2808: if(len_dd == 0 ) { /* no unit_str */
2809: sprintf(sub_ans_str,"%s\n\n", lower);
2810: } else {
2811: sprintf(sub_ans_str,"%s %s\n\n", lower,ai->ans_unit_str);
2812: }
2813: }
2814: break;
2815: case ANSWER_STRING_MODE:
2816: total_len = len_aa + len_bb + len_cc + len_dd + 8;
2817: /* 8 is by adding up characters ' [,] \n\n' plus one */
2818: sub_ans_str = (char *)capa_malloc(sizeof(char),total_len);
2819: if(num_answer==2) {
2820: if(len_dd == 0 ) { /* no unit_str */
2821: sprintf(sub_ans_str,", %s", fmted_ans);
2822: } else {
2823: sprintf(sub_ans_str,", %s %s", fmted_ans,ai->ans_unit_str);
2824: }
2825: } else {
2826: if(len_dd == 0 ) { /* no unit_str */
2827: sprintf(sub_ans_str,", %s", lower);
2828: } else {
2829: sprintf(sub_ans_str,", %s %s", lower,ai->ans_unit_str);
2830: }
2831: }
2832: break;
2833: case HTML_MODE:
2834: if(num_answer==2) {
2835: str_aa = format_toHTML(fmted_ans);
2836: total_len = strlen(str_aa) + len_dd + 8;
2837: str_bb = format_toHTML(lower);
2838: total_len += strlen(str_bb);
2839: str_cc = format_toHTML(upper);
2840: total_len += strlen(str_cc);
2841: /* 8 is by adding up characters ' [,] \n\n' plus one */
2842: sub_ans_str = (char *)capa_malloc(sizeof(char),total_len);
2843: if(len_dd == 0 ) { /* no unit_str */
2844: sprintf(sub_ans_str,"%s [%s,%s]\n\n", str_aa,str_bb,str_cc);
2845: } else {
2846: sprintf(sub_ans_str,"%s [%s,%s] %s\n\n",
2847: str_aa,str_bb,str_cc,ai->ans_unit_str);
2848: }
2849: capa_mfree((char *)str_aa); capa_mfree((char *)str_bb); capa_mfree((char
2850: *)str_cc);
2851: } else {
2852: if ( (ai->ans_type == ANSWER_IS_INTEGER) ||
2853: (ai->ans_type == ANSWER_IS_FLOAT )) {
2854: str_bb = format_toHTML(lower);
2855: } else { /* answer could be string, choice */
2856: str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1);
2857: if (ai->ans_type == ANSWER_IS_FORMULA || 1)
2858: sprintf(str_bb,"<PRE>\n%s\n</PRE>",lower);
2859: else
2860: strcpy(str_bb,lower);
2861: }
2862: total_len = strlen(str_bb) + len_dd + 4;
2863: /* 4 is by adding up characters ' \n\n' plus one */
2864: sub_ans_str = (char *)capa_malloc(sizeof(char),total_len);
2865: if(len_dd == 0 ) { /* no unit_str */
2866: sprintf(sub_ans_str,"%s\n\n", str_bb);
2867: } else {
2868: sprintf(sub_ans_str,"%s %s\n\n", str_bb,ai->ans_unit_str);
2869: }
2870: capa_mfree((char *)str_bb);
2871: }
2872: break;
2873: } /* end of switch */
2874: total_len = strlen(ans_str);
2875: total_len += (strlen(sub_ans_str) + 1);
2876: tmp_str = (char *)capa_malloc(sizeof(char),total_len);
2877: strncpy(tmp_str, ans_str, strlen(ans_str)+1);
2878: strcat(tmp_str, sub_ans_str);
2879: capa_mfree(ans_str); capa_mfree(sub_ans_str);
2880: capa_mfree(fmted_ans);
2881: ans_str = tmp_str;
2882: } /* end of for */
2883: } /* end of if */
2884:
2885: return (ans_str); /* the calling routing needs to deallocate it */
2886: }
2887:
2888:
2889:
2890: /* ------------------------------ called from capalogin */
2891: /* impose stronger checking on the user input string *answer */
2892: /* */
2893:
2894: /* <== This routine checks user input string *ans against correct answer *s ==> */
2895: int
1.10 albertel 2896: capa_check_ans(ai,ans, error) AnswerInfo_t *ai; char *ans; char **error;
1.1 albertel 2897: {
2898: int t; /* ans_type */
2899: char *s; /* ans_str */
2900: int c; /* ans_calc */
2901: int tt; /* ans_tol_type */
2902: double to; /* ans_tol */
2903: int su; /* ans_sig_ub */
2904: int sl; /* ans_sig_lb */
2905: char *fm; /* ans_fmt */
2906: char *us; /* ans_unit_str */
2907: Unit_t *u_p; /* ans_unit */
2908: int input_len, all_alphabet = 1, idx, ii, type;
2909: int outcome, result = INCORRECT;
2910: int sig, corr_len;
2911: int choice[ANSWER_STRING_LENG];
2912: char num_str[ANSWER_STRING_LENG], unit_str[ANSWER_STRING_LENG];
2913: char fmted[ANSWER_STRING_LENG], correct[ANSWER_STRING_LENG], answer[ANSWER_STRING_LENG];
2914: double n_part;
2915: double given, target, ratio, fmted_target, target_u, target_l, scale=1.0;
2916: double delta;
2917:
2918: t = ai->ans_type; s = ai->ans_str; c = ai->ans_calc;
2919: tt = ai->ans_tol_type; to = ai->ans_tol;
2920: su = ai->ans_sig_ub; sl = ai->ans_sig_lb;
2921: fm = ai->ans_fmt;
2922: us = ai->ans_unit_str; u_p = ai->ans_unit;
2923:
2924: switch(t) {
2925: case ANSWER_IS_INTEGER:
2926: case ANSWER_IS_FLOAT:
2927: {
2928: input_len = strlen(ans);
2929: all_alphabet = 1;
2930: for(idx=0;idx<input_len;idx++) {
2931: if( isdigit(ans[idx]) ) {
2932: all_alphabet = 0;
2933: }
2934: }
2935: if( !all_alphabet ) { /* answer string is not all alphabets */
2936: outcome = split_num_unit(ans,&n_part,num_str,unit_str);
2937: if( outcome > 1 ) { /* with both num and unit parts or only unit part */
2938: if( u_p != NULL ) {
1.10 albertel 2939: if (UNIT_FAIL == (result = check_correct_unit(unit_str,u_p,&scale))) {
2940: *error=strsave(unit_str);
2941: }
1.1 albertel 2942: } else { /* what to do when no unit is specified but student entered a unit? */
2943: result = UNIT_NOTNEEDED;
1.10 albertel 2944: *error=strsave(unit_str);
1.1 albertel 2945: }
2946: } else {
2947: if( u_p != NULL ) {
2948: result = NO_UNIT;
2949: }
2950: }
2951: if( (result != NO_UNIT) && (result != UNIT_FAIL) && ( result != UNIT_NOTNEEDED) ) {
2952: if( t == ANSWER_IS_FLOAT ) {
2953: target = (double)atof(s); /* real number */
2954: } else {
2955: target = (double)atol(s); /* Integer answer */
2956: }
2957: given = n_part * scale; /* convert the given answer into proper scale for units */
2958: sig = calc_sig( num_str );
1.10 albertel 2959: if( ((sig < sl ) || (sig > su )) && (sig!=0)) {
2960: result = SIG_FAIL;
2961: *error=capa_malloc(1,ANSWER_STRING_LENG);
2962: sprintf(*error,"%d",sig);
1.1 albertel 2963: } else {
2964: switch( tt ) { /* tolerence type */
2965: case TOL_ABSOLUTE:
2966: fmted_target = target; /* if answer type is integer */
2967: if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */
2968: sprintf(fmted, fm, target);
2969: fmted_target = (double)atof(fmted);
2970: }
2971: to = fabs(to); /* tol must be positive */
2972: if( c == CALC_FORMATED) {
2973: target_l = fmted_target - to; target_u = fmted_target + to;
2974: } else {
2975: target_l = target - to; target_u = target + to;
2976: }
2977: if( (given >= target_l) && (given <= target_u) ) {
2978: result = APPROX_ANS;
2979: } else { result = INCORRECT; }
2980: break;
2981: case TOL_PERCENTAGE:
2982: if( target != 0.0 ) {
2983: ratio = (double)(to / 100.0);
2984: fmted_target = target; /* if answer type is integer */
2985: if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */
2986: sprintf(fmted, fm, target);
2987: fmted_target = (double)atof(fmted);
2988: }
2989: delta = (double)fabs((double)ratio*target);
2990: if( c == CALC_FORMATED) {
2991: target_l = fmted_target - delta; target_u = fmted_target + delta;
2992: } else {
2993: target_l = target - delta; target_u = target + delta;
2994: }
2995: } else { target_l = target_u = target; }
2996: if ( (given >= target_l) && (given <= target_u) ) {
2997: result = APPROX_ANS;
2998: } else { result = INCORRECT; }
2999: break;
3000: }
3001: } /* end sig check */
3002: } /* end if unit check */
3003: } else { /* user entered alphabets, but no number */
1.10 albertel 3004: result = WANTED_NUMERIC;
1.1 albertel 3005: }
3006: }
3007: break;
3008: case ANSWER_IS_CHOICE:
3009: {
3010: corr_len = strlen(s); input_len = strlen(ans);
3011: if( corr_len == input_len ) {
3012: for(idx=0;idx<ANSWER_STRING_LENG;idx++) choice[idx] = 0;
3013: result = EXACT_ANS;
3014: for(ii=0;ii<corr_len; ii++) {
3015: idx = toupper(correct[ii]) - 'A'; choice[idx] = 1;
3016: }
3017: for(ii=0;ii<input_len;ii++) {
3018: idx = toupper(answer[ii]) - 'A';
3019: if(choice[idx] != 1 ) result = INCORRECT;
3020: }
3021: } else { result = INCORRECT; }
3022: break;
3023: }
3024: case ANSWER_IS_STRING_CI:
3025: if (strcasecmp(ans, s)) { result = INCORRECT; } else { result = EXACT_ANS; }
3026: break;
3027: case ANSWER_IS_STRING_CS:
3028: if (strcmp(ans, s)) { result = INCORRECT; } else { result = EXACT_ANS; }
3029: break;
3030: case ANSWER_IS_FORMULA:
3031: result = check_formula_ans(s,ans,ai->ans_id_list,ai->ans_pts_list,tt,to);
3032: break;
3033: case ANSWER_IS_EXTERNAL: /* Not yet implemented */
1.7 albertel 3034:
1.9 albertel 3035:
3036:
1.1 albertel 3037: break;
3038: }
3039: return (result);
3040: }
3041:
3042: /* =============================================================================== */
3043: /* calling sequence capa_check_answers() --> capa_check_answer() */
3044: /* --> capa_check_ans() */
3045:
3046:
3047: /* How we check the correct answer against user input string */
3048: /*
3049: If the correct answer is a number (either integer or real number)
3050: check if user input string consists of only alphabet characters
3051: use split_num_unit() heuristic function to split the input string into two parts
3052: numerical part and units part.
3053: if the outcome contains units, check if the units is correct or not
3054:
3055: */
3056:
3057:
3058: int
1.10 albertel 3059: capa_check_answer(p, answer, error) Problem_t *p; char *answer; char **error;
1.1 albertel 3060: {
3061: int type;
3062: char *correct;
3063: char input[ANSWER_STRING_LENG], unit_str[ANSWER_STRING_LENG];
3064: int tol_type, calc_type;
3065: double tol, n_part;
3066: int sig_l;
3067: int sig_u;
3068: char *fmt;
3069: int choice[ANSWER_STRING_LENG], ii, idx, corr_len, input_len;
3070: int result = INCORRECT, sig, outcome, all_alphabet;
3071: char fmted[FORMAT_STRING_LENG];
3072: double given, target, ratio, fmted_target, target_u, target_l, scale=1.0;
3073: double delta;
3074:
3075: type = p->ans_type;
3076: correct = p->answer;
3077: tol_type = p->tol_type;
3078: tol = p->tolerance;
3079: sig_l = p->sig_lbound;
3080: sig_u = p->sig_ubound;
3081: fmt = p->ans_fmt;
3082: calc_type = p->calc;
3083: unit_str[0]=0;
3084:
3085: switch(type) {
3086: case ANSWER_IS_INTEGER:
3087: case ANSWER_IS_FLOAT:
3088: {
3089: input_len = strlen(answer);
3090: all_alphabet = 1;
3091: for(idx=0;idx<input_len;idx++) {
3092: if( isdigit(answer[idx]) ) {
3093: all_alphabet = 0;
3094: }
3095: }
3096: if( !all_alphabet ) {
3097: outcome = split_num_unit(answer,&n_part,input,unit_str);
3098: if( outcome > 1 ) { /* with both num and unit parts or only unit part */
3099: if( p->ans_unit != NULL ) {
1.10 albertel 3100: if ( UNIT_FAIL == ( result = check_correct_unit(unit_str,p->ans_unit,&scale) ) ) {
3101: *error=strsave(unit_str);
3102: }
1.1 albertel 3103: } else { /* what to do when no unit is specified but student entered a unit? */
3104: result = UNIT_NOTNEEDED;
1.10 albertel 3105: *error=strsave(unit_str);
1.1 albertel 3106: }
3107: } else {
3108: if( p->ans_unit != NULL ) {
3109: result = NO_UNIT;
3110: }
3111: }
3112: if( (result != NO_UNIT) && (result != UNIT_FAIL) && ( result != UNIT_NOTNEEDED) ) {
3113: if( type == ANSWER_IS_FLOAT ) {
3114: target = (double)atof(correct); /* real number */
3115: } else {
3116: target = (double)atol(correct); /* Integer answer */
3117: }
3118: given = n_part * scale; /* convert the given answer into proper scale for units */
3119: sig = calc_sig( input );
1.5 albertel 3120: if( ((sig < sig_l) || (sig > sig_u)) && (sig!=0)) {
1.1 albertel 3121: result = SIG_FAIL;
1.10 albertel 3122: *error=capa_malloc(1,ANSWER_STRING_LENG);
3123: sprintf(*error,"%d",sig);
1.1 albertel 3124: } else {
3125: switch( tol_type ) {
3126: case TOL_ABSOLUTE:
3127: fmted_target = target; /* if answer type is integer */
3128: if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */
3129: sprintf(fmted, fmt, target);
3130: fmted_target = (double)atof(fmted);
3131: }
3132: tol = fabs(tol); /* tol must be positive */
3133: if( calc_type == CALC_FORMATED) {
3134: target_l = fmted_target - tol; target_u = fmted_target + tol;
3135: } else {
3136: target_l = target - tol; target_u = target + tol;
3137: }
3138: if( (given >= target_l) && (given <= target_u) ) {
3139: result = APPROX_ANS;
3140: } else { result = INCORRECT; }
3141: break;
3142: case TOL_PERCENTAGE:
3143: if( target != 0.0 ) {
3144: ratio = (double)(tol / 100.0);
3145: fmted_target = target; /* if answer type is integer */
3146: if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */
3147: sprintf(fmted, fmt, target);
3148: fmted_target = (double)atof(fmted);
3149: }
3150: delta = (double)fabs((double)ratio*target);
3151: if( calc_type == CALC_FORMATED) {
3152: target_l = fmted_target - delta; target_u = fmted_target + delta;
3153: } else {
3154: target_l = target - delta; target_u = target + delta;
3155: }
3156: } else { target_l = target_u = target; }
3157: if ( (given >= target_l) && (given <= target_u) ) {
3158: result = APPROX_ANS;
3159: } else { result = INCORRECT; }
3160: break;
3161: }
3162: } /* end sig check */
3163: } /* end if unit check */
3164: } else { /* user entered alphabet, but no number */
1.10 albertel 3165: result = WANTED_NUMERIC;
1.1 albertel 3166: }
3167: }
3168: break;
3169: case ANSWER_IS_CHOICE:
3170: {
3171: corr_len = strlen(correct); input_len = strlen(answer);
3172: if( corr_len == input_len ) {
3173: for(ii=0;ii<ANSWER_STRING_LENG;ii++) choice[ii] = 0; result = EXACT_ANS;
3174: for(ii=0;ii<corr_len; ii++) {
3175: idx = toupper(correct[ii]) - 'A'; choice[idx] = 1;
3176: }
3177: for(ii=0;ii<input_len;ii++) {
3178: idx = toupper(answer[ii]) - 'A';
3179: if(choice[idx] != 1 ) result = INCORRECT;
3180: }
3181: } else { result = INCORRECT; }
3182: break;
3183: }
3184: case ANSWER_IS_STRING_CI:
3185: if (strcasecmp(answer, correct)) { result = INCORRECT; } else { result = EXACT_ANS; }
3186: break;
3187: case ANSWER_IS_STRING_CS:
3188: if (strcmp(answer, correct)) { result = INCORRECT; } else { result = EXACT_ANS; }
3189: break;
3190: case ANSWER_IS_FORMULA:
3191: result = check_formula_ans(correct,answer,p->id_list,p->pts_list,tol_type,tol);
3192: break;
3193: case ANSWER_IS_EXTERNAL: /* not yet implemented */
1.5 albertel 3194: /* we assume the external program is called through popen() */
3195: /* and the result will be given back as 0 or 1 to indicate the */
3196: /* given answer is correct or not */
1.7 albertel 3197: /* arguments are given to the program as */
3198:
1.1 albertel 3199: break;
3200:
3201: }
3202: return (result);
3203: }
3204:
3205: /* ----------------------------------------------------------------------------------- */
3206: /* assumming the formula is *fml_str and the student input is *input_str */
3207: /* according to the type of tolerance, we form the final formula as */
3208: /* absolute tolerance: (*fml_str) - (*input_str) */
3209: /* relative tolerance: (*input_str) / (*fml_str) */
3210: int
3211: check_formula_ans(fml_str,input_str,var_list,pts_list,tol_type,tol)
3212: char *fml_str;char *input_str;char *var_list;PointsList_t *pts_list;int tol_type; double tol;
3213: {
3214: char *check_fml_str;
3215: int f_len, i_len, outcome, error_code;
3216: PointsList_t *pt, *next;
3217: double formula_val, diff;
3218:
3219: f_len = strlen(fml_str);
3220: i_len = strlen(input_str);
3221:
3222: check_fml_str = (char *)capa_malloc((f_len + i_len + 16), sizeof(char));
3223: if( tol_type == TOL_ABSOLUTE ) {
3224: sprintf(check_fml_str,"abs((%s) - (%s))",fml_str, input_str);
3225: } else {
3226: sprintf(check_fml_str,"(%s) / (%s)",input_str,fml_str);
3227: }
3228: outcome = APPROX_ANS;
3229: for(pt= pts_list; pt!=NULL ; pt=next) {
3230: next=pt->pts_next;
3231: error_code = f_eval_formula(&formula_val,check_fml_str, var_list, pt->pts_str);
3232: if( ! error_code ) {
3233: if( tol_type == TOL_ABSOLUTE ) {
3234: diff = tol - formula_val;
3235: if( diff < 0.0 ) {
3236: outcome = INCORRECT;
3237: }
3238: } else {
3239: diff = abs(1.0 - formula_val) * 100.0 ;
3240: if( diff < tol ) {
3241: outcome = INCORRECT;
3242: }
3243: }
3244: } else {
3245: outcome = BAD_FORMULA;
3246: break;
3247: }
3248: }
3249: capa_mfree((char *)check_fml_str);
3250:
3251: return (outcome);
3252:
3253: }
3254: /* inputs: type :: answer type, calc_type :: input string format string tolerance type */
3255: /* returns: lower upper */
3256:
3257: int
3258: calc_ansrange(type, calc_type, input, fmt, tol_type, tol, lower, upper)
3259: int type;int calc_type;char *input;char *fmt;
3260: int tol_type;double tol;char *lower;char *upper;
3261: {
3262: int result = 2, leng;
3263: char fmted[ANSWER_STRING_LENG];
3264: double target, fmted_target, ratio, target_l, target_u, tmp, delta;
3265:
3266:
3267: if( (type == ANSWER_IS_FORMULA) ||
3268: (type == ANSWER_IS_EXTERNAL ) ) {
3269: strcpy(lower, input);
3270: result = 1;
3271: return (result);
3272: } else {
3273: if( tol == 0.0 ) { /* answer could be ANSWER_IS_FLOAT ANSWER_IS_INTEGER,
3274: ANSWER_IS_STRING_CI ANSWER_IS_STRING_CS
3275: ANSWER_IS_CHOICE
3276: */
3277: result = 1; /* only one answer */
3278: if( type == ANSWER_IS_FLOAT ) {
3279: target = (double)atof(input);
3280: sprintf(fmted, fmt, target);
3281: leng = strlen(fmted)+1;
3282:
3283: strcpy(lower, fmted);
3284: } else { /* could be integer, choice, string ci, string cs */
3285: strcpy(lower, input);
3286: }
3287: } else { /* we have tolerence */
3288:
3289: target = (double)atof(input);
3290: switch( tol_type ) {
3291: case TOL_ABSOLUTE:
3292: fmted_target = target; /* if answer type is integer */
3293: if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */
3294: sprintf(fmted, fmt, target);
3295: fmted_target = (double)atof(fmted);
3296: }
3297: tol = fabs(tol); /* tol must be positive */
3298: if( calc_type == CALC_FORMATED) {
3299: target_l = fmted_target - tol; target_u = fmted_target + tol;
3300: } else {
3301: target_l = target - tol; target_u = target + tol;
3302: }
3303: if(type == ANSWER_IS_FLOAT) {
3304: sprintf(fmted, fmt, target_l ); strcpy(lower, fmted);
3305: sprintf(fmted, fmt, target_u ); strcpy(upper, fmted);
3306: } else {
3307: sprintf(fmted, "%.15g", target_l ); strcpy(lower, fmted);
3308: sprintf(fmted, "%.15g", target_u ); strcpy(upper, fmted);
3309: }
3310: break;
3311: case TOL_PERCENTAGE:
3312: if( target != 0.0 ) {
3313: ratio = (double)(tol / 100.0);
3314: fmted_target = target; /* if answer type is integer */
3315: if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */
3316: sprintf(fmted, fmt, target);
3317: fmted_target = (double)atof(fmted);
3318: }
3319: delta = (double)fabs((double)ratio*target);
3320: if( calc_type == CALC_FORMATED) {
3321: target_l = fmted_target - delta; target_u = fmted_target + delta;
3322: } else {
3323: target_l = target - delta; target_u = target + delta;
3324: }
3325: if( target_l > target_u ) { tmp = target_u; target_u = target_l; target_l = tmp; }
3326: if(type == ANSWER_IS_FLOAT) {
3327: sprintf(fmted, fmt, target_l ); strcpy(lower, fmted);
3328: sprintf(fmted, fmt, target_u ); strcpy(upper, fmted);
3329: } else {
3330: sprintf(fmted, "%.15g", target_l ); strcpy(lower, fmted);
3331: sprintf(fmted, "%.15g", target_u ); strcpy(upper, fmted);
3332: }
3333: } else { strcpy(lower, "0.0"); strcpy(upper, "0.0"); result = 1;}
3334: break;
3335: }
3336: }
3337: }
3338:
3339: return (result);
3340: }
3341:
3342: /* Algorithms : check ALL units first */
3343: /* sig figs second */
3344: /* numerical, string comparisons last */
3345: /* result from capa_check_ans() could be */
3346:
3347: /* New check answers routine checks the /AND and /OR group of answers */
3348: /* use array of char pointers char **a */
3349: int
1.10 albertel 3350: capa_check_answers(p,answers,cnt,error)
3351: Problem_t *p; char **answers; int cnt; char **error;
1.1 albertel 3352: {
3353: AnswerInfo_t *ai;
3354: int ii, done, result;
3355: int *outcomes;
1.10 albertel 3356: char **errormsg;
1.1 albertel 3357:
1.10 albertel 3358: errormsg=(char**)capa_malloc(cnt,sizeof(char*));
1.1 albertel 3359: if(p->ans_op == ANS_AND) { /* ans /and ans */
3360: if( (cnt != p->ans_cnt) ) { return (ANS_CNT_NOT_MATCH); }
1.10 albertel 3361: if( cnt == 1 ) { return (capa_check_answer(p, answers[0], error)); } /* there is only one answer */
1.1 albertel 3362: outcomes = (int *)capa_malloc(sizeof(int),cnt);
3363: for(ii=0;ii<cnt;ii++) outcomes[ii]=0; /* initialize the outcomes array */
1.10 albertel 3364: outcomes[0] = capa_check_answer(p, answers[0], &errormsg[0]);
1.1 albertel 3365: for(ii=1, ai = p->ans_list; ai; ii++,ai = ai->ans_next ) {
1.10 albertel 3366: outcomes[ii] = capa_check_ans(ai,answers[ii],&(errormsg[ii]));
1.1 albertel 3367: }
3368: done = ii = 0;
3369: result = 0;
3370: while( !done ) { /* check if any of the outcome has failed on units */
3371: if( (outcomes[ii] == UNIT_FAIL) ||
3372: (outcomes[ii] == NO_UNIT) ||
3373: (outcomes[ii] == UNIT_NOTNEEDED) ) {
3374: result = outcomes[ii];
1.10 albertel 3375: if (result != NO_UNIT) { *error=strsave(errormsg[ii]); }
1.1 albertel 3376: done = 1;
3377: }
3378: ii++;
3379: if(ii==cnt) done = 1;
3380: }
1.10 albertel 3381: if( result == 0 ) { /* check if any of the outcome has failed to be a numeric */
3382: done = ii = 0;
3383: while( !done ) {
3384: if( outcomes[ii] == WANTED_NUMERIC ) {
3385: result = outcomes[ii];
3386: done = 1;
3387: }
3388: ii++;
3389: if(ii==cnt) done = 1;
3390: }
3391: }
1.1 albertel 3392: if( result == 0 ) { /* check if any of the outcome has failed on sig figs */
3393: done = ii = 0;
3394: while( !done ) {
3395: if( outcomes[ii] == SIG_FAIL ) {
3396: result = outcomes[ii];
1.10 albertel 3397: *error = strsave(errormsg[ii]);
1.1 albertel 3398: done = 1;
3399: }
3400: ii++;
3401: if(ii==cnt) done = 1;
3402: }
3403: }
3404: if( result == 0 ) { /* check if any of the outcome is incorrect */
3405: done = ii = 0;
3406: while( !done ) {
3407: if( outcomes[ii] == INCORRECT ) {
3408: result = outcomes[ii];
3409: done = 1;
3410: }
3411: ii++;
3412: if(ii==cnt) done = 1;
3413: }
3414: }
1.10 albertel 3415: for (ii=0;ii<cnt;ii++) {
3416: if( (outcomes[ii] == UNIT_FAIL) ||
3417: (outcomes[ii] == SIG_FAIL) ||
3418: (outcomes[ii] == UNIT_NOTNEEDED) ) {
3419: capa_mfree(errormsg[ii]);
3420: }
3421: }
3422: capa_mfree((char *)errormsg);
1.1 albertel 3423: capa_mfree((char *)outcomes);
3424: if( result == 0 ) {
3425: result = APPROX_ANS; /* all answers are correct */
3426: }
1.10 albertel 3427:
1.1 albertel 3428: } else { /* should be ANS_OR , user answer count should always be 1 */
3429: if( cnt != 1 ) { return (ANS_CNT_NOT_MATCH); }
1.10 albertel 3430: if( p->ans_cnt == 1 ) { return (capa_check_answer(p, answers[0], error)); }
3431: result = capa_check_answer(p, answers[0], error);
1.1 albertel 3432: ii = 1; ai = p->ans_list;
3433: while( (ii<p->ans_cnt) && ( (result != EXACT_ANS) && (result != APPROX_ANS) ) ) {
1.10 albertel 3434: if((ii!=1)&&((result==UNIT_FAIL)||(result==SIG_FAIL)||(result==UNIT_NOTNEEDED))) {
3435: capa_mfree((char*)error);
3436: }
3437: result = capa_check_ans(ai,answers[0],error);
3438: ai = ai->ans_next; ii++;
1.1 albertel 3439: }
3440: }
3441: return (result);
3442: }
3443:
3444:
3445:
3446:
3447:
3448:
3449:
3450:
3451: /* ========================================================================= */
3452: int w_getclassdir(cpath_p, cown_p, class)
3453: char **cpath_p; char **cown_p; char *class;
3454: {
3455: FILE *fp;
3456: char filename[SMALL_LINE_BUFFER];
3457: char *cname_p;
3458: int done;
3459: char c;
3460:
3461: sprintf(filename,"class.conf");
3462: if ((fp=fopen(filename,"r"))==NULL) {
3463: sprintf(filename,"../class.conf");
3464: if ((fp=fopen(filename,"r"))==NULL) {
3465: printf("Error: can't open %s\n",filename);
3466: exit (1);
3467: }
3468: }
3469: do {
3470: c_ignorewhite(fp);
3471: c = getc(fp); ungetc(c,fp);
3472: if( c != EOF ) {
3473: cname_p = c_getword(fp);
3474: *cpath_p = c_getword(fp);
3475: *cown_p = c_getword(fp);
3476: throwaway_line(fp);
3477: if( ! strcasecmp(cname_p, class) ) {
3478: done = 1;
3479: } else {
3480: free(cname_p); free(*cpath_p); free(*cown_p);
3481: done = 0;
3482: }
3483: } else {
3484: done = 1;
3485: }
3486: } while ( ! done );
3487: fclose(fp);
3488: free(cname_p);
3489: return (1);
3490: }
3491:
3492: /* ----------------------------------------------------------------- */
3493: /* read_capa_config gets a value out of the capa.config file
3494: in the read resultant string all " are removed expect for \" occurances"
3495: in fact all case of \ then another character become just the last
3496: character
3497:
3498: inputs : key_word - a string that is searched for on the lefthand side
3499: of an equals sign
3500: outputs : value - a char pointer that the value of the key_word as defined
3501: in the config file is copied into
3502: return : -1 - unable to find or acces the capa.config file
3503: 0 - the requested keyword was not found
3504: >0 - length of the string that was returned in value
3505: */
3506: /* ----------------------------------------------------------------- */
3507: int read_capa_config(key_word,value)
3508: char *key_word;char *value;
3509: {
3510: FILE *fp;
3511: char filename[SMALL_LINE_BUFFER];
3512: char left[MAX_BUFFER_SIZE],right[MAX_BUFFER_SIZE],c;
3513: int failed=0,done=0,num=0,result=-1,found=0,returnVal=0,i,j;
3514:
3515: sprintf(filename,"capa.config");
3516: if ((fp=fopen(filename,"r"))==NULL) {
3517: return (-1);
3518: }
3519: do {
3520: num = fscanf(fp,"%[^ \n\t#] = %[^\n]",left,right);
3521: if (num == 2) { result = strcasecmp(left,key_word); }
3522: if (result==0) { done=1; }
3523: if (num==EOF) { failed=1; }
3524: if (num!=2) {
3525: found=0;
3526: while(1) {
3527: c=fgetc(fp);
3528: if (found) {
3529: if (c!='\n') {
3530: ungetc(c,fp);
3531: break;
3532: }
3533: }
3534: if (c=='\n') found=1;
3535: if (((char)c)==((char)EOF)) break;
3536: }
3537: }
3538: } while (!done && !failed);
3539:
3540: fclose(fp);
3541:
3542: if (done) {
1.4 albertel 3543: trim_response_ws(right); /*get rid of leading and trailing spaces*/
1.1 albertel 3544: for(i=0,j=0;i<(strlen(right)+1);i++) {
3545: value[j]='\0';
3546: if (right[i] == '\\' && (i < (strlen(right))) ) {
3547: i++;value[j]=right[i];j++;
3548: } else if (right[i] != '\"' ) {
3549: value[j]=right[i];j++;
3550: }
3551: }
3552: value[j]='\0';
3553: returnVal=j;
3554: }
3555: return returnVal;
3556: }
3557:
3558: int capa_access(const char *pathname, int mode)
3559: {
3560: pid_t euid,egid;
3561: struct stat status;
3562:
3563: euid=geteuid();
3564: egid=getegid();
3565: if ( -1 == stat(pathname,&status) ) { return -1; }
3566: /*printf("mode:%x F_OK:%x mode&F_OK:%x\n",mode,F_OK,(mode&F_OK));*/
3567: /*printf("st_mode:%x S_IFMT:%x st_mode&S_IFMT:%x\n",
3568: status.st_mode,S_IFMT,(status.st_mode&S_IFMT));*/
3569: if (!(status.st_mode & S_IFMT)) { return -1; }
3570: /*printf("euid: %d\t egid: %d\tstatus.st_uid: %d\tstatus.st_gid: %d\n",
3571: euid,egid,status.st_uid,status.st_gid);*/
3572: /*printf("mode:%x R_OK:%x mode&R_OK:%x\n",mode,R_OK,(mode&R_OK));*/
3573: /*printf("mode:%x W_OK:%x mode&W_OK:%x\n",mode,R_OK,(mode&R_OK));*/
3574: /*printf("mode:%x X_OK:%x mode&X_OK:%x\n",mode,R_OK,(mode&R_OK));*/
3575: if (euid==status.st_uid) {
3576: /*printf("here1\n");*/
3577: if ((mode & R_OK) && (!(status.st_mode & S_IRUSR))) { return -1; }
3578: if ((mode & W_OK) && (!(status.st_mode & S_IWUSR))) { return -1; }
3579: if ((mode & X_OK) && (!(status.st_mode & S_IXUSR))) { return -1; }
3580: } else {
3581: if (egid==status.st_gid) {
3582: /*printf("here2\n");*/
3583: if ((mode & R_OK) && (!(status.st_mode & S_IRGRP))) { return -1; }
3584: if ((mode & W_OK) && (!(status.st_mode & S_IWGRP))) { return -1; }
3585: if ((mode & X_OK) && (!(status.st_mode & S_IXGRP))) { return -1; }
3586: } else {
3587: /*printf("here3\n");*/
3588: if ((mode & R_OK) && (!(status.st_mode & S_IROTH))) { return -1; }
3589: if ((mode & W_OK) && (!(status.st_mode & S_IWOTH))) { return -1; }
3590: if ((mode & X_OK) && (!(status.st_mode & S_IXOTH))) { return -1; }
3591: }
3592: }
3593: return 0;
3594: }
3595:
3596: /*checks if the string is all whitespace*/
3597: /*returns 0 if it isn't */
3598: /*returns 1 if it is */
3599: int is_all_ws(char* answer)
3600: {
3601: int length,result=1,i;
3602: if (answer!=NULL) {
3603: length=strlen(answer);
3604: for(i=0;i<length;i++) {
3605: if (!isspace(answer[i])) {result=0;break;}
3606: }
3607: }
3608: return result;
3609: }
3610:
3611: void trim_response_ws(char* answer)
3612: {
3613: char *temp;
3614: int i,j=0,length;
3615: length=strlen(answer);
3616: temp=capa_malloc(length+1,1);
3617: strcpy(temp,answer);
3618: for(i=0; i<length;i++) if (!(isspace(temp[i]))) break;
3619: for(j=length-1;j>=0;j--) if (!(isspace(temp[j]))) break;
3620: temp[++j]='\0';
3621: strcpy(answer,&temp[i]);
3622: }
3623:
3624: void throwaway_line(FILE* fp)
3625: {
3626: int c;
3627: do {
3628: c = getc(fp);
3629: } while ( (c != '\n') && (c != EOF) );
3630: }
3631:
3632: char* capa_get_seat(char* studentnum,char* seatfile)
3633: {
3634: FILE* fp;
3635: T_student student;
3636: char *result,*defaultseatfile="seatingchart";
3637: char line[TMP_LINE_LENGTH],*lineend;
3638: int stuline=0,seatline=0;
3639:
3640: stuline = capa_get_student(studentnum,&student);
3641: if (stuline < 1 ) goto error;
3642: if (seatfile == NULL) seatfile=defaultseatfile;
3643: if ((fp=fopen(seatfile,"r"))==NULL) goto error;
3644: while( (stuline>seatline) && (fgets(line,TMP_LINE_LENGTH-1,fp)) ) seatline++;
3645: if (seatline< stuline) goto error;
3646: if ((lineend=index(line,' '))!=NULL) lineend='\0';
3647: result=capa_malloc(strlen(line)+1,1);
3648: strcpy(result,line);
3649: return result;
3650:
3651: error:
3652: result= capa_malloc(8,1);
3653: sprintf(result,"No Seat");
3654: return result;
3655:
3656: }
3657:
3658: void protect_log_string(char* log_string)
3659: {
3660: int i,len=strlen(log_string);
3661: for(i=0;i<len;i++) {
3662: switch (log_string[i]) {
3663: case '\n': case '\t': case '\r':
3664: log_string[i]=' ';
3665: break;
3666: }
3667: }
3668: }
3669:
3670: int capa_get_login_time(char *student_number,int set,time_t *logintime)
3671: {
3672: FILE *fp;
3673: int found,temp=0;
3674: char filename[FILE_NAME_LENGTH],line[SMALL_LINE_BUFFER];
3675:
3676: *logintime=0;
3677: sprintf(filename,"records/access%d.log",set);
3678:
3679: if ((fp=fopen(filename,"r"))==NULL) return (-1);
3680: found = 0;
3681: while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) {
3682: if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1;
3683: }
3684: fclose(fp);
3685: if (found) sscanf(rindex(line,':'),":%d",&temp);
3686: *logintime=(time_t)temp;
3687: return found;
3688: }
3689:
3690: /*----------------------------------------------------------*/
3691: /* INPUT: set the X in logX.db */
3692: /* OUTPUT: creates the accessX.log file if it doesn't exist */
3693: /* and inserts stunum:time(NULL) if stunum isn't */
3694: /* in ther already. */
3695: /* */
3696: /* RETURN: -1 file error */
3697: /* 0 already set */
3698: /* 1 succesfully logged a login time */
3699: /*----------------------------------------------------------*/
3700: int capa_set_login_time(char *student_number,int set)
3701: {
3702: FILE *fp;
3703: int errcode=0;
3704: int found=0;
3705: char filename[FILE_NAME_LENGTH],line[SMALL_LINE_BUFFER];
3706:
3707: sprintf(filename,"records/access%d.log",set);
3708:
3709: if ((fp=fopen(filename,"r"))!=NULL) {
3710: while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) {
3711: if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1;
3712: }
3713: fclose(fp);
3714: }
3715:
3716: if (found) return 0;
3717:
3718: sprintf(line,"%s:%d\n", student_number,(int)time(NULL));
3719: if ((fp=fopen(filename,"a+"))==NULL) return (-1);
3720: flockstream(fp);
3721: fseek(fp,0L,SEEK_END);
3722: if ( !fwrite((char *)line, strlen(line), 1, fp) ) {
3723: errcode = -1;
3724: } else {
3725: errcode = 1;
3726: }
3727: fflush(fp);
3728: funlockstream(fp);
3729: fclose(fp);
3730: return (errcode);
3731: }
3732: /* =||>|===================== End of capaCommon.c =====================|<||= */
3733:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>