/*
Copyright (c) 1993-2008, Cognitive Technologies
All rights reserved.

Разрешается повторное распространение и использование как в виде исходного кода,
так и в двоичной форме, с изменениями или без, при соблюдении следующих условий:

      * При повторном распространении исходного кода должны оставаться указанное
        выше уведомление об авторском праве, этот список условий и последующий
        отказ от гарантий.
      * При повторном распространении двоичного кода в документации и/или в
        других материалах, поставляемых при распространении, должны сохраняться
        указанная выше информация об авторском праве, этот список условий и
        последующий отказ от гарантий.
      * Ни название Cognitive Technologies, ни имена ее сотрудников не могут
        быть использованы в качестве средства поддержки и/или продвижения
        продуктов, основанных на этом ПО, без предварительного письменного
        разрешения.

ЭТА ПРОГРАММА ПРЕДОСТАВЛЕНА ВЛАДЕЛЬЦАМИ АВТОРСКИХ ПРАВ И/ИЛИ ДРУГИМИ ЛИЦАМИ "КАК
ОНА ЕСТЬ" БЕЗ КАКОГО-ЛИБО ВИДА ГАРАНТИЙ, ВЫРАЖЕННЫХ ЯВНО ИЛИ ПОДРАЗУМЕВАЕМЫХ,
ВКЛЮЧАЯ ГАРАНТИИ КОММЕРЧЕСКОЙ ЦЕННОСТИ И ПРИГОДНОСТИ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ, НО НЕ
ОГРАНИЧИВАЯСЬ ИМИ. НИ ВЛАДЕЛЕЦ АВТОРСКИХ ПРАВ И НИ ОДНО ДРУГОЕ ЛИЦО, КОТОРОЕ
МОЖЕТ ИЗМЕНЯТЬ И/ИЛИ ПОВТОРНО РАСПРОСТРАНЯТЬ ПРОГРАММУ, НИ В КОЕМ СЛУЧАЕ НЕ
НЕСЁТ ОТВЕТСТВЕННОСТИ, ВКЛЮЧАЯ ЛЮБЫЕ ОБЩИЕ, СЛУЧАЙНЫЕ, СПЕЦИАЛЬНЫЕ ИЛИ
ПОСЛЕДОВАВШИЕ УБЫТКИ, СВЯЗАННЫЕ С ИСПОЛЬЗОВАНИЕМ ИЛИ ПОНЕСЕННЫЕ ВСЛЕДСТВИЕ
НЕВОЗМОЖНОСТИ ИСПОЛЬЗОВАНИЯ ПРОГРАММЫ (ВКЛЮЧАЯ ПОТЕРИ ДАННЫХ, ИЛИ ДАННЫЕ,
СТАВШИЕ НЕГОДНЫМИ, ИЛИ УБЫТКИ И/ИЛИ ПОТЕРИ ДОХОДОВ, ПОНЕСЕННЫЕ ИЗ-ЗА ДЕЙСТВИЙ
ТРЕТЬИХ ЛИЦ И/ИЛИ ОТКАЗА ПРОГРАММЫ РАБОТАТЬ СОВМЕСТНО С ДРУГИМИ ПРОГРАММАМИ,
НО НЕ ОГРАНИЧИВАЯСЬ ЭТИМИ СЛУЧАЯМИ), НО НЕ ОГРАНИЧИВАЯСЬ ИМИ, ДАЖЕ ЕСЛИ ТАКОЙ
ВЛАДЕЛЕЦ ИЛИ ДРУГОЕ ЛИЦО БЫЛИ ИЗВЕЩЕНЫ О ВОЗМОЖНОСТИ ТАКИХ УБЫТКОВ И ПОТЕРЬ.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of the Cognitive Technologies nor the names of its
      contributors may be used to endorse or promote products derived from this
      software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "nt_types.h"
#include "struct.h"
#include "cstr.h"
#include "func.h"

#include "linear.h"

#ifdef _BAL_VERSION_   // Nick 10.02.2001

#include "bal.h"

extern BYTE fax1x2;
extern Word8 language;
extern BYTE multy_language;

extern Word16 actual_resolution;
extern BOOL   line_BL;
extern Word8  spec_camera;
extern Word8  no_linpen;
extern Int16  prop_l_delta, prop_r_delta;
extern Word8  db_pass;

extern Word8 *letters_pidx_table;  // 512
extern Word8 decode_ASCII_to_[256][4];


INT     minrow,mincol, maxrow, maxcol;
INT     bs_got=0;     // in baton.c - LONG - error!?

INT			  bbs0,bbs1, bbs2, bbs3, bbs4, bbsm;  // bbst,
INT           bsdust_upper, bsdust_lower, bsdust_ps;
INT           Nb1, Nb2, Nb3, Nb4, Nbt, Ps, Psf;
BYTE          multi_bas;

INT           Ns1=0,Ns2=0;        // in Iot.c   only  !!!
//INT           pen_up;         // for otladka 't' in St_tools.c

BYTE          let_to_dust=0;

CHAR          all_caps=0;
CHAR          all_diffs_made=0;
CSTR_line     lin_str=(CSTR_line)NULL;     // pass3.c only

CHAR          dust_in = 0;

static BAL_bas_ln all_bases[32];

// Linpon.c
INT sMALL_SIZE=SMALL_SIZE;

INT obtain_diff(INT arg);

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

INT get_bsm()
 { return (bbsm+minrow); }
/////////
INT def_locbas(cell *cl)
{
 BAL_bas_ln *bc, *bn, *bsp;
 INT i, x, y, dc, dn;
 Word8 fl_defb;

 if ((multi_bas & 128) == 0)
   goto retps;  // multiple bases not set

 if (cl==NULL)
 {
   bc=all_bases;
   goto make;
 }
 x=cl->col;
 y=x+cl->w/2;
 for (i=0, bc=all_bases, bn=bc+1; i<32; i++, bc++,bn++)
 {
  if (y <= bc->endcol)  break;
  if (bn->endcol==32000) break;
  if (x >= bn->startcol) continue;
  if ((dc=x-bc->endcol)<=0) break;
  if ((dn=bn->startcol-y)<=0) { bc=bn; break; }
  if (dc<=dn) break;
  bc=bn;
  break;
 }
make:
 bsp=bc;
 Ps   = bsp->ps;
 bbs1 = bsp->b1;
 bbs2 = bsp->b2;
 bbs3 = bsp->b3;
 bbs4 = bsp->b4;
 Ps = bbs3-bbs2;    //?????????????? 940119 ????
 if (Ps <= 0)
 {
   Ps = 1;
   bbs2 = bbs3-1;
 }
 bbsm = (bbs2+bbs3)/2;
 fl_defb = bsp->fl_def;
 Nb1 = (fl_defb & c_db_b1)? bsp->n1 : -1;
 Nb2 = (fl_defb & c_db_b2)? bsp->n2 : -1;
 Nb3 = (fl_defb & c_db_b3)? bsp->n3 : -1;
 Nb4 = (fl_defb & c_db_b4)? bsp->n4 : -1;
 if (Nb1==0) Nb1=-1;
 if (Nb2==0) Nb2=-1;
 if (Nb3==0) Nb3=-1;
 if (Nb4==0) Nb4=-1;
 all_caps = fl_defb & c_fdef_cap;

retps:
 Psf = Ps;
 if (fax1x2) Psf += 3;  // AL 940329 was +2 TWICE ??!!

 return Ps;
}
//////////
void get_b_lines(cell *C, B_LINES *bas)
 {
 INT dif;

 if (C)
 {
   def_locbas(C);
   if (all_diffs_made)    // are all diffs already defined ?
   {
     dif = C->bdiff;
     if (C->difflg & (c_db_down + c_db_up))
	 {
//       if (C->difflg & c_db_up)   dif --;     // restore proper
//       else          dif ++;     // base diff without corrections
//   // Nick - 16.03.2001 - accord to  set c_db_up,down !
       if (C->difflg & c_db_up)   dif ++;     // restore proper
       else          dif --;     // base diff without corrections
	 }
   }
   else      // diff not defined yet
     dif = obtain_diff(C->col);
   dif += minrow;
 }
 else
 {
   def_locbas(NULL);
   dif=minrow;
 }

 if (Ps <= 0)
 {
   Ps = 1;
   bbs2 = bbs3-1;
 }
 if (bbs2 >= bbs3)
   bbs2 = bbs3-1;
 if (bbs1 >= bbs2)
   bbs1 = bbs2-1;
 if (bbs4 <= bbs3)
   bbs4=bbs3+1;
 bas->ps = bbs3-bbs2; //////////?????????? 940119 ???
 bas->b0=bbs0+minrow;
 bas->b1=bbs1+dif;
 bas->b2=bbs2+dif;
 bas->b3=bbs3+dif;
 bas->b4=bbs4+dif;
 bas->bm=bbsm+dif;
 bas->n1=Nb1;
 bas->n2=Nb2;
 bas->n3=Nb3;
 bas->n4=Nb4;
 }
///////////////////////////
LONG get_size()                                                   //16.01.97
 { if (multi_bas & 128)
      def_locbas(NULL);
   return (LONG) Ps;                                              //16.01.97
 }
///////////////////////
//
// from linutil.c
#include "ligas.h"      // Pit 10-10-94 03:56pm

/*============= Func prototypes ==================*/

BYTE to_lower(BYTE c);
BYTE to_upper(BYTE c);
INT  is_lower(BYTE ch);
INT  is_upper(BYTE ch);
INT  isletter(BYTE ch);
BYTE get_homot(BYTE ch);
INT  draft_cut_hyps(INT bs,INT fl);

/*============= Source code ============*/
BOOL is_liga_ff(BYTE c)
{
// Код лиги определен через макру в ligas.h 05.09.2000 E.P.
  return (c==liga_ff);
}
BOOL is_liga_ffl(BYTE c)
{
// Код лиги определен через макру в ligas.h 05.09.2000 E.P.
  return (c==liga_ffl);
}

INT is_russian(BYTE ch)
{
if( language==LANG_RUSSIAN || language==LANG_ENGLISH && multy_language )
switch(fEdCode){
  case ED_ASCII: // for ASCII
   if((ch >=(BYTE)' ' && ch <=(BYTE)'Ї') ||
      (ch >=(BYTE)'а' && ch <=(BYTE)'п') ||
      (ch >=(BYTE)'Ђ' && ch <=(BYTE)'џ') ||
       memchr("рсхчшэИА",ch,8)
     ) return 1;
  break;
  case ED_WIN: // for Windows (ANSI)
      if( (ch >=0xE0 && ch <=0xFF)||(ch >=(BYTE)'Ђ' && ch <=(BYTE)'џ'))
        return 1;
  break;
  case ED_MAC: // for Macintosh
      if(
       (ch >=0xE0 && ch <=0xFE) || ch == 0xDF || (ch >= 0xC0 && ch <= 0xDF)
        ) return 1;
  break;
        }
return 0;
}

INT is_english(BYTE ch)
{
return (ch >= 'a' && ch <= 'z')||(ch >= 'A' && ch <= 'Z')||
       (
//	   ch>=ligas_beg && ch<=ligas_end &&
	   is_liga(ch) &&  // 14.09.2000 E.P.

	   ch!=liga_exm && ch!=liga_qm )
	   ;
}

INT is_serbian_special(BYTE ch)
{
return (ch == SERB_j  ||   ch == SERB_J  ||
        ch == SERB_n  ||   ch == SERB_N  ||
        ch == SERB_l  ||   ch == SERB_L  ||
        ch == SERB_h  ||   ch == SERB_H  ||
        ch == SERB_hh ||   ch == SERB_HH ||
        ch == SERB_u  ||   ch == SERB_U  );

}

INT is_polish_special(BYTE ch)
{
return (ch == POLISH_SS  ||   ch == POLISH_s  ||
        ch == POLISH_ZZD ||   ch == POLISH_zd ||
        ch == POLISH_ZZR ||   ch == POLISH_zr ||
        ch == POLISH_LL  ||   ch == POLISH_l  ||
        ch == POLISH_AA  ||   ch == POLISH_a  ||
        ch == POLISH_CC  ||   ch == POLISH_a  ||
        ch == POLISH_NN  ||   ch == POLISH_n  ||
        ch == POLISH_EE  ||   ch == POLISH_e  ||
        ch == POLISH_OO  ||   ch == POLISH_o
    );
}

INT is_czech_special(BYTE let)
{
return (
     let == AA_right_accent || let == a_right_accent	||
     let == CC_inv_roof		|| let == c_inv_roof		||
     let == DD_inv_roof		|| let == d_inv_roof		||
     let == EE_right_accent || let == e_right_accent	||
     let == EE_inv_roof		|| let == e_inv_roof		||
     let == II_right_accent || let == i_right_accent	||
     let == NN_inv_roof		|| let == n_inv_roof		||
     let == OO_right_accent || let == o_right_accent	||
     let == RR_inv_roof		|| let == r_inv_roof		||
     let == SS_inv_roof_latin	|| let == s_inv_roof_latin	||
     let == TT_inv_roof		|| let == t_inv_roof		||
     let == UU_right_accent || let == u_right_accent	||
     let == UU_circle_accent|| let == u_circle_accent	||
     let == YY_right_accent || let == y_right_accent	||
     let == ZZ_inv_roof_latin		|| let == z_inv_roof_latin
    );
}

INT is_roman_special(BYTE let)
{
return (
     let == AA_semicircle			|| 	let == a_semicircle				||
     let == AA_roof_accent			|| 	let == a_roof_accent			||
     let == II_roof_accent			|| 	let == i_roof_accent			||
     let == SS_bottom_accent_latin	|| 	let == s_bottom_accent_latin	||
     let == TT_bottom_accent		|| 	let == t_bottom_accent
    );
}

INT is_hungar_special(BYTE let)
{
return (
     let == AA_right_accent || 		let == a_right_accent ||
     let == EE_right_accent || 		let == e_right_accent ||
     let == II_right_accent || 		let == i_right_accent ||
     let == OO_right_accent || 		let == o_right_accent ||
     let == OO_2dot_accent  || 		let == o_2dot_accent  ||
     let == OO_double_right || 		let == o_double_right
    );
}
INT is_slovenian_special(BYTE let)
{
return (
     let == CC_inv_roof			|| let == c_inv_roof		||
     let == SS_inv_roof_latin	|| let == s_inv_roof_latin	||
     let == ZZ_inv_roof_latin	|| let == z_inv_roof_latin
    );
}

INT isnot_slovenian(BYTE let)
{
return (
     let == 'Q' || let == 'q' ||
     let == 'W' || let == 'w' ||
     let == 'X' || let == 'x' ||
     let == 'Y' || let == 'y'
    );
}

INT is_baltic_palka(BYTE c)
{
// Определение балтийских палок. 30.05.2002 E.P.

	if (!is_baltic_language(language))
		return 0;

	return (
			c==II_macron		|| c==i_macron ||
			c==II_bottom_accent || c==i_bottom_accent ||
			c==LL_bottom_accent || c==l_bottom_accent ||
			0
			);
}

INT is_latvian_special(BYTE let)
{
return (
     let == AA_macron			||let == a_macron			||
     let == CC_inv_roof			||let == c_inv_roof			||
     let == EE_macron			||let == e_macron			||
     let == GG_bottom_accent	||let == LATVIAN_g			||
     let == II_macron			||let == i_macron			||
     let == KK_bottom_accent	||let == k_bottom_accent	||
     let == LL_bottom_accent	||let == l_bottom_accent	||
     let == NN_bottom_accent	||let == n_bottom_accent	||
     let == SS_inv_roof_baltic	||let == s_inv_roof_baltic	||
     let == UU_macron			||let == u_macron			||
     let == ZZ_inv_roof_baltic	||let == z_inv_roof_baltic	||
	 0
    );
}

INT isnot_latvian(BYTE let)
{
return (
     let == 'Q' || let == 'q' ||
     let == 'W' || let == 'w' ||
     let == 'X' || let == 'x' ||
     let == 'Y' || let == 'y'
    );
}

INT is_lithuanian_special(BYTE let)
{
return (
     let == AA_bottom_accent	|| 	let == a_bottom_accent	||
     let == CC_inv_roof			|| 	let == c_inv_roof		||
     let == EE_bottom_accent	|| 	let == e_bottom_accent	||
     let == EE_dot_accent		|| 	let == e_dot_accent		||
     let == II_bottom_accent	|| 	let == i_bottom_accent	||
     let == SS_inv_roof_baltic	|| 	let == s_inv_roof_baltic||
     let == UU_bottom_accent	|| 	let == u_bottom_accent	||
     let == UU_macron			|| 	let == u_macron			||
     let == ZZ_inv_roof_baltic	|| 	let == z_inv_roof_baltic||
	 0
    );
}

INT isnot_lithuanian(BYTE let)
{
return (
     let == 'Q' || let == 'q' ||
     let == 'W' || let == 'w' ||
     let == 'X' || let == 'x'
    );
}

INT is_estonian_special(BYTE let)
{
return (
     let == AA_2dot_accent		|| 	let == a_2dot_accent		||
     let == OO_tild_accent		|| 	let == o_tild_accent		||
     let == OO_2dot_accent		|| 	let == o_2dot_accent		||
     let == SS_inv_roof_baltic	|| 	let == s_inv_roof_baltic	||
     let == UU_2dot_accent		|| 	let == u_2dot_accent		||
     let == ZZ_inv_roof_baltic	|| 	let == z_inv_roof_baltic	||
	 0
    );
}

INT isnot_estonian(BYTE let)
{
return (
     let == 'C' || let == 'c' ||
     let == 'Q' || let == 'q' ||
     let == 'W' || let == 'w' ||
     let == 'X' || let == 'x' ||
     let == 'Y' || let == 'y'
    );
}

INT is_turkish_special(BYTE let)
{
return (
     let == AA_roof_accent			|| 	let == a_roof_accent			||
     let == CC_bottom_accent		|| 	let == c_bottom_accent			||
     let == GG_semicircle			|| 	let == g_semicircle				||
     let == II_dot_accent			|| 	let == i_sans_accent			||
     let == II_roof_accent			|| 	let == i_roof_accent			||
     let == OO_2dot_accent			|| 	let == o_2dot_accent			||
     let == SS_bottom_accent_turkish|| 	let == s_bottom_accent_turkish	||
     let == UU_2dot_accent			|| 	let == u_2dot_accent			||
     let == UU_roof_accent			|| 	let == u_roof_accent			||
	 0
    );
}

INT is_turkish_bottom_accent(BYTE c)
{
// Определение нижнего акцента. 20.05.2002 E.P.
	return (

	c == CC_bottom_accent || c == c_bottom_accent ||
	c == SS_bottom_accent || c == s_bottom_accent ||

	0);
}

INT is_turkish_palka(BYTE c)
{
// Определение турецких палок. 21.05.2002 E.P.

	if (!is_turkish_language(language))
		return 0;

	return (
			c == II_roof_accent	|| c == i_roof_accent ||
			c == II_dot_accent	|| c == i_sans_accent ||
			0
			);
}

INT is_russian_turkish_conflict(BYTE c)
{
/*
	Определение конфликта между русскими
	и турецкими буквами. 21.05.2002 E.P.

	Список конфликтных русских букв:

		- ХЩйо - выглядят как •, ™, ©, ®
		- украинские UKR_ii, UKR_G, UKR_g - выглядят как
			русские буквы В,З,Ц
		- тчю - выглядят как русские буквы в, з, о
		- r_cu_a, r_cu_d  - выглядят как русские буквы р,э

	Полный список конфликтных букв выглядит так:
			"•™©®ВЗЦвзорэ"
*/
	if (!is_turkish_language(language))
		return FALSE;

	if (
		c == liga_bull_turkish	|| // '•'
		c == liga_TM_turkish	|| // '™'
		c == liga_CC_turkish	|| // '©'
		c == liga_CR_turkish	|| // '®'
		c == AA_roof_accent		|| // 'В'
		c == a_roof_accent		|| // 'в'
		c == CC_bottom_accent	|| // 'З'
		c == c_bottom_accent	|| // 'з'
		c == OO_2dot_accent		|| // 'Ц'
		c == i_roof_accent		|| // 'о'
		c == r_cu_a				|| // 'р'
		c == r_cu_d				|| // 'э'
		0
	   )
		return TRUE;

	return FALSE;
}

INT isnot_turkish(BYTE let)
{
extern  char    alphabet[256];

return (
	 !alphabet[let] || // Отсекаю французские акценты. 09.06.2002 E.P.
     let == 'Q' || let == 'q' ||
     let == 'W' || let == 'w' ||
     let == 'X' || let == 'x'
    );
}

///////////////////////////////////////
INT is_lower(BYTE ch)
{

if(language==LANG_RUSSIAN)
        switch(fEdCode){
  case ED_ASCII: // for ASCII
   if((ch >=(BYTE)' ' && ch <=(BYTE)'Ї') ||
      (ch >=(BYTE)'а' && ch <=(BYTE)'п') ||
       memchr("рсхчшэА",ch,7)
     ) return 1;
  break;
  case ED_WIN: // for Windows (ANSI)
      if (ch >=0xE0 && ch <=0xFF)
        return 1;
  break;
  case ED_MAC: // for Macintosh
      if(((ch >=0xE0 && ch <=0xFE) || ch == 0xDF)
        ) return 1;
  break;
        }
 if(ch >= 'a' && ch <= 'z') return 1;
 return 0;
}
INT is_upper(BYTE ch)
{
if(language==LANG_RUSSIAN)
    switch(fEdCode){
    case ED_ASCII:
    case ED_MAC: // for ASCII and Macintosh
      if(ch >=(BYTE)'Ђ' && ch <=(BYTE)'џ'||
         ch==(BYTE)r_EE_2dot
        )  return 1;
    break;
    case ED_WIN: // for Windows (ANSI)
      if(ch >= 0xC0 && ch <= 0xDF)
        return 1;
    break;
    }
if(ch >= 'A' && ch <= 'Z') return 1;
 return 0;
}

BOOL is_digit(BYTE ch)
{
if(ch >= (BYTE)'0' && ch <= (BYTE)'9') return TRUE;
else return FALSE;
}

INT isletter(BYTE ch)
{
if(is_lower(ch) || is_upper(ch)) return 1;
else return 0;
}

static const BYTE non_twin[]=" ЂЎЃҐ…";
static const BYTE lat_twins[]="cCoOpPsSvVwWxXzZ";

INT twin(BYTE ch)
{
if(!isletter(ch)) return 0;
if( language==LANG_RUSSIAN )
 if(memchr(non_twin,ch,sizeof non_twin)) return 0;
 else                                    return 1;
if( language!=LANG_RUSSIAN && memchr(lat_twins,ch,sizeof lat_twins)) return 1;
return 0;
}

BYTE get_homot(BYTE ch )
{
 if(ch == '0') return ((BYTE)'®');
 if(is_upper(ch)) return to_lower(ch);
 if(is_lower(ch)) return to_upper(ch);
 return ch;
}

/* Function returns UPPER CASE variant of the letter.             */
BYTE to_upper( BYTE c )
{
  if ( c >= (BYTE)'a' && c <= (BYTE)'z') return c - (BYTE)'a' + (BYTE)'A';
  if(language==LANG_RUSSIAN)
       switch(fEdCode){
  case ED_ASCII:  // for ASCII
    if ( c >= (BYTE)' ' && c <= (BYTE)'Ї') return c - (BYTE)' ' + (BYTE)'Ђ';
    if ( c >= (BYTE)'а' && c <= (BYTE)'п') return c - (BYTE)'а' + (BYTE)'ђ';
  break;
  case ED_WIN: // for Windows (ANSI)
    if ( c >= 0xE0 && c <= 0xFF ) return c - 0xE0 + 0xC0;
  break;
  case ED_MAC: // for Macintosh
    if ((c >= 0xE0 && c <= 0xFE) ) return c - 0xE0 + 0x80;
    if ( c == 0xDF )               return 0x9F;
  break;
  }
    return c;
}

 /* Function returns LOWER CASE variant of the letter.             */
BYTE to_lower(BYTE c)
{
  if ( c >= (BYTE)'A' && c <= (BYTE)'Z') return c - (BYTE)'A'+ (BYTE)'a' ;
  if(language==LANG_RUSSIAN)
        switch(fEdCode){
  case ED_ASCII: // for ASCII
    if ( c >= (BYTE)'Ђ' && c <= (BYTE)'Џ') return c - (BYTE)'Ђ'+ (BYTE)' ' ;
    if ( c >= (BYTE)'ђ' && c <= (BYTE)'џ') return c - (BYTE)'ђ'+ (BYTE)'а' ;
  break;
  case ED_WIN: // for Windows
    if ( c >= 0xC0 && c <= 0xDF) return c - 0xC0 + 0xE0 ;
  break;
  case ED_MAC: // for Macintosh
    if ( c >= 0x80 && c <= 0x9E) return c - 0x80 + 0xE0 ;
    if ( c == 0x9F )             return 0xDF;
  break;
        }
    return c;
}
/////////////////////
INT is_cen_bottom_accent(BYTE c)
{
// Определение нижнего акцента 12.09.2000 E.P.
	return (

	c== AA_bottom_accent		|| c== a_bottom_accent	||
	c== CC_bottom_accent		|| c== c_bottom_accent	||
	c== EE_bottom_accent		|| c== e_bottom_accent	||
	c== SS_bottom_accent_latin || c== s_bottom_accent	||
	c== TT_bottom_accent		|| c== t_bottom_accent	||

	0);
}
/////////////////////
INT is_baltic_bottom_accent(BYTE c)
{
// Определение нижнего акцента 10.07.2001 E.P.
	return (

	c == AA_bottom_accent_baltic || c == a_bottom_accent_baltic ||
	c == EE_bottom_accent_baltic || c == e_bottom_accent_baltic ||
	c == GG_bottom_accent		 ||
	c == II_bottom_accent		 || c == i_bottom_accent ||
	c == KK_bottom_accent		 || c == k_bottom_accent ||
	c == LL_bottom_accent		 || c == l_bottom_accent ||
	c == NN_bottom_accent		 || c == n_bottom_accent ||
	c == UU_bottom_accent		 || c == u_bottom_accent ||
	0);
}

INT is_russian_baltic_conflict(BYTE c)
{
// Определение конфликта между русскими и балтийскими буквами. 17.07.2001 E.P.
	if (!is_baltic_language(language))
		return FALSE;

	if (strchr("абвджзилмноп",c))
		return TRUE;

	return FALSE;
}
/////////////////////////////////
// Linpon.c
INT is_defis(cell *C)
 {   INT bs2m, bsm3;
 INT i, j;
 if ((C->w < 3) || (C->h < 2) || (2*C->h > C->w) || (9 * (C->h) > 4 * Ps))
  return 0;
 i=C->row-minrow+C->bdiff; j=i+C->h;
 bs2m=(bbs2+bbsm)/2;
 bsm3=(bbsm+bbs3)/2;
 if ((i < bs2m) || (j > bsm3)) return 0;
 return 1;
 }
//////////////////////
// Linpon.c
INT if_dust(cell *C)
 { INT rb, w1, wh, wps;
 // Check position in the string - have to intersect with string middle
 // MUST request local BASELINES !!!!!!!!!!!!!!
 rb = 0;
 wps = def_locbas(C);
 /////////  931230 if (5*C->h > 3*wps) rb |= 16;    // indicate LARGE
 w1=(C->row - minrow)-bbsm-C->bdiff;
 if (w1 >= 0)
  { rb |= 1; goto chks; }
 w1=w1+1+C->h+((fax1x2)?2:0);
 if (w1 < 0)
  rb |= 2;
			       // Check height of cell:
chks:              // height(cell) + 4 >= main_base-small_base
 wh=C->h+((fax1x2)?2:0);
 if ((wh <= sMALL_SIZE) || (5*wh < 3*wps))  //NB 3.4.94
  return (rb | 4);
 if (4*wh < 3*wps)
  return (rb | 8);
 return 0;
 }
/////////////
//////////////////////
static void SetRstrGlobals(BAL_RSTR_GLOBALS  *rstrGlob)
{
INT rast_is_BOX_solid (CSTR_rast B1);

	rstrGlob->language = language;
	rstrGlob->line_number = line_number;
	rstrGlob->fax1x2 =fax1x2;
	rstrGlob->actual_resolution = actual_resolution;
    rstrGlob->fEdCode   = fEdCode ; // ASCII
    rstrGlob->line_BL   = line_BL;
    rstrGlob->spec_camera = spec_camera;
    rstrGlob->no_linpen   = no_linpen;

    rstrGlob->prop_l_delta  = prop_l_delta;
	rstrGlob->prop_r_delta  = prop_r_delta;

	rstrGlob->let_lindef3 = let_lindef3;
    rstrGlob->let_lindef = let_lindef;
    rstrGlob->let_linpos = let_linpos ;
    rstrGlob->let_linshape = let_linshape ;
    rstrGlob->let_sans_acc =  let_sans_acc;
    rstrGlob->letters_pidx_table =    letters_pidx_table ;
	rstrGlob->decode_ASCII_to_ = &decode_ASCII_to_[0][0];

	rstrGlob->skew_corr = skew_corr;
	rstrGlob->rast_is_BOX_solid = rast_is_BOX_solid;

	rstrGlob->db_status = db_status ;
	rstrGlob->db_pass   = db_pass ;
	rstrGlob->snap_activity = snap_activity;
	rstrGlob->snap_monitor  = snap_monitor;
	rstrGlob->snap_show_text= snap_show_text;
	rstrGlob->snap_monitor_ori= snap_monitor_ori;//IGOR
	rstrGlob->snap_is_marked= snap_is_marked;//IGOR
	rstrGlob->snap_baselines= snap_baselines;//IGOR
	rstrGlob->snap_draw_line= snap_draw_line;//IGOR
	rstrGlob->snap_del_line = snap_del_line;//IGOR
}
//////////////////////
static void GetBalGlobals(BAL_INOUT_GLOBALS  *balGlob)
{
	all_caps       = balGlob->all_caps;
    all_diffs_made = balGlob->all_diffs_made;
	bbs0 = balGlob->bbs0;
	bbs1 = balGlob->bbs1;
	bbs2 = balGlob->bbs2;
	bbs3 = balGlob->bbs3;
	bbs4 = balGlob->bbs4;
	bbsm = balGlob->bbsm;

	bs_got       = balGlob->bs_got      ;
	bsdust_lower = balGlob->bsdust_lower;
	bsdust_ps    = balGlob->bsdust_ps   ;
	bsdust_upper = balGlob->bsdust_upper;
	let_to_dust  = balGlob->let_to_dust ;
	maxcol = balGlob->maxcol ;
	mincol = balGlob->mincol ;
	maxrow = balGlob->maxrow ;
	minrow = balGlob->minrow ;
	multi_bas = balGlob->multi_bas;

	Nb1 = balGlob->Nb1 ;
	Nb2 = balGlob->Nb2 ;
	Nb3 = balGlob->Nb3 ;
	Nb4 = balGlob->Nb4 ;

	Ns1 = balGlob->Ns1 ;
	Ns2 = balGlob->Ns2 ;
	Ps  = balGlob->Ps  ;
	Psf = balGlob->Psf ;

	nIncline = (Int16)balGlob->nIncline;
}
/////////////////////
static void SetBalGlobals(BAL_INOUT_GLOBALS  *balGlob)
{
	balGlob->all_caps       = all_caps;
    balGlob->all_diffs_made = all_diffs_made;
	balGlob->bbs0 = bbs0;
	balGlob->bbs1 = bbs1;
	balGlob->bbs2 = bbs2;
	balGlob->bbs3 = bbs3;
	balGlob->bbs4 = bbs4;
	balGlob->bbsm = bbsm;

	balGlob->bs_got       = bs_got;
	balGlob->bsdust_lower = bsdust_lower;
	balGlob->bsdust_ps    = bsdust_ps;
	balGlob->bsdust_upper = bsdust_upper;
	balGlob->let_to_dust  = let_to_dust;
	balGlob->maxcol = maxcol;
	balGlob->mincol = mincol;
	balGlob->maxrow = maxrow;
	balGlob->minrow = minrow;
	balGlob->multi_bas = multi_bas;

	balGlob->Nb1 = Nb1;
	balGlob->Nb2 = Nb2;
	balGlob->Nb3 = Nb3;
	balGlob->Nb4 = Nb4;

	balGlob->Ns1 = Ns1;
	balGlob->Ns2 = Ns2;
	balGlob->Ps  = Ps;
	balGlob->Psf = Psf;

	balGlob->nIncline = nIncline;
}
//////////////////////
static CSTR_head *llRaw=(CSTR_head *)NULL;
static Word16 SetNoScaleLine(CSTR_line ln )
{
	CSTR_attr lattr;
	CSTR_rast rast;
	CSTR_rast_attr attr;
	CCOM_comp *cmp;
	Word16 scale;

    llRaw = (CSTR_head *)ln;

	CSTR_GetLineAttr(ln,&lattr);
	if( !(lattr.Flags & CSTR_STR_SCALED) ||
		!lattr.scale
	  )
		return 0;

	for(rast=CSTR_GetNext(CSTR_GetFirstRaster(ln));rast;
	    rast = CSTR_GetNext(rast) )
	{
			CSTR_GetAttr(rast,&attr);

			attr.h>>=lattr.scale;
			attr.w>>=lattr.scale;
			attr.row>>=lattr.scale;
			attr.col>>=lattr.scale;
			attr.r_row>>=lattr.scale;
			attr.r_col>>=lattr.scale;

			CSTR_SetAttr(rast,&attr);

			cmp = CSTR_GetComp(rast);

			if( cmp )
			{
				cmp->w >>= lattr.scale;
				cmp->h >>= lattr.scale;
				cmp->upper >>= lattr.scale;
				cmp->left  >>= lattr.scale;
			}

	}

    scale = lattr.scale;
	lattr.Flags &= ~CSTR_STR_SCALED;

	lattr.scale = 0;
    CSTR_SetLineAttr(ln,&lattr);

	return scale;
}
///////////////
//////////////////////
static Word16 RestoreScaleLine(CSTR_line ln , Word16 scale)
{
	CSTR_attr lattr;
	CSTR_rast rast;
	CSTR_rast_attr attr;
	CCOM_comp *cmp;

	if( !scale )
		return scale;

	CSTR_GetLineAttr(ln,&lattr);
	lattr.Flags |= CSTR_STR_SCALED;
	lattr.scale  = (Word8)scale;
	CSTR_SetLineAttr(ln,&lattr);

	for(rast=CSTR_GetNext(CSTR_GetFirstRaster(ln));rast;
	    rast = CSTR_GetNext(rast) )
	{
			CSTR_GetAttr(rast,&attr);

			attr.h<<=lattr.scale;
			attr.w<<=lattr.scale;
			attr.row<<=lattr.scale;
			attr.col<<=lattr.scale;
			attr.r_row<<=lattr.scale;
			attr.r_col<<=lattr.scale;

			CSTR_SetAttr(rast,&attr);

			cmp = CSTR_GetComp(rast);

			if( cmp )
			{
				cmp->w <<= lattr.scale;
				cmp->h <<= lattr.scale;
				cmp->upper <<= lattr.scale;
				cmp->left  <<= lattr.scale;
			}
	}

	return scale;
}
///////////////
void clear_cells(void);
void Cells2CSTR(CSTR_line lin,CSTR_line lino,cell *cur,Bool32 enable_scaled);
// для CopyAttr2CSTR в Cells2CSTR() !!!
BOOL SetFontReady(BOOL fready);
Int32 p2_Cstr2Cell( CSTR_line lin,CSTR_rast first,CSTR_rast last,Bool32 needVers, Word32 disable );
// предварительный поиск базовых линий
void basedraft(CSTR_line ln)
{
 BAL_RSTR_GLOBALS   rstrGlob;
 BAL_INOUT_GLOBALS  balGlob;
 CSTR_line line_bal=(CSTR_line)NULL;
 int  i;
 CSTR_rast rast;
 int  ret;
 Word16 saveScale;
 Bool32 retBaseDraft;
 CSTR_attr lattr,lattr_bal;

   lin_str = ln;
   CSTR_GetLineAttr(ln,&lattr);

   for( i=0; i < 5;i++)
   {
    line_bal = CSTR_NewLine(line_number, CSTR_LINVERS_BAL + i*10, -1 );
    if( line_bal )
	  break;
   }

    if( !line_bal )
	 return;

	// переведем cell_f()-> в нашу линию, используя
	// атрибуты ln
	{
	  BOOL old_ready = SetFontReady(TRUE);
      Cells2CSTR( ln, line_bal, NULL, 1);
	  SetFontReady(old_ready);
	}

    SetRstrGlobals(&rstrGlob);
	SetBalGlobals(&balGlob);

	// установим - как будто не было шкалирования -
	// как в версии с cell()
	saveScale = SetNoScaleLine( line_bal );

	// установим row,hei как у исходной - чтобы было совпадение с
	// старой версией для skew_corr()
	//
	CSTR_GetLineAttr(line_bal,&lattr_bal);
	lattr_bal.row=lattr.row;
	lattr_bal.hei=lattr.hei;
	CSTR_SetLineAttr(line_bal,&lattr_bal);

	dust_in = 0;
	BAL_basedraft(line_bal, 0, &rstrGlob, &balGlob, all_bases);

    //  вернем истину
	if( saveScale )
		 RestoreScaleLine( line_bal, saveScale );

	GetBalGlobals(&balGlob);

	// переведем в cell
    clear_cells();
    ret = p2_Cstr2Cell( line_bal,NULL,NULL,TRUE, CSTR_f_space );

    // добавим мусор
	dust_ini(ln); //bring_dust(0);
	dust_in = 1;

    // очистим нашу линию
	for(rast=CSTR_GetNext(CSTR_GetFirstRaster(line_bal));
	    rast; rast=CSTR_DelRaster(rast) );

    // переведем cell_f()-> в нашу линию, используя
	// атрибуты ln
    {
	  BOOL old_ready = SetFontReady(TRUE);
      Cells2CSTR( ln, line_bal, NULL, 1);
	  SetFontReady(old_ready);
	}

	// установим - как будто не было шкалирования -
	// как в версии с cell()
	saveScale = SetNoScaleLine( line_bal );

	SetBalGlobals(&balGlob);

	// установим row,hei как у исходной - чтобы было совпадение с
	// старой версией для skew_corr()
	//
	CSTR_GetLineAttr(line_bal,&lattr_bal);
	lattr_bal.row=lattr.row;
	lattr_bal.hei=lattr.hei;
	CSTR_SetLineAttr(line_bal,&lattr_bal);

	retBaseDraft = BAL_basedraft(line_bal, 1, &rstrGlob, &balGlob, all_bases);
	GetBalGlobals(&balGlob);
    //  вернем истину
	if( saveScale )
		 RestoreScaleLine( line_bal, saveScale );

    // переведем в cell
    clear_cells();
    ret = p2_Cstr2Cell( line_bal,NULL,NULL,TRUE, CSTR_f_space );

	// есть сомнения (и есть дополнительные возможности)
    if( !retBaseDraft )
	{
	// добавим мусор
	 dust_ini(ln); //bring_dust(0);
	 dust_in = 1;

    // очистим нашу линию
	 for(rast=CSTR_GetNext(CSTR_GetFirstRaster(line_bal));
	    rast; rast=CSTR_DelRaster(rast) );

    // переведем cell_f()-> в нашу линию, используя
	// атрибуты ln
     {
	  BOOL old_ready = SetFontReady(TRUE);
      Cells2CSTR( ln, line_bal, NULL, 1);
	  SetFontReady(old_ready);
	}

	// установим - как будто не было шкалирования -
	// как в версии с cell()
	 saveScale = SetNoScaleLine( line_bal );

	 // установим row,hei как у исходной - чтобы было совпадение с
	// старой версией для skew_corr()
	//
	 CSTR_GetLineAttr(line_bal,&lattr_bal);
	 lattr_bal.row=lattr.row;
	 lattr_bal.hei=lattr.hei;
	 CSTR_SetLineAttr(line_bal,&lattr_bal);

	 SetBalGlobals(&balGlob);
	 retBaseDraft = BAL_basedraft(line_bal, 2, &rstrGlob, &balGlob, all_bases);
	 GetBalGlobals(&balGlob);
    //  вернем истину
	 if( saveScale )
		 RestoreScaleLine( line_bal, saveScale );

    // переведем в cell
     clear_cells();
     ret = p2_Cstr2Cell( line_bal,NULL,NULL,TRUE, CSTR_f_space );
	}

	CSTR_DeleteLine(line_bal);
}
///////////////
// окончательно уточнить базовые линии
void basefin(CSTR_line ln)
{
 BAL_RSTR_GLOBALS   rstrGlob;
 BAL_INOUT_GLOBALS  balGlob;
 CSTR_line line_bal=(CSTR_line)NULL;
 int  i;
 int  ret;
 Word16 saveScale;

   lin_str = ln;

   for( i=0; i < 5;i++)
   {
	   line_bal = CSTR_NewLine(line_number, CSTR_LINVERS_BAL + i*10, -1 );
    if( line_bal )
	  break;
   }

    if( !line_bal )
	 return;

	// переведем cell_f()-> в нашу линию, используя
	// атрибуты ln
    {
	  BOOL old_ready = SetFontReady(TRUE);
      Cells2CSTR( ln, line_bal, NULL, 1);
	  SetFontReady(old_ready);
	}

    SetRstrGlobals(&rstrGlob);
	SetBalGlobals(&balGlob);

	// установим - как будто не было шкалирования -
	// как в версии с cell()
	saveScale = SetNoScaleLine( line_bal );

	BAL_basefin(line_bal, &rstrGlob, &balGlob, all_bases);
	GetBalGlobals(&balGlob);
	    //  вернем истину
	if( saveScale )
		 RestoreScaleLine( line_bal, saveScale );

	// переведем в cell
    clear_cells();
    ret = p2_Cstr2Cell( line_bal,NULL,NULL,TRUE, 0 );

	CSTR_DeleteLine(line_bal);
}
////////////////////
// уточнить базовые линии, проверить multi-base
// оштрафовать - удалить версии по базовым линиям
void linpos(CSTR_line ln)
{
 BAL_RSTR_GLOBALS   rstrGlob;
 BAL_INOUT_GLOBALS  balGlob;
 CSTR_line line_bal=(CSTR_line)NULL;
 int  i;
 int  ret;
 Word16 saveScale;

   lin_str = ln;

   for( i=0; i < 5;i++)
   {
    line_bal = CSTR_NewLine(line_number, CSTR_LINVERS_BAL + i*10, -1 );
    if( line_bal )
	  break;
   }

    if( !line_bal )
	 return;

	// переведем cell_f()-> в нашу линию, используя
	// атрибуты ln
    {
	  BOOL old_ready = SetFontReady(TRUE);
      Cells2CSTR( ln, line_bal, NULL, 1);
	  SetFontReady(old_ready);
	}

    SetRstrGlobals(&rstrGlob);
	SetBalGlobals(&balGlob);

	// установим - как будто не было шкалирования -
	// как в версии с cell()
	saveScale = SetNoScaleLine( line_bal );

	BAL_linpos(line_bal, &rstrGlob, &balGlob, all_bases);
	GetBalGlobals(&balGlob);
	    //  вернем истину
	if( saveScale )
		 RestoreScaleLine( line_bal, saveScale );

	// переведем в cell
    clear_cells();
    ret = p2_Cstr2Cell( line_bal,NULL,NULL,TRUE, 0 );

	CSTR_DeleteLine(line_bal);
}
////////////////
//////////////////
void BaseLineStatisticInit(void)
{
	BAL_StatInit();
}
/////////////////

#endif
