/* 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 <ctype.h>
#if defined(__sun) || defined(linux) || defined(__alpha) || defined(hpux) || defined(AIX) || defined(IRIX)
#include <unistd.h> /* lockf() */
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "capaParser.h"
#include "capaToken.h"
#include "capaCommon.h"
#include "ranlib.h"
/*----------------------------------------------------------*/
/* flock() in SUN is in BSD compatibility lib */
/* #include <sys/file.h> */
/*----------------------------------------------------------*/
int yyparse();
extern FILE *yyin;
extern void yyrestart();
/*----------------------------------------------------------*/
/* 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;i<entry->e_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;ii<nq;ii++) { /* Initialize answer string and tries string */
ans_p[ii] = '-'; tries_p[3*ii] = ' '; tries_p[3*ii + 1] = '0';
if(ii < nq-1) tries_p[3*ii + 2] = ',';
}
entry->answers = 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<nq;ii++) {
ans_p[ii] = '-'; tries_p[3*ii] = ' '; tries_p[3*ii + 1] = '0';
if(ii < nq-1) tries_p[3*ii + 2] = ',';
}
ans_p[nq]='\0';tries_p[3*(nq)+2]='\0';tries_p[3*length-1]=',';
}
}
return (offset);
}
/*----------------------------------------------------------*/
/* Constants defining the column number for each fields */
/* in classl file */
/*----------------------------------------------------------*/
#define SECTION_BEGIN_COLUMN 10
#define SN_BEGIN_COLUMN 14
#define NAME_BEGIN_COLUMN 24
#define EMAIL_BEGIN_COLUMN 60
#define CAPAID_BEGIN_COLUMN 100
/*----------------------------------------------------------*/
/* 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 the */
/* order in classl */
/* 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_get_section(student_pp, section)
T_student **student_pp;
int section;
{
FILE *fp;
char line[SMALL_LINE_BUFFER],fmtbuf[SMALL_LINE_BUFFER], *cp;
int i, line_len;
int tmp_sec, student_cnt, tmp_capaid;
T_student *s1_p, *s2_p, *s3_p;
if ((fp=fopen("classl","r"))==NULL) {
/*printf("Error: Can't open classlist file\n");*/
return (-1);
}
student_cnt = 0; s1_p = s2_p = s3_p = (T_student *)NULL;
while (fgets(line,SMALL_LINE_BUFFER-1,fp)) {
line_len = strlen(line);
if(line_len > 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;i<MAX_NAME_CHAR;i++) s3_p->s_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;i<MAX_EMAIL_CHAR;i++) s3_p->s_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<probs_cnt;ii++) {
set_valids += (a_header.weight[ii] - '0');
}
set_scores = -1;
*answers_pp = a_record.answers;
capa_mfree(a_record.tries); a_record.tries = NULL;
} else {
for(set_scores=0,ii=0, never_login=1;ii<probs_cnt;ii++) {
switch(a_record.answers[ii]) {
case 'Y': case 'y': never_login = 0;
set_scores += (a_header.weight[ii] - '0');
set_valids += (a_header.weight[ii] - '0'); break;
case '-': case 'N': case 'n':
set_valids += (a_header.weight[ii] - '0'); break;
case 'E': case 'e': break;
default : if( a_record.answers[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;i<MAX_SECTION_COUNT;i++) cnt_arry[i]=0;
max = 0;
while ( fgets(line,TMP_LINE_LENGTH-1,fp) && (strlen(line) != 0) ) {
sec_num=0;
sscanf(line+SECTION_BEGIN_COLUMN,"%d", &sec_num);
if( sec_num != 0 ) {
max = MAX(sec_num,max);
cnt_arry[sec_num]++;
}
}
fclose(fp);
cnt = 0;
for(i=1; i <= max; i++) {
if(cnt_arry[i]) cnt++;
}
cnt_arry[0] = max;
return (cnt);
}
/*----------------------------------------------------------*/
/* lookup student information from classl file by */
/* student number */
/*----------------------------------------------------------*/
/* INPUT: student_number char array of student 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 */
/* >0 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;i<MAX_EMAIL_CHAR;i++) student_p->s_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;i<MAX_EMAIL_CHAR;i++) student_p->s_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;
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);
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<MAX_STUDENT_NUMBER;i++) {
if(islower(student_number[i])) {
tmpSN[i] = toupper(student_number[i]);
} else {
tmpSN[i] = student_number[i];
}
}
tmpSN[MAX_STUDENT_NUMBER] = 0;
if( big_endian ) { /* big endian ** SUN, BlackNeXT 68xxx , PowerPC */
for(i=0;i<4;i++) dest[i] = tmpSN[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[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<i; j++) {
if (current == all_pins[j]) {
current=1000+ignlgi()%9000;
nope++;
}
}
} while (nope);
all_pins[i]=current;
if (guess && guess==current) correct=i;
}
gscgn(SET_GENERATOR, &orig_gen);
if (guess) return (correct);
return (current);
}
/* -------------------------------------------------------------------- */
/* returns a longer pin, the first four characters are the same as the */
/* normal capaId, additionally the result is a capa_malloc string */
/* containing the number */
/* NOTE!-> 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;i<MAX_PIN_CHAR+plus;i++) {
rout = ignlgi()%10;
result[i] = letters[rout];
}
result[i] = '\0';
gscgn(SET_GENERATOR, &orig_gen);
return result;
}
/* -------------------------------------------------------------------- */
/* need to set problem_p = NULL after this call */
/* -------------------------------------------------------------------- */
void
free_problems(problem_p) Problem_t *problem_p;
{
Problem_t *p, *next;
for (p=problem_p; p!=NULL ; p=next) {
next=p->next;
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<leng;ii++) {
if( !isdigit(an_int[ii]) ) result = 1;
}
return (result);
}
/* --------------------------- */
/* 0 OK , 1 NOT a real number */
int
check_real( a_real ) char *a_real;
{
int ii, leng;
int result=0;
if( (a_real[0] == '-') || (a_real[0]== '+') ) a_real++;
leng = strlen(a_real);
for(ii=0;ii<leng;ii++) {
if( (!isdigit(a_real[ii])) && (a_real[ii]!='e') && (a_real[ii]!='E') &&
(a_real[ii]!='.') && (a_real[ii]!='+') && (a_real[ii]!='-') ) result = 1;
}
return (result);
}
int
check_input_usymb(u_symb)char *u_symb;
{
int result=0;
return (result);
}
/* <== This routine determine emperically where to split a character */
/* string into two portions, one for numerical answer and the */
/* other for units */
/* ----------------------------------------------------------------- */
/* inputs : buf : answer string */
/* outputs: num : the numerical part */
/* num_p : the numerical part in string */
/* unit_p : the unit string */
/* num_p is used to calculate sig figs */
/* return : 0 empty string */
/* 1 number without units */
/* 2 empty number with units */
/* 3 number with units */
/* */
int split_num_unit(buf,num,num_p,unit_p)
char *buf;double *num; char *num_p; char *unit_p;
{
char num_str[ANSWER_STRING_LENG], unit_str[ANSWER_STRING_LENG];
char base_str[ANSWER_STRING_LENG], exp_str[ANSWER_STRING_LENG];
int idx=0, errcode=0;
int len, ii, n_idx=0, b_idx=0, e_idx=0, u_idx=0;
double n_part, x_part, b_part, e_part, result;
unit_str[0]=0; /* initialize unit_str[] */
len = strlen(buf);
while( isspace(buf[idx]) ) { idx++; } /* ignore white spaces */
num_str[n_idx]=0; /* initialize number string */
if( buf[idx] == '+' || buf[idx] == '-' ) {
/* the first char is either '+' or '-' */
num_str[n_idx++]= buf[idx++];
}
/* skip over alphabet char and those that are not '.' */
while( (!isdigit( buf[idx] )) && buf[idx] != '.' ) { idx++; }
while( isdigit( buf[idx] ) || buf[idx] == '.' ) { /* collect decimal numbers */
num_str[n_idx++]= buf[idx++];
}
num_str[n_idx] = 0; /* end the string with a '\0' */
sprintf(num_p,"%s",num_str); /* put the collected numerical string in num_p */
/* skip over white spaces */
while( isspace(buf[idx]) ) { idx++; }
if( buf[idx] == 'e' || buf[idx] == 'E' ) { /* optional e or E part */
/* peek further one char to see if it belongs to one of the following */
if( buf[idx+1] == '-' || buf[idx+1] == '+' || isspace(buf[idx+1]) || isdigit(buf[idx+1])) {
num_str[n_idx++] = buf[idx++]; /* should be 'e' or 'E' */
while( isspace(buf[idx]) ) { idx++; } /* skip over spaces */
num_str[n_idx++] = buf[idx++]; /* the second char '-', '+' or digit */
while( isdigit(buf[idx]) ) { /* only integer is allowed, not '.' */
num_str[n_idx++] = buf[idx++];
}
}
num_str[n_idx] = 0; /* terminiate the numerical string */
while( isspace(buf[idx]) ) { idx++; }
sscanf(num_str, "%lg", &result); /* put the numerical value into a double variable */
errcode = errcode | 1;
} else if( buf[idx] == 'x' || buf[idx] == 'X') { /* optional x or X part */
idx++; /* skip x or X */
while( isspace(buf[idx]) ) { idx++; }
e_part = 1.0; /* default power */
base_str[b_idx] = 0; /* initialize base_str[] */
while( isdigit(buf[idx]) || buf[idx] == '.' ) { /* should start with a digit or . */
base_str[b_idx++] = buf[idx++];
}
base_str[b_idx] = 0; /* terminate base_str[] */
while( isspace(buf[idx]) ) { idx++; } /* skip over white spaces */
if( buf[idx] == '^' ) { /* power */
idx++;
exp_str[e_idx] = 0; /* initialize exp_str[] */
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; /* initialize exp_str[], again */
while( isdigit(buf[idx]) || buf[idx] == '.' || buf[idx] == '+' || buf[idx] == '-' ) {
exp_str[e_idx++] = buf[idx++];
}
exp_str[e_idx] = 0; /* terminate exp_str[] */
}
while( isspace(buf[idx]) ) { idx++; }
if( buf[idx] == '}' || buf[idx] == ')' ) {
idx++;
}
sscanf(exp_str, "%lg", &e_part);
}
if( strlen(base_str) > 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);
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] $%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 $%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,"<PRE>\n%s\n</PRE>",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,"<PRE>\n%s\n</PRE>",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 */
}
/* ------------------------------ 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, result = INCORRECT;
int sig, corr_len;
int choice[ANSWER_STRING_LENG];
char num_str[ANSWER_STRING_LENG], unit_str[ANSWER_STRING_LENG];
char fmted[ANSWER_STRING_LENG], correct[ANSWER_STRING_LENG], 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<input_len;idx++) {
if( isdigit(ans[idx]) ) {
all_alphabet = 0;
}
}
if( !all_alphabet ) { /* answer string is not all alphabets */
outcome = split_num_unit(ans,&n_part,num_str,unit_str);
if( outcome > 1 ) { /* with both num and unit parts or only unit part */
if( u_p != NULL ) {
if (UNIT_FAIL == (result = check_correct_unit(unit_str,u_p,&scale))) {
*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) && (result != UNIT_FAIL) && ( 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;idx<ANSWER_STRING_LENG;idx++) choice[idx] = 0;
result = EXACT_ANS;
for(ii=0;ii<corr_len; ii++) {
idx = toupper(correct[ii]) - 'A'; choice[idx] = 1;
}
for(ii=0;ii<input_len;ii++) {
idx = toupper(answer[ii]) - 'A';
if(choice[idx] != 1 ) result = INCORRECT;
}
} else { result = INCORRECT; }
break;
}
case ANSWER_IS_STRING_CI:
if (strcasecmp(ans, s)) { result = INCORRECT; } else { result = EXACT_ANS; }
break;
case ANSWER_IS_STRING_CS:
if (strcmp(ans, s)) { result = INCORRECT; } else { result = EXACT_ANS; }
break;
case ANSWER_IS_FORMULA:
result = check_formula_ans(s,ans,ai->ans_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[ANSWER_STRING_LENG], ii, idx, corr_len, input_len;
int result = INCORRECT, sig, outcome, 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<input_len;idx++) {
if( isdigit(answer[idx]) ) {
all_alphabet = 0;
}
}
if( !all_alphabet ) {
outcome = split_num_unit(answer,&n_part,input,unit_str);
if( outcome > 1 ) { /* with both num and unit parts or only unit part */
if( p->ans_unit != NULL ) {
if ( UNIT_FAIL == ( result = check_correct_unit(unit_str,p->ans_unit,&scale) ) ) {
*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) && (result != UNIT_FAIL) && ( 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(ii=0;ii<ANSWER_STRING_LENG;ii++) choice[ii] = 0; result = EXACT_ANS;
for(ii=0;ii<corr_len; ii++) {
idx = toupper(correct[ii]) - 'A'; choice[idx] = 1;
}
for(ii=0;ii<input_len;ii++) {
idx = toupper(answer[ii]) - 'A';
if(choice[idx] != 1 ) result = INCORRECT;
}
} else { result = INCORRECT; }
break;
}
case ANSWER_IS_STRING_CI:
if (strcasecmp(answer, correct)) { result = INCORRECT; } else { result = EXACT_ANS; }
break;
case ANSWER_IS_STRING_CS:
if (strcmp(answer, correct)) { result = INCORRECT; } else { result = EXACT_ANS; }
break;
case ANSWER_IS_FORMULA:
result = check_formula_ans(correct,answer,p->id_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 */
break;
}
return (result);
}
/* ----------------------------------------------------------------------------------- */
/* 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, diff;
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;
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 ) {
if( tol_type == TOL_ABSOLUTE ) {
diff = tol - formula_val;
if( diff < 0.0 ) {
outcome = INCORRECT;
}
} else {
diff = abs(1.0 - formula_val) * 100.0 ;
if( diff < tol ) {
outcome = INCORRECT;
}
}
} else {
outcome = BAD_FORMULA;
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;ii<cnt;ii++) outcomes[ii]=0; /* initialize the outcomes array */
outcomes[0] = capa_check_answer(p, answers[0], &errormsg[0]);
for(ii=1, ai = p->ans_list; ai; ii++,ai = ai->ans_next ) {
outcomes[ii] = capa_check_ans(ai,answers[ii],&(errormsg[ii]));
}
done = ii = 0;
result = 0;
while( !done ) { /* check if any of the outcome has failed on units */
if( (outcomes[ii] == UNIT_FAIL) ||
(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 */
done = ii = 0;
while( !done ) {
if( outcomes[ii] == WANTED_NUMERIC ) {
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;ii<cnt;ii++) {
if( (outcomes[ii] == UNIT_FAIL) ||
(outcomes[ii] == SIG_FAIL) ||
(outcomes[ii] == UNIT_NOTNEEDED) ) {
capa_mfree(errormsg[ii]);
}
}
capa_mfree((char *)errormsg);
capa_mfree((char *)outcomes);
if( result == 0 ) {
result = APPROX_ANS; /* all answers are correct */
}
} else { /* should be ANS_OR , user answer count should always be 1 */
if( cnt != 1 ) { return (ANS_CNT_NOT_MATCH); }
if( p->ans_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( (ii<p->ans_cnt) && ( (result != EXACT_ANS) && (result != APPROX_ANS) ) ) {
if((ii!=1)&&((result==UNIT_FAIL)||(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)) 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<length;i++) {
if (!isspace(answer[i])) {result=0;break;}
}
}
return result;
}
void trim_response_ws(char* answer)
{
char *temp;
int i,j=0,length;
length=strlen(answer);
temp=capa_malloc(length+1,1);
strcpy(temp,answer);
for(i=0; i<length;i++) if (!(isspace(temp[i]))) break;
for(j=length-1;j>=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<len;i++) {
switch (log_string[i]) {
case '\n': case '\t': case '\r':
log_string[i]=' ';
break;
}
}
}
int capa_get_login_time(char *student_number,int set,time_t *logintime)
{
FILE *fp;
int found,temp=0;
char filename[FILE_NAME_LENGTH],line[SMALL_LINE_BUFFER];
*logintime=0;
sprintf(filename,"records/access%d.log",set);
if ((fp=fopen(filename,"r"))==NULL) return (-1);
found = 0;
while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) {
if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1;
}
fclose(fp);
if (found) sscanf(rindex(line,':'),":%d",&temp);
*logintime=(time_t)temp;
return found;
}
/*----------------------------------------------------------*/
/* INPUT: set the X in logX.db */
/* OUTPUT: creates the accessX.log file if it doesn't exist */
/* and inserts stunum:time(NULL) if stunum isn't */
/* in ther already. */
/* */
/* RETURN: -1 file error */
/* 0 already set */
/* 1 succesfully logged a login time */
/*----------------------------------------------------------*/
int capa_set_login_time(char *student_number,int set)
{
FILE *fp;
int errcode=0;
int found=0;
char filename[FILE_NAME_LENGTH],line[SMALL_LINE_BUFFER];
sprintf(filename,"records/access%d.log",set);
if ((fp=fopen(filename,"r"))!=NULL) {
while( (!found) && ( fgets(line,SMALL_LINE_BUFFER-1,fp) != NULL) ) {
if( !strncasecmp(line,student_number,MAX_STUDENT_NUMBER) ) found = 1;
}
fclose(fp);
}
if (found) return 0;
sprintf(line,"%s:%d\n", student_number,(int)time(NULL));
if ((fp=fopen(filename,"a+"))==NULL) return (-1);
flockstream(fp);
fseek(fp,0L,SEEK_END);
if ( !fwrite((char *)line, strlen(line), 1, fp) ) {
errcode = -1;
} else {
errcode = 1;
}
fflush(fp);
funlockstream(fp);
fclose(fp);
return (errcode);
}
/* =||>|===================== End of capaCommon.c =====================|<||= */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>