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