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