/*\c
 * \secb{Declarations for lx2l}
 * Copyright (C) 1995 -- 1998  Michael Plugge (m.plugge@fh-mannheim.de)
 *
 * This file is part of the cvt2ltx package, a package of LaTeX
 * converters. The whole package is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License. See the files
 * config.h and COPYING for further details.
 * 
 * Features included from (complete) lx2l:
 *     macros:                  NO
 *     conditionals:            NO
 *     threads:                 YES
 *     character remapping:     NO
 *     include files:           NO
 *     xinclude files:          NO
 *     configuration files:     NO
 *     date and time:           NO
 *     native VMS CLI:          NO
 *     CVT2LTX specials:        NO
 *     warning if obsolete:     NO
 *     make full/make short:    NO
 *     lxx mode:                NO
 *     debug support:           NO
 */

%{
#define LX_VERSION "1.0.0"
#define BUFSIZE 32768         /* main buffer size */

#if VMS
#  include <unixio.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#if VMS
#  undef ECHO
#  define ECHO (yyleng==1) ? fputc(*yytext,yyout) : fprintf(yyout,"%s",yytext)
#endif

#define NONE  0L
#define ALL   0xffffffffL

   /* WARNING - if you want to increase THREAD_INDEX, RTFS first; you have to modify some rules
    * and also the following conditionals (UNDERLINE, LOCAL_COND*) are changed!!!
    */

#define THREAD_INDEX 10   /* maximum number of indices per thread character */
#define MAX_THREADS  (THREAD_INDEX*26) /* don't change this value!! */

char *ptr,*ptr1,*mptr,*bu_ptr,*cptr,*buffer,thread_group[26+1],lx_only=1;

int i,j,c,warn_def,ret_val,skip_start,init_sc,use_src,target_index,src_index,sc;

long target_mode,src_mode[THREAD_INDEX],line=1;

void print_time(char *format);
char *copy_and_checkmode(char *optr);
int die(char *cmd,int mode);
%}

WS     [ \t\n]
WSO    [ \t\n]*
SP     [ \t]+
SPO    [ \t]*
THREAD (\{!?@@\^?[a-z0-9@()-]*\})|(\{@@@\^[a-z0-9()-]+\})
CONDITION_NAME [A-Z][A-Z0-9$_]*

%x NEGATIVE_CLASS POSITIVE_CLASS SET_ALL_POSITIVE SET_ALL_NEGATIVE

%option 8bit noyywrap never-interactive outfile="lx2l.c"

%%

   for(i=0;i<THREAD_INDEX;i++)src_mode[i]=ALL; /* start of file: enable all threads */
   use_src=1;

"{@@##}"\n{SPO} line++;
"{@@}"    use_src=0; for(i=0;i<THREAD_INDEX;i++)src_mode[i]=NONE;
"{@@@}"   {
      if(target_index==0)
         use_src=1;
      else
         use_src=0;
      src_mode[0]=ALL;
   }
"{@@@@}"  use_src=1; for(i=0;i<THREAD_INDEX;i++)src_mode[i]=ALL; 
"{@@@^"[a-z0-9@()-]+\}   {
      use_src=0;
      strcpy(buffer,yytext);
      sc=YY_START;
      yyless(5);
      for(i=0;i<THREAD_INDEX;i++)src_mode[i]=ALL;
      BEGIN(SET_ALL_NEGATIVE);
   }
\{@@\^?[a-z0-9@()][a-z0-9@()-]*\} {
      use_src=0;
      strcpy(buffer,yytext);
      sc=YY_START;
      if(*(yytext+3)=='^'){
         yyless(4);
         for(i=0;i<THREAD_INDEX;i++)src_mode[i]=ALL;
         BEGIN(NEGATIVE_CLASS);
      }
      else{
         yyless(3);
         for(i=0;i<THREAD_INDEX;i++)src_mode[i]=NONE;
         BEGIN(POSITIVE_CLASS);
      }
   }

<POSITIVE_CLASS>{
 \([a-z]+\)[0-9-]+ {   /* handle {@@a(bcd)345de} */
      for(ptr=yytext+1,i=0;*ptr!=')';)thread_group[i++]= *ptr++-'a';
      thread_group[i]=0;
      for(ptr++;*ptr;ptr++){
         if(*ptr && *(ptr+1)=='-'){
            for(i= *ptr-'0';i<= *(ptr+2)-'0';i++)
               for(ptr1=thread_group;*ptr1;)src_mode[i]|=(1L<<*ptr1++);
            ptr+=2;
         }
         else
            for(ptr1=thread_group;*ptr1;)src_mode[*ptr-'0']|=(1L<<*ptr1++);
      }
 }
 [a-z][0-9-]* {
      c=1L<<(*yytext-'a');
      if(yyleng==1)
         src_mode[0]|=c;
      else{
         for(ptr=yytext+1;*ptr;ptr++)
            if(*(ptr+1)=='-'){
               for(i= *ptr-'0';i<= *(ptr+2)-'0';i++)src_mode[i]|=c;
               ptr+=2;
            }
            else
               src_mode[*ptr-'0']|=c;
      }
   }
 @    BEGIN(SET_ALL_POSITIVE);
}

<NEGATIVE_CLASS>{
 \([a-z]+\)[0-9-]+ {   /* handle {@@^a(bcd)345de} */
      for(ptr=yytext+1,i=0;*ptr!=')';)thread_group[i++]= *ptr++-'a';
      thread_group[i]=0;
      for(ptr++;*ptr;ptr++){
         if(*(ptr+1)=='-'){
            for(i= *ptr-'0';i<= *(ptr+2)-'0';i++)
               for(ptr1=thread_group;*ptr1;)src_mode[i]&=~(1L<<*ptr1++);
            ptr+=2;
         }
         else
            for(ptr1=thread_group;*ptr1;)src_mode[*ptr-'0']&=~(1L<<*ptr1++);
      }
 }
 [a-z][0-9-]* {
      c=~(1L<<(*yytext-'a'));
      if(yyleng==1)
         src_mode[0]&=c;
      else{
         for(ptr=yytext+1;*ptr;ptr++)
            if(*(ptr+1)=='-'){
               for(i= *ptr-'0';i<= *(ptr+2)-'0';i++)src_mode[i]&=c;
               ptr+=2;
            }
            else
               src_mode[*ptr-'0']&=c;
      }
   }
 @    BEGIN(SET_ALL_NEGATIVE);
}

<SET_ALL_POSITIVE>{
 [0-9]\-[0-9] for(i= *yytext-'0';i<= *(yytext+2)-'0';i++)src_mode[i]=ALL;
 [0-9]   src_mode[*yytext-'0']=ALL;
 [a-z]   c=1L<<(*yytext-'a'); for(i=0;i<THREAD_INDEX;i++)src_mode[i]|=c;
}

<SET_ALL_NEGATIVE>{
 [0-9]\-[0-9] for(i= *yytext-'0';i<= *(yytext+2)-'0';i++)src_mode[i]=NONE;
 [0-9]   src_mode[*yytext-'0']=NONE;
 [a-z]   c=~(1L<<(*yytext-'a')); for(i=0;i<THREAD_INDEX;i++)src_mode[i]&=c;
}

<SET_ALL_POSITIVE,SET_ALL_NEGATIVE>[^a-z0-9}] |
<POSITIVE_CLASS,NEGATIVE_CLASS>[^a-z0-9@}] {
      fprintf(stderr,"error: bad thread syntax %s in line %ld; disable output\n",
         buffer,line);
      use_src=0;
      BEGIN(sc);
   }

<POSITIVE_CLASS,NEGATIVE_CLASS,SET_ALL_POSITIVE,SET_ALL_NEGATIVE>\}   {
     if(src_mode[target_index]&target_mode || target_mode==ALL)use_src=1;
     BEGIN(sc);
   }

^{SPO}\n {
      if(use_src)fputc('\n',yyout);
      line++;
      lx_only=1;
   }
\n {
      if(use_src && !lx_only)fputc('\n',yyout);
      line++;
      lx_only=1;
   }

. {
      if(use_src){
         lx_only=0;
         fputc(*yytext,yyout);
      }
   }

%%

int die(char *cmd,int mode)
{
   switch(mode){
      case 1:
         fprintf(stderr,"Can't open %s for read; exit\n",cmd);
         exit(4);
      case 2:
         fprintf(stderr,"Can't open %s for write; exit\n",cmd);
         exit(4);
      case 3:
         fprintf(stderr,"%s\n",cmd);
         exit(4);
      default:
         return 0;
   }
}

int main(int argc,char **argv)
{
#if VMS
   ret_val=1;
#else
   ret_val=0;
#endif
   if(argc<4){
      fprintf(stderr,"missing arguments for lx2l\n\
usage: lx2l <thread> <inputfile> <outputfile>\n");
      exit(4);
   }
   buffer=malloc(512);
   warn_def=1;
   bu_ptr=calloc(BUFSIZE,1);
   target_mode=ALL;
   target_mode=1L<<(*argv[1]-'a');
   if(c= *(argv[1]+1))
      target_index=c-'0';
   else
      target_index=0;
   (yyin=fopen(argv[2],"r")) || die(argv[2],1);
   (yyout=fopen(argv[3],"w")) || die(argv[3],2);
#ifdef FLEX_DEBUG
   if(yy_flex_debug){
      fprintf(stderr,"redirect stderr to file lx2l.dbg\n");
      freopen("lx2l.dbg","w",stderr);
   }
#endif   /* FLEX_DEBUG */
   yylex();
   fclose(yyin);
   fclose(yyout);
   return(ret_val);
}
