/******************************************************************************
 * program:     wp2latex                                                      *
 * function:    convert WordPerfect 3.x 4.x, 5.x or 6.x files into LaTeX      *
 * modul:       pass1.cc                                                      *
 * description: @file This modul is a library of functions that supports all  *
 *              conversion modules that performs  first pass. In the first    *
 *              pass information of the WP binary file will splitted in two   *
 *              parts:                                                        *
 *              1) A text file containing the whole text. The special WP      *
 *                 characters are translated.                                 *
 *              2) A binary file which contains information about             *
 *                 environments, tabbings, line endings                       *
 * licency:     GPL		                                              *
 ******************************************************************************/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include <ctype.h>
#ifdef __UNIX__
 #include <unistd.h>
#endif

#include "sets.h"
#include "stringa.h"
#include "lists.h"

#include "raster.h"
#include "wp2latex.h"
#include "struct.h"
#include "cp_lib/cptran.h"


extern list FontTable,UserLists;
set WP2LaTeXsty;		//This set enumerates all wp2latex.sty features

static const char *Parts[8] = {
 "part", "chapter", "section", "subsection",
 "subsubsection", "paragraph", "subparagraph","" };

#ifndef FINAL
/**This procedure isn't normally called. It can be used for exploration of new objects*/
void CrackObject(TconvertedPass1 *cq, uint32_t end_of_code)
{
FILE *txt;
unsigned short i,y;
long pos;
uint32_t len;
static char ss[13] = "00__Hack.txt";
char c;

  pos = ftell(cq->wpd);

  len = end_of_code - ftell(cq->wpd);

  if (ss[1] > '9')
     {
     ss[1] = '0';
     ss[0]++;
     }

  txt = OpenWrChk(ss,"w",cq->err);
  if(txt == NULL) return;

  fprintf(txt, "Real file pos %lXh (%ld)\n", pos, pos);
  for (i = 0; i <= len; i++)
      {
      fread(&c, 1, 1, cq->wpd);
      y=c & 0xFF;
      fprintf(txt, "%3u %2x ", i, y);
      if (c >= ' ' && c <= 'z')
	  fprintf(txt, " %c", c);
      putc('\n', txt);
      }
  ss[1]++;   /**/

  fclose(txt);
  fseek(cq->wpd, pos, 0);
}
#endif


/**This procedure initialises TBox struct members.*/
void initBox(TBox &Box)
{
  Box.CaptionPos = 0;
  Box.CaptionSize = 0;
  Box.Contents = 0;
  Box.HScale = 1;
  Box.Image_offset = 0;
  Box.Image_size = 0;
  Box.Image_type = 0; 	// Image on disk
  Box.RotAngle = 0;
  Box.Type = 2;		//default is user box
  Box.Width = -1;	// Undefined width is <=0
  Box.VScale = 1;

}

//++++++Procedures for manipulating with ATTR struct+++++++

/* This procedure initialize an attr structure */
void attribute::InitAttr(void)
{
 Math_Depth = Closed_Depth = Opened_Depth = 0;
}



/** Open all attributes and feed result into string.
 * @param[in,out]	a	Attribute list.
 * @param[out]		s	Openning sequence stored in string. */
void Open_All_Attr(attribute & a, string & s)
{
 s.erase();
 while(a.Opened_Depth<a.Closed_Depth)
   {
   const TStyleOpCl *stl = StyleOpCl + a.stack[a.Opened_Depth++];

   if(a.Math_Depth<=0)
       s += stl->Open;
   else
       s += ((stl->MathOpen==NULL)?stl->Open:stl->MathOpen);
     
   if(a.Math_Depth<=0 && *stl->Open=='$')   
       a.Math_Depth = a.Opened_Depth;
   }
}


/** This procedure opens all temporary closed attributes in the attr structure */
void Open_All_Attr(attribute & a, FILE *f)
{
 while(a.Opened_Depth<a.Closed_Depth)
   {   
   const TStyleOpCl *stl = StyleOpCl + a.stack[a.Opened_Depth++];
      
   if(a.Math_Depth<=0)
       fputs(stl->Open, f);
   else
       fputs((stl->MathOpen==NULL)?stl->Open:stl->MathOpen, f);
   
   if(a.Math_Depth<=0 && *stl->Open=='$')   
       a.Math_Depth = a.Opened_Depth;
   }
}


/** Temporarily close all attributes and feed result into the string.
 * @param[in,out]	a	Attribute structure.
 * @param[out]		s	String to receive closing sequence.
 * @param[in]		StartAttr Start position of attributes beeing opened. */
void Close_All_Attr(attribute & a, string & s, unsigned StartAttr)
{
 s.erase();
 while(a.Opened_Depth>StartAttr)
     {
     const TStyleOpCl *stl = StyleOpCl + a.stack[--a.Opened_Depth];     
     if(a.Math_Depth>a.Opened_Depth) a.Math_Depth=0;

     if(a.Math_Depth>0)			// We are in trouble now and the '$' must be stripped.
         s += ((stl->MathClose==NULL)?stl->Close:stl->MathClose); 
     else
         s += stl->Close;
     }
}


/** This procedure temporary closes all attributes in the attr structure.
 * @param[in,out]	a	Attribute structure. */
void Close_All_Attr(attribute & a, FILE *f, unsigned StartAttr)
{
 while(a.Opened_Depth>StartAttr)
     {
     const TStyleOpCl *stl = StyleOpCl + a.stack[--a.Opened_Depth];      
     if(a.Math_Depth>a.Opened_Depth) a.Math_Depth=0;

     if(a.Math_Depth>0)			// We are in trouble now and the '$' must be stripped.
       fputs((stl->MathClose==NULL)?stl->Close:stl->MathClose,f); 
     else
       fputs(stl->Close,f);
     }
}


/** This procedure opens one attribut (lettertype) in the attr structure.
 * @param[in,out]	a	Stack with all attributes opened.
 * @param[in]		Attr	Attribute to be opened anew. */
void AttrOn(attribute & a, char Attr)
{
unsigned i;
			/*Try to find an opened attribute in the stack */
 for(i=0; i<a.Closed_Depth; i++)
   {
   if(a.stack[i]==Attr)
     {
     return;
     }
   }
 if(a.Closed_Depth>MaxAttributes) return;	// attr stack overflow.
 a.stack[a.Closed_Depth++] = Attr;
 
 switch(Attr)
 {
   case Cyr_Font: Cyrillic=true; break;
   case Heb_Font: cjHebrew=true; break;
   case Georgia_Font: mxedruli=true; break;
   case Arabic_Font: arabtex=true; break;
 }

return;
}


/** This function checks whether the given attribute is on. */
int IsAttrOn(const attribute & a, char Attr)
{
unsigned pos;
	/* Try to find a currently closed attribute in the stack */
 pos = a.Closed_Depth;
 while(pos>0)	// better than: "for(pos=a.Closed_Depth-1; pos>=0; pos--)"
 {
   pos--;
   if(a.stack[pos]==Attr) return(pos);
 }

return(-1);
}


/* This procedure closes one attribut (lettertype) in the attr structure.
   It must generate some output to string.   */
void _AttrOff(attribute & a, char Attr, string & s)
{
int pos;

 s.erase();

	/* Try to find a currently closed attribute in the stack */
 pos = a.Closed_Depth;
 while(pos > 0)
   {
   pos--;
   if(a.stack[pos]==Attr)
     {		/* Close all opened attributes above closed & closed one */
     while(a.Opened_Depth>pos)		// a.Opened_Depth is granted here tobe at least 1, because 1>0.
	{
        const TStyleOpCl *stl = StyleOpCl + a.stack[--a.Opened_Depth];        
	if(a.Math_Depth>a.Opened_Depth)
		a.Math_Depth=0;		/*First Math responsible attr is closed*/

        if(a.Math_Depth>0)	// We are in trouble now and the '$' must be stripped.
          s += (stl->MathClose==NULL) ? stl->Close :stl->MathClose;
        else 
          s += stl->Close;
	}
		/* Remove closed attribute from chain of clossed attributes */
     if(a.Closed_Depth>0) a.Closed_Depth--;
     while(pos<a.Closed_Depth)
       {
       a.stack[pos] = a.stack[pos+1];
       pos++;
       }

     return;
     }
   }

 //printf(_("Attribute cannot be closed"));
 return;
}


/**This procedure closes one attribut and write closing sequence into the file cq->strip*/
void AttrOff(TconvertedPass1 *cq, char attr_num)
{
string s;

 _AttrOff(cq->attr,attr_num,s);
 if(!s.isEmpty()) fputs(s(),cq->strip);

 if(attr_num==Heb_Font && cq->Font==FONT_HEBREW)
 {
   cq->Font = FONT_NORMAL;
 }
 if(attr_num==Cyr_Font && cq->Font==FONT_CYRILLIC)
 {
   cq->Font = FONT_NORMAL;
 }
 if(attr_num==Georgia_Font && cq->Font==FONT_GEORGIA)
 {
   cq->Font = FONT_NORMAL;
 }
 if(attr_num==Arabic_Font && cq->Font==FONT_ARABIC)
 {
   cq->Font = FONT_NORMAL;
 }

return;
}


/**This procedure opens an attribute. Opening sequence is delayed and it is not written now.*/
void Attr_ON(TconvertedPass1 *cq, unsigned char b)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Attr_ON(%c) ",b);fflush(cq->log);
#endif

  if(b==0xFF)
     fread(&b, sizeof(unsigned char), 1, cq->wpd);   /* the attribute code */

  b &= 0x7F;			// mask bit 7: nested duplicated attr
  if(b==7) {
	   if ((LaTeX_Version & 0xFF00) < 0x300)  // outline is supported by NFSS only
		{
		strcpy(cq->ObjType, "!Attr Outlin On");
		return;
		}
	   }
  if(b==0xA) {
	     if(colors<0)
		  {
		  strcpy(cq->ObjType, "!Attr Red On");
		  return;
		  }
	     colors=true;
	     }
  if(b==11 || b==13 || b==14)
	   {
	   if(Ulem==0) Ulem=1;
	   }
  if(b<16) AttrOn(cq->attr,b & 0xF);
      else if (cq->err != NULL)
	    {
	    cq->perc.Hide();
	    fprintf(cq->err, _("\nWarning: Strange attribute %d!"),(int)b);
	    }

  sprintf(cq->ObjType, "Attr %d On",(int)b);
}


/** This funcction closes attribute and flushes closing sequence into output stream.
 * @param[in]	b	Attribute number. 0xFF means that attribute is read from input stream. */
void Attr_OFF(TconvertedPass1 *cq, unsigned char b)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Attr_OFF(%c) ",b);fflush(cq->log);
#endif
  string s;

  if(b==0xFF)
     fread(&b, sizeof(unsigned char), 1, cq->wpd);   /* less attribuut-code */
  b &= 0x7F;			// mask bit 7: nested duplicated attr

  if(b==0xA && colors<=0) goto RejectAttr;
  if ((b==7) && ((LaTeX_Version & 0xFF00) < 0x300))  goto RejectAttr;

  _AttrOff(cq->attr,b & 0xF,s);
  if(!s.isEmpty()) fputs(s(),cq->strip);

RejectAttr:
  sprintf(cq->ObjType, "Attr %d Off",(int)b);
}


/** This procedure creates opening&closing sequence of attrs after that Base will have same items as A_new. */
void AttrFit(attribute & Base, const attribute & A_New, string & s)
{
int i,pos;
const char *ch;

 s.erase();

 Base.Closed_Depth=Base.Opened_Depth;
 for(pos=0; pos<Base.Opened_Depth; pos++)
   {
   if(A_New.stack[pos]!=Base.stack[pos] || pos>=A_New.Closed_Depth)
     {  //close all attrs Base[MaxPos] ... Base[Pos]
     while(Base.Opened_Depth>pos)
       {
       const TStyleOpCl *stl = StyleOpCl + Base.stack[--Base.Opened_Depth];       
       if(Base.Math_Depth>Base.Opened_Depth)
		Base.Math_Depth=0;		/*First Math responsible attr is closed*/
       if(Base.Math_Depth>0)	// We are in trouble now and the '$' must be stripped.       
         s + ((stl->MathClose==NULL) ? stl->Close : stl->MathClose);
       else 
         s += stl->Close;
       }		
     Base.Closed_Depth = Base.Opened_Depth;
     break;
     }
   }

 for(i=pos; i<A_New.Closed_Depth; i++)
   {
   AttrOn(Base,A_New.stack[i]);
   }

 Base.Math_Depth=0;			//Compute MathDepth from scratch
 for(i=0; i<Base.Closed_Depth; i++)
   {   
   ch = StyleOpCl[Base.stack[i]].Open;
   if(*ch=='$' && Base.Math_Depth<=0)
     {
     Base.Math_Depth=i+1;
     break;
     }
   }
}


/** Solve attributes for columns in table header.
 * @param[in]	 Attributes	Bit mask containing attributes.
 * @return 	LaTeX string that causes selected attributes to close. */
temp_string Attributes2String(uint32_t Attributes)
{
string TexAttrib;
			//Solve attributes for columns
 if(Attributes &  1) {TexAttrib+="\\LARGE";goto SizeOK;}
 if(Attributes &  2) {TexAttrib+="\\Large";goto SizeOK;}
 if(Attributes &  4) {TexAttrib+="\\large";goto SizeOK;}
 if(Attributes &  8) {TexAttrib+="\\small";goto SizeOK;}
 if(Attributes & 16) TexAttrib+="\\footnotesize";
SizeOK:
    //32 supscript
    //64 subscript
    //128 outline
 if(Attributes & 256)  TexAttrib+="\\it";
 if(Attributes & 1024 && ((LaTeX_Version & 0xFF00) >= 0x300) && (colors>=0))
			{
			TexAttrib+="\\color{red}";
			colors=true;
			}
    //2048 double underline
 if(Attributes & 4096) TexAttrib+="\\bf";
    //8192  strikeout
    //16384 underline
 if(Attributes & 32768)TexAttrib+="\\sc";
    //65536 blink
    //131072 reverse video
return temp_string(TexAttrib);
}


/** This procedure changes a number of columns in document. */
void Column(TconvertedPass1 *cq, signed char number)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Column(%d) ",(int)number);fflush(cq->log);
#endif
int i;
const char b='M';

 if(Columns<0)
	{
	strcpy(cq->ObjType, "!Col");
	return;
	}

			/* Any of section's attr cannot be opened */
 for(i=First_com_section; i<=Last_com_section; i++)
		     AttrOff(cq,i);
 if(cq->char_on_line==CHAR_PRESENT) NewLine(cq);

 if(number>1)
	 {
	 cq->Columns=number;
	 fwrite(&b, 1, 1, cq->table);
	 fwrite(&cq->Columns, 1, 1, cq->table);
	 NewLine(cq);
	 strcpy(cq->ObjType, "Col On");
	 }
 else    {
	 if(cq->Columns<=1) goto NoOneCol;
	 cq->Columns=1;
	 fwrite(&b, 1, 1, cq->table);
	 fwrite(&cq->Columns, 1, 1, cq->table);
	 NewLine(cq);
NoOneCol:strcpy(cq->ObjType, "Col Off");
	 }

 if(Columns<cq->Columns)
    {
    if(Columns==1 && cq->Columns==2) Columns=3;
				else Columns=cq->Columns;
    }
}


/** This procedure finishes indenting. */
void End_of_indent(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#End_of_indent() ");fflush(cq->log);
#endif
  cq->indent_end = true;
  strcpy(cq->ObjType, "End Indent");
}


/**This procedure converts Hard Line Break*/
void HardReturn(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#HardReturn() ");fflush(cq->log);
#endif

 if(cq->envir == 'B')		// Hard return
	{
	Close_All_Attr(cq->attr,cq->strip);
/*	if ((LaTeX_Version & 0xFF00) >= 0x300)
	     fputs(" \\tabularnewline ", cq->strip);
	else */
	     fputs(" \\penalty-10001 ", cq->strip);
        strcpy(cq->ObjType, "!HRt");
	return;
	}
    else Terminate_Line(cq,'h');

  strcpy(cq->ObjType, "HRt");
}


/** This procedure performs conversion of [indent] symbol*/
void Indent(TconvertedPass1 *cq, char WP)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Indent ");fflush(cq->log);
#endif
uint16_t dif, abs;
unsigned char b;

  /* check whether the section is opened */
  for(abs=0; abs<cq->attr.Closed_Depth; abs++)
	{
	if(cq->attr.stack[abs] >= First_com_section &&
	   cq->attr.stack[abs] <= Last_com_section) 
	     {
	     if(cq->err!=NULL && Verbosing>0)
	       {
	       cq->perc.Hide();
	     
	       fprintf(cq->err, _("\nWarning: Don't know how to convert indent inside section."));
	       }
	     goto NoIndent;
	     }
	}
	

	/* check for proper environment for indenting */
  if(cq->envir=='T' || cq->Columns>1)
	{
NoIndent:	
	putc(' ', cq->strip);		//ignore indent
	strcpy(cq->ObjType, "!Indent");
	return;
	}

	/* Al one tabcommand gezet dus er mag geen insp */
  Close_All_Attr(cq->attr,cq->strip);
  putc('\n', cq->strip);

  cq->line_term = 's';     // Soft return
  Make_tableentry_envir_extra_end(cq);

  if(cq->envir=='I') cq->envir='i';
		else cq->envir='I';
  cq->indenting++;

  Make_tableentry_attr(cq);

  b=0;
  switch(WP)
	{
	case 0:abs=cq->tabpos[0]; break;
	case 0x14:fread(&b, 1, 1, cq->wpd);	//obsolette WP4
	       if(b>=TAB_POS_SIZE) b = TAB_POS_SIZE-1;
	       abs = cq->tabpos[b];
	       b = 0;
	       break;
	case 4:RdWORD_HiEnd(&abs, cq->wpd);	// WP4
	       break;
	case 5:fread(&b, 1, 1, cq->wpd);	// WP5
	       b &= 0x1;
	       Rd_word(cq->wpd, &dif);
	       Rd_word(cq->wpd, &abs);   /* Previous old column */
	       Rd_word(cq->wpd, &abs);
	       break;
	case 6:fseek(cq->wpd, 3L, SEEK_CUR);	// WP6
	       Rd_word(cq->wpd, &abs);
	       break;
	}


  if(abs <= cq->WP_sidemargin)
     {
     if(cq->err!=NULL && Verbosing>0)
	{
	cq->perc.Hide();
	fprintf(cq->err, _("\nWarning: Negative indent, fixed!"));
	}
     cq->ind_leftmargin = cq->tabpos[0];
     }
     else  cq->ind_leftmargin = abs - cq->WP_sidemargin;

/*     if (b == 1)
   cq->ind_rightmargin += dif;*/
 /*Margins bepaald less voorby rest van functie-codes */

 strcpy(cq->ObjType, "Indent");
}


/** This procedure converts Line numbering. */
void LineNumbering(TconvertedPass1 *cq, uint8_t LineNumbering)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#LineNumbering() ");fflush(cq->log);
#endif

  if(LineNumbering)
    {
    if(LineNo>=STYLE_NOTUSED) 
      {
      LineNo = STYLE_USED;
      AttrOn(cq->attr,Line_Num);
      }
    }
  else
    AttrOff(cq,Line_Num);

sprintf(cq->ObjType,"%sLine Num:%s", (LineNo>=STYLE_NOTUSED)?"":"!", (LineNumbering&1)?"On":"Off");
}


/**This procedure make fingerprint of all currently opened Attributes to
  the .TAB file. These are from 0 to Opened_Depth-1. */
void Make_tableentry_attr(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Make_tableentry_attr() ");fflush(cq->log);
#endif
unsigned char num_of_attr;
int j;
static const unsigned char TABLE_LINE_DELIMITER = 0xF0;

  fwrite(&TABLE_LINE_DELIMITER, 1, 1, cq->table);
  
  num_of_attr = cq->attr.Opened_Depth;
  fwrite(&num_of_attr, 1, 1, cq->table);
  for(j=0; j<num_of_attr; j++)
      fwrite(&cq->attr.stack[j], 1, 1, cq->table);
}


/** This procedure closes one line in the TAB file and it should be called after each \n in the STR file */
void Make_tableentry_envir_extra_end(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Make_tableentry_envir_extra_end() ");fflush(cq->log);
#endif
unsigned char b;

  switch(cq->envir)
    {
    case 'B': if(LongTable==0) LongTable=1;
              b = 'B';
              fwrite(&b, 1, 1, cq->table);
              break;

    case 'C':
    case 'c': b = 'C';
	      fwrite(&b, 1, 1, cq->table);
	      break;

    case 'L': b = 'L';
              fwrite(&b, 1, 1, cq->table);
              break;

    case 'R': b = 'R';
              fwrite(&b, 1, 1, cq->table);
              break;

/*  case 'q': b = 'q';
	      fwrite(&b, 1, 1, cq->table);
              break;
    case 'Q': b = 'Q';
              fwrite(&b, 1, 1, cq->table);
              break; */

    case 'T': b = 'T';
              fwrite(&b, 1, 1, cq->table);
              break;

    case 't': b = 't';
              fwrite(&b, 1, 1, cq->table);
	      break;

    case 'I':
    case 'i': b = cq->envir;
              fwrite(&b, 1, 1, cq->table);
              Wr_word(cq->table, cq->ind_leftmargin);

              fwrite(&cq->indenting, 1, 1, cq->table);
              break;

    case '!': b = '!';
              fwrite(&b, 1, 1, cq->table);
	      break;
    case '^': b = '^';
              fwrite(&b, 1, 1, cq->table);
              break;
    }

  b = cq->line_term;
  fwrite(&b, sizeof(unsigned char), 1, cq->table);

  b = 0xff;
  fwrite(&b, sizeof(unsigned char), 1, cq->table);
#ifdef DEBUG
  fputc('\n',cq->table);	//make TBL file readable
#endif
}


void Make_tableentry_tabset(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Make_tableentry_tabset() ");fflush(cq->log);
#endif
  unsigned char b = 'S';
  long j, FORLIM;

  fwrite(&b, sizeof(unsigned char), 1, cq->table);

  b = cq->num_of_tabs;
  fwrite(&b, sizeof(unsigned char), 1, cq->table);

  FORLIM = cq->num_of_tabs;
  for(j=0; j<FORLIM; j++)
    Wr_word(cq->table, cq->tabpos[j]);
}


void NewLine(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#NewLine() ");fflush(cq->log);
#endif
  putc('\n', cq->strip);
  cq->line_term = 's';   /* Soft return */
  Make_tableentry_envir_extra_end(cq);
  cq->char_on_line = false;
  cq->nomore_valid_tabs = false;
  cq->rownum++;
  Make_tableentry_attr(cq);
  cq->latex_tabpos = 0;
}


/** This procedure creates n empty lines in the file. */
void NewLines(TconvertedPass1 *cq, int Lines, bool CRFlag)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#NewLines(%d) ",Lines);fflush(cq->log);
#endif

  if(CRFlag) putc('\n', cq->strip);
  cq->line_term = 's'; 			/* Soft return */
  Make_tableentry_envir_extra_end(cq);
  cq->char_on_line = false;
  cq->nomore_valid_tabs = false;
  cq->rownum++;
  Make_tableentry_attr(cq);
  cq->latex_tabpos = 0;
  while(--Lines>0)
    {
    if(CRFlag) putc('\n', cq->strip);
    Make_tableentry_envir_extra_end(cq);
    cq->rownum++;
    Make_tableentry_attr(cq);
    }
}


inline void SkipWP6Packets(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#SkipWP6Packets() ");fflush(cq->log);
#endif
uint8_t flags,PIDs;

 flags=fgetc(cq->wpd);
 if(feof(cq->wpd)) return;
 if(flags & 0x80)
   {
   PIDs = fgetc(cq->wpd);
   fseek(cq->wpd,2*(int)PIDs,SEEK_CUR);
   }
}

//++++++General Purpose procedures for converting files+++++++
//                 alphabetically ordered

void CancelHyph(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#CancelHyph() ");fflush(cq->log);
#endif

  fprintf(cq->strip, "{\\nobreak}");

  strcpy(cq->ObjType, "Cancel Hyph");
}


/** Cell in the table. */
void CellTable(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#CellTable() ");fflush(cq->log);
#endif

  if(cq->envir == 'B')
       {
       if(cq->char_on_line==CHAR_PRESENT || cq->char_on_line==-1)
	 {
	 Close_All_Attr(cq->attr,cq->strip);
	 fprintf(cq->strip, " & ");
	 }
       cq->char_on_line = true;
       }
  else if(cq->char_on_line==CHAR_PRESENT) fputc(' ',cq->strip);

  strcpy(cq->ObjType, "!Cell"+((cq->envir!='B')?0:1));
}


/* This procedure set on the center environment if there is no */
/* currently active environment .                              */
void Center(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Center() ");fflush(cq->log);
#endif

  if(cq->char_on_line == FIRST_CHAR_MINIPAGE)  /* first line of minipages */
	{			/* a new line have to be creared */
	fputs("%\n", cq->strip);
	cq->line_term = 's';   /* Soft return */

	Make_tableentry_envir_extra_end(cq);
	cq->rownum++;

	cq->nomore_valid_tabs = false;
	Make_tableentry_attr(cq);
	cq->char_on_line = NO_CHAR;
	}

  if (cq->envir == ' ')		/* environment = center */
	{
	cq->envir = 'c';	// the small 'c' is turned off on by the EOL
	if(cq->char_on_line != CHAR_PRESENT)
		cq->char_on_line = LEAVE_ONE_EMPTY_LINE;
	}

  strcpy(cq->ObjType, "Center");
}


void CenterPage(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#CenterPage() ");fflush(cq->log);
#endif

  fprintf(cq->strip, "\\strut\\vfil ");
  cq->CentrePage=true;

  strcpy(cq->ObjType, "CenterPg");
}


/** This procedure outputs character string */
void CharacterStr(TconvertedPass1 *cq, const char *LatexCode)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#CharacterStr(%s) ",chk(LatexCode));fflush(cq->log);
#endif
 int DollarNo;

 if(LatexCode==NULL) return;

 cq->char_on_line = true;   /*Some character is placed on line */

 if(cq->Font != cq->RequiredFont)
      {
      switch(cq->RequiredFont)
	 {
	 case FONT_NEUTRAL:break;		//neutral font
	 case FONT_NORMAL:			//normal latin font
	       if(cq->Font==FONT_CYRILLIC)
		 {
		 if(LatexCode && LatexCode[0]!=0 && LatexCode[1]==0)
		   if(*LatexCode == '?' || *LatexCode == '.' || (*LatexCode > ' ' && *LatexCode < ';'))
		     break;
		 AttrOff(cq,Cyr_Font);
		 }
	       if(cq->Font==FONT_HEBREW)
		 {
		 AttrOff(cq,Heb_Font);
		 }
	       if(cq->Font==FONT_GEORGIA)
                 {
		 AttrOff(cq,Georgia_Font);
                 }
               if(cq->Font==FONT_ARABIC)
                 {
		 AttrOff(cq,Arabic_Font);
                 }
	       cq->Font = FONT_NORMAL;
	       fprintf(cq->strip, "\\rm ");
	       break;
         case FONT_ARABIC:
	       AttrOn(cq->attr,Arabic_Font);
	       cq->Font = FONT_ARABIC;
	       break;
	 case FONT_CYRILLIC:		//cyrillic font
	       AttrOn(cq->attr,Cyr_Font);
	       cq->Font = FONT_CYRILLIC;
	       break;
	 case FONT_GEORGIA:		//georgia font
	       AttrOn(cq->attr,Georgia_Font);
	       cq->Font = FONT_GEORGIA;
	       break;
	case FONT_HEBREW:		//hebrew font
               if(cq->envir=='c')		  // This is some problem workaround in LaTex.
		 fprintf(cq->strip, "\\strut ");  // Why latex otherwise cannot center \begin{hebrew} \end{hebrew} block?
	       AttrOn(cq->attr,Heb_Font);
	       cq->Font = FONT_HEBREW;
	       break;
	 default: cq->Font = cq->RequiredFont = FONT_NORMAL; //should not occur
	 }
    }

 if(cq->attr.Closed_Depth!=cq->attr.Opened_Depth)
	{
	Open_All_Attr(cq->attr,cq->strip);
	}

 if(cq->attr.Math_Depth>0)
   {
   DollarNo=0;
   while(*LatexCode!=0)		// Tohle se musi jeste trochu predelat 1.$  a 2.$ !!!!!!!!!!
	   {
	   if(*LatexCode == '\\')
		   {
		   switch(LatexCode[1])
		     {
		     case '\'':fputs("\\acute", cq->strip); break;
		     case '=':fputs("\\bar", cq->strip); break;
		     case 'u':if(isalpha(LatexCode[2])) goto DEFAULT;
			      fputs("\\breve", cq->strip); break;
		     case 'r':if(isalpha(LatexCode[2])) goto DEFAULT;
			      fputs("\\mathring", cq->strip); break;
		     case '.':fputs("\\dot", cq->strip); break;
		     case '`':fputs("\\grave", cq->strip); break;
		     case '^':fputs("\\hat", cq->strip); break;
		     case '~':fputs("\\tilde", cq->strip); break;
		     case '$':fputs("\\$", cq->strip); break;
		     case '\\':fputs("\\\\", cq->strip); break;
		     default:
DEFAULT:		      fputc('\\',cq->strip);
			      goto NextChar;
		     }
		   LatexCode+=2;
		   continue;
		   }
	   if(*LatexCode == '$')	// math around must be removed
	      {
	      if(DollarNo++ & 1) fputs("}{", cq->strip);
			    else fputs("}{\\rm ", cq->strip);
	      }
	   else fputc(*LatexCode, cq->strip);
NextChar:  LatexCode++;
	   }
   }
   else fputs(LatexCode, cq->strip);
}


/**This procedure converts changes of colors of the text.*/
void Color(TconvertedPass1 *cq, signed char WP, RGBQuad *RGB)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Color(%d) ",(int)WP);fflush(cq->log);
#endif
const char *ColorType="?";
uint8_t Red,Green,Blue;

  if(colors<0 || LaTeX_Version<0x300)
	{
	strcpy(cq->ObjType, "!Color");
	return;
	}
  colors=true;

  if(RGB!=NULL)
	{
	Red=RGB->R;
	Green=RGB->G;
	Blue=RGB->B;
	}
  else
    {
    if(WP==3)  //WP3 has [OldR][OldG][OldB][R][G][B] as Hi endian Words
       {
       fseek(cq->wpd, 6l, SEEK_CUR);
       fread(&Red, 1, 1, cq->wpd);
       fseek(cq->wpd, 1l, SEEK_CUR);
       fread(&Green, 1, 1, cq->wpd);
       fseek(cq->wpd, 1l, SEEK_CUR);
       fread(&Blue, 1, 1, cq->wpd);
       }
    else	//WP5 and 6 have <R><G><B>
       {
       fseek(cq->wpd, 3l, SEEK_CUR);
       fread(&Red, 1, 1, cq->wpd);
       fread(&Green, 1, 1, cq->wpd);
       fread(&Blue, 1, 1, cq->wpd);
       //if(WP==7) fread(&Transparency, 1, 1, cq->wpd);	//WP6 marked as 7 has Transparency here
       }
    }

  if(Red==0 && Green==0 && Blue==0) ColorType="black";
  if(Red==0xFF && Green==0xFF && Blue==0xFF) ColorType="white";

  if(Red==0xFF && Green==0 && Blue==0) ColorType="red";
  if(Red==0 && Green==0xFF && Blue==0) ColorType="green";
  if(Red==0 && Green==0 && Blue==0xFF) ColorType="blue";

  if(Red==0xFF && Green==0xFF && Blue==0) ColorType="yellow";
  if(Red==0xFF && Green==0 && Blue==0xFF) ColorType="magenta";
  if(Red==0 && Green==0xFF && Blue==0xFF) ColorType="cyan";

  if(*ColorType!='?')
	fprintf(cq->strip, "\\color{%s}",ColorType);
  else fprintf(cq->strip, "\\color[rgb]{%1.2f,%1.2f,%1.2f}",
	((float)Red)/0xFF,((float)Green)/0xFF,((float)Blue)/0xFF);

  sprintf(cq->ObjType, "Color:%s", ColorType);
}


void DateCode(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#DateCode() ");fflush(cq->log);
#endif

  fprintf(cq->strip, "\\today{}");

  strcpy(cq->ObjType, "Date");
  cq->char_on_line = true;
}


void EndSection(TconvertedPass1 *cq, signed char WP)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#EndSection() ");fflush(cq->log);
#endif
  unsigned char b;
  string s;

  if(WP>0)
    {
    if(WP==6) fseek(cq->wpd, 3L, SEEK_CUR);
    fread(&b, sizeof(unsigned char), 1, cq->wpd);   /* less attribuut-code */
    }
  else b=abs(WP);
  sprintf(cq->ObjType, "End MarkToC %d",(int)b);

  if (b > 0) b -= cq->FirstSection;

  b += OutputStyle;
  if (b > Last_com_section) return;

  if(OptimizeSection && cq->envir!='B') _AttrOff(cq->attr,b,s);
				   else _AttrOff(cq->attr,Last_com_section+1,s);
  if(!s.isEmpty()) fputs(s(),cq->strip);
}


/** This procedure finishes table that is beeing converted. */
void EndTable(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#EndTable() ");fflush(cq->log);
#endif

  if (cq->envir == 'B')
	{
	Close_All_Attr(cq->attr,cq->strip);
	fprintf(cq->strip, " \\\\ \\hline\n");
	}
	else fprintf(cq->strip, " \n");

  cq->line_term = 'h';   /* Hard return */
  Make_tableentry_envir_extra_end(cq);


  strcpy(cq->ObjType, "!End Table"+((cq->envir!='B')?0:1));
  if (cq->envir == 'B')
	{
	cq->envir = ' ';
    /*cq.line_term := 's';
	    writeln(cq.strip^,);
	    Make_tableentry_envir_extra_end(cq);*/
	}
  cq->char_on_line = false;
  cq->nomore_valid_tabs = false;
  cq->rownum++;
  Make_tableentry_attr(cq);
  cq->latex_tabpos = 0;
}


/** This function converts Flush Right command. */
void Flush_right(TconvertedPass1 *cq,char type)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Flush_right(%d) ",(int)type);fflush(cq->log);
#endif

  if(cq->envir == 'T')
      {
      Close_All_Attr(cq->attr,cq->strip);
      fprintf(cq->strip, "\\`");
      Open_All_Attr(cq->attr,cq->strip);

      cq->nomore_valid_tabs = true;

//    cq->envir = 'T';
      }
      else {
	   if(cq->char_on_line!=CHAR_PRESENT) fprintf(cq->strip, "\\strut");
	   cq->char_on_line = true;   /*Something is placed on line */
	   if(type==1) fprintf(cq->strip, "\\dotfill ");
		  else fprintf(cq->strip, "\\hfill ");
	   }

  sprintf(cq->ObjType, "Flsh Rtg%s",type==1?" (dot)":"");
}


void HardHyphen(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#HardHyphen() ");fflush(cq->log);
#endif

 CharacterStr(cq,"-");

 strcpy(cq->ObjType, "- Hyphen");
}


/** This procedure provide conversion of Hard Page code [HPg]. */
void HardPage(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#HardPage() ");fflush(cq->log);
#endif

 if(cq->flag > NormalText)
    {
    if(cq->flag > HeaderText) fputc(' ',cq->strip);
	 else Terminate_Line(cq,'h');  //hard return replaces hard page
    strcpy(cq->ObjType, "!HPg");
    }
 else {
      Terminate_Line(cq,'P');
      strcpy(cq->ObjType, "HPg");
      }
}


void HLine(TconvertedPass1 *cq, signed char WP)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#HLine() ");fflush(cq->log);
#endif
  unsigned char AnchorType,HorizontalPos,VerticalPos,Shading;
  uint16_t Width,Length,Raise,Left;

  switch(WP)
    {
    case 5:
      cq->ActualPos = ftell(cq->wpd);
      fseek(cq->wpd, cq->ActualPos+2L, SEEK_SET);
      fread(&VerticalPos, 1, 1, cq->wpd);
      VerticalPos=(VerticalPos>>2) & 7; /*0-baseline, 4-absolute*/
      fread(&HorizontalPos, 1, 1, cq->wpd);
      HorizontalPos&=7;		        /*0-Left, 1-Right, 2-Center, 3-Full, 4-absolute*/
      Rd_word(cq->wpd,&Length);
      Rd_word(cq->wpd,&Width);
      Rd_word(cq->wpd,&Left);	        /*X-position*/
      Rd_word(cq->wpd,&Raise);		/*Y-position*/
      fseek(cq->wpd, 20L, SEEK_CUR);
      fread(&Shading, 1, 1, cq->wpd);
      break;
    case 6:
      SkipWP6Packets(cq);
      fseek(cq->wpd, 18L, SEEK_CUR);
      fread(&AnchorType, 1, 1, cq->wpd);
      if(AnchorType & 1)
	  {
	  strcpy(cq->ObjType, "!VLine");
	  return;
	  }
      fread(&HorizontalPos, 1, 1, cq->wpd); /*bits 2-4:0-Left, 1-Right, 2-Center, 3-Full */
      HorizontalPos=(HorizontalPos>>2) & 3;
      fseek(cq->wpd, 6L, SEEK_CUR);
      Rd_word(cq->wpd,&Width);
      Rd_word(cq->wpd,&Length);
      AnchorType=0;
      VerticalPos=0;
      Shading=100;
      Left=Raise=0;
      break;
    default:
      Width=-WP;
      if(Width<=0) Width=16;
      HorizontalPos=3;
      AnchorType=0;
      VerticalPos=0;
      Shading=100;
      Left=Raise=0;
      break;
    }

  if(Shading>100) Shading=100;

  WP2LaTeXsty+=sty_xvadjust;
  fprintf(cq->strip,"\\Xvadjust{");
  if(HorizontalPos==1 || HorizontalPos==2) fprintf(cq->strip,"\\hss");
  if(HorizontalPos==4)
	fprintf(cq->strip,"\\kern %2.2fcm",((float)Left-cq->WP_sidemargin)/470);
  fprintf(cq->strip,"\\rule");
/*  if(VerticalPos==4 && Raise!=0)	//sorry I do not know how to set absolute position
	fprintf(cq->strip,"[%2.2fcm]",(float)Raise/470);*/
  if(HorizontalPos==3) fprintf(cq->strip,"{\\textwidth}{%2.2fcm}",(float)Width/470);
		  else fprintf(cq->strip,"{%2.2fcm}{%2.2fcm}",(float)Length/470,(float)Width/470);
  if(HorizontalPos==0 || HorizontalPos==2) fprintf(cq->strip,"\\hss");
  fprintf(cq->strip,"}");

  strcpy(cq->ObjType, "HLine");
}


void Hyphenation(TconvertedPass1 *cq,char state)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Hyphenation() ");fflush(cq->log);
#endif

switch(state)
   {
   case true:fprintf(cq->strip, "\\hyphenpenalty 45 ");
	     strcpy(cq->ObjType, "Hyph On");
	     break;
   case false:fprintf(cq->strip, "\\hyphenpenalty 10000 ");
	      strcpy(cq->ObjType, "Hyph Off");
	      break;
   default:strcpy(cq->ObjType, "!Hyph ?");
   }
}


/** occurance - 0 \neverpages, 1 \allpages, 2 \oddpages, 4 \evenpages */
void InitHeaderFooter(TconvertedPass1 *cq, char HorF, char occurance)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#InitHeaderFooter(%d,%d) ",(int)HorF,(int)occurance);fflush(cq->log);
#endif

if(FancyHdr<0)
  {
  switch (HorF)
      {
      case 0:
      case 1:fprintf(cq->strip, "\\headtext"); 
	     WP2LaTeXsty+=sty_headtext;
	     break;

      case 2:
      case 3:fprintf(cq->strip, "\\foottext"); 
	     WP2LaTeXsty+=sty_foottext;
	     break;
      }
			// bit 0 - occurance on odd pages
  switch (occurance)	// bit 1 - occurance on even pages
      {
      case 0:fprintf(cq->strip, "{\\neverpages}{");   break;
      case 1:fprintf(cq->strip, "{\\allpages}{");     break;
      case 2:fprintf(cq->strip, "{\\oddpages}{");
	     twoside=true;
	     break;
      case 4:fprintf(cq->strip, "{\\evenpages}{");
	     twoside=true;
	     break;
      default:fprintf(cq->strip, "{}{"); 	//unknown occurance
	      break;
      }
  }
else
  {
  FancyHdr=1;
  switch (HorF)
      {
      case 0:
      case 1:fprintf(cq->strip,"\\fancyhead");
	     switch (occurance)
	       {
	       case 0:fprintf(cq->strip,"{} {"); break;
	       case 1:fprintf(cq->strip,"{} \\fancyhead[L]{"); break;
	       case 2:fprintf(cq->strip,"[O]{} \\fancyhead[LO]{");
		      twoside=true;
		      break;
	       case 4:fprintf(cq->strip,"[E]{} \\fancyhead[LE]{");
		      twoside=true;
		      break;
	       default:putc('{', cq->strip);
		       break;
	       }
	     break;

      case 2:
      case 3:fprintf(cq->strip, "\\fancyfoot");
	     switch (occurance)
	       {
	       case 0:fprintf(cq->strip,"{} {"); break;
	       case 1:fprintf(cq->strip,"{} \\fancyfoot[L]{"); break;
	       case 2:fprintf(cq->strip,"[O]{} \\fancyfoot[LO]{");
		      twoside=true;
		      break;
	       case 4:fprintf(cq->strip,"[E]{} \\fancyfoot[LE]{");
		      twoside=true;
		      break;
	       default:putc('{', cq->strip);
		       break;
	       }
	     break;
      default:putc('{', cq->strip);
      }
  }
}


void InvisibleSoftReturn(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#InvisibleSoftReturn() ");fflush(cq->log);
#endif

  if(cq->char_on_line==CHAR_PRESENT) /* Ignore misplaced ISRt */
     {
     fprintf(cq->strip, "{\\penalty0}");
     }

  strcpy(cq->ObjType, "ISRt");
}


void Justification(TconvertedPass1 *cq, unsigned char WPx)
{
static const char JustWP3_2WP5[4]={0,2,3,1};

#ifdef DEBUG
  fprintf(cq->log,"\n#Justification() ");fflush(cq->log);
#endif
  uint8_t b;
  const char *Direction="?";
  char OldEnvir;
			// This is impossible to change environment for one
  if(cq->envir == 'B') goto JustifEnd; // cell in the table.

  if(WPx==5||WPx==3||WPx==1) fseek(cq->wpd, 1L, SEEK_CUR);
  if(WPx==6) fseek(cq->wpd, 3L, SEEK_CUR);
  if(WPx<0x80) fread(&b, 1, 1, cq->wpd);    /*0-Left, 3-Right, 2-Center, 1-Full */
	  else b=WPx & 3;		    /*WPx=80   WPx=83   WPx=82    WPx=81 - direct set */
  if((WPx==3 || WPx==1)  && (b&0xFC)==0)
	  b=JustWP3_2WP5[b&0x3];

  if(cq->char_on_line == FIRST_CHAR_MINIPAGE)	//first line after minipages
    {
    putc('%', cq->strip);
    cq->char_on_line = CHAR_PRESENT;
    }
  if(cq->char_on_line==CHAR_PRESENT)                      //!!!!!!!!!   ////
    {
    NewLine(cq);
    }
  cq->latex_tabpos = 0;
  OldEnvir = cq->envir;
  cq->envir = ' ';

  switch(b)
    {
    case 0:cq->envir = 'L';     /* environment = left */
	   Direction="Left";
	   break;
    case 1:cq->envir = ' ';     /* environment = full */
	   Direction="Full";
	   break;
    case 2:cq->envir = 'C';     /* environment = center */
	   Direction="Center";
	   break;
    case 3:cq->envir = 'R';     /* environment = right */
	   Direction="Right";
	   break;
    case 4:cq->envir = ' ';     /* environment = full all lines */
	   Direction="Full all lines";
	   break;
    case 5:cq->envir = ' ';     /* environment = full all lines */
	   Direction="!Decimal";
	   break;
    default:cq->envir = ' ';	/* unknown enviroment */
	    Direction="?";
    }

  if(OldEnvir != cq->envir)
    {
    //Close_All_Attr(cq->attr,cq->strip); Not required! Attributes are handled in pass2.
    if(cq->envir!=' ' || OldEnvir!=' ')
  	cq->char_on_line = LEAVE_ONE_EMPTY_LINE;
    }

JustifEnd:
  sprintf(cq->ObjType, "Justification %s",Direction);
}


/* I really don't know whether are these national settings correct.
 * If you find problems, please correct them and send me your improvement.
 * http://parokia.kre.hu/lelkesz/latex/babel.pdf */
LangItem LangTable[31] = 
{
// quarenteed indexes
  {{'D','E'}, 0x02, "german", 0},

// other indexes
  {{'A','F'}, 0x0F, "afrikaans", 0},
//Arabic ... $18
//Chinese .... $15
//Cyprian .... $21
  {{'B','R'}, 0xFF, "brazil",0},		//Portugesse - Brasil
  {{'C','Z'}, 0x11, "czech",0},
  {{'C','A'}, 0x0D, "catalan", 0},
  {{'C','E'}, 0xFF, "canadian", 0},		//ENcanada
  {{'C','F'}, 0xFF, "canadien", 0},		//FRcanada
//Danish .... $05
//Faeroese... $20
//Flemish ... $07
  {{'E','S'}, 0x08, "spanish",0},
  {{'F','R'}, 0x01, "french", 0},
  {{'G','A'}, 0xFF, "galician", 0},
  {{'G','R'}, 0x13, "greek", 0},
  {{'H','R'}, 0xFF, "croatian", 0},		//hrvatski
  {{'H','U'}, 0xFF, "hungarian", 0},
  {{'I','S'}, 0x0B, "icelandic", 0},
  {{'I','T'}, 0x04, "italian", 0},
//{{'J','P'}, 0x14, "japanese", 0},
  {{'L','F'}, 0xFF, "canadien", 0},		//FRcanada  
  {{'M','A'}, 0xFF, "hungarian", 0},
  {{'N','L'}, 0x06, "dutch", 0},		//nederland
//Hebrew .... $19
//Hindi ..... $1C
//Korean .... $16
//Maltese ... $22
//Norwegian . $0A
  {{'N','O'}, 0xFF, "norsk", 0},		//norwegian
  {{'O','Z'}, 0xFF, "australian", 0},	//ENaustralia
//Persian ... $1A
//Taiwanese .. $17
//Thai ....... $1D
  {{'P','L'}, 0x0E, "polish", 0},
  {{'P','O'}, 0x09, "portuges",0},		//Portugesse - Portugal
  {{'R','U'}, 0x12, "russian", 0},
//{{'S','D'}, 0xFF, "switzerland", 0},	//german-switzerland
  {{'S','V'}, 0x03, "swedish", 0},  
  {{'S','L'}, 0xFF, "slovak", 0},
  {{'S','O'}, 0xFF, "slovene", 0},		// slovenian
  {{'S','U'}, 0x10, "finnish", 0},
  {{'T','R'}, 0x0C, "turkish", 0},  
//Urdu....... $1B
  {{'U','S'}, 0xFF, "USenglish", 0},
  {{'U','K'}, 0,    "UKenglish", 0},
  {{'Y','K'}, 0x1F, "ukrainian", 0},
//Yugoslavian. $1E
};



/**Switch to a new language. Note:some languages are unknown for me.
   WPx_Language 5 - specially tailored for WP5   
	        6 - specially tailored for WP6
		other - two chars packed, to denote languege
*/
void Language(TconvertedPass1 *cq, uint16_t WPx_Language)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Language(%d) ",WPx_Language);fflush(cq->log);
#endif
char CurLang[3], OldLang[3];
const char *LangStr;
int i;

  CurLang[2]=0;
  OldLang[2]=0;
  switch(WPx_Language)
    {
    case 3:fseek(cq->wpd, 1L, SEEK_CUR);  //skip Old Script
           fread(OldLang,1,1,cq->wpd);
           fseek(cq->wpd, 3L, SEEK_CUR);  //skip Old Script
	   fread(CurLang,1,1,cq->wpd);
	   break;
    case 6:fread(OldLang,2,1,cq->wpd);
	   fread(CurLang,2,1,cq->wpd);
	   break;
    case 5:fseek(cq->wpd, 2L, SEEK_CUR);  //skip Old language
	   fread(CurLang,2,1,cq->wpd);
	   fread(OldLang,2,1,cq->wpd);
	   break;
    default:if((WPx_Language & 0xFF)<0x20) goto Finish;
	   if((WPx_Language & 0xFF00)<0x2000) goto Finish;
	   CurLang[0]=WPx_Language & 0xFF;
	   CurLang[1]=WPx_Language >> 8;

    }
  LangStr = CurLang;


	/* traverse whole lang table */
  if(WPx_Language==3)
    {
    for(i=0;i<sizeof(LangTable)/sizeof(LangItem);i++)
      {
      if(CurLang[0] == LangTable[i].WP3LangId)
        {
        if(LangTable[i].UseLang >= 0)
	  {
	  LangTable[i].UseLang = 1;
	  LangStr = LangTable[i].LangDesc;
	  }
        break;
        }
      }
    }
  else
    {
    for(i=0;i<sizeof(LangTable)/sizeof(LangItem);i++)
      {
      if(!strncmp(CurLang,LangTable[i].LangShort,2))
        {
        if(LangTable[i].UseLang >= 0)
	  {
	  LangTable[i].UseLang = 1;
	  LangStr = LangTable[i].LangDesc;
	  }
        break;
        }
      }
    }

  if(strcmp(CurLang,"??") && strlen(CurLang)>0)
    {
    if(LaTeX_Version<0x300)
      fprintf(cq->strip, "\\language=\\%s ", LangStr);
    else
      {
      if(strlen(LangStr)>2)  	// Is language correctly recognised, and LeTeX equivalent found?
        fprintf(cq->strip, "\\selectlanguage{%s}", LangStr);	  
      }
    }

Finish:
  sprintf(cq->ObjType, "Lang:%s",CurLang);
}


/* This procedure write macro for current number of paragraph in the document */
void ParagraphNumber(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#ParagraphNumber() ");fflush(cq->log);
#endif
  unsigned char ParNumType;
  int i;
  static char count='A';


  fread(&ParNumType, 1, 1, cq->wpd);
  ParNumType=ParNumType ^ 0x80;
  if(ParNumType>=0x80) strcpy(cq->ObjType, "ParNum:Auto");
		  else sprintf(cq->ObjType, "ParNum:%d",(int)ParNumType);

/* check whether the section is opened */
  for(i = 0; i < cq->attr.Closed_Depth; i++)
	{
	if(cq->attr.stack[i] >= First_com_section &&
	   cq->attr.stack[i] <= Last_com_section) return;
	}


  if (cq->attr.Closed_Depth!=cq->attr.Opened_Depth)
	 {
	 Open_All_Attr(cq->attr,cq->strip);
	 }
  if(ParNumType>=0x80) {
		       ParNumType=0x80;	//!!!!!!!!!!! opravit !!!!!
		       fprintf(cq->strip, "\\label{ParNum_%c}\\ref{ParNum_%c}",count,count );
		       count++;
		       }
		  else {
		       if (ParNumType > 0) ParNumType -= cq->FirstSection;
		       ParNumType += OutputStyle - First_com_section;

		       if(ParNumType>=7) return;

		       fprintf(cq->strip, "\\the%s ", Parts[ParNumType]);
		       }

  cq->char_on_line = true;
}


/* This procedure wrote a macro for writing a number of current page */
void PageNumber(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#PageNumber() ");fflush(cq->log);
#endif

  if (cq->attr.Closed_Depth!=cq->attr.Opened_Depth)
         {
	 Open_All_Attr(cq->attr,cq->strip);
         }
  fprintf(cq->strip, "\\thepage ");

  strcpy(cq->ObjType, "Insert Pg Num");
  cq->char_on_line = true;
}


/*This procedure creates header or footer with number of page exactly positioned*/
void Page_number_position(TconvertedPass1 *cq, unsigned char WP)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Page_number_position() ");fflush(cq->log);
#endif
  unsigned char position_code;
  const char *PgNumType="?", *PgNumAttr="";
  string PgNumAttrS;
  uint32_t Attributes;
  uint8_t Flags,IDs;

  if(WP==3) fseek(cq->wpd, 1L, SEEK_CUR);
  if(WP==4) fseek(cq->wpd, 1L, SEEK_CUR);
  if(WP==5) fseek(cq->wpd, 3L, SEEK_CUR);   /*Skip length of code; always 10*/
  if(WP==6) {
	    fread(&Flags, 1, 1, cq->wpd);
	    IDs=fgetc(cq->wpd);
	    fseek(cq->wpd, 14L + 2L*IDs, SEEK_CUR);
	    Rd_dword(cq->wpd, &Attributes);
	    PgNumAttrS = Attributes2String(Attributes);
	    if(!PgNumAttrS.isEmpty()) PgNumAttr=PgNumAttrS();
	    fseek(cq->wpd, -9L, SEEK_CUR);
	    }
					    /* + old information */
  fread(&position_code, 1, 1, cq->wpd);
  if(WP<6 && position_code>=9) position_code=0;

  if(FancyHdr<0)
    {
    WP2LaTeXsty+=sty_pagenumpos;
    fprintf(cq->strip, "\\pagenumpos");
    switch (position_code)
      {
      case 0x0: PgNumType="No";
NoNumber:       fprintf(cq->strip,"{\\pnno}");			      break;
      case 0x1: fprintf(cq->strip,"{\\pntl}"); PgNumType="TopLeft";   break;
      case 0x2: fprintf(cq->strip,"{\\pntc}"); PgNumType="TopCenter"; break;
      case 0x3: fprintf(cq->strip,"{\\pntr}"); PgNumType="TopRight";  break;
      case 0x4: fprintf(cq->strip,"{\\pnat}");
		PgNumType="TopAlt";
		twoside=true; 					    break;
      case 0x5: fprintf(cq->strip,"{\\pnbl}"); PgNumType="BotLeft";   break;
      case 0x6: fprintf(cq->strip,"{\\pnbc}"); PgNumType="BotCenter"; break;
      case 0x7: fprintf(cq->strip,"{\\pnbr}"); PgNumType="BotRight";  break;
      case 0x8: fprintf(cq->strip,"{\\pnab}");
		PgNumType="BottomAlt";
		twoside=true; 					    break;
      case 0x9: fprintf(cq->strip,"{\\pnit}");
		PgNumType="TopAltInside";
		twoside=true; 					    break;
      case 0xA: fprintf(cq->strip,"{\\pnib}");
		PgNumType="BotAltInside";
		twoside=true; 					    break;

      default:  goto NoNumber;
      }
    }
  else
    {
    FancyHdr=1;
    switch (position_code)
      {
      case 0x0: PgNumType="No";
NoNumber_f:     fprintf(cq->strip,"\\fancyfoot{}\\fancyhead{}"); break;
      case 0x1: fprintf(cq->strip,"\\fancyhead{}\\fancyhead[L]{%s\\thepage}",PgNumAttr);
		PgNumType="TopLeft";   				     break;
      case 0x2: fprintf(cq->strip,"\\fancyhead{}\\fancyhead[C]{%s\\thepage}",PgNumAttr);
		PgNumType="TopCenter"; 				     break;
      case 0x3: fprintf(cq->strip,"\\fancyhead{}\\fancyhead[R]{%s\\thepage}",PgNumAttr);
		PgNumType="TopRight"; 				     break;
      case 0x4: fprintf(cq->strip,"\\fancyhead{}\\fancyhead[RO,LE]{%s\\thepage}",PgNumAttr);
		PgNumType="TopAlt";
		twoside=true; 					    break;
      case 0x5: fprintf(cq->strip,"\\fancyfoot{}\\fancyfoot[L]{%s\\thepage}",PgNumAttr);
		PgNumType="BotLeft";                                break;
      case 0x6: fprintf(cq->strip,"\\fancyfoot{}\\fancyfoot[C]{%s\\thepage}",PgNumAttr);
		PgNumType="BotCenter";                              break;
      case 0x7: fprintf(cq->strip,"\\fancyfoot{}\\fancyfoot[R]{%s\\thepage}",PgNumAttr);
		PgNumType="BotRight";                               break;
      case 0x8: fprintf(cq->strip,"\\fancyfoot{}\\fancyfoot[RO,LE]{%s\\thepage}",PgNumAttr);
		PgNumType="BottomAlt";
		twoside=true; 					    break;
      case 0x9: fprintf(cq->strip,"\\fancyhead{}\\fancyhead[LO,RE]{%s\\thepage}",PgNumAttr);
		PgNumType="TopAltInside";
		twoside=true; 					    break;
      case 0xA: fprintf(cq->strip,"\\fancyfoot{}\\fancyfoot[LO,RE]{%s\\thepage}",PgNumAttr);
		PgNumType="BotAltInside";
		twoside=true; 					    break;

      default:  goto NoNumber_f;
      }
    }

  sprintf(cq->ObjType, "Pg Numbering:%s",PgNumType);
}


/*This procedure makes placing endnotes here*/
void PlaceEndnotes(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#PlaceEndnotes() ");fflush(cq->log);
#endif
  if(EndNotes<0) return;
  EndNotes=2;		/* set up endnotes */

  Close_All_Attr(cq->attr,cq->strip);

  NewLine(cq);
  fprintf(cq->strip,"\\begingroup");
  NewLine(cq);
  fprintf(cq->strip,"\\parindent 0pt \\parskip 1ex");
  NewLine(cq);
  fprintf(cq->strip,"\\def\\enotesize{\\normalsize}");
  NewLine(cq);
  fprintf(cq->strip,"\\theendnotes");
  NewLine(cq);
  fprintf(cq->strip,"\\endgroup");
  NewLine(cq);

  strcpy(cq->ObjType, "Place Endnotes");
}


/*This procedure put mark for making index here*/
void PlaceIndex(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#PlaceIndex() ");fflush(cq->log);
#endif

  Index=true;
  cq->line_term = 's';   		/* Soft return */
  if(cq->char_on_line) NewLine(cq);
  if(MakeIdx>=0) MakeIdx=1;
  fprintf(cq->strip, "\\printindex	%%here should be placed index");
  NewLine(cq);
  strcpy(cq->ObjType, "Def Mark:Index");
}


/** Performs conversion for [row] in tables */
void RowTable(TconvertedPass1 *cq, char LineType)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#RowTable() ");fflush(cq->log);
#endif

  if(cq->envir == 'B')
       {
       if(cq->char_on_line==CHAR_PRESENT || cq->char_on_line==JUNK_CHARS)
	 {
	 Close_All_Attr(cq->attr,cq->strip);
	 fprintf(cq->strip, " \\\\");
	 }
       switch(LineType)
         {
	 case 0: fprintf(cq->strip, " \n"); break;	// None
	 case 1:					// Hairline
	 case 2:                                      	// Single
	 case 3:					// Thick
	 case 4:				 	// Extra Thick
	 case 5:					// Dashed
	 case 6: fprintf(cq->strip, " \\hline\n"); break; // Dotted
	 case 7: 					// Double
	 case 8: fprintf(cq->strip, " \\hline\\hline\n"); break; //Double Thick
	 }
       cq->line_term = 's';   /* Soft return */
       }
   else {
	cq->line_term = 'h';   /* Hard return */
	putc('\n', cq->strip);
	}

  Make_tableentry_envir_extra_end(cq);

  cq->char_on_line = false;
  cq->nomore_valid_tabs = false;
  cq->rownum++;
  Make_tableentry_attr(cq);
  cq->latex_tabpos = 0;

  strcpy(cq->ObjType, "!Row"+((cq->envir!='B')?0:1));
}


/*Change counter related to endnotes*/
void SetEndnoteNum(TconvertedPass1 *cq, unsigned char WP)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#SetEndnoteNum() ");fflush(cq->log);
#endif
  uint16_t OldEndNoteNum,CurEndNoteNum;
  uint8_t Flag,NumID;


  switch(WP)
    {
    case 3:RdWORD_HiEnd(&OldEndNoteNum, cq->wpd);
	   RdWORD_HiEnd(&CurEndNoteNum, cq->wpd);
	   break;
    case 5:Rd_word(cq->wpd, &OldEndNoteNum);
	   Rd_word(cq->wpd, &CurEndNoteNum);
	   break;
    case 6:Flag=getc(cq->wpd);
	   if(Flag & 0x80) NumID=getc(cq->wpd);
		      else NumID=0;
	   fseek(cq->wpd,2l*NumID + 4,SEEK_CUR);
	   Rd_word(cq->wpd, &CurEndNoteNum);
	   CurEndNoteNum--;
	   break;
    default:return;
    }

  if(!EndNotes) EndNotes=true;		/* set up endnotes */
  if(EndNotes>0)
      fprintf(cq->strip, "\\setcounter{endnote}{%u}",(unsigned)CurEndNoteNum);
  sprintf(cq->ObjType, "Endnote Num:%u",(unsigned)CurEndNoteNum);
}


void SetFont(TconvertedPass1 *cq, int PointSize, const char *FontName)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#SetFont(%d,%s) ",PointSize,chk(FontName));fflush(cq->log);
#endif
int i;
string TexFontName(FontName);
const char *FontTblItem;

 if(FontName!=NULL)
   {
   TexFontName="WP:"+TexFontName;
   for(i=0;i<length(FontTable);i++)	//Try to find LaTeX equivalent of WP font
	{
	if((FontTblItem=FontTable[i]) == NULL) continue;
	if(strstr(FontTblItem,TexFontName())!=NULL)
		{
		if((FontTblItem=strstr(FontTblItem,"TeX:"))==NULL) continue;
		if(*FontTblItem==0) continue;
		TexFontName = FontTblItem+4;
		goto Found;
		}
	}
   TexFontName.erase();		/*Font name was not found in the table*/
   }

Found:
  cq->NativeCpg = NULL;
  i = 0;
  if(NFSS)
    {    
    Close_All_Attr(cq->attr,cq->strip);
    if(PointSize>0)
	{
	fprintf(cq->strip, "\\fontsize{%2.1f}{%2.1f}", float(PointSize)/50, float(PointSize+50)/50);
	i = 1;
	}
    if(FontName != NULL)
      {
      if(!TexFontName.isEmpty())
	{
	fprintf(cq->strip,"\\fontshape{%s}",TexFontName());
	i |= 2;
	}      
      }
    if(i>0) fprintf(cq->strip,"\\selectfont ");
    }

  if((i&2) == 0)
    {
    if(FontName!=NULL && !strncmp(FontName,"Wingdings",9))
      {
        cq->NativeCpg = GetTranslator("WingdingsTOinternal");
      }
    }
}


void SetFontSize(TconvertedPass1 *cq, char WP)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#SetFontSize() ");fflush(cq->log);
#endif
uint16_t  PointSize;
const char *ig="!";

  if(WP==4) {
	    fseek(cq->wpd, 2l, SEEK_CUR);
	    PointSize=50*fgetc(cq->wpd);
	    }
  if(WP==5) {
	    fseek(cq->wpd, 28l, SEEK_CUR);
	    Rd_word(cq->wpd,&PointSize);
	    }
  if(WP==6) {
	    fseek(cq->wpd,  6l, SEEK_CUR);
	    Rd_word(cq->wpd,&PointSize);
	    }

  SetFont(cq,PointSize,NULL);
  if(NFSS) ig="";

  sprintf(cq->ObjType, "%sFont %2.2f",ig,float(PointSize)/50);
}


/*This procedure changes the number of current footnote*/
void SetFootnoteNum(TconvertedPass1 *cq, signed char WP)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#SetFootnoteNum() ");fflush(cq->log);
#endif
  uint16_t OldFootnoteNum,CurFootnoteNum;
  uint8_t Flag,NumID;


  switch(WP)
    {
    case -4:RdWORD_HiEnd(&CurFootnoteNum, cq->wpd);/* obsolette set Footnote Num WP4.x*/
	    break;
    case 3:
    case 4:RdWORD_HiEnd(&OldFootnoteNum, cq->wpd);
	   RdWORD_HiEnd(&CurFootnoteNum, cq->wpd);/* bit 7 of second byte doesn't count, and the value */
	   break;                                 /* is offset by one.  */
    case 5:Rd_word(cq->wpd, &OldFootnoteNum);
	   Rd_word(cq->wpd, &CurFootnoteNum);
	   break;
    case 6:Flag=getc(cq->wpd);
	   if(Flag & 0x80) NumID=getc(cq->wpd);
		      else NumID=0;
	   fseek(cq->wpd,2l*NumID + 4,SEEK_CUR);
	   Rd_word(cq->wpd, &CurFootnoteNum);
	   CurFootnoteNum--;
	   break;
    default:return;
    }


  fprintf(cq->strip, "\\setcounter{footnote}{%u}",(unsigned)CurFootnoteNum);
  sprintf(cq->ObjType, "Footnote Num:%u",(unsigned)CurFootnoteNum);
}


/*This procedure changes the number of current page*/
void SetPgNum(TconvertedPass1 *cq, unsigned char WP)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#SetPgNum() ");fflush(cq->log);
#endif
  uint16_t OldPgNum,CurPgNum;

  switch(WP)
    {
    case 3:fseek(cq->wpd,1l,SEEK_CUR);	//skip Old Def
	   RdWORD_HiEnd(&OldPgNum, cq->wpd);
	   fseek(cq->wpd,1l,SEEK_CUR);	//skip New Def
	   RdWORD_HiEnd(&CurPgNum, cq->wpd);
	   break;
    case 4:RdWORD_HiEnd(&OldPgNum, cq->wpd);
	   OldPgNum&=0x7FFF;		//16. bit means page numbering Arabic/Roman
	   RdWORD_HiEnd(&CurPgNum, cq->wpd);
	   CurPgNum&=0x7FFF;
	   break;
    case 5:Rd_word(cq->wpd, &OldPgNum);
	   Rd_word(cq->wpd, &CurPgNum);
	   break;
    case 6:fseek(cq->wpd,5l,SEEK_CUR);
	   Rd_word(cq->wpd, &CurPgNum);
	   fseek(cq->wpd,1l,SEEK_CUR);
	   Rd_word(cq->wpd, &OldPgNum);
	   break;
//  defalut:return;
    }

  fprintf(cq->strip, "\\setcounter{page}{%u}",(unsigned)CurPgNum);
  sprintf(cq->ObjType, "Pg Num:%u",(unsigned)CurPgNum);
}


void SoftHyphen(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#SoftHyphen() ");fflush(cq->log);
#endif

 fputs("\\-", cq->strip);

 strcpy(cq->ObjType, "- Soft Hyphen");
}


void SoftReturn(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#SoftReturn() ");fflush(cq->log);
#endif

 if(cq->envir == 'B')		// Hard return
	{
	Close_All_Attr(cq->attr,cq->strip);
/*	if ((LaTeX_Version & 0xFF00) >= 0x300)
	     fputs(" \\tabularnewline ", cq->strip);
	else */
	     fputs(" \\penalty-10001 ", cq->strip);
	return;
	}
    else Terminate_Line(cq,'s');

  strcpy(cq->ObjType, "SRt");
}


void StartSection(TconvertedPass1 *cq, signed char WP)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#StartSection() ");fflush(cq->log);
#endif
  unsigned char b;
  int i;

  if(WP>0)
      {
      if(WP==6)fseek(cq->wpd, 3L, SEEK_CUR);
      fread(&b, 1, 1, cq->wpd);		/* read level of section */
      }
  else b=abs(WP); // direct set

  sprintf(cq->ObjType, "Start MarkToC %d",(int)b);

			/* check whether any section is already opened */
  for (i = 0; i < cq->attr.Closed_Depth; i++)
	{
	if(cq->attr.stack[i] >= First_com_section &&
	   cq->attr.stack[i] <= Last_com_section)
	     {
	     if (cq->err != NULL)
	       {
	       cq->perc.Hide();
	       fprintf(cq->err, _("\nWarning: Double MarkToC %d inside %d, second one will be ignored!"),
                       (int)b, (int)(cq->attr.stack[i]-First_com_section));
	       }
	     return;
	     }
	}


  if (cq->FirstSection > 100)
	{			   /*setup for 1'st section in the document*/
	cq->FirstSection = 0;
	if (b == 1) cq->FirstSection = 1;
	}
  if (b > 0) b -= cq->FirstSection;

  b += OutputStyle;
  if (b > Last_com_section) return;

  if(cq->envir!='B') NewLine(cq);

  if(OptimizeSection && cq->envir!='B')
	{
	AttrOn(cq->attr,b);
			//move section attribute on the first place
	if(cq->attr.Closed_Depth>1)
		{
		Close_All_Attr(cq->attr,cq->strip);
		cq->attr.stack[cq->attr.Closed_Depth-1]=cq->attr.stack[0];
		cq->attr.stack[0]=b;
		}

	}
   else {
	fprintf(cq->strip, "\\addcontentsline{toc}{%s}",Parts[b-First_com_section]);
	AttrOn(cq->attr,Last_com_section+1);
	}
}


void Suppress(TconvertedPass1 *cq, char WP)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Suppress() ");fflush(cq->log);
#endif
  uint8_t SupType;
  uint8_t HA,HB,FA,FB,ForceNum;
  const char *suppress="!";

  if(WP==3)
  {
    fseek(cq->wpd,2l,SEEK_CUR);
    uint16_t SupTypeW;
    RdWORD_HiEnd(&SupTypeW, cq->wpd);
    SupType = (uint8_t)SupTypeW;
  }
  else
  {
    if(WP==5) fseek(cq->wpd,1l,SEEK_CUR);
    if(WP==6) fseek(cq->wpd,3l,SEEK_CUR);
    SupType = fgetc(cq->wpd);
  }

  switch(WP)
	{
	case 4:HA = SupType & 0x10;
	       HB = SupType & 0x20;
	       FA = SupType & 0x40;
	       FB = SupType & 0x20;
	       ForceNum = SupType & 0x04;
	       break;

        case 3:
	case 5://bit 0-NoPgNum; 1-ThisNum; 2-HeaderA; 3-HeaderB; 4-FooterA; 5-FooterB
	case 6://               for WP6.x  6-WatermarkA; 7-WatermarkB
	       HA = SupType & 0x04;
	       HB = SupType & 0x08;
	       FA = SupType & 0x10;
	       FB = SupType & 0x20;
	       ForceNum = SupType & 0x02;
	       break;

	default:return;
	}

  if( HA && HB && FA && FB)
    {
    fprintf(cq->strip, "\\thispagestyle{%s} ",ForceNum?"plain":"empty");
    suppress="";
    }

  sprintf(cq->ObjType,"%sSuppress:%s%s%s%s",suppress,HA?" HA":"",HB?" HB":"",FA?" FA":"",FB?" FB":"");
}


/** This Procedure converts [TAB] command. */
void Tab(TconvertedPass1 *cq, char WP)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Tab() ");fflush(cq->log);
#endif
int j;
uint16_t wpu;
int tabnum, new_tabs, FORLIM;
const char *TabType="";

  if (cq->envir != 'I' && cq->envir != 'i' && cq->envir != 'B' && !cq->nomore_valid_tabs
		       && TABs && Columns<2 )
    {   /* No indent or table --> normal tab */

	/* TabType = 0-Left, 1-Full, 2-Center, 3-Right, 4-Aligned */
    switch(WP)
      {
      case 3:j = fgetc(cq->wpd);
	     switch(j & 0x0F)
	 	{
		case 0: cq->tab_type = 4; break;
		case 1: cq->tab_type = 2; break;
	        case 2: cq->tab_type = 3; break;
	        case 3: cq->tab_type = 4; break;	// character alligned
                case 4: cq->tab_type = 4; break;	// bar (vertical line)
	        }
	     wpu = 0;
	     break;

      case 5:if (cq->subby == 0x48) cq->tab_type = 3;
	     if (cq->subby == 0x40) cq->tab_type = 4;
	     if (cq->subby == 0xc8) cq->tab_type = 2;

	     fseek(cq->wpd, 2L, SEEK_CUR);
	     Rd_word(cq->wpd, &wpu);   /* less abs.-indent [wpu] */
	     break;

      case 6:if ((cq->subby >> 3) == 0x12) cq->tab_type = 3;
	     if ((cq->subby >> 3) == 0x02) cq->tab_type = 4;
	     if ((cq->subby >> 3) == 0x09) cq->tab_type = 2;

	     fseek(cq->wpd, 3L, SEEK_CUR);
	     Rd_word(cq->wpd, &wpu);   /* less abs.-indent [wpu] */
	     break;

      default:goto NoTab;
      }

    switch(cq->tab_type)
    {
      case 2: TabType=":Centered"; break;
      case 3: TabType=":Right"; break;
      case 4: TabType=":Aligned"; break;
    }

    if (wpu <= cq->WP_sidemargin)
       {
       if(cq->err!=NULL && Verbosing>=1)
	    {
	    cq->perc.Hide();
	    fprintf(cq->err, _("\nWarning: Negative tabular, fixed!"));
	    }
       wpu = cq->tabpos[0];   /*fix negative value*/
       }
     else wpu -= cq->WP_sidemargin;  /* Correctie ivm WP kantlijn */

    tabnum = 0;
    FORLIM = cq->num_of_tabs;
    for (j = 1; j <= FORLIM; j++)
      {   /* Bepaal welke tabpos */
      if (wpu >= cq->tabpos[j-1]) tabnum = j;
      }

    new_tabs = tabnum - cq->latex_tabpos;

    for(j=0;j<cq->attr.Closed_Depth;j++)
    	{
	if(cq->attr.stack[j]>=0x10 && cq->attr.stack[j]<=0x13)
        	{		/* \section{ attribute found */
                fprintf(cq->strip, "\\hspace*{%2.2fcm} ", wpu/470.0);   /*Right*/
                cq->char_on_line = true;
	        new_tabs = 0;
		goto SkipTabs;
		}
        }

    if ((cq->char_on_line<=NO_CHAR) && cq->envir != 'T')
        {
        if(new_tabs==0) new_tabs++;
        for (j = 1; j <= new_tabs; j++)
	        fprintf(cq->strip, "\\TAB ");
	cq->char_on_line = CHAR_PRESENT;
        new_tabs = 0;
	}

    if(new_tabs > 0)
	{
        cq->envir = 'T';    /* This is one or more tabs in This row */
        Close_All_Attr(cq->attr,cq->strip);
        for (j = 1; j <= new_tabs; j++)
	        fprintf(cq->strip, "\\> ");
	if (cq->tab_type==2)
	  {
	  WP2LaTeXsty+=sty_ctab;
          fprintf(cq->strip, "\\ctab{");
	  }
	}

SkipTabs:
    cq->latex_tabpos = tabnum;
    } 
    else 
      {
NoTab:putc(' ', cq->strip);
      strcpy(cq->ObjType, "!Tab");
      return;
      }

  sprintf(cq->ObjType,"Tab%s",TabType);
}


void TableOfContents(TconvertedPass1 *cq, char WP)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#TableOfContents() ");fflush(cq->log);
#endif
  char ListType,ListSubType,b;
  string ListName;

  if ((cq->char_on_line==CHAR_PRESENT)||(cq->attr.Opened_Depth>0))
    {
    Close_All_Attr(cq->attr,cq->strip);

    NewLine(cq);
    }

  fread(&ListType, 1, 1, cq->wpd);
  switch(ListType>>4)
	{
	case  0:fprintf(cq->strip, "\\tableofcontents ");
		cq->line_term = 's';   /* Soft return */
		NewLine(cq);
		strcpy(cq->ObjType, "Def Mark:ToC");
		break;
	case  1:PlaceIndex(cq);
		break;
	case  2:if(WP>4) fread(&ListSubType, 1, 1, cq->wpd);
		else ListSubType=0;
		ListType = (ListType & 0xF) + 1;
		sprintf(cq->ObjType, "%d",ListType);
		ListName=_("List ");
		ListName+=cq->ObjType;
		b=ListName() IN UserLists;
		if(b) b--;
		   else b=UserLists+=ListName();

		WP2LaTeXsty+=sty_showuserlist;
		fprintf(cq->strip, "\\ShowUserList{l%c}{%s}",b+'a',ListName());
		cq->line_term = 's';   /* Soft return */
		NewLine(cq);
		sprintf(cq->ObjType, "Def Mark:List,%d:%d",(int)ListType,(int)ListSubType+1);
		break;
	case  3:sprintf(cq->ObjType, "!Def Mark:ToA,%d",(int)(ListType & 0xF +1));
// !!!!!!!!! The tables of autorities are not converted yet
		break;

	default: strcpy(cq->ObjType, "Def Mark:?Unknown");
	}

}

/** This function emits line termination.
 * @param [in] line_term   'h';   Hard return
			   's';   Soft return
			   'P';   Hard page
			   'p';   Soft page */
void Terminate_Line(TconvertedPass1 *cq, char line_term)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Terminate_Line(%c) ",line_term);fflush(cq->log);
#endif
  cq->line_term = line_term;

  if(cq->CentrePage && (line_term=='p' || line_term=='P'))
	{						// finish page centering
	fprintf(cq->strip, "\\vfil ");
	cq->CentrePage=false;
	}
  
  if(line_term=='h' || line_term=='P')
    for(int j=0; j<cq->attr.Opened_Depth; j++)		// Look for subscript and superscript.
      {
      if(cq->attr.stack[j]==5 || cq->attr.stack[j]==6)	// subscript or superscript
        {
        Close_All_Attr(cq->attr, cq->strip, j);		// close them on HRT or HPG.
        break;
        }    
      }

  putc('\n', cq->strip);

  Make_tableentry_envir_extra_end(cq);

  if((line_term=='h' || line_term=='P')&&(toupper(cq->envir) == 'I'))
	{
	cq->indent_end=true;  /* enforce End of indent on [HRt] and [Hpg] */
	}

  if (cq->indent_end)
      {
      cq->envir = ' ';
      cq->indenting = 0;
      cq->ind_text1 = false;
      cq->ind_leftmargin = 0;
      cq->ind_rightmargin = 0;

      cq->indent_end = false;
      }
   else if (cq->envir != ' ' &&
	    cq->envir != 'R' && cq->envir != 'L' && cq->envir != 'C' &&
	    cq->envir != 'I' && cq->envir != 'i' && cq->envir != 'B')
		{	// turn off one line long enviroments
		if( (cq->envir == 'c' || cq->envir == 'T')
		     && cq->char_on_line == CHAR_PRESENT)
			{
			cq->char_on_line = LEAVE_ONE_EMPTY_LINE;
			cq->envir = ' ';
			goto NoSetCharOnLine;
			}
		cq->envir = ' ';
		}

  cq->char_on_line = false;
NoSetCharOnLine:
  cq->nomore_valid_tabs = false;

  cq->rownum++;

  Make_tableentry_attr(cq);

  cq->latex_tabpos = 0;
}


/** This function turns on/off WidowOrphan protection. 
 type=0 Wid:Off, Orph:Off; type=1 Wid:On, Orph:Off; 
 type=2 Wid:Off, Orph:On;  type=3 Wid:On, Orph:On; */
void WidowOrphan(TconvertedPass1 *cq,signed char type) /*type 0:off; 1:on; 6:Wp6.0*/
{
#ifdef DEBUG
  fprintf(cq->log,"\n#WidowOrphan(%d) ",(int)type);fflush(cq->log);
#endif

if(type==6)
	{
	fseek(cq->wpd,3l,SEEK_CUR);
	fread(&type,1,1,cq->wpd);
	if(type==1) type=3;
	}

  if(type<=3)
     {
     fprintf(cq->strip, "\\widowpenalty %d ", (type&1)?150:0 );
     fprintf(cq->strip, "\\clubpenalty %d ", (type&2)?150:0 );

     sprintf(cq->ObjType, "Wid%s/Orph:%s",
         (type==2||type==1)?((type&1)?":On":":Off"):"",
	 (type&2)?"On":"Off");
     }
  else sprintf(cq->ObjType, "!Wid/Orph:%d",type);

}


///////////////////////////////////////////


void TconvertedPass1::InitMe(FILE *FileIn, FILE *Table, FILE *StripOut, FILE *LogFile, FILE *ErrorFile)
{
  attr.InitAttr();

  wpd   = FileIn;
  table = Table;
  strip = StripOut;
  log   = LogFile;
  err   = ErrorFile;

  Initialise_Conversion(this);

  envir = ' ';
  nomore_valid_tabs = false;
  rownum = 0;

  Make_tableentry_attr(this);   /* attribuut instelling */
  Make_tableentry_tabset(this);   /* Geef the defaulttabinstelling door tied the 2e pass */
}


#ifndef __Limited_Proc_Size
void TconvertedPass1::PleaseReport(const char *Feature, const char *Type)
{
static const char *PrevFeature = NULL;
  if(err==NULL) return;

  if(PrevFeature != NULL)  
  {
    if(!strcmp(PrevFeature,Feature)) return;
  }
  PrevFeature = Feature;

  perc.Hide();
  fprintf(err, _("\nNote: Please send me this %s file for WP2LaTeX improvement, unimplemented feature \"%s\"."),Type,Feature);
}
#endif



void ReportNoMemory(TconvertedPass1 *cq)
{
  fprintf((cq==NULL||cq->err==NULL)?stderr:cq->err, _("\nFatal: Not enough memory."));
}

/*--------------------End of PASS1--------------------*/		
