/********************************************************************************
 * program:     wp2latex                                                        *
 * function:    convert WordPerfect 2.x, 2,3.x,4.x,5.x and 6.x files into LaTeX *
 * modul:       wp2l_lib.cc                                                     *
 * licency:     GPL		                                                *
 * description: Library with commonly used procedures.			        *
 ********************************************************************************/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifdef __GNUC__
 #include <sys/stat.h>
#else
 #ifndef _MSC_VER
  #include <dir.h>
 #else
  #include <direct.h>
 #endif
#endif

//Non standard include files
#include "common.h"
#include "stringa.h"
#include "lists.h"

#include "wp2latex.h"
#include "struct.h"
#include "images/image.h"
#include "images/img_futi.h"

#ifdef __BORLANDC__
 #include "cp_lib/cptran.h"
#else
 #include "cptran.h"
#endif


#ifdef __Disable_NULL_printf
 #define chk(x) x==NULL?"NULL":x
#else
 #define chk(x) x
#endif


/** Useful forward declarations. */
void GetLogFileName(string & LogFile);


/*
Flags:'h';       Hard return
      's';       Soft return      !!!!!!! 'r'
      'P';       Hard page
      'p';       Soft page

      'B'        Table
      'C','c'    Center (only one line)
      'I','i'    Identing (both)
      'L'        Left
      'M' [cols] Multicolumn enviroment
      'R'        Right
      'Q','q'    Equation (array of equations)
      'T'        Tabbing

      'l' size			Line Spacing
      'S' number,[tab1,tab2]	Tabset

      '%'		        Empty line that might be removed
      '!'			Ignore change Enviroment before (push)
      '^'			Ignore change Enviroment after (pop)
      #FF			end of line
*/

/*Char_on_line  -20 Line after nested enviroment change
		-10 Line before nested enviroment change
		 -1 No valic character on line, but previous line plays like character
		  0 No valid character on the line
		  1 Valid character placed on the line */

/*WP2LaTex switches: -1:disabled; 0:automatically enabled; 1: forced to enable*/
int8_t   Accents = STYLE_NOTUSED,
	AmsMath = -1,
        Amssymb = -1,		// Totaly Disabled
	Arevmath = -1,		// Totaly Disabled
        Cyrillic = STYLE_NOTUSED,
	cjHebrew = STYLE_NOTUSED,
	colors = STYLE_NOTUSED,	// Only for LaTex 2.0e
	textcomp = -1,
	EndNotes = STYLE_NOTUSED,
	FancyHdr = -1,
	Columns = 1,		// -1 disabled; 0 auto two; 1 auto multi; 2 forced two; >2 forced multi*/
	InputPS = IMG_graphicx,	// -1 disabled; 0 auto InputPS.sty; 1 InputPS.sty; 2 auto graphicx.sty; 3 graphicx.sty; 4 auto epsfig.sty; 5 epsfig.sty; 8 auto graphics.sty; 9 graphics.sty;
	pifont = STYLE_NOTUSED,
	PostScript = STYLE_NOTUSED,
	MakeIdx = -1,
	Wasy = -1,		// Totaly Disabled	
	LaTeXsym = 0,
	Bbm = -1,
	TIPA = -1,
	fontenc = -1,
	Rsfs = -1,
	Ulem = 0,		// Enabled on demand
	rus_yo = 0,
	LongTable = -1,
	SaveWPG = -1,
        Rotate = STYLE_NOTUSED,
        Scalerel = STYLE_NOTUSED,
        mxedruli = STYLE_NOTUSED,
	LineNo = STYLE_NOTUSED;
bool Index = false,
        Interactive = true,
	NFSS = false,
	TABs = true,
	twoside = false,
	ExactFnNumbers = false,
	CPStyles = false;        

string force, FORCE;
int LaTeX_Version=0x300; /* 0x209=LaTeX 2.09; 0x300=LaTex 3.0 (or 2e) */
unsigned short OutCodePage, WPcharset;
FFormatDetect FilForD;
#ifdef _has_MemStreams
int UseMemStream=0;
#endif


bool OptimizeSection;
signed char Verbosing;	  ///< <=-1 no errors, <=0 no warnings, 1 normal, >1 verbosive
#ifdef _REENTRANT
short Job4Run = -1;
#endif
bool TexChars;
bool ExtendedCheck, FixSpaces;
bool EraseStrip=true;
bool UndoRedo=true;
bool Noclobber=false;
string InputDir("./");
string RelativeFigDir("."), OutputDir("./");
list ImgInputDirs="./";
list Counters;
list FontTable;
list UserLists;

long  num_of_lines_stripfile,
      UnknownCharacters,UnknownObjects,CorruptedObjects;
CpTranslator *UserWPCharSet=NULL;

string wpd_filename, strip_filename, table_filename, latex_filename,
       log_filename;
string wpd_password;
FILE *wpd, *table;
FILE *strip, *logg, *err;
FILE *latex;


/// Opening and closing for styles in LaTeX v2
const TStyleOpCl StyleOpCl2[] =
{
  {"{\\LARGE ",        "}",    NULL,       NULL},
  {"{\\Large ",        "}",    NULL,       NULL},
  {"{\\large ",        "}",    NULL,       NULL},
  {"{\\small ",        "}",    NULL,       NULL},
  {"{\\footnotesize ", "}", NULL,       NULL},
  {"$^{{\\rm ",        "}}$",  "^{{\\rm ", "}}"},
  {"$_{{\\rm ",        "}}$",  "_{{\\rm ", "}}"},
  {"{\\fontshape{ol}\\selectfont ", "}",  NULL, NULL},
  {"{\\it ",           "\\/}", "}",        "{\rm "},
  {"", "",                     NULL,       NULL},
  {"\\textcolor{red}{", "}",   NULL,       NULL},
  {"\\uuline{", "}", NULL, NULL},
  {"{\\bf ", "}", NULL, NULL},
  {"\\sout{", "}", NULL, NULL},
  {"\\uline{", "}", NULL, NULL},
  {"{\\sc ", "}", NULL, NULL},
  {"{\\tt ", "}", NULL, NULL},
  {"\\part{", "}", NULL, NULL},
  {"\\chapter{", "}", NULL, NULL},
  {"\\section{", "}", NULL, NULL},
  {"\\subsection{", "}", NULL, NULL},
  {"\\subsubsection{", "}", NULL, NULL},
  {"\\paragraph{", "}", NULL, NULL},
  {"\\subparagraph{", "}", NULL, NULL},
  {"{", "}", NULL, NULL},
  {"{", "}", NULL, NULL},
  {"\\iffalse ", "\\fi ", NULL, NULL},
  {"\\cyr ", "", NULL, NULL},
  {"\\begin{cjhebrew}", "\\end{cjhebrew}", NULL, NULL},
  {"\\begin{linenumbers}", "\\end{linenumbers}", NULL, NULL},
  {"\\mxedc ", "", NULL, NULL},
};


/// Opening and closing for styles in LaTeX v3
const TStyleOpCl StyleOpCl3[] =
{
  {"{\\LARGE ",        "}",    NULL,       NULL},
  {"{\\Large ",        "}",    NULL,       NULL},
  {"{\\large ",        "}",    NULL,       NULL},
  {"{\\small ",        "}",    NULL,       NULL},
  {"{\\footnotesize ", "}", NULL,       NULL},
  {"$^{{\\rm ",        "}}$",  "^{{\\rm ", "}}"},
  {"$_{{\\rm ",        "}}$",  "_{{\\rm ", "}}"},
  {"{\\fontshape{ol}\\selectfont ", "}",  NULL, NULL},
  {"{\\itshape ",      "\\/}", "}",        "{\rm "},
  {"", "",                     NULL,       NULL},
  {"\\textcolor{red}{", "}",   NULL,       NULL},
  {"\\uuline{", "}", NULL, NULL},
  {"{\\bfseries ", "}", NULL, NULL},
  {"\\sout{", "}", NULL, NULL},
  {"\\uline{", "}", NULL, NULL},
  {"{\\scshape ", "}", NULL, NULL},
  {"{\\tt ", "}", NULL, NULL},
  {"\\part{", "}", NULL, NULL},
  {"\\chapter{", "}", NULL, NULL},
  {"\\section{", "}", NULL, NULL},
  {"\\subsection{", "}", NULL, NULL},
  {"\\subsubsection{", "}", NULL, NULL},
  {"\\paragraph{", "}", NULL, NULL},
  {"\\subparagraph{", "}", NULL, NULL},
  {"{", "}", NULL, NULL},
  {"{", "}", NULL, NULL},
  {"\\iffalse ", "\\fi ", NULL, NULL},
  {"\\cyr ", "", NULL, NULL},
  {"\\begin{cjhebrew}", "\\end{cjhebrew}", NULL, NULL},
  {"\\begin{linenumbers}", "\\end{linenumbers}", NULL, NULL},
  {"\\mxedc ", "", NULL, NULL},
};


const TStyleOpCl *StyleOpCl = StyleOpCl2;



int OutputStyle = First_com_section + 2;

#if defined(__BORLANDC__) && defined(__MSDOS__)
 #include <alloc.h>
 #define CORELEFT() coreleft()
#endif


/** destroy all ununderstable characters. */
void FixLabelText(const char *str, FILE *f)
{
  if(str==NULL) return;
  while(*str)
   {
   switch(*str)
     {
     case 0: return;
     case '\\':fputs("_bsl", f); break;
     case '$': fputs("_dol", f); break;
     case '{': fputs("_opb", f); break;
     case '}': fputs("_clb", f); break;
     case '%': fputs("_prc", f); break;
     case '_': fputs("_und", f); break;
     default:  fputc(*str, f); break;
     }
   str++;
   }
 return;
}


void UpdateFigDir(void)
{
char ch;
int i;

 ch = RelativeFigDir[StrLen(RelativeFigDir)-1];
 if(ch=='/' || ch=='\\')
         RelativeFigDir = copy(RelativeFigDir,0,StrLen(RelativeFigDir)-1);

 if(wpd_filename.isEmpty()) return;

 if((i=GetPathEnd(wpd_filename())) > 0)
    {
    ch = wpd_filename[++i];
    wpd_filename[i]=0;
    InputDir = wpd_filename();
    ImgInputDirs |= InputDir;
    wpd_filename[i]=ch;
    }

 if(latex_filename == '-') return;

 if((i=GetPathEnd(latex_filename())) > 0)
	{
	ch=latex_filename[++i];
	latex_filename[i]=0;
	if(!strcmp(latex_filename,InputDir())) OutputDir=InputDir;
			   else	OutputDir=latex_filename(); //must work with char*, string is temporary shorted
	latex_filename[i]=ch;
	}

 if(RelativeFigDir!=".")
	{
	string AbsoluteFigDir;
	AbsoluteFigDir = MergePaths(OutputDir,RelativeFigDir,false);
        ch=AbsoluteFigDir[StrLen(RelativeFigDir)-1];
        if(ch=='/' || ch=='\\')
           AbsoluteFigDir=copy(AbsoluteFigDir,0,StrLen(AbsoluteFigDir)-1);
#if defined(__Mkdir_Has_1_arg)
	mkdir(AbsoluteFigDir());
#else
	mkdir(AbsoluteFigDir(), S_IRWXU);
#endif
	}

}


/** This procedure extracts additional configuration info from system variable 'wp2latex'. */
void Sys_Variable(void)
{
string var;
char **argv;
int argc,i;
char typ,oldtyp;

 argc=0;

 var = getenv("noclobber");
 if(length(var)>0) Noclobber=true;

 var = getenv("wp2latex");
 if(var.isEmpty()) var = getenv("WP2LATEX");
 if(var.isEmpty()) return;

 oldtyp=0;
 for(i=0;i<length(var);i++)
	{
        if((var[i]==' ')||(var[i]==9))
			{
			typ=0;
			var[i]=0;
                        }
        	   else typ=1;

        if(typ==1 && oldtyp==0) argc++;
        oldtyp=typ;
        }

 if((argv=(char **)calloc(argc,sizeof(char**))) == NULL) return;
 argc=0;
 if(var[0]!=0) argv[argc++]=var();
 for(i=1;i<length(var);i++)
	{
	if((var[i-1]==0)&&(var[i]!=0))
			 argv[argc++]=&var[i];
	}
 CommandLine(argc, argv);
 free(argv);
return;
}


/** This procedure is aimed to parse a configuration file. */
void LoadConfigFile(const char *filename)
{
FILE *F;
string s;
int Section=0;
//int i;

if( (F=fopen(filename,"r"))==NULL ) return;
while(!feof(F))
   {
   fGets2(F,s);
   s.trim();
   if(s.isEmpty()) continue;
/*   if(s=="[WPUserChars]")
	{
	Section=1;
	continue;
	} */
   if(s=="[Fonts]")
	{
	Section=2;
	continue;
	}

   switch(Section)
	{
	case 0:break;
/*	case 1:if(sscanf(s(),"%d",&i)!=1) break;
	       if(i<0 || i>255) break;
	       while(isdigit(s[0]))
		   {
		   s=copy(s,1,length(s)-1);
		   if(s.isEmpty()) break;
		   }
	       s=trim(s);
	       if(UserWPCharSet==NULL)
		   {
		   UserWPCharSet = (char**)calloc(256,sizeof(char *));
		   if(UserWPCharSet==NULL) break;
		   memset(UserWPCharSet,0,256*sizeof(char *));
		   }

	       if(UserWPCharSet[i]!=NULL) free(UserWPCharSet[i]);
	       UserWPCharSet[i]=strdup(s());
	       break; */
	case 2:FontTable+=s;
	       break;
	}
   }

fclose(F);
}


//---------  File format detectors -------------
const char EncryptionWarning[]=N_("\nWarning: File seems to be encrypted. Conversion may not be possible!!");
#define MaxChar 0x200   //this can be used to tune a quality of autodetection


/// This procedure provides autodetection of Accent format.
static int DetectAccent(FILE *text, FFormatDetect & iFFD)
{
int Status,CharNo=0,chr;
string s;

  iFFD.DocumentType = "Accent";
  iFFD.Converter = iFFD.DocumentType;
  iFFD.Extension = "acc";
  if(text==NULL) return(0);

  Status=0;
  fseek(text,0,SEEK_SET);
  while(CharNo<MaxChar)
	{
	if( (chr=fgetc(text)) == EOF) goto NoAccent;
	chr = toupper(chr);
	CharNo++;
	switch(Status)
		{
		case 0:if(isspace(chr)) break;
		       if(chr=='<') {Status=1;break;}
		       goto NoAccent;
		case 1:if(chr=='V') {Status=2;break;}
		       goto NoAccent;
		case 2:if(chr=='E') {Status=3;break;}
		       goto NoAccent;
		case 3:if(chr=='R') {Status=4;break;}
		       goto NoAccent;
		case 4:if(isspace(chr)) break;
		       Status = 5;
		case 5:if(chr=='>')
			    {
			    fseek(text,0,SEEK_SET);
			    if(copy(s,0,29)=="ACCENT SOFTWARE INTERNATIONAL")
				 return(1);	//Accent succesfully detected
			    else return(0);
			    }
		       s += chr;
		       break;
		default:printf(_("Error: State automat failed at state %d\n"),Status);
			Status=0;
		}
	}

NoAccent:
  fseek(text,0,SEEK_SET);
  return(0);
}


/**This procedure provides autodetection of BMP format.*/
static int DetectBMP(FILE *stream, FFormatDetect & iFFD)
{
char buffer[2];

  iFFD.DocumentType="BMP image";
  iFFD.Extension = iFFD.Converter = "BMP";
  iFFD.Probability=-1;
  iFFD.DocVersion=0;

  if(fread(buffer,1,2,stream)!=2) 
    {
    fseek(stream,-2,SEEK_CUR);
    return 0;
    }
  fseek(stream,-2,SEEK_CUR);
  if(!memcmp(buffer,"BM",2)) return 1;
  return(0);
}



/// This is a state machine for detecting HTML files
static int DetectHtml(FILE *text, FFormatDetect & iFFD)
{
int Status, CharNo=0, chr;

  iFFD.DocumentType="HTML";
  iFFD.Converter = iFFD.DocumentType;
  iFFD.Extension = "htm";
  if(text==NULL) return(0);

  Status=0;
  fseek(text,0,SEEK_SET);
  while(CharNo<MaxChar)
	{
	if( (chr=fgetc(text)) == EOF) goto NoHTML;
	chr=toupper(chr);
	CharNo++;
	switch(Status)
		{
		case 0:if(isspace(chr)) break;
		       if(chr=='<') {Status=1;break;}
		       goto NoHTML;
		case 1:if(chr=='!') {Status=11;break;}
		       if(chr=='H') {Status=2;break;}	// HTML
		       if(chr=='M') {Status=7;break;}	// META
		       goto NoHTML;
		case 2:if(chr=='T') {Status=3;break;}
		       goto NoHTML;
		case 3:if(chr=='M') {Status=4;break;}
		       goto NoHTML;
		case 4:if(chr=='L') {Status=5;break;}
		       goto NoHTML;
		case 5:if(chr=='>')
			    {
			    fseek(text,0,SEEK_SET);
			    return(1);		//HTML succesfully detected
			    }
		       Status=6;break;
		case 6:if(chr=='>')
			    {
			    fseek(text,0,SEEK_SET);
			    return(1);	//HTML succesfully detected
			    }
		       break;

		case 7:if(chr=='E') {Status=8;break;}
		       goto NoHTML;
		case 8:if(chr=='T') {Status=9;break;}
		       goto NoHTML;
		case 9:if(chr=='A') {Status=10;break;}
		       goto NoHTML;

		case 10:if(chr==' '){Status=11;break;}
		       if(chr=='>') {Status=0;break;}
		       goto NoHTML;
		case 11:if(chr=='>') Status=0;
		       break;
		default:printf(_("Error: State automat failed at state %d\n"),Status);
			Status=0;
		}
	}

NoHTML:
  fseek(text,0,SEEK_SET);
  return(0);
}


/// This procedure provides autodetection of MTEF format.
static int DetectMTEF(FILE *stream, FFormatDetect & iFFD)
{
uint32_t Version,ObjLen,ThisFileSize;
uint16_t HdrLen;

  iFFD.DocumentType = "MTEF";
  iFFD.Converter = iFFD.DocumentType;
  iFFD.Extension = "MTF";
  if(stream==NULL) return(0);

  ThisFileSize = FileSize(stream);
  fseek(stream,0,SEEK_SET);
  Rd_word(stream, &HdrLen);
  Rd_dword(stream, &Version);

  if(HdrLen!=0x1C) goto NoMTEF;		//strange hdr len
  if(Version>0x2FFFF) goto NoMTEF;		//unsupported version

  fseek(stream,8,SEEK_SET);
  Rd_dword(stream, &ObjLen);

  if(ObjLen+HdrLen!=ThisFileSize) goto NoMTEF;	//wrong overall size

  fseek(stream,HdrLen+3,SEEK_SET);
  RdWORD_HiEnd((uint16_t *)&iFFD.DocVersion,stream);

  fseek(stream,HdrLen,SEEK_SET);
  return(1);			// Beware to seek offset!

NoMTEF:
  fseek(stream,0,SEEK_SET);
  return(0);
}


/** This procedure provides autodetection of postscript text. */
static int DetectPostScript(FILE *stream, FFormatDetect & iFFD)
{
uint16_t Magic1,Magic2;

  iFFD.DocumentType="PostScript file";
  iFFD.Extension = iFFD.Converter = "PS";
  if(stream==NULL) return 0;

  Rd_word(stream, &Magic1);
  Rd_word(stream, &Magic2);
  fseek(stream,-4,SEEK_CUR);

  if(Magic1 == 0x2125 && Magic2 == 0x5350)	//This is a PostScript file
	{
	return 1;
	}
  return 0;
}


/** This procedure provides autodetection of RTF format. */
static int DetectRTF(FILE *text, FFormatDetect & iFFD)
{
long OldFilePos;
char buffer[6];

  iFFD.DocumentType = "RTF";
  iFFD.Extension = iFFD.Converter = iFFD.DocumentType;

  if(text==NULL) return(0);

  OldFilePos = ftell(text);

  if(fread(buffer,1,5,text)!=5) goto NoRTF;
  if(!strncmp(buffer,"{\\rtf",5))		//RTF startup detected
	{
	fseek(text,OldFilePos,SEEK_SET);
	return(1);
	}

NoRTF:
  fseek(text,OldFilePos,SEEK_SET);
  return(0);
}


/** This procedure provides autodetection of RTF format. */
static int DetectT602(FILE *text, FFormatDetect & iFFD)
{
long OldFilePos;
string Command;
int commands=0,len;

  iFFD.DocumentType = "Text 602";
  iFFD.Extension = iFFD.Converter = "T602";
  if(text==NULL) return(0);
  OldFilePos = ftell(text);

  while(!feof(text))
    {
    fGets2(text, Command, 1024);
    if(length(Command)<3)
	{
HdrEnd:	if(commands<3) goto NoT602;
	fseek(text,OldFilePos,SEEK_SET);
	return(1);
	}
    if(Command[0]!='@')
	goto HdrEnd;
    for(len=1;len<length(Command);len++)
       {
       if(isspace(Command[len])) break; 
       }
    if(len>3) goto HdrEnd;
    
    commands++;
    }

NoT602:
  fseek(text,OldFilePos,SEEK_SET);
  return(0);
}


/** This procedure provides autodetection of windows metafile. */
static int DetectWinMetafile(FILE *stream, FFormatDetect & iFFD)
{
uint32_t Magic1,Magic2;

  iFFD.DocumentType = "Windows Metafile";
  iFFD.Extension = iFFD.Converter = "WMF";
  if(stream==NULL) return 0;

  Rd_dword(stream, &Magic1);
  Rd_dword(stream, &Magic2);
  fseek(stream,-8,SEEK_CUR);

  if(Magic1==0x9AC6CDD7)
  {
    iFFD.Converter="WMFspecial";
    return 1;			//This is a WMF with a special header.
  }
  if(Magic1==0x00090001) return 1;	//This is a WMF

  iFFD.DocumentType="Enhanced Metafile";
  iFFD.Extension = iFFD.Converter = "EMF";

  if(Magic1==0x464D4520 && Magic2==0x00000100) return 1; //This is EMF

  if(Magic1==0x00000001 && Magic2>=80)
  {
    fseek(stream,0x28,SEEK_CUR);
    Rd_dword(stream, &Magic2);
    fseek(stream,-0x32,SEEK_CUR);
    if(Magic2==0x464D4520) return 1;	// "EMF "
  }

  return 0;
}


/// This is a state machine for detecting DocBook files
/// Docbook document might start with XML tag <book>
/// or XML preamble folloved by <book> tag.
/// DetectXML() does not detect <META><book>
static int DetectDocbook(FILE *text, FFormatDetect & iFFD)
{
int Status, CharNo=0, chr;

  iFFD.DocumentType = "docbook";
  iFFD.Converter = iFFD.DocumentType;
  iFFD.Extension = "DCB";
  if(text==NULL) return(0);

  Status=0;
  fseek(text,0,SEEK_SET);
  while(CharNo<MaxChar)
	{
	if( (chr=fgetc(text)) == EOF) goto NoDocBook;
	chr=toupper(chr);
	CharNo++;
	switch(Status)
		{
		case 0:if(isspace(chr)) break;
		       if(chr=='<') {Status=1;break;}
		       goto NoDocBook;
		case 1:if(chr=='!') {Status=101;break;}	// ?xml
		       if(chr=='?') {Status=101;break;}	// ?xml
		       if(chr=='B') {Status=2;break;}	// BOOK tag
		       if(chr=='M') {Status=7;break;}	// META tag
		       goto NoDocBook;

		case 2:if(chr=='O') {Status=3;break;}
		       goto NoDocBook;
		case 3:if(chr=='O') {Status=4;break;}
		       goto NoDocBook;
		case 4:if(chr=='K') {Status=5;break;}
		       goto NoDocBook;
		case 5:if(chr=='>')
			    {
			    fseek(text,0,SEEK_SET);
			    return(2);		//Docbook succesfully detected
			    }
		       Status=6;break;
		case 6:if(chr=='>')
			    {
			    fseek(text,0,SEEK_SET);
			    return(2);		//Docbook succesfully detected
			    }
		       break;

		case 7:if(chr=='E') {Status=8;break;}
		       goto NoDocBook;
		case 8:if(chr=='T') {Status=9;break;}
		       goto NoDocBook;
		case 9:if(chr=='A') {Status=100;break;}
		       goto NoDocBook;

		case 100:if(chr==' '){Status=11;break;}	// Space or TAG close.
		       if(chr=='>') {Status=0;break;}
		       goto NoDocBook;

		case 101:if(chr=='>') Status=0;
		       break;
		default:printf(_("Error: State automat failed at state %d\n"),Status);
			Status=0;
		}
	}

NoDocBook:
  fseek(text,0,SEEK_SET);
  return(0);
}


/** This procedure provides autodetection of XML format. */
static int DetectXML(FILE *text, FFormatDetect & iFFD)
{
int Status,CharNo=0,chr;
static const char *XML="?xml version";
static const char *DocType="!DOCTYPE";

  iFFD.DocumentType = "XML";
  iFFD.Extension = iFFD.Converter = iFFD.DocumentType;
  if(text==NULL) return(0);

  Status=0;
  fseek(text,0,SEEK_SET);
  while(CharNo<MaxChar)
	{
	if( (chr=fgetc(text)) == EOF) goto NoXML;
	CharNo++;
	//printf("[%d,%d:%c]",CharNo,Status,chr);
	switch(Status)
		{
		case 0:if(isspace(chr)) break;
		       if(chr=='<') {Status=100;break;}
		       goto NoXML;
		case 1:if(chr=='>') Status=2;
		       break;
		case 2:if(isspace(chr)) break;
		       if(chr=='<') {Status=150;break;}
		       goto XML_Detected;

			//detect a part after !DOCTYPE
		case 3:if(isspace(chr)) break;
		       if(chr=='a') {Status=4;break;}
		       if(chr=='b') {Status=20;break;}
		       goto XML_Detected;
		case 4:if(chr=='b') {Status=5;break;}
		       goto XML_Detected;
		case 5:if(chr=='i') {Status=6;break;}
		       goto XML_Detected;
		case 6:if(chr=='w') {Status=7;break;}
		       goto XML_Detected;
		case 7:if(chr=='o') {Status=8;break;}
		       goto XML_Detected;
		case 8:if(chr=='r') {Status=9;break;}
		       goto XML_Detected;
		case 9:if(chr=='d') {Status=10;break;}
		       goto XML_Detected;
		case 10:if(chr=='>')
			   {
			   fseek(text,0,SEEK_SET);
			   iFFD.DocumentType="abiword";
			   iFFD.Converter=iFFD.DocumentType;
			   iFFD.Extension = "abw";
			   return(2);
			   }
		       break;

		case 20:if(chr=='o') {Status=21;break;}		//<book>  with XML preamble.
		       goto XML_Detected;
		case 21:if(chr=='o') {Status=22;break;}
		       goto XML_Detected;
		case 22:if(chr=='k') {Status=23;break;}
		       goto XML_Detected;
		case 23:if(chr=='>')
			   {
			   fseek(text,0,SEEK_SET);
			   iFFD.DocumentType = "docbook";
			   iFFD.Converter = iFFD.DocumentType;
			   iFFD.Extension = "DCB";
			   return(3);
			   }
		       break;

		case 30:if(chr=='o') {Status=31;break;}		//<book>  without XML preamble.
		       goto NoXML;
		case 31:if(chr=='o') {Status=32;break;}
		       goto NoXML;
		case 32:if(chr=='k') {Status=23;break;}
		       goto NoXML;

		case 100: if(chr=='b') {Status=30;break;}	// try to catch <book>.
		default:if(Status>=100 && Status<strlen(XML)+100)
			   {
			   if(chr!=XML[Status-100]) goto NoXML;
			   Status++;
			   if(XML[Status-100]==0) Status=1;
			   break;
			   }
			if(Status>=150 && Status<strlen(DocType)+150)
			   {
			   if(chr!=DocType[Status-150]) goto XML_Detected;
			   Status++;
			   if(DocType[Status-150]==0) Status=3;
			   break;
			   }
			printf(_("Error: State automat failed at state %d\n"),Status);
			Status=0;
		}

	}

NoXML:
  fseek(text,0,SEEK_SET);
  return(0);
XML_Detected:
  fseek(text,0,SEEK_SET);
  return(1);
}


/** This procedure provides autodetection of OLE stream wrapper format. */
static int DetectOLEStream(FILE *stream, FFormatDetect & iFFD)
{
uint32_t Magic1,Magic2;

  iFFD.DocumentType = "OLE Stream (might be Word or encapsulated WP)";
  iFFD.Converter = "OLE Stream";
  iFFD.Extension = "OLE";
  iFFD.Probability=-1;

  Rd_dword(stream, &Magic1);
  Rd_dword(stream, &Magic2);
  fseek(stream,-8,SEEK_CUR);

  if(Magic1==0xE011CFD0 && Magic2==0xE11AB1A1) return(1);
  return(0);
}


#ifndef NO_IMG
/// This procedure provides autodetection of PNG format.
static int DetectPNG(FILE *stream, FFormatDetect & iFFD)
{
static const unsigned char PngSignature[8] = {0x89,'P','N','G',0x0D, 0x0A, 0x1A, 0x0A};
char buffer[sizeof(PngSignature)];

  iFFD.DocumentType = "PNG image";
  iFFD.Extension = iFFD.Converter = "PNG";
  iFFD.Probability=-1;
  iFFD.DocVersion=0;

  if(fread(buffer,1,sizeof(PngSignature),stream)!=8) 
    {
    fseek(stream,-(long)sizeof(PngSignature),SEEK_CUR);
    return 0;
    }
  fseek(stream,-(long)sizeof(PngSignature),SEEK_CUR);
  if(!memcmp(buffer,PngSignature,sizeof(PngSignature))) return 1;
  return(0);
}


/// This is a state machine for detecting SVG files
static int DetectSvg(FILE *text, FFormatDetect & iFFD)
{
int Status, CharNo=0, chr;

  iFFD.DocumentType="SVG";
  iFFD.Converter = iFFD.DocumentType;
  iFFD.Extension = "svg";
  if(text==NULL) return(0);

  Status=0;
  fseek(text,0,SEEK_SET);
  while(CharNo<1400)		// SVG header might be very big with comments.
	{
	if( (chr=fgetc(text)) == EOF) goto NoSVG;
	chr=toupper(chr);
	CharNo++;
	switch(Status)
		{
		case 0:if(isspace(chr)) break;
		       if(chr=='<') {Status=1;break;}
		       goto NoSVG;
		case 1:if(chr=='!') {Status=101;break;}	// !-- comment
		       if(chr=='?') {Status=101;break;}	// ?xml
		       if(chr=='S') {Status=2;break;}	// HTML tag
		       if(chr=='M') {Status=7;break;}	// META tag
		       goto NoSVG;

		case 2:if(chr=='V') {Status=3;break;}
		       goto NoSVG;
		case 3:if(chr=='G') {Status=4;break;}
		       goto NoSVG;
		case 4:if(chr=='>')
			    {
			    fseek(text,0,SEEK_SET);
			    return(2);		//SVG succesfully detected
			    }
		       Status=5;break;
		case 5:if(chr=='>')
			    {
			    fseek(text,0,SEEK_SET);
			    return(2);	//SVG succesfully detected
			    }
		       break;

		case 7:if(chr=='E') {Status=8;break;}
		       goto NoSVG;
		case 8:if(chr=='T') {Status=9;break;}
		       goto NoSVG;
		case 9:if(chr=='A') {Status=100;break;}
		       goto NoSVG;

		case 100:if(chr==' '){Status=11;break;}	// Space or TAG close.
		       if(chr=='>') {Status=0;break;}
		       goto NoSVG;

		case 101:if(chr=='>') Status=0;
		       if(chr=='[') Status=102;
		       break;
		case 102: if(chr==']') Status=101;
		      break;
		default:printf(_("Error: State automat failed at state %d\n"),Status);
			Status=0;
		}
	}

NoSVG:
  fseek(text,0,SEEK_SET);
  return(0);
}
#endif


/// This procedure provides autodetection of unicode plain text.
static int DetectUnicode(FILE *stream, FFormatDetect & iFFD)
{
uint16_t Magic1;
uint8_t Magic2,Check3;
  Rd_word(stream, &Magic1);
  Magic2=fgetc(stream);
  Check3=fgetc(stream);
  fseek(stream,-4,SEEK_CUR);

  iFFD.Extension = "TXT";
  if(Magic1 == 0xFEFF)	//This is an unicode text document
	{
	iFFD.DocumentType = "Unicode Text";
	iFFD.Converter = "UNICODE";
	return 1;
	}
  if(Magic1 == 0xFFFE)	//This is an unicode text document in High Endian
	{
	if(Magic2==0 && Check3==0) return 0;  //looks strange

	iFFD.DocumentType = "Unicode High Endian Text";
	iFFD.Converter = "HIENDUNICODE";
	return 1;
	}
  if(Magic1==0xBBEF && Magic2==0xBF)	//This is an unicode text document in UTF8
	{
	iFFD.DocumentType = "Unicode UTF8 Text";
	iFFD.Converter = "UTF8";
	return 1;
	}
  return 0;
}


/** Checks whether the given document is a valid Microsoft Word document.
 * For WORD>=8.x thich check inner OLE file  */
int DetectWord(FILE *f, FFormatDetect & iFFD)
{
uint16_t wIdent;			/* 0x0000 */
uint16_t nFib;			/* 0x0002 */
long CurrentPos;
uint32_t cbMac=0xFFFF;

  iFFD.DocumentType="Microsoft Word";
  iFFD.Converter = "WORD";
  iFFD.Extension = "DOC";

  iFFD.DocVersion = 0x800;

  CurrentPos = ftell(f);
  Rd_word(f,&wIdent);
  Rd_word(f,&nFib);

    if (wIdent == 0x37FE) iFFD.DocVersion = 0x500;
    else {	/*begin from microsofts kb q 40 */
	 if (nFib < 101)
	    {
	    iFFD.DocVersion = 0x200;
	    }
	  else
	    {
	    switch (nFib)
		  {
		  case 101: iFFD.DocVersion = 0x600; break;
		  case 103:
		  case 104: iFFD.DocVersion = 0x700; break;
		  //default:  break;
		  }
	    }	/*end from microsofts kb q 40 */
	 }

//    return (ret);
  switch(iFFD.DocVersion>>8)
     {
     case 5:fseek(f,CurrentPos,SEEK_SET);
	    return(5);
     case 6:fseek(f,CurrentPos,SEEK_SET);
	    return(6);
     case 8:fseek(f,CurrentPos+0x40,SEEK_SET);
	    Rd_dword(f,&cbMac);
	    if(feof(f))
		{fseek(f,CurrentPos,SEEK_SET);return(0);}
	    if(cbMac==FileSize(f))
		{
		fseek(f,CurrentPos,SEEK_SET);
		return(8);
		}
	    cbMac=FileSize(f);
	    break;
     }

  fseek(f,CurrentPos,SEEK_SET);
  return(0);
}


				/*(4,5,3,3,3,3,4,4,4,5,5,6,6,8,8,0);*/
uint8_t ObjWP6SizesF0[0x10] = {4, 5, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 8, 8, 0};

/* Checks whether the given document is a valid  WP5.x or WP6.x - document.
 * return: int: 0 if OK, else error code  */
int DetectWordPerfect(FILE *wpd, FFormatDetect & iFFD)
{
uint32_t id;
uint16_t filetype, ver, encryption, dmp3;
uint32_t StartDoc;
long FilePos;

  iFFD.Converter = NULL;
  iFFD.Extension = "WP";
  FilePos = ftell(wpd);
  Rd_dword(wpd, &id);
  Rd_dword(wpd,&StartDoc);
  Rd_word(wpd, &filetype);
  Rd_word(wpd, &ver);
  Rd_word(wpd, &encryption);
  Rd_word(wpd, &dmp3);
  fseek(wpd,FilePos,SEEK_SET);

  if(id == 0x435057FF)		//Standard Corell WPG Header
    {
    switch(filetype>>8)
	{
	case  0xA:iFFD.DocumentType="WordPerfect Document";break;
	case  0xB:iFFD.DocumentType="Dictionary file";break;
	case  0xC:iFFD.DocumentType="Thesaurus file";break;
	case  0xD:iFFD.DocumentType="Block";
		  RunError(0x15,iFFD.DocumentType);
		  break;
	case  0xE:iFFD.DocumentType="Rectangular Block";
		  RunError(0x15,iFFD.DocumentType);
		  break;
	case  0xF:iFFD.DocumentType="Column Block";
		  RunError(0x15,iFFD.DocumentType);
		  break;
	case 0x10:iFFD.DocumentType="Printer Resource file (.PRS)";break;
	case 0x11:iFFD.DocumentType="Setup file";break;
	case 0x12:iFFD.DocumentType="Reserved";break;
	case 0x13:iFFD.DocumentType="Printer Resource file (.ALL)";break;
	case 0x14:iFFD.DocumentType="Display Resource file (.DRS)";break;
	case 0x15:iFFD.DocumentType="Overlay file";break;
	case 0x16:iFFD.DocumentType="WordPerfect Graphics file";
                  iFFD.Extension = iFFD.Converter = "WPG";
                  iFFD.DocVersion=ver<<8;
                  if(encryption!=0) fprintf(err,_(EncryptionWarning));
                  break;
	case 0x17:iFFD.DocumentType="Hyphenation code module";break;
	case 0x18:iFFD.DocumentType="Hyphenation data module";break;
	case 0x19:iFFD.DocumentType="Macro Resource File";break;
	case 0x1A:iFFD.DocumentType="Graphics screen Driver";break;
	case 0x1B:iFFD.DocumentType="Hyphenation lex module";break;
	case 0x1C:iFFD.DocumentType="Printer Q codes (VAX/DG)";
		  RunError(0x15,iFFD.DocumentType);
		  break;
	case 0x1D:iFFD.DocumentType="Spell code module word list";break;
	case 0x1E:iFFD.DocumentType="WP5.1 equation resource file";break;
	case 0x1F:iFFD.DocumentType="Reserved";break;
	case 0x20:iFFD.DocumentType="VAX.SET";break;
	case 0x21:iFFD.DocumentType="Spell code module rules";break;
	case 0x22:iFFD.DocumentType="Dictionary rules";break;
	case 0x23:iFFD.DocumentType="Reserved";break;
	case 0x24:iFFD.DocumentType=".WPD files";
		  RunError(0x15,iFFD.DocumentType);
		  break;
	case 0x25:iFFD.DocumentType="Rhymer word file";break;
	case 0x26:iFFD.DocumentType="Rhymer word file";break;
	case 0x27:
	case 0x28:iFFD.DocumentType="Reserved";break;
	case 0x29:iFFD.DocumentType="WP5.1 ins file";
		  RunError(0x15,iFFD.DocumentType);
		  break;
	case 0x2A:iFFD.DocumentType="Mouse driver for WP5.1";break;
	case 0x2B:iFFD.DocumentType="Unix setup for WP5.0";break;
	case 0x2C:iFFD.DocumentType="Macintosh WP2,3.x document";
                  switch(ver & 0xFF)
                  {
	            case 1: if(err)
                                fprintf(err,_("\nWarning: Unknown MAC WP version 0x%x. Guessing WP%u.%u. EXPECT ERRORS!!! Please report."),ver,ver&0xFF,ver>>8);
                    case 2: 	/*   version == MAC 2 -> WP 3.x  */
                    case 3: 	/*   version == MAC 3 -> WP 3.x  */
                    case 4: 	/*   version == MAC 4 -> WP MAC4.x  */
	                   iFFD.DocVersion = (ver&0xFF)<<8 | ver>>8;
	                   iFFD.DocumentStart = StartDoc;
                           if(encryption!=0)
		           {
		             if(Verbosing>=1 && err!=NULL) 
		             fprintf(err,_(EncryptionWarning));
		             iFFD.Converter="WP3.x encrypted";
		           }
                           else
		             iFFD.Converter="WP3.x";		//Convert_pass1_WP3;
  	                   return ver & 0xFF;
	          }
                  break;
	case 0x2D:iFFD.DocumentType="VAX file WP4.0 document";
		  RunError(0x15,iFFD.DocumentType);
		  break;
	case 0x2E:iFFD.DocumentType="External spell code";break;
	case 0x2F:iFFD.DocumentType="External spell dictionary";break;
	case 0x30:iFFD.DocumentType="Macintosh soft graphics";break;

	case 0x38:iFFD.DocumentType="WPWin5.1 App Resource library";break;
        case 0x3A:iFFD.DocumentType="WP5.2 Far east";break;
	}

    if(filetype==0x3A01)
        {
    	iFFD.DocumentStart = StartDoc;
        iFFD.DocVersion=0x500 + (uint16_t)(ver>>8);
        iFFD.Converter = "WP5.FarEast";
        }

    if(filetype==0xA01)
	   /*   version == 0x0000 -> WP 5.0
	    *   version == 0x0100 -> WP 5.1
	    *   version == 0x0002 -> WP 6.0
	    *   version == 0x0102 -> WP 6.1
	    *   version == 0x0202 -> WP 7.0  */
         {
         iFFD.DocumentStart = StartDoc;
         switch(ver & 0xFF)  // major version
	   {
	   case 0:iFFD.DocVersion=0x500 + (uint16_t)(ver>>8);
		  if(encryption==0) iFFD.Converter="WP5.x";
			       else iFFD.Converter="WP5.x encrypted";
		  break;
	   case 2:iFFD.DocVersion=0x600 + (uint16_t)(ver>>8);
		  if(iFFD.DocVersion>=0x602) iFFD.DocVersion+=0xFE;
		  if(encryption==0) iFFD.Converter="WP6.x";
		  else
		    {
		    iFFD.Converter="WP6.x encrypted";
		    fprintf(err,_(EncryptionWarning));
		    }
		  break;
	   default:iFFD.DocVersion=0x500l + (uint16_t)(ver>>8) + 256*(ver & 0xFF);
		   iFFD.Converter="WP6.x";	/* Place here -FORCE warning */
		   fprintf(err,_("\nWarning: Unknown WP version 0x%x. Guessing WP%u.%u. EXPECT ERRORS!!! Please report."),ver,iFFD.DocVersion>>8,iFFD.DocVersion & 0xFF);
		   if(encryption!=0) fprintf(err,_(EncryptionWarning));
		   encryption=0;
	   }
	
	}
    /*if (filetype == 0xA20)
	{
	iFFD.Converter="WP??";
	}*/
    return 5;		/* it is a valid WP [5,6].x - document*/
    }

  if(id == 0x6161FFFE)		//This is a WP4.1 encrypted document
	{
	iFFD.DocVersion=0x401;
	iFFD.Converter = "WP4.x encrypted";  //Convert_pass1_WP4_encrypted;
	iFFD.DocumentType = "WP4.x enc";
	return 4;
	}

return 0;
}


uint8_t ObjWP4SizesC0[] =
	{6,  4,  3,  5,  5,  6,  4,  6,  8, 42,  3,  6,  4,  3,  4,  3,
	 6,  0,  0,  4,  4,  4,  6, 65,  4,  4,  4,  4,  9, 24,  4,  0,
//                                  ^0                  ^0
	 4,  3,  0,150,  6, 30, 11,  3,  3,  0,  0,  4,  0,  0, 44, 18,
//                          ^23                     ^32  4   0   4  18
	 6,106,  0,100,  4,  0,  5,  0,  0,  0,  0,  0,  0,  0,  0,  0};


uint8_t ObjWP1SizesC0[]=
	{10, 4,  4,  7,  7,  6,  4,  6,  8,  0,  3,  6,  6,  3,  6,  3,
	 6,  0,  0,  4,  4,  4,  6,  0,  4,  4,  4,  4,  0, 24,  6,  0,
	 4,  3,  0,150,  6, 23, 11,  3,  3,  0,  0, 32,  5,  0, 44, 18,
	 6,106,  0,196,  4,  0,  5,  4,  4,  8,  0,  4,  0,  0,  0,  0};


/** Common detection procedure for both WP1Mac and WP4PC. */
static int DetectWP1and4(FILE *wpd, const uint8_t *ObjWPxSizesC0)
{
long FilePos;
uint8_t w,Flag;
int WP_hit;
unsigned CharNo;

  FilePos = ftell(wpd);

  WP_hit = 0;
  CharNo = 0;
  while(!feof(wpd) && CharNo<MaxChar)
     {
     const uint8_t c = fgetc(wpd);	CharNo++;
//   printf("[%X %X]",ftell(wpd),c);

     if(c>=0xC0)
	{
	w=ObjWPxSizesC0[c-0xC0];
	if(w<=1)	// random size objects
	   {
	   while(1)
	     {
	     w=fgetc(wpd);
	     if(w==c) break;	//delimiter has been found
	     if(feof(wpd)) {WP_hit=0; break;}
	     }
	   }
	else		// fixed size objects
	   {
	   Flag=0;
	   while(w-->2)
	     {         		//detect & ignore continuous areas
	     if(fgetc(wpd)!=c) Flag=1;
	     }
	   w=fgetc(wpd);
	   if(w!=c) {WP_hit=0;break;}	//autodetection failed
	   WP_hit+=Flag;
	   if(WP_hit>2)		//attempt to cut autodetection block
	     {
	     if(ObjWP4SizesC0[c-0xC0] != ObjWP1SizesC0[c-0xC0])
		break;	//more than 2 special WP keywords found
	     }
	   }
	}
     }

  fseek(wpd,FilePos,SEEK_SET);
  return WP_hit;
}


int DetectWordPerfect4(FILE *wpd, FFormatDetect & iFFD)
{
  iFFD.DocumentType="Word Perfect";
  iFFD.Converter = "WP4.x";
  iFFD.Extension = "WP";
  iFFD.DocVersion=0x400;

  return DetectWP1and4(wpd, ObjWP4SizesC0);
}


int DetectWordPerfect1(FILE *wpd, FFormatDetect & iFFD)
{
  iFFD.DocumentType="Word Perfect";
  iFFD.Converter="WP1.x";
  iFFD.Extension = "WP";
  iFFD.DocVersion=0x100;

  return DetectWP1and4(wpd, ObjWP1SizesC0);
}


typedef int (DetectXXX)(FILE *wpd, FFormatDetect & iFFD);
/*Note detectors are sorted according to the quality of detection*/
DetectXXX *Detect[] = {
		//*****Strong tests*****
	DetectWordPerfect,DetectOLEStream,
#ifndef NO_IMG
	DetectPNG,
#endif
		//++++Weak Tests++++
	DetectBMP,
	DetectUnicode,DetectPostScript,DetectHtml,
#ifndef NO_IMG
	DetectSvg,
#endif
	DetectXML, DetectDocbook,
	DetectAccent,DetectRTF,DetectMTEF,DetectWord,DetectWinMetafile,
	DetectWordPerfect4,DetectWordPerfect1,DetectT602
	};


//void (*Convert_first_pass)(FILE *FileIn,FILE  *table, FILE *StripOut,FILE *LogFile,FILE *ErrorFile);


int CheckFileFormat(FILE *wpd, FFormatDetect & FilForD)
{
int i;
FFormatDetect iFFD;
float Probability;

  FilForD.DocumentType = "Unknown type";
  FilForD.Converter = "";
  FilForD.Extension = NULL;
  FilForD.DocVersion = 0;
  FilForD.Probability = -1;
  FilForD.DocumentStart = 0;
  iFFD = FilForD;

  if(wpd==NULL) return(0);

  for(i=0; i<sizeof(Detect)/sizeof(DetectXXX *); i++)
     {
     iFFD.DocumentStart = 0;
     if((Probability=Detect[i](wpd,iFFD))>0)
	{
	if(Probability==FilForD.Probability)
	  {
	  if(err)
            fprintf(err,_("\nWarning: two file formats hit %s and %s, please use -FORCE."),FilForD.Converter,iFFD.Converter);
	  }

	if(Probability>FilForD.Probability)
	  {
	  FilForD = iFFD;
          FilForD.Probability = Probability;
	  }
	}
     }

  if(FilForD.Probability>=0)
    {
    fseek(wpd,FilForD.DocumentStart,SEEK_SET);
    return(1);
    }

  return 0;         /* it may be a valid WP4.x || WP1.x document - but error is reported*/
}


#define L1_5cm          709   /*length of 1.5 cm*/
#define L1_27cm         600   /*length of 1.27 cm*/

/*This procedure initialises all common fields inside conversion structure*/
void Initialise_Conversion(TconvertedPass1 *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#Initialise_Conversion() ");fflush(cq->log);
#endif
long j;

  cq->RequiredFont=cq->Font = FONT_NORMAL;
  cq->FirstSection = 120;
  cq->recursion = 0;
  cq->flag = NormalText;

  cq->latex_tabpos = 0;
  cq->tab_type   = 0;
  cq->CentrePage = false;

  cq->indenting = false;
  cq->indent_end = false;
  cq->ind_text1 = false;
  cq->char_on_line = false;              //!!!!!!
  cq->ind_leftmargin = 0;
  cq->ind_rightmargin = 0;
  cq->Columns = 0;

		// Default sizes of the document
  cq->WP_sidemargin = 1200;
  cq->Lmar = 1890;
  cq->Rmar = 1200;

		// Default tab sets
  cq->tabpos[0] = L1_27cm;   /* 1e WP-tab is kantlijn --> */
  for(j=2; j<=10; j++)   /* Size of tabs is 1,27  cm  */
	cq->tabpos[j-1] = cq->tabpos[j-2] + L1_27cm;
  for(j=10; j<=39; j++)   /* ($02c5 wpu) verder        */
	cq->tabpos[j] = 0xffffL;

  cq->num_of_tabs = 10;
  cq->nomore_valid_tabs = false;

  cq->envir=' ';
  cq->rownum=0;

  cq->NativeCpg = cq->ConvertCpg = NULL;
}

#undef L1_5cm
#undef L1_27cm


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

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

  cq->line_term = 's';			   /* Soft return */
  Make_tableentry_envir_extra_end(cq);
  if(cq->CentrePage)    /* finish page centering */
	{
	fprintf(cq->strip, "\\vfil ");
	cq->CentrePage=false;
	}

  num_of_lines_stripfile = cq->rownum;

  if(Verbosing >= 1)		//finishing a procentage counter
     {
     cq->perc.SetPercent(100);
     }
}


/** Emit error if next exgument exceeds argument list. */
int CheckArg(int & p, int argc, const char *arg=NULL)
{
  if(++p>=argc)
    {
    if(err)
      {
      Heading();
      fprintf(err,_("\nMissing argument%s%s!"),
        (arg==NULL)?"":" ",
	(arg==NULL)?"":arg);
      }
    return 0;  
    }
return 1;  
}


typedef struct
{
  const char *Name;
  int8_t      *Flag;
  const char *Description;
} PkgItem;

/** Package list with command line switches. */
static const PkgItem PkgList[] = 
	{{"accents",&Accents, N_("Use accents to support additional accents.")},
        {"amssymb",&Amssymb,NULL},
        {"Amssymb",&Amssymb, N_("Use AMSsymb with special characters.")},
	{"arevmath",&Arevmath,NULL},
        {"Arevmath",&Arevmath, N_("Use arevmath with special characters.")},
        {"amsmath",&AmsMath,NULL},
        {"AmsMath",&AmsMath, N_("Use AmsMath with special characters.")},
        {"bbm",&Bbm,NULL},
        {"Bbm",&Bbm, N_("Use Bbm with special characters.")},
        {"cjhebrew",&cjHebrew}, {"cjHebrew",&cjHebrew},
        {"cyrillic",&Cyrillic,NULL},
        {"Cyrillic",&Cyrillic, N_("Use cyrillic.sty to support cyrillic script.")},
        {"endnotes",&EndNotes,NULL},
        {"Endnotes",&EndNotes},
        {"fancyhdr",&FancyHdr}, {"Fancyhdr",&FancyHdr},   {"FancyHdr",&FancyHdr},
        {"fontenc-T1",&fontenc, NULL},
        {"FontEnc-T1",&fontenc, N_("Use package fontenc.sty [T1] with additional characters")},
        {"LaTeXsym",&LaTeXsym,NULL},
        {"latexsym",&LaTeXsym, N_("Use latexsym with special characters.")},
        {"LineNo", &LineNo,NULL},
        {"lineno", &LineNo},
        {"longtable",&LongTable,NULL},
        {"LongTable",&LongTable, N_("Use longtable for better tables.")},
        {"makeidx",&MakeIdx,NULL},   
        {"MakeIdx",&MakeIdx, N_("Use makeidx for placing index.")},
        {"mxedruli",&mxedruli, N_("Use mxedruli for Georgia characters.")},
        {"pifont",&pifont,NULL},
        {"PiFont",&pifont, N_("Use additional package pifont.")},
        {"rsfs",&Rsfs,NULL},
        {"Rsfs",&Rsfs, N_("Use mathrsfs with special characters.")},
        {"scalerel",&Scalerel, N_("Use additional package scalerel.")},
        {"tipa",&TIPA,NULL},
        {"TIPA",&TIPA, N_("Use TIPA.sty for IPA and other phonetic characters")},
        {"ulem",&Ulem,NULL},
        {"Ulem",&Ulem, N_("Use ulem for underlining and striking out.")},
        {"wasy",&Wasy,NULL},
        {"Wasy",&Wasy,N_("Use Wasy2 with special characters.")}};


static char StyleUsed(int8_t *u)
{
  if(u==NULL) return ' ';
  if(*u<=-1) return '-';
  if(*u>=+1) return '+';
return '*';
}

void PrintPackageList(void)
{
  printf(_("\nAdditional package list: (-disabled, +always, *used when necessary)"));
  for(int i=0; i<sizeof(PkgList)/sizeof(PkgItem); i++)
  {
    if(PkgList[i].Description==NULL) continue;
    printf("\n   -%s \t%c%s", PkgList[i].Name, StyleUsed(PkgList[i].Flag),
         _(PkgList[i].Description));
  }
}


/// See which CPs are supported by inputenc: https://ctan.math.illinois.edu/macros/latex/base/inputenc.pdf
const TOutCodePage OutCodepages[11] =
{
  {"852", "internalTOcp852", 852, true},
  {"866", NULL, 866, false},
  {"895", NULL, 895, false},
  {"1250", "internalTOcp1250", 1250, true},
  {"1251", NULL,1251, false},
  {"ISO8859-1", "internalTOiso_8859_1", ISO8859_1, true},
  {"ISO-8859-1", "internalTOiso_8859_1", ISO8859_1, true},
  {"ISO8859-2", "internalTOiso_8859_2", ISO8859_2, true},
  {"ISO-8859-2", "internalTOiso_8859_2", ISO8859_2, true},
  {"KOI8R", NULL, KOI8R, false},
  {"UTF8", "internalTOunicode", UTF8, true}
};


/** This procedure handles parameters and the filenames*/
int CommandLine(int argc, char *argv[])
{
const char *ArgName, *name;
int p;

  //wpd_filename = ""; 		removed to allow multiple commandline call
  //latex_filename = "";

  for(p=1; p<argc; p++)
    {
    ArgName = argv[p];
    if(ArgName==NULL || *ArgName==0) continue;
    name = ArgName;

    if(name[0]=='-' || name[0]=='/')
      {
      name++;

      int i;
      for(i=0; i<sizeof(PkgList)/sizeof(PkgItem); i++)
        {
        if(!strcmp(name, PkgList[i].Name)) break;
        }
      if(i<sizeof(PkgList)/sizeof(PkgItem))
        {
        *(PkgList[i].Flag) = false;	// alias 0
        continue;
        }      
    
      if(!strcmp(name, "configfile")||!strcmp(name, "@"))
		{
		if(CheckArg(p,argc,argv[p]))
		    {
		    LoadConfigFile(argv[p]);
		    }
		continue;
		}

      if(!strcmp(name, "copyright") || !strcmp(name, "-copyright"))
	   {
	   Heading();
           ShowCopyright();
	   RunError(-2); return(0);
	   }

      if(!strncmp(name, "cp",2))
	  {
	  name += 2;
	  if(*name=='-') name++;
	  if(*name==0)
	    {
	    if(!CheckArg(p,argc,argv[p])) continue;
	    name = argv[p];
	    }

          for(i=0; i<sizeof(OutCodepages)/sizeof(TOutCodePage); i++)
	      {
              if(!strcmp(name, OutCodepages[i].Name))
	        {
	        OutCodePage = OutCodepages[i].Id;
		if(OutCodepages[i].Translator)
		  Convert2Target = GetTranslator(OutCodepages[i].Translator);
		CPStyles = OutCodepages[i].UseCpStyles;
                break;	      
                }
	      }
          if(i<=sizeof(OutCodepages)/sizeof(OutCodePage)) continue;	// Output codepage has been found.
	  
	  if(!strcmp(name, "Styles") || !strcmp(name, "styles"))
	     {
	     CPStyles = true;
	     continue;
	     }
	  OutCodePage = 0;
	  Heading();
	  printf(_("Warning: Unknown output codepage \"%s\"!"),name);
	  continue;
	  }
      if(!strcmp(name, "epsfig"))
	  {
	  InputPS = IMG_epsfig;
	  continue;
	  }
      if(!strcmp(name, "extract-images")||!strcmp(name, "extractImages")||!strcmp(name, "extractimages")||!strcmp(name, "Extract-Images"))
	  {
	  SaveWPG = 1;
	  continue;
	  }
      if(!strcmp(name, "extractWPG")||!strcmp(name, "extract-WPG")||!strcmp(name, "extract-wpg")||!strcmp(name, "Extract-WPG"))
	  {
          if(err!=NULL)
            fprintf(err,"\n-extract-WPG is deprecated, use -extract-images instead.");
	  SaveWPG = 1;
	  continue;
	  }

      if(!strcmp(name, "CurrentFontSet"))
	  {
	  if(CheckArg(p,argc,argv[p]))
	    {
	    string CFSconverter(argv[p]);
            CFSconverter += "TOinternal";
            UserWPCharSet = GetTranslator(CFSconverter());
	    if(UserWPCharSet==NULL)
	      {
	      if(err!=NULL)
                fprintf(err,_("Warning, cannot get code page translator \"%s\"."), CFSconverter());
	      }
	    }
	  continue;
	  }

      if(!strcmp(name, "fig-output-dir")||!strcmp(name, "figoutputdir"))
	  {
	  if(CheckArg(p,argc,argv[p]))
	    {
	    RelativeFigDir = argv[p];
	    }
	  continue;
	  }
      if(!strcmp(name, "-fix-spaces")||!strcmp(name, "-fixspaces"))
	  {
	  FixSpaces = true;
	  continue;
	  }
      if(!strncmp(name, "force",5))
	  {
	  if(name[5]==0)
            {
	     if(CheckArg(p,argc,argv[p]))
	         force = argv[p];
            }
            else
            {
            if(name[5]=='-') force=name+6;
	                else force=name+5;
            }
	  continue;
	  }
      if(!strncmp(name, "FORCE",5))
	  {
	    if(name[5]==0)
              {
	      if(CheckArg(p,argc,argv[p]))
		    FORCE = argv[p];
	      }
	    else
              {                     
	      if(name[6]=='-') FORCE=name+6;
			  else FORCE=name+5;
              }
	    continue;
	    }
      if(!strcmp(name, "graphics"))
	    {
	    InputPS = IMG_graphics;
	    continue;
	    }
      if(!strcmp(name, "graphicx"))
		{
		InputPS = IMG_graphicx;
		continue;
		}
      if(!strcmp(name, "charset1"))
		{
		WPcharset = 1;
		continue;
		}
      if(!strcmp(name, "charsetCZ") || !strcmp(name, "charsetCS"))
		{
		WPcharset = 2;
		continue;
		}

      if(!strcmp(name, "ignore-tabs") || !strcmp(name, "ignoretabs"))
		{
		TABs = false;
		continue;
		}
      if(!strcmp(name, "image-path")||!strcmp(name, "imagepath"))
		{
		if(CheckArg(p,argc,argv[p]))
		  ImgInputDirs |= argv[p];
		continue;
		}
      if(!strcmp(name, "input-PS") || !strcmp(name, "inputPS"))
		{
		InputPS = IMG_InputPS;
		continue;
		}
      if(!strcmp(name, "L"))
		{
		if(CheckArg(p,argc,argv[p]))
		    {
#ifdef __gettext__
		    string StrName(EnvLanguage);
		    StrName += argv[p];
		    putenv(StrName.ExtractString()); //The string must not be released!!!
#endif //__gettext__
		    }
		continue;
		}

      if(!strcmp(name, "LaTeX2") || !strcmp(name, "latex2") || !strcmp(name, "latex209"))
		{
		LaTeX_Version=0x209;
		Amssymb=-1;
		if(Columns==1) Columns=0;
		continue;
		}
      if(!strcmp(name, "LaTeX3") || !strcmp(name, "latex3"))
		{
		LaTeX_Version=0x300;
		continue;
		}      
#ifdef _has_MemStreams
      if(!strcmp(name, "memstream")||!strcmp(name, "MemStream"))
		{
		UseMemStream = true;
		continue;
		}
#endif
      if(!strcmp(name, "NFSS")||!strcmp(name, "nfss"))
		{
		NFSS = true;
		continue;
		}

      if(!strncmp(name, "no",2))
        {
	name += 2;

		// check list of packages.
        if(*name=='-')		// -no-
          {
          name++;

            {
            int i;
            for(i=0; i<sizeof(PkgList)/sizeof(PkgItem); i++)
              {
              if(!strcmp(name, PkgList[i].Name)) break;
              }
            if(i<sizeof(PkgList)/sizeof(PkgItem))
              {
              *(PkgList[i].Flag) = -1;		// disable package
              continue;
              }
            }
             

	  if(!strncmp(name, "lang",4))
            {
	    int lng;
	    name += 4;
	    if(*name=='-') name++;	    	// -no-lang-

	    for(lng=0; lng<sizeof(LangTable)/sizeof(LangItem); lng++)
	      {
              if(!strcmp(name,LangTable[lng].LangDesc))
	        {
	        LangTable[lng].UseLang = -1;
	        break;
	        }
	      }
            if(lng >= sizeof(LangTable)/sizeof(LangItem))
              {
                if(err!=NULL)
                  fprintf(err,_("\nLanguage \"%s\" not present."),name);
              }
            continue;
	    }

          if(!strcmp(name, "interactive"))
            {
            Interactive = false;
            continue;
            }
          }	// end of -no-

        if(!strcmp(name, "clobber"))		// accepts -no-clobber and -noclobber
              {
              Noclobber = true;
              continue;
              }
	if(!strcmp(name, "erase-strip")||!strcmp(name, "erasestrip")) /*-no-erase-strip*/
	      {
	      EraseStrip = false;
	      continue;
	      }
        if(!strcmp(name, "extract-images")||!strcmp(name, "extractImages")||!strcmp(name, "extractimages")) /*-no-extract-WPG*/
		{
		SaveWPG = -1;
		continue;
		}
	if(!strcmp(name, "extract-WPG")||!strcmp(name, "extractWPG")||!strcmp(name, "extractwpg")) /*-no-extract-WPG*/
		{
                if(err!=NULL)
                  fprintf(err,_("\n-no-extract-WPG is deprecated, use -no-extract-images instead."));
		SaveWPG = -1;
		continue;
		}
	if(!strcmp(name, "fix-spaces")||!strcmp(name, "fixspaces")) /*-no-fix-spaces*/
		{
		FixSpaces = false;
		continue;
		}
	if(!strcmp(name, "columns")||!strcmp(name, "Columns")) /*-no-columns*/
		{
		Columns = -1;
		continue;
		}
	if(!strcmp(name, "inputPS")||!strcmp(name, "InputPS")) /*-no-inputPS*/
		{
		InputPS = -1;
		continue;
		}
#ifdef _REENTRANT
	if(!strcmp(name, "jobs")||!strcmp(name, "Jobs")) /*-no-jobs*/
		{
		Job4Run = 0;
		continue;
		}
#endif
	if(!strcmp(name, "NFSS")||!strcmp(name, "nfss")) /*-no-NFSS*/
		{
		NFSS = false;
		continue;
		}
	if(!strcmp(name, "optimize-section")||!strcmp(name, "optimizesection")||!strcmp(name, "Optimize-Section"))
		{
		OptimizeSection = false;
		continue;
		}
	if(!strcmp(name, "safemode")||!strcmp(name, "safe-mode")) /*-no-safemode*/
		{
		ExtendedCheck = false;
		continue;
		}
	if(!strcmp(name, "texchars")||!strcmp(name, "TeXchars")) /*-no-texchars*/
		{
		TexChars = false;
		continue;
		}
	if(!strcmp(name, "textcomp")) /*-no-textcomp*/
		{
		textcomp = -1;
		continue;
		}
	if(!strcmp(name, "undoredo") || !strcmp(name, "UndoRedo")) /*-no-undoredo*/
		{
		UndoRedo = false;
		continue;
		}
	  	// enf of "-no-lang" else branch


	name = ArgName + 1;
	}	// enf of "-no"

      if(!strcmp(name, "optimize-section")||!strcmp(name, "optimizesection"))
	   {
	   OptimizeSection = true;
	   continue;
	   }
		
      if (!strncmp(name, "rus-yo",6))
	    {
	    name += 6;
	    if(*name=='-') name++;
	    if(!strcmp(name, "no"))
		rus_yo=-1;
	    if(!strcmp(name, "TeX") || !strcmp(name, "tex") )
		rus_yo=1;
	    if(*name==0) rus_yo=0;
	    continue;
	    }
		
      if (!strcmp(name, "texchars"))
		{
		TexChars = true;
		continue;
		}
      if (!strcmp(name, "textcomp"))
		{
		textcomp = true;
		continue;
		}
      if (!strcmp(name, "safemode"))
		{
		ExtendedCheck = true;
		continue;
                }
      if (!strcmp(name, "s"))
      		{
		if(CheckArg(p,argc,argv[p]))
		    {
		    wpd_password = argv[p];
		    }
		continue;
		}
      if(!strcmp(name, "S") || !strcmp(name, "Silent") || !strcmp(name, "silent"))
		{
		Verbosing = 0;
		continue;
		}
      if(!strcmp(name, "SS") || !strcmp(name, "SSilent") || !strcmp(name, "ssilent"))
		{
		Verbosing = -1;
		continue;
		}
      if(!strcmp(name, "V") || !strcmp(name, "Verbose") || !strcmp(name, "verbose"))
		{
		Verbosing = 2;
		continue;
		}    
      if(!strcmp(name, "undoredo") || !strcmp(name, "UndoRedo"))
		{
		UndoRedo = true;
		continue;
		}
      if(!strcmp(name, "use-all") || !strcmp(name, "useall"))
		{
		Amssymb = false;
                AmsMath = false;
		Bbm = false;
		Columns = 1;	/*-1 disabled; 0 auto two; 1 auto multi; 2 forced two; >2 forced multi*/
		EndNotes = false;
		fontenc = false;
		if(InputPS<0) InputPS = IMG_graphics;
		TIPA = false;
		LaTeXsym = false;
                LineNo = false;
		pifont = false;
		PostScript = false;
		Rsfs = false;
		textcomp = false;
		Ulem = false;
		Wasy = false;
		continue;
		}
      if(!strcmp(name, "v"))
		{
		fprintf(err,_("wp2latex %s   %s\n  modules:("), VersionWP2L, VersionDate);
		FFormatTranslator *Fx;
		Fx = FFormatTranslator::first();
		while(Fx!=NULL)
		  {
		  fprintf(err, (Fx->next()==NULL)?"%s":"%s,", Fx->shortkey());
		  Fx = Fx->next();
		  }
		fprintf(err,")\n");
		TImageFileHandler *LoadPicture_XXX;
	        fprintf(err,_("  Supported Image formats:"));
	        for(LoadPicture_XXX=TImageFileHandler::first();LoadPicture_XXX!=NULL;LoadPicture_XXX=LoadPicture_XXX->next())
		    {
		    if(LoadPicture_XXX->LoadPicture!=NULL || LoadPicture_XXX->SavePicture!=NULL)
		      fprintf(err,"%s[%s%s]%s", LoadPicture_XXX->extension(),
		         LoadPicture_XXX->LoadPicture==NULL?"":"R",
		         LoadPicture_XXX->SavePicture==NULL?"":"W",
                         LoadPicture_XXX->next()==NULL?"":"; ");
		    }
	        fprintf(err,"\n");
#ifdef CORELEFT
		fprintf(err,"  free memory %ld\n",CORELEFT());
#endif
#if __BORLANDC__ == 0x0551
		fprintf(err,_("  Compiled by free Borland C++ compiler r 5.5\n"));
#endif
#ifdef DEBUG
		fprintf(err,_("*** Debugging build ***\n"));
#endif
		RunError(-1);     return(0);
		}

      if(!strcmp(name, "-help") || !strcmp(name, "?") || !strcmp(name, "help"))
	   {
#ifdef __gettext__
           CheckGettext(argv==NULL?NULL:*argv, "wp2latex");
#endif
	   Heading();
	   ShowHelp();
	   RunError(-2); return(0);
	   }

      if(!strcmp(name, "i"))
	  {
	  if(CheckArg(p,argc,argv[p]))
	    wpd_filename = argv[p];
	  continue;
	  }
      if(!strcmp(name, "o"))
	  {
	  if(CheckArg(p,argc,argv[p]))
	    {
	    latex_filename = argv[p];
	    if(latex_filename == '-') Verbosing = 0; /*disable messages to stdout*/
	    }
	  continue;
	  }
      if(!strcmp(name, "l"))
	  {
	  if(CheckArg(p,argc,argv[p]))
	    {       
	    log_filename = argv[p];
	    }
	  else  // ask for logfile
	    {
            if(length(wpd_filename)>0)
              {
              log_filename = copy(wpd_filename,0,
		      GetExtension(wpd_filename()) - wpd_filename()) + ".log";              
              }
            if(Interactive)
	        GetLogFileName(log_filename);
	    }
	  continue;
	  }
      
      name = ArgName;
      if(name[0]=='-') goto UnknownArg;
      }


    if(wpd_filename.isEmpty())
       {
       wpd_filename = name;
       continue;
       }
    if(latex_filename.isEmpty())
       {
       latex_filename = name;
       continue;
       }

UnknownArg:
    Heading();
    fprintf(err,_("Warning: Unknown argument \"%s\"!"),chk(name));
  }

  if(latex_filename == '-') Verbosing=0;

  if(Amssymb>=STYLE_NOTUSED && LaTeX_Version<0x300)
	fprintf(err,_("\nWarning: Package \"amssymb\" should not be used in LaTeX 2.09!"));

  //StrName = getenv("LANGUAGE");  ?? Na co to tu je ??
return(0);
}


/** This class is a container for converter modules */
FFormatTranslator *FFormatTranslator::First=NULL;
FFormatTranslator::FFormatTranslator(const char *NewShortKey,Factory_Pass1 NewFactory)
{
 ShortKey=NewShortKey;
 Factory=NewFactory;

 Next=First;
 Previous=NULL;
 First=this;
 if(Next!=NULL) Next->Previous=this;
}

FFormatTranslator::~FFormatTranslator(void)
{
 if(First==this)
	{
	First=Next;
	if(Next!=NULL) Next->Previous=NULL;
	return;
	}
 if(Next!=NULL) Next->Previous=Previous;
 if(Previous==NULL) return; //Error
 Previous->Next=Next;
}

TconvertedPass1 *GetConverter(const char *ShortKey)
{
FFormatTranslator *Fx;

if(ShortKey==NULL) return(NULL);
Fx=FFormatTranslator::First;
while(Fx!=NULL)
  {
  if(!strcmp(Fx->ShortKey,ShortKey))
	{
	if(Fx->Factory==NULL) return NULL;
	return(Fx->Factory());
	}
  Fx=Fx->Next;
  }
return(NULL);
}

/* End of WP2L_LIB */
