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