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, 5 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.)

    1: /* The LearningOnline Network with CAPA
    2:  * Helaper functions for capa convertor. 
    3:  * $Id: capaCommon.c,v 1.11 2001/12/05 18:58:21 albertel Exp $
    4:  *
    5:  * Copyright Michigan State University Board of Trustees
    6:  *
    7:  * This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    8:  *
    9:  * LON-CAPA is free software; you can redistribute it and/or modify
   10:  * it under the terms of the GNU General Public License as published by
   11:  * the Free Software Foundation; either version 2 of the License, or
   12:  * (at your option) any later version.
   13:  *
   14:  * LON-CAPA is distributed in the hope that it will be useful,
   15:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   16:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17:  * GNU General Public License for more details.
   18:  *
   19:  * You should have received a copy of the GNU General Public License
   20:  * along with LON-CAPA; if not, write to the Free Software
   21:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22:  *
   23:  * /home/httpd/html/adm/gpl.txt
   24:  *
   25:  * http://www.lon-capa.org/
   26:  */
   27: 
   28: /* =||>|===================== capaCommon.c =====================|<||= */
   29: /* created 1994 by Isaac Tsai                                         */
   30: /* 1994, 1995, 1996, 1997, 1998, 1999  copyrighted by Isaac Tsai      */
   31: /* TODO: restructure capa_check_ans*() calls into one                 */
   32: /* =||>|===================== capaCommon.c =====================|<||= */
   33: #include <ctype.h>
   34: #if defined(__sun) || defined(linux) || defined(__alpha) || defined(hpux) || defined(AIX) || defined(IRIX) 
   35: #include <unistd.h>  /* lockf() */
   36: #endif
   37: #include <sys/types.h>
   38: #include <sys/stat.h>
   39: #include <fcntl.h>
   40: #include "capaParser.h"
   41: #include "capaToken.h"
   42: #include "capaCommon.h"
   43: #include "ranlib.h"
   44: 
   45: 
   46: /*----------------------------------------------------------*/
   47: /*  flock() in SUN is in BSD compatibility lib              */
   48: /*  #include <sys/file.h>                                   */
   49: /*----------------------------------------------------------*/
   50: char        Parse_class[QUARTER_K];
   51: int         Parse_set;
   52: int         Parse_section; 
   53: char        Parse_student_number[MAX_STUDENT_NUMBER+1];
   54: char        Parse_name[MAX_NAME_CHAR+1];
   55: long        capaid_plus_gen;
   56: int         managermode;
   57:  
   58: int     yyparse();
   59: int     yylex();
   60: extern  FILE *yyin;
   61: extern  void yyrestart();
   62: 
   63: 
   64: /*----------------------------------------------------------*/
   65: /*  Lock file shared                                        */
   66: /*  lock the file specified by file stream pointer sp       */
   67: /*----------------------------------------------------------*/
   68: int
   69: flockstream_sh(sp) FILE *sp;
   70: {
   71:   int fd;
   72:   
   73:   fd = fileno(sp);
   74:   
   75: #if defined(__sun) || defined(hpux) || defined(AIX)
   76:   return ( lockf(fd,F_LOCK, 0L) );
   77: #else
   78:   return (flock(fd,LOCK_SH));
   79: #endif
   80: }
   81: /*----------------------------------------------------------*/
   82: int
   83: flockstream(sp) FILE *sp;
   84: {
   85:   int fd;
   86:   
   87:   fd = fileno(sp);
   88:   
   89: #if defined(__sun) || defined(hpux) || defined(AIX)
   90:   return ( lockf(fd,F_LOCK, 0L) );
   91: #else
   92:   return (flock(fd,LOCK_EX));
   93: #endif
   94: }
   95: /*----------------------------------------------------------*/
   96: int
   97: funlockstream(sp) FILE *sp;
   98: {
   99:   int fd;
  100:   
  101:   fd = fileno(sp);
  102:   
  103: #if defined(__sun) || defined(hpux) || defined(AIX)
  104:   return ( lockf(fd,F_ULOCK, 0L) );
  105: #else
  106:   return ( flock(fd,LOCK_UN) );
  107: #endif
  108: }
  109: 
  110: int
  111: inquery_a_lock(sp,cmd,type,offset,whence,len)
  112: FILE *sp;int cmd;off_t offset;int whence;off_t len;
  113: {
  114:   struct flock lock;
  115:   int    fd;
  116:   lock.l_type   = type;   lock.l_start = offset;
  117:   lock.l_whence = whence; lock.l_len   = len;
  118:   fd=fileno(sp);
  119:   return (fcntl(fd,cmd,&lock));
  120: }
  121: #define  Blocked_Write_Lock(sp) \
  122:           inquery_a_lock(sp,F_SETLK,F_WRLCK,0,0,0)
  123: 
  124: #define  Blocked_Write_Lock(sp) \
  125:           inquery_a_lock(sp,F_SETLK,F_WRLCK,0,0,0)
  126: 
  127: #define  Un_Lock(sp) \
  128:           inquery_a_lock(sp,F_SETLK,F_UNLCK,0,0,0)
  129: 
  130:          
  131: 
  132: 
  133: /******************************************************************************/
  134: /* PARSE SOURCE FILE AND RETURN BLOCKS OF TEXT, unlike capa_parse_student     */
  135: /******************************************************************************/
  136: int  
  137: capa_parse(set,problem,filename,num_questions,func_ptr)
  138: int  set;Problem_t **problem;char *filename;int  *num_questions;
  139: void (*func_ptr)();
  140: {
  141:   int   errcode,temp;
  142: extern  FILE      *Input_stream[MAX_OPENED_FILE];
  143: extern  char       Opened_filename[MAX_OPENED_FILE][QUARTER_K];
  144: extern  int        Lexi_line;
  145: extern  int        Lexi_qnum;
  146: extern  Problem_t *FirstProblem_p;
  147: extern  Problem_t *LastProblem_p;
  148: extern  Problem_t *LexiProblem_p;
  149: extern  char      *StartText_p;
  150: extern  char      *EndText_p;
  151: extern  char      *ErrorMsg_p;
  152: extern  int        ErrorMsg_count;
  153: extern  int        Symb_count;
  154: extern  int        first_run;
  155: extern  void       (*Status_Func)();
  156:   char             warn_msg[WARN_MSG_LENGTH];
  157:   
  158:   if(ErrorMsg_p) { capa_mfree(ErrorMsg_p); ErrorMsg_p = NULL; }
  159:   if(EndText_p)  { capa_mfree(EndText_p);  EndText_p  = NULL; }
  160:   if(StartText_p)  { capa_mfree(StartText_p);  StartText_p  = NULL; }
  161:   ErrorMsg_p = NULL; first_run = 1; EndText_p = NULL;
  162:   Symb_count = ErrorMsg_count = Lexi_line = Lexi_qnum = 0;
  163:   FirstProblem_p = LastProblem_p = NULL;
  164:   LexiProblem_p = (Problem_t *)capa_malloc(sizeof(Problem_t),1);
  165:   Status_Func=func_ptr;
  166: 
  167: #ifdef AVOIDYYINPUT
  168:   yyin=fopen(filename,"r");
  169: #else
  170:  if ( (Input_stream[0]=fopen(filename,"r")) == NULL) {
  171:      /* printf("Error: can't open %s\n",filename);*/
  172:      sprintf(warn_msg,"capa_parse(): CANNOT OPEN FILE\"%s\", file does not exist or is not readable.\n", filename);
  173:      capa_msg(MESSAGE_ERROR,warn_msg);
  174:      return (-1);
  175:   }
  176: #endif
  177:   sprintf(Opened_filename[0],"%s",filename);
  178:   
  179:   /*yyrestart(yyin);*/
  180:   begin_text();
  181:   /*if ( !yyparse() )  { errcode = Lexi_qnum; } else { errcode = 0; }*/
  182:   if (!(temp=yylex())) { errcode = Lexi_qnum; } else { errcode = 0; }
  183:   fprintf(stderr,"\nExited on: %d\n",temp);
  184:   fprintf(stderr,"Current cache: %d\n",current_cache);
  185:   fprintf(stderr,"Flushing:\n"); 
  186:   flush_delayed();
  187:   /* fclose(Input_stream[0]);*/ /*The Lexer handles closing this*/
  188:   /* print_symb_stat(); */
  189:   /*
  190:   capa_mfree((char *)LexiProblem_p);
  191:   LexiProblem_p = NULL;
  192:   */
  193:  (*problem) = FirstProblem_p;
  194:  (*num_questions) = Lexi_qnum;
  195:   return (errcode);
  196: }
  197: 
  198: int dyn_maxlen=1000000;
  199: int delay;
  200: void dyn_init(struct dyn_string *dyn)
  201: {
  202:     dyn->len=0;
  203:     dyn->max=0;
  204:     dyn->str=NULL;
  205: }
  206: 
  207: void dyn_free(struct dyn_string* dyn)
  208: {
  209:     if (dyn->str) {
  210:       free(dyn->str);dyn->str=NULL;
  211:       dyn->len=0;
  212:       dyn->max=0;
  213:     }
  214: }
  215: 
  216: 
  217: int append_message(struct dyn_string *dyn_msg,char *format,va_list ap) {
  218:     char *new;
  219:     int len,result;
  220: 
  221:     if ((result=vasprintf(&new,format,ap))==-1) {
  222:       fprintf(stderr,"vaspintf didn't like :%s:",format);
  223:       exit(1);
  224:     }
  225:     len=strlen(new);
  226: 
  227: #ifdef DYN_DEBUG
  228:     fprintf(stderr,"before: len %d; gcount %d; max %d\n",
  229: 	    len,dyn_msg->len,dyn_msg->max);
  230: #endif /* DYN_DEBUG */
  231: 
  232:     if (dyn_msg->len+len < dyn_maxlen) {
  233: 	if (dyn_msg->len+len>dyn_msg->max-2) {
  234: 	    dyn_msg->max=(dyn_msg->len+len)*2;
  235: 	    if (dyn_msg->max>dyn_maxlen) { dyn_msg->max=dyn_maxlen; }
  236: 	    if (dyn_msg->max != 0) {
  237: 	      dyn_msg->str=realloc(dyn_msg->str,dyn_msg->max);
  238: 	    } else {
  239: 	      return 1;
  240: 	    }
  241: 	    dyn_msg->str[dyn_msg->len]='\0';
  242: 	}
  243: 	strcat(dyn_msg->str,new);
  244: 	dyn_msg->len+=len;
  245:     } else {
  246: 	if (dyn_msg->max != dyn_maxlen-1) { /*already maxed out or can 
  247: 					       we fit this one in?*/
  248: 	    dyn_msg->max=dyn_maxlen;
  249: 	    dyn_msg->str=realloc(dyn_msg->str,dyn_msg->max);
  250: 	    dyn_msg->str[dyn_msg->len]='\0';
  251: 	    strncat(dyn_msg->str,new,dyn_msg->max-dyn_msg->len-1);
  252: 	    dyn_msg->len=strlen(dyn_msg->str);
  253: 	}
  254:     }
  255:     free(new);
  256: 
  257: #ifdef DYN_DEBUG
  258:     fprintf(stderr,"after: len %d; gcount %d; max %d; strlen(dyn_msg): %d\n",
  259: 	    len,dyn_msg->len,dyn_msg->max,strlen(dyn_msg->str));
  260: #endif /* DYN_DEBUG */
  261: 
  262:     return 1;
  263: }
  264: 
  265: void start_delayed(){ delay=1; }
  266: void end_delayed(){ delay=0; }
  267: 
  268: void add_delayed(char *format, ...) {
  269:     va_list ap;
  270: 
  271:     va_start(ap,format);
  272:     append_message(&dyn_delayed,format,ap);
  273:     if (do_cache[current_cache]) {
  274:       append_message(&cached_data[current_cache],format,ap);
  275:     }	
  276: }
  277: 
  278: void flush_delayed()
  279: {
  280:   delay=0;
  281:   if (dyn_delayed.str) { send(dyn_delayed.str); }
  282:   dyn_free(&dyn_delayed);dyn_init(&dyn_delayed);
  283: }
  284: 
  285: 
  286: int current_dest=DEFAULT_DEST;
  287: void change_destination(int which_dest)
  288: {
  289:   if (which_dest < MAX_DEST) {
  290:     current_dest = which_dest;
  291:   } else {
  292:     fprintf(stderr,"Tried to set destination above MAX_DEST: %d", which_dest);
  293:     exit(1);
  294:   } 
  295: }
  296:  
  297: void send_to(int which_dest, int which, char *text, va_list ap)
  298: {
  299:   if (delay) {
  300:     append_message(&dyn_delayed,text,ap);
  301:   } else {
  302:     if (num_streams[which_dest]) {
  303:       if (which == ALL_STREAMS) {
  304: 	int i;
  305: 	for (i=0;i<num_streams[which_dest];i++) { append_message(&streams[which_dest][i],text,ap); }
  306:       } else {
  307: 	append_message(&streams[which_dest][which],text,ap);
  308:       }
  309:     } else {
  310:       vprintf(text,ap);
  311:     }
  312:   }
  313:   if (do_cache[current_cache]) {
  314:     append_message(&cached_data[current_cache],text,ap);
  315:   }	
  316: }
  317: 
  318: void send(char *text,...)
  319: {
  320:   va_list ap;
  321:   va_start(ap,text);
  322:   send_to(current_dest,ALL_STREAMS,text,ap);
  323: }
  324: 
  325: void send_stream(int which, char *text,...)
  326: {
  327:   va_list ap;
  328:   va_start(ap,text);
  329:   send_to(current_dest,which,text,ap);
  330: }
  331: 
  332: int num_streams[MAX_DEST];
  333: struct dyn_string streams[MAX_DEST][MAX_STREAMS];
  334: void start_streams(int which_dest, int num) {
  335:   int i;
  336:   for(i=0; i<num; i++) { dyn_init(&streams[which_dest][i]); }
  337:   for(i=1; i<num; i++) { beg_mode[which_dest][i]=mode[current_dest][0];
  338:                          mode[which_dest][i]=mode[current_dest][0]; }
  339:   num_streams[which_dest]=num;
  340:   current_dest = which_dest;
  341: }
  342: 
  343: void end_streams(int which_dest, int which) {
  344:   int i;
  345:   start_mode(beg_mode[which_dest][which],NULL);
  346:   fputs(streams[which_dest][which].str,stdout);
  347:   for(i=0; i<num_streams[which_dest]; i++) { dyn_free(&streams[which_dest][which]); }
  348:   num_streams[which_dest]=0;
  349:   mode[DEFAULT_DEST][0]=mode[which_dest][which];
  350:   start_mode(mode[DEFAULT_DEST][0],NULL);
  351: }
  352: 
  353: int is_dest_empty(int which_dest) {
  354:   int i,empty=1;
  355: 
  356:   if ( num_streams[which_dest] ) {
  357:     for(i=0; i<num_streams[which_dest]; i++) {
  358:       if (streams[which_dest][i].str != NULL) { empty=0; break; }
  359:     }
  360:   } else {
  361:     if (streams[which_dest][0].str != NULL) { empty=0; }
  362:   }
  363:   return empty;
  364: }
  365: 
  366: int mode[MAX_DEST][MAX_STREAMS];
  367: int watch_mode[MAX_DEST][MAX_STREAMS];
  368: int beg_mode[MAX_DEST][MAX_STREAMS];
  369: void end_mode()
  370: {
  371:   end_mode_stream(current_dest, ALL_STREAMS);
  372: }
  373: 
  374: void end_mode_stream(int which_dest, int which)
  375: {
  376:   if (num_streams[which_dest]) {
  377:     if (which == ALL_STREAMS) {
  378:       int i;
  379:       for (i=0;i<num_streams[which_dest];i++) { end_mode_stream(which_dest,i); }
  380:       return;
  381:     }
  382:   } else {
  383:     which=0;/* if streams aren't active make sure which is correct */
  384:   }
  385:   switch (mode[which_dest][which]) {
  386:   case MODE_COMMENT: send_stream(which,"</comment>\n"); break;
  387:   case MODE_BLOCK: send_stream(which,"</block>\n"); break;
  388:   case MODE_SCRIPT: send_stream(which,"</script>\n"); break;
  389:   case MODE_OUTTEXT: send_stream(which,"<endouttext />\n"); break;
  390:   case MODE_ANSWER: send_stream(which,"\n"); break;
  391:   case MODE_IMPORT: send_stream(which,"</import>\n"); break;
  392:   case MODE_NONE: break;
  393:   }
  394:   mode[which_dest][which]=MODE_NONE;
  395:   watch_mode[which_dest][which]=0;
  396: }
  397: 
  398: void start_mode(int newmode,char* args)
  399: {
  400:   start_mode_stream(current_dest,ALL_STREAMS,newmode,args);
  401: }
  402: 
  403: void start_mode_stream(int which_dest,int which,int newmode,char* args)
  404: {
  405:   if (num_streams[which_dest]) {
  406:     if (which == ALL_STREAMS) {
  407:       int i;
  408:       for (i=0;i<num_streams[which_dest];i++) { start_mode_stream(which_dest,i,newmode,args); }
  409:       return;
  410:     } else {
  411:       if (newmode == mode[which_dest][which]) return;
  412:     }
  413:   } else {
  414:     if (newmode == mode[which_dest][0]) return;
  415:     which=0;/* if streams aren't active make sure which is correct */
  416:   }
  417:   end_mode_stream(which_dest,which);
  418:   switch (newmode) {
  419:   case MODE_COMMENT: send_stream(which,"<comment>\n"); break;
  420:   case MODE_BLOCK: send_stream(which,"<block %s>\n",args); break;
  421:   case MODE_SCRIPT: send_stream(which,"<script type=\"loncapa/perl\">\n"); break;
  422:   case MODE_OUTTEXT: send_stream(which,"<startouttext />\n"); break;
  423:   case MODE_ANSWER: send_stream(which,"\n"); break;
  424:   case MODE_IMPORT: send_stream(which,"<import>"); break;
  425:   case MODE_NONE: break;
  426:   }
  427:   mode[which_dest][which]=newmode;
  428: }
  429: 
  430: int current_cache=-1;
  431: int do_cache[MAX_CACHE];
  432: struct dyn_string cached_data[MAX_CACHE];
  433: 
  434: void new_cache()
  435: {
  436:   current_cache++;
  437:   do_cache[current_cache]=1;
  438:   if (current_cache>MAX_CACHE) { exit(CACHE_ERROR); }
  439:   dyn_init(&cached_data[current_cache]);
  440: }
  441: 
  442: void start_cache() 
  443: {
  444:   do_cache[current_cache]=1;
  445: }
  446: 
  447: void stop_cache()
  448: {
  449:   do_cache[current_cache]=0;
  450: }
  451: 
  452: void delete_cache()
  453: {
  454:   if (current_cache > -1) {
  455:     dyn_free(&cached_data[current_cache]);
  456:     current_cache--;
  457:   }
  458: }
  459: /* =||>|===================== End of capaCommon.c =====================|<||= */
  460: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>