Annotation of capa/capa51/pProj/capaCommon.c, revision 1.16
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;
1452: due_time_tm=localtime(&duetime);
1453: sprintf(date_str,"%04d/%02d/%02d %02d:%02d",((due_time_tm->tm_year)+1900),
1454: due_time_tm->tm_mon+1,due_time_tm->tm_mday,due_time_tm->tm_hour,
1455: due_time_tm->tm_min);
1456: return;
1457: }
1458: }
1459: strncpy(date_str,current->due_date,DATE_BUFFER);
1460: }
1461:
1462: /* student_number can be NULL, if it isn't NULL it is used by get_due_date */
1463: /* to assign a due date based on the time the student first accessed the */
1464: /* set if duration is non-zero */
1465: int
1466: capa_get_date(int which,char *student_number,int section,int set,char *date_str)
1467: {
1468: T_dates *current;
1469: int result;
1470: result=capa_get_section_dates(section,set,¤t);
1471: if (result<0) return result;
1472: result=1;
1473: switch(which) {
1474: case CHECK_OPEN_DATE: strncpy(date_str,current->open_date,DATE_BUFFER); break;
1475: case CHECK_DUE_DATE: capa_get_due_date(date_str,current,student_number,set); break;
1476: case CHECK_ANS_DATE: strncpy(date_str,current->answer_date,DATE_BUFFER); break;
1477: default: strncpy(date_str,current->open_date,DATE_BUFFER); result=-4;break;
1478: }
1479: capa_mfree((char*)current);
1480: return result;
1481: }
1482:
1483: int
1484: capa_get_duration(char *student_number,int section,int set)
1485: {
1486: T_dates *current;
1487: int duration=0,result;
1488: result=capa_get_section_dates(section,set,¤t);
1489: if (result<0) return result;
1490: duration=capa_convert_duration(current->duration);
1491: capa_mfree((char*)current);
1492: return duration;
1493: }
1494:
1495: int
1496: capa_get_section_dates(int section,int set,T_dates** dates)
1497: {
1498: register int c;
1499: FILE *fp;
1500: int result = 0, done;
1501: int tmp_low, tmp_high, sec_mode;
1502: char filename[FILE_NAME_LENGTH], tmpline[TMP_LINE_LENGTH],
1503: default_line[TMP_LINE_LENGTH];
1504:
1505: sprintf(filename,"records/date%d.db",set);
1506: if( capa_access(filename, F_OK) != 0 ) { result = -2; } else {
1507: if ((fp=fopen(filename,"r")) == NULL) { result = -2; } else {
1508: done = 0; result = -3;
1509: /* first non-comment line is assumed to be the default line */
1510: c_gettype(fp); c_ignorewhite(fp); fgets(default_line,TMP_LINE_LENGTH-1,fp);
1511: do {
1512: c_ignorewhite(fp); c = getc(fp); ungetc(c,fp);
1513: if( c != EOF ) {
1514: sec_mode = c_getsec_range(fp,&tmp_low,&tmp_high);
1515: if( sec_mode > 0 ) { /* no error */
1516: c_ignorewhite(fp); fgets(tmpline,TMP_LINE_LENGTH-1,fp);
1517: if( sec_mode == 1 ) { /* form: sec date_info */
1518: if((result == -3) && (tmp_low == section)) {
1519: result=-4;
1520: *dates=add_date_info(tmp_low,tmp_low,tmpline);
1521: if ( *dates != NULL ) { done = 1; result = 1; }
1522: }
1523: } else { /* form : [low,high] date_info */
1524: if( (result == -3) && ((section>=tmp_low)&&(section<=tmp_high)) ) {
1525: result = -4;
1526: *dates=add_date_info(tmp_low,tmp_high,tmpline);
1527: if ( *dates != NULL ) { done = 1; result = 1; }
1528: }
1529: }
1530: } else { /* error in specify section date */
1531: while ( ((c = getc(fp)) != '\n') && ( c != EOF) ); /* skip to end of line */
1532: }
1533: } else { /* EOF encountered */
1534: done = 1;
1535: }
1536: } while (!done);
1537: /* need to deal with those sections not show up in the dateX.db file */
1538: if( result == -3 ) { /* section not in the dateX.db file, use default */
1539: result = -4;
1540: *dates=add_date_info(DATE_DEFAULTS,DATE_DEFAULTS,default_line);
1541: if ( *dates != NULL ) { result = 1; }
1542: }
1543: }
1544: fclose(fp);
1545: }
1546: return (result);
1547: }
1548:
1549: T_dates* add_date_info(int lowsec,int highsec, char *dateinfo)
1550: {
1551: T_dates *dates;
1552: int result;
1553: dates=(T_dates*)capa_malloc(sizeof(T_dates),1);
1554: result=sscanf(dateinfo,"%16c,%16c,%16c,%s %d,%d",dates->open_date,dates->due_date,
1555: dates->answer_date,dates->duration,&(dates->inhibit_response),
1556: &(dates->view_problems_after_due));
1557: if (result != 6) {
1558: capa_mfree((char*)dates);
1559: dates=NULL;
1560: } else {
1561: dates->section_start=lowsec;
1562: dates->section_end=highsec;
1563: dates->s_next=NULL;
1564: }
1565: return dates;
1566: }
1567: /*----------------------------------------------------------*/
1568: /* INPUT: set the X in dateX.db */
1569: /* dates a pointer to the dates pointer */
1570: /* ACTION: builds a linked list of T_dates containing */
1571: /* the login information */
1572: /* RETURN: <0 file error */
1573: /* >0 success (number of lines successfully */
1574: /* proccessed) */
1575: /*----------------------------------------------------------*/
1576: int capa_get_all_dates (int set,T_dates **dates)
1577: {
1578: T_dates *current;
1579: FILE *fp;
1580: int result = 0, done, tmp_low, tmp_high, sec_mode, c, num=0;
1581: char filename[FILE_NAME_LENGTH], tmpline[TMP_LINE_LENGTH];
1582:
1583: sprintf(filename,"records/date%d.db",set);
1584: if ( ((fp=fopen(filename,"r")) == NULL)) { result = -2; } else {
1585: done = 0; result = -3;
1586: /* first non-comment line is assumed to be the default line */
1587: c_gettype(fp); c_ignorewhite(fp); fgets(tmpline,TMP_LINE_LENGTH-1,fp);
1588: *dates=add_date_info(DATE_DEFAULTS,DATE_DEFAULTS,tmpline);
1589: num++;
1590: if ( NULL == (current=*dates) ) {
1591: result = -3;
1592: } else {
1593: while(1) {
1594: c_ignorewhite(fp); c = getc(fp); ungetc(c,fp);
1595: if( c == EOF ) { break; }
1596: sec_mode = c_getsec_range(fp,&tmp_low,&tmp_high);
1597: if( sec_mode > 0 ) { /* no error */
1598: c_ignorewhite(fp); fgets(tmpline,TMP_LINE_LENGTH-1,fp);
1599: if( sec_mode == 1 ) { /* form: sec date_info */
1600: current->s_next=add_date_info(tmp_low,tmp_low,tmpline);
1601: } else { /* form : [low,high] date_info */
1602: current->s_next=add_date_info(tmp_low,tmp_high,tmpline);
1603: }
1604: current=current->s_next;
1605: num++;
1606: } else { /* error in specify section date */
1607: while ( ((c = getc(fp)) != '\n') && ( c != EOF) ); /* skip to end of line */
1608: }
1609: }
1610: result=num;
1611: }
1612: fclose(fp);
1613: }
1614: return (result);
1615: }
1616:
1617: /*----------------------------------------------------------*/
1618: /* INPUT: dates a pointer to the dates pointer */
1619: /* ACTION: frees a linked list of T_dates */
1620: /*----------------------------------------------------------*/
1621: void free_dates(T_dates *dates)
1622: {
1623: T_dates *current = dates,*next;
1624: while ( current != NULL ) {
1625: next = current->s_next;
1626: capa_mfree((char*)current);
1627: current = next;
1628: }
1629: }
1630:
1631: /*----------------------------------------------------------*/
1632: /* INPUT: set the X in dateX.db */
1633: /* dates a pointer to the dates pointer */
1634: /* ACTION: takes a linked list of date information and */
1635: /* and writes the info to a file */
1636: /* RETURN: -1 file error */
1637: /* 1 success */
1638: /*----------------------------------------------------------*/
1639: int capa_set_all_dates (int set,T_dates *dates)
1640: {
1641: T_dates *current = dates;
1642: int result;
1643: FILE* fp;
1644: char filename[FILE_NAME_LENGTH];
1645:
1646: sprintf(filename,"records/date%d.db",set);
1647: if ( ((fp=fopen(filename,"w")) == NULL) ) { result = -1; } else {
1648: result=1;
1649: while ( current != NULL ) {
1650: if ( current->section_start == DATE_DEFAULTS ) {
1651: fprintf(fp,"<< DEFAULTS >> ");
1652: } else {
1653: fprintf(fp,"[%d, %d] ", current->section_start,current->section_end);
1654: }
1655: fprintf(fp,"%s,%s,%s,%s %d,%d\n", current->open_date,current->due_date,
1656: current->answer_date,current->duration,current->inhibit_response,
1657: current->view_problems_after_due);
1658: current = current->s_next;
1659: }
1660: fclose(fp);
1661: }
1662: return result;
1663: }
1664:
1665: /*----------------------------------------------------------*/
1666: /* INPUT: set the X in logX.db */
1667: /* OUTPUT: none */
1668: /* */
1669: /* RETURN: -1 file error */
1670: /* 0 no login */
1671: /* >0 number of logins in that logX.db file */
1672: /*----------------------------------------------------------*/
1673:
1674: #define FIFTEEN_MINUTES (15*60)
1675: #define TEN_MINUTES (600)
1676: #define ONE_DAY (86400)
1677: int /* RETURNS: 1 first time login, 2 second time login, 0 not ok, -1 file error */
1678: login_check(student_number) /* ARGUMENTS: */
1679: char *student_number; /* Student # */
1680: { /* LOCALS: */
1681: FILE *fp;
1682:
1683: int errcode=0;
1684: int found;
1685: char filename[FILE_NAME_LENGTH];
1686: char line[SMALL_LINE_BUFFER], new_line[SMALL_LINE_BUFFER];
1687: struct tm *theDT;
1688: time_t login_time, record_time;
1689: long offsetL, offsetR, offsetEnd,left_leng;
1690: char s_number[MAX_STUDENT_NUMBER+1];
1691: char tty_name[FILE_NAME_LENGTH];
1692: int log_tries, p_id;
1693: int month, day, year, hour, min, sec;
1694: char *tmp_buffer;
1695:
1696: sprintf(filename,"records/active.log");
1697:
1698: if( capa_access(filename,F_OK) < 0 ) { /*<------------- File not exist */
1699: if ((fp=fopen(filename,"w"))==NULL) { /* create if non-existant */
1700: /*printf("Error: can't create %s\n",filename);*/
1701: return (-1);
1702: }
1703: fclose(fp);
1704: }
1705: if ((fp=fopen(filename,"r"))==NULL) {
1706: /*printf("Error: can't open %s\n",filename);*/
1707: return (-1);
1708: }
1709: flockstream(fp); /* lock exclusively and perform read/write operation */
1710:
1711: found = 0;
1712: while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) {
1713: if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1;
1714: }
1715: offsetR = ftell(fp);
1716: offsetL = offsetR - strlen(line);
1717: funlockstream(fp); fclose(fp);
1718:
1719: if( found && (strlen(line) != 0) ) {
1720: /* printf("FOUND:%slen=%d\n",line,strlen(line)); */
1721: 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);
1722: record_time = time(NULL);
1723: theDT = localtime(&record_time);
1724: theDT->tm_sec = sec; theDT->tm_min = min;
1725: theDT->tm_hour = hour; theDT->tm_mday = day;
1726: theDT->tm_mon = month-1; theDT->tm_year = year;
1727: theDT->tm_wday = weekday(year,month,day);
1728: theDT->tm_yday = julianday(year,month,day);
1729: record_time = mktime( theDT );
1730: time(&login_time); theDT = localtime(&login_time);
1731: switch(log_tries) {
1732: case 0: log_tries = 1; errcode = 1; break;
1733: case 1: log_tries = 2; errcode = 2;
1734: break;
1735: case 2: log_tries = 3; errcode = 0; break;
1736: case 3: if( (login_time - record_time) >= TEN_MINUTES ) {
1737: log_tries = 1; errcode = 1;
1738: } else {
1739: log_tries = 3; errcode = 2;
1740: return (0);
1741: }
1742: break;
1743: default: printf("ERROR: Number of logins UNKNOWN\n");
1744: log_tries = 1; errcode = 1;
1745: break;
1746: }
1747: 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);
1748: if ((fp=fopen(filename,"r+"))==NULL) {
1749: /*printf("Error: can't open %s\n",filename);*/
1750: return (-1);
1751: }
1752: flockstream(fp);
1753: tmp_buffer = (char *)malloc(8*1024*56);
1754: found = 0;
1755: while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) {
1756: if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1;
1757: }
1758: offsetR = ftell(fp); offsetL = offsetR - strlen(line);
1759: fseek(fp,0L,SEEK_END); offsetEnd = ftell(fp);
1760: left_leng = offsetEnd - offsetR;
1761: fseek(fp,offsetR,SEEK_SET);
1762: left_leng = fread(tmp_buffer, 1, left_leng+1, fp);
1763: tmp_buffer[left_leng] = 0;
1764: fseek(fp,offsetL,SEEK_SET);
1765: if ( fprintf(fp,"%s%s",new_line,tmp_buffer) < 0 ) {
1766: /*printf("Error: cannot write active.log\n");*/
1767: errcode = -1;
1768: }
1769: fflush(fp);
1770: free( (char *)tmp_buffer);
1771: funlockstream(fp);
1772: fclose(fp);
1773: } else { /********************************** First time login */
1774: if ((fp=fopen(filename,"a+"))==NULL) {
1775: /*printf("Error: can't open %s\n",filename);*/
1776: return (-1);
1777: }
1778: log_tries = 1;
1779: time(&login_time);
1780: theDT = localtime(&login_time);
1781: 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);
1782: /*
1783: leng = strlen(line);
1784: for(idx = 0, len_idx = 0; idx<(leng-1); idx++) {
1785: if(line[idx] == '\n' && line[idx+1] == '\n') {
1786: line[idx+1] = 0;
1787: }
1788: }
1789: */
1790: flockstream(fp);
1791: if ( !fwrite((char *)line, strlen(line), 1, fp) ) {
1792: /*printf("ERROR: cannot write active.log\n");*/
1793: errcode = -1;
1794: } else {
1795: errcode = 1;
1796: }
1797: fflush(fp);
1798: funlockstream(fp);
1799: fclose(fp);
1800: }
1801: return (errcode);
1802:
1803: }
1804:
1805: /******************************************************************************/
1806: /* Logout check */
1807: /******************************************************************************/
1808: int /* RETURNS: 1 successful, 0 otherwise, -1 file error */
1809: logout_check(student_number) /* ARGUMENTS: */
1810: char *student_number; /* Student # */
1811: { /* LOCALS: */
1812: FILE *fp;
1813:
1814: int errcode=0;
1815: int found;
1816: char filename[FILE_NAME_LENGTH];
1817: char line[SMALL_LINE_BUFFER];
1818: long offsetL, offsetR, offsetEnd,left_leng;
1819: char s_number[MAX_STUDENT_NUMBER+1];
1820: char tty_name[FILE_NAME_LENGTH];
1821: int log_tries, p_id;
1822: int month, day, year, hour, min, sec;
1823: char *tmp_buffer;
1824:
1825:
1826: sprintf(filename,"records/active.log");
1827: if ((fp=fopen(filename,"r"))==NULL) {
1828: /*printf("Error: can't open %s\n",filename);*/
1829: return (-1);
1830: }
1831: flockstream(fp); /* lock exclusively and perform read/write operation */
1832:
1833: found = 0;
1834: while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) {
1835: if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1;
1836: }
1837: offsetR = ftell(fp);
1838: offsetL = offsetR - strlen(line);
1839:
1840: funlockstream(fp);
1841: fclose(fp);
1842:
1843: if( found ) {
1844: #ifdef __alpha
1845: 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);
1846: #else
1847: sscanf(line,"%s , %d , %d , /dev/%s ,(%d/%d/%d %d:%d:%d)\n", \
1848: s_number,&log_tries,&p_id,tty_name,&month,&day,&year,&hour,&min,&sec);
1849: #endif
1850: switch(log_tries) {
1851: case 0: log_tries = 0;
1852: break;
1853: case 1: log_tries = 0;
1854: break;
1855: case 2: log_tries = 0;
1856: break;
1857: default: printf("ERROR: Number of logins UNKNOWN\n");
1858: log_tries = 0;
1859: break;
1860: }
1861: #ifdef __alpha
1862: 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);
1863: #else
1864: sprintf(line,"%s , %2d , %5d , /dev/%s ,(%02d/%02d/%02d %02d:%02d:%02d)\n", \
1865: s_number,log_tries, p_id, tty_name, month, day, year, hour, min, sec);
1866: #endif
1867:
1868: if ((fp=fopen(filename,"r+"))==NULL) {
1869: /*printf("Error: can't open %s\n",filename);*/
1870: return (-1);
1871: }
1872: flockstream(fp);
1873: tmp_buffer = (char *)malloc(8*1024*56);
1874: fseek(fp,0L,SEEK_END);
1875: offsetEnd = ftell(fp);
1876: left_leng = offsetEnd - offsetR;
1877: fseek(fp,offsetR,SEEK_SET);
1878: fread(tmp_buffer, left_leng, 1, fp);
1879: tmp_buffer[left_leng] = 0;
1880: /*
1881: for(idx=0, l_idx = 0; idx< (left_leng-1); idx++) {
1882: if( tmp_buffer[idx] == '/n' && tmp_buffer[idx+1] == '/n' ) {
1883: }
1884: }
1885: */
1886: fseek(fp,offsetL,SEEK_SET);
1887: if ( fprintf(fp,"%s%s",line,tmp_buffer) < 0 ) {
1888: /*printf("Error: write error\n");*/
1889: errcode = -1;
1890: } else {
1891: errcode = 1;
1892: }
1893: fflush(fp);
1894: free( (char *)tmp_buffer);
1895: funlockstream(fp);
1896: fclose(fp);
1897: } else {
1898: errcode = -1;
1899: }
1900: return (errcode);
1901:
1902: }
1903: /*********************************************/
1904: /* SIZE of char =1, int=4, long=4, double=8 */
1905: void
1906: capa_seed(seed1,seed2,student_number)long *seed1;long *seed2;char *student_number;
1907: {
1908: int class_pin1, class_pin2;
1909: int s_pin1, s_pin2, s_pin3;
1910: int i;
1911: char dest[16], tmpSN[MAX_STUDENT_NUMBER+1];
1912: char *class,*capadefault="capadefault";
1913: long part1, part2;
1914: #if defined(NeXT)
1915: char cwd[FILE_NAME_LENGTH];
1916: #endif
1917: int big_endian;
1918:
1919: big_endian = endian(); /* determine what type of CPU we are on */
1920:
1921: #if defined(NeXT)
1922: class = getwd(cwd);
1923: if( class == NULL ) { class = cwd; }
1924: #else
1925: class = getcwd(NULL,255);
1926: #endif
1927: class_pin1 = class_pin2 = 2;
1928: s_pin1 = s_pin2 = s_pin3 = 2;
1929:
1930: if( class == NULL ) {
1931: printf("capa_seed(): Current working directory unknown! Using capadefault\n");
1932: class=capa_malloc(strlen(capadefault)+1,1);
1933: strcpy(class,capadefault);
1934: }
1935: if( big_endian ) {
1936: for(i=0;i<4;i++) dest[i] = class[strlen(class)-8+i];
1937: for(i=4;i<8;i++) dest[i] = 0;
1938: memcpy((char *)(&class_pin1), dest, 4);
1939: for(i=0;i<4;i++) dest[i] = class[strlen(class)-4+i];
1940: for(i=4;i<8;i++) dest[i] = 0;
1941: memcpy((char *)(&class_pin2), dest, 4);
1942: } else {
1943: for(i=0;i<4;i++) dest[i] = class[strlen(class)-i-5];
1944: for(i=4;i<8;i++) dest[i] = 0;
1945: memcpy((char *)(&class_pin1), dest, 4);
1946: for(i=0;i<4;i++) dest[i] = class[strlen(class)-i-1];
1947: for(i=4;i<8;i++) dest[i] = 0;
1948: memcpy((char *)(&class_pin2), dest, 4);
1949: }
1950: for(i=0;i<MAX_STUDENT_NUMBER;i++) {
1951: if(islower(student_number[i])) {
1952: tmpSN[i] = toupper(student_number[i]);
1953: } else {
1954: tmpSN[i] = student_number[i];
1955: }
1956: }
1957: tmpSN[MAX_STUDENT_NUMBER] = 0;
1958:
1959: if( big_endian ) { /* big endian ** SUN, BlackNeXT 68xxx , PowerPC */
1960: for(i=0;i<4;i++) dest[i] = tmpSN[i];
1961: for(i=4;i<8;i++) dest[i] = 0;
1962: memcpy((char *)(&s_pin1), dest, 4); /* 012345678 -> "0123" */
1963: for(i=0;i<4;i++) dest[i] = tmpSN[i+2];
1964: for(i=4;i<8;i++) dest[i] = 0;
1965: memcpy((char *)(&s_pin2), dest, 4); /* 012345678 -> "2345" */
1966: for(i=0;i<4;i++) dest[i] = tmpSN[i+5];
1967: for(i=4;i<8;i++) dest[i] = 0;
1968: memcpy((char *)(&s_pin3), dest, 4); /* 012345678 -> "5678" */
1969: } else { /* Intel 386, 486 */
1970: for(i=0;i<4;i++) dest[i] = tmpSN[3-i];
1971: for(i=4;i<8;i++) dest[i] = 0;
1972: memcpy((char *)(&s_pin1), dest, 4); /* 012345678 -> "0123" */
1973: for(i=0;i<4;i++) dest[i] = tmpSN[5-i];
1974: for(i=4;i<8;i++) dest[i] = 0;
1975: memcpy((char *)(&s_pin2), dest, 4); /* 012345678 -> "2345" */
1976: for(i=0;i<4;i++) dest[i] = tmpSN[8-i];
1977: for(i=4;i<8;i++) dest[i] = 0;
1978: memcpy((char *)(&s_pin3), dest, 4); /* 012345678 -> "5678" */
1979: }
1980:
1981:
1982: part1 = s_pin1 + s_pin3+ class_pin2; if(part1 < 0) part1 = part1 * (-1);
1983: part2 = s_pin2 + class_pin1; if(part2 < 0) part2 = part2 * (-1);
1984:
1985: #ifdef SEED_DBG
1986: printf("S_PIN(%d,%d, %d) C_PIN(%d,%d)\n",s_pin1, s_pin2, s_pin3, class_pin1, class_pin2);
1987: printf("SEED(%ld,%ld)\n",part1, part2);
1988: #endif
1989: {
1990: extern void gsrgs(long getset,long *qvalue);
1991: static long qrgnin;
1992: gsrgs(0L,&qrgnin);
1993: if(!qrgnin)
1994: setall(part1, part2);
1995: }
1996: (*seed1) = part1;
1997: (*seed2) = part2;
1998: free(class);
1999: }
2000: /* ======================================================= PIN number */
2001: /* pin should only called once for each student. */
2002: /* if not called at the beginning of problem set, try to call it automatically */
2003:
2004: int /* RETURNS: pin number for login set */
2005: capa_PIN(student_number, set, guess) /* ARGUMENTS: */
2006: char *student_number;
2007: int set; /* Problem set number */
2008: int guess;
2009: { /* LOCALS: */
2010: int current=0, /* Current pin for set */
2011: i,j, /* Array indices */
2012: nope,
2013: correct=0,
2014: all_pins[ONE_K];
2015: long part1, part2;
2016: long orig_gen, new_gen;
2017:
2018: capa_seed(&part1, &part2, student_number);
2019: gscgn(GET_GENERATOR, &orig_gen);
2020: new_gen = PIN_G;
2021: gscgn(SET_GENERATOR, &new_gen);
2022: setsd(part1, part2);
2023: /* Generate 4-digit pin (1000-9999) */
2024: for (i=1; i<=set; i++) {
2025: current=1000+ignlgi()%9000;
2026: do {
2027: nope=0;
2028: for (j=1; j<i; j++) {
2029: if (current == all_pins[j]) {
2030: current=1000+ignlgi()%9000;
2031: nope++;
2032: }
2033: }
2034: } while (nope);
2035: all_pins[i]=current;
2036: if (guess && guess==current) correct=i;
2037: }
2038: gscgn(SET_GENERATOR, &orig_gen);
2039: if (guess) return (correct);
2040: return (current);
2041: }
2042:
2043: /* -------------------------------------------------------------------- */
2044: /* returns a longer pin, the first four characters are the same as the */
2045: /* normal capaId, additionally the result is a capa_malloc string */
2046: /* containing the number */
2047: /* NOTE!-> the result is a string of letters where A=1..I=9,J=0 */
2048: /* -------------------------------------------------------------------- */
2049: char*
2050: capa_id_plus(student_number, set, plus)
2051: char *student_number;
2052: int set;
2053: int plus;
2054: {
2055: long part1,part2,orig_gen,new_gen,pin,rout,k,i;
2056: char *result;
2057: char letters[10]={'J','A','B','C','D','E','F','G','H','I'};
2058: capa_seed(&part1, &part2, student_number);
2059: gscgn(GET_GENERATOR, &orig_gen);
2060: new_gen = PIN_G;
2061: gscgn(SET_GENERATOR, &new_gen);
2062: setsd(part1, part2);
2063: pin=capa_PIN(student_number,set,0);
2064: result=(char *)capa_malloc(sizeof(char), plus+MAX_PIN_CHAR+1);
2065: k=1;
2066: for(i=1;i<=MAX_PIN_CHAR;i++) {
2067: result[MAX_PIN_CHAR-i] = letters[(pin%(k*10))/k];
2068: k*=10;
2069: }
2070: for(i=MAX_PIN_CHAR;i<MAX_PIN_CHAR+plus;i++) {
2071: rout = ignlgi()%10;
2072: result[i] = letters[rout];
2073: }
2074: result[i] = '\0';
2075: gscgn(SET_GENERATOR, &orig_gen);
2076: return result;
2077: }
2078: /* -------------------------------------------------------------------- */
2079: /* need to set problem_p = NULL after this call */
2080: /* -------------------------------------------------------------------- */
2081: void
2082: free_problems(problem_p) Problem_t *problem_p;
2083: {
2084: Problem_t *p, *next;
2085:
2086: for (p=problem_p; p!=NULL ; p=next) {
2087: next=p->next;
2088: if (p->question != NULL) capa_mfree(p->question);
2089: if (p->answer != NULL) capa_mfree(p->answer);
2090: if (p->ans_cnt > 1 ) { AnswerInfo_t *a,*b;
2091: for(a = p->ans_list; a != NULL ; a = b) {
2092: b = a->ans_next;
2093: if (a->ans_str != NULL) capa_mfree(a->ans_str);
2094: if (a->ans_id_list != NULL ) capa_mfree(a->ans_id_list);
2095: if (a->ans_pts_list) {
2096: free_ptslist(a->ans_pts_list);
2097: }
2098: if (a->ans_unit) {
2099: freelist_unit_e(a->ans_unit->u_list);
2100: if (a->ans_unit != NULL) capa_mfree((char *)a->ans_unit);
2101: }
2102: capa_mfree((char *)a);
2103: }
2104: }
2105: if (p->id_list != NULL ) capa_mfree(p->id_list);
2106: if (p->pts_list!= NULL ) {
2107: free_ptslist(p->pts_list);
2108: }
2109: if (p->hint != NULL ) capa_mfree(p->hint);
2110: if (p->explain != NULL ) capa_mfree(p->explain);
2111: if (p->ans_unit !=NULL ) {
2112: freelist_unit_e(p->ans_unit->u_list);
2113: capa_mfree((char *)p->ans_unit);
2114: }
2115: capa_mfree((char *)p);
2116: p=NULL;
2117: }
2118: problem_p=NULL;
2119: }
2120:
2121: /******************************************************************************/
2122: /* PARSE SOURCE FILE AND RETURN BLOCKS OF TEXT */
2123: /******************************************************************************/
2124: int
2125: capa_parse(set,problem,student_number,num_questions,func_ptr)
2126: int set;Problem_t **problem;char *student_number;int *num_questions;
2127: void (*func_ptr)();
2128: {
2129: char filename[QUARTER_K];
2130: int errcode;
2131: FILE *fp;
2132: extern FILE *Input_stream[MAX_OPENED_FILE];
2133: extern char Opened_filename[MAX_OPENED_FILE][QUARTER_K];
2134: extern int Lexi_line;
2135: extern int Lexi_qnum;
2136: extern Problem_t *FirstProblem_p;
2137: extern Problem_t *LastProblem_p;
2138: extern Problem_t *LexiProblem_p;
2139: extern char *StartText_p;
2140: extern char *EndText_p;
2141: extern char *ErrorMsg_p;
2142: extern int ErrorMsg_count;
2143: extern char Parse_class[QUARTER_K];
2144: extern int Parse_section;
2145: extern int Parse_set;
2146: extern char Parse_name[MAX_NAME_CHAR+1];
2147: extern char Parse_student_number[MAX_STUDENT_NUMBER+1];
2148: extern int Symb_count;
2149: extern int first_run;
2150: extern int Stop_Parser;
2151: extern void (*Status_Func)();
1.11 albertel 2152: #ifdef TTH
2153: extern void tth_restart();
2154: extern char* tth_err;
2155: #endif /*TTH*/
1.1 albertel 2156: long seed1, seed2;
2157: T_student a_student;
2158: char *class, *classname, warn_msg[WARN_MSG_LENGTH];
2159: #if defined(NeXT)
2160: char cwd[FILE_NAME_LENGTH];
2161:
2162: class = getwd(cwd);
2163: if( class == NULL ) { class = cwd; }
2164: #else
2165: class = getcwd(NULL,255);
2166:
2167: #endif
2168:
2169: if(class == NULL) { /* printf("capa_parse(): Current working directory unknown!"); */ return (-1); }
2170: classname = rindex(class,'/'); classname++; /*** hpux complained */
2171: sprintf(Parse_class,"%s", classname);
2172: free(class);
2173: if( capa_get_student(student_number, &a_student) < 1 ) {
2174: /*printf("Error: capa_parse() encountered a student which is not in classl file\n"); */
2175: return (-1);
2176: }
2177: sprintf(filename,"capa.config");
2178: if ((fp=fopen(filename,"r"))==NULL) {
2179: /* printf("Error: can't open %s\n",filename);*/
2180: return (-1);
2181: }
2182: u_getunit(fp);
2183: fclose(fp);
1.11 albertel 2184: #ifdef TTH
2185: if(tth_err) { free(tth_err); tth_err=NULL; }
2186: tth_restart();
2187: #endif /*TTH*/
1.1 albertel 2188: strncpy(Parse_name,a_student.s_nm,MAX_NAME_CHAR+1);
2189: strncpy(Parse_student_number,student_number,MAX_STUDENT_NUMBER+1);
2190: Parse_section = a_student.s_sec;
2191: if(ErrorMsg_p) { capa_mfree(ErrorMsg_p); ErrorMsg_p = NULL; }
2192: if(EndText_p) { capa_mfree(EndText_p); EndText_p = NULL; }
2193: if(StartText_p) { capa_mfree(StartText_p); StartText_p = NULL; }
2194: ErrorMsg_p = NULL; first_run = 1; EndText_p = NULL;
2195: free_symtree(); Symb_count = ErrorMsg_count = Lexi_line = Lexi_qnum = 0;
2196: FirstProblem_p = LastProblem_p = NULL;
2197: LexiProblem_p = (Problem_t *)capa_malloc(sizeof(Problem_t),1);
2198: problem_default(LexiProblem_p);
2199: /*LexiProblem_p->capaidplus=NULL;*/
2200: Parse_set = set;
2201: Status_Func=func_ptr;
2202: sprintf(filename,"set%d.qz",set);
2203: #ifdef AVOIDYYINPUT
2204: yyin=fopen(filename,"r");
2205: #else
2206: if ( (Input_stream[0]=fopen(filename,"r")) == NULL) {
2207: /* printf("Error: can't open %s\n",filename);*/
2208: sprintf(warn_msg,"capa_parse(): CANNOT OPEN FILE\"%s\", file does not exist or is not readable.\n", filename);
2209: capa_msg(MESSAGE_ERROR,warn_msg);
2210: return (-1);
2211: }
2212: #endif
2213: sprintf(Opened_filename[0],"%s",filename);
2214:
2215: capa_seed(&seed1, &seed2, student_number); setall(seed1,seed2);
2216:
2217: yyrestart(yyin);
2218: Stop_Parser=0;
2219: if ( !yyparse() ) { errcode = Lexi_qnum; } else { errcode = 0; }
2220: /* fclose(Input_stream[0]);*/ /* The Lexer handles closing this */
2221: /* print_symb_stat(); */
2222: free_symtree();
2223: /*
2224: capa_mfree((char *)LexiProblem_p);
2225: LexiProblem_p = NULL;
2226: */
2227: (*problem) = FirstProblem_p;
2228: (*num_questions) = Lexi_qnum;
2229: return (errcode);
2230: }
2231:
2232: /******************************************************************************/
2233: /* PARSE SOURCE FILE AND RETURN BLOCKS OF TEXT, unlike capa_parse_student */
2234: /******************************************************************************/
2235: int
2236: capa_parse_student(set,problem,a_student,num_questions,func_ptr)
2237: int set;Problem_t **problem;T_student *a_student;int *num_questions;
2238: void (*func_ptr)();
2239: {
2240: char filename[QUARTER_K];
2241: int errcode;
2242: FILE *fp;
2243: extern FILE *Input_stream[MAX_OPENED_FILE];
2244: extern char Opened_filename[MAX_OPENED_FILE][QUARTER_K];
2245: extern int Lexi_line;
2246: extern int Lexi_qnum;
2247: extern Problem_t *FirstProblem_p;
2248: extern Problem_t *LastProblem_p;
2249: extern Problem_t *LexiProblem_p;
2250: extern char *StartText_p;
2251: extern char *EndText_p;
2252: extern char *ErrorMsg_p;
2253: extern int ErrorMsg_count;
2254: extern char Parse_class[QUARTER_K];
2255: extern int Parse_section;
2256: extern int Parse_set;
2257: extern char Parse_name[MAX_NAME_CHAR+1];
2258: extern char Parse_student_number[MAX_STUDENT_NUMBER+1];
2259: extern int Symb_count;
2260: extern int first_run;
2261: extern void (*Status_Func)();
2262: long seed1, seed2;
2263: char *class, *classname, warn_msg[WARN_MSG_LENGTH];
2264:
2265: #if defined(NeXT)
2266: char cwd[FILE_NAME_LENGTH];
2267:
2268: class = getwd(cwd);
2269: if( class == NULL ) { class = cwd; }
2270: #else
2271: class = getcwd(NULL,255);
2272:
2273: #endif
2274:
2275: if(class == NULL) { /* printf("capa_parse(): Current working directory unknown!"); */ return (-1); }
2276: classname = rindex(class,'/'); classname++; /*** hpux complained */
2277: sprintf(Parse_class,"%s", classname);
2278: free(class);
2279:
2280: sprintf(filename,"capa.config");
2281: if ((fp=fopen(filename,"r"))==NULL) {
2282: /* printf("Error: can't open %s\n",filename);*/
2283: sprintf(warn_msg,"capa_parse(): CANNOT OPEN FILE\"%s\", file does not exist or is not readable.\n", filename);
2284: capa_msg(MESSAGE_ERROR,warn_msg);
2285: return (-1);
2286: }
2287: u_getunit(fp);
2288: fclose(fp);
2289: strncpy(Parse_name,a_student->s_nm,MAX_NAME_CHAR+1);
2290: strncpy(Parse_student_number,a_student->s_sn,MAX_STUDENT_NUMBER+1);
2291: Parse_section = a_student->s_sec;
2292: if(ErrorMsg_p) { capa_mfree(ErrorMsg_p); ErrorMsg_p = NULL; }
2293: if(EndText_p) { capa_mfree(EndText_p); EndText_p = NULL; }
2294: if(StartText_p) { capa_mfree(StartText_p); StartText_p = NULL; }
2295: ErrorMsg_p = NULL; first_run = 1; EndText_p = NULL;
2296: free_symtree(); Symb_count = ErrorMsg_count = Lexi_line = Lexi_qnum = 0;
2297: FirstProblem_p = LastProblem_p = NULL;
2298: LexiProblem_p = (Problem_t *)capa_malloc(sizeof(Problem_t),1);
2299: problem_default(LexiProblem_p);
2300: /*LexiProblem_p->capaidplus=NULL;*/
2301: Parse_set = set;
2302: Status_Func=func_ptr;
2303: sprintf(filename,"set%d.qz",set);
2304: #ifdef AVOIDYYINPUT
2305: yyin=fopen(filename,"r");
2306: #else
2307: if ( (Input_stream[0]=fopen(filename,"r")) == NULL) {
2308: /* printf("Error: can't open %s\n",filename);*/
2309: sprintf(warn_msg,"capa_parse(): CANNOT OPEN FILE\"%s\", file does not exist or is not readable.\n", filename);
2310: capa_msg(MESSAGE_ERROR,warn_msg);
2311: return (-1);
2312: }
2313: #endif
2314: sprintf(Opened_filename[0],"%s",filename);
2315:
2316: capa_seed(&seed1, &seed2, a_student->s_sn); setall(seed1,seed2);
2317:
2318: yyrestart(yyin);
2319: if ( !yyparse() ) { errcode = Lexi_qnum; } else { errcode = 0; }
2320: /* fclose(Input_stream[0]);*/ /*The Lexer handles closing this*/
2321: /* print_symb_stat(); */
2322: free_symtree();
2323: /*
2324: capa_mfree((char *)LexiProblem_p);
2325: LexiProblem_p = NULL;
2326: */
2327: (*problem) = FirstProblem_p;
2328: (*num_questions) = Lexi_qnum;
2329: return (errcode);
2330: }
2331:
2332: /* =================================================================== */
2333: /* A utility method to convert a date string and time string to time_t */
2334: /* dateStr: yyyy/mm/dd */
2335: /* timeStr: hh:mm */
2336: time_t
2337: convertTime(dateStr,timeStr)char *dateStr; char *timeStr;
2338: {
2339: struct tm *theTimeData;
2340: time_t result;
2341: int dateTime[5];
2342: int year, month, day, mm, hh;
2343:
2344: sscanf(dateStr,"%4d/%2d/%2d",&year,&month,&day);
2345: dateTime[0] = month;
2346: dateTime[1] = day;
2347: dateTime[2] = year;
2348: sscanf(timeStr,"%2d:%2d",&hh,&mm);
2349: dateTime[3] = hh;
2350: dateTime[4] = mm;
2351: result = time(NULL);
2352: theTimeData = localtime(&result);
2353: theTimeData->tm_sec = 0;
2354: theTimeData->tm_min = dateTime[4];
2355: theTimeData->tm_hour = dateTime[3];
2356: theTimeData->tm_mday = dateTime[1];
2357: theTimeData->tm_mon = dateTime[0]-1;
2358: theTimeData->tm_year = dateTime[2]-1900;/* tm_year is years since 1900 */
2359: /* these fields are ignored by mktime
2360: theTimeData->tm_wday = weekday(year,month,day);
2361: theTimeData->tm_yday = julianday(year,month,day);
2362: */
2363: result = mktime( theTimeData );
2364: return (result);
2365: }
2366:
2367: int
2368: weekday( year, month, day) int year; int month; int day;
2369: {
2370: register int dow;
2371: #if defined(hpux)
2372: int juldays[13];
2373: juldays[0]=0;juldays[1]=0;juldays[2]=31;juldays[3]=59;
2374: juldays[4]=90;juldays[5]=120;juldays[6]=151;juldays[7]=181;
2375: juldays[8]=212;juldays[9]=243;juldays[10]=273;juldays[11]=304;juldays[12]=334;
2376: #else
2377: int juldays[13] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
2378: #endif
2379:
2380: dow = 7 + year + year/4 - year/100 + year/400 + juldays[month] + day;
2381: if( (month < 3) && ( leap_year(year) ) ) dow--;
2382: dow %= 7;
2383: return (dow);
2384: } /* weekday */
2385:
2386: int
2387: julianday( year, month, day)int year;int month;int day;
2388: {
2389: register int doy;
2390: #if defined(hpux)
2391: int juldays[13];
2392: juldays[0]=0;juldays[1]=0;juldays[2]=31;juldays[3]=59;
2393: juldays[4]=90;juldays[5]=120;juldays[6]=151;juldays[7]=181;
2394: juldays[8]=212;juldays[9]=243;juldays[10]=273;juldays[11]=304;juldays[12]=334;
2395: #else
2396: int juldays[13] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
2397: #endif
2398:
2399: doy = juldays[month];
2400: if((month > 2) && (leap_year(year)) ) doy++;
2401: doy += day;
2402: return (doy);
2403: } /* julianday */
2404:
2405: int
2406: check_int( an_int ) char *an_int;
2407: {
2408: int ii, leng;
2409: int result=0;
2410:
2411: if( (an_int[0] == '-') || (an_int[0]== '+') ) an_int++;
2412: leng = strlen(an_int);
2413: for(ii=0;ii<leng;ii++) {
2414: if( !isdigit(an_int[ii]) ) result = 1;
2415: }
2416: return (result);
2417: }
2418: /* --------------------------- */
2419: /* 0 OK , 1 NOT a real number */
2420: int
2421: check_real( a_real ) char *a_real;
2422: {
2423: int ii, leng;
2424: int result=0;
2425:
2426: if( (a_real[0] == '-') || (a_real[0]== '+') ) a_real++;
2427: leng = strlen(a_real);
2428: for(ii=0;ii<leng;ii++) {
2429: if( (!isdigit(a_real[ii])) && (a_real[ii]!='e') && (a_real[ii]!='E') &&
2430: (a_real[ii]!='.') && (a_real[ii]!='+') && (a_real[ii]!='-') ) result = 1;
2431: }
2432: return (result);
2433: }
2434:
2435: int
2436: check_input_usymb(u_symb)char *u_symb;
2437: {
2438: int result=0;
2439:
2440:
2441: return (result);
2442: }
2443:
2444: /* <== This routine determine emperically where to split a character */
2445: /* string into two portions, one for numerical answer and the */
2446: /* other for units */
2447: /* ----------------------------------------------------------------- */
2448: /* inputs : buf : answer string */
2449: /* outputs: num : the numerical part */
2450: /* num_p : the numerical part in string */
2451: /* unit_p : the unit string */
2452: /* num_p is used to calculate sig figs */
2453: /* return : 0 empty string */
2454: /* 1 number without units */
2455: /* 2 empty number with units */
2456: /* 3 number with units */
2457: /* */
2458: int split_num_unit(buf,num,num_p,unit_p)
2459: char *buf;double *num; char *num_p; char *unit_p;
2460: {
2461: char num_str[ANSWER_STRING_LENG], unit_str[ANSWER_STRING_LENG];
2462: char base_str[ANSWER_STRING_LENG], exp_str[ANSWER_STRING_LENG];
2463: int idx=0, errcode=0;
2464: int len, ii, n_idx=0, b_idx=0, e_idx=0, u_idx=0;
2465: double n_part, x_part, b_part, e_part, result;
2466:
2467: unit_str[0]=0; /* initialize unit_str[] */
2468: len = strlen(buf);
2469: while( isspace(buf[idx]) ) { idx++; } /* ignore white spaces */
2470: num_str[n_idx]=0; /* initialize number string */
2471: if( buf[idx] == '+' || buf[idx] == '-' ) {
2472: /* the first char is either '+' or '-' */
2473: num_str[n_idx++]= buf[idx++];
2474: }
2475: /* skip over alphabet char and those that are not '.' */
2476: while( (!isdigit( buf[idx] )) && buf[idx] != '.' ) { idx++; }
2477: while( isdigit( buf[idx] ) || buf[idx] == '.' ) { /* collect decimal numbers */
2478: num_str[n_idx++]= buf[idx++];
2479: }
2480: num_str[n_idx] = 0; /* end the string with a '\0' */
2481: sprintf(num_p,"%s",num_str); /* put the collected numerical string in num_p */
2482: /* skip over white spaces */
2483: while( isspace(buf[idx]) ) { idx++; }
2484: if( buf[idx] == 'e' || buf[idx] == 'E' ) { /* optional e or E part */
2485: /* peek further one char to see if it belongs to one of the following */
2486: if( buf[idx+1] == '-' || buf[idx+1] == '+' || isspace(buf[idx+1]) || isdigit(buf[idx+1])) {
2487: num_str[n_idx++] = buf[idx++]; /* should be 'e' or 'E' */
2488: while( isspace(buf[idx]) ) { idx++; } /* skip over spaces */
2489: num_str[n_idx++] = buf[idx++]; /* the second char '-', '+' or digit */
2490: while( isdigit(buf[idx]) ) { /* only integer is allowed, not '.' */
2491: num_str[n_idx++] = buf[idx++];
2492: }
2493: }
2494: num_str[n_idx] = 0; /* terminiate the numerical string */
2495: while( isspace(buf[idx]) ) { idx++; }
2496: sscanf(num_str, "%lg", &result); /* put the numerical value into a double variable */
2497: errcode = errcode | 1;
2498: } else if( buf[idx] == 'x' || buf[idx] == 'X') { /* optional x or X part */
2499: idx++; /* skip x or X */
2500: while( isspace(buf[idx]) ) { idx++; }
2501:
2502: e_part = 1.0; /* default power */
2503: base_str[b_idx] = 0; /* initialize base_str[] */
2504: while( isdigit(buf[idx]) || buf[idx] == '.' ) { /* should start with a digit or . */
2505: base_str[b_idx++] = buf[idx++];
2506: }
2507: base_str[b_idx] = 0; /* terminate base_str[] */
2508: while( isspace(buf[idx]) ) { idx++; } /* skip over white spaces */
2509: if( buf[idx] == '^' ) { /* power */
2510: idx++;
2511: exp_str[e_idx] = 0; /* initialize exp_str[] */
2512: while( isspace(buf[idx]) ) { idx++; }
2513: if( buf[idx] == '{'|| buf[idx] == '(' ) { /* matching right bracket */
2514: idx++;
2515: }
2516: while( isspace(buf[idx]) ) { idx++; }
2517: if( isdigit(buf[idx]) || buf[idx] == '+' || buf[idx] == '-' ) {
2518: exp_str[e_idx] = 0; /* initialize exp_str[], again */
2519: while( isdigit(buf[idx]) || buf[idx] == '.' || buf[idx] == '+' || buf[idx] == '-' ) {
2520: exp_str[e_idx++] = buf[idx++];
2521: }
2522: exp_str[e_idx] = 0; /* terminate exp_str[] */
2523: }
2524: while( isspace(buf[idx]) ) { idx++; }
2525: if( buf[idx] == '}' || buf[idx] == ')' ) {
2526: idx++;
2527: }
2528: sscanf(exp_str, "%lg", &e_part);
2529: }
2530: if( strlen(base_str) > 0 ) {
2531: sscanf(base_str, "%lg", &b_part);
2532: x_part = pow(b_part, e_part);
2533: } else {
2534: x_part = 0.0;
2535: }
2536: if( strlen(num_str) > 0 ) {
2537: sscanf(num_str, "%lg", &n_part);
2538: } else {
2539: n_part=0.0;
2540: }
2541: result = n_part * x_part;
2542: errcode = errcode | 1;
2543: } else if ( buf[idx] == '^' ) { /* number ^ */
2544: idx++;
2545: e_part = 1.0;
2546: while( isspace(buf[idx]) ) { idx++; }
2547: if( buf[idx] == '{'|| buf[idx] == '(' ) { /* matching right bracket */
2548: idx++;
2549: }
2550: while( isspace(buf[idx]) ) { idx++; }
2551: if( isdigit(buf[idx]) || buf[idx] == '+' || buf[idx] == '-' ) {
2552: exp_str[e_idx] = 0;
2553: while( isdigit(buf[idx]) || buf[idx] == '.' || buf[idx] == '+' || buf[idx] == '-' ) {
2554: exp_str[e_idx++] = buf[idx++];
2555: }
2556: exp_str[e_idx] = 0;
2557: }
2558: while( isspace(buf[idx]) ) { idx++; }
2559: if( buf[idx] == '}' || buf[idx] == ')' ) {
2560: idx++;
2561: }
2562: sscanf(exp_str, "%lg", &e_part);
2563: sscanf(num_str, "%lg", &n_part);
2564: result = pow(n_part,e_part);
2565: errcode = errcode | 1;
2566: } else { /* number unit */
2567: if( strlen(num_str) > 0 ) {
2568: sscanf(num_str, "%lg", &result);
2569: errcode = errcode | 1;
2570: }
2571: }
2572:
2573: if( idx < len ) { /* collect the rest as unit string */
2574: for(ii=idx;ii< len; ii++ ) {
2575:
2576: unit_str[u_idx++] = buf[ii];
2577: }
2578: unit_str[u_idx]=0; /* terminate unit_str[] */
2579: if(u_idx>0) {
2580: errcode = errcode | 2;
2581: }
2582: }
2583: if( strlen(num_str) > 0 ) {
2584: *num = result;
2585: } else { /* empty number string */
2586: *num = 0.0;
2587: }
2588: sprintf(unit_p,"%s", unit_str);
2589: return (errcode);
2590: }
2591:
2592: char *
2593: answers_string(mode, p)int mode;Problem_t *p;
2594: {
2595: char *fmted_ans, lower[ANSWER_STRING_LENG], upper[ANSWER_STRING_LENG];
2596: char *str_aa, *str_bb, *str_cc, *ans_str, *sub_ans_str, *tmp_str;
2597: int len_aa=0, len_bb=0, len_cc=0,len_dd=0, total_len, num_answer;
2598: double d_answer;
2599:
2600: if( p->ans_type == ANSWER_IS_SUBJECTIVE ) {
2601: char *a="Subjective Answer\n";
2602: ans_str = (char *)capa_malloc(strlen(a)+1,1);
2603: strcpy(ans_str,a);
2604: return (ans_str);
2605: }
2606: num_answer = calc_ansrange(p->ans_type,p->calc, p->answer, p->ans_fmt, p->tol_type,
2607: p->tolerance, lower, upper);
2608:
2609: if( p->ans_type == ANSWER_IS_FLOAT ) {
2610: fmted_ans = capa_malloc(SMALL_LINE_BUFFER,1);
2611: d_answer = (double)atof(p->answer);
2612: sprintf(fmted_ans,p->ans_fmt,d_answer);
2613: } else {
2614: fmted_ans = capa_malloc(strlen(p->answer)+2,1);
2615: strcpy(fmted_ans,p->answer);
2616: }
2617:
2618: len_aa = strlen(fmted_ans);
2619: if (lower != NULL ) len_bb = strlen(lower); else len_bb = 0;
2620: if (upper != NULL ) len_cc = strlen(upper); else len_cc = 0;
2621: if ( p->unit_str != NULL ) len_dd = strlen(p->unit_str); else len_dd = 0;
2622:
2623: switch(mode) {
2624: case TeX_MODE:
2625: if(num_answer==2) {
2626: /* 16 is by adding up characters ' [,] \n\n' and others */
2627: str_aa = format_toTeX(fmted_ans);
2628: total_len = strlen(str_aa) + len_dd + 16;
2629: str_bb = format_toTeX(lower);
2630: total_len += strlen(str_bb);
2631: str_cc = format_toTeX(upper);
2632: total_len += strlen(str_cc);
2633: ans_str = (char *)capa_malloc(total_len,1);
2634: if(len_dd == 0 ) { /* no unit_str */
2635: sprintf(ans_str," %s [%s,%s]\n\n", str_aa,str_bb,str_cc);
2636: } else {
2637: sprintf(ans_str," %s [%s,%s] $%s$\n\n", str_aa,str_bb,str_cc,p->unit_str);
2638: }
2639: capa_mfree((char *)str_aa);
2640: capa_mfree((char *)str_bb);
2641: capa_mfree((char *)str_cc);
2642: } else { /* only one answer */
2643: if ( (p->ans_type == ANSWER_IS_INTEGER) ||
2644: (p->ans_type == ANSWER_IS_FLOAT )) {
2645: str_bb = format_toTeX(lower);
2646: } else { /* answer could be string, choice */
2647: str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1);
1.10 albertel 2648: if (p->verbatim == DO_VERBATIM)
1.1 albertel 2649: sprintf(str_bb,"\\begin{verbatim}%s\\end{verbatim}",lower);
2650: else
2651: strcpy(str_bb,lower);
2652: }
2653: total_len = strlen(str_bb) + len_dd + 8;
2654: /* 4 is by adding up characters ' \\\n' plus four */
2655: ans_str = (char *)capa_malloc(sizeof(char),total_len);
2656: if(len_dd == 0 ) { /* no unit_str */
2657: sprintf(ans_str," %s\n", str_bb);
2658: } else {
2659: sprintf(ans_str," %s $%s$\n", str_bb,p->unit_str);
2660: }
2661: capa_mfree((char *)str_bb);
2662: }
2663: break;
2664: case ASCII_MODE:
2665: total_len = len_aa + len_bb + len_cc + len_dd + 8;
2666: /* 8 is by adding up characters ' [,] \n\n' plus one */
2667: ans_str = (char *)capa_malloc(sizeof(char),total_len);
2668: if(num_answer==2) {
2669: if(len_dd == 0 ) { /* no unit_str */
2670: sprintf(ans_str,"%s [%s,%s]\n\n", fmted_ans,lower,upper);
2671: } else {
2672: sprintf(ans_str,"%s [%s,%s] %s\n\n", fmted_ans,lower,upper,p->unit_str);
2673: }
2674: } else {
2675: if(len_dd == 0 ) { /* no unit_str */
2676: sprintf(ans_str,"%s\n\n", lower);
2677: } else {
2678: sprintf(ans_str,"%s %s\n\n", lower,p->unit_str);
2679: }
2680: }
2681: break;
2682: case ANSWER_STRING_MODE:
2683: total_len = len_aa + len_bb + len_cc + len_dd + 8;
2684: /* 8 is by adding up characters ' [,] \n\n' plus one */
2685: ans_str = (char *)capa_malloc(sizeof(char),total_len);
2686: if(num_answer==2) {
2687: if(len_dd == 0 ) { /* no unit_str */
2688: sprintf(ans_str,"%s", fmted_ans);
2689: } else {
2690: sprintf(ans_str,"%s %s", fmted_ans,p->unit_str);
2691: }
2692: } else {
2693: if(len_dd == 0 ) { /* no unit_str */
2694: sprintf(ans_str,"%s", lower);
2695: } else {
2696: sprintf(ans_str,"%s %s", lower,p->unit_str);
2697: }
2698: }
2699: break;
2700: case HTML_MODE:
2701: if(num_answer==2) { /* this indicates that answer should be either float or int
2702: */
2703: str_aa = format_toHTML(fmted_ans);
2704: total_len = strlen(str_aa) + len_dd + 8;
2705: str_bb = format_toHTML(lower);
2706: total_len += strlen(str_bb);
2707: str_cc = format_toHTML(upper);
2708: total_len += strlen(str_cc);
2709: /* 8 is by adding up characters ' [,] \n\n' plus one */
2710: ans_str = (char *)capa_malloc(sizeof(char),total_len);
2711: if(len_dd == 0 ) { /* no unit_str */
2712: sprintf(ans_str,"%s [%s,%s]\n\n", str_aa,str_bb,str_cc);
2713: } else {
2714: sprintf(ans_str,"%s [%s,%s] %s\n\n", str_aa,str_bb,str_cc,p->unit_str);
2715: }
2716: capa_mfree((char *)str_aa); capa_mfree((char *)str_bb); capa_mfree((char
2717: *)str_cc);
2718: } else {
2719: if ( (p->ans_type == ANSWER_IS_INTEGER) ||
2720: (p->ans_type == ANSWER_IS_FLOAT )) {
2721: str_bb = format_toHTML(lower);
2722: } else { /* answer could be string, choice */
2723: str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1);
2724: if (p->ans_type == ANSWER_IS_FORMULA || 1)
2725: sprintf(str_bb,"<PRE>\n%s\n</PRE>",lower);
2726: else
2727: strcpy(str_bb,lower);
2728: }
2729: total_len = strlen(str_bb) + len_dd + 4;
2730: /* 4 is by adding up characters ' \n\n' plus one */
2731: ans_str = (char *)capa_malloc(sizeof(char),total_len);
2732: if(len_dd == 0 ) { /* no unit_str */
2733: sprintf(ans_str,"%s\n\n", str_bb);
2734: } else {
2735: sprintf(ans_str,"%s %s\n\n", str_bb,p->unit_str);
2736: }
2737: capa_mfree((char *)str_bb);
2738: }
2739: break;
2740: }
2741: capa_mfree(fmted_ans);
2742:
2743: if( p->ans_cnt > 1 ) {
2744: AnswerInfo_t *ai;
2745: for( ai = p->ans_list; ai; ai = ai->ans_next) {
2746: num_answer = calc_ansrange(ai->ans_type,ai->ans_calc, ai->ans_str, ai->ans_fmt,
2747: ai->ans_tol_type,ai->ans_tol,lower,upper);
2748: if( ai->ans_type == ANSWER_IS_FLOAT ) {
2749: fmted_ans = capa_malloc(SMALL_LINE_BUFFER,1);
2750: d_answer = (double)atof(ai->ans_str);
2751: sprintf(fmted_ans,ai->ans_fmt,d_answer);
2752: } else {
2753: fmted_ans = capa_malloc(strlen(ai->ans_str)+2,1);
2754: strcpy(fmted_ans,ai->ans_str);
2755: }
2756: len_aa = strlen(fmted_ans);
2757: len_bb = strlen(lower);
2758: len_cc = strlen(upper);
2759: len_dd = strlen(ai->ans_unit_str);
2760: switch(mode) {
2761: case TeX_MODE:
2762: if(num_answer==2) {
2763: /* 16 is by adding up characters ' [,] \n\n' and others */
2764:
2765: str_aa = format_toTeX(fmted_ans);
2766: total_len = strlen(str_aa) + len_dd + 16;
2767: str_bb = format_toTeX(lower);
2768: total_len += strlen(str_bb);
2769: str_cc = format_toTeX(upper);
2770: total_len += strlen(str_cc);
2771:
2772: sub_ans_str = (char *)capa_malloc(sizeof(char),total_len);
2773:
2774: if(len_dd == 0 ) { /* no unit_str */
2775: sprintf(sub_ans_str," %s [%s,%s]\n\n", str_aa,str_bb,str_cc);
2776: } else {
2777: sprintf(sub_ans_str," %s [%s,%s] $%s$\n\n",
2778: str_aa,str_bb,str_cc,ai->ans_unit_str);
2779: }
2780: capa_mfree((char *)str_aa); capa_mfree((char *)str_bb); capa_mfree((char *)str_cc);
2781: } else { /* only one answer */
2782: if ( (ai->ans_type == ANSWER_IS_INTEGER) ||
2783: (ai->ans_type == ANSWER_IS_FLOAT )) {
2784: str_bb = format_toTeX(lower);
2785: } else { /* answer could be string, choice */
2786: str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1);
2787: if (ai->ans_type == ANSWER_IS_FORMULA || 1)
2788: sprintf(str_bb,"\\begin{verbatim}%s\\end{verbatim}",lower);
2789: else
2790: strcpy(str_bb,lower);
2791: }
2792: total_len = strlen(str_bb) + len_dd + 8;
2793: /* 4 is by adding up characters ' \\\n' plus four */
2794: sub_ans_str = (char *)capa_malloc(sizeof(char),total_len);
2795: if(len_dd == 0 ) { /* no unit_str */
2796: sprintf(sub_ans_str," %s\n", str_bb);
2797: } else {
2798: sprintf(sub_ans_str," %s $%s$\n", str_bb,ai->ans_unit_str);
2799: }
2800: capa_mfree((char *)str_bb);
2801: }
2802: break;
2803: case ASCII_MODE:
2804: total_len = len_aa + len_bb + len_cc + len_dd + 8;
2805: /* 8 is by adding up characters ' [,] \n\n' plus one */
2806: sub_ans_str = (char *)capa_malloc(sizeof(char),total_len);
2807: if(num_answer==2) {
2808: if(len_dd == 0 ) { /* no unit_str */
2809: sprintf(sub_ans_str,"%s [%s,%s]\n\n", fmted_ans,lower,upper);
2810: } else {
2811: sprintf(sub_ans_str,"%s [%s,%s] %s\n\n",
2812: fmted_ans,lower,upper,ai->ans_unit_str);
2813: }
2814: } else {
2815: if(len_dd == 0 ) { /* no unit_str */
2816: sprintf(sub_ans_str,"%s\n\n", lower);
2817: } else {
2818: sprintf(sub_ans_str,"%s %s\n\n", lower,ai->ans_unit_str);
2819: }
2820: }
2821: break;
2822: case ANSWER_STRING_MODE:
2823: total_len = len_aa + len_bb + len_cc + len_dd + 8;
2824: /* 8 is by adding up characters ' [,] \n\n' plus one */
2825: sub_ans_str = (char *)capa_malloc(sizeof(char),total_len);
2826: if(num_answer==2) {
2827: if(len_dd == 0 ) { /* no unit_str */
2828: sprintf(sub_ans_str,", %s", fmted_ans);
2829: } else {
2830: sprintf(sub_ans_str,", %s %s", fmted_ans,ai->ans_unit_str);
2831: }
2832: } else {
2833: if(len_dd == 0 ) { /* no unit_str */
2834: sprintf(sub_ans_str,", %s", lower);
2835: } else {
2836: sprintf(sub_ans_str,", %s %s", lower,ai->ans_unit_str);
2837: }
2838: }
2839: break;
2840: case HTML_MODE:
2841: if(num_answer==2) {
2842: str_aa = format_toHTML(fmted_ans);
2843: total_len = strlen(str_aa) + len_dd + 8;
2844: str_bb = format_toHTML(lower);
2845: total_len += strlen(str_bb);
2846: str_cc = format_toHTML(upper);
2847: total_len += strlen(str_cc);
2848: /* 8 is by adding up characters ' [,] \n\n' plus one */
2849: sub_ans_str = (char *)capa_malloc(sizeof(char),total_len);
2850: if(len_dd == 0 ) { /* no unit_str */
2851: sprintf(sub_ans_str,"%s [%s,%s]\n\n", str_aa,str_bb,str_cc);
2852: } else {
2853: sprintf(sub_ans_str,"%s [%s,%s] %s\n\n",
2854: str_aa,str_bb,str_cc,ai->ans_unit_str);
2855: }
2856: capa_mfree((char *)str_aa); capa_mfree((char *)str_bb); capa_mfree((char
2857: *)str_cc);
2858: } else {
2859: if ( (ai->ans_type == ANSWER_IS_INTEGER) ||
2860: (ai->ans_type == ANSWER_IS_FLOAT )) {
2861: str_bb = format_toHTML(lower);
2862: } else { /* answer could be string, choice */
2863: str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1);
2864: if (ai->ans_type == ANSWER_IS_FORMULA || 1)
2865: sprintf(str_bb,"<PRE>\n%s\n</PRE>",lower);
2866: else
2867: strcpy(str_bb,lower);
2868: }
2869: total_len = strlen(str_bb) + len_dd + 4;
2870: /* 4 is by adding up characters ' \n\n' plus one */
2871: sub_ans_str = (char *)capa_malloc(sizeof(char),total_len);
2872: if(len_dd == 0 ) { /* no unit_str */
2873: sprintf(sub_ans_str,"%s\n\n", str_bb);
2874: } else {
2875: sprintf(sub_ans_str,"%s %s\n\n", str_bb,ai->ans_unit_str);
2876: }
2877: capa_mfree((char *)str_bb);
2878: }
2879: break;
2880: } /* end of switch */
2881: total_len = strlen(ans_str);
2882: total_len += (strlen(sub_ans_str) + 1);
2883: tmp_str = (char *)capa_malloc(sizeof(char),total_len);
2884: strncpy(tmp_str, ans_str, strlen(ans_str)+1);
2885: strcat(tmp_str, sub_ans_str);
2886: capa_mfree(ans_str); capa_mfree(sub_ans_str);
2887: capa_mfree(fmted_ans);
2888: ans_str = tmp_str;
2889: } /* end of for */
2890: } /* end of if */
2891:
2892: return (ans_str); /* the calling routing needs to deallocate it */
2893: }
2894:
2895:
2896:
2897: /* ------------------------------ called from capalogin */
2898: /* impose stronger checking on the user input string *answer */
2899: /* */
2900:
2901: /* <== This routine checks user input string *ans against correct answer *s ==> */
2902: int
1.10 albertel 2903: capa_check_ans(ai,ans, error) AnswerInfo_t *ai; char *ans; char **error;
1.1 albertel 2904: {
2905: int t; /* ans_type */
2906: char *s; /* ans_str */
2907: int c; /* ans_calc */
2908: int tt; /* ans_tol_type */
2909: double to; /* ans_tol */
2910: int su; /* ans_sig_ub */
2911: int sl; /* ans_sig_lb */
2912: char *fm; /* ans_fmt */
2913: char *us; /* ans_unit_str */
2914: Unit_t *u_p; /* ans_unit */
2915: int input_len, all_alphabet = 1, idx, ii, type;
2916: int outcome, result = INCORRECT;
2917: int sig, corr_len;
2918: int choice[ANSWER_STRING_LENG];
2919: char num_str[ANSWER_STRING_LENG], unit_str[ANSWER_STRING_LENG];
2920: char fmted[ANSWER_STRING_LENG], correct[ANSWER_STRING_LENG], answer[ANSWER_STRING_LENG];
2921: double n_part;
2922: double given, target, ratio, fmted_target, target_u, target_l, scale=1.0;
2923: double delta;
2924:
2925: t = ai->ans_type; s = ai->ans_str; c = ai->ans_calc;
2926: tt = ai->ans_tol_type; to = ai->ans_tol;
2927: su = ai->ans_sig_ub; sl = ai->ans_sig_lb;
2928: fm = ai->ans_fmt;
2929: us = ai->ans_unit_str; u_p = ai->ans_unit;
2930:
2931: switch(t) {
2932: case ANSWER_IS_INTEGER:
2933: case ANSWER_IS_FLOAT:
2934: {
2935: input_len = strlen(ans);
2936: all_alphabet = 1;
2937: for(idx=0;idx<input_len;idx++) {
2938: if( isdigit(ans[idx]) ) {
2939: all_alphabet = 0;
2940: }
2941: }
2942: if( !all_alphabet ) { /* answer string is not all alphabets */
2943: outcome = split_num_unit(ans,&n_part,num_str,unit_str);
2944: if( outcome > 1 ) { /* with both num and unit parts or only unit part */
2945: if( u_p != NULL ) {
1.10 albertel 2946: if (UNIT_FAIL == (result = check_correct_unit(unit_str,u_p,&scale))) {
2947: *error=strsave(unit_str);
2948: }
1.1 albertel 2949: } else { /* what to do when no unit is specified but student entered a unit? */
2950: result = UNIT_NOTNEEDED;
1.10 albertel 2951: *error=strsave(unit_str);
1.1 albertel 2952: }
2953: } else {
2954: if( u_p != NULL ) {
2955: result = NO_UNIT;
2956: }
2957: }
2958: if( (result != NO_UNIT) && (result != UNIT_FAIL) && ( result != UNIT_NOTNEEDED) ) {
2959: if( t == ANSWER_IS_FLOAT ) {
2960: target = (double)atof(s); /* real number */
2961: } else {
2962: target = (double)atol(s); /* Integer answer */
2963: }
2964: given = n_part * scale; /* convert the given answer into proper scale for units */
2965: sig = calc_sig( num_str );
1.10 albertel 2966: if( ((sig < sl ) || (sig > su )) && (sig!=0)) {
2967: result = SIG_FAIL;
2968: *error=capa_malloc(1,ANSWER_STRING_LENG);
2969: sprintf(*error,"%d",sig);
1.1 albertel 2970: } else {
2971: switch( tt ) { /* tolerence type */
2972: case TOL_ABSOLUTE:
2973: fmted_target = target; /* if answer type is integer */
2974: if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */
2975: sprintf(fmted, fm, target);
2976: fmted_target = (double)atof(fmted);
2977: }
2978: to = fabs(to); /* tol must be positive */
2979: if( c == CALC_FORMATED) {
2980: target_l = fmted_target - to; target_u = fmted_target + to;
2981: } else {
2982: target_l = target - to; target_u = target + to;
2983: }
2984: if( (given >= target_l) && (given <= target_u) ) {
2985: result = APPROX_ANS;
2986: } else { result = INCORRECT; }
2987: break;
2988: case TOL_PERCENTAGE:
2989: if( target != 0.0 ) {
2990: ratio = (double)(to / 100.0);
2991: fmted_target = target; /* if answer type is integer */
2992: if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */
2993: sprintf(fmted, fm, target);
2994: fmted_target = (double)atof(fmted);
2995: }
2996: delta = (double)fabs((double)ratio*target);
2997: if( c == CALC_FORMATED) {
2998: target_l = fmted_target - delta; target_u = fmted_target + delta;
2999: } else {
3000: target_l = target - delta; target_u = target + delta;
3001: }
3002: } else { target_l = target_u = target; }
3003: if ( (given >= target_l) && (given <= target_u) ) {
3004: result = APPROX_ANS;
3005: } else { result = INCORRECT; }
3006: break;
3007: }
3008: } /* end sig check */
3009: } /* end if unit check */
3010: } else { /* user entered alphabets, but no number */
1.10 albertel 3011: result = WANTED_NUMERIC;
1.1 albertel 3012: }
3013: }
3014: break;
3015: case ANSWER_IS_CHOICE:
3016: {
3017: corr_len = strlen(s); input_len = strlen(ans);
3018: if( corr_len == input_len ) {
3019: for(idx=0;idx<ANSWER_STRING_LENG;idx++) choice[idx] = 0;
3020: result = EXACT_ANS;
3021: for(ii=0;ii<corr_len; ii++) {
3022: idx = toupper(correct[ii]) - 'A'; choice[idx] = 1;
3023: }
3024: for(ii=0;ii<input_len;ii++) {
3025: idx = toupper(answer[ii]) - 'A';
3026: if(choice[idx] != 1 ) result = INCORRECT;
3027: }
3028: } else { result = INCORRECT; }
3029: break;
3030: }
3031: case ANSWER_IS_STRING_CI:
3032: if (strcasecmp(ans, s)) { result = INCORRECT; } else { result = EXACT_ANS; }
3033: break;
3034: case ANSWER_IS_STRING_CS:
3035: if (strcmp(ans, s)) { result = INCORRECT; } else { result = EXACT_ANS; }
3036: break;
3037: case ANSWER_IS_FORMULA:
3038: result = check_formula_ans(s,ans,ai->ans_id_list,ai->ans_pts_list,tt,to);
3039: break;
3040: case ANSWER_IS_EXTERNAL: /* Not yet implemented */
1.7 albertel 3041:
1.9 albertel 3042:
3043:
1.1 albertel 3044: break;
3045: }
3046: return (result);
3047: }
3048:
3049: /* =============================================================================== */
3050: /* calling sequence capa_check_answers() --> capa_check_answer() */
3051: /* --> capa_check_ans() */
3052:
3053:
3054: /* How we check the correct answer against user input string */
3055: /*
3056: If the correct answer is a number (either integer or real number)
3057: check if user input string consists of only alphabet characters
3058: use split_num_unit() heuristic function to split the input string into two parts
3059: numerical part and units part.
3060: if the outcome contains units, check if the units is correct or not
3061:
3062: */
3063:
3064:
3065: int
1.10 albertel 3066: capa_check_answer(p, answer, error) Problem_t *p; char *answer; char **error;
1.1 albertel 3067: {
3068: int type;
3069: char *correct;
3070: char input[ANSWER_STRING_LENG], unit_str[ANSWER_STRING_LENG];
3071: int tol_type, calc_type;
3072: double tol, n_part;
3073: int sig_l;
3074: int sig_u;
3075: char *fmt;
3076: int choice[ANSWER_STRING_LENG], ii, idx, corr_len, input_len;
3077: int result = INCORRECT, sig, outcome, all_alphabet;
3078: char fmted[FORMAT_STRING_LENG];
3079: double given, target, ratio, fmted_target, target_u, target_l, scale=1.0;
3080: double delta;
3081:
3082: type = p->ans_type;
3083: correct = p->answer;
3084: tol_type = p->tol_type;
3085: tol = p->tolerance;
3086: sig_l = p->sig_lbound;
3087: sig_u = p->sig_ubound;
3088: fmt = p->ans_fmt;
3089: calc_type = p->calc;
3090: unit_str[0]=0;
3091:
3092: switch(type) {
3093: case ANSWER_IS_INTEGER:
3094: case ANSWER_IS_FLOAT:
3095: {
3096: input_len = strlen(answer);
3097: all_alphabet = 1;
3098: for(idx=0;idx<input_len;idx++) {
3099: if( isdigit(answer[idx]) ) {
3100: all_alphabet = 0;
3101: }
3102: }
3103: if( !all_alphabet ) {
3104: outcome = split_num_unit(answer,&n_part,input,unit_str);
3105: if( outcome > 1 ) { /* with both num and unit parts or only unit part */
3106: if( p->ans_unit != NULL ) {
1.10 albertel 3107: if ( UNIT_FAIL == ( result = check_correct_unit(unit_str,p->ans_unit,&scale) ) ) {
3108: *error=strsave(unit_str);
3109: }
1.1 albertel 3110: } else { /* what to do when no unit is specified but student entered a unit? */
3111: result = UNIT_NOTNEEDED;
1.10 albertel 3112: *error=strsave(unit_str);
1.1 albertel 3113: }
3114: } else {
3115: if( p->ans_unit != NULL ) {
3116: result = NO_UNIT;
3117: }
3118: }
3119: if( (result != NO_UNIT) && (result != UNIT_FAIL) && ( result != UNIT_NOTNEEDED) ) {
3120: if( type == ANSWER_IS_FLOAT ) {
3121: target = (double)atof(correct); /* real number */
3122: } else {
3123: target = (double)atol(correct); /* Integer answer */
3124: }
3125: given = n_part * scale; /* convert the given answer into proper scale for units */
3126: sig = calc_sig( input );
1.5 albertel 3127: if( ((sig < sig_l) || (sig > sig_u)) && (sig!=0)) {
1.1 albertel 3128: result = SIG_FAIL;
1.10 albertel 3129: *error=capa_malloc(1,ANSWER_STRING_LENG);
3130: sprintf(*error,"%d",sig);
1.1 albertel 3131: } else {
3132: switch( tol_type ) {
3133: case TOL_ABSOLUTE:
3134: fmted_target = target; /* if answer type is integer */
3135: if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */
3136: sprintf(fmted, fmt, target);
3137: fmted_target = (double)atof(fmted);
3138: }
3139: tol = fabs(tol); /* tol must be positive */
3140: if( calc_type == CALC_FORMATED) {
3141: target_l = fmted_target - tol; target_u = fmted_target + tol;
3142: } else {
3143: target_l = target - tol; target_u = target + tol;
3144: }
3145: if( (given >= target_l) && (given <= target_u) ) {
3146: result = APPROX_ANS;
3147: } else { result = INCORRECT; }
3148: break;
3149: case TOL_PERCENTAGE:
3150: if( target != 0.0 ) {
3151: ratio = (double)(tol / 100.0);
3152: fmted_target = target; /* if answer type is integer */
3153: if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */
3154: sprintf(fmted, fmt, target);
3155: fmted_target = (double)atof(fmted);
3156: }
3157: delta = (double)fabs((double)ratio*target);
3158: if( calc_type == CALC_FORMATED) {
3159: target_l = fmted_target - delta; target_u = fmted_target + delta;
3160: } else {
3161: target_l = target - delta; target_u = target + delta;
3162: }
3163: } else { target_l = target_u = target; }
3164: if ( (given >= target_l) && (given <= target_u) ) {
3165: result = APPROX_ANS;
3166: } else { result = INCORRECT; }
3167: break;
3168: }
3169: } /* end sig check */
3170: } /* end if unit check */
3171: } else { /* user entered alphabet, but no number */
1.10 albertel 3172: result = WANTED_NUMERIC;
1.1 albertel 3173: }
3174: }
3175: break;
3176: case ANSWER_IS_CHOICE:
3177: {
3178: corr_len = strlen(correct); input_len = strlen(answer);
3179: if( corr_len == input_len ) {
3180: for(ii=0;ii<ANSWER_STRING_LENG;ii++) choice[ii] = 0; result = EXACT_ANS;
3181: for(ii=0;ii<corr_len; ii++) {
3182: idx = toupper(correct[ii]) - 'A'; choice[idx] = 1;
3183: }
3184: for(ii=0;ii<input_len;ii++) {
3185: idx = toupper(answer[ii]) - 'A';
3186: if(choice[idx] != 1 ) result = INCORRECT;
3187: }
3188: } else { result = INCORRECT; }
3189: break;
3190: }
3191: case ANSWER_IS_STRING_CI:
3192: if (strcasecmp(answer, correct)) { result = INCORRECT; } else { result = EXACT_ANS; }
3193: break;
3194: case ANSWER_IS_STRING_CS:
3195: if (strcmp(answer, correct)) { result = INCORRECT; } else { result = EXACT_ANS; }
3196: break;
3197: case ANSWER_IS_FORMULA:
3198: result = check_formula_ans(correct,answer,p->id_list,p->pts_list,tol_type,tol);
3199: break;
3200: case ANSWER_IS_EXTERNAL: /* not yet implemented */
1.5 albertel 3201: /* we assume the external program is called through popen() */
3202: /* and the result will be given back as 0 or 1 to indicate the */
3203: /* given answer is correct or not */
1.7 albertel 3204: /* arguments are given to the program as */
1.16 ! albertel 3205: /* before running the program, check its existance first */
! 3206: /* should we specify a time out period in capa.config file? */
! 3207: /* set up a timer for this purpose */
! 3208: /* FILE *popen (const char *command,const char *type ); */
1.7 albertel 3209:
1.1 albertel 3210: break;
3211:
3212: }
3213: return (result);
3214: }
3215:
1.16 ! albertel 3216: /* -------------------------------------------------------------------------- */
1.1 albertel 3217: /* assumming the formula is *fml_str and the student input is *input_str */
3218: /* according to the type of tolerance, we form the final formula as */
3219: /* absolute tolerance: (*fml_str) - (*input_str) */
3220: /* relative tolerance: (*input_str) / (*fml_str) */
3221: int
3222: check_formula_ans(fml_str,input_str,var_list,pts_list,tol_type,tol)
3223: char *fml_str;char *input_str;char *var_list;PointsList_t *pts_list;int tol_type; double tol;
3224: {
3225: char *check_fml_str;
3226: int f_len, i_len, outcome, error_code;
3227: PointsList_t *pt, *next;
3228: double formula_val, diff;
3229:
3230: f_len = strlen(fml_str);
3231: i_len = strlen(input_str);
3232:
3233: check_fml_str = (char *)capa_malloc((f_len + i_len + 16), sizeof(char));
3234: if( tol_type == TOL_ABSOLUTE ) {
3235: sprintf(check_fml_str,"abs((%s) - (%s))",fml_str, input_str);
3236: } else {
3237: sprintf(check_fml_str,"(%s) / (%s)",input_str,fml_str);
3238: }
3239: outcome = APPROX_ANS;
3240: for(pt= pts_list; pt!=NULL ; pt=next) {
3241: next=pt->pts_next;
3242: error_code = f_eval_formula(&formula_val,check_fml_str, var_list, pt->pts_str);
3243: if( ! error_code ) {
3244: if( tol_type == TOL_ABSOLUTE ) {
3245: diff = tol - formula_val;
3246: if( diff < 0.0 ) {
3247: outcome = INCORRECT;
3248: }
3249: } else {
3250: diff = abs(1.0 - formula_val) * 100.0 ;
3251: if( diff < tol ) {
3252: outcome = INCORRECT;
3253: }
3254: }
3255: } else {
3256: outcome = BAD_FORMULA;
3257: break;
3258: }
3259: }
3260: capa_mfree((char *)check_fml_str);
3261:
3262: return (outcome);
3263:
3264: }
3265: /* inputs: type :: answer type, calc_type :: input string format string tolerance type */
3266: /* returns: lower upper */
3267:
3268: int
3269: calc_ansrange(type, calc_type, input, fmt, tol_type, tol, lower, upper)
3270: int type;int calc_type;char *input;char *fmt;
3271: int tol_type;double tol;char *lower;char *upper;
3272: {
3273: int result = 2, leng;
3274: char fmted[ANSWER_STRING_LENG];
3275: double target, fmted_target, ratio, target_l, target_u, tmp, delta;
3276:
3277:
3278: if( (type == ANSWER_IS_FORMULA) ||
3279: (type == ANSWER_IS_EXTERNAL ) ) {
3280: strcpy(lower, input);
3281: result = 1;
3282: return (result);
3283: } else {
3284: if( tol == 0.0 ) { /* answer could be ANSWER_IS_FLOAT ANSWER_IS_INTEGER,
3285: ANSWER_IS_STRING_CI ANSWER_IS_STRING_CS
3286: ANSWER_IS_CHOICE
3287: */
3288: result = 1; /* only one answer */
3289: if( type == ANSWER_IS_FLOAT ) {
3290: target = (double)atof(input);
3291: sprintf(fmted, fmt, target);
3292: leng = strlen(fmted)+1;
3293:
3294: strcpy(lower, fmted);
3295: } else { /* could be integer, choice, string ci, string cs */
3296: strcpy(lower, input);
3297: }
3298: } else { /* we have tolerence */
3299:
3300: target = (double)atof(input);
3301: switch( tol_type ) {
3302: case TOL_ABSOLUTE:
3303: fmted_target = target; /* if answer type is integer */
3304: if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */
3305: sprintf(fmted, fmt, target);
3306: fmted_target = (double)atof(fmted);
3307: }
3308: tol = fabs(tol); /* tol must be positive */
3309: if( calc_type == CALC_FORMATED) {
3310: target_l = fmted_target - tol; target_u = fmted_target + tol;
3311: } else {
3312: target_l = target - tol; target_u = target + tol;
3313: }
3314: if(type == ANSWER_IS_FLOAT) {
3315: sprintf(fmted, fmt, target_l ); strcpy(lower, fmted);
3316: sprintf(fmted, fmt, target_u ); strcpy(upper, fmted);
3317: } else {
3318: sprintf(fmted, "%.15g", target_l ); strcpy(lower, fmted);
3319: sprintf(fmted, "%.15g", target_u ); strcpy(upper, fmted);
3320: }
3321: break;
3322: case TOL_PERCENTAGE:
3323: if( target != 0.0 ) {
3324: ratio = (double)(tol / 100.0);
3325: fmted_target = target; /* if answer type is integer */
3326: if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */
3327: sprintf(fmted, fmt, target);
3328: fmted_target = (double)atof(fmted);
3329: }
3330: delta = (double)fabs((double)ratio*target);
3331: if( calc_type == CALC_FORMATED) {
3332: target_l = fmted_target - delta; target_u = fmted_target + delta;
3333: } else {
3334: target_l = target - delta; target_u = target + delta;
3335: }
3336: if( target_l > target_u ) { tmp = target_u; target_u = target_l; target_l = tmp; }
3337: if(type == ANSWER_IS_FLOAT) {
3338: sprintf(fmted, fmt, target_l ); strcpy(lower, fmted);
3339: sprintf(fmted, fmt, target_u ); strcpy(upper, fmted);
3340: } else {
3341: sprintf(fmted, "%.15g", target_l ); strcpy(lower, fmted);
3342: sprintf(fmted, "%.15g", target_u ); strcpy(upper, fmted);
3343: }
3344: } else { strcpy(lower, "0.0"); strcpy(upper, "0.0"); result = 1;}
3345: break;
3346: }
3347: }
3348: }
3349:
3350: return (result);
3351: }
3352:
3353: /* Algorithms : check ALL units first */
3354: /* sig figs second */
3355: /* numerical, string comparisons last */
3356: /* result from capa_check_ans() could be */
3357:
3358: /* New check answers routine checks the /AND and /OR group of answers */
3359: /* use array of char pointers char **a */
3360: int
1.10 albertel 3361: capa_check_answers(p,answers,cnt,error)
3362: Problem_t *p; char **answers; int cnt; char **error;
1.1 albertel 3363: {
3364: AnswerInfo_t *ai;
3365: int ii, done, result;
3366: int *outcomes;
1.10 albertel 3367: char **errormsg;
1.1 albertel 3368:
1.10 albertel 3369: errormsg=(char**)capa_malloc(cnt,sizeof(char*));
1.1 albertel 3370: if(p->ans_op == ANS_AND) { /* ans /and ans */
3371: if( (cnt != p->ans_cnt) ) { return (ANS_CNT_NOT_MATCH); }
1.10 albertel 3372: if( cnt == 1 ) { return (capa_check_answer(p, answers[0], error)); } /* there is only one answer */
1.1 albertel 3373: outcomes = (int *)capa_malloc(sizeof(int),cnt);
3374: for(ii=0;ii<cnt;ii++) outcomes[ii]=0; /* initialize the outcomes array */
1.10 albertel 3375: outcomes[0] = capa_check_answer(p, answers[0], &errormsg[0]);
1.16 ! albertel 3376: #ifdef COMMON_DBUG
! 3377: fprintf(dfp,"CAPA_CHECK_ANSWER(%s,%s):: outcome[0]=%d\n",
! 3378: p->answer,answers[0],outcomes[0]); fflush(dfp);
! 3379: #endif
1.1 albertel 3380: for(ii=1, ai = p->ans_list; ai; ii++,ai = ai->ans_next ) {
1.10 albertel 3381: outcomes[ii] = capa_check_ans(ai,answers[ii],&(errormsg[ii]));
1.16 ! albertel 3382: #ifdef COMMON_DBUG
! 3383: fprintf(dfp,"CAPA_CHECK_ANS(%s,%s): outcome[%d]=%d\n", ai->ans_str,answers[ii],ii,outcomes[ii]); fflush(dfp);
! 3384: #endif
1.1 albertel 3385: }
3386: done = ii = 0;
3387: result = 0;
3388: while( !done ) { /* check if any of the outcome has failed on units */
3389: if( (outcomes[ii] == UNIT_FAIL) ||
3390: (outcomes[ii] == NO_UNIT) ||
3391: (outcomes[ii] == UNIT_NOTNEEDED) ) {
3392: result = outcomes[ii];
1.10 albertel 3393: if (result != NO_UNIT) { *error=strsave(errormsg[ii]); }
1.1 albertel 3394: done = 1;
3395: }
3396: ii++;
3397: if(ii==cnt) done = 1;
3398: }
1.15 albertel 3399: if( result == 0 ) {
3400: /* check if any of the outcome has failed to be a numeric
3401: or was a malformed equation */
1.10 albertel 3402: done = ii = 0;
3403: while( !done ) {
1.15 albertel 3404: if( outcomes[ii] == WANTED_NUMERIC || outcomes[ii] == BAD_FORMULA ) {
1.10 albertel 3405: result = outcomes[ii];
3406: done = 1;
3407: }
3408: ii++;
3409: if(ii==cnt) done = 1;
3410: }
3411: }
1.15 albertel 3412: if( result == 0 ) {/*check if any of the outcome has failed on sig figs*/
1.1 albertel 3413: done = ii = 0;
3414: while( !done ) {
3415: if( outcomes[ii] == SIG_FAIL ) {
3416: result = outcomes[ii];
1.10 albertel 3417: *error = strsave(errormsg[ii]);
1.1 albertel 3418: done = 1;
3419: }
3420: ii++;
3421: if(ii==cnt) done = 1;
3422: }
3423: }
3424: if( result == 0 ) { /* check if any of the outcome is incorrect */
3425: done = ii = 0;
3426: while( !done ) {
3427: if( outcomes[ii] == INCORRECT ) {
3428: result = outcomes[ii];
3429: done = 1;
3430: }
3431: ii++;
3432: if(ii==cnt) done = 1;
3433: }
3434: }
1.10 albertel 3435: for (ii=0;ii<cnt;ii++) {
3436: if( (outcomes[ii] == UNIT_FAIL) ||
3437: (outcomes[ii] == SIG_FAIL) ||
3438: (outcomes[ii] == UNIT_NOTNEEDED) ) {
3439: capa_mfree(errormsg[ii]);
3440: }
3441: }
3442: capa_mfree((char *)errormsg);
1.1 albertel 3443: capa_mfree((char *)outcomes);
3444: if( result == 0 ) {
3445: result = APPROX_ANS; /* all answers are correct */
3446: }
1.10 albertel 3447:
1.1 albertel 3448: } else { /* should be ANS_OR , user answer count should always be 1 */
3449: if( cnt != 1 ) { return (ANS_CNT_NOT_MATCH); }
1.10 albertel 3450: if( p->ans_cnt == 1 ) { return (capa_check_answer(p, answers[0], error)); }
3451: result = capa_check_answer(p, answers[0], error);
1.1 albertel 3452: ii = 1; ai = p->ans_list;
3453: while( (ii<p->ans_cnt) && ( (result != EXACT_ANS) && (result != APPROX_ANS) ) ) {
1.10 albertel 3454: if((ii!=1)&&((result==UNIT_FAIL)||(result==SIG_FAIL)||(result==UNIT_NOTNEEDED))) {
3455: capa_mfree((char*)error);
3456: }
3457: result = capa_check_ans(ai,answers[0],error);
3458: ai = ai->ans_next; ii++;
1.1 albertel 3459: }
3460: }
3461: return (result);
3462: }
3463:
3464:
3465:
3466:
3467:
3468:
3469:
3470:
3471: /* ========================================================================= */
3472: int w_getclassdir(cpath_p, cown_p, class)
3473: char **cpath_p; char **cown_p; char *class;
3474: {
3475: FILE *fp;
3476: char filename[SMALL_LINE_BUFFER];
3477: char *cname_p;
3478: int done;
3479: char c;
3480:
3481: sprintf(filename,"class.conf");
3482: if ((fp=fopen(filename,"r"))==NULL) {
3483: sprintf(filename,"../class.conf");
3484: if ((fp=fopen(filename,"r"))==NULL) {
3485: printf("Error: can't open %s\n",filename);
3486: exit (1);
3487: }
3488: }
3489: do {
3490: c_ignorewhite(fp);
3491: c = getc(fp); ungetc(c,fp);
3492: if( c != EOF ) {
3493: cname_p = c_getword(fp);
3494: *cpath_p = c_getword(fp);
3495: *cown_p = c_getword(fp);
3496: throwaway_line(fp);
3497: if( ! strcasecmp(cname_p, class) ) {
3498: done = 1;
3499: } else {
3500: free(cname_p); free(*cpath_p); free(*cown_p);
3501: done = 0;
3502: }
3503: } else {
3504: done = 1;
3505: }
3506: } while ( ! done );
3507: fclose(fp);
3508: free(cname_p);
3509: return (1);
3510: }
3511:
3512: /* ----------------------------------------------------------------- */
3513: /* read_capa_config gets a value out of the capa.config file
3514: in the read resultant string all " are removed expect for \" occurances"
3515: in fact all case of \ then another character become just the last
3516: character
3517:
3518: inputs : key_word - a string that is searched for on the lefthand side
3519: of an equals sign
3520: outputs : value - a char pointer that the value of the key_word as defined
3521: in the config file is copied into
3522: return : -1 - unable to find or acces the capa.config file
3523: 0 - the requested keyword was not found
3524: >0 - length of the string that was returned in value
3525: */
3526: /* ----------------------------------------------------------------- */
3527: int read_capa_config(key_word,value)
3528: char *key_word;char *value;
3529: {
3530: FILE *fp;
3531: char filename[SMALL_LINE_BUFFER];
3532: char left[MAX_BUFFER_SIZE],right[MAX_BUFFER_SIZE],c;
3533: int failed=0,done=0,num=0,result=-1,found=0,returnVal=0,i,j;
3534:
3535: sprintf(filename,"capa.config");
3536: if ((fp=fopen(filename,"r"))==NULL) {
3537: return (-1);
3538: }
3539: do {
3540: num = fscanf(fp,"%[^ \n\t#] = %[^\n]",left,right);
3541: if (num == 2) { result = strcasecmp(left,key_word); }
3542: if (result==0) { done=1; }
3543: if (num==EOF) { failed=1; }
3544: if (num!=2) {
3545: found=0;
3546: while(1) {
3547: c=fgetc(fp);
3548: if (found) {
3549: if (c!='\n') {
3550: ungetc(c,fp);
3551: break;
3552: }
3553: }
3554: if (c=='\n') found=1;
3555: if (((char)c)==((char)EOF)) break;
3556: }
3557: }
3558: } while (!done && !failed);
3559:
3560: fclose(fp);
3561:
3562: if (done) {
1.4 albertel 3563: trim_response_ws(right); /*get rid of leading and trailing spaces*/
1.1 albertel 3564: for(i=0,j=0;i<(strlen(right)+1);i++) {
3565: value[j]='\0';
3566: if (right[i] == '\\' && (i < (strlen(right))) ) {
3567: i++;value[j]=right[i];j++;
3568: } else if (right[i] != '\"' ) {
3569: value[j]=right[i];j++;
3570: }
3571: }
3572: value[j]='\0';
3573: returnVal=j;
3574: }
3575: return returnVal;
3576: }
3577:
3578: int capa_access(const char *pathname, int mode)
3579: {
3580: pid_t euid,egid;
3581: struct stat status;
3582:
3583: euid=geteuid();
3584: egid=getegid();
3585: if ( -1 == stat(pathname,&status) ) { return -1; }
3586: /*printf("mode:%x F_OK:%x mode&F_OK:%x\n",mode,F_OK,(mode&F_OK));*/
3587: /*printf("st_mode:%x S_IFMT:%x st_mode&S_IFMT:%x\n",
3588: status.st_mode,S_IFMT,(status.st_mode&S_IFMT));*/
3589: if (!(status.st_mode & S_IFMT)) { return -1; }
3590: /*printf("euid: %d\t egid: %d\tstatus.st_uid: %d\tstatus.st_gid: %d\n",
3591: euid,egid,status.st_uid,status.st_gid);*/
3592: /*printf("mode:%x R_OK:%x mode&R_OK:%x\n",mode,R_OK,(mode&R_OK));*/
3593: /*printf("mode:%x W_OK:%x mode&W_OK:%x\n",mode,R_OK,(mode&R_OK));*/
3594: /*printf("mode:%x X_OK:%x mode&X_OK:%x\n",mode,R_OK,(mode&R_OK));*/
3595: if (euid==status.st_uid) {
3596: /*printf("here1\n");*/
3597: if ((mode & R_OK) && (!(status.st_mode & S_IRUSR))) { return -1; }
3598: if ((mode & W_OK) && (!(status.st_mode & S_IWUSR))) { return -1; }
3599: if ((mode & X_OK) && (!(status.st_mode & S_IXUSR))) { return -1; }
3600: } else {
3601: if (egid==status.st_gid) {
3602: /*printf("here2\n");*/
3603: if ((mode & R_OK) && (!(status.st_mode & S_IRGRP))) { return -1; }
3604: if ((mode & W_OK) && (!(status.st_mode & S_IWGRP))) { return -1; }
3605: if ((mode & X_OK) && (!(status.st_mode & S_IXGRP))) { return -1; }
3606: } else {
3607: /*printf("here3\n");*/
3608: if ((mode & R_OK) && (!(status.st_mode & S_IROTH))) { return -1; }
3609: if ((mode & W_OK) && (!(status.st_mode & S_IWOTH))) { return -1; }
3610: if ((mode & X_OK) && (!(status.st_mode & S_IXOTH))) { return -1; }
3611: }
3612: }
3613: return 0;
3614: }
3615:
3616: /*checks if the string is all whitespace*/
3617: /*returns 0 if it isn't */
3618: /*returns 1 if it is */
3619: int is_all_ws(char* answer)
3620: {
3621: int length,result=1,i;
3622: if (answer!=NULL) {
3623: length=strlen(answer);
3624: for(i=0;i<length;i++) {
3625: if (!isspace(answer[i])) {result=0;break;}
3626: }
3627: }
3628: return result;
3629: }
3630:
3631: void trim_response_ws(char* answer)
3632: {
3633: char *temp;
3634: int i,j=0,length;
3635: length=strlen(answer);
3636: temp=capa_malloc(length+1,1);
3637: strcpy(temp,answer);
3638: for(i=0; i<length;i++) if (!(isspace(temp[i]))) break;
3639: for(j=length-1;j>=0;j--) if (!(isspace(temp[j]))) break;
3640: temp[++j]='\0';
3641: strcpy(answer,&temp[i]);
3642: }
3643:
3644: void throwaway_line(FILE* fp)
3645: {
3646: int c;
3647: do {
3648: c = getc(fp);
3649: } while ( (c != '\n') && (c != EOF) );
3650: }
3651:
3652: char* capa_get_seat(char* studentnum,char* seatfile)
3653: {
3654: FILE* fp;
3655: T_student student;
3656: char *result,*defaultseatfile="seatingchart";
3657: char line[TMP_LINE_LENGTH],*lineend;
3658: int stuline=0,seatline=0;
3659:
3660: stuline = capa_get_student(studentnum,&student);
3661: if (stuline < 1 ) goto error;
3662: if (seatfile == NULL) seatfile=defaultseatfile;
3663: if ((fp=fopen(seatfile,"r"))==NULL) goto error;
3664: while( (stuline>seatline) && (fgets(line,TMP_LINE_LENGTH-1,fp)) ) seatline++;
3665: if (seatline< stuline) goto error;
3666: if ((lineend=index(line,' '))!=NULL) lineend='\0';
3667: result=capa_malloc(strlen(line)+1,1);
3668: strcpy(result,line);
3669: return result;
3670:
3671: error:
3672: result= capa_malloc(8,1);
3673: sprintf(result,"No Seat");
3674: return result;
3675:
3676: }
3677:
3678: void protect_log_string(char* log_string)
3679: {
3680: int i,len=strlen(log_string);
3681: for(i=0;i<len;i++) {
3682: switch (log_string[i]) {
3683: case '\n': case '\t': case '\r':
3684: log_string[i]=' ';
3685: break;
3686: }
3687: }
3688: }
3689:
3690: int capa_get_login_time(char *student_number,int set,time_t *logintime)
3691: {
3692: FILE *fp;
3693: int found,temp=0;
3694: char filename[FILE_NAME_LENGTH],line[SMALL_LINE_BUFFER];
3695:
3696: *logintime=0;
3697: sprintf(filename,"records/access%d.log",set);
3698:
3699: if ((fp=fopen(filename,"r"))==NULL) return (-1);
3700: found = 0;
3701: while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) {
3702: if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1;
3703: }
3704: fclose(fp);
3705: if (found) sscanf(rindex(line,':'),":%d",&temp);
3706: *logintime=(time_t)temp;
3707: return found;
3708: }
3709:
3710: /*----------------------------------------------------------*/
3711: /* INPUT: set the X in logX.db */
3712: /* OUTPUT: creates the accessX.log file if it doesn't exist */
3713: /* and inserts stunum:time(NULL) if stunum isn't */
3714: /* in ther already. */
3715: /* */
3716: /* RETURN: -1 file error */
3717: /* 0 already set */
3718: /* 1 succesfully logged a login time */
3719: /*----------------------------------------------------------*/
3720: int capa_set_login_time(char *student_number,int set)
3721: {
3722: FILE *fp;
3723: int errcode=0;
3724: int found=0;
3725: char filename[FILE_NAME_LENGTH],line[SMALL_LINE_BUFFER];
3726:
3727: sprintf(filename,"records/access%d.log",set);
3728:
3729: if ((fp=fopen(filename,"r"))!=NULL) {
3730: while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) {
3731: if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1;
3732: }
3733: fclose(fp);
3734: }
3735:
3736: if (found) return 0;
3737:
3738: sprintf(line,"%s:%d\n", student_number,(int)time(NULL));
3739: if ((fp=fopen(filename,"a+"))==NULL) return (-1);
3740: flockstream(fp);
3741: fseek(fp,0L,SEEK_END);
3742: if ( !fwrite((char *)line, strlen(line), 1, fp) ) {
3743: errcode = -1;
3744: } else {
3745: errcode = 1;
3746: }
3747: fflush(fp);
3748: funlockstream(fp);
3749: fclose(fp);
3750: return (errcode);
3751: }
3752: /* =||>|===================== End of capaCommon.c =====================|<||= */
3753:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>