/* Library of useful functions Copyright (C) 1992-2000 Michigan State University The CAPA system is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The CAPA system is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the CAPA system; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, you have permission to link this program with the TtH/TtM library and distribute executables, as long as you follow the requirements of the GNU GPL in regard to all of the software in the executable aside from TtH/TtM. */ /* =||>|===================== capaCommon.c =====================|<||= */ /* created 1994 by Isaac Tsai */ /* TODO: restructure capa_check_ans*() calls into one */ /* =||>|===================== capaCommon.c =====================|<||= */ #include #if defined(__sun) || defined(linux) || defined(__alpha) || defined(hpux) || defined(AIX) || defined(IRIX) #include /* lockf() */ #endif #include #include #include #include "capaParser.h" #include "capaToken.h" #include "capaCommon.h" #include "ranlib.h" /*----------------------------------------------------------*/ /* flock() in SUN is in BSD compatibility lib */ /* #include */ /*----------------------------------------------------------*/ int yyparse(); extern FILE *yyin; extern void yyrestart(); extern FILE *dfp; /*----------------------------------------------------------*/ /* RETURN: -1 file error */ /* 0 success */ /* INPUT: if section == 0, for all students in class */ /* set : 1, 2, 3, ... */ /* prob: 1, 2, 3, ... */ /*----------------------------------------------------------*/ int capa_excuse(int set,int prob,int section) { int nq; T_header header; T_entry entry; T_student *student_p, *s1_p; char tmp_number[MAX_STUDENT_NUMBER+1]; long offset; int num_students; /* Calculate parameters */ if (capa_get_header(&header,set)) return (-1); sscanf(header.num_questions,"%d", &nq); if( ( prob > nq ) || (section < 0 ) || (section > MAX_SECTION_COUNT) ) return (-1); num_students= 0; if ( (num_students = capa_get_section(&student_p, section))== -1 ) return (-1); for ( s1_p = student_p ; s1_p ; s1_p = (s1_p->s_next)) { sprintf(tmp_number,"%s",s1_p->s_sn); offset = capa_get_entry(&entry,tmp_number,set); if(offset < 0 ) offset = -offset; switch(entry.answers[prob-1]) { case '0': case '-': entry.answers[prob-1] = 'E'; break; case 'N': entry.answers[prob-1] = 'E'; break; case 'n': entry.answers[prob-1] = 'e'; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (entry.answers[prob-1] < header.weight[prob-1]) { entry.answers[prob-1] = 'E'; } break; default : break; } capa_set_entry(&entry,tmp_number,set,offset); capa_mfree(entry.answers); entry.answers = NULL; capa_mfree(entry.tries); entry.tries = NULL; } capa_mfree(header.weight); capa_mfree(header.partial_credit); free_students(student_p); return (0); } /*----------------------------------------------------------*/ /* Lock file shared */ /* lock the file specified by file stream pointer sp */ /*----------------------------------------------------------*/ int flockstream_sh(sp) FILE *sp; { int fd; fd = fileno(sp); #if defined(__sun) || defined(hpux) || defined(AIX) return ( lockf(fd,F_LOCK, 0L) ); #else return (flock(fd,LOCK_SH)); #endif } /*----------------------------------------------------------*/ int flockstream(sp) FILE *sp; { int fd; fd = fileno(sp); #if defined(__sun) || defined(hpux) || defined(AIX) return ( lockf(fd,F_LOCK, 0L) ); #else return (flock(fd,LOCK_EX)); #endif } /*----------------------------------------------------------*/ int funlockstream(sp) FILE *sp; { int fd; fd = fileno(sp); #if defined(__sun) || defined(hpux) || defined(AIX) return ( lockf(fd,F_ULOCK, 0L) ); #else return ( flock(fd,LOCK_UN) ); #endif } int inquery_a_lock(sp,cmd,type,offset,whence,len) FILE *sp;int cmd;off_t offset;int whence;off_t len; { struct flock lock; int fd; lock.l_type = type; lock.l_start = offset; lock.l_whence = whence; lock.l_len = len; fd=fileno(sp); return (fcntl(fd,cmd,&lock)); } #define Blocked_Write_Lock(sp) \ inquery_a_lock(sp,F_SETLK,F_WRLCK,0,0,0) #define Blocked_Write_Lock(sp) \ inquery_a_lock(sp,F_SETLK,F_WRLCK,0,0,0) #define Un_Lock(sp) \ inquery_a_lock(sp,F_SETLK,F_UNLCK,0,0,0) /*----------------------------------------------------------*/ /* INPUT: set problem set number */ /* RETURN: -1 no records/setX.db file or file error */ /* 0 success */ /* OUTPUT: header pointer to T_header structure */ /*----------------------------------------------------------*/ int capa_set_header(header, set) T_header *header;int set; { FILE *fp; char *big_buf=NULL, filename[FILE_NAME_LENGTH], cr=0, oneline[TMP_LINE_LENGTH]; int nq, len, errcode, fd, item_cnt, exists=1; T_header oldheader; long orig_size, new_size, big_buf_size; sprintf(filename,"records/set%d.db",set); if ((fp=fopen(filename,"r+"))==NULL) { exists=0; if ((fp=fopen(filename,"w"))==NULL) { /* create if non-existant */ /*printf("Error: can't open %s\n",filename);*/ return (-1); } } sscanf(header->num_questions,"%d",&nq); /* sprintf(oneline,"%d,%s,%s,%s\n",nq,header->open_date,header->due_date,header->answer_date); */ sprintf(oneline,"%d\n",nq); len = strlen(oneline); flockstream(fp); errcode = 0; if (exists) { /*get file size*/ fseek(fp,0L,SEEK_END); orig_size = ftell(fp); big_buf_size = orig_size; /*the amt we need to read is less then the file's size*/ big_buf = capa_malloc(big_buf_size,1); fseek(fp,0L,SEEK_SET); /*read in old header*/ fscanf(fp,"%d",&nq); while ( cr != '\n' && cr != EOF ) { cr=fgetc(fp); } oldheader.weight=capa_malloc(nq+1,1); oldheader.partial_credit=capa_malloc(nq+1,1); if (!fread(oldheader.weight, sizeof(char), nq, fp)) errcode = -2; if (EOF==(cr=fgetc(fp))) errcode = -3; if (!fread(oldheader.partial_credit, sizeof(char), nq, fp)) errcode = -4; if (EOF==(cr=fgetc(fp))) errcode = -5; capa_mfree(oldheader.weight); capa_mfree(oldheader.partial_credit); /*read rest of file*/ item_cnt=fread(big_buf,1,big_buf_size, fp); } /*write new header*/ fseek(fp,0L,SEEK_SET); if (!fwrite(oneline, len, 1, fp)) {errcode = -6;} if ( header->weight != NULL ) { if (!fwrite((char *)(header->weight), strlen(header->weight), 1, fp)) errcode=-7; } if (EOF==(!fputc('\n', fp))) errcode = -8; if (header->partial_credit != NULL) { if (!fwrite((char *)(header->partial_credit), strlen(header->partial_credit), 1, fp)) { errcode = -9; } } if (EOF==(!fputc('\n', fp))) errcode = -10; if (exists) { /*write out rest of file*/ if (item_cnt >= 0 ) { big_buf[item_cnt]=0; if (!fwrite(big_buf,item_cnt,1,fp) ) errcode= -11; new_size = ftell(fp); if (new_size < orig_size ) { fd = fileno(fp); ftruncate(fd,new_size); } } } fflush(fp); funlockstream(fp); fclose(fp); if (big_buf!=NULL) capa_mfree(big_buf); return (errcode); } /*----------------------------------------------------------*/ /* INPUT: set problem set number */ /* RETURN: -1 file error */ /* 0 success */ /* OUTPUT: header pointer to T_header structure */ /* Note: allocates space for the partial_credit and weight */ /* fields of the passed in header, caller needs to */ /* eventually free them with capa_mfree */ /*----------------------------------------------------------*/ int capa_get_header(header, set) T_header *header;int set; { FILE *fp; char filename[FILE_NAME_LENGTH]; char cr; int nq=0, errcode; sprintf(filename,"records/set%d.db",set); if ((fp=fopen(filename,"r"))==NULL) { /*printf("Error capa_get_header(): can't open %s\n",filename);*/ return (-1); } flockstream(fp); errcode = 0; fscanf(fp,"%d",&nq); cr='\0'; while ( cr != '\n' && cr != EOF ) { cr=fgetc(fp); } header->weight=capa_malloc(nq+1,1); header->partial_credit=capa_malloc(nq+1,1); if (nq > 0 ) { if (!fread(header->weight, sizeof(char), nq, fp)) errcode = -1; } if (EOF==(cr=fgetc(fp))) errcode = -1; if (nq > 0 ) { if (!fread(header->partial_credit, sizeof(char), nq, fp)) errcode = -1; } funlockstream(fp); fclose(fp); header->weight[nq]='\0'; header->partial_credit[nq]='\0'; sprintf(header->num_questions,"%d",nq); return (errcode); } /*----------------------------------------------------------*/ /* ----------- previous version, obsolete as of May 1997 int capa_set_entry(entry, student_number, set, offset) T_entry *entry; char *student_number; int set; long offset; { FILE *fp; int errcode=0; int len; char filename[FILE_NAME_LENGTH]; char a_line[TMP_LINE_LENGTH]; sprintf(filename,"records/set%d.db",set); if ((fp=fopen(filename,"r+"))==NULL) { return (-1); } sprintf(a_line,"%s %s,%s\n",entry->student_number,entry->answers,entry->tries); len = strlen(a_line); flockstream(fp); fseek(fp,offset,0); if (!fwrite(a_line,len,1,fp) ) { printf("Error writing data to file\n"); errcode= (-1); } fflush(fp); funlockstream(fp); fclose(fp); return (errcode); } ---------- */ int capa_set_entry(entry, student_number, set, offset) T_entry *entry; char *student_number; int set; long offset; { FILE *fp; int fd; int errcode=0; int done, len, new_len, item_cnt; long next_r, orig_size, new_size, big_buf_size; char filename[FILE_NAME_LENGTH]; char *a_line, tmpline[TMP_LINE_LENGTH], tmp_sn[MAX_STUDENT_NUMBER+1], fmtbuf[SMALL_LINE_BUFFER]; char *big_buf; sprintf(filename,"records/set%d.db",set); if ((fp=fopen(filename,"r+"))==NULL) { /* printf("Error capa_set_entry(): can't open %s\n",filename); */ return (-1); } /* entry->answers*3 == entry->tries, + fudge factor*/ a_line=capa_malloc(strlen(entry->tries)*5+MAX_STUDENT_NUMBER,1); sprintf(a_line,"%s %s,%s\n",entry->student_number,entry->answers,entry->tries); new_len = strlen(a_line); sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER); flockstream(fp); /* <==== lock the setX.db file */ fseek(fp,0L,SEEK_END); orig_size = ftell(fp); big_buf_size = orig_size + new_len; big_buf = capa_malloc(big_buf_size,1); fseek(fp,0L,SEEK_SET); /* rewind to beginning of file */ fgets(tmpline,TMP_LINE_LENGTH-1,fp); /* skip weight line, including \n */ fgets(tmpline,TMP_LINE_LENGTH-1,fp); /* hand grading */ done = 0; while(!done) { done = !fgets(tmpline,TMP_LINE_LENGTH-1,fp); len = strlen(tmpline); if( !done ) { sscanf(tmpline,fmtbuf,tmp_sn); if( !strncasecmp(tmp_sn,student_number,MAX_STUDENT_NUMBER) ) { /* Found */ next_r = ftell(fp); offset = next_r - len; done = 1; item_cnt=fread(big_buf,1,big_buf_size, fp); /* read remaining lines into buffer */ if(item_cnt >= 0 ) { /* no error reading remaining lines */ big_buf[item_cnt]=0; /* terminate the buffer, for sure */ fseek(fp,offset,SEEK_SET); /* reposition file pointer to the record */ if (!fwrite(a_line,new_len,1,fp) ) { /* write out the records */ /* printf("Error writing data to file\n"); */ errcode= (-1); } if (item_cnt != 0) { if (!fwrite(big_buf,item_cnt,1,fp) ){/*write out the remainings*/ /* printf("Error writing data to file\n"); */ errcode= (-1); } } new_size = ftell(fp); if(new_size < orig_size ) { fd = fileno(fp); ftruncate(fd,new_size); } } } } else { /* end of file */ fseek(fp,0L,SEEK_END); offset = ftell(fp); /* last byte, if last byte is cr, back up one */ fseek(fp,-1L,SEEK_END); while(fgetc(fp) == '\n' ) { offset--; fseek(fp,offset,SEEK_SET); } offset = offset +2; /* last char and cr */ done=1; fseek(fp,offset,SEEK_SET); if (!fwrite(a_line,new_len,1,fp) ) { /* write out the records */ /* printf("Error writing data to file\n"); */ errcode= (-1); } } } fflush(fp); funlockstream(fp); /* <======= unlock the file */ fclose(fp); capa_mfree(big_buf); /* free up the buffer */ return (errcode); } /* for all elements in entry->answers that aren't ? it changes the file to have the new values (except if student has a Y and for all entries in entry->tries that don't have the value -1 it changes the file to have the new value */ int capa_change_entry(entry, student_number, set) T_entry *entry; char *student_number; int set; { FILE *fp; int fd; int errcode=0,offset=0; int done, len, new_len, item_cnt,i,j; long next_r, orig_size, new_size, big_buf_size; char filename[FILE_NAME_LENGTH]; char *a_line, tmpline[TMP_LINE_LENGTH], tmp_sn[MAX_STUDENT_NUMBER+1], fmtbuf[SMALL_LINE_BUFFER]; char *big_buf; sprintf(filename,"records/set%d.db",set); if ((fp=fopen(filename,"r+"))==NULL) { /* printf("Error capa_set_entry(): can't open %s\n",filename); */ return (-1); } /* entry->answers*3 == entry->tries, + fudge factor*/ a_line=capa_malloc(strlen(entry->tries)*5+MAX_STUDENT_NUMBER,1); sprintf(a_line,"%s %s,%s\n",entry->student_number,entry->answers,entry->tries); new_len = strlen(a_line); sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER); flockstream(fp); /* <==== lock the setX.db file */ fseek(fp,0L,SEEK_END); orig_size = ftell(fp); big_buf_size = orig_size + new_len; big_buf = capa_malloc(big_buf_size,1); fseek(fp,0L,SEEK_SET); /* rewind to beginning of file */ fgets(tmpline,TMP_LINE_LENGTH-1,fp); /* skip weight line, including \n */ fgets(tmpline,TMP_LINE_LENGTH-1,fp); /* hand grading */ done = 0; while(!done) { done = !fgets(tmpline,TMP_LINE_LENGTH-1,fp); len = strlen(tmpline); if( !done ) { sscanf(tmpline,fmtbuf,tmp_sn); if( !strncasecmp(tmp_sn,student_number,MAX_STUDENT_NUMBER) ) { /* Found */ next_r = ftell(fp); offset = next_r - len; done = 1; item_cnt=fread(big_buf,1,big_buf_size,fp); /*read remaining lines into buffer*/ if(item_cnt >= 0 ) { /* no error reading remaining lines */ big_buf[item_cnt]=0; /* terminate the buffer, for sure */ fseek(fp,offset,SEEK_SET); /* reposition file pointer to the record */ for(i=0;ie_probs;i++) { /*if entry has been updated, and student doesn't have a Y yet*/ if ((entry->answers[i]!='?') && (tmpline[MAX_STUDENT_NUMBER+1+i]!='Y')) tmpline[MAX_STUDENT_NUMBER+1+i]=entry->answers[i]; j = atoi(&(entry->tries[i*3])); if ( j > -1 ) { tmpline[MAX_STUDENT_NUMBER+1+entry->e_probs+1+i*3]=entry->tries[i*3]; tmpline[MAX_STUDENT_NUMBER+1+entry->e_probs+1+i*3+1]=entry->tries[i*3+1]; } } if (!fwrite(tmpline,new_len,1,fp) ) { errcode= (-1); } if (item_cnt != 0) { if (!fwrite(big_buf,item_cnt,1,fp) ){/*write out the remainings*/ /* printf("Error writing data to file\n"); */ errcode= (-1); } } new_size = ftell(fp); if(new_size < orig_size ) { fd = fileno(fp); ftruncate(fd,new_size); } } } } else { /* end of file */ fseek(fp,0L,SEEK_END); offset = ftell(fp); /* last byte, if last byte is cr, back up one */ fseek(fp,-1L,SEEK_END); while(fgetc(fp) == '\n' ) { offset--; fseek(fp,offset,SEEK_SET); } offset = offset +2; /* last char and cr */ done=1; fseek(fp,offset,SEEK_SET); if (!fwrite(a_line,new_len,1,fp) ) { /* write out the records */ /* printf("Error writing data to file\n"); */ errcode= (-1); } } } fflush(fp); funlockstream(fp); /* <======= unlock the file */ fclose(fp); capa_mfree(big_buf); /* free up the buffer */ return (errcode); } /* -------------------------------------------------- */ /* append a entry record to the very end of the file */ long capa_append_entry(entry, student_number, set) T_entry *entry; char *student_number; int set; { FILE *fp; int len; char filename[FILE_NAME_LENGTH]; char a_line[TMP_LINE_LENGTH]; long offset; sprintf(filename,"records/set%d.db",set); if ((fp=fopen(filename,"r+"))==NULL) { /* printf("Error capa_set_entry(): can't open %s\n",filename); */ return (-1); } sprintf(a_line,"%s %s,%s\n",entry->student_number,entry->answers,entry->tries); len = strlen(a_line); flockstream(fp); /* <==== lock the setX.db file */ fseek(fp,0L,SEEK_END); offset = ftell(fp); fseek(fp,-1L,SEEK_END); while(fgetc(fp) == '\n' ) { offset--; fseek(fp,offset,SEEK_SET); } offset = offset +2; fseek(fp,offset,SEEK_SET); if (!fwrite(a_line,len,1,fp) ) { /* printf("Error writing data to file\n"); */ return (-1); } fflush(fp); funlockstream(fp); fclose(fp); return (offset); } /*----------------------------------------------------------*/ long /* RETURNS: byte offset to start of record, 0 if error, -offset if not found & newly created */ capa_get_entry(entry, student_number, set) T_entry *entry; char *student_number; int set; { char filename[FILE_NAME_LENGTH]; FILE *fp; int len, nq; char *ans_p, *tries_p, oneline[TMP_LINE_LENGTH],fmtbuf[SMALL_LINE_BUFFER]; long offset = 0, next_r; int ii, done, found = 0; char a_sn[MAX_STUDENT_NUMBER+1]; sprintf(filename,"records/set%d.db",set); if ((fp=fopen(filename,"r"))==NULL) { /*printf("Error capa_get_entry(): can't open %s\n",filename);*/ return (0); } sprintf(entry->student_number,"%s",student_number); sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER); flockstream(fp); fgets(oneline,TMP_LINE_LENGTH-1,fp); len = strlen(oneline); sscanf(oneline,"%d",&nq); fgets(oneline,TMP_LINE_LENGTH-1,fp); /* skip weight line, including \n */ fgets(oneline,TMP_LINE_LENGTH-1,fp); /* hand grading */ done = 0; while(!done) { done = !fgets(oneline,TMP_LINE_LENGTH-1,fp); len = strlen(oneline); if( !done ) { sscanf(oneline,fmtbuf,a_sn); if( !strncasecmp(a_sn,student_number,MAX_STUDENT_NUMBER) ) { /* Found */ next_r = ftell(fp); offset = next_r - len; done = 1; found = 1; } } else { /* end of file */ fseek(fp,0L,SEEK_END); offset = ftell(fp); /* last byte, if last bye is cr, back up one */ fseek(fp,-1L,SEEK_END); while(fgetc(fp) == '\n' ) { offset--; fseek(fp,offset,SEEK_SET); } offset = offset +2; /* last char and cr */ found = 0; done=1; } } funlockstream(fp); fclose(fp); if(!found) { ans_p = capa_malloc(nq+2,1); tries_p = capa_malloc(3*nq+3,1); /* space and \0 */ for(ii=0;iianswers = ans_p; entry->tries = tries_p; entry->e_probs = nq; offset = capa_append_entry(entry,student_number,set); } else { /* grows records shorter than nq to nq in length*/ char *comma; int length; comma=index(oneline,','); length=((int)(comma-oneline))-(MAX_STUDENT_NUMBER+1); if (length < nq) { ans_p = capa_malloc(nq+2,1); tries_p = capa_malloc(3*nq+3,1); /* space and \0 */ } else { ans_p = capa_malloc(length+2,1); tries_p = capa_malloc(3*length+3,1); /* space and \0 */ } sprintf(fmtbuf, "%%%dc",length); sscanf(oneline + MAX_STUDENT_NUMBER+1,fmtbuf,ans_p); ans_p[length]='\0'; sprintf(fmtbuf, "%%%dc",(3*length-1)); sscanf(oneline + MAX_STUDENT_NUMBER+1+length+1,fmtbuf,tries_p); tries_p[3*length-1]='\0'; entry->answers = ans_p; entry->tries = tries_p; entry->e_probs = nq; if (length < nq) { for(ii=length;ii 25 ) { /* contains valid information, instead of only cr */ sscanf(line+SECTION_BEGIN_COLUMN,"%d", &tmp_sec); if (!section || tmp_sec == section) { s3_p = (T_student *)capa_malloc(sizeof(T_student),1); s3_p->s_sec = tmp_sec; sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER); sscanf(line+SN_BEGIN_COLUMN,fmtbuf,s3_p->s_sn); cp = (char *)&line[NAME_BEGIN_COLUMN]; for(i=0;is_nm[i]=' '; i=0; while( (i < MAX_NAME_CHAR) && ( isalnum(cp[i]) || cp[i] == ',' || cp[i] == '.' || cp[i] == '\'' || cp[i] == ' ' || cp[i] == '\t'|| cp[i] == '-' ) ) { s3_p->s_nm[i]=cp[i]; i++; } s3_p->s_nm[MAX_NAME_CHAR]='\0'; s3_p->s_email[0]=0; if( line_len > EMAIL_BEGIN_COLUMN ) { /* contains email */ cp = (char *)&line[EMAIL_BEGIN_COLUMN]; for(i=0;is_email[i]=' '; i=0; while( (i < MAX_EMAIL_CHAR) && ( isalnum(cp[i]) || cp[i] == '@' || cp[i] == '.' ) ) { s3_p->s_email[i]=cp[i]; i++; } s3_p->s_email[i]='\0'; /* terminate the email string with the string length */ if( line_len > CAPAID_BEGIN_COLUMN ) { /* contains capa id */ sscanf(line+CAPAID_BEGIN_COLUMN,"%d", &tmp_capaid); if(tmp_capaid > 0 ) { s3_p->s_capaid = tmp_capaid; } } } if( student_cnt == 0 ) { s1_p = s3_p; s3_p->s_prev = s3_p; s3_p->s_next = (T_student *)NULL; s2_p = s3_p; } else { s3_p->s_prev = s2_p; s3_p->s_next = (T_student *)NULL; s2_p->s_next = s3_p; s2_p = s3_p; } student_cnt++; } } } fclose(fp); *student_pp = s1_p; return (student_cnt); } /*----------------------------------------------------------*/ /*----------------------------------------------------------*/ /* Retrieve a linked list of students with specified */ /* section in classl file */ /* If the input section number is 0, students in the whole */ /* classl will be retrieved. */ /* The resulting linked list is ordered according to */ /* student name */ /* Remember to use free_students() to free up the linked */ /* list once done with it. */ /*----------------------------------------------------------*/ /* INPUT: section section number */ /* 0 means to load the whole class */ /* OUTPUT: student_pp */ /* pointer to pointer of structure T_student */ /* RETURN: number of students in specified section */ /*----------------------------------------------------------*/ int capa_sorted_section(student_pp, section) T_student **student_pp; int section; { int student_cnt; T_student *student_p, *c_sp; student_cnt = capa_get_section(&student_p,section); if( student_cnt > 1 ) { for(c_sp=student_p;c_sp;c_sp=c_sp->s_next){ strcpy(c_sp->s_key,c_sp->s_nm); } msort_main(&student_p); } *student_pp = student_p; return (student_cnt); } /*----------------------------------------------------------*/ /* INPUT: address of a pointer to T_student structure */ /* OUTPUT: address of a pointer to T_student structure */ /* */ /* RETURN: none */ /*----------------------------------------------------------*/ void msort_main(head_pp) T_student **head_pp; { T_student *right_p, *out_sp; if( (*head_pp != NULL) && ((*head_pp)->s_next != NULL) ) { msort_split( *head_pp, &right_p); msort_main(head_pp); msort_main(&right_p); msort_merge(*head_pp, right_p, &out_sp); *head_pp = out_sp; } } /*----------------------------------------------------------*/ /* INPUT: a_sp pointer to T_student structur */ /* OUTPUT: a_sp */ /* b_pp address of a pointer to T_student structure */ /* */ /* RETURN: none */ /*----------------------------------------------------------*/ void msort_split(a_sp, b_pp) T_student *a_sp; T_student **b_pp; { T_student *c_sp; *b_pp = a_sp; c_sp = a_sp->s_next; c_sp = c_sp->s_next; while( c_sp != NULL ) { c_sp = c_sp->s_next; *b_pp = (*b_pp)->s_next; if( c_sp != NULL ) c_sp = c_sp->s_next; } c_sp = (*b_pp)->s_next; (*b_pp)->s_next = NULL; *b_pp = c_sp; } /*----------------------------------------------------------*/ /* INPUT: a_sp pointer to T_student structur */ /* b_sp pointer to T_student structur */ /* OUTPUT: c_pp address of a pointer to T_student structure */ /* */ /* RETURN: none */ /*----------------------------------------------------------*/ void msort_merge(a_sp, b_sp, c_pp) T_student *a_sp, *b_sp, **c_pp; { T_student *d_sp; if( a_sp == NULL || b_sp == NULL ) { } else { if( strcmp(a_sp->s_key, b_sp->s_key) <= 0 ) { *c_pp = a_sp; a_sp = a_sp->s_next; } else { *c_pp = b_sp; b_sp = b_sp->s_next; } d_sp = *c_pp; while( (a_sp != NULL) && (b_sp != NULL) ) { if( strcmp(a_sp->s_key, b_sp->s_key) <= 0) { d_sp->s_next = a_sp; d_sp = a_sp; a_sp = a_sp->s_next; } else { d_sp->s_next = b_sp; d_sp = b_sp; b_sp = b_sp->s_next; } } if( a_sp == NULL ) { d_sp->s_next = b_sp; } else { d_sp->s_next = a_sp; } } } /*----------------------------------------------------------*/ /* INPUT: head_p pointer to T_student structure */ /* OUTPUT: head_p pointed to sorted linked list */ /* */ /* RETURN: none */ /*----------------------------------------------------------*/ void insert_sort(head_p) T_student *head_p; { T_student *tail_p, *i_p, *p_p, *r_p; if( head_p != NULL ) { tail_p = head_p; while( tail_p->s_next != NULL ) { i_p = tail_p->s_next; if( strcmp( i_p->s_key, head_p->s_key) < 0 ) { tail_p->s_next = i_p->s_next; i_p->s_next = head_p; head_p = i_p; } else { r_p = head_p; p_p = r_p->s_next; while( strcmp(i_p->s_key, p_p->s_key) > 0 ) { r_p = p_p; p_p = r_p->s_next; } if( i_p == p_p ) { tail_p = i_p; } else { tail_p->s_next = i_p->s_next; i_p->s_next = p_p; r_p->s_next = i_p; } } } } } /*----------------------------------------------------------*/ /* The purpose of this routine is to free up all spaces */ /* in the linked list */ /*----------------------------------------------------------*/ /* INPUT: student_p pointer to T_student structure */ /* OUTPUT: none */ /* */ /* RETURN: none */ /*----------------------------------------------------------*/ void free_students(student_p) T_student *student_p; { T_student *s_p,*next_p; for (s_p=student_p; s_p; s_p=next_p) { next_p = (s_p->s_next); capa_mfree((char *)s_p); } } /*----------------------------------------------------------*/ /* The purpose of this routine is to free up all spaces */ /* in the linked list */ /*----------------------------------------------------------*/ /* INPUT: student_p pointer to T_student structur */ /* OUTPUT: none */ /* */ /* RETURN: -2 file error */ /* -1 never login */ /* >= 0 score for that set */ /*----------------------------------------------------------*/ int capa_get_score(student_number,set,valid_scores,answers_pp) char *student_number;int set;int *valid_scores;char **answers_pp; { T_entry a_record; T_header a_header; long offset; int set_scores, set_valids=0, probs_cnt; int ii=0, never_login=1; if( (offset = capa_get_entry(&a_record,student_number,set) ) == 0 ) { return (-2); } probs_cnt = a_record.e_probs; if( capa_get_header(&a_header,set) < 0 ) { return (-2); } if( offset < 0 ) { for(set_valids=0,ii=0;ii= '0' && a_record.answers[ii] <= '9' ) { set_scores += (a_record.answers[ii] - '0'); set_valids += (a_header.weight[ii] - '0'); never_login = 0; } break; } } *answers_pp = a_record.answers; capa_mfree(a_record.tries); a_record.tries = NULL; } capa_mfree(a_header.weight); capa_mfree(a_header.partial_credit); *valid_scores = set_valids; if(never_login) set_scores = -1; return (set_scores); } /*----------------------------------------------------------*/ /* Reads the classl file and returns the number of students */ /* for each section in cnt_arry[] */ /* In cnt_arry[0] is the maximum section number that */ /* has at least one student */ /*----------------------------------------------------------*/ /* INPUT: cnt_arry[] integer array */ /* OUTPUT: cnt_arry[] */ /* */ /* */ /* RETURN: -1 file error */ /*----------------------------------------------------------*/ int capa_get_section_count(cnt_arry) int cnt_arry[]; { FILE *fp; char filename[FILE_NAME_LENGTH]; char line[TMP_LINE_LENGTH]; int sec_num, cnt, i, max; sprintf(filename,"classl"); if ((fp=fopen(filename,"r"))==NULL) { /*printf("Error: can't open %s\n",filename);*/ return (-1); } for(i=0;i0 success (line number in classl of student)*/ /*----------------------------------------------------------*/ int capa_get_student(student_number, student_p) char *student_number; T_student *student_p; { FILE *fp; char line[SMALL_LINE_BUFFER],fmtbuf[SMALL_LINE_BUFFER], sNumber[MAX_STUDENT_NUMBER+1], aNumber[MAX_STUDENT_NUMBER+1]; int i,found,line_len,tmp_capaid,linenum=0; char *cp; strncpy(sNumber, student_number,MAX_STUDENT_NUMBER+1); if ((fp=fopen("classl","r"))==NULL) { /*printf("Error: Can't open classlist file\n");*/ return (-1); } found = 0; while (!found && fgets(line,SMALL_LINE_BUFFER-1,fp)) { linenum++; line_len = strlen(line); sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER); sscanf(line+SN_BEGIN_COLUMN,fmtbuf,aNumber); if(!strncasecmp(sNumber,aNumber, MAX_STUDENT_NUMBER)) { found = 1; i=0; strncpy(student_p->s_sn, student_number,MAX_STUDENT_NUMBER+1); cp = (char *)&line[NAME_BEGIN_COLUMN]; while( (i< MAX_NAME_CHAR) && (isalnum(cp[i]) || cp[i] == ',' || cp[i] == '.' || cp[i] == '\'' || cp[i] == ' ' || cp[i] == '\t'|| cp[i] == '-' || cp[i] == '_' || cp[i] == '~' ) ) { student_p->s_nm[i]=cp[i]; i++; } student_p->s_nm[i]='\0'; sscanf(line+SECTION_BEGIN_COLUMN,"%d", &(student_p->s_sec)); student_p->s_email[0]=0; if( line_len > EMAIL_BEGIN_COLUMN ) { /* contains email */ cp = (char *)&line[EMAIL_BEGIN_COLUMN]; for(i=0;is_email[i]=' '; i=0; while( (i < MAX_EMAIL_CHAR) && ( isalnum(cp[i]) || cp[i] == '@' || cp[i] == '.' || cp[i] == '!' || cp[i] == '=' || cp[i] == '_' || cp[i] == '-' || cp[i] == '+' || cp[i] == '^' || cp[i] == '|' ) ) { student_p->s_email[i]=cp[i]; i++; } student_p->s_email[i]='\0'; /* terminate the email string with the string length */ if( line_len > CAPAID_BEGIN_COLUMN ) { /* contains capa id */ sscanf(line+CAPAID_BEGIN_COLUMN,"%d", &tmp_capaid); if(tmp_capaid > 0 ) { student_p->s_capaid = tmp_capaid; } } } } } fclose(fp); if (found > 0) found=linenum; return (found); } /*----------------------------------------------------------*/ /* lookup student information from classl file by */ /* student name */ /*----------------------------------------------------------*/ /* INPUT: student_name char array of student name */ /* OUTPUT: student_p pointer to a T_student structure */ /* that contains the student name, */ /* student number, section number */ /* of the student inquired */ /* */ /* RETURN: -1 file error */ /* 0 no such student */ /* 1 success */ /*----------------------------------------------------------*/ int capa_student_byname(student_name, student_p) char *student_name; T_student *student_p; { FILE *fp; char line[SMALL_LINE_BUFFER],fmtbuf[SMALL_LINE_BUFFER], sName[MAX_NAME_CHAR+1], aName[MAX_NAME_CHAR+1]; int i,found, len, line_len,tmp_capaid; char *cp; len = strlen(student_name); strncpy(sName, student_name,MAX_NAME_CHAR+1); if ((fp=fopen("classl","r"))==NULL) { /*printf("Error: Can't open classlist file\n");*/ return (-1); } found = 0; while (fgets(line,SMALL_LINE_BUFFER-1,fp)) { i=0; cp = (char *)&line[NAME_BEGIN_COLUMN]; while( (i < MAX_NAME_CHAR) && (isalnum(cp[i]) || cp[i] == ',' || cp[i] == '.' || cp[i] == '\'' || cp[i] == ' ' || cp[i] == '\t' || cp[i] == '-' || cp[i] == '_' || cp[i] == '~') ) { aName[i]=cp[i]; i++; } aName[i]='\0'; if(!strncasecmp(sName,aName,len)) { found = 1; strcpy(student_p->s_nm,aName); sscanf(line+SECTION_BEGIN_COLUMN,"%d", &(student_p->s_sec)); sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER); sscanf(line+SN_BEGIN_COLUMN,fmtbuf,student_p->s_sn); student_p->s_email[0]=0; line_len=strlen(line); if( line_len > EMAIL_BEGIN_COLUMN ) { /* contains email */ cp = (char *)&line[EMAIL_BEGIN_COLUMN]; for(i=0;is_email[i]=' '; i=0; while( (i < MAX_EMAIL_CHAR) && ( isalnum(cp[i]) || cp[i] == '@' || cp[i] == '.' || cp[i] == '!' || cp[i] == '=' || cp[i] == '_' || cp[i] == '-' || cp[i] == '+' || cp[i] == '^' || cp[i] == '|' ) ) { student_p->s_email[i]=cp[i]; i++; } student_p->s_email[i]='\0'; /* terminate the email string with the string length */ if( line_len > CAPAID_BEGIN_COLUMN ) { /* contains capa id */ sscanf(line+CAPAID_BEGIN_COLUMN,"%d", &tmp_capaid); if(tmp_capaid > 0 ) { student_p->s_capaid = tmp_capaid; } } } } } fclose(fp); return (found); } /*----------------------------------------------------------*/ /* Randomly selected a student from classl file specified */ /* by section */ /*----------------------------------------------------------*/ /* INPUT: section section number */ /* OUTPUT: student_p pointer to a T_student structure */ /* that contains the student name, */ /* student number, section number */ /* of the student inquired */ /* */ /* RETURN: -1 file error */ /* 0 no such student */ /* 1 success */ /*----------------------------------------------------------*/ int capa_pick_student(section, student_p) int section; T_student *student_p; { T_student *s1_p, *s2_p; int student_cnt, idx, pick=-1; student_cnt = capa_get_section(&s1_p,section); if(student_cnt > 0 ) { srand(time(NULL)); pick = rand() % student_cnt; for(s2_p = s1_p, idx=0; s2_p && idx < pick; idx++) { s2_p = s2_p->s_next; } strcpy(student_p->s_sn,s2_p->s_sn); strcpy(student_p->s_nm,s2_p->s_nm); strcpy(student_p->s_email,s2_p->s_email); student_p->s_capaid=s2_p->s_capaid; student_p->s_sec = s2_p->s_sec; free_students(s1_p); } return (pick); } /* -------------------------------------------------- */ /* add a student to the class file */ /* check duplicated student id */ /* student name? */ /* Returns: 0 success */ /* 1 there is an duplicate entry */ /* -------------------------------------------------- */ int capa_add_student(student_p) T_student *student_p; { FILE *fp; char line[SMALL_LINE_BUFFER], fmtbuf1[SMALL_LINE_BUFFER], tmp_nm[MAX_STUDENT_NUMBER+1], tmp_nu[MAX_NAME_CHAR+1]; int i,found, len; char *class, *cp; char cid[4],cn[4]; #if defined(NeXT) char cwd[FILE_NAME_LENGTH]; #endif #if defined(NeXT) class = getwd(cwd); if( class == NULL ) { class = cwd; } #else class = getcwd(NULL,255); #endif if( class == NULL ) { printf("capa_add_student(): Current working directory unknown!\n"); } len=strlen(class); cp=class; cp=cp+(len-8); for(i=0;i<3;i++) { cid[i] = cp[i+3]; cn[i] = cp[i]; } cid[3]=cn[3]=0; if ((fp=fopen("classl","r+"))==NULL) { /*printf("Error: Can't open classlist file\n");*/ return (-1); } found = 0; sprintf(fmtbuf1, "%%%dc",MAX_STUDENT_NUMBER); while (fgets(line,SMALL_LINE_BUFFER-1,fp)) { sscanf(line+SN_BEGIN_COLUMN,fmtbuf1,tmp_nu); tmp_nu[MAX_STUDENT_NUMBER]='\0'; if(!strncasecmp(student_p->s_sn,tmp_nu, MAX_STUDENT_NUMBER)) { found = 1; break; } i=0; cp = (char *)&line[NAME_BEGIN_COLUMN]; while( (i < MAX_NAME_CHAR) && (isalnum(cp[i]) || cp[i] == ',' || cp[i] == '.' || cp[i] == '\'' || cp[i] == ' ' || cp[i] == '\t'|| cp[i] == '-' || cp[i] == '_' || cp[i] == '~') ) { tmp_nm[i]=cp[i]; i++; } tmp_nm[i]='\0'; len=strlen(tmp_nm); if(!strncasecmp(student_p->s_nm,tmp_nm,len)) { found = 1; break; } } if(!found) { sprintf(line,"%s %s %03d %s %s\n", cn,cid,student_p->s_sec,student_p->s_sn,student_p->s_nm); len = strlen(line); fseek(fp,0L,SEEK_END); if (!fwrite(line,len,1,fp) ) { /*printf("Error writing data to file\n");*/ found = -1; } fflush(fp); } fclose(fp); free(class); return (found); } /*----------------------------------------------------------*/ /* INPUT: student_number char array of student number */ /* set the X in logX.db */ /* OUTPUT: none */ /* */ /* RETURN: -1 file error */ /* 0 no login */ /* >0 number of logins in that logX.db file */ /*----------------------------------------------------------*/ int capa_get_login_count(student_number,set) char *student_number; int set; { char filename[FILE_NAME_LENGTH], sNumber[MAX_STUDENT_NUMBER+1], aNumber[MAX_STUDENT_NUMBER+1]; FILE *fp; char line[MAX_BUFFER_SIZE],fmtbuf[MAX_BUFFER_SIZE]; int num; strncpy(sNumber, student_number,MAX_STUDENT_NUMBER+1); sprintf(filename,"records/log%d.db",set); if( !capa_access(filename, F_OK) ) { if ((fp=fopen(filename,"r"))==NULL) { /*printf("Error: can't open %s\n",filename);*/ return (-1); } } else { return (-1); } num = 0; while (fgets(line,MAX_BUFFER_SIZE-1,fp)) { sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER); sscanf(line,fmtbuf,aNumber); if(!strncasecmp(sNumber,aNumber, MAX_STUDENT_NUMBER)) num++; } fclose(fp); return (num); } /*----------------------------------------------------------*/ /* INPUT: set the X in logX.db */ /* OUTPUT: none */ /* */ /* RETURN: -1 file error */ /* 0 no login */ /* >0 number of logins in that logX.db file */ /*----------------------------------------------------------*/ #define ANSWER_BEGIN_COLUMN 35 int capa_get_login_db(login_item,num_probs,set) T_entry login_item[]; int *num_probs; int set; { FILE *fp; char filename[FILE_NAME_LENGTH]; char line[MAX_BUFFER_SIZE],fmtbuf[SMALL_LINE_BUFFER]; T_header header; int num_q, count, len; if(capa_get_header(&header,set)) return (0); sscanf(header.num_questions,"%d",&num_q); *num_probs = num_q; capa_mfree(header.weight); capa_mfree(header.partial_credit); sprintf(filename,"records/log%d.db",set); if((fp=fopen(filename,"r"))==NULL) { /*printf("Error: can't open %s\n",filename);*/ return (-1); } count=0; while ( fgets(line,MAX_BUFFER_SIZE,fp) && (strlen(line) != 0 )) { len = strlen(line); if(len > ANSWER_BEGIN_COLUMN ) { sprintf(fmtbuf, "%%%dc",MAX_STUDENT_NUMBER); sscanf(line,fmtbuf, login_item[count].student_number); login_item[count].answers = capa_malloc(num_q,1); sprintf(fmtbuf, "%%%dc",num_q); sscanf(line+ANSWER_BEGIN_COLUMN,fmtbuf, login_item[count].answers); count++; } } fclose(fp); return (count); } /*----------------------------------------------------------*/ /* INPUT: option the option the check */ /* set the X in dateX.db */ /* section which section to check for */ /* */ /* OUTPUT: none */ /* */ /* RETURN: -2 invalid option */ /* -1 capa_get_section_dates error */ /* 0 no */ /* 1 yes */ /*----------------------------------------------------------*/ int capa_check_option(int option,int set,int section) { T_dates* dates; int result; result=capa_get_section_dates(section,set,&dates); if (result < 0) return -1; switch(option) { case OPTION_INHIBIT_RESPONSE: result=dates->inhibit_response;break; case OPTION_VIEW_PROBLEMS_AFTER_DUE: result=dates->view_problems_after_due;break; default: result=-2; } capa_mfree((char*)dates); return result; } /*----------------------------------------------------------*/ /* INPUT: time the current time */ /* datetime the datetime string to compare */ /* OUTPUT: none */ /* */ /* RETURN: -1 time is earlier then datetime */ /* 1 time is later than datetime */ /*----------------------------------------------------------*/ int compare_datetime(time,datetime) time_t time; char *datetime; { char dateStr[16], timeStr[16]; time_t time2; char *t_ptr; int idx; /* sscanf(datetime,"%s %s",dateStr,timeStr); */ t_ptr = index(datetime,' '); t_ptr++; /*** hpux complained */ for(idx=0;idx<10;idx++) dateStr[idx] = datetime[idx]; dateStr[10] = 0; for(idx=0;idx<5;idx++) timeStr[idx] = t_ptr[idx]; timeStr[5] = 0; time2 = convertTime(dateStr,timeStr); if(time == time2 ) return (0); return ( (time > time2)? 1 : -1 ); } /* --------------------------------- */ /* check if records/dateX.db exists */ /* read the section open date, answer date, due date info */ /* What if: [7,3] date_info */ /* [3,7] date_info */ /* 4 date_info */ /* RETURN: -1 if not pass time */ /* 1 if pass time (or no time available */ int capa_check_date(int which,char *student_number, int section,int set) { int result; char date_str[TMP_LINE_LENGTH]; time_t curtime; time(&curtime); result = capa_get_date(which,student_number,section,set,date_str); if ( result == 1 ) { result = compare_datetime(curtime,date_str); } return result; } time_t capa_convert_duration(char *duration) { int hour, minute; sscanf(duration,"%d:%d",&hour,&minute); return ((hour*60)+minute)*60; } void capa_get_due_date(char *date_str,T_dates *current,char *student_number,int set) { time_t duration=capa_convert_duration(current->duration); time_t duetime=0; time_t logintime; struct tm *due_time_tm; if ((duration > 0) && (student_number!=NULL)) { if (capa_get_login_time(student_number,set,&logintime)==1) { duetime=logintime+duration; if (compare_datetime(duetime,current->due_date)==-1) { due_time_tm=localtime(&duetime); sprintf(date_str,"%04d/%02d/%02d %02d:%02d",((due_time_tm->tm_year)+1900), due_time_tm->tm_mon+1,due_time_tm->tm_mday,due_time_tm->tm_hour, due_time_tm->tm_min); } else { strncpy(date_str,current->due_date,DATE_BUFFER); } return; } } strncpy(date_str,current->due_date,DATE_BUFFER); } /* student_number can be NULL, if it isn't NULL it is used by get_due_date */ /* to assign a due date based on the time the student first accessed the */ /* set if duration is non-zero */ int capa_get_date(int which,char *student_number,int section,int set,char *date_str) { T_dates *current; int result; result=capa_get_section_dates(section,set,¤t); if (result<0) return result; result=1; switch(which) { case CHECK_OPEN_DATE: strncpy(date_str,current->open_date,DATE_BUFFER); break; case CHECK_DUE_DATE: capa_get_due_date(date_str,current,student_number,set); break; case CHECK_ANS_DATE: strncpy(date_str,current->answer_date,DATE_BUFFER); break; default: strncpy(date_str,current->open_date,DATE_BUFFER); result=-4;break; } capa_mfree((char*)current); return result; } int capa_get_duration(char *student_number,int section,int set) { T_dates *current; int duration=0,result; result=capa_get_section_dates(section,set,¤t); if (result<0) return result; duration=capa_convert_duration(current->duration); capa_mfree((char*)current); return duration; } int capa_get_section_dates(int section,int set,T_dates** dates) { register int c; FILE *fp; int result = 0, done; int tmp_low, tmp_high, sec_mode; char filename[FILE_NAME_LENGTH], tmpline[TMP_LINE_LENGTH], default_line[TMP_LINE_LENGTH]; sprintf(filename,"records/date%d.db",set); if( capa_access(filename, F_OK) != 0 ) { result = -2; } else { if ((fp=fopen(filename,"r")) == NULL) { result = -2; } else { done = 0; result = -3; /* first non-comment line is assumed to be the default line */ c_gettype(fp); c_ignorewhite(fp); fgets(default_line,TMP_LINE_LENGTH-1,fp); do { c_ignorewhite(fp); c = getc(fp); ungetc(c,fp); if( c != EOF ) { sec_mode = c_getsec_range(fp,&tmp_low,&tmp_high); if( sec_mode > 0 ) { /* no error */ c_ignorewhite(fp); fgets(tmpline,TMP_LINE_LENGTH-1,fp); if( sec_mode == 1 ) { /* form: sec date_info */ if((result == -3) && (tmp_low == section)) { result=-4; *dates=add_date_info(tmp_low,tmp_low,tmpline); if ( *dates != NULL ) { done = 1; result = 1; } } } else { /* form : [low,high] date_info */ if( (result == -3) && ((section>=tmp_low)&&(section<=tmp_high)) ) { result = -4; *dates=add_date_info(tmp_low,tmp_high,tmpline); if ( *dates != NULL ) { done = 1; result = 1; } } } } else { /* error in specify section date */ while ( ((c = getc(fp)) != '\n') && ( c != EOF) ); /* skip to end of line */ } } else { /* EOF encountered */ done = 1; } } while (!done); /* need to deal with those sections not show up in the dateX.db file */ if( result == -3 ) { /* section not in the dateX.db file, use default */ result = -4; *dates=add_date_info(DATE_DEFAULTS,DATE_DEFAULTS,default_line); if ( *dates != NULL ) { result = 1; } } } fclose(fp); } return (result); } T_dates* add_date_info(int lowsec,int highsec, char *dateinfo) { T_dates *dates; int result; dates=(T_dates*)capa_malloc(sizeof(T_dates),1); result=sscanf(dateinfo,"%16c,%16c,%16c,%s %d,%d",dates->open_date,dates->due_date, dates->answer_date,dates->duration,&(dates->inhibit_response), &(dates->view_problems_after_due)); if (result != 6) { capa_mfree((char*)dates); dates=NULL; } else { dates->section_start=lowsec; dates->section_end=highsec; dates->s_next=NULL; } return dates; } /*----------------------------------------------------------*/ /* INPUT: set the X in dateX.db */ /* dates a pointer to the dates pointer */ /* ACTION: builds a linked list of T_dates containing */ /* the login information */ /* RETURN: <0 file error */ /* >0 success (number of lines successfully */ /* proccessed) */ /*----------------------------------------------------------*/ int capa_get_all_dates (int set,T_dates **dates) { T_dates *current; FILE *fp; int result = 0, done, tmp_low, tmp_high, sec_mode, c, num=0; char filename[FILE_NAME_LENGTH], tmpline[TMP_LINE_LENGTH]; sprintf(filename,"records/date%d.db",set); if ( ((fp=fopen(filename,"r")) == NULL)) { result = -2; } else { done = 0; result = -3; /* first non-comment line is assumed to be the default line */ c_gettype(fp); c_ignorewhite(fp); fgets(tmpline,TMP_LINE_LENGTH-1,fp); *dates=add_date_info(DATE_DEFAULTS,DATE_DEFAULTS,tmpline); num++; if ( NULL == (current=*dates) ) { result = -3; } else { while(1) { c_ignorewhite(fp); c = getc(fp); ungetc(c,fp); if( c == EOF ) { break; } sec_mode = c_getsec_range(fp,&tmp_low,&tmp_high); if( sec_mode > 0 ) { /* no error */ c_ignorewhite(fp); fgets(tmpline,TMP_LINE_LENGTH-1,fp); if( sec_mode == 1 ) { /* form: sec date_info */ current->s_next=add_date_info(tmp_low,tmp_low,tmpline); } else { /* form : [low,high] date_info */ current->s_next=add_date_info(tmp_low,tmp_high,tmpline); } current=current->s_next; num++; } else { /* error in specify section date */ while ( ((c = getc(fp)) != '\n') && ( c != EOF) ); /* skip to end of line */ } } result=num; } fclose(fp); } return (result); } /*----------------------------------------------------------*/ /* INPUT: dates a pointer to the dates pointer */ /* ACTION: frees a linked list of T_dates */ /*----------------------------------------------------------*/ void free_dates(T_dates *dates) { T_dates *current = dates,*next; while ( current != NULL ) { next = current->s_next; capa_mfree((char*)current); current = next; } } /*----------------------------------------------------------*/ /* INPUT: set the X in dateX.db */ /* dates a pointer to the dates pointer */ /* ACTION: takes a linked list of date information and */ /* and writes the info to a file */ /* RETURN: -1 file error */ /* 1 success */ /*----------------------------------------------------------*/ int capa_set_all_dates (int set,T_dates *dates) { T_dates *current = dates; int result; FILE* fp; char filename[FILE_NAME_LENGTH]; sprintf(filename,"records/date%d.db",set); if ( ((fp=fopen(filename,"w")) == NULL) ) { result = -1; } else { result=1; while ( current != NULL ) { if ( current->section_start == DATE_DEFAULTS ) { fprintf(fp,"<< DEFAULTS >> "); } else { fprintf(fp,"[%d, %d] ", current->section_start,current->section_end); } fprintf(fp,"%s,%s,%s,%s %d,%d\n", current->open_date,current->due_date, current->answer_date,current->duration,current->inhibit_response, current->view_problems_after_due); current = current->s_next; } fclose(fp); } return result; } /*----------------------------------------------------------*/ /* INPUT: set the X in logX.db */ /* OUTPUT: none */ /* */ /* RETURN: -1 file error */ /* 0 no login */ /* >0 number of logins in that logX.db file */ /*----------------------------------------------------------*/ #define FIFTEEN_MINUTES (15*60) #define TEN_MINUTES (600) #define ONE_DAY (86400) int /* RETURNS: 1 first time login, 2 second time login, 0 not ok, -1 file error */ login_check(student_number) /* ARGUMENTS: */ char *student_number; /* Student # */ { /* LOCALS: */ FILE *fp; int errcode=0; int found; char filename[FILE_NAME_LENGTH]; char line[SMALL_LINE_BUFFER], new_line[SMALL_LINE_BUFFER]; struct tm *theDT; time_t login_time, record_time; long offsetL, offsetR, offsetEnd,left_leng; char s_number[MAX_STUDENT_NUMBER+1]; char tty_name[FILE_NAME_LENGTH]; int log_tries, p_id; int month, day, year, hour, min, sec; char *tmp_buffer; sprintf(filename,"records/active.log"); if( capa_access(filename,F_OK) < 0 ) { /*<------------- File not exist */ if ((fp=fopen(filename,"w"))==NULL) { /* create if non-existant */ /*printf("Error: can't create %s\n",filename);*/ return (-1); } fclose(fp); } if ((fp=fopen(filename,"r"))==NULL) { /*printf("Error: can't open %s\n",filename);*/ return (-1); } flockstream(fp); /* lock exclusively and perform read/write operation */ found = 0; while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) { if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1; } offsetR = ftell(fp); offsetL = offsetR - strlen(line); funlockstream(fp); fclose(fp); if( found && (strlen(line) != 0) ) { /* printf("FOUND:%slen=%d\n",line,strlen(line)); */ 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); record_time = time(NULL); theDT = localtime(&record_time); theDT->tm_sec = sec; theDT->tm_min = min; theDT->tm_hour = hour; theDT->tm_mday = day; theDT->tm_mon = month-1; theDT->tm_year = year; theDT->tm_wday = weekday(year,month,day); theDT->tm_yday = julianday(year,month,day); record_time = mktime( theDT ); time(&login_time); theDT = localtime(&login_time); switch(log_tries) { case 0: log_tries = 1; errcode = 1; break; case 1: log_tries = 2; errcode = 2; break; case 2: log_tries = 3; errcode = 0; break; case 3: if( (login_time - record_time) >= TEN_MINUTES ) { log_tries = 1; errcode = 1; } else { log_tries = 3; errcode = 2; return (0); } break; default: printf("ERROR: Number of logins UNKNOWN\n"); log_tries = 1; errcode = 1; break; } 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); if ((fp=fopen(filename,"r+"))==NULL) { /*printf("Error: can't open %s\n",filename);*/ return (-1); } flockstream(fp); tmp_buffer = (char *)malloc(8*1024*56); found = 0; while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) { if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1; } offsetR = ftell(fp); offsetL = offsetR - strlen(line); fseek(fp,0L,SEEK_END); offsetEnd = ftell(fp); left_leng = offsetEnd - offsetR; fseek(fp,offsetR,SEEK_SET); left_leng = fread(tmp_buffer, 1, left_leng+1, fp); tmp_buffer[left_leng] = 0; fseek(fp,offsetL,SEEK_SET); if ( fprintf(fp,"%s%s",new_line,tmp_buffer) < 0 ) { /*printf("Error: cannot write active.log\n");*/ errcode = -1; } fflush(fp); free( (char *)tmp_buffer); funlockstream(fp); fclose(fp); } else { /********************************** First time login */ if ((fp=fopen(filename,"a+"))==NULL) { /*printf("Error: can't open %s\n",filename);*/ return (-1); } log_tries = 1; time(&login_time); theDT = localtime(&login_time); 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); /* leng = strlen(line); for(idx = 0, len_idx = 0; idx<(leng-1); idx++) { if(line[idx] == '\n' && line[idx+1] == '\n') { line[idx+1] = 0; } } */ flockstream(fp); if ( !fwrite((char *)line, strlen(line), 1, fp) ) { /*printf("ERROR: cannot write active.log\n");*/ errcode = -1; } else { errcode = 1; } fflush(fp); funlockstream(fp); fclose(fp); } return (errcode); } /******************************************************************************/ /* Logout check */ /******************************************************************************/ int /* RETURNS: 1 successful, 0 otherwise, -1 file error */ logout_check(student_number) /* ARGUMENTS: */ char *student_number; /* Student # */ { /* LOCALS: */ FILE *fp; int errcode=0; int found; char filename[FILE_NAME_LENGTH]; char line[SMALL_LINE_BUFFER]; long offsetL, offsetR, offsetEnd,left_leng; char s_number[MAX_STUDENT_NUMBER+1]; char tty_name[FILE_NAME_LENGTH]; int log_tries, p_id; int month, day, year, hour, min, sec; char *tmp_buffer; sprintf(filename,"records/active.log"); if ((fp=fopen(filename,"r"))==NULL) { /*printf("Error: can't open %s\n",filename);*/ return (-1); } flockstream(fp); /* lock exclusively and perform read/write operation */ found = 0; while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) { if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1; } offsetR = ftell(fp); offsetL = offsetR - strlen(line); funlockstream(fp); fclose(fp); if( found ) { #ifdef __alpha 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); #else 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); #endif switch(log_tries) { case 0: log_tries = 0; break; case 1: log_tries = 0; break; case 2: log_tries = 0; break; default: printf("ERROR: Number of logins UNKNOWN\n"); log_tries = 0; break; } #ifdef __alpha 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); #else 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); #endif if ((fp=fopen(filename,"r+"))==NULL) { /*printf("Error: can't open %s\n",filename);*/ return (-1); } flockstream(fp); tmp_buffer = (char *)malloc(8*1024*56); fseek(fp,0L,SEEK_END); offsetEnd = ftell(fp); left_leng = offsetEnd - offsetR; fseek(fp,offsetR,SEEK_SET); fread(tmp_buffer, left_leng, 1, fp); tmp_buffer[left_leng] = 0; /* for(idx=0, l_idx = 0; idx< (left_leng-1); idx++) { if( tmp_buffer[idx] == '/n' && tmp_buffer[idx+1] == '/n' ) { } } */ fseek(fp,offsetL,SEEK_SET); if ( fprintf(fp,"%s%s",line,tmp_buffer) < 0 ) { /*printf("Error: write error\n");*/ errcode = -1; } else { errcode = 1; } fflush(fp); free( (char *)tmp_buffer); funlockstream(fp); fclose(fp); } else { errcode = -1; } return (errcode); } /*********************************************/ /* SIZE of char =1, int=4, long=4, double=8 */ void capa_seed(seed1,seed2,student_number)long *seed1;long *seed2;char *student_number; { int class_pin1, class_pin2; int s_pin1, s_pin2, s_pin3; int i; char dest[16], tmpSN[MAX_STUDENT_NUMBER+1]; char *class,*capadefault="capadefault"; long part1, part2; #if defined(NeXT) char cwd[FILE_NAME_LENGTH]; #endif int big_endian; big_endian = endian(); /* determine what type of CPU we are on */ #if defined(NeXT) class = getwd(cwd); if( class == NULL ) { class = cwd; } #else class = getcwd(NULL,255); #endif class_pin1 = class_pin2 = 2; s_pin1 = s_pin2 = s_pin3 = 2; if( class == NULL ) { printf("capa_seed(): Current working directory unknown! Using capadefault\n"); class=capa_malloc(strlen(capadefault)+1,1); strcpy(class,capadefault); } if( big_endian ) { for(i=0;i<4;i++) dest[i] = class[strlen(class)-8+i]; for(i=4;i<8;i++) dest[i] = 0; memcpy((char *)(&class_pin1), dest, 4); for(i=0;i<4;i++) dest[i] = class[strlen(class)-4+i]; for(i=4;i<8;i++) dest[i] = 0; memcpy((char *)(&class_pin2), dest, 4); } else { for(i=0;i<4;i++) dest[i] = class[strlen(class)-i-5]; for(i=4;i<8;i++) dest[i] = 0; memcpy((char *)(&class_pin1), dest, 4); for(i=0;i<4;i++) dest[i] = class[strlen(class)-i-1]; for(i=4;i<8;i++) dest[i] = 0; memcpy((char *)(&class_pin2), dest, 4); } for(i=0;i "0123" */ for(i=0;i<4;i++) dest[i] = tmpSN[i+2]; for(i=4;i<8;i++) dest[i] = 0; memcpy((char *)(&s_pin2), dest, 4); /* 012345678 -> "2345" */ for(i=0;i<4;i++) dest[i] = tmpSN[i+5]; for(i=4;i<8;i++) dest[i] = 0; memcpy((char *)(&s_pin3), dest, 4); /* 012345678 -> "5678" */ } else { /* Intel 386, 486 */ for(i=0;i<4;i++) dest[i] = tmpSN[3-i]; for(i=4;i<8;i++) dest[i] = 0; memcpy((char *)(&s_pin1), dest, 4); /* 012345678 -> "0123" */ for(i=0;i<4;i++) dest[i] = tmpSN[5-i]; for(i=4;i<8;i++) dest[i] = 0; memcpy((char *)(&s_pin2), dest, 4); /* 012345678 -> "2345" */ for(i=0;i<4;i++) dest[i] = tmpSN[8-i]; for(i=4;i<8;i++) dest[i] = 0; memcpy((char *)(&s_pin3), dest, 4); /* 012345678 -> "5678" */ } part1 = s_pin1 + s_pin3+ class_pin2; if(part1 < 0) part1 = part1 * (-1); part2 = s_pin2 + class_pin1; if(part2 < 0) part2 = part2 * (-1); #ifdef SEED_DBG printf("S_PIN(%d,%d, %d) C_PIN(%d,%d)\n",s_pin1, s_pin2, s_pin3, class_pin1, class_pin2); printf("SEED(%ld,%ld)\n",part1, part2); #endif { extern void gsrgs(long getset,long *qvalue); static long qrgnin; gsrgs(0L,&qrgnin); if(!qrgnin) setall(part1, part2); } (*seed1) = part1; (*seed2) = part2; free(class); } /* ======================================================= PIN number */ /* pin should only called once for each student. */ /* if not called at the beginning of problem set, try to call it automatically */ int /* RETURNS: pin number for login set */ capa_PIN(student_number, set, guess) /* ARGUMENTS: */ char *student_number; int set; /* Problem set number */ int guess; { /* LOCALS: */ int current=0, /* Current pin for set */ i,j, /* Array indices */ nope, correct=0, all_pins[ONE_K]; long part1, part2; long orig_gen, new_gen; capa_seed(&part1, &part2, student_number); gscgn(GET_GENERATOR, &orig_gen); new_gen = PIN_G; gscgn(SET_GENERATOR, &new_gen); setsd(part1, part2); /* Generate 4-digit pin (1000-9999) */ for (i=1; i<=set; i++) { current=1000+ignlgi()%9000; do { nope=0; for (j=1; j the result is a string of letters where A=1..I=9,J=0 */ /* -------------------------------------------------------------------- */ char* capa_id_plus(student_number, set, plus) char *student_number; int set; int plus; { long part1,part2,orig_gen,new_gen,pin,rout,k,i; char *result; char letters[10]={'J','A','B','C','D','E','F','G','H','I'}; capa_seed(&part1, &part2, student_number); gscgn(GET_GENERATOR, &orig_gen); new_gen = PIN_G; gscgn(SET_GENERATOR, &new_gen); setsd(part1, part2); pin=capa_PIN(student_number,set,0); result=(char *)capa_malloc(sizeof(char), plus+MAX_PIN_CHAR+1); k=1; for(i=1;i<=MAX_PIN_CHAR;i++) { result[MAX_PIN_CHAR-i] = letters[(pin%(k*10))/k]; k*=10; } for(i=MAX_PIN_CHAR;inext; if (p->question != NULL) capa_mfree(p->question); if (p->answer != NULL) capa_mfree(p->answer); if (p->ans_cnt > 1 ) { AnswerInfo_t *a,*b; for(a = p->ans_list; a != NULL ; a = b) { b = a->ans_next; if (a->ans_str != NULL) capa_mfree(a->ans_str); if (a->ans_id_list != NULL ) capa_mfree(a->ans_id_list); if (a->ans_pts_list) { free_ptslist(a->ans_pts_list); } if (a->ans_unit) { freelist_unit_e(a->ans_unit->u_list); if (a->ans_unit != NULL) capa_mfree((char *)a->ans_unit); } capa_mfree((char *)a); } } if (p->id_list != NULL ) capa_mfree(p->id_list); if (p->pts_list!= NULL ) { free_ptslist(p->pts_list); } if (p->hint != NULL ) capa_mfree(p->hint); if (p->explain != NULL ) capa_mfree(p->explain); if (p->ans_unit !=NULL ) { freelist_unit_e(p->ans_unit->u_list); capa_mfree((char *)p->ans_unit); } capa_mfree((char *)p); p=NULL; } problem_p=NULL; } /******************************************************************************/ /* PARSE SOURCE FILE AND RETURN BLOCKS OF TEXT */ /******************************************************************************/ int capa_parse(set,problem,student_number,num_questions,func_ptr) int set;Problem_t **problem;char *student_number;int *num_questions; void (*func_ptr)(); { char filename[QUARTER_K]; int errcode; FILE *fp; extern FILE *Input_stream[MAX_OPENED_FILE]; extern char Opened_filename[MAX_OPENED_FILE][QUARTER_K]; extern int Lexi_line; extern int Lexi_qnum; extern Problem_t *FirstProblem_p; extern Problem_t *LastProblem_p; extern Problem_t *LexiProblem_p; extern char *StartText_p; extern char *EndText_p; extern char *ErrorMsg_p; extern int ErrorMsg_count; extern char Parse_class[QUARTER_K]; extern int Parse_section; extern int Parse_set; extern char Parse_name[MAX_NAME_CHAR+1]; extern char Parse_student_number[MAX_STUDENT_NUMBER+1]; extern int Symb_count; extern int first_run; extern int Stop_Parser; extern void (*Status_Func)(); #ifdef TTH extern void tth_restart(); extern char* tth_err; #endif /*TTH*/ long seed1, seed2; T_student a_student; char *class, *classname, warn_msg[WARN_MSG_LENGTH]; #if defined(NeXT) char cwd[FILE_NAME_LENGTH]; class = getwd(cwd); if( class == NULL ) { class = cwd; } #else class = getcwd(NULL,255); #endif if(class == NULL) { /* printf("capa_parse(): Current working directory unknown!"); */ return (-1); } classname = rindex(class,'/'); classname++; /*** hpux complained */ sprintf(Parse_class,"%s", classname); free(class); if( capa_get_student(student_number, &a_student) < 1 ) { /*printf("Error: capa_parse() encountered a student which is not in classl file\n"); */ return (-1); } sprintf(filename,"capa.config"); if ((fp=fopen(filename,"r"))==NULL) { /* printf("Error: can't open %s\n",filename);*/ return (-1); } u_getunit(fp); fclose(fp); #ifdef TTH if(tth_err) { free(tth_err); tth_err=NULL; } tth_restart(); #endif /*TTH*/ strncpy(Parse_name,a_student.s_nm,MAX_NAME_CHAR+1); strncpy(Parse_student_number,student_number,MAX_STUDENT_NUMBER+1); Parse_section = a_student.s_sec; if(ErrorMsg_p) { capa_mfree(ErrorMsg_p); ErrorMsg_p = NULL; } if(EndText_p) { capa_mfree(EndText_p); EndText_p = NULL; } if(StartText_p) { capa_mfree(StartText_p); StartText_p = NULL; } ErrorMsg_p = NULL; first_run = 1; EndText_p = NULL; free_symtree(); Symb_count = ErrorMsg_count = Lexi_line = Lexi_qnum = 0; FirstProblem_p = LastProblem_p = NULL; LexiProblem_p = (Problem_t *)capa_malloc(sizeof(Problem_t),1); problem_default(LexiProblem_p); /*LexiProblem_p->capaidplus=NULL;*/ Parse_set = set; Status_Func=func_ptr; sprintf(filename,"set%d.qz",set); #ifdef AVOIDYYINPUT yyin=fopen(filename,"r"); #else if ( (Input_stream[0]=fopen(filename,"r")) == NULL) { /* printf("Error: can't open %s\n",filename);*/ sprintf(warn_msg,"capa_parse(): CANNOT OPEN FILE\"%s\", file does not exist or is not readable.\n", filename); capa_msg(MESSAGE_ERROR,warn_msg); return (-1); } #endif sprintf(Opened_filename[0],"%s",filename); capa_seed(&seed1, &seed2, student_number); setall(seed1,seed2); yyrestart(yyin); Stop_Parser=0; if ( !yyparse() ) { errcode = Lexi_qnum; } else { errcode = 0; } /* fclose(Input_stream[0]);*/ /* The Lexer handles closing this */ /* print_symb_stat(); */ free_symtree(); /* capa_mfree((char *)LexiProblem_p); LexiProblem_p = NULL; */ (*problem) = FirstProblem_p; (*num_questions) = Lexi_qnum; return (errcode); } /******************************************************************************/ /* PARSE SOURCE FILE AND RETURN BLOCKS OF TEXT, unlike capa_parse_student */ /******************************************************************************/ int capa_parse_student(set,problem,a_student,num_questions,func_ptr) int set;Problem_t **problem;T_student *a_student;int *num_questions; void (*func_ptr)(); { char filename[QUARTER_K]; int errcode; FILE *fp; extern FILE *Input_stream[MAX_OPENED_FILE]; extern char Opened_filename[MAX_OPENED_FILE][QUARTER_K]; extern int Lexi_line; extern int Lexi_qnum; extern Problem_t *FirstProblem_p; extern Problem_t *LastProblem_p; extern Problem_t *LexiProblem_p; extern char *StartText_p; extern char *EndText_p; extern char *ErrorMsg_p; extern int ErrorMsg_count; extern char Parse_class[QUARTER_K]; extern int Parse_section; extern int Parse_set; extern char Parse_name[MAX_NAME_CHAR+1]; extern char Parse_student_number[MAX_STUDENT_NUMBER+1]; extern int Symb_count; extern int first_run; extern void (*Status_Func)(); long seed1, seed2; char *class, *classname, warn_msg[WARN_MSG_LENGTH]; #if defined(NeXT) char cwd[FILE_NAME_LENGTH]; class = getwd(cwd); if( class == NULL ) { class = cwd; } #else class = getcwd(NULL,255); #endif if(class == NULL) { /* printf("capa_parse(): Current working directory unknown!"); */ return (-1); } classname = rindex(class,'/'); classname++; /*** hpux complained */ sprintf(Parse_class,"%s", classname); free(class); sprintf(filename,"capa.config"); if ((fp=fopen(filename,"r"))==NULL) { /* printf("Error: can't open %s\n",filename);*/ sprintf(warn_msg,"capa_parse(): CANNOT OPEN FILE\"%s\", file does not exist or is not readable.\n", filename); capa_msg(MESSAGE_ERROR,warn_msg); return (-1); } u_getunit(fp); fclose(fp); strncpy(Parse_name,a_student->s_nm,MAX_NAME_CHAR+1); strncpy(Parse_student_number,a_student->s_sn,MAX_STUDENT_NUMBER+1); Parse_section = a_student->s_sec; if(ErrorMsg_p) { capa_mfree(ErrorMsg_p); ErrorMsg_p = NULL; } if(EndText_p) { capa_mfree(EndText_p); EndText_p = NULL; } if(StartText_p) { capa_mfree(StartText_p); StartText_p = NULL; } ErrorMsg_p = NULL; first_run = 1; EndText_p = NULL; free_symtree(); Symb_count = ErrorMsg_count = Lexi_line = Lexi_qnum = 0; FirstProblem_p = LastProblem_p = NULL; LexiProblem_p = (Problem_t *)capa_malloc(sizeof(Problem_t),1); problem_default(LexiProblem_p); /*LexiProblem_p->capaidplus=NULL;*/ Parse_set = set; Status_Func=func_ptr; sprintf(filename,"set%d.qz",set); #ifdef AVOIDYYINPUT yyin=fopen(filename,"r"); #else if ( (Input_stream[0]=fopen(filename,"r")) == NULL) { /* printf("Error: can't open %s\n",filename);*/ sprintf(warn_msg,"capa_parse(): CANNOT OPEN FILE\"%s\", file does not exist or is not readable.\n", filename); capa_msg(MESSAGE_ERROR,warn_msg); return (-1); } #endif sprintf(Opened_filename[0],"%s",filename); capa_seed(&seed1, &seed2, a_student->s_sn); setall(seed1,seed2); yyrestart(yyin); if ( !yyparse() ) { errcode = Lexi_qnum; } else { errcode = 0; } /* fclose(Input_stream[0]);*/ /*The Lexer handles closing this*/ /* print_symb_stat(); */ free_symtree(); /* capa_mfree((char *)LexiProblem_p); LexiProblem_p = NULL; */ (*problem) = FirstProblem_p; (*num_questions) = Lexi_qnum; return (errcode); } /* =================================================================== */ /* A utility method to convert a date string and time string to time_t */ /* dateStr: yyyy/mm/dd */ /* timeStr: hh:mm */ time_t convertTime(dateStr,timeStr)char *dateStr; char *timeStr; { struct tm *theTimeData; time_t result; int dateTime[5]; int year, month, day, mm, hh; sscanf(dateStr,"%4d/%2d/%2d",&year,&month,&day); dateTime[0] = month; dateTime[1] = day; dateTime[2] = year; sscanf(timeStr,"%2d:%2d",&hh,&mm); dateTime[3] = hh; dateTime[4] = mm; result = time(NULL); theTimeData = localtime(&result); theTimeData->tm_sec = 0; theTimeData->tm_min = dateTime[4]; theTimeData->tm_hour = dateTime[3]; theTimeData->tm_mday = dateTime[1]; theTimeData->tm_mon = dateTime[0]-1; theTimeData->tm_year = dateTime[2]-1900;/* tm_year is years since 1900 */ /* these fields are ignored by mktime theTimeData->tm_wday = weekday(year,month,day); theTimeData->tm_yday = julianday(year,month,day); */ result = mktime( theTimeData ); return (result); } int weekday( year, month, day) int year; int month; int day; { register int dow; #if defined(hpux) int juldays[13]; juldays[0]=0;juldays[1]=0;juldays[2]=31;juldays[3]=59; juldays[4]=90;juldays[5]=120;juldays[6]=151;juldays[7]=181; juldays[8]=212;juldays[9]=243;juldays[10]=273;juldays[11]=304;juldays[12]=334; #else int juldays[13] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; #endif dow = 7 + year + year/4 - year/100 + year/400 + juldays[month] + day; if( (month < 3) && ( leap_year(year) ) ) dow--; dow %= 7; return (dow); } /* weekday */ int julianday( year, month, day)int year;int month;int day; { register int doy; #if defined(hpux) int juldays[13]; juldays[0]=0;juldays[1]=0;juldays[2]=31;juldays[3]=59; juldays[4]=90;juldays[5]=120;juldays[6]=151;juldays[7]=181; juldays[8]=212;juldays[9]=243;juldays[10]=273;juldays[11]=304;juldays[12]=334; #else int juldays[13] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; #endif doy = juldays[month]; if((month > 2) && (leap_year(year)) ) doy++; doy += day; return (doy); } /* julianday */ int check_int( an_int ) char *an_int; { int ii, leng; int result=0; if( (an_int[0] == '-') || (an_int[0]== '+') ) an_int++; leng = strlen(an_int); for(ii=0;ii 0 ) { sscanf(base_str, "%lg", &b_part); x_part = pow(b_part, e_part); } else { x_part = 0.0; } if( strlen(num_str) > 0 ) { sscanf(num_str, "%lg", &n_part); } else { n_part=0.0; } result = n_part * x_part; errcode = errcode | 1; } else if ( buf[idx] == '^' ) { /* number ^ */ idx++; e_part = 1.0; while( isspace(buf[idx]) ) { idx++; } if( buf[idx] == '{'|| buf[idx] == '(' ) { /* matching right bracket */ idx++; } while( isspace(buf[idx]) ) { idx++; } if( isdigit(buf[idx]) || buf[idx] == '+' || buf[idx] == '-' ) { exp_str[e_idx] = 0; while( isdigit(buf[idx]) /*|| buf[idx] == '.'*/ || buf[idx] == '+' || buf[idx] == '-' ) { exp_str[e_idx++] = buf[idx++]; } exp_str[e_idx] = 0; } while( isspace(buf[idx]) ) { idx++; } if( buf[idx] == '}' || buf[idx] == ')' ) { idx++; } sscanf(exp_str, "%lg", &e_part); sscanf(num_str, "%lg", &n_part); if( n_part != 10 ) { return (-1); } result = pow(n_part,e_part); errcode = errcode | 1; } else { /* number unit */ if( strlen(num_str) > 0 ) { sscanf(num_str, "%lg", &result); errcode = errcode | 1; } } if( idx < len ) { /* collect the rest as unit string */ for(ii=idx;ii< len; ii++ ) { unit_str[u_idx++] = buf[ii]; } unit_str[u_idx]=0; /* terminate unit_str[] */ if(u_idx>0) { errcode = errcode | 2; } } if( strlen(num_str) > 0 ) { *num = result; } else { /* empty number string */ *num = 0.0; } sprintf(unit_p,"%s", unit_str); return (errcode); } char * answers_string(mode, p)int mode;Problem_t *p; { char *fmted_ans, lower[ANSWER_STRING_LENG], upper[ANSWER_STRING_LENG]; char *str_aa, *str_bb, *str_cc, *ans_str, *sub_ans_str, *tmp_str; int len_aa=0, len_bb=0, len_cc=0,len_dd=0, total_len, num_answer; double d_answer; if( p->ans_type == ANSWER_IS_SUBJECTIVE ) { char *a="Subjective Answer\n"; ans_str = (char *)capa_malloc(strlen(a)+1,1); strcpy(ans_str,a); return (ans_str); } num_answer = calc_ansrange(p->ans_type,p->calc, p->answer, p->ans_fmt, p->tol_type, p->tolerance, lower, upper); if( p->ans_type == ANSWER_IS_FLOAT ) { fmted_ans = capa_malloc(SMALL_LINE_BUFFER,1); d_answer = (double)atof(p->answer); sprintf(fmted_ans,p->ans_fmt,d_answer); } else { fmted_ans = capa_malloc(strlen(p->answer)+2,1); strcpy(fmted_ans,p->answer); } len_aa = strlen(fmted_ans); if (lower != NULL ) len_bb = strlen(lower); else len_bb = 0; if (upper != NULL ) len_cc = strlen(upper); else len_cc = 0; if ( p->unit_str != NULL ) len_dd = strlen(p->unit_str); else len_dd = 0; switch(mode) { case TeX_MODE: if(num_answer==2) { /* 16 is by adding up characters ' [,] \n\n' and others */ str_aa = format_toTeX(fmted_ans); total_len = strlen(str_aa) + len_dd + 16; str_bb = format_toTeX(lower); total_len += strlen(str_bb); str_cc = format_toTeX(upper); total_len += strlen(str_cc); ans_str = (char *)capa_malloc(total_len,1); if(len_dd == 0 ) { /* no unit_str */ sprintf(ans_str," %s [%s,%s]\n\n", str_aa,str_bb,str_cc); } else { sprintf(ans_str," %s [%s,%s] $\\mathrm{%s}$\n\n", str_aa,str_bb,str_cc,p->unit_str); } capa_mfree((char *)str_aa); capa_mfree((char *)str_bb); capa_mfree((char *)str_cc); } else { /* only one answer */ if ( (p->ans_type == ANSWER_IS_INTEGER) || (p->ans_type == ANSWER_IS_FLOAT )) { str_bb = format_toTeX(lower); } else { /* answer could be string, choice */ str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1); if (p->verbatim == DO_VERBATIM) sprintf(str_bb,"\\begin{verbatim}%s\\end{verbatim}",lower); else strcpy(str_bb,lower); } total_len = strlen(str_bb) + len_dd + 8; /* 4 is by adding up characters ' \\\n' plus four */ ans_str = (char *)capa_malloc(sizeof(char),total_len); if(len_dd == 0 ) { /* no unit_str */ sprintf(ans_str," %s\n", str_bb); } else { sprintf(ans_str," %s $\\mathrm{%s}$\n", str_bb,p->unit_str); } capa_mfree((char *)str_bb); } break; case ASCII_MODE: total_len = len_aa + len_bb + len_cc + len_dd + 8; /* 8 is by adding up characters ' [,] \n\n' plus one */ ans_str = (char *)capa_malloc(sizeof(char),total_len); if(num_answer==2) { if(len_dd == 0 ) { /* no unit_str */ sprintf(ans_str,"%s [%s,%s]\n\n", fmted_ans,lower,upper); } else { sprintf(ans_str,"%s [%s,%s] %s\n\n", fmted_ans,lower,upper,p->unit_str); } } else { if(len_dd == 0 ) { /* no unit_str */ sprintf(ans_str,"%s\n\n", lower); } else { sprintf(ans_str,"%s %s\n\n", lower,p->unit_str); } } break; case ANSWER_STRING_MODE: total_len = len_aa + len_bb + len_cc + len_dd + 8; /* 8 is by adding up characters ' [,] \n\n' plus one */ ans_str = (char *)capa_malloc(sizeof(char),total_len); if(num_answer==2) { if(len_dd == 0 ) { /* no unit_str */ sprintf(ans_str,"%s", fmted_ans); } else { sprintf(ans_str,"%s %s", fmted_ans,p->unit_str); } } else { if(len_dd == 0 ) { /* no unit_str */ sprintf(ans_str,"%s", lower); } else { sprintf(ans_str,"%s %s", lower,p->unit_str); } } break; case HTML_MODE: if(num_answer==2) { /* this indicates that answer should be either float or int */ str_aa = format_toHTML(fmted_ans); total_len = strlen(str_aa) + len_dd + 8; str_bb = format_toHTML(lower); total_len += strlen(str_bb); str_cc = format_toHTML(upper); total_len += strlen(str_cc); /* 8 is by adding up characters ' [,] \n\n' plus one */ ans_str = (char *)capa_malloc(sizeof(char),total_len); if(len_dd == 0 ) { /* no unit_str */ sprintf(ans_str,"%s [%s,%s]\n\n", str_aa,str_bb,str_cc); } else { sprintf(ans_str,"%s [%s,%s] %s\n\n", str_aa,str_bb,str_cc,p->unit_str); } capa_mfree((char *)str_aa); capa_mfree((char *)str_bb); capa_mfree((char *)str_cc); } else { if ( (p->ans_type == ANSWER_IS_INTEGER) || (p->ans_type == ANSWER_IS_FLOAT )) { str_bb = format_toHTML(lower); } else { /* answer could be string, choice */ str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1); if (p->ans_type == ANSWER_IS_FORMULA || 1) sprintf(str_bb,"
\n%s\n
",lower); else strcpy(str_bb,lower); } total_len = strlen(str_bb) + len_dd + 4; /* 4 is by adding up characters ' \n\n' plus one */ ans_str = (char *)capa_malloc(sizeof(char),total_len); if(len_dd == 0 ) { /* no unit_str */ sprintf(ans_str,"%s\n\n", str_bb); } else { sprintf(ans_str,"%s %s\n\n", str_bb,p->unit_str); } capa_mfree((char *)str_bb); } break; } capa_mfree(fmted_ans); if( p->ans_cnt > 1 ) { AnswerInfo_t *ai; for( ai = p->ans_list; ai; ai = ai->ans_next) { num_answer = calc_ansrange(ai->ans_type,ai->ans_calc, ai->ans_str, ai->ans_fmt, ai->ans_tol_type,ai->ans_tol,lower,upper); if( ai->ans_type == ANSWER_IS_FLOAT ) { fmted_ans = capa_malloc(SMALL_LINE_BUFFER,1); d_answer = (double)atof(ai->ans_str); sprintf(fmted_ans,ai->ans_fmt,d_answer); } else { fmted_ans = capa_malloc(strlen(ai->ans_str)+2,1); strcpy(fmted_ans,ai->ans_str); } len_aa = strlen(fmted_ans); len_bb = strlen(lower); len_cc = strlen(upper); len_dd = strlen(ai->ans_unit_str); switch(mode) { case TeX_MODE: if(num_answer==2) { /* 16 is by adding up characters ' [,] \n\n' and others */ str_aa = format_toTeX(fmted_ans); total_len = strlen(str_aa) + len_dd + 16; str_bb = format_toTeX(lower); total_len += strlen(str_bb); str_cc = format_toTeX(upper); total_len += strlen(str_cc); sub_ans_str = (char *)capa_malloc(sizeof(char),total_len); if(len_dd == 0 ) { /* no unit_str */ sprintf(sub_ans_str," %s [%s,%s]\n\n", str_aa,str_bb,str_cc); } else { sprintf(sub_ans_str," %s [%s,%s] $%s$\n\n", str_aa,str_bb,str_cc,ai->ans_unit_str); } capa_mfree((char *)str_aa); capa_mfree((char *)str_bb); capa_mfree((char *)str_cc); } else { /* only one answer */ if ( (ai->ans_type == ANSWER_IS_INTEGER) || (ai->ans_type == ANSWER_IS_FLOAT )) { str_bb = format_toTeX(lower); } else { /* answer could be string, choice */ str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1); if (ai->ans_type == ANSWER_IS_FORMULA || 1) sprintf(str_bb,"\\begin{verbatim}%s\\end{verbatim}",lower); else strcpy(str_bb,lower); } total_len = strlen(str_bb) + len_dd + 8; /* 4 is by adding up characters ' \\\n' plus four */ sub_ans_str = (char *)capa_malloc(sizeof(char),total_len); if(len_dd == 0 ) { /* no unit_str */ sprintf(sub_ans_str," %s\n", str_bb); } else { sprintf(sub_ans_str," %s $%s$\n", str_bb,ai->ans_unit_str); } capa_mfree((char *)str_bb); } break; case ASCII_MODE: total_len = len_aa + len_bb + len_cc + len_dd + 8; /* 8 is by adding up characters ' [,] \n\n' plus one */ sub_ans_str = (char *)capa_malloc(sizeof(char),total_len); if(num_answer==2) { if(len_dd == 0 ) { /* no unit_str */ sprintf(sub_ans_str,"%s [%s,%s]\n\n", fmted_ans,lower,upper); } else { sprintf(sub_ans_str,"%s [%s,%s] %s\n\n", fmted_ans,lower,upper,ai->ans_unit_str); } } else { if(len_dd == 0 ) { /* no unit_str */ sprintf(sub_ans_str,"%s\n\n", lower); } else { sprintf(sub_ans_str,"%s %s\n\n", lower,ai->ans_unit_str); } } break; case ANSWER_STRING_MODE: total_len = len_aa + len_bb + len_cc + len_dd + 8; /* 8 is by adding up characters ' [,] \n\n' plus one */ sub_ans_str = (char *)capa_malloc(sizeof(char),total_len); if(num_answer==2) { if(len_dd == 0 ) { /* no unit_str */ sprintf(sub_ans_str,", %s", fmted_ans); } else { sprintf(sub_ans_str,", %s %s", fmted_ans,ai->ans_unit_str); } } else { if(len_dd == 0 ) { /* no unit_str */ sprintf(sub_ans_str,", %s", lower); } else { sprintf(sub_ans_str,", %s %s", lower,ai->ans_unit_str); } } break; case HTML_MODE: if(num_answer==2) { str_aa = format_toHTML(fmted_ans); total_len = strlen(str_aa) + len_dd + 8; str_bb = format_toHTML(lower); total_len += strlen(str_bb); str_cc = format_toHTML(upper); total_len += strlen(str_cc); /* 8 is by adding up characters ' [,] \n\n' plus one */ sub_ans_str = (char *)capa_malloc(sizeof(char),total_len); if(len_dd == 0 ) { /* no unit_str */ sprintf(sub_ans_str,"%s [%s,%s]\n\n", str_aa,str_bb,str_cc); } else { sprintf(sub_ans_str,"%s [%s,%s] %s\n\n", str_aa,str_bb,str_cc,ai->ans_unit_str); } capa_mfree((char *)str_aa); capa_mfree((char *)str_bb); capa_mfree((char *)str_cc); } else { if ( (ai->ans_type == ANSWER_IS_INTEGER) || (ai->ans_type == ANSWER_IS_FLOAT )) { str_bb = format_toHTML(lower); } else { /* answer could be string, choice */ str_bb = (char *)capa_malloc(strlen(lower)+MAX_BUFFER_SIZE,1); if (ai->ans_type == ANSWER_IS_FORMULA || 1) sprintf(str_bb,"
\n%s\n
",lower); else strcpy(str_bb,lower); } total_len = strlen(str_bb) + len_dd + 4; /* 4 is by adding up characters ' \n\n' plus one */ sub_ans_str = (char *)capa_malloc(sizeof(char),total_len); if(len_dd == 0 ) { /* no unit_str */ sprintf(sub_ans_str,"%s\n\n", str_bb); } else { sprintf(sub_ans_str,"%s %s\n\n", str_bb,ai->ans_unit_str); } capa_mfree((char *)str_bb); } break; } /* end of switch */ total_len = strlen(ans_str); total_len += (strlen(sub_ans_str) + 1); tmp_str = (char *)capa_malloc(sizeof(char),total_len); strncpy(tmp_str, ans_str, strlen(ans_str)+1); strcat(tmp_str, sub_ans_str); capa_mfree(ans_str); capa_mfree(sub_ans_str); capa_mfree(fmted_ans); ans_str = tmp_str; } /* end of for */ } /* end of if */ return (ans_str); /* the calling routing needs to deallocate it */ } int check_for_unit_fail(int result) { int ret; ret = (result == UNIT_FAIL || result == UNIT_IRRECONCIBLE || result == UNIT_INVALID_STUDENT3 || result == UNIT_INVALID_STUDENT2 || result == UNIT_INVALID_STUDENT1); return ret; } /* ------------------------------ called from capalogin */ /* impose stronger checking on the user input string *answer */ /* */ /* <== This routine checks user input string *ans against correct answer *s ==> */ int capa_check_ans(ai,ans, error) AnswerInfo_t *ai; char *ans; char **error; { int t; /* ans_type */ char *s; /* ans_str */ int c; /* ans_calc */ int tt; /* ans_tol_type */ double to; /* ans_tol */ int su; /* ans_sig_ub */ int sl; /* ans_sig_lb */ char *fm; /* ans_fmt */ char *us; /* ans_unit_str */ Unit_t *u_p; /* ans_unit */ int input_len, all_alphabet = 1, idx, ii, type; int outcome=-1, result = INCORRECT; int sig, corr_len; int choice[MAX_ASCII]; char num_str[ANSWER_STRING_LENG], unit_str[ANSWER_STRING_LENG]; char fmted[ANSWER_STRING_LENG], correctans[MAX_ASCII], answer[ANSWER_STRING_LENG]; double n_part; double given, target, ratio, fmted_target, target_u, target_l, scale=1.0; double delta; t = ai->ans_type; s = ai->ans_str; c = ai->ans_calc; tt = ai->ans_tol_type; to = ai->ans_tol; su = ai->ans_sig_ub; sl = ai->ans_sig_lb; fm = ai->ans_fmt; us = ai->ans_unit_str; u_p = ai->ans_unit; switch(t) { case ANSWER_IS_INTEGER: case ANSWER_IS_FLOAT: { input_len = strlen(ans); all_alphabet = 1; for(idx=0;idx 0 ) { if( outcome > 1 ) { /* with both num and unit parts or only unit part */ if( u_p != NULL ) { result = check_correct_unit(unit_str,u_p,&scale); if (check_for_unit_fail(result)) { *error=strsave(unit_str); } } else { /* what to do when no unit is specified but student entered a unit? */ result = UNIT_NOTNEEDED; *error=strsave(unit_str); } } else { if( u_p != NULL ) { result = NO_UNIT; } } if( (result != NO_UNIT) && (!check_for_unit_fail(result)) && ( result != UNIT_NOTNEEDED) ) { if( t == ANSWER_IS_FLOAT ) { target = (double)atof(s); /* real number */ } else { target = (double)atol(s); /* Integer answer */ } given = n_part * scale; /* convert the given answer into proper scale for units */ sig = calc_sig( num_str ); if( ((sig < sl ) || (sig > su )) && (sig!=0)) { result = SIG_FAIL; *error=capa_malloc(1,ANSWER_STRING_LENG); sprintf(*error,"%d",sig); } else { switch( tt ) { /* tolerence type */ case TOL_ABSOLUTE: fmted_target = target; /* if answer type is integer */ if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */ sprintf(fmted, fm, target); fmted_target = (double)atof(fmted); } to = fabs(to); /* tol must be positive */ if( c == CALC_FORMATED) { target_l = fmted_target - to; target_u = fmted_target + to; } else { target_l = target - to; target_u = target + to; } if( (given >= target_l) && (given <= target_u) ) { result = APPROX_ANS; } else { result = INCORRECT; } break; case TOL_PERCENTAGE: if( target != 0.0 ) { ratio = (double)(to / 100.0); fmted_target = target; /* if answer type is integer */ if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */ sprintf(fmted, fm, target); fmted_target = (double)atof(fmted); } delta = (double)fabs((double)ratio*target); if( c == CALC_FORMATED) { target_l = fmted_target - delta; target_u = fmted_target + delta; } else { target_l = target - delta; target_u = target + delta; } } else { target_l = target_u = target; } if ( (given >= target_l) && (given <= target_u) ) { result = APPROX_ANS; } else { result = INCORRECT; } break; } } /* end sig check */ } /* end if unit check */ } else { /* user entered alphabets, but no number */ result = WANTED_NUMERIC; } } break; case ANSWER_IS_CHOICE: { corr_len = strlen(s); input_len = strlen(ans); if( corr_len == input_len ) { for(idx=0;idxans_id_list,ai->ans_pts_list,tt,to); break; case ANSWER_IS_EXTERNAL: /* Not yet implemented */ break; } return (result); } /* =============================================================================== */ /* calling sequence capa_check_answers() --> capa_check_answer() */ /* --> capa_check_ans() */ /* How we check the correct answer against user input string */ /* If the correct answer is a number (either integer or real number) check if user input string consists of only alphabet characters use split_num_unit() heuristic function to split the input string into two parts numerical part and units part. if the outcome contains units, check if the units is correct or not */ int capa_check_answer(p, answer, error) Problem_t *p; char *answer; char **error; { int type; char *correct; char input[ANSWER_STRING_LENG], unit_str[ANSWER_STRING_LENG]; int tol_type, calc_type; double tol, n_part; int sig_l; int sig_u; char *fmt; int choice[MAX_ASCII], correctans[MAX_ASCII]; int ii, idx, corr_len, input_len; int result = INCORRECT, sig, outcome=-1, all_alphabet; char fmted[FORMAT_STRING_LENG]; double given, target, ratio, fmted_target, target_u, target_l, scale=1.0; double delta; type = p->ans_type; correct = p->answer; tol_type = p->tol_type; tol = p->tolerance; sig_l = p->sig_lbound; sig_u = p->sig_ubound; fmt = p->ans_fmt; calc_type = p->calc; unit_str[0]=0; switch(type) { case ANSWER_IS_INTEGER: case ANSWER_IS_FLOAT: { input_len = strlen(answer); all_alphabet = 1; for(idx=0;idx 0 ) { if( outcome > 1 ) { /* with both num and unit parts or only unit part */ if( p->ans_unit != NULL ) { result = check_correct_unit(unit_str,p->ans_unit,&scale); if (check_for_unit_fail(result)) { *error=strsave(unit_str); } } else { /* what to do when no unit is specified but student entered a unit? */ result = UNIT_NOTNEEDED; *error=strsave(unit_str); } } else { if( p->ans_unit != NULL ) { result = NO_UNIT; } } if( (result != NO_UNIT) && (!check_for_unit_fail(result)) && ( result != UNIT_NOTNEEDED) ) { if( type == ANSWER_IS_FLOAT ) { target = (double)atof(correct); /* real number */ } else { target = (double)atol(correct); /* Integer answer */ } given = n_part * scale; /* convert the given answer into proper scale for units */ sig = calc_sig( input ); if( ((sig < sig_l) || (sig > sig_u)) && (sig!=0)) { result = SIG_FAIL; *error=capa_malloc(1,ANSWER_STRING_LENG); sprintf(*error,"%d",sig); } else { switch( tol_type ) { case TOL_ABSOLUTE: fmted_target = target; /* if answer type is integer */ if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */ sprintf(fmted, fmt, target); fmted_target = (double)atof(fmted); } tol = fabs(tol); /* tol must be positive */ if( calc_type == CALC_FORMATED) { target_l = fmted_target - tol; target_u = fmted_target + tol; } else { target_l = target - tol; target_u = target + tol; } if( (given >= target_l) && (given <= target_u) ) { result = APPROX_ANS; } else { result = INCORRECT; } break; case TOL_PERCENTAGE: if( target != 0.0 ) { ratio = (double)(tol / 100.0); fmted_target = target; /* if answer type is integer */ if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */ sprintf(fmted, fmt, target); fmted_target = (double)atof(fmted); } delta = (double)fabs((double)ratio*target); if( calc_type == CALC_FORMATED) { target_l = fmted_target - delta; target_u = fmted_target + delta; } else { target_l = target - delta; target_u = target + delta; } } else { target_l = target_u = target; } if ( (given >= target_l) && (given <= target_u) ) { result = APPROX_ANS; } else { result = INCORRECT; } break; } } /* end sig check */ } /* end if unit check */ } else { /* user entered alphabet, but no number */ result = WANTED_NUMERIC; } } break; case ANSWER_IS_CHOICE: { corr_len = strlen(correct); input_len = strlen(answer); if( corr_len == input_len ) { for(idx=0;idxid_list,p->pts_list,tol_type,tol); break; case ANSWER_IS_EXTERNAL: /* not yet implemented */ /* we assume the external program is called through popen() */ /* and the result will be given back as 0 or 1 to indicate the */ /* given answer is correct or not */ /* arguments are given to the program as */ /* before running the program, check its existance first */ /* should we specify a time out period in capa.config file? */ /* set up a timer for this purpose */ /* FILE *popen (const char *command,const char *type ); */ break; } return (result); } int check_tol (formula_val,tol_type,tol) double formula_val;int tol_type;double tol; { double diff; int outcome=APPROX_ANS; if( tol_type == TOL_ABSOLUTE ) { diff = tol - formula_val; if( diff < 0.0 ) { outcome = INCORRECT; } } else { diff = fabs(1.0 - formula_val) * 100.0 ; if( diff > tol ) { outcome = INCORRECT; } } return outcome; } /* -------------------------------------------------------------------------- */ /* assumming the formula is *fml_str and the student input is *input_str */ /* according to the type of tolerance, we form the final formula as */ /* absolute tolerance: (*fml_str) - (*input_str) */ /* relative tolerance: (*input_str) / (*fml_str) */ int check_formula_ans(fml_str,input_str,var_list,pts_list,tol_type,tol) char *fml_str;char *input_str;char *var_list;PointsList_t *pts_list;int tol_type; double tol; { char *check_fml_str; int f_len, i_len, outcome, error_code; PointsList_t *pt, *next; double formula_val; f_len = strlen(fml_str); i_len = strlen(input_str); check_fml_str = (char *)capa_malloc((f_len + i_len + 16), sizeof(char)); if( tol_type == TOL_ABSOLUTE ) { sprintf(check_fml_str,"abs((%s) - (%s))",fml_str, input_str); } else { sprintf(check_fml_str,"(%s) / (%s)",input_str,fml_str); } outcome = APPROX_ANS; if( pts_list==NULL ) { error_code = f_eval_formula(&formula_val,check_fml_str, var_list, NULL); if( ! error_code ) { outcome = check_tol(formula_val,tol_type,tol); } else { outcome = BAD_FORMULA; } } for(pt= pts_list; pt!=NULL ; pt=next) { next=pt->pts_next; error_code = f_eval_formula(&formula_val,check_fml_str, var_list, pt->pts_str); if( ! error_code ) { outcome = check_tol(formula_val,tol_type,tol); } else { outcome = BAD_FORMULA; break; } if (outcome != APPROX_ANS) { break; } } capa_mfree((char *)check_fml_str); return (outcome); } /* inputs: type :: answer type, calc_type :: input string format string tolerance type */ /* returns: lower upper */ int calc_ansrange(type, calc_type, input, fmt, tol_type, tol, lower, upper) int type;int calc_type;char *input;char *fmt; int tol_type;double tol;char *lower;char *upper; { int result = 2, leng; char fmted[ANSWER_STRING_LENG]; double target, fmted_target, ratio, target_l, target_u, tmp, delta; if( (type == ANSWER_IS_FORMULA) || (type == ANSWER_IS_EXTERNAL ) ) { strcpy(lower, input); result = 1; return (result); } else { if( tol == 0.0 ) { /* answer could be ANSWER_IS_FLOAT ANSWER_IS_INTEGER, ANSWER_IS_STRING_CI ANSWER_IS_STRING_CS ANSWER_IS_CHOICE */ result = 1; /* only one answer */ if( type == ANSWER_IS_FLOAT ) { target = (double)atof(input); sprintf(fmted, fmt, target); leng = strlen(fmted)+1; strcpy(lower, fmted); } else { /* could be integer, choice, string ci, string cs */ strcpy(lower, input); } } else { /* we have tolerence */ target = (double)atof(input); switch( tol_type ) { case TOL_ABSOLUTE: fmted_target = target; /* if answer type is integer */ if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */ sprintf(fmted, fmt, target); fmted_target = (double)atof(fmted); } tol = fabs(tol); /* tol must be positive */ if( calc_type == CALC_FORMATED) { target_l = fmted_target - tol; target_u = fmted_target + tol; } else { target_l = target - tol; target_u = target + tol; } if(type == ANSWER_IS_FLOAT) { sprintf(fmted, fmt, target_l ); strcpy(lower, fmted); sprintf(fmted, fmt, target_u ); strcpy(upper, fmted); } else { sprintf(fmted, "%.15g", target_l ); strcpy(lower, fmted); sprintf(fmted, "%.15g", target_u ); strcpy(upper, fmted); } break; case TOL_PERCENTAGE: if( target != 0.0 ) { ratio = (double)(tol / 100.0); fmted_target = target; /* if answer type is integer */ if( type == ANSWER_IS_FLOAT) { /* format the exact answer as specified */ sprintf(fmted, fmt, target); fmted_target = (double)atof(fmted); } delta = (double)fabs((double)ratio*target); if( calc_type == CALC_FORMATED) { target_l = fmted_target - delta; target_u = fmted_target + delta; } else { target_l = target - delta; target_u = target + delta; } if( target_l > target_u ) { tmp = target_u; target_u = target_l; target_l = tmp; } if(type == ANSWER_IS_FLOAT) { sprintf(fmted, fmt, target_l ); strcpy(lower, fmted); sprintf(fmted, fmt, target_u ); strcpy(upper, fmted); } else { sprintf(fmted, "%.15g", target_l ); strcpy(lower, fmted); sprintf(fmted, "%.15g", target_u ); strcpy(upper, fmted); } } else { strcpy(lower, "0.0"); strcpy(upper, "0.0"); result = 1;} break; } } } return (result); } /* Algorithms : check ALL units first */ /* sig figs second */ /* numerical, string comparisons last */ /* result from capa_check_ans() could be */ /* New check answers routine checks the /AND and /OR group of answers */ /* use array of char pointers char **a */ int capa_check_answers(p,answers,cnt,error) Problem_t *p; char **answers; int cnt; char **error; { AnswerInfo_t *ai; int ii, done, result; int *outcomes; char **errormsg; errormsg=(char**)capa_malloc(cnt,sizeof(char*)); if(p->ans_op == ANS_AND) { /* ans /and ans */ if( (cnt != p->ans_cnt) ) { return (ANS_CNT_NOT_MATCH); } if( cnt == 1 ) { return (capa_check_answer(p, answers[0], error)); } /* there is only one answer */ outcomes = (int *)capa_malloc(sizeof(int),cnt); for(ii=0;iianswer,answers[0],outcomes[0]); #endif for(ii=1, ai = p->ans_list; ai; ii++,ai = ai->ans_next ) { outcomes[ii] = capa_check_ans(ai,answers[ii],&(errormsg[ii])); #ifdef COMMON_DBUG printf("CAPA_CHECK_ANS(%s,%s): outcome[%d]=%d\n", ai->ans_str,answers[ii],ii,outcomes[ii]); #endif } done = ii = 0; result = 0; while( !done ) { /* check if any of the outcome has failed on units */ if( (check_for_unit_fail(outcomes[ii])) || (outcomes[ii] == NO_UNIT) || (outcomes[ii] == UNIT_NOTNEEDED) ) { result = outcomes[ii]; if (result != NO_UNIT) { *error=strsave(errormsg[ii]); } done = 1; } ii++; if(ii==cnt) done = 1; } if( result == 0 ) { /* check if any of the outcome has failed to be a numeric or was a malformed equation */ done = ii = 0; while( !done ) { if( outcomes[ii] == WANTED_NUMERIC || outcomes[ii] == BAD_FORMULA ) { result = outcomes[ii]; done = 1; } ii++; if(ii==cnt) done = 1; } } if( result == 0 ) {/*check if any of the outcome has failed on sig figs*/ done = ii = 0; while( !done ) { if( outcomes[ii] == SIG_FAIL ) { result = outcomes[ii]; *error = strsave(errormsg[ii]); done = 1; } ii++; if(ii==cnt) done = 1; } } if( result == 0 ) { /* check if any of the outcome is incorrect */ done = ii = 0; while( !done ) { if( outcomes[ii] == INCORRECT ) { result = outcomes[ii]; done = 1; } ii++; if(ii==cnt) done = 1; } } for (ii=0;iians_cnt == 1 ) { return (capa_check_answer(p, answers[0], error)); } result = capa_check_answer(p, answers[0], error); ii = 1; ai = p->ans_list; while( (iians_cnt) && ( (result != EXACT_ANS) && (result != APPROX_ANS) ) ) { if((ii!=1)&&((check_for_unit_fail(result))||(result==SIG_FAIL)||(result==UNIT_NOTNEEDED))) { capa_mfree((char*)error); } result = capa_check_ans(ai,answers[0],error); ai = ai->ans_next; ii++; } } return (result); } /* ========================================================================= */ int w_getclassdir(cpath_p, cown_p, class) char **cpath_p; char **cown_p; char *class; { FILE *fp; char filename[SMALL_LINE_BUFFER]; char *cname_p; int done; char c; sprintf(filename,"class.conf"); if ((fp=fopen(filename,"r"))==NULL) { sprintf(filename,"../class.conf"); if ((fp=fopen(filename,"r"))==NULL) { printf("Error: can't open %s\n",filename); exit (1); } } do { c_ignorewhite(fp); c = getc(fp); ungetc(c,fp); if( c != EOF ) { cname_p = c_getword(fp); *cpath_p = c_getword(fp); *cown_p = c_getword(fp); throwaway_line(fp); if( ! strcasecmp(cname_p, class) ) { done = 1; } else { free(cname_p); free(*cpath_p); free(*cown_p); done = 0; } } else { done = 1; } } while ( ! done ); fclose(fp); free(cname_p); return (1); } /* ----------------------------------------------------------------- */ /* read_capa_config gets a value out of the capa.config file in the read resultant string all " are removed expect for \" occurances" in fact all case of \ then another character become just the last character inputs : key_word - a string that is searched for on the lefthand side of an equals sign outputs : value - a char pointer that the value of the key_word as defined in the config file is copied into return : -1 - unable to find or acces the capa.config file 0 - the requested keyword was not found >0 - length of the string that was returned in value */ /* ----------------------------------------------------------------- */ int read_capa_config(key_word,value) char *key_word;char *value; { FILE *fp; char filename[SMALL_LINE_BUFFER]; char left[MAX_BUFFER_SIZE],right[MAX_BUFFER_SIZE],c; int failed=0,done=0,num=0,result=-1,found=0,returnVal=0,i,j; sprintf(filename,"capa.config"); if ((fp=fopen(filename,"r"))==NULL) { return (-1); } do { num = fscanf(fp,"%[^ \n\t#] = %[^\n]",left,right); if (num == 2) { result = strcasecmp(left,key_word); } if (result==0) { done=1; } if (num==EOF) { failed=1; } if (num!=2) { found=0; while(1) { c=fgetc(fp); if (found) { if (c!='\n') { ungetc(c,fp); break; } } if (c=='\n') found=1; if (((char)c)==((char)EOF)) {failed=1;break;} } } } while (!done && !failed); fclose(fp); if (done) { trim_response_ws(right); /*get rid of leading and trailing spaces*/ for(i=0,j=0;i<(strlen(right)+1);i++) { value[j]='\0'; if (right[i] == '\\' && (i < (strlen(right))) ) { i++;value[j]=right[i];j++; } else if (right[i] != '\"' ) { value[j]=right[i];j++; } } value[j]='\0'; returnVal=j; } return returnVal; } int capa_access(const char *pathname, int mode) { pid_t euid,egid; struct stat status; euid=geteuid(); egid=getegid(); if ( -1 == stat(pathname,&status) ) { return -1; } /*printf("mode:%x F_OK:%x mode&F_OK:%x\n",mode,F_OK,(mode&F_OK));*/ /*printf("st_mode:%x S_IFMT:%x st_mode&S_IFMT:%x\n", status.st_mode,S_IFMT,(status.st_mode&S_IFMT));*/ if (!(status.st_mode & S_IFMT)) { return -1; } /*printf("euid: %d\t egid: %d\tstatus.st_uid: %d\tstatus.st_gid: %d\n", euid,egid,status.st_uid,status.st_gid);*/ /*printf("mode:%x R_OK:%x mode&R_OK:%x\n",mode,R_OK,(mode&R_OK));*/ /*printf("mode:%x W_OK:%x mode&W_OK:%x\n",mode,R_OK,(mode&R_OK));*/ /*printf("mode:%x X_OK:%x mode&X_OK:%x\n",mode,R_OK,(mode&R_OK));*/ if (euid==status.st_uid) { /*printf("here1\n");*/ if ((mode & R_OK) && (!(status.st_mode & S_IRUSR))) { return -1; } if ((mode & W_OK) && (!(status.st_mode & S_IWUSR))) { return -1; } if ((mode & X_OK) && (!(status.st_mode & S_IXUSR))) { return -1; } } else { if (egid==status.st_gid) { /*printf("here2\n");*/ if ((mode & R_OK) && (!(status.st_mode & S_IRGRP))) { return -1; } if ((mode & W_OK) && (!(status.st_mode & S_IWGRP))) { return -1; } if ((mode & X_OK) && (!(status.st_mode & S_IXGRP))) { return -1; } } else { /*printf("here3\n");*/ if ((mode & R_OK) && (!(status.st_mode & S_IROTH))) { return -1; } if ((mode & W_OK) && (!(status.st_mode & S_IWOTH))) { return -1; } if ((mode & X_OK) && (!(status.st_mode & S_IXOTH))) { return -1; } } } return 0; } /*checks if the string is all whitespace*/ /*returns 0 if it isn't */ /*returns 1 if it is */ int is_all_ws(char* answer) { int length,result=1,i; if (answer!=NULL) { length=strlen(answer); for(i=0;i=0;j--) if (!(isspace(temp[j]))) break; temp[++j]='\0'; strcpy(answer,&temp[i]); } void throwaway_line(FILE* fp) { int c; do { c = getc(fp); } while ( (c != '\n') && (c != EOF) ); } char* capa_get_seat(char* studentnum,char* seatfile) { FILE* fp; T_student student; char *result,*defaultseatfile="seatingchart"; char line[TMP_LINE_LENGTH],*lineend; int stuline=0,seatline=0; stuline = capa_get_student(studentnum,&student); if (stuline < 1 ) goto error; if (seatfile == NULL) seatfile=defaultseatfile; if ((fp=fopen(seatfile,"r"))==NULL) goto error; while( (stuline>seatline) && (fgets(line,TMP_LINE_LENGTH-1,fp)) ) seatline++; if (seatline< stuline) goto error; if ((lineend=index(line,' '))!=NULL) lineend='\0'; result=capa_malloc(strlen(line)+1,1); strcpy(result,line); return result; error: result= capa_malloc(8,1); sprintf(result,"No Seat"); return result; } void protect_log_string(char* log_string) { int i,len=strlen(log_string); for(i=0;i|===================== End of capaCommon.c =====================|<||= */