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