File:
[LON-CAPA] /
loncom /
homework /
CAPA-converter /
capaCommon.c
Revision
1.11:
download - view:
text,
annotated -
select for diffs
Wed Dec 5 18:58:21 2001 UTC (23 years ago) by
albertel
Branches:
MAIN
CVS tags:
version_2_9_X,
version_2_9_99_0,
version_2_9_1,
version_2_9_0,
version_2_8_X,
version_2_8_99_1,
version_2_8_99_0,
version_2_8_2,
version_2_8_1,
version_2_8_0,
version_2_7_X,
version_2_7_99_1,
version_2_7_99_0,
version_2_7_1,
version_2_7_0,
version_2_6_X,
version_2_6_99_1,
version_2_6_99_0,
version_2_6_3,
version_2_6_2,
version_2_6_1,
version_2_6_0,
version_2_5_X,
version_2_5_99_1,
version_2_5_99_0,
version_2_5_2,
version_2_5_1,
version_2_5_0,
version_2_4_X,
version_2_4_99_0,
version_2_4_2,
version_2_4_1,
version_2_4_0,
version_2_3_X,
version_2_3_99_0,
version_2_3_2,
version_2_3_1,
version_2_3_0,
version_2_2_X,
version_2_2_99_1,
version_2_2_99_0,
version_2_2_2,
version_2_2_1,
version_2_2_0,
version_2_1_X,
version_2_1_99_3,
version_2_1_99_2,
version_2_1_99_1,
version_2_1_99_0,
version_2_1_3,
version_2_1_2,
version_2_1_1,
version_2_1_0,
version_2_12_X,
version_2_11_X,
version_2_11_5_msu,
version_2_11_5,
version_2_11_4_uiuc,
version_2_11_4_msu,
version_2_11_4,
version_2_11_3_uiuc,
version_2_11_3_msu,
version_2_11_3,
version_2_11_2_uiuc,
version_2_11_2_msu,
version_2_11_2_educog,
version_2_11_2,
version_2_11_1,
version_2_11_0_RC3,
version_2_11_0_RC2,
version_2_11_0_RC1,
version_2_11_0,
version_2_10_X,
version_2_10_1,
version_2_10_0_RC2,
version_2_10_0_RC1,
version_2_10_0,
version_2_0_X,
version_2_0_99_1,
version_2_0_2,
version_2_0_1,
version_2_0_0,
version_1_99_3,
version_1_99_2,
version_1_99_1_tmcc,
version_1_99_1,
version_1_99_0_tmcc,
version_1_99_0,
version_1_3_X,
version_1_3_3,
version_1_3_2,
version_1_3_1,
version_1_3_0,
version_1_2_X,
version_1_2_99_1,
version_1_2_99_0,
version_1_2_1,
version_1_2_0,
version_1_1_X,
version_1_1_99_5,
version_1_1_99_4,
version_1_1_99_3,
version_1_1_99_2,
version_1_1_99_1,
version_1_1_99_0,
version_1_1_3,
version_1_1_2,
version_1_1_1,
version_1_1_0,
version_1_0_99_3,
version_1_0_99_2,
version_1_0_99_1,
version_1_0_99,
version_1_0_3,
version_1_0_2,
version_1_0_1,
version_1_0_0,
version_0_99_5,
version_0_99_4,
version_0_99_3,
version_0_99_2,
version_0_99_1,
version_0_99_0,
version_0_6_2,
version_0_6,
version_0_5_1,
version_0_5,
version_0_4,
stable_2002_spring,
stable_2002_july,
stable_2002_april,
stable_2001_fall,
loncapaMITrelate_1,
language_hyphenation_merge,
language_hyphenation,
conference_2003,
bz6209-base,
bz6209,
bz5969,
bz2851,
STABLE,
PRINT_INCOMPLETE_base,
PRINT_INCOMPLETE,
HEAD,
GCI_3,
GCI_2,
GCI_1,
BZ5971-printing-apage,
BZ5434-fox,
BZ4492-merge,
BZ4492-feature_horizontal_radioresponse,
BZ4492-feature_Support_horizontal_radioresponse,
BZ4492-Support_horizontal_radioresponse
- added multiple "destinations", to do large scale rearrangement of problem chunks. (Notably Hints and explanations now appear in the correct location.)
/* The LearningOnline Network with CAPA
* Helaper functions for capa convertor.
* $Id: capaCommon.c,v 1.11 2001/12/05 18:58:21 albertel Exp $
*
* Copyright Michigan State University Board of Trustees
*
* This file is part of the LearningOnline Network with CAPA (LON-CAPA).
*
* LON-CAPA 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.
*
* LON-CAPA 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 LON-CAPA; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* /home/httpd/html/adm/gpl.txt
*
* http://www.lon-capa.org/
*/
/* =||>|===================== capaCommon.c =====================|<||= */
/* created 1994 by Isaac Tsai */
/* 1994, 1995, 1996, 1997, 1998, 1999 copyrighted 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> */
/*----------------------------------------------------------*/
char Parse_class[QUARTER_K];
int Parse_set;
int Parse_section;
char Parse_student_number[MAX_STUDENT_NUMBER+1];
char Parse_name[MAX_NAME_CHAR+1];
long capaid_plus_gen;
int managermode;
int yyparse();
int yylex();
extern FILE *yyin;
extern void yyrestart();
/*----------------------------------------------------------*/
/* 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)
/******************************************************************************/
/* PARSE SOURCE FILE AND RETURN BLOCKS OF TEXT, unlike capa_parse_student */
/******************************************************************************/
int
capa_parse(set,problem,filename,num_questions,func_ptr)
int set;Problem_t **problem;char *filename;int *num_questions;
void (*func_ptr)();
{
int errcode,temp;
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 int Symb_count;
extern int first_run;
extern void (*Status_Func)();
char warn_msg[WARN_MSG_LENGTH];
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;
Symb_count = ErrorMsg_count = Lexi_line = Lexi_qnum = 0;
FirstProblem_p = LastProblem_p = NULL;
LexiProblem_p = (Problem_t *)capa_malloc(sizeof(Problem_t),1);
Status_Func=func_ptr;
#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);
/*yyrestart(yyin);*/
begin_text();
/*if ( !yyparse() ) { errcode = Lexi_qnum; } else { errcode = 0; }*/
if (!(temp=yylex())) { errcode = Lexi_qnum; } else { errcode = 0; }
fprintf(stderr,"\nExited on: %d\n",temp);
fprintf(stderr,"Current cache: %d\n",current_cache);
fprintf(stderr,"Flushing:\n");
flush_delayed();
/* fclose(Input_stream[0]);*/ /*The Lexer handles closing this*/
/* print_symb_stat(); */
/*
capa_mfree((char *)LexiProblem_p);
LexiProblem_p = NULL;
*/
(*problem) = FirstProblem_p;
(*num_questions) = Lexi_qnum;
return (errcode);
}
int dyn_maxlen=1000000;
int delay;
void dyn_init(struct dyn_string *dyn)
{
dyn->len=0;
dyn->max=0;
dyn->str=NULL;
}
void dyn_free(struct dyn_string* dyn)
{
if (dyn->str) {
free(dyn->str);dyn->str=NULL;
dyn->len=0;
dyn->max=0;
}
}
int append_message(struct dyn_string *dyn_msg,char *format,va_list ap) {
char *new;
int len,result;
if ((result=vasprintf(&new,format,ap))==-1) {
fprintf(stderr,"vaspintf didn't like :%s:",format);
exit(1);
}
len=strlen(new);
#ifdef DYN_DEBUG
fprintf(stderr,"before: len %d; gcount %d; max %d\n",
len,dyn_msg->len,dyn_msg->max);
#endif /* DYN_DEBUG */
if (dyn_msg->len+len < dyn_maxlen) {
if (dyn_msg->len+len>dyn_msg->max-2) {
dyn_msg->max=(dyn_msg->len+len)*2;
if (dyn_msg->max>dyn_maxlen) { dyn_msg->max=dyn_maxlen; }
if (dyn_msg->max != 0) {
dyn_msg->str=realloc(dyn_msg->str,dyn_msg->max);
} else {
return 1;
}
dyn_msg->str[dyn_msg->len]='\0';
}
strcat(dyn_msg->str,new);
dyn_msg->len+=len;
} else {
if (dyn_msg->max != dyn_maxlen-1) { /*already maxed out or can
we fit this one in?*/
dyn_msg->max=dyn_maxlen;
dyn_msg->str=realloc(dyn_msg->str,dyn_msg->max);
dyn_msg->str[dyn_msg->len]='\0';
strncat(dyn_msg->str,new,dyn_msg->max-dyn_msg->len-1);
dyn_msg->len=strlen(dyn_msg->str);
}
}
free(new);
#ifdef DYN_DEBUG
fprintf(stderr,"after: len %d; gcount %d; max %d; strlen(dyn_msg): %d\n",
len,dyn_msg->len,dyn_msg->max,strlen(dyn_msg->str));
#endif /* DYN_DEBUG */
return 1;
}
void start_delayed(){ delay=1; }
void end_delayed(){ delay=0; }
void add_delayed(char *format, ...) {
va_list ap;
va_start(ap,format);
append_message(&dyn_delayed,format,ap);
if (do_cache[current_cache]) {
append_message(&cached_data[current_cache],format,ap);
}
}
void flush_delayed()
{
delay=0;
if (dyn_delayed.str) { send(dyn_delayed.str); }
dyn_free(&dyn_delayed);dyn_init(&dyn_delayed);
}
int current_dest=DEFAULT_DEST;
void change_destination(int which_dest)
{
if (which_dest < MAX_DEST) {
current_dest = which_dest;
} else {
fprintf(stderr,"Tried to set destination above MAX_DEST: %d", which_dest);
exit(1);
}
}
void send_to(int which_dest, int which, char *text, va_list ap)
{
if (delay) {
append_message(&dyn_delayed,text,ap);
} else {
if (num_streams[which_dest]) {
if (which == ALL_STREAMS) {
int i;
for (i=0;i<num_streams[which_dest];i++) { append_message(&streams[which_dest][i],text,ap); }
} else {
append_message(&streams[which_dest][which],text,ap);
}
} else {
vprintf(text,ap);
}
}
if (do_cache[current_cache]) {
append_message(&cached_data[current_cache],text,ap);
}
}
void send(char *text,...)
{
va_list ap;
va_start(ap,text);
send_to(current_dest,ALL_STREAMS,text,ap);
}
void send_stream(int which, char *text,...)
{
va_list ap;
va_start(ap,text);
send_to(current_dest,which,text,ap);
}
int num_streams[MAX_DEST];
struct dyn_string streams[MAX_DEST][MAX_STREAMS];
void start_streams(int which_dest, int num) {
int i;
for(i=0; i<num; i++) { dyn_init(&streams[which_dest][i]); }
for(i=1; i<num; i++) { beg_mode[which_dest][i]=mode[current_dest][0];
mode[which_dest][i]=mode[current_dest][0]; }
num_streams[which_dest]=num;
current_dest = which_dest;
}
void end_streams(int which_dest, int which) {
int i;
start_mode(beg_mode[which_dest][which],NULL);
fputs(streams[which_dest][which].str,stdout);
for(i=0; i<num_streams[which_dest]; i++) { dyn_free(&streams[which_dest][which]); }
num_streams[which_dest]=0;
mode[DEFAULT_DEST][0]=mode[which_dest][which];
start_mode(mode[DEFAULT_DEST][0],NULL);
}
int is_dest_empty(int which_dest) {
int i,empty=1;
if ( num_streams[which_dest] ) {
for(i=0; i<num_streams[which_dest]; i++) {
if (streams[which_dest][i].str != NULL) { empty=0; break; }
}
} else {
if (streams[which_dest][0].str != NULL) { empty=0; }
}
return empty;
}
int mode[MAX_DEST][MAX_STREAMS];
int watch_mode[MAX_DEST][MAX_STREAMS];
int beg_mode[MAX_DEST][MAX_STREAMS];
void end_mode()
{
end_mode_stream(current_dest, ALL_STREAMS);
}
void end_mode_stream(int which_dest, int which)
{
if (num_streams[which_dest]) {
if (which == ALL_STREAMS) {
int i;
for (i=0;i<num_streams[which_dest];i++) { end_mode_stream(which_dest,i); }
return;
}
} else {
which=0;/* if streams aren't active make sure which is correct */
}
switch (mode[which_dest][which]) {
case MODE_COMMENT: send_stream(which,"</comment>\n"); break;
case MODE_BLOCK: send_stream(which,"</block>\n"); break;
case MODE_SCRIPT: send_stream(which,"</script>\n"); break;
case MODE_OUTTEXT: send_stream(which,"<endouttext />\n"); break;
case MODE_ANSWER: send_stream(which,"\n"); break;
case MODE_IMPORT: send_stream(which,"</import>\n"); break;
case MODE_NONE: break;
}
mode[which_dest][which]=MODE_NONE;
watch_mode[which_dest][which]=0;
}
void start_mode(int newmode,char* args)
{
start_mode_stream(current_dest,ALL_STREAMS,newmode,args);
}
void start_mode_stream(int which_dest,int which,int newmode,char* args)
{
if (num_streams[which_dest]) {
if (which == ALL_STREAMS) {
int i;
for (i=0;i<num_streams[which_dest];i++) { start_mode_stream(which_dest,i,newmode,args); }
return;
} else {
if (newmode == mode[which_dest][which]) return;
}
} else {
if (newmode == mode[which_dest][0]) return;
which=0;/* if streams aren't active make sure which is correct */
}
end_mode_stream(which_dest,which);
switch (newmode) {
case MODE_COMMENT: send_stream(which,"<comment>\n"); break;
case MODE_BLOCK: send_stream(which,"<block %s>\n",args); break;
case MODE_SCRIPT: send_stream(which,"<script type=\"loncapa/perl\">\n"); break;
case MODE_OUTTEXT: send_stream(which,"<startouttext />\n"); break;
case MODE_ANSWER: send_stream(which,"\n"); break;
case MODE_IMPORT: send_stream(which,"<import>"); break;
case MODE_NONE: break;
}
mode[which_dest][which]=newmode;
}
int current_cache=-1;
int do_cache[MAX_CACHE];
struct dyn_string cached_data[MAX_CACHE];
void new_cache()
{
current_cache++;
do_cache[current_cache]=1;
if (current_cache>MAX_CACHE) { exit(CACHE_ERROR); }
dyn_init(&cached_data[current_cache]);
}
void start_cache()
{
do_cache[current_cache]=1;
}
void stop_cache()
{
do_cache[current_cache]=0;
}
void delete_cache()
{
if (current_cache > -1) {
dyn_free(&cached_data[current_cache]);
current_cache--;
}
}
/* =||>|===================== End of capaCommon.c =====================|<||= */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>