File:  [LON-CAPA] / loncom / homework / CAPA-converter / capaCommon.c
Revision 1.9: download - view: text, annotated - select for diffs
Sun Nov 18 09:40:45 2001 UTC (22 years, 7 months ago) by albertel
Branches: MAIN
CVS tags: HEAD
- added a cache data structure
   - new_cache() adds a new cache strutuce and sets that one as the one
     being added to.
   - delete_cache() deletes the last cache and sets the previous one as
     current
   - start_cache() turns on caching for the current cache
   - stop_cache() turns off caching for the current cache
     (Both append_delayed() and send() data are stuck into the current cache)
- added a streams data structure
   - allows multiple versions of the output to be generated simultaneously
   - send() and flush_delayed() by default put all data into all streams
   - send_stream() lets one pick a stream to send data to
   - start_streams() starts off all of the streams requested
   - end_streams() sends the specified stream out, and free()s the rest
   - start_mode_stream end_mode_stream, allows one to change modes on
     specific streams, different streams can be in different modes.
   - the global var watch_mode can be used to check if a stream has
     changed modes, everytime a mode change occurs on a specific stream
     the watch_mode var for that stream gets set to zero.

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

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