Annotation of loncom/homework/CAPA-converter/capaCommon.c, revision 1.11

1.10      albertel    1: /* The LearningOnline Network with CAPA
                      2:  * Helaper functions for capa convertor. 
1.11    ! albertel    3:  * $Id: capaCommon.c,v 1.10 2001/12/04 15:17:57 albertel Exp $
1.10      albertel    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: 
1.1       albertel   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: {
1.3       albertel  141:   int   errcode,temp;
1.1       albertel  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; }*/
1.3       albertel  182:   if (!(temp=yylex())) { errcode = Lexi_qnum; } else { errcode = 0; }
1.9       albertel  183:   fprintf(stderr,"\nExited on: %d\n",temp);
                    184:   fprintf(stderr,"Current cache: %d\n",current_cache);
                    185:   fprintf(stderr,"Flushing:\n"); 
1.3       albertel  186:   flush_delayed();
1.1       albertel  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: 
1.3       albertel  198: int dyn_maxlen=1000000;
                    199: int delay;
1.9       albertel  200: void dyn_init(struct dyn_string *dyn)
1.3       albertel  201: {
1.9       albertel  202:     dyn->len=0;
                    203:     dyn->max=0;
                    204:     dyn->str=NULL;
1.3       albertel  205: }
                    206: 
1.9       albertel  207: void dyn_free(struct dyn_string* dyn)
1.3       albertel  208: {
1.9       albertel  209:     if (dyn->str) {
                    210:       free(dyn->str);dyn->str=NULL;
                    211:       dyn->len=0;
                    212:       dyn->max=0;
                    213:     }
1.3       albertel  214: }
                    215: 
1.9       albertel  216: 
1.3       albertel  217: int append_message(struct dyn_string *dyn_msg,char *format,va_list ap) {
                    218:     char *new;
                    219:     int len,result;
                    220: 
1.9       albertel  221:     if ((result=vasprintf(&new,format,ap))==-1) {
                    222:       fprintf(stderr,"vaspintf didn't like :%s:",format);
                    223:       exit(1);
                    224:     }
1.3       albertel  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: 
1.4       albertel  268: void add_delayed(char *format, ...) {
1.3       albertel  269:     va_list ap;
                    270: 
                    271:     va_start(ap,format);
                    272:     append_message(&dyn_delayed,format,ap);
1.9       albertel  273:     if (do_cache[current_cache]) {
                    274:       append_message(&cached_data[current_cache],format,ap);
                    275:     }	
                    276: }
1.3       albertel  277: 
                    278: void flush_delayed()
                    279: {
                    280:   delay=0;
1.9       albertel  281:   if (dyn_delayed.str) { send(dyn_delayed.str); }
                    282:   dyn_free(&dyn_delayed);dyn_init(&dyn_delayed);
1.3       albertel  283: }
                    284: 
1.9       albertel  285: 
1.11    ! albertel  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)
1.1       albertel  298: {
1.3       albertel  299:   if (delay) {
                    300:     append_message(&dyn_delayed,text,ap);
                    301:   } else {
1.11    ! albertel  302:     if (num_streams[which_dest]) {
1.9       albertel  303:       if (which == ALL_STREAMS) {
                    304: 	int i;
1.11    ! albertel  305: 	for (i=0;i<num_streams[which_dest];i++) { append_message(&streams[which_dest][i],text,ap); }
1.9       albertel  306:       } else {
1.11    ! albertel  307: 	append_message(&streams[which_dest][which],text,ap);
1.9       albertel  308:       }
                    309:     } else {
                    310:       vprintf(text,ap);
                    311:     }
1.3       albertel  312:   }
1.9       albertel  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);
1.11    ! albertel  322:   send_to(current_dest,ALL_STREAMS,text,ap);
1.2       albertel  323: }
                    324: 
1.9       albertel  325: void send_stream(int which, char *text,...)
                    326: {
                    327:   va_list ap;
                    328:   va_start(ap,text);
1.11    ! albertel  329:   send_to(current_dest,which,text,ap);
1.9       albertel  330: }
                    331: 
1.11    ! albertel  332: int num_streams[MAX_DEST];
        !           333: struct dyn_string streams[MAX_DEST][MAX_STREAMS];
        !           334: void start_streams(int which_dest, int num) {
1.9       albertel  335:   int i;
1.11    ! albertel  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;
1.9       albertel  341: }
                    342: 
1.11    ! albertel  343: void end_streams(int which_dest, int which) {
1.9       albertel  344:   int i;
1.11    ! albertel  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;
1.9       albertel  364: }
                    365: 
1.11    ! albertel  366: int mode[MAX_DEST][MAX_STREAMS];
        !           367: int watch_mode[MAX_DEST][MAX_STREAMS];
        !           368: int beg_mode[MAX_DEST][MAX_STREAMS];
1.3       albertel  369: void end_mode()
1.2       albertel  370: {
1.11    ! albertel  371:   end_mode_stream(current_dest, ALL_STREAMS);
1.9       albertel  372: }
                    373: 
1.11    ! albertel  374: void end_mode_stream(int which_dest, int which)
1.9       albertel  375: {
1.11    ! albertel  376:   if (num_streams[which_dest]) {
1.9       albertel  377:     if (which == ALL_STREAMS) {
                    378:       int i;
1.11    ! albertel  379:       for (i=0;i<num_streams[which_dest];i++) { end_mode_stream(which_dest,i); }
1.9       albertel  380:       return;
                    381:     }
                    382:   } else {
                    383:     which=0;/* if streams aren't active make sure which is correct */
                    384:   }
1.11    ! albertel  385:   switch (mode[which_dest][which]) {
1.9       albertel  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;
1.3       albertel  392:   case MODE_NONE: break;
                    393:   }
1.11    ! albertel  394:   mode[which_dest][which]=MODE_NONE;
        !           395:   watch_mode[which_dest][which]=0;
1.2       albertel  396: }
                    397: 
1.3       albertel  398: void start_mode(int newmode,char* args)
1.2       albertel  399: {
1.11    ! albertel  400:   start_mode_stream(current_dest,ALL_STREAMS,newmode,args);
1.9       albertel  401: }
                    402: 
1.11    ! albertel  403: void start_mode_stream(int which_dest,int which,int newmode,char* args)
1.9       albertel  404: {
1.11    ! albertel  405:   if (num_streams[which_dest]) {
1.9       albertel  406:     if (which == ALL_STREAMS) {
                    407:       int i;
1.11    ! albertel  408:       for (i=0;i<num_streams[which_dest];i++) { start_mode_stream(which_dest,i,newmode,args); }
1.9       albertel  409:       return;
                    410:     } else {
1.11    ! albertel  411:       if (newmode == mode[which_dest][which]) return;
1.9       albertel  412:     }
                    413:   } else {
1.11    ! albertel  414:     if (newmode == mode[which_dest][0]) return;
1.9       albertel  415:     which=0;/* if streams aren't active make sure which is correct */
                    416:   }
1.11    ! albertel  417:   end_mode_stream(which_dest,which);
1.3       albertel  418:   switch (newmode) {
1.9       albertel  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;
1.3       albertel  425:   case MODE_NONE: break;
                    426:   }
1.11    ! albertel  427:   mode[which_dest][which]=newmode;
1.9       albertel  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:   }
1.1       albertel  458: }
                    459: /* =||>|===================== End of capaCommon.c =====================|<||= */
                    460: 

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