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