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 (22 years, 4 months 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_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>