 
# include "decl.h"
# include "macros.h"
# include "ifunc.h"
# include "fileio.h"
# include "alph_tab.h"

#include "version.h"

#include <errno.h>

# define MDEBUG 0
# define MDEBUG1 0

/* Dependences (This module is self-sufficient)
   ri_alphabet:
         ri_isCyrillic, ...., 
              IndexCase, ri_NumericType, ri_DigitType, IndexAlphabet
   ri_alphabet_s: 
   ri_init_unicode_case_groups
   ri_tolower, ri_toupper:
         ri_utf_to_int - not needed, ri_int_to_utf+, ri_isCaseInsensitive
   isIndexMinus,
   ri_isWhiteSpace, ri_WhiteSpaceType, ri_WhiteSpaceWidth, ri_WhiteSpaceLength
   ri_is_utf_seq - not needed, ri_byte_to_utf_seq - not needed, 
   ri_get_utf_ln+, ri_isunicode+, ri_int_to_utf+
   ri_utf_explode - not called in this module, ri_utf_expl+
*/

/* ToDo:
   (1) Call of the function ri_utf_to_int (may and) has to be excluded everywhere below. 
       The calls are just rudiments.
   (2) Function ri_utf_explode is never called in this module and maybe should be moved in func1.c.
   (3) Function ri_byte_to_utf_seq is never called in this module and is used only in ri_put (refio.c). Maybe it should be moved in refio.c.
   (4) Function  ri_is_utf_seq is never called in this module and is used only in ri_getc (refio.c). Maybe it should be moved in refio.c.
*/

/* Nemytykh, version: 30-08-2023
  Alphabet type of utf-8 character uchar.
  The corresponding information was taken from: 
  https://www.key-shortcut.com/en/writing-systems/
  https://unicode-table.com/en/alphabets/
*/
static char mln;                      /* UTF-8 symbol length encoded with leading bits of the char. */
static char uchar_str_prop [MAXWS+1]; /* Buffer used for unicode character properties given by string. */

int ri_alphabet (unsigned long usymb)
// Should be: int ri_alphabet (utf usymb) , see (1) in the ToDo list above.
   {
	  
	  mln = 0; /* Utf8-length of the encoded usymb is used by the alphabetic predicates. */ 
	  for (int i=3;i>=0;i--){
			if ((usymb & (255<<i*8)) != 0){
			     mln = (mln>>1)|128;
			}
		}
   	
   	if ( ri_isCyrillic(usymb) ) {
				return 'c'; 
		} else if (ri_isLatin(usymb)) {
				return 'l'; 
		} else if (ri_isSymbols(usymb)) { 
				return 's'; 
		} else if (ri_isGreek(usymb)) {
				return 'g'; 
      } else if (ri_isMath(usymb)) {  /* Mathematical alphabet letters */
            return 'M';
		} else if (ri_isArabic(usymb)) {  /* aRabic */
				return 'r'; 
   	} else if (ri_isHebrew(usymb)) {
				return 'h'; 
		} else if (ri_isArmenian(usymb)) {
				return 'a'; 
		} else if (ri_isGeorgian(usymb)) { /* Mchedruli */
				return 'm'; 
		} else if (ri_isJapanese(usymb)) { 
				return 'j'; 
		} else if (ri_isKorean(usymb)) { 
				return 'k'; 
		} else if (ri_isChinese(usymb)) { /* ChineZe (CJK) */
				return 'z';  
   	} else if (ri_isEthiopian(usymb)) { 
				return 'e';
		} else if (ri_isOld(usymb)) { 
            return 'o';
		} else if (ri_isBrahmic(usymb)) { /* Indic Scripts */
				return 'i';
		} else { return 'u'; }             /* Unknown */
   }
 
char * ri_alphabet_s (utf usymb)
   {
	  
	  mln = 0; /* Utf8-length of the encoded usymb is used by the alphabetic predicates. */ 
	  for (int i=3;i>=0;i--){
			if ((usymb & (255<<i*8)) != 0){
			     mln = (mln>>1)|128;
			}
		}
   	
   	if ( ri_isCyrillic(usymb) ) {
				return strcpy(uchar_str_prop,"Cyrillic"); 
		} else if (ri_isLatin(usymb)) {
				return strcpy(uchar_str_prop,"Latin"); 
		} else if (ri_isMath(usymb)) {  /* Mathematical alphabet letters */
				return strcpy(uchar_str_prop,"Math"); 
		} else if (ri_isSymbols(usymb)) { 
				return strcpy(uchar_str_prop,"Symbol"); 
		} else if (ri_isGreek(usymb)) {
				return strcpy(uchar_str_prop,"Greek"); 
		} else if (ri_isArabic(usymb)) {  
				return strcpy(uchar_str_prop,"Arabic"); 
   	} else if (ri_isHebrew(usymb)) {
				return strcpy(uchar_str_prop,"Hebrew"); 
		} else if (ri_isArmenian(usymb)) {
				return strcpy(uchar_str_prop,"Armenian"); 
		} else if (ri_isGeorgian(usymb)) { /* Mchedruli */
				return strcpy(uchar_str_prop,"Georgian"); 
		} else if (ri_isJapanese(usymb)) { 
				return strcpy(uchar_str_prop,"Japanese"); 
		} else if (ri_isKorean(usymb)) { 
				return strcpy(uchar_str_prop,"Korean"); 
		} else if (ri_isChinese(usymb)) { /* Chinese (CJK) */
				return strcpy(uchar_str_prop,"Chinese"); 
   	} else if (ri_isEthiopian(usymb)) { 
				return strcpy(uchar_str_prop,"Ethiopian"); 
		} else if (ri_isOld(usymb)) { 
				return strcpy(uchar_str_prop,"Old"); 
		} else if (ri_isBrahmic(usymb)) { /* Indic Scripts */
				return strcpy(uchar_str_prop,"Indian"); 
		} else { return strcpy(uchar_str_prop,"Unknown"); }  /* Unknown */
	   return uchar_str_prop;
   }

/* As a rule, the letter (upper-lower) case is repeatedly replaced inside the letters from the same (previous) group.
   The following static variables keep in mind the previous groups, in oder to try overcoming an unnecessary search. 
*/
static utf prev_upgr_n;
static utf prev_lowgr_n;

void ri_init_unicode_case_groups (void) {
	prev_upgr_n  = n_uprop+1; /* This value signals that none group was still considered. */
	prev_lowgr_n = n_uprop+1;
	return; 
}

int ri_isCaseInsensitive (utf usymb) {
	if (ri_isChinese(usymb) 
/*	   || ri_isJapanese(usymb)  // Fullwidth ASCII variants:  FF00—FFEF incudes Ａ-Ｚ vs ａ-ｚ -- U+FF21-FF3A  vs U+FF41-U+FF5A  +-0x20 */
	   || ri_isKorean(usymb)  ||
	    ri_isArabic(usymb)  || ri_isHebrew(usymb)   || ri_isBrahmic(usymb) 
/*	    || ri_isSymbols(usymb) // Latin numbers are case sensitive */
	   ) return 1;
	return 0;
}

utf ri_tolower (utf usymb) {
   int i, j, k, shift, parity, cnt, n;
   int prev_gr;
   unsigned long l, r;

          /* Actually, it is not certernly that the folowing call allows us to decrease the number of comparisons. 
             Maybe it should be removed. 
          */
   if ( ri_isCaseInsensitive(usymb) ) return usymb;

   unsigned long unicode = ri_utf_to_int(usymb);
   long u = (long)unicode; /* This strange variable is used below, 
                              in oder to treat the first bit of the shift as a sign (+,-) of the integer.*/ 
                              
   prev_gr = (prev_upgr_n > n_uprop) ? 0:1;
/* As a rule, the repeated call of the function ri_tolower has to consider the same group of symbols
   which was considered by the previous call og this function.
   In such a case the static variable prev_upgr_n is used in order to keep in mind the previous symbol group.
   The actull search starting at the zero point begins to work only if the previous and current symbol groups do not coincide.
*/    

   j = n_uprop; /* Actually this loop takes at most [log(n_uprop)]+1 iterations. See the break below. */
 	for(k=0, cnt=0; cnt < n_uprop; cnt++) {
  	      /* If the function call is repeated then try firstly the previous group used by this function. */
 	   i = (prev_gr == 0)? (k+j)/2 : prev_upgr_n; 
 	 start:
		l = upper_alph_tab[i].lbounder;
		r = upper_alph_tab[i].rbounder;
		if ( (l <= unicode) && (unicode <= r) ) {
			parity = upper_alph_tab[i].parity;
 				                 /* The type transformation cannot be removed! 
    			                    Since unicode is unsigned, while the shift can be negative. */ 
  		   shift = (int)upper_alph_tab[i].shift;
			switch (parity) {
			case HALF_OF_GROUP: 
			         unicode = u + shift; 
   		            break;
  		   case GROUP_OF_SIXTEENS: 
 		            n = (r-unicode)%16; if ( n < 8 ) unicode -= 8;
  		            break;
  		   case GROUP_OF_FIFTY_TWOS:
  		            n = (unicode-l)%52; if ( n < 26 ) unicode += 26 /* 0x1A */;
  		            break;
  		   case GROUP_OF_FIFTY_EIGHTS:
  		            n = (unicode-l)%58; 
  		            if ( (n < (17+8)) && (n != 17) ) unicode += 26 /* 0x1A */; 
  		            break;
 		   case GROUP_OF_THREE: /* if (unicode-l+1)%3 != 0 then +- 3-((unicode-l+1)%3) */
  		            n = (unicode-l+1)%3; if ( n != 0 ) unicode += 3-n;
  		            break;
  		   case HALF_OF_ODD_GROUP: /* The upper-case letters occupy only odd places. */ 
  		            if ( (u & 0x01L) == 1 )
  		              {
  		              	unicode = u + shift;
   		           };
 		            break;
  		   default: /* the parity is 0 or 1 */  
  		            if ( (unicode & 0x01) == parity )
  		            	unicode += shift; /* Here the shift > 0, otherwise overcome the sign problem as done above/ */ 
         
			};
			prev_upgr_n = i; /* Store this successful search. */
			goto Done;
		}
                 /* The previous ugroup is not relevant. Start to search. */
         if (prev_gr == 1) { prev_gr = 0; i = (k+j)/2; goto start; } 
         if ( j-k < 2 ) { break; }
 			if( unicode <= l ) {
				j = i; 
 			} else {
            k = i;
			}
		}
 
// Was:   j = n_alone_pst; /* j/2 = [Div(j,2)] <= Div(j,2) */
   j = n_alone_pst; /* j/2 = [Div(j,2)] <= Div(j,2) */
   if ( j%2 ) j++; // Nemytykh, 30-08-2023 */
                    /* Actually this loop takes at most [log(n_alone_pst)]+1 iterations. See the return below. */

  for( k = 0, cnt = 0; cnt < n_alone_pst; cnt++ ) {
  	i = (k+j)/2;
   l = upper_alone_pairs[i].lbounder;
 	   	if( (unicode == l) ) {
   		  unicode = upper_alone_pairs[i].rbounder;  

  		     goto Done; 
   		}
         if ( j-k < 2 ) { return usymb; }
			if( unicode < l ) {
				j = i; 
			} else {
            k = i;
			} 
   }
 
	Done:          /* ASCII test: */
         usymb = ( unicode > 127 ) ? r_int_to_utf(unicode) : unicode;
 	return usymb;
}

utf ri_toupper (utf usymb) {
   int i, j, k, shift, parity, n, cnt;
   int prev_gr;
   unsigned long l, r;
          /* Actually, it is not certernly that this call allow to decrease the number of comparations. 
             Maybe it should be removed. 
          */
   if ( ri_isCaseInsensitive(usymb) ) return usymb;

   unsigned long unicode = ri_utf_to_int(usymb);
   long u = (long)unicode; /* This strange variable is used below, 
                              in oder to treat the first bit of the shift as a sign (+,-) of the integer.*/ 
   prev_gr = (prev_lowgr_n > n_uprop) ? 0:1; /* See a comment in the function tolower above. */

   j = n_uprop;
 	for(k=0, cnt=0; cnt < n_uprop; cnt++) {
  	      /* If the function call is repeated then try firstly the previous group used by this function. */
  	   i = (prev_gr == 0)? (k+j)/2 : prev_lowgr_n; 
  	 start:
		l = lower_alph_tab[i].lbounder;
		r = lower_alph_tab[i].rbounder;
		if ( (l <= unicode) && (unicode <= r) ) {
			parity = lower_alph_tab[i].parity;
 				                 /* The type transformation cannot be removed! 
    			                    Since unicode is unsigned, while the shift can be negative. */ 
  		   shift = (int)lower_alph_tab[i].shift;
			switch (parity) {
			case HALF_OF_GROUP: 
			           unicode = u-shift; 
  		            break;
  		   case GROUP_OF_SIXTEENS: 
  		            n = (unicode-l)%16; if ( n < 8 ) unicode += 8;
  		            break;
  		   case GROUP_OF_THREE: /* if (unicode-l+1)%3 != 0 then +- 3-((unicode-l+1)%3) */
   		         /* Tolower function:   l = (unicode-l+1)%3; if ( l != 0 ) unicode -= (3-l);. */
   		         /* The inverse relation is not a function: one lower-case letter has two capitalized ones. */ 
   		         /* For this reason we implement: Upper1 Upper2 Lower ==> Upper1 Upper1 Upper2 */
   		         /* I.e. the second upper-case letter is replaced with the upperst letter, 
   		            while the lowe-case letter is replaced with the second upper-case letter. */ 
 		            if ((r - unicode + 1)%3 != 0) unicode--;
  		            break;
  		   case GROUP_OF_FIFTY_TWOS:
  		            n = (unicode-l)%52; if ( n > 25 ) unicode -= 26 /* 0x1A */;
  		            break;
  		   case GROUP_OF_FIFTY_EIGHTS:
 		            n = (unicode-l)%58; 
  		            if ( (25 < n) && (n < 51) ) {
   		               if ( n == 43 ) unicode -= 25 /* 0x19 */;
  		               else unicode -= 26 /* 0x1A */;
  		            }
  		            break;
  		   case HALF_OF_ODD_GROUP: /* The upper-case letters occupy only odd places. */ 
  		            if ( (u & 0x01L) == 1 )
  		              {
  		              	unicode = u-shift;
    		           };
 		            break;
  		   default: /* the parity is 0 or 1 */  
 		            if ( (~unicode & 0x01) == parity )
 		            {
  	            	  unicode -= shift; /* Here the shift > 0, otherwise overcome the sign problem as done above. */
  		            } 
 			};
			prev_lowgr_n = i; /* Store this successful search. */
			goto Done;
		}
                 /* The previous ugroup is not relevant. Start to search. */
         if (prev_gr == 1) { prev_gr = 0; i = (k+j)/2; goto start; } 
         if ( j-k < 2 ) { break; }
			if( unicode <= l ) {
				j = i; 
 			} else {
            k = i;
			}
		}
 
// Was:    j = n_alone_pst; /* j/2 = [Div(j,2)] <= Div(j,2) */
    j = n_alone_pst; /* j/2 = [Div(j,2)] <= Div(j,2) */
    if ( j%2 ) j++; // Nemytykh, 30-08-2023 */
//+    j = n_alone_pst+1; /* j/2 = [Div(j,2)] <= Div(j,2) */ // Nemytykh, 30-08-2023 */

  for( k = 0, cnt = 0; cnt < n_alone_pst; cnt++ ) {
  	i = (k+j)/2;
   l = lower_alone_pairs[i].lbounder;
 	   	if( unicode == l ) {
   		  unicode = lower_alone_pairs[i].rbounder;  
  		  goto Done;
   		}
         if ( j-k < 2 ) { return usymb; }
			if( unicode < l ) {
				j = i; 
			} else {
            k = i;
			} 
   }
/**************************** It from the to_Lower function.
   j = n_alone_pst; / * j/2 = [Div(j,2)] <= Div(j,2) * /
                    / * Actually this loop takes at most [log(n_alone_pst)]+1 iterations. See the return below. * /
  for( k = 0, cnt = 0; cnt < n_alone_pst; cnt++ ) {
  	i = (k+j)/2;
   l = upper_alone_pairs[i].lbounder;
 	   	if( (unicode == l) ) {
   		  unicode = upper_alone_pairs[i].rbounder;  

  		     goto Done; 
   		}
         if ( j-k < 2 ) return usymb;
			if( unicode < l ) {
				j = i; 
			} else {
            k = i;
			} 
   }
 
****************************/

	Done:          /* ASCII test: */
         usymb = ( unicode > 127 ) ? r_int_to_utf(unicode) : unicode;
 	return usymb;
}


int ri_isCyrillic(utf usymb) {
	/* U+0400 -- U+052F, U+A640 -- U+A69F  */
	/* эти символы перенесены в группу Symbol Index Cyrillic: U+2DE0 -- U+2DFF, 
	   эти символы перенесены в группу Symbol Cyrillic numerals: ꙰-꙲ -- U+A670-U+A672  */
	/* UTF-8: 110b+bbbb 10bb+bbbb, 04hh == UTF-8: 1101+00bb 10bb+bbbb */

   /* Пропущено, добавил: U+1C80—U+1C8F -- xE1B280-xE1B28F 	 */
 		
	/* U+0400 -- U+052F, Basic and from U+052F: Supplement, 2 bytes; utf8(U+0400) = D080,  utf8(U+052F) = D4AF */
	// what = 400 Octet-4 = 80 Octet-3 = d0, what = 52F Octet-4 = af Octet-3 = d4

   unsigned long unicode = ri_utf_to_int(usymb);
   
	if( ( (usymb>>12) == 0xD ) ) { /* 2 bytes */ 
		if ( (0x400 <= unicode) && (unicode <= 0x52F) ) return 1;
	   return 0;
   }

	if( (mln & '\xE0') == mln ) { /* 3 bytes */
       /* U+1C80—U+1C8F -- xE1B280-xE1B28F */	    
   	 if ( (0x1C80 <= unicode) && (unicode <= 0x1C8F) ) return 1;
	    
		 /* U+2DE0 -- U+2DFF, Extended-A, 3 bytes; utf8(U+2DE0) = 0xE2B7A0, utf8(U+2DFF) = 0xE2B7BF */
   	 /* U+2DE0   -- Is not an utf-8 symbol?!  // U+2DFF      Error? ASCII? */
   	 /* what = 2DE0 Octet-4 = a0 Octet-3 = b7 Octet-2 = e2, what = 2DFF Octet-4 = bf Octet-3 = b7 Octet-2 = e2 */
   	 /* эти символы перенесены в группу Symbol Index Cyrillic: U+2DE0 -- U+2DFF */
   	 /* if ( (0x2DE0 <= unicode) && (unicode <= 0x2DFF) ) return 1; */
	
	   /* U+A640 -- U+A69F, Extended-B; utf8(U+A640) = 0xEA9980, utf8(U+A69F) = 0xEA9A9F */
	   /* what = A640 Octet-4 = 80 Octet-3 = 99 Octet-2 = ea, what = A69F Octet-4 = 9f Octet-3 = 9a Octet-2 = ea */
	         /* эти символы перенесены в группу Symbol Cyrillic numerals: ꙰-꙲ -- U+A670-U+A672 */
	   if ( ((0xA640 <= unicode) && (unicode <= 0xA69F)) && !((0xA670 <= unicode) && (unicode <= 0xA672)) ) return 1;
	}  
	
	return 0;
}
 
int ri_isLatin(utf usymb) {
	/* 1. U+0000 -- U+017F */
	    /* U+0000 -- U+007F , Basic Latin
	       At code point 01 to 1F, ASCII, ISO 8859-1 and Unicode contain control characters that cannot be displayed.
	    */
	    /* U+0080 -- U+00FF, Latin-1 Supplement
	       At code point 7F to 9F, ISO8859-1 and Unicode have invisible control characters. 
	       Most newer browser do display characters from Microsofts codepage Windows-1252 (Western European) here. 
	       Most notably something that looks like a Euro symbol at position 80. This, however, is dangerous. 
	       You cannot trust that these characters will be visible on other PCs than your own. 
	       While most modern browsers handle this "ISO 8859-1 to Windows-1252" replacement just fine, 
	       many email programs do not. A mail with a non-standard Euro sign may look crippled on the recipients computer. 
	       Btw, the "real" Euro-symbol is at code point 20AC in Unicode.
	       ----       управляющие символы: U+0080-U+009F
	                  печатные символы: U+00A0-U+00BF
	                     из них: U+00B2, U+00B3, U+00B9 (верхние индексы цифры)
	                             U+00BС -- U+00BE (дроби)
	                  латинские буквы: U+00C0-U+00FF
	                         здесь в середине исключение U+00D7, U+00F7 перенесены в (математические) знаки
                     другие знаки в этом отрезке: U+00F7, U+00A0
	    */
	    /* U+0100 -- U+017F, Extended-A; U+0180 -- U+024F, Extended-B; */
		       /*   ƀ- ƿ -- U+0180-U+01BF -- old Latin for ancient ono-Europien languages. moved to the old group */
	/* 2.0 U+01C4 -- U+024F, Extended-B; */
		       /*   ǝ-ǿ -- U+01DD-U+01FF -- old Latin for phonetic and ancient alphabets. moved to the old group  */
	/* 2. U+1E00 -- U+1EFF, Extended Additional */
	         /*     ẜ->ẝ  U+1E9C-U+1E9D -- +-1 Moved to the old group
		             Ỻ-ỿ U+1EFA-U+1EFF    +-1 */

	/* 3. U+2460 -- U+24FF, Enclosed Alphanumerics --> moved to the symbol group. */
	/* 4. U+2C60 -- U+2C7F, Extended-C */
	/* 5. U+A720 -- U+A787, U+A78D -- U+A7FF,!= U+A78F Extended-D */
	/* 5.a U+AB30 -- U+AB6F, Extended-E  */
	/*-- 6. U+FB00 -- U+FB4F, Alphabetic Presentation Forms , They belong to Hebrew */
	/* 7. U+FE50 -- U+FE6F, Small Form Variants */
	

   unsigned long unicode = ri_utf_to_int(usymb);
 	
	/* 1. U+00C0 -- U+017F, 2 bytes: utf8(U+?????) = 0x80, utf8(U+017F) = 0xC5BF */
 	if(  (0xC0 <= unicode) && (unicode <= 0x17F) ) { /* 2 bytes, where char <= 0xC3BF codes of an one byte character: 
                                                 Latin-1 = Basic Latin-1 + Latin-1 Supplement */
	    /* U+0100 -- U+017F, Extended-A; U+0180 -- U+024F, Extended-B; */
		       /*   ƀ-ƿ -- U+0180-U+01BF -- old Latin for ancient ono-Europien languages. moved to the old group */
		       /*   ǝ-ǿ -- U+01DD-U+01FF -- old Latin for phonetic and ancient alphabets. moved to the old group  */
	     if ( (unicode != 0xD7) && (unicode != 0xF7) /* moved to the group of (mathematical) symbols */
	        ) return 1;
        return 0;
	} 

	 {                             /* 2.0 U+01C4 -- U+024F, Extended-B; */
	  if ( (0x1C0 <= unicode) && (unicode <= 0x1DC) ) return 1;
	  if ( (0x200 <= unicode) && (unicode <= 0x24F) ) return 1;
	 }
		/* 2. U+1E00 -- U+1EFF, Extended Additional; utf8(U+1E00) = 0xE1B880, utf8(U+1EFF) = 0xE1BBBF */
	         /*     ẜ->ẝ  U+1E9C-U+1E9D -- +-1 Moved to the old group
		             Ỻ-ỿ U+1EFA-U+1EFF    +-1 */
	  if ( (0x1E9C == unicode) || (0x1E9D == unicode) || ((0x1E9C <= unicode) && (unicode <= 0x1E9F)) || 
	       ((0x1EFA <= unicode) && (unicode <= 0x1EFF))
	     ) return 0;  /* Moved to the old group. */
	  		                                           /*  U+1E00 -- U+1EFF, Extended Additional: 
		                                                  Ạ-ỹ -- U+1EA0-U+1EF9 +-1
		                                             */

      if ( (0x1E00 <= unicode) && (unicode <= 0x1EF9) ) return 1;
		
		/* Moved to the symbol group.	
	   / * 3. U+2460 -- U+24FF, Enclosed Alphanumerics; utf8(U+2460) = 0xE291A0, utf8(U+24FF) = 0xE293BF * /
	   / * what = 2460 Octet-4 = a0 Octet-3 = 91 Octet-2 = e2, what = 24FF Octet-4 = bf Octet-3 = 93 Octet-2 = e2 * /
	   if ( (0xE291A0 <= usymb) && (usymb <= 0xE293BF) ) { return 1; }
	   */
			
	   /* 4. U+2C60 -- U+2C7F, Extended-C; utf8(U+2C60) = 0xE2B1A0, utf8(U+2C7F) = 0xE2B1BF  */
	   if ( (0x2C60 <= unicode) && (unicode <= 0x2C7F) ) return 1;
  
   	/* 5. U+A720 -- U+A7FF, Extended-D; utf8(U+A720) = 0xEA9CA0, utf8(U+A7FF) = 0xEA9FBF */
   	/* 5. U+A720 -- U+A787, U+A78D -- U+A7FF,!= U+A78F Extended-D */
   	if ( ((0xA720 <= unicode) && (unicode <= 0xA787)) || ((0xA78D <= unicode) && (unicode <= 0xA7FF) && (unicode != 0xA78F)) ) return 1;

	  /* 5.a U+AB30 -- U+AB6F, Extended-E */
   	if ( (0xAB30 <= unicode) && (unicode <= 0xAB6F) ) return 1;

			
	/*-- 6. U+FB00 -- U+FB4F, Alphabetic Presentation Forms. They belong to Hebrew */

			
	   /* 7. U+FE50 -- U+FE6F, Small Form Variants; utf8(U+FE50) = 0xEFB990 , utf8(U+FE6F) = 0xEFB9AF */
   	if ( (0xFE50 <= unicode) && (unicode <= 0xFE6F) ) return 1;
			
	return 0;	
}

/* Mathematical alphabet letters */
int ri_isMath(utf usymb) {
/*	U+1D400 -- U+1D7CD;  utf8(U+1D400) = 0xF09D9080 , utf8(U+1D7CD) = 0xF09D9F8D	 */

   unsigned long unicode = ri_utf_to_int(usymb);

/* Mathematical Bold Capital 𝐀 -- Mathematical Bold Small Digamma 𝟋 (U+1D7CB).
   The last two simbols U+1D7CC and U+1D7CD are still empty.
   https://unicode-table.com/en/blocks/mathematical-alphanumeric-symbols/
*/   
	if( (0x1D400 <= unicode) && (unicode <= 0x1D7CD) ) {   /* 4 bytes */
	    return 1;
   }
   
   return 0;
}

int ri_isSymbols(utf usymb) {
	/* 0. ----       Исключения: U+00D7 и U+00F7 (математические знаки) перенесены из раздела Latin-1 
	                             U+00A0 (неразрываемый пробел) перенесен из раздела Latin-1
	                             U+00B2, U+00B3, U+00B9 (верхние индексы цифры) перенесены из раздела Latin-1
	*/
	/* 00. U+02B0-U+02D5: ʰ-ʸ -- U+02B0-U+02B8, ʹ-ˋ -- U+02B9-U+02CB, ˌ-˕ -- U+02CC-U+02D5
	       U+02D8-U+02DD: ˘-˚ -- U+02D8-U+02DA, ˛-- U+02DB, ˜-˝ U+02DC-U+02DD,
	       U+02EA-U+02F3: ˪-˫ -- U+02EA-U+02EB, ˬ -- U+02EC, ˭ -- U+02ED, ˮ -- U+02EE, ˯-˳ -- U+02EF-U+02F3,
	       ˷ -- U+02F7,
	       U+02F9-U+02FF: ˹-˺ -- U+02F9-U+02FA, ˻-˿ -- U+02FB-U+02FF
	*/ 
	/* 01. ᴀᴃ-ᴥ-ᴦ-ᴪ-ᴫ -- U+1D00-U+1D25-U+1D26-U+1D2A-U+1D2B -- эти буквы можно считать индексами или написанными мелким шрифтом -- непонятно */
	/* 0a. ᴬ-ᵂ -- U+1D2C-U+1D42, ᵃ-ᵜ-ᵝ-ᵡ -- U+1D43-U+1D5C-U+1D5D-U+1D61, Superscripts
	       ᵸ -- U+1D78,
	       ᵢ-ᵪ -- U+1D62-U+1D6A, Subscripts
	*/
	/* 1. U+2070 -- U+20CF */
	     /* U+2070 -- U+209F, Superscripts and Subscripts */
	     /* U+20A0 -- U+20CF, Currency Symbols */
	/* 2. U+2100 -- U+218F */
	     /* U+2100 -- U+214F, Letterlike Symbols */
	     /* U+2150 -- U+218F, Number Forms */
	/* 3. U+2200 -- U+22FF, Mathematical Operators */
	/* 3a. U+2460 -- U+24FF, Enclosed Alphanumerics --> moved from the symbol groop. */
	/* 4. U+27C0 -- U+27EF, Miscellaneous Mathematical Symbols-A */
	/* 4a. ⱽ -- U+2C7D */
	/* 5. U+2980 -- U+2AFF */
	     /* U+2980 -- U+29FF, Miscellaneous Mathematical Symbols-B */
	     /* U+2A00 -- U+2AFF, Supplemental Mathematical Operators */
	          /* эти симолы перенесены в группу Symbol из Cyrillic: U+2DE0 -- U+2DFF */
	         /* эти символы перенесены в группу Symbol из Cyrillic -- numerals: ꙰-꙲ -- U+A670-U+A672 */
	/* 6. U+A700-U+A707: ꜀-꜁ -- U+A700-U+A701, ꜂-꜅ -- U+A702-U+A705, ꜆-꜇ U+A706-U+A707, 
	      U+A717-U+A71F: ꜗ-ꜚ -- U+A717-U+A71A, ꜛ-ꜞ -- U+A71B-U+A71E, ꜟ -- U+A71F, 
	       ꞈ -- U+A788  
	*/
	/* 7. Fullwidth Digits:  ０-９ -- U+FF10-U+FF19 -- moved from the Japanese group. */
	/* 8.    	           -- and  ！-／  -- U+FF01-U+FF0F, ：-＠  -- U+FF1A-U+FF20, 
   	                                       ［-｀ -- U+FF3B-U+FF40, ｛-･ -- U+FF5B-U+FF65,
                                      ￠-￦ -- U+FFE0-U+FFE6, ￨-￮ -- U+FFE8-U+FFEE 
                                      ------- these chracters from the Japanese group. 
   */
   /* 9. General Punctuation: --  Range: U+2000—U+206F */


   /* Take into account. The following C-output in incorrect: printf("\n Ⅷ, Ⅷ; Ⅷ Ⅷ"); 
      The gcc-team should be informed!
   */
   
   /* 10; Other mathematical digit fonts: 𝟎-𝟗 -- U+1D7CE-U+1D7D7, 𝟘-𝟡 -- U+1D7D8-U+1D7E1, 𝟢-𝟫 -- U+1D7E2-U+1D7EB, 
                                          𝟬-𝟵 -- U+1D7EC-U+1D7F5, 𝟶-𝟿 -- U+1D7F6-U+1D7FF
   */
 
    unsigned long unicode = ri_utf_to_int(usymb);
 
                       /* 3 bytes; moved from the Latin-1 group */
	if ( (unicode == 0xA0) || (unicode == 0xD7) || (unicode == 0xF7) ) return 1;

	if( ((0x2B0 <= unicode) && (unicode <= 0x2D5)) || ((0x2D8 <= unicode) && (unicode <= 0x2DD)) || ((0x2EA <= unicode) && (unicode <= 0x2F3)) ||
	    (unicode <= 0x2F7) || ((0x2F9 <= unicode) && (unicode <= 0x2FF))
	  ) { /* 3 bytes */
	    return 1;
   };  

 /* 9. General Punctuation: --  Range: U+2000—U+206F */
	if( ((0x2000 <= unicode) && (unicode <= 0x206F)) ) { /* 3 bytes */
	    return 1;
   };  
	   
	if( ((0x1D00 <= unicode) && (unicode <= 0x1D6A)) || (unicode == 0x1D78) || ((0x1D9B <= unicode) && (unicode <= 0x1DBF)) || (unicode == 0x2C7D)
// Was:	    ((0x1D2C <= unicode) && (unicode <= 0x1D6A)) || ((0x1D9B <= unicode) && (unicode <= 0x1DBF)) || ((0x1D00 <= unicode) && (unicode <= 0x1D2B))
	  ) { /* 3 bytes */
	    return 1;
   };  
	   
	if( ( (usymb>>16) == 0xE2 ) ) { /* 3 bytes */
   	/* 1. U+2070 -- U+20CF; utf8(U+2070) = 0xE281B0 , utf8(U+20CF) = 0xE2838F  */
   	if ( (0xE281B0 <= usymb) && (usymb <= 0xE2838F) ) { return 1; }
					
	   /* 2. U+2100 -- U+218F; utf8(U+2100) = 0xE28480 , utf8(U+218F) = 0xE2868F */
	   if ( (0xE28480 <= usymb) && (usymb <= 0xE2868F) ) { return 1; }

	   /* 3. U+2200 -- U+22FF, Mathematical Operators; utf8(U+2200) = 0xE28880 , utf8(U+22FF) = 0xE28BBF */
	   if ( (0xE28880 <= usymb) && (usymb <= 0xE28BBF) ) { return 1; }
	   
	   /* Moved rom the symbol groop.	*/
	   /* 3a. U+2460 -- U+24FF, Enclosed Alphanumerics; utf8(U+2460) = 0xE291A0, utf8(U+24FF) = 0xE293BF */
	   if ( (0xE291A0 <= usymb) && (usymb <= 0xE293BF) ) { return 1; }

	   /* 4. U+27C0 -- U+27EF, Miscellaneous Mathematical Symbols-A; utf8(U+27C0) = 0xE29F80 , utf8(U+27EF) = 0xE29FAF */
	   if ( (0xE29F80 <= usymb) && (usymb <= 0xE29FAF) ) { return 1; }

	   /* 5. U+2980 -- U+2AFF; utf8(U+2980) = 0xE2A680 , utf8(U+2AFF) = 0xE2ABBF */
	   if ( (0xE2A680 <= usymb) && (usymb <= 0xE2ABBF) ) { return 1; }
	   
	   /* 6. U+2DE0 -- U+2DFF; */
	   /* эти симолы перенесены в группу Symbol из Cyrillic: U+2DE0 -- U+2DFF */
	   if ( (0x2DE0 <= unicode) && (unicode <= 0x2DFF) ) return 1; 

	}

	         /* эти символы перенесены в группу Symbol из Cyrillic numerals: ꙰-꙲ -- U+A670-U+A672 */
	   if ( ((0xA670 <= unicode) && (unicode <= 0xA672)) ) return 1;

   /* 6. */
	/* 6. U+A700-U+A707: ꜀-꜁ -- U+A700-U+A701, ꜂-꜅ -- U+A702-U+A705, ꜆-꜇ U+A706-U+A707, 
	      U+A717-U+A71F: ꜗ-ꜚ -- U+A717-U+A71A, ꜛ-ꜞ -- U+A71B-U+A71E, ꜟ -- U+A71F, 
	       ꞈ -- U+A788  
	*/
  	/* 4a. ⱽ -- U+2C7D */
	if( ((0xA700 <= unicode) && (unicode <= 0xA707)) || ((0xA717 <= unicode) && (unicode <= 0xA71F)) || (unicode == 0xA788) ) { /* 3 bytes */
	    return 1;
   };  

	/* 7. Fullwidth Digits:  ０-９ -- U+FF10-U+FF19 -- moved from the Japanese group. */
	if( ((0xFF10 <= unicode) && (unicode <= 0xFF19)) ) { /* 3 bytes */
	    return 1;
   };  
	/* 8.    	           -- and  ！-／  -- U+FF01-U+FF0F, ：-＠  -- U+FF1A-U+FF20, 
   	                                       ［-｀ -- U+FF3B-U+FF40, ｛-･ -- U+FF5B-U+FF65,
                                      ￠-￦ -- U+FFE0-U+FFE6, ￨-￮ -- U+FFE8-U+FFEE 
                                      ------- these chracters from the Japanese group. 
   */
	if( ((0xFF01 <= unicode) && (unicode <= 0xFF0F)) || ((0xFF1A <= unicode) && (unicode <= 0xFF20)) ||
	    ((0xFF3B <= unicode) && (unicode <= 0xFF40)) || ((0xFF5B <= unicode) && (unicode <= 0xFF65)) ||
	    ((0xFFE0 <= unicode) && (unicode <= 0xFFE6)) || ((0xFFE8 <= unicode) && (unicode <= 0xFFEE))
	  ) { /* 3 bytes */
	    return 1;
   };  

   /* 10; Other mathematical digit fonts: 𝟎-𝟗 -- U+1D7CE-U+1D7D7, 𝟘-𝟡 -- U+1D7D8-U+1D7E1, 𝟢-𝟫 -- U+1D7E2-U+1D7EB, 
                                          𝟬-𝟵 -- U+1D7EC-U+1D7F5, 𝟶-𝟿 -- U+1D7F6-U+1D7FF
   */
	if( ((0x1D7CE <= unicode) && (unicode <= 0x1D7FF)) ) { /* 4 bytes */
	    return 1;
   };  

	return 0;
}

int ri_isIndex (utf usymb) {
	/* 0. ²,³,¹ -- U+00B2, U+00B3, U+00B9 */
	/* 1. Was: ⁰,¹,²,³,⁴-⁹⁺⁻⁼⁽⁾ vs ₀-₉₊₋₌₍₎ -- U+2070,U+00B9,U+00B2,U+00B3,U+2074-U+2079,U+207A-U+207E vs U+2080-U+2089,U+208A-U+208E    */
	/* 1. ⁰⁻⁹⁺⁻⁼⁽⁾ vs ₀-₉₊₋₌₍₎ -- U+2070-U+207E vs U+2080-U+208E    */
	/* 1.0 ⁿ  -- U+207F */
	/* 1.a. ₐ-ₜ -- U+2090-U+209C */
	/* 2. ᴀᴃ-ᴥ-ᴦ-ᴪ-ᴫ -- U+1D00-U+1D25-U+1D26-U+1D2A-U+1D2B -- эти буквы можно считать индексами или написанными мелким шрифтом -- непонятно */
	/* 3. ᴬ-ᵂ -- U+1D2C-U+1D42, ᵃ-ᵜ-ᵝ-ᵡ -- U+1D43-U+1D5C-U+1D5D-U+1D61 (ᵘ->ᵤ -- U+1D58->U+1D64, ᵛ->ᵥ -- U+1D5B->U+1D65), ᵢ-ᵪ -- U+1D62-U+1D6A,
	      ᵸ -- U+1D78,
	      ᶛ-ᶿ -- U+1D9B-U+1DBF, 
	*/
	/* 4. ₐₑₒ-ₔ-ₜ -- U+2090-U+2091-U+2092-U+2094-U+209C,  */
	/* 0. U+02B0-U+02D5: ʰ-ʸ -- U+02B0-U+02B8, ʹ-ˋ -- U+02B9-U+02CB, ˌ-˕ -- U+02CC-U+02D5
	      U+02D8-U+02DD: ˘-˚ -- U+02D8-U+02DA, ˛-- U+02DB, ˜-˝ U+02DC-U+02DD,
	      U+02EA-U+02F3: ˪-˫ -- U+02EA-U+02EB, ˬ -- U+02EC, ˭ -- U+02ED, ˮ -- U+02EE, ˯-˳ -- U+02EF-U+02F3,
	      ˷ -- U+02F7,
	      U+02F9-U+02FF: ˹-˺ -- U+02F9-U+02FA, ˻-˿ -- U+02FB-U+02FF
	*/ 
	/* 1.b. ⱽ -- U+2C7D */
	/* 1.с  ⷠ-ⷿ  эти симолы перенесены из группы Cyrillic: U+2DE0 -- U+2DFF */
	/* 5. U+A700-U+A707: ꜀-꜁ -- U+A700-U+A701, ꜂-꜅ -- U+A702-U+A705, ꜆-꜇ U+A706-U+A707,
	      U+A717-U+A71F: ꜗ-ꜚ -- U+A717-U+A71A, ꜛ-ꜞ -- U+A71B-U+A71E, ꜟ -- U+A71F,
	      ꞈ -- U+A788,
	*/

    unsigned long unicode = ri_utf_to_int(usymb);

   if ( (unicode == 0x00B2) || (unicode == 0x00B3) || (unicode == 0x00B9) ||
        ((0x2070 <= unicode) && (unicode <= 0x208E)) || 
        ((0x2090 <= unicode) && (unicode <= 0x209C)) || (unicode == 0x2C7D) || 
        ((0x1D00 <= unicode) && (unicode <= 0x1D6A)) || (unicode == 0x1D78) || ((0x1D9B <= unicode) && (unicode <= 0x1DBF)) ||
        ((0x2B0 <= unicode) && (unicode <= 0x2D5)) || ((0x2D8 <= unicode) && (unicode <= 0x2DD)) || ((0x2EA <= unicode) && (unicode <= 0x2F3)) ||
                     (unicode == 0x2F7) || 
                     ((0x2DE0 <= unicode) && (unicode <= 0x2DFF)) || /* 1.с  ⷠ-ⷿ  эти символы перенесены из группы Cyrillic: U+2DE0 -- U+2DFF */
                     ((0x2F9 <= unicode) && (unicode <= 0x2FF)) ||
        ((0xA700 <= unicode) && (unicode <= 0xA707)) || ((0xA717 <= unicode) && (unicode <= 0xA71F)) || (unicode == 0xA788)
	   ) { return 1; }
	return 0;
}

char * IndexCase (utf usymb) {
	/* 1. Was: ⁰,¹,²,³,⁴-⁹⁺⁻⁼⁽⁾ vs ₀-₉₊₋₌₍₎ -- U+2070,U+00B9,U+00B2,U+00B3,U+2074-U+2079,U+207A-U+207E vs U+2080-U+2089,U+208A-U+208E    */
	/* 1. ⁰⁻⁹⁺⁻⁼⁽⁾ vs ₀-₉₊₋₌₍₎ -- U+2070-U+207E vs U+2080-U+208E    */
	/* 1.0 ⁿ  -- U+207F */
	/* 1.a. ₐ-ₜ -- U+2090-U+209C */
	/* 1.b. ⱽ -- U+2C7D */
	/* 1.с  ⷠ-ⷿ  эти симолы перенесены из группы Cyrillic: U+2DE0 -- U+2DFF */

	/* 2. ᴀᴃ-ᴥ-ᴦ-ᴪ-ᴫ -- U+1D00-U+1D25-U+1D26-U+1D2A-U+1D2B -- эти буквы можно считать индексами или написанными мелким шрифтом -- непонятно */
	/* 3. ᴬ-ᵂ -- U+1D2C-U+1D42, ᵃ-ᵜ-ᵝ-ᵡ -- U+1D43-U+1D5C-U+1D5D-U+1D61 (ᵘ->ᵤ -- U+1D58->U+1D64, ᵛ->ᵥ -- U+1D5B->U+1D65), 
	      ᵢ-ᵥ -- U+1D62-U+1D65, ᵦ-ᵪ -- U+1D66-U+1D6A,
	      ᵸ -- U+1D78,
	      ᶛ-ᶿ -- U+1D9B-U+1DBF, 
	*/
	/* ToDo: ʰ-ʸ -- U+02B0-U+02B8, ʹ-ˋ -- U+02B9-U+02CB, ˌ-˕ -- U+02CC-U+02D5, 
	         ˘-˚ -- U+02D8-U+02DA, ˛-- U+02DB, ˜-˝ U+02DC-U+02DD, ˪-˫ -- U+02EA-U+02EB, ˬ -- U+02EC, ˭ -- U+02ED
	         ˮ -- U+02EE, ˯-˳ -- U+02EF-U+02F3, ˷ -- U+02F7, ˹-˺ -- U+02F9-U+02FA, ˻-˿ -- U+02FB-U+02FF
	        ꜀-꜁ -- U+A700-U+A701, ꜂-꜅ -- U+A702-U+A705, ꜗ-ꜚ -- U+A717-U+A71A, ꜛ-ꜞ -- U+A71B-U+A71E, ꜟ -- U+A71F, ꞈ -- U+A788,  NO: (ꝰ -- U+A770)
	*/
	/* 0. U+02B0-U+02D5: ʰ-ʸ -- U+02B0-U+02B8, ʹ-ˋ -- U+02B9-U+02CB, ˌ-˕ -- U+02CC-U+02D5
	      U+02D8-U+02DD: ˘-˚ -- U+02D8-U+02DA, ˛-- U+02DB, ˜-˝ U+02DC-U+02DD,
	      U+02EA-U+02F3: ˪-˫ -- U+02EA-U+02EB, ˬ -- U+02EC, ˭ -- U+02ED, ˮ -- U+02EE, ˯-˳ -- U+02EF-U+02F3,
	      ˷ -- U+02F7,
	      U+02F9-U+02FF: ˹-˺ -- U+02F9-U+02FA, ˻-˿ -- U+02FB-U+02FF
	*/ 
	/* 5. U+A700-U+A707: ꜀-꜁ -- U+A700-U+A701, ꜂-꜅ -- U+A702-U+A705, ꜆-꜇ U+A706-U+A707,
	      U+A717-U+A71F: ꜗ-ꜚ -- U+A717-U+A71A, ꜛ-ꜞ -- U+A71B-U+A71E, ꜟ -- U+A71F,
	      ꞈ -- U+A788,
	*/

    unsigned long unicode = ri_utf_to_int(usymb);

   if ( (unicode == 0x00B2) || (unicode == 0x00B3) || (unicode == 0x00B9) ||
        ((0x2B0 <= unicode) && (unicode <= 0x2CB)) || ((0x2D8 <= unicode) && (unicode <= 0x2DD) && (unicode != 0x2DB)) ||
             ((0x2EA <= unicode) && (unicode <= 0x2EE) && (unicode != 0x2EC)) || ((0x2F9 <= unicode) && (unicode <= 0x2FA)) ||
        ((0x2070 <= unicode) && (unicode <= 0x207F)) || 
        (unicode == 0x2C7D) ||  
        ((0x2DE0 <= unicode) && (unicode <= 0x2DFF)) || /* 1.с  ⷠ-ⷿ  эти симолы перенесены из группы Cyrillic: U+2DE0 -- U+2DFF */
        ((0x1D2C <= unicode) && (unicode <= 0x1D65)) || (unicode == 0x1D78) || ((0x1D9B <= unicode) && (unicode <= 0x1DBF)) ||
        ((0xA702 <= unicode) && (unicode <= 0xA705)) || ((0xA717 <= unicode) && (unicode <= 0xA71E)) 
	   ) return strcpy(uchar_str_prop,"Top");
   return strcpy(uchar_str_prop,"Bottom");
}

int isIndexMinus(utf usymb) {
   unsigned long unicode = ri_utf_to_int(usymb);
   if ( (unicode == 0x207B) || (unicode == 0x208B) ) return 1;
	return 0;
}

/* Титла - модификаторы  ⷠ-ⷿ -- U-2DE0—U-2DFF, ꙴ  -꙽ -- U+A674-U+A67D,  */
/* Numeric - числовые - Кириллица: ꙰-꙲ -- U+A670-U+A672
   См. Range: 2150—218F
              Arabic-Indic Digit
              Mathematical Bold Digit, Mathematical Monospace Digit, 
              Mathematical Double-Struck Digit, Mathematical Sans-Serif Digit,
              Mathematical Sans-Serif Bold Digit, Fullwidth Digit,  
*/

char * ri_NumericType (utf usymb) {
/* 0. Arabic digits: .???.. 
     U+00BС -- U+00BE (Fractions)
*/
/* 1.-5.: Digit: U+1D7CE-U+1D7FF
   1. Mathematical Bold Digits: 𝟎-𝟗 -- U+1D7CE-U+1D7D7 
   2. Mathematical Double-Struck Digits: 𝟘-𝟡 -- U+1D7D8-U+1D7E1 
   3. Mathematical Sans-Serif Digits: 𝟢-𝟫 -- U+1D7E2-U+1D7EB
   4. Mathematical Sans-Serif Bold Digits: 𝟬-𝟵 -- U+1D7EC-U+1D7F5 
   5. Mathematical Monospace Digits: 𝟶-𝟿 -- U+1D7F6-U+1D7FF 
*/
/* 6. Fullwidth Digits:  ０-９ -- U+FF10-U+FF19 */
/* 7. Fractions: ⅐-⅞-⅟ -- U+2150-U+215F -- The last is fruction numerator 
              ↉ -- U+2189
*/
/*   7.-9.-8.: U+2150-U+2189
     7. Fractions: ⅐-⅞-⅟ -- U+2150-U+215F -- The last is fruction numerator
     8. Archaic Roman numerals: ↀ-ↈ -- U+2180-U+2188
     9. Roman numerals: ⅠⅡ-Ⅿ vs ⅰ-ⅿ -- U+2160-U+216F vs U+2170-U+217F 
              ↉ -- U+2189 */
/* 10. Cyrillic numerals: ꙰-꙲ -- U+A670-U+A672 -- это составные символы и тип у них просто так не определить -- разобраться */
/* 11. Arabic-Indic Digits: ٩-٠ -- U+0660-U+0669, ۰-۹ -- U+06F0-U+06F9,  */

   unsigned long unicode = ri_utf_to_int(usymb);
   
   if ( ((0x1D7CE <= unicode) && (unicode <= 0x1D7FF)) || ((0xFF10 <= unicode) && (unicode <= 0xFF19)) || 
        ((0x660 <= unicode) && (unicode <= 0x669)) || ((0x6F0 <= unicode) && (unicode <= 0x6F9)) 
	   ) return strcpy(uchar_str_prop,"Digit");
   if ( ((0x00BC <= unicode) && (unicode <= 0x00BE)) || ((0x2150 <= unicode) && (unicode <= 0x215F)) || 
        (unicode == 0x2189) ) return strcpy(uchar_str_prop,"Fraction");
   if ( (0x2160 <= unicode) && (unicode <= 0x2188) ) return strcpy(uchar_str_prop,"Roman");
   if ( (0xA670 <= unicode) && (unicode <= 0xA672) ) return strcpy(uchar_str_prop,"Cyrillic");

	return NULL; 
}

char * ri_DigitType (utf usymb) {
/* 0. Arabic digits: .???.. */
/* 1.-5.: Digit: U+1D7CE-U+1D7FF
   1. Mathematical Bold Digits: 𝟎-𝟗 -- U+1D7CE-U+1D7D7 
   2. Mathematical Double-Struck Digits: 𝟘-𝟡 -- U+1D7D8-U+1D7E1 
   3. Mathematical Sans-Serif Digits: 𝟢-𝟫 -- U+1D7E2-U+1D7EB
   4. Mathematical Sans-Serif Bold Digits: 𝟬-𝟵 -- U+1D7EC-U+1D7F5 
   5. Mathematical Monospace Digits: 𝟶-𝟿 -- U+1D7F6-U+1D7FF 
*/
/* 6. Fullwidth Digits:  ０-９ -- U+FF10-U+FF19 */
/* 11. Arabic-Indic Digits: ٩٠-٠ -- U+0660-U+0669, ۰-۹ -- U+06F0-U+06F9,  */

   unsigned long unicode = ri_utf_to_int(usymb);
   
   if ( 0x1D7CE <= unicode ) {
   	if ( unicode <= 0x1D7D7 )  return strcpy(uchar_str_prop,"Bold");
      if ( unicode <= 0x1D7E1 )  return strcpy(uchar_str_prop,"Double-Struck");
      if ( unicode <= 0x1D7EB )  return strcpy(uchar_str_prop,"Sans-Serif");
      if ( unicode <= 0x1D7F5 )  return strcpy(uchar_str_prop,"Sans-Serif-Bold");
      if ( unicode <= 0x1D7FF )  return strcpy(uchar_str_prop,"Monospace");
   }; 
   
   if ( (0xFF10 <= unicode) && (unicode <= 0xFF19) ) return strcpy(uchar_str_prop,"Fullwidth");
   if ( ((0x660 <= unicode) && (unicode <= 0x669)) || ((0x6F0 <= unicode) && (unicode <= 0x6F9)) ) 
                                                     return strcpy(uchar_str_prop,"Arabic-Indic");
   return NULL;
}


char * IndexAlphabet (utf usymb) {
	/* 0-0. ²,³,¹ -- U+00B2, U+00B3, U+00B9 */
	/* 0. ʰ-ʸ -- U+02B0-U+02B8, ˭ -- U+02ED, */ 
	/* Was: 1. ⁰,¹,²,³,⁴-⁹⁺⁻⁼⁽⁾ vs ₀-₉₊₋₌₍₎ -- U+2070,U+00B9,U+00B2,U+00B3,U+2074-U+2079,U+207A-U+207E vs U+2080-U+2089,U+208A-U+208E    */
	/* 1. ⁰⁻⁹⁺⁻⁼⁽⁾ vs ₀-₉₊₋₌₍₎ -- U+2070-U+207E vs U+2080-U+208E    */
	/* 1.0 ⁿ  -- U+207F */
	/* 1.a. ₐ-ₜ -- U+2090-U+209C */
	/* 1.b. ⱽ -- U+2C7D */
	/* 2. ᴀᴃ-ᴥ-ᴦ-ᴪ-ᴫ -- U+1D00-U+1D25-U+1D26-U+1D2A-U+1D2B -- эти буквы можно считать индексами или написанными мелким шрифтом -- непонятно */
	/* 3. ᴬ-ᵂ -- U+1D2C-U+1D42, ᵃ-ᵜ-ᵝ-ᵡ -- U+1D43-U+1D5C-U+1D5D-U+1D61 (ᵘ->ᵤ -- U+1D58->U+1D64, ᵛ->ᵥ -- U+1D5B->U+1D65), 
	      ᵢ-ᵥ -- U+1D62-U+1D65, ᵦ-ᵪ -- U+1D66-U+1D6A,
	      ᵸ -- U+1D78,
	      ᶛ-ᶿ -- U+1D9B-U+1DBF, 
	*/
	/* 5. U+A700-U+A705: ꜀-꜁ -- U+A700-U+A701, ꜂-꜅ -- U+A702-U+A705, ꜆-꜇ U+A706-U+A707, */
	
    unsigned long unicode = ri_utf_to_int(usymb);

   if ( (unicode == 0x00B2) || (unicode == 0x00B3) || (unicode == 0x00B9) ||
        ((0x2070 <= unicode) && (unicode <= 0x2079)) || ((0x2080 <= unicode) && (unicode <= 0x2089))
	   ) { return strcpy(uchar_str_prop,"Digit"); }
	else if ( ((0x207A <= unicode) && (unicode <= 0x207B)) || ((0x208A <= unicode) && (unicode <= 0x208B)) ) {
		return strcpy(uchar_str_prop,"Operation");
	} else if ( (unicode == 0x2ED) || (unicode == 0x207C) ||  (unicode == 0x208C) || ((0xA700 <= unicode) && (unicode <= 0xA707)) ) {
		return strcpy(uchar_str_prop,"Relation");
	} else if ( ((0x207D <= unicode) && (unicode <= 0x207E)) || ((0x208D <= unicode) && (unicode <= 0x208E)) ) {
		return strcpy(uchar_str_prop,"Parenthesis");
	} else if ( ((0x2B0 <= unicode) && (unicode <= 0x2B8)) ||
	            ((0x1D00 <= unicode) && (unicode <= 0x1D25)) || ((0x1D2C <= unicode) && (unicode <= 0x1D5C)) || 
	            ((0x1D62 <= unicode) && (unicode <= 0x1D65)) || (unicode == 0x207F) || ((0x2090 <= unicode) && (unicode <= 0x209C)) || (unicode == 0x2C7D) ||
	           /* ((0x1D9B <= unicode) && (unicode <= 0x1DBF))  This group includes various symbols that can be related to different alphabets. See below. */
	            (unicode == 0x1D9C) || (unicode == 0x1DA0) || (unicode == 0x1DA2) || (unicode == 0x1DA9) || (unicode == 0x1DAB) 
	                                || (unicode == 0x1DAB) || (unicode == 0x1DB0) || (unicode == 0x1DB8) || (unicode == 0x1DBB)
	          ) 
	{  return strcpy(uchar_str_prop,"Latin");          	
	} else if ( ((0x1D26 <= unicode) && (unicode <= 0x1D2A)) || ((0x1D5D <= unicode) && (unicode <= 0x1D61)) ||
	            ((0x1D66 <= unicode) && (unicode <= 0x1D6A)) || 
	           /* ((0x1D9B <= unicode) && (unicode <= 0x1DBF))  This group includes various symbols that can be related to different alphabets */
	            (unicode == 0x1D9B) || ((0x1D9D <= unicode) && (unicode <= 0x1D9F)) || (unicode == 0x1DAF) 
	                                || ((0x1DB1 <= unicode) && (unicode <= 0x1DB2)) || ((0x1DB9 <= unicode) && (unicode <= 0x1DBA))
	                                || ((0x1DBE <= unicode) && (unicode <= 0x1DBF))
	          ) 
	{  return strcpy(uchar_str_prop,"Greek");
	} else if ( (unicode == 0x1D2B) || (unicode == 0x1D78) || ((0x2DE0 <= unicode) && (unicode <= 0x2DFF))) {
		return strcpy(uchar_str_prop,"Cyrillic");
	}
   return strcpy(uchar_str_prop,"Other");
}


int ri_isWhiteSpace (utf usymb) {
/* 1.Non-breaking: 
        No-Break Space: U+00A0. */
/* General Punctuation: --  Range: U+2000—U+206F
   2.-4. Non-breaking   
   2. Figure Space: U+2007 +
   3. Narrow No-Break Space: U+202F +-
   4. Word Joiner: U+2060     ++
*/
/* 5.-6. EN:  
   5. En Quad: U+2000 +
   6. En Space: U+2002 +
*/
/* 7.-11. EM:  U+2001, U+2003-U+2006 +
   7. Em Quad: U+2001
   8. Em Space: U+2003
   9. THREE-PER-EM SPACE: 1/3 (⅓ -- U+2153) -- U+2004
   10. FOUR-PER-EM SPACE: 1/4 (¼ -- U+00BC) --  U+2005
   11. SIX-PER-EM SPACE: 1/6 (⅙ -- U+2159) -- U+2006
*/
/* 12.-14. Thin Spaces: U+2008-U+200A +
   12. Punctuation Space: U+2008
   13. Thin Space: U+2009
   14: Hair Space: U+200A
*/
/* 15.-17. Zero_width Spaces: U+200B-U+200D +
       15. ZERO-WIDTH SPACE -- U+200B, 16. Zero Width Non-Joiner -- U+200C, 17. Zero Width Joiner -- U+200D (??? maybe non-breaking??)
*/
/* 18.-23. Separators (U+2028-U+2029, U+2063, U+2065) and Marks (U+200E-U+200F): 
   18. Left-To-Right Mark: U+200E, +
   19. Right-To-Left Mark: U+200F, +
   20. Line Separator: U+2028,         +-
   21. Paragraph Separator: U+2029     +-
   22. Invisible Comma: U+2063         ++
   23. Undefined in Unicode: U+2065    ++
*/
/* 24.-32. Format characters: U+202A-U+202E, U+2066-U+2069
   24. Left-To-Right Embedding: U+202A,     +-
   25. Right-To-Left Embedding: U+202B,     +-
   26. Pop Directional Formatting: U+202C,  +-
   27. Left-To-Right Override: U+202D,      +-
   28. Right-To-Left Override: U+202E,      +-
                                                                                 
   29. Left-To-Right Isolate: U+2066,   ++
   30. Right-To-Left Isolate: U+2067,   ++
   31. First Strong Isolate: U+2068,    ++
   32. Pop Directional Isolate: U+2069, ++
*/
/* 33. MEDIUM MATHEMATICAL SPACE: U+205F, ++ */
/* 34.-36. Invisible operators: 
   34. Function Application: U+2061, ++
   35. Invisible Times: U+2062,      ++
   36. Invisible Plus: U+2064,       ++
*/
/* 37.-42. Deprecated: U+206A-U+206F  ++
   37. Inhibit Symmetric Swapping: U+206A,
   38. Activate Symmetric Swapping: U+206B,
   39. Inhibit Arabic Form Shaping: U+206C,
   40. Activate Arabic Form Shaping: U+206D,
   41. National Digit Shapes: U+206E,
   42. Nominal Digit Shapes: U+206F,
*/
/* 43. Ideographic Space: U+3000 */
/*               https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%B1%D0%B5%D0%BB
                 https://unicode-table.com/en/blocks/general-punctuation/  */


   unsigned long unicode = ri_utf_to_int(usymb);
   
   if ( (unicode == 0x00A0) ||      /* 1. */
        ( ((0x2000 <= unicode) && (unicode <= 0x206F)) &&  
             ( (unicode <= 0x200F)  /* 2, 5.-19. */
               || ((0x2028 <= unicode) && (unicode <= 0x202F)) /* 20.-21., 24.-28., 3.  */
               || ((0x205F <= unicode) && (unicode <= 0x206F)) /* 33., 4., 34.-35., 22., 36., 23., 29.-32., 37.-42. */
             )
	     ) || (unicode == 0x3000)  /* 43. */
	   ) { if ( (0x2004 <= unicode) && (unicode <= 0x2006) ) return 2;
	       else return 1;
	     }

 	return 0; 
}
 
char * ri_WhiteSpaceType (utf usymb) {
/* 1.Non-breaking: 
        No-Break Space: U+00A0. */
/* General Punctuation: --  Range: U+2000—U+206F
   2.-4. Non-breaking   
   2. Figure Space: U+2007 
   3. Narrow No-Break Space: U+202F 
   4. Word Joiner: U+2060     
*/
/* 5.-6. EN:  
   5. En Quad: U+2000 
   6. En Space: U+2002 
*/
/* 7.-11. EM:  U+2001, U+2003-U+2006 
   7. Em Quad: U+2001
   8. Em Space: U+2003
   9. THREE-PER-EM SPACE: 1/3 (⅓ -- U+2153) -- U+2004
   10. FOUR-PER-EM SPACE: 1/4 (¼ -- U+00BC) --  U+2005
   11. SIX-PER-EM SPACE: 1/6 (⅙ -- U+2159) -- U+2006
*/
/* 12.-14. Thin Spaces: U+2008-U+200A 
   12. Punctuation Space: U+2008
   13. Thin Space: U+2009
   14: Hair Space: U+200A
*/
/* 15.-17. Zero_width Spaces: U+200B-U+200D 
       15. ZERO-WIDTH SPACE -- U+200B, 16. Zero Width Non-Joiner -- U+200C, 17. Zero Width Joiner -- U+200D (??? maybe non-breaking??)
*/
/* 18.-23. Separators (U+2028-U+2029, U+2063, U+2065) and Marks (U+200E-U+200F): 
   18. Left-To-Right Mark: U+200E, 
   19. Right-To-Left Mark: U+200F, 
   20. Line Separator: U+2028,         
   21. Paragraph Separator: U+2029     
   22. Invisible Comma: U+2063         
   23. Undefined in Unicode: U+2065    
*/
/* 24.-32. Format characters: U+202A-U+202E, U+2066-U+2069
   24. Left-To-Right Embedding: U+202A,     
   25. Right-To-Left Embedding: U+202B,     
   26. Pop Directional Formatting: U+202C,  
   27. Left-To-Right Override: U+202D,      
   28. Right-To-Left Override: U+202E,      
                                                                                 
   29. Left-To-Right Isolate: U+2066,   
   30. Right-To-Left Isolate: U+2067,   
   31. First Strong Isolate: U+2068,    
   32. Pop Directional Isolate: U+2069, 
*/
/* 33. MEDIUM MATHEMATICAL SPACE: U+205F,  */
/* 34.-36. Invisible operators: 
   34. Function Application: U+2061, 
   35. Invisible Times: U+2062,      
   36. Invisible Plus: U+2064,       
*/
/* 37.-42. Deprecated: U+206A-U+206F  
   37. Inhibit Symmetric Swapping: U+206A,
   38. Activate Symmetric Swapping: U+206B,
   39. Inhibit Arabic Form Shaping: U+206C,
   40. Activate Arabic Form Shaping: U+206D,
   41. National Digit Shapes: U+206E,
   42. Nominal Digit Shapes: U+206F,
*/
/* 43. Ideographic Space: U+3000 */
/*               https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%B1%D0%B5%D0%BB
                 https://unicode-table.com/en/blocks/general-punctuation/  */


   unsigned long unicode = ri_utf_to_int(usymb);
   
   if ( (unicode == 0x00A0) || (unicode == 0x2007) || (unicode == 0x202F) || (unicode == 0x2060) ) /* 1.-4. */
              return strcpy(uchar_str_prop,"Non-breaking");
   if ( ((0x2000 == unicode) || (unicode == 0x2002)) )  /* 5.-6. EN */
	           return strcpy(uchar_str_prop,"EN");    
   if ( ((0x2001 == unicode) || ((0x2003 <= unicode) && (unicode <= 0x2006))) )  /* 7.-11. EM */
	           return strcpy(uchar_str_prop,"EM");    
   if ( ((0x2008 <= unicode) && (unicode <= 0x200D)) )  /* 12.-17. Thin Spaces */
   { if (0x2008 == unicode) return strcpy(uchar_str_prop,"Punctuation"); /* 12. */
     if (0x2009 == unicode) return strcpy(uchar_str_prop,"Thin");        /* 13. */
     if (0x200A == unicode) return strcpy(uchar_str_prop,"Hair");        /* 14. */
     return strcpy(uchar_str_prop,"Zero_width");                         /* 15.-17. */
   }
   if ( ( (unicode == 0x2028) || (unicode == 0x2029) || (unicode == 0x2063) || (unicode == 0x2065) || 
          ((0x200E == unicode) || (unicode == 0x200F))) )  /* 18.-23. Separators (U+2028-U+2029, U+2063, U+2065) and Marks (U+200E-U+200F)  */
	           return strcpy(uchar_str_prop,"Separator");    
   if ( (((0x202A <= unicode) && (unicode <= 0x202E)) || ((0x2066 <= unicode) && (unicode <= 0x2069))) )  /* 24.-32. Format characters */
	           return strcpy(uchar_str_prop,"Format_char");    
   if ( (unicode == 0x205F) )  /* 33. MEDIUM MATHEMATICAL SPACE */
	           return strcpy(uchar_str_prop,"Medium_math");    
   if ( ((0x2064 == unicode) || ((0x2061 <= unicode) && (unicode <= 0x2062))) )  /* 34.-36. Invisible operators: */
	           return strcpy(uchar_str_prop,"Invisible_operator");    
   if ( ((0x206A <= unicode) && (unicode <= 0x206F)) )  /* 37.-42. Deprecated */
	           return strcpy(uchar_str_prop,"Deprecated");    
	
   if ( unicode == 0x3000 ) return strcpy(uchar_str_prop,"Ideographic"); /* 43. */
   
 	return NULL; 
}

char * ri_WhiteSpaceWidth  (utf usymb) {
/* 5.-6. EN:  
   5. En Quad: U+2000 
   6. En Space: U+2002 
*/
/* 7.-11. EM:  U+2001, U+2003-U+2006 
   7. Em Quad: U+2001
   8. Em Space: U+2003
*/

   unsigned long unicode = ri_utf_to_int(usymb);
   
   if ( (unicode == 0x2000) || (unicode == 0x2001) ) /* 5., 7. */
              return strcpy(uchar_str_prop,"Quad");
   if ( (unicode == 0x2002) || (unicode == 0x2003) ) /* 6., 8. */
              return strcpy(uchar_str_prop,"Space");
              
   
 	return NULL; 
}
 
utf ri_WhiteSpaceLength  (utf usymb) {

/* 7.-11. EM:  U+2001, U+2003-U+2006 
   9. THREE-PER-EM SPACE: 1/3 (⅓ -- U+2153) -- U+2004
   10. FOUR-PER-EM SPACE: 1/4 (¼ -- U+00BC) --  U+2005
   11. SIX-PER-EM SPACE: 1/6 (⅙ -- U+2159) -- U+2006
*/
   unsigned long unic = 0x00BC;
   unsigned long unicode = ri_utf_to_int(usymb);
   
   if ( (unicode == 0x2004) ) unic = 0x2153;
/*   else if ( (unicode == 0x2005) ) unic = 0x00BC; */
   else if ( (unicode == 0x2006) ) unic = 0x2159; 
   return r_int_to_utf(unic);
}

int ri_isGreek(utf usymb) {
	/* 1. U+0370 -- U+03FF, Greek and Coptic */
		         /*  Excluding the symbols U+0374, U+0375 that are not letters! */

	/* 2. U+1F00 -- U+1FFF, Greek Extended */
	/* изменение регистра: xCDB0--xCDB3, xCDB6--xCDB7   +- x01
	                       xCE91--xCF89   +- x20
	                       xCF98--xCFAF, xCFB7--xCFB8   +- x01
	                       xCFBA--xCFBB                 +- x01
	                       xE1BC80--xE1BC8F, xE1BC90--xE1BC9D  +- x08  --- в этой группе прописные следуют за строчными
	                       xE1BCA0--xE1BCAF, xE1BCB0--xE1BCBF  +- x08  --- в этой группе прописные следуют за строчными
	                       xE1BD80--xE1BD8D X X, xE1BD90--xE1BD9F ..X_(2k+1).. +- x08 
	                                                                   --- в этой группе прописные следуют за строчными
	                       xE1BDA0--xE1BDAF, xE1BE80--xE1BE8F  +- x08  --- в этой группе прописные следуют за строчными
	                       xE1BE90--xE1BE9F, xE1BEA0--xE1BEAF  +- x08  --- в этой группе прописные следуют за строчными
	                       xE1BEB0- на этом отрезке только 2 первые и две последние-xE1BEB9 +- x08  
	                                                                   --- в этой группе прописные следуют за строчными
	                       xE1BF90- на этом отрезке только 2 первые и две последние-xE1BF99 +- x08 		 	 	 	 	 	
	                                                                   --- в этой группе прописные следуют за строчными
	                       xE1BFA0- на этом отрезке только 2 первые и две последние-xE1BFA9 +- x08 		 	 	 	 	 	
	                                                                   --- в этой группе прописные следуют за строчными
	*/

    unsigned long unicode = ri_utf_to_int(usymb);

	if( ( (usymb>>12) == 0xC ) ) { /* 2 bytes */
   if ( (0x370 <= unicode) && (unicode <= 0x3FF) &&
	        (unicode != 0x374) && (unicode != 0x375) /*  These symbols are not letters! */
	      ) return 1;

    return 0;
	}
					
	if( (usymb>>12) == 0xE1B ) { /* 3 bytes */
	   /* 2. U+1F00 -- U+1FFF; tf8(U+1F00) = 0xE1BC80, utf8(U+1FFF) = 0xE1BFBF */
	   if ( (0x1F00 <= unicode) && (unicode <= 0x1FFF) ) return 1;
	}

 	return 0;
}
   
int ri_isArabic(utf usymb) {  /* aRabic */
  /* Arabic is one of the most widespread writing systems in the world (cf. world map of writing systems). 
     It is an alphabet script. It is written right-to-left. Unicode contains approximately 1.100 code points 
     for Arabic characters. Among others, Arabic contains the digits ٩ | ٨ | ٧ | ٦ | ٥ | ٤ | ٣ | ٢ | ١ | ٠ 
     starting at code point U+0660, from which the Latin digits 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 have developed. 
     All latin characters can be used in webpages coded with HTML charset UTF-8. 
  */
  /* 1. U+0600 -- U+06FF */
  /* 2. U+0750 -- U+077F, Arabic Supplement */
  /* 3. U+08A0 -- U+08FF, Arabic Extended-A */
  /* 4. U+FB50 -- U+FDFF, Arabic Presentation Forms-A */
  /* 5. U+FE70 -- U+FEFF, Arabic Presentation Forms B */
  
	if( ( (usymb>>12) == 0xD ) ) { /* 2 bytes */
  	   /* 1. U+0600 -- U+06FF; tf8(U+0600) = 0xD880, utf8(U+06FF) = 0xDBBF */
  	   if ( (0xD880 <= usymb) && (usymb <= 0xDBBF) ) { return 1; }
					
	   /* 2. U+0750 -- U+077F; tf8(U+0750) = 0xDD90, utf8(U+077F) = 0xDDBF */
	   if ( (0xDD90 <= usymb) && (usymb <= 0xDDBF) ) { return 1; }
	   
	   return 0;
	}

	if( (mln & '\xE0') == mln ) { /* 3 bytes */
	   /* 3. U+08A0 -- U+08FF; tf8(U+08A0) = 0xE0A2A0, utf8(U+08FF) = 0xE0A3BF */
	   if ( (0xE0A2A0 <= usymb) && (usymb <= 0xE0A3BF) ) { return 1; }
	   
	   /* 4. U+FB50 -- U+FDFF; tf8(U+FB50) = 0xEFAD90, utf8(U+FDFF) = 0xEFB7BF */
	   if ( (0xEFAD90 <= usymb) && (usymb <= 0xEFB7BF) ) { return 1; }
	   
   	/* 5. U+FE70 -- U+FEFF; tf8(U+FE70) = 0xEFB9B0, utf8(U+FEFF) = 0xEFBBBF */
   	if ( (0xEFB9B0 <= usymb) && (usymb <= 0xEFBBBF) ) { return 1; }
   }

   return 0;
}
      
int ri_isHebrew(utf usymb) {
	 /* 1. U+0590 -- U+05FF */
	 /* 2. U+FB00 -- U+FB4F, Alphabetic Presentation Forms */
	
	if( ( (usymb>>12) == 0xD ) ) { /* 2 bytes */
   	/* 1. U+0590 -- U+05FF; tf8(U+0590) = 0xD690, utf8(U+05FF) = 0xD7BF */
   	if ( (0xD690 <= usymb) && (usymb <= 0xD7BF) ) { return 1; }
	   return 0;
	}
					
	if( (usymb>>12) == 0xEFA ) { /* 3 bytes */
	   /* 2. UU+FB00 -- U+FB4F; tf8(U+FB00) = 0xEFAC80, utf8(U+FB4F) = 0xEFAD8F */
	   if ( (0xEFAC80 <= usymb) && (usymb <= 0xEFAD8F) ) { return 1; }
	}

	return 0;
 } 
         
int ri_isArmenian(utf usymb) {
	/* 1. U+0530 -- U+058F */
	    /* Изменение регистра: Ա-Ֆ -- U+0531-U+0556 и ա-ֆ -- U+0561-U+0556 +-0x30 */
	/* 2. U+FB00 -- U+FB4F, Alphabetic Presentation Forms. See Hebrew characters  above. */
	
	if( ( (usymb>>12) == 0xD ) ) { /* 2 bytes */
	   /* 1. U+0530 -- U+058F; tf8(U+0530) = 0xD4B0, utf8(U+058F) = 0xD68F */
	   if ( (0xD4B0 <= usymb) && (usymb <= 0xD68F) ) { return 1; }
	}
	
	return 0;
}
         
int ri_isGeorgian(utf usymb) { /* Mchedruli */
   /* 1. U+10A0 -- U+10FF */
	   /* Изменение регистра: Ⴀ-Ⴥ -- U+10A0-U+10C5 и ⴀ-ⴥ -- U+2D00-U+2D25 +-0x1C60 */
	/* 1.a  U+1C90 -- U+1CBF, Georgian Extended */
 	   /* Изменение регистра: Ა-Ჰ -- U+1C90-U+1CB0 и ა-ჰ -- U+10D0-U+10F0 -+0xBC0 */
   /* 2. U+2D00 -- U+2D2F, Georgian Supplement */

    unsigned long unicode = ri_utf_to_int(usymb);
   
	if( (mln & '\xE0') == mln ) { /* 3 utf8-bytes */
      /* 1. U+10A0 -- U+10FF; tf8(U+10A0) = 0xE182A0, utf8(U+10FF) = 0xE183BF  */
      if ( (0x10A0 <= unicode) && (unicode <= 0x10FF) ) return 1;
					
 	/* 1.a  U+1C90 -- U+1CBF, Georgian Extended */
      if ( (0x1C90 <= unicode) && (unicode <= 0x1CBF) ) return 1;

  	/* 2. U+2D00 -- U+2D2F, Georgian Supplement; tf8(U+2D00) = 0xE2B480, utf8(U+2D2F) = 0xE2B4AF */
      if ( (0x2D00 <= unicode) && (unicode <= 0x2D2F) ) return 1;
	}

   return 0;
}    
       
int ri_isBrahmic(utf usymb) { /* Indic Scripts */
   /* Brahmic 1:
     India and Southeast Asia are considered to be the world’s region with the most writing systems. 
     Here, only the main official languages and fonts are shown:

    Devanagari (India), Bengali (Bangladesh), Tamilisch / Singhalese (Sri Lanka), Thai (Thailand),
    Lao (Laos), Myanmar (Myanmar), Khmer (Cambodia).
    
    These syllabic scripts are written from left to right. Support for these fonts is widely inadequate, however. 
    Although they are technically allowed in documents and web sites with UTF-8 charsets, 
    fonts such as Arial Unicode MS or Code2000 are often missing. 
    For additional writing systems of Southeast Asia see Brahmi / Indic Scripts 2 below.
    
    1. U+0900 -- U+097F, Devanagari
    2. U+A8E0 -- U+A8FF, Devanagari Extended
    3. U+1CD0 -- U+1CFF, Vedic Extensions
    4. U+0980 -- U+09FF, Bengali
    5. U+0B80 -- U+0BFF, Tamil
    6-8. U+0D80 -- U+0DFF] -- U+0E7F] -- U+0EFF, Sinhala -- Thai -- Lao
    9.  U+1000 -- U+109F, Myanmar (Burmese)
    10. U+AA60 -- U+AA7F , Myanmar Extended-A
    11. U+1780 -- U+17FF, Khmer
    12. U+19E0 -- U+19FF, Khmer Symbols
   */
   
 	if( ( (usymb>>8) == 0xDE ) ) { /* 2 bytes */
     /* 0-13. U+0780 -- U+07BF, Thaana (Divehi); tf8(U+0780) = 0xDE80, utf8(U+07BF) = 0xDEBF  */
      if ( (0xDE80 <= usymb) && (usymb <= 0xDEBF) ) { return 1; }
   }  
					

	if( ( (usymb>>16) == 0xE0 ) ) { /* 3 bytes */
	
	 if( ( (usymb>>12) == 0xE0A ) ) { /* 3 bytes */
      /* 1. U+0900 -- U+097F, Devanagari; tf8(U+0900) = 0xE0A480, utf8(U+097F) = 0xE0A5BF  */
     if ( (0xE0A480 <= usymb) && (usymb <= 0xE0A5BF) ) { return 1; }
	   /* 1_4. U+0980 -- U+09FF, Bengali; tf8(U+0980) = 0xE0A680, utf8(U+09FF) = 0xE0A7BF */
	   if ( (0xE0A680 <= usymb) && (usymb <= 0xE0A7BF) ) { return 1; }
      /* 1_5. U+0B80 -- U+0BFF, Tamil; tf8(U+0B80) = 0xE0AE80, utf8(U+0BFF) = 0xE0AFBF  */
      if ( (0xE0AE80 <= usymb) && (usymb <= 0xE0AFBF) ) { return 1; }
	   /* 1_14-16. U+0A00 -- U+0A7F] -- U+0AFF] -- U+0B7F, Gurmukhi -- Gujarati -- Oriya; 
	                                                     tf8(U+0A00) = 0xE0A880, utf8(U+0B7F) = 0xE0ADBF */
	   if ( (0xE0A880 <= usymb) && (usymb <= 0xE0ADBF) ) { return 1; }
      return 0;
     }
      
	 if( ( (usymb>>12) == 0xE0B ) ) { /* 3 bytes */
	   /* 1_6-8. U+0D80 -- U+0DFF] -- U+0E7F] -- U+0EFF, Sinhala -- Thai -- Lao; 
	                                           tf8(U+0D80) = 0xE0B680, utf8(U+0EFF) = 0xE0BBBF */
	   if ( (0xE0B680 <= usymb) && (usymb <= 0xE0BBBF) ) { return 1; }
      /* 1_17-19. U+0C00 -- U+0C7F] -- U+0CFF] -- U+0D7F, Telugu -- Kannada -- Malayalam; 
                                                        tf8(U+0C00) = 0xE0B080, utf8(U+0D7F) = 0xE0B5BF  */
      if ( (0xE0B080 <= usymb) && (usymb <= 0xE0B5BF) ) { return 1; }
	   /* 1_20. U+0F00 -- U+0FFF, Tibetantf8(U+0F00) = 0xE0BC80, utf8(U+0FFF) = 0xE0BFBF */
	   if ( (0xE0BC80 <= usymb) && (usymb <= 0xE0BFBF) ) { return 1; }
     }
	 return 0;
 }

	   					
	if( ( (usymb>>16) == 0xE1 ) ) { /* 3 bytes */
	   /* 2. U+A8E0 -- U+A8FF, Devanagari Extended; tf8(U+A8E0) = 0xEAA3A0, utf8(U+A8FF) = 0xEAA3BF *+/
	   if ( (0xEAA3A0 <= usymb) && (usymb <= 0xEAA3BF) ) { return 1; }
	   */

      /* 3. U+1CD0 -- U+1CFF, Vedic Extensions; tf8(U+1CD0) = 0xE1B390, utf8(U+1CFF) = 0xE1B3BF  */
      if ( (0xE1B390 <= usymb) && (usymb <= 0xE1B3BF) ) { return 1; }
					
	   /* 4. U+0980 -- U+09FF, Bengali; tf8(U+0980) = 0xE0A680, utf8(U+09FF) = 0xE0A7BF *+/
	   if ( (0xE0A680 <= usymb) && (usymb <= 0xE0A7BF) ) { return 1; }
	   */

      /* 5. U+0B80 -- U+0BFF, Tamil; tf8(U+0B80) = 0xE0AE80, utf8(U+0BFF) = 0xE0AFBF  *+/
       if ( (0xE0AE80 <= usymb) && (usymb <= 0xE0AFBF) ) { return 1; }
					
	   /+* 6-8. U+0D80 -- U+0DFF] -- U+0E7F] -- U+0EFF, Sinhala -- Thai -- Lao; 
	                                           tf8(U+0D80) = 0xE0B680, utf8(U+0EFF) = 0xE0BBBF */
	   /* 
	   if ( (0xE0B680 <= usymb) && (usymb <= 0xE0BBBF) ) { return 1; }
	   */

      /* 9.  U+1000 -- U+109F, Myanmar (Burmese); tf8(U+1000) = 0xE18080, utf8(U+109F) = 0xE1829F  */
      if ( (0xE18080 <= usymb) && (usymb <= 0xE1829F) ) { return 1; }
					
	   /* 10. U+AA60 -- U+AA7F , Myanmar Extended-A; tf8(U+AA60) = 0xEAA9A0, utf8(U+AA7F) = 0xEAA9BF *+/
	   if ( (0xEAA9A0 <= usymb) && (usymb <= 0xEAA9BF) ) { return 1; }
	   */

      /* 11. U+1780 -- U+17FF, Khmer; tf8(U+1780) = 0xE19E80, utf8(U+17FF) = 0xE19FBF  */
      if ( (0xE19E80 <= usymb) && (usymb <= 0xE19FBF) ) { return 1; }
					
	   /* 12. U+19E0 -- U+19FF, Khmer Symbols; tf8(U+19E0) = 0xE1A7A0, utf8(U+19FF) = 0xE1A7BF */
	   if ( (0xE1A7A0 <= usymb) && (usymb <= 0xE1A7BF) ) { return 1; }
	
	/* Brahmic 2:
	   13. U+0780 -- U+07BF, Thaana (Divehi)
	   14-16. U+0A00 -- U+0A7F] -- U+0AFF] -- U+0B7F, Gurmukhi -- Gujarati -- Oriya
	   17-19. U+0C00 -- U+0C7F] -- U+0CFF] -- U+0D7F, Telugu -- Kannada -- Malayalam
	   20. U+0F00 -- U+0FFF, Tibetan
	   21-24. U+1700 -- U+171F] -- U+173F] -- U+175F] -- U+177F, Tagalog -- Hanunóo -- Buhid -- Tagbanwa
	   25-27. U+1900 -- U+194F] -- U+197F] -- U+19DF, Limbu -- Tai Le -- New Tai Lue
	   28-29. U+1A00 -- U+1A1F] -- U+1AAF, Buginese -- Tai Tham
	   30-31. U+1B00 -- U+1B7F] -- U+1BBF, Balinese -- Sundanese
	   32. U+1CC0 -- U+1CCF, Sundanese Supplement
	   33-34. U+1C00 -- U+1C4F] -- U+1C7F, Lepcha -- Ol Chiki
	   35. U+A830 -- U+A83F, Common Indic Number Forms
	   36. U+A880 -- U+A8DF, Saurashtra
	   37. U+A930 -- U+A95F, Rejang
	   38. U+A980 -- U+A9DF, Javanese
	   39. U+AA00 -- U+AA5F, Cham
	   40. U+AA80 -- U+AADF, Tai Viet
	*/
	
	   /* 14-16. U+0A00 -- U+0A7F] -- U+0AFF] -- U+0B7F, Gurmukhi -- Gujarati -- Oriya; 
	                                                     tf8(U+0A00) = 0xE0A880, utf8(U+0B7F) = 0xE0ADBF *+/
	   if ( (0xE0A880 <= usymb) && (usymb <= 0xE0ADBF) ) { return 1; }
	   */

      /* 17-19. U+0C00 -- U+0C7F] -- U+0CFF] -- U+0D7F, Telugu -- Kannada -- Malayalam; 
                                                        tf8(U+0C00) = 0xE0B080, utf8(U+0D7F) = 0xE0B5BF  *+/
      if ( (0xE0B080 <= usymb) && (usymb <= 0xE0B5BF) ) { return 1; }
      */
					
	   /* 20. U+0F00 -- U+0FFF, Tibetantf8(U+0F00) = 0xE0BC80, utf8(U+0FFF) = 0xE0BFBF *+/
	   if ( (0xE0BC80 <= usymb) && (usymb <= 0xE0BFBF) ) { return 1; }
	   */

      /* 21-24. U+1700 -- U+171F] -- U+173F] -- U+175F] -- U+177F, Tagalog -- Hanunóo -- Buhid -- Tagbanwa; 
                                                                   tf8(U+1700) = 0xE19C80, utf8(U+177F) = 0xE19DBF  */
      if ( (0xE19C80 <= usymb) && (usymb <= 0xE19DBF) ) { return 1; }
					
	   /* 25-27. U+1900 -- U+194F] -- U+197F] -- U+19DF, Limbu -- Tai Le -- New Tai Lue; 
	                                                     tf8(U+1900) = 0xE1A480, utf8(U+19DF) = 0xE1A79F */
	   if ( (0xE1A480 <= usymb) && (usymb <= 0xE1A79F) ) { return 1; }

      /* 28-29. U+1A00 -- U+1A1F] -- U+1AAF, Buginese -- Tai Tham; tf8(U+1A00) = 0xE1A880, utf8(U+1AAF) = 0xE1AAAF  */
      if ( (0xE1A880 <= usymb) && (usymb <= 0xE1AAAF) ) { return 1; }
					
	   /* 30-31. U+1B00 -- U+1B7F] -- U+1BBF, Balinese -- Sundanese; tf8(U+1B00) = 0xE1AC80, utf8(U+1BBF) = 0xE1AEBF */
	   if ( (0xE1AC80 <= usymb) && (usymb <= 0xE1AEBF) ) { return 1; }

      /* 32. U+1CC0 -- U+1CCF, Sundanese Supplement; tf8(U+1CC0) = 0xE1B380, utf8(U+1CCF) = 0xE1B38F */
      if ( (0xE1B380 <= usymb) && (usymb <= 0xE1B38F) ) { return 1; }
					
	   /* 33-34. U+1C00 -- U+1C4F] -- U+1C7F, Lepcha -- Ol Chiki; tf8(U+1C00) = 0xE1B080, utf8(U+1C7F) = 0xE1B1BF */
	   if ( (0xE1B080 <= usymb) && (usymb <= 0xE1B1BF) ) { return 1; }
	   return 0;
	}

	if( ( (usymb>>12) == 0xEAA ) ) { /* 3 bytes */
	   /* 34a_2. U+A8E0 -- U+A8FF, Devanagari Extended; tf8(U+A8E0) = 0xEAA3A0, utf8(U+A8FF) = 0xEAA3BF */
	   if ( (0xEAA3A0 <= usymb) && (usymb <= 0xEAA3BF) ) { return 1; }

	   /* 34b_10. U+AA60 -- U+AA7F , Myanmar Extended-A; tf8(U+AA60) = 0xEAA9A0, utf8(U+AA7F) = 0xEAA9BF */
	   if ( (0xEAA9A0 <= usymb) && (usymb <= 0xEAA9BF) ) { return 1; }

      /* 35. U+A830 -- U+A83F, Common Indic Number Forms; tf8(U+A830) = 0xEAA0B0, utf8(U+A83F) = 0xEAA0BF */
      if ( (0xEAA0B0 <= usymb) && (usymb <= 0xEAA0BF) ) { return 1; }
					
	   /* 36. U+A880 -- U+A8DF, Saurashtra; tf8(U+A880) = 0xEAA280, utf8(U+A8DF) = 0xEAA39F */
	   if ( (0xEAA280 <= usymb) && (usymb <= 0xEAA39F) ) { return 1; }

      /* 37. U+A930 -- U+A95F, Rejang; tf8(U+A930) = 0xEAA4B0, utf8(U+A95F) = 0xEAA59F */
      if ( (0xEAA4B0 <= usymb) && (usymb <= 0xEAA59F) ) { return 1; }
					
	   /* 38. U+A980 -- U+A9DF, Javanese; tf8(U+A980) = 0xEAA680, utf8(U+A9DF) = 0xEAA79F */
	   if ( (0xEAA680 <= usymb) && (usymb <= 0xEAA79F) ) { return 1; }

      /* 39. U+AA00 -- U+AA5F, Cham; tf8(U+AA00) = 0xEAA880, utf8(U+AA5F) = 0xEAA99F */
      if ( (0xEAA880 <= usymb) && (usymb <= 0xEAA99F) ) { return 1; }
					
	   /* 40. U+AA80 -- U+AADF, Tai Viet; tf8(U+AA80) = 0xEAAA80, utf8(U+AADF) = 0xEAAB9F */
	   if ( (0xEAAA80 <= usymb) && (usymb <= 0xEAAB9F) ) { return 1; }
	}
	   
   return 0;
  }
             
int ri_isJapanese(utf usymb) {
	/* The Japanese writing system consists of 4 scripts:
      Hiragana, used for writing native words for which no kanji exist, including particles and suffixes.
      Katakana, used for writing foreign words (phonetically) in Japanese.
      Kanji ("Han characters"), Chinese characters used for writing nouns, adjective and verb stems.
      Rōmaji ("Roman letters"), latin letters used for writing Japanese phonetically in "western" characters, 
      the common way to input Japanese into computers.
      
      1. U+3040 -- U+309F] -- U+30FF, Hiragana -- Katakana
      2. U+31F0 -- U+31FF, Katakana Phonetic Extensions
      3. U+3190 -- U+319F, Kanbun
      4. U+FF00 -- U+FFEF, Halfwidth and Fullwidth Forms 
                 -- Fullwidth ASCII variants:  FF00—FFEF incudes Ａ-Ｚ vs ａ-ｚ -- U+FF21-FF3A  vs U+FF41-U+FF5A  +-0x20
                 -- and  ！-／  -- U+FF01-U+FF0F, ：-＠  -- U+FF1A-U+FF20, ［-｀ -- U+FF3B-U+FF40, ｛-､ -- U+FF5B-U+FF64,
                         ￠-￦ -- U+FFE0-U+FFE6, ￨-￮ -- U+FFE8-U+FFEE ------- these chracters should be move in the Symbol group!
                         as well as: Fullwidth Digits:  １-９ -- U+FF11-U+FF19 already moved to the Symbol group
 
      -- Kanji, the Chinese characters used for writing Japanese, 
                are shown the unified Han-character table for Chinese (CJK).
	*/
	
	if( ( (usymb>>12) == 0xE38 ) ) { /* 3 bytes */
      /* 1. U+3040 -- U+309F] -- U+30FF, Hiragana -- Katakana; tf8(U+3040) = 0xE38180, utf8(U+30FF) = 0xE3829F  */
      if ( (0xE38180 <= usymb) && (usymb <= 0xE3829F) ) { return 1; }
					
	   /* 2. U+31F0 -- U+31FF, Katakana Phonetic Extensions; tf8(U+31F0) = 0xE387B0, utf8(U+31FF) = 0xE387BF */
	   if ( (0xE387B0 <= usymb) && (usymb <= 0xE387BF) ) { return 1; }

      /* 3. U+3190 -- U+319F, Kanbun; tf8(U+3190) = 0xE38690, utf8(U+319F) = 0xE3869F  */
	   if ( (0xE38690 <= usymb) && (usymb <= 0xE3869F) ) { return 1; }
	   
	   return 0;
	}

	if( ( (usymb>>12) == 0xEFB ) ) { /* 3 bytes */
   	/* 4. U+FF00 -- U+FFEF, Halfwidth and Fullwidth Forms; tf8(U+FF00) = 0xEFBC80, utf8(U+FFEF) = 0xEFBFAF */
   	/* what = FF00 Octet-4 = 80 Octet-3 = bc Octet-2 = ef, what = FFEF Octet-4 = af Octet-3 = bf Octet-2 = ef */
   	     /* Fullwidth Digits:  0-９ -- U+FF10-U+FF19 already moved to the Symbol group, utf(U+FF10) = 0xEFBC90, utf(U+FF19) = 0xEFBC99 */
   	            /*          -- and  ！-／  -- U+FF01-U+FF0F, ：-＠  -- U+FF1A-U+FF20, 
   	                                       ［-｀ -- U+FF3B-U+FF40, ｛-･ -- U+FF5B-U+FF65,
                                      ￠-￦ -- U+FFE0-U+FFE6, ￨-￮ -- U+FFE8-U+FFEE 
                                      ------- these chracters should be move in the Symbol group! */
// Was:	   if ( ((0xEFBC80 <= usymb) && (usymb <= 0xEFBFAF)) && !((0xEFBC90 <= usymb) && (usymb <= 0xEFBC99)) ) { return 1; }
         /* Ａ-Ｚ -- U+FF21-U+FF3A, tf8(U+FF21) = 0xEFBCA1, tf8(U+FF3A) = 0xEFBCBA,
            ａ-ｚ -- U+FF41-U+FF5A, utf8(U+FF41) = 0xEFBD81, utf8(U+FF5A) = 0xEFBD9A,
              ｦ-ￜ -- U+FF66-U+FFDC, utf8(U+FF66) = 0xEFBDA6, utf8(U+FFDC) = 0xEFBF9C, 
            
         */
	   if ( ((0xEFBCA1 <= usymb) && (usymb <= 0xEFBCBA)) || ((0xEFBD81 <= usymb) && (usymb <= 0xEFBD9A)) ||
	        ((0xEFBDA6 <= usymb) && (usymb <= 0xEFBF9C)) 
	      ) { return 1; }
   }

	return 0;
 } 
              
int ri_isKorean(utf usymb) {
	/* 1. U+1100 -- U+11FF, Hangul Jamo
	   2. U+3130 -- U+318F, Hangul Compatibility Jamo
	   3. U+A960 -- U+A97F, Hangul Jamo Extended-A
	*/
	
	if( ( (usymb>>20) == 0xE ) ) { /* 3 bytes */
	   /* 1. U+1100 -- U+11FF, Hangul Jamo; tf8(U+1100) = 0xE18480, utf8(U+11FF) = 0xE187BF  */
	   if ( (0xE18480 <= usymb) && (usymb <= 0xE187BF) ) { return 1; }
					
	   /* 2. U+3130 -- U+318F, Hangul Compatibility Jamo; tf8(U+3130) = 0xE384B0, utf8(U+318F) = 0xE3868F */
	   if ( (0xE384B0 <= usymb) && (usymb <= 0xE3868F) ) { return 1; }

      /* 3. U+A960 -- U+A97F, Hangul Jamo Extended-A; tf8(U+A960) = 0xEAA5A0, utf8(U+A97F) = 0xEAA5BF  */
      if ( (0xEAA5A0 <= usymb) && (usymb <= 0xEAA5BF) ) { return 1; }
	}

	return 0; 
  } 
              
int ri_isChinese(utf usymb) { /* ChineZe (CJK) */
   
   /* CJK (for Chinese, Japanese, Korean) encompasses all characters for the Chinese Hànzì, 
     the Japanese Kanji and the Korean Hanja (cf. Unicode world map of scripts). 
     They are graphemes, representations of a syllable. There are more than 85.000 Chinese characters, 
     but only 3.000 of them are essential. Unicode has code points for roughly 25.000 CJK characters, 
     and they can be used in documents and web pages coded in charset UTF-8, provided a suitable font - e.g.
     Arial Unicode or Code2000 - is installed.
     
     CJK-1:
       1-2. U+2E80 -- U+2EFF] -- U+2FDF, Radicals Supplement -- Kangxi Radicals
       3. U+3000 -- U+303F, Symbols and Punctuation
       4. U+31C0 -- U+31EF, Strokes
       5. U+3200 -- U+32FF] -- U+33FF] -- U+3FFF] -- U+4DBF
                                            , Enclosed CJK Letters and Months -- Compatibility 
                                            -- Unified Ideographs Extension A -- Unified Ideographs Extension A
       6. U+4E00 -- U+4FFF, Unified Ideographs
     
   */
   
	if( ( (usymb>>20) == 0xE ) ) { /* 3 bytes */
      /* 1-2. U+2E80 -- U+2EFF] -- U+2FDF, Radicals Supplement -- Kangxi Radicals; 
                                           utf8(U+2E80) = 0xE2BA80, utf8(U+2FDF) = 0xE2BF9F  */
      if ( (0xE2BA80 <= usymb) && (usymb <= 0xE2BF9F) ) { return 1; }
					
	 if( ( (usymb>>16) == 0xE3 ) ) { /* 3 bytes */
	   /* 3. U+3000 -- U+303F, Symbols and Punctuation; utf8(U+3000) = 0xE38080, utf8(U+303F) = 0xE380BF */
	   if ( (0xE38080 <= usymb) && (usymb <= 0xE380BF) ) { return 1; }

      /* 4. U+31C0 -- U+31EF, Strokes; utf8(U+31C0) = 0xE38780, utf8(U+31EF) = 0xE387AF  */
      if ( (0xE38780 <= usymb) && (usymb <= 0xE387AF) ) { return 1; }
      /* Here should be without return; See the next case. */
    }

	   /* 5-8. U+3200 -- U+32FF] -- U+33FF] -- U+3FFF] -- U+4DBF; utf8(U+3200) = 0xE38880, utf8(U+4DBF) = 0xE4B6BF */
	   if ( (0xE38880 <= usymb) && (usymb <= 0xE4B6BF) ) { return 1; }

   /* 9. U+4E00 -- U+4FFF] -- U+5FFF] -- U+6FFF] -- U+7FFF] -- U+8FFF] -- U+9FFF
                                            , Unified Ideographs -- Unified Ideographs (Continued)
                                           -- Unified Ideographs (Continued). See below
                                           ; utf8(U+4E00) = 0xE4B880, utf8(U+9FFF) = 0xE9BFBF
   */
      if ( (0xE4B880 <= usymb) && (usymb <= 0xE9BFBF) ) { return 1; }
   } 
   
   /* CJK-2:
      9. U+5000 -- U+5FFF] , Unified Ideographs (Continued) --
      CJK-2a:
      9. U+6000 -- U+7FFF , Unified Ideographs (Continued) --
      CJK-3:
      9. U+8000 -- U+8FFF] -- U+9FFF , Unified Ideographs (Continued) See above.
      10. U+F900 -- U+FAFF, Compatibility Ideographs
      11. U+FE10 -- U+FE1F, Vertical Forms
      12. U+FE30 -- U+FE4F, Compatibility Forms
   */
   
	if( ( (usymb>>16) == 0xEF ) ) { /* 3 bytes */
      /* 10. U+F900 -- U+FAFF, Compatibility Ideographs; utf8(U+F900) = 0xEFA480, utf8(U+FAFF) = 0xEFABBF */
      if ( (0xEFA480 <= usymb) && (usymb <= 0xEFABBF) ) { return 1; }

      /* 11. U+FE10 -- U+FE1F, Vertical Forms; utf8(U+FE10) = 0xEFB890, utf8(U+FE1F) = 0xEFB89F  */
      if ( (0xEFB890 <= usymb) && (usymb <= 0xEFB89F) ) { return 1; }

	   /* 12. U+FE30 -- U+FE4F, Compatibility Forms; utf8(U+FE30) = 0xEFB8B0, utf8(U+FE4F) = 0xEFB98F */
	   if ( (0xEFB8B0 <= usymb) && (usymb <= 0xEFB98F) ) { return 1; }
	}

    return 0;
  } 
             
int ri_isEthiopian(utf usymb) {
	/* Ethiopic:
	   1-2. U+1200 -- U+137F] -- U+139F, Ethiopic -- Ethiopic Supplement
	   3. U+2D80 -- U+2DDF, Ethiopic Extended
	   4. U+AB00 -- U+AB2F, Ethiopic Extended-A
	*/
	
	if( ( (usymb>>20) == 0xE ) ) { /* 3 bytes */
	   /* 1-2. U+1200 -- U+137F] -- U+139F, Ethiopic -- Ethiopic Supplement; 
	                                utf8(U+1200) = 0xE18880, utf8(U+139F) = 0xE18E9F  */
	   if ( (0xE18880 <= usymb) && (usymb <= 0xE18E9F) ) { return 1; }
					
	   /* 3. U+2D80 -- U+2DDF, Ethiopic Extended; utf8(U+2D80) = 0xE2B680, utf8(U+2DDF) = 0xE2B79F */
	   if ( (0xE2B680 <= usymb) && (usymb <= 0xE2B79F) ) { return 1; }

      /* 4. U+AB00 -- U+AB2F, Ethiopic Extended-A; utf8(U+AB00) = 0xEAAC80, utf8(U+AB2F) = 0xEAACAF  */
      if ( (0xEAAC80 <= usymb) && (usymb <= 0xEAACAF) ) { return 1; }
	}

	return 0;
  } 
              
int ri_isOld(utf usymb) { /* Old and rare */
   /*
		0.  ƀ- ƿ -- U+0180-U+01BF -- old Latin for ancient ono-Europien languages. moved from the Latin Extended-B group
 		0.1  ǝ-ǿ -- U+01DD-U+01FF -- old Latin for phonetic and ancient alphabets. moved from the Latin Extended-B group
     1-2. U+1680 -- U+169F] -- U+16FF, Ogham -- Runic
      3. U+2C00 -- U+2C5F, Glagolitic
      3.a ẜ->ẝ  U+1E9C-U+1E9D  +-1 From medieval (moved from Additional Extended Latin)
		    Ỻ-ỿ U+1EFA-U+1EFF    +-1 
      4. U+2800 -- U+28FF, Braille Patterns
   */
   
    unsigned long unicode = ri_utf_to_int(usymb);

/*		0.  ƀ- ƿ -- U+0180-U+01BF -- old Latin for ancient ono-Europien languages. moved from the Latin Extended-B group 
 		0.1  ǝ-ǿ -- U+01DD-U+01FF -- old Latin for phonetic and ancient alphabets. moved from the Latin Extended-B group
*/
	if( ((0x180 <= unicode) && (unicode <= 0x1BF)) ||
	    ((0x1DD <= unicode) && (unicode <= 0x1FF)) ) { /* 2 bytes */
	    return 1;
   }

	if( ( (usymb>>12) == 0xE19 ) ) { /* 3 bytes */
      /* 1-2. U+1680 -- U+169F] -- U+16FF, Ogham -- Runic; utf8(U+1680) = 0xE19A80, utf8(U+16FF) = 0xE19BBF  */
      if ( (0xE19A80 <= usymb) && (usymb <= 0xE19BBF) ) { return 1; }
      return 0;
   }

/*     3.a ẜ->ẝ  U+1E9C-U+1E9D  +-1 From medieval (moved from Additional Extended Latin)
		     Ỻ-ỿ U+1EFA-U+1EFF    +-1 
*/
	if( (unicode == 0x1E9C) || (unicode == 0x1E9D) ||   /* 4 bytes */
	     ((0x1EFA <= unicode) && (unicode <= 0x1EFF)) ) { 
	    return 1;
   }
					
	if( ( (usymb>>16) == 0xE2 ) ) { /* 3 bytes */
 	   /* 3. U+2C00 -- U+2C5F, Glagolitic; utf8(U+2C00) = 0xE2B080, utf8(U+2C5F) = 0xE2B19F */
	   if ( (0xE2B080 <= usymb) && (usymb <= 0xE2B19F) ) { return 1; }

     /* 4. U+2800 -- U+28FF, Braille Patterns; utf8(U+2800) = 0xE2A080, utf8(U+28FF) = 0xE2A3BF  */
      if ( (0xE2A080 <= usymb) && (usymb <= 0xE2A3BF) ) { return 1; }
	}

   return 0;
  } 
 
 	/*
Примеры кодирования
Символ 	Двоичный код символа 	UTF-8 в двоичном виде 	UTF-8 в шестнадцатеричном виде
$ 	U+0024 	0100100 	00100100 	24
¢ 	U+00A2 	10100010 	11000010 10100010 	C2 A2
€ 	U+20AC 	100000 10101100 	11100010 10000010 10101100 	E2 82 AC
 ૂ    U+0AC2   00001001 10110010  11100000 10101011 10000010    E0 AB 82 
𐍈 	U+10348 	1 00000011 01001000 	11110000 10010000 10001101 10001000 	F0 90 8D 88
	*/  



int ri_is_utf_seq(char * seq) {
	int ln;
	unsigned char header = ((unsigned char)(* seq))<<1; 
	
	/* Count body-bytes following the header. */
	for ( ln=1, seq++; ((header & '\x80') == '\x80') && (*seq != 0) && IS_UTF_BODY(* seq); ln++, seq++) {
		if ( ln>4 ) return 0;
		header = header<<1;
	};
	
	/* Either the body length bln is greater the length lnh indicated in the header, or lnh > lnb. */ 
	if( (header & '\x80') == '\x80' ) return 0; /* ln > 4 */
	/* Accept the scanned prefix as an utf-sequece; does not matter what is the byte following the sequence. */  
	return ln;
}

 
 static char utf_symbol[5] = {0,0,0,0,0};  /* utf-8 sequence */

 char * ri_byte_to_utf_seq(unsigned char c) {
 	utf_symbol[0] = '\xC0'| (c>>6); 
 	utf_symbol[1] = '\x80'| (c & '\x3F'); 
 	utf_symbol[2] = '\0';
  	return (char *)utf_symbol;
 }
 
static int utf_ln = 0;
int r_get_utf_ln (void) { return utf_ln;}

/* Nemytykh after Teriukha, 25-01-2023 */ 
/* Function r_isunicode takes input byte string.
   If a prefix of the string is a utf-8 sequence then  
   the function returns (utf) unsigned long representing the sequence
   and saves either the utf-8 sequence length or 1 in the static variable utf_ln.
   The value of the variable can be taken by function r_get_utf_ln above.
   If no prefix in the input string is a utf-8 sequence then the function returns 0.
*/
utf r_isunicode(char *in) { 
    utf result = 0;
    int length = strlen(in);

     int ln = 0; /* Utf8-length declared in the first byte. */ 
	  char c = in[0];
	  utf_ln = 0;
	  for ( ln=0; ln <= 5 ; ln++ ){
			if((c & 128) != 0) c = c<<1;
			else break;
		}
	
//-	 if ((ln == 2) && (((unsigned char)(in[0]) < 0xC2) ||  ((unsigned char)(in[0]) > 0xC3))) {	return 0; } // Таких utf-8 кодировок не существует!!!, Немытых 15-09-2023
	 if ((ln == 2) && (((unsigned char)(in[0]) < 0xC2))) { return 0; } // Таких utf-8 кодировок не существует!!!, Немытых 15-09-2023
    if( (ln < 2) || (ln > 4) || (ln > length)) {
    	if( (unsigned char)(in[0]) > 127 ) {
    		result = r_int_to_utf((unsigned char)(in[0]));
    		utf_ln = 1;                 /* Неre is the length for shifting rather than utf-length. */
    		return result;
    	} else return 0; 
    } 
    result = (unsigned char)(in[0]);
    for ( int i = 1; i < ln; i++){   /* Looking for the actual utf-8 body. */
// Was:			if( (in[i] & 0x80) != 0x80 ) break;
			if( (in[i] & 0x80) != 0x80 ) { utf_ln = 0; return 0; } // Длина, объявленная в заголовке > реальной длины предлагаемого тела, Немытых 15-09-2023
			result = result << 8;
	   	result += (unsigned char)(in[i]);
	 }
   
    utf_ln = ln;
    return result;
}
 
/* Represent the argument as a sum (a sequence of bytes) of powers of 2^6 with the following prefixes.
   The first bits of the leading byte represent the length of the sequence in the unary base
   following by the zero-bit, otherwise the first two bits of the bytes are 10 in the binary system.
   The sum may include a leading zero in the base 2^6, 
   i.e., the corresponding byte includes only the length prefix and nothing else.
*/ 

utf r_int_to_utf(unsigned long n) {
	unsigned long res = 0L;
	unsigned char d, ln = 1;
	int i = 0;
	
	/* Tests:
      п = U+43F = 0xD0BF
	   Ⰱ = U+2C01 = 0xE2B081 = 11100010 10110000 10000001 
	   𑃐 = U+110D0 = 0xF0918390 = 11110000 10010001 10000011 10010000
	   𐍈 = U+10348 = 0xF0908D88 = 11110000 10010000 10001101 10001000
	*/

	n %= (MAX_UNICODE+1);
	while (n != 0) {
		d = (((unsigned char) n) & 0x3F);
		res |= (d | 0x80)<<(8*i);
		n >>= 6;
		i++;
	}
	
	ln = '\xF8'<<(5-i);                     /* The header: Is there enough leading bits needed for |the utf-8 length|+1? */
	if ( (ln ^ ((d>>(7-i))<<(7-i)))  == ln ) {
		res |= ((unsigned long)(ln))<<(8*(i-1));            /* Put the length. */
	} else {  /* Insert an additional byte for header contaning only the length. */
 		res |= (((unsigned long)((ln>>1)|(0x80)))<<(8*i)); /* Increment the length and put it. */
	}
   return res;
}

/* Represent the input utf-8 number given in the base 2^6, module the service bits, in the base 2^8. */
unsigned long ri_utf_to_int(utf usymb) {
	unsigned long res = 0;
	unsigned char d;
	int i = 0;
	
	/* The tests:
      п = U+43F = 0xD0BF
	   Ⰱ = U+2C01 = 0xE2B081 = 11100010 10110000 10000001 
	   𑃐 = U+110D0 = 0xF0918390 = 11110000 10010001 10000011 10010000
	   𐍈 = U+10348 = 0xF0908D88 = 11110000 10010000 10001101 10001000
	*/

	d = (char)usymb;   /*Take the last byte. */
	while ( (d & 0xC0) != 0xC0 )	{ /* The utf-8 body. */
      res += ((unsigned long)(d & 0x3F))<<(6*i);
	   usymb >>= 8;
	   d = (char)usymb;
	   i++;
	}
	res += ((unsigned long)(d & (0xFF>>(i+1))))<<(6*i); /* The utf-8 header */
	return res;
}


int ri_utf_explode(utf symb, char * buff, int lim) {
	char utf[4] = {0,0,0,0};
	int i, j;
	
   for(i = 4; (i != 0) && (symb != 0); ) { 
       utf[--i] = symb%256;
       symb = symb>>8;
   } 

   if( (4-i) >= lim ) return -1;
    for( j = 0 ; (i < 4); i++ ) { 
       buff[j++] = utf[i];
   } 
   return (j-1);
}

char * r_utf_expl(utf symb) {
	int i;

   for(i = 4; (i != 0) && (symb != 0); ) { 
       utf_symbol[--i] = symb%256;
       symb = symb>>8;
   } 

  return ((char *)utf_symbol+i);
}

char * rc_reverse_ustr (char ** ustr) {
	char utf_first[5] = {0,0,0,0,0};
	utf symb;
	int ln, i, j;
	int ln_str = (int) strlen (* ustr);
	char ** s;
	s = ustr;

   while ( ln_str > 0 ) {
   	if( r_isunicode(* ustr) ) {
   		ln = i = r_get_utf_ln();
   		for (j = 0; i > 0; j++, i--) { /* copy the unicode sequence to buffer */
   			utf_first[j] = * (* ustr + j);
   		}
   		utf_first[j] = '\0';
   		/* move the rest of the unicode sequence to the begin of the input unicode sequence */
   		for ( ; j < ln_str; j++, i++) { 
   			* (* ustr + i) = * (* ustr + j);
   		}
    		for (j = 0; utf_first[j] ; j++, i++) { /* copy the unicode sequence from buffer to the end of the prefix moved */
   			* (* ustr + i) = utf_first[j];
   		}
   		ln_str -= ln; /* decrease the moved prefix length */
   	}
   	else break; 

  		if ( * ustr == NULL ) { break; }
   }	
// printf("\n rc_reverse_ustr_end: * ustr = %s, start = %s \n", * ustr, * s); getchar();
   return s;
}

#define ESC 27


/* Identifier should start with a letter  belonging to the union 
   of the following alphabets:
   (extended) Latin, (extended) Greek, Mathematical (alpha-) letter alphabet,
   including all fonts of theirs letters, supported by the unicode set.
   Nemytykh 28-03-2023.
*/
int isFirstIdChar (char * cp_str, char flag) {
	
	if ( isalpha (cp_str [0]) ) return 1;
	
	utf usymb = r_isunicode(cp_str);
	if ( usymb && !ri_isIndex(usymb) &&
	     ( ri_isLatin(usymb) || ri_isGreek(usymb) || ri_isMath(usymb) || ((flag == PrefixPreWord) && ri_isCyrillic(usymb)) ) 
	   ) return r_get_utf_ln();
	return 0;
}

int isIdChar (char * cp_str, char flag) {
	utf usymb;
	
	if ( IS_PREFIX(flag) ) { 
	   if (isalnum (* cp_str) || (* cp_str == '_') || (* cp_str == '-')) { return flag; }
   	else if ((* cp_str) < 128) { return 0; }
		
      usymb = r_isunicode(cp_str);
	   if ( usymb && ((flag & PrefixId) == 1) &&
	        (ri_isLatin(usymb) || ri_isGreek(usymb) || ri_isMath(usymb)) 
	      ) { return flag; 
	   } else if ( usymb && ( flag == PrefixPreWord ) && ri_isCyrillic(usymb) ) { 
	         return flag; 
	   } else if ( ri_isIndex(usymb) ) {
  	         flag = (flag == PrefixId) ? IndexId : IndexPreWord;
        Index:
  	         if ( isIndexMinus(usymb) ) return flag;
	         char * alphabet = IndexAlphabet(usymb);
	         if ( (strcmp(alphabet, "Latin") == 0) || (strcmp(alphabet, "Greek") == 0) || 
	              (strcmp(alphabet, "Math") == 0)  || (strcmp(alphabet, "Digit") == 0) ) {
	    	      return flag;  
   	      } else if ( (flag == IndexPreWord) && (strcmp(alphabet, "Cyrillic") == 0) ) { 
   	         return flag;  
	         };
      }
   } else if ( IS_INDEX(flag) ) 
   { 
      usymb = r_isunicode(cp_str);
      goto Index; 
   }
	return 0;
}

int ri_isIdentifierOrPreWord (char * cp_str, char flag, char vtype) { /* 16-08-2023 */
	int i, i_len = (int)strlen (cp_str);
	char c;
	int j;
	utf usymb;

	/* Identifier and preword should start with a letter, 77777 */
	int utf_len = isFirstIdChar(cp_str, flag);
	if ( ! utf_len ) return 0;

	for (i = utf_len; i < i_len; ) {
	   if ( IS_PREFIX(flag) ) { 
         c = cp_str [i];	
	   	if (isalnum (c) || c == '_' || c == '-') { ++i; continue; }
	   	else if (c < 128) { return 0; }
		
      	usymb = r_isunicode(cp_str+i);
      	j = r_get_utf_ln();
	      if ( usymb && !ri_isIndex(usymb) && ((flag & PrefixId) == 1)) {
	      	if ( (ri_isLatin(usymb) || ri_isGreek(usymb) || ri_isMath(usymb)) ) {
	      		i += j;  continue; 
	      	}
	      	else if ( (flag == PrefixPreWord) && ri_isCyrillic(usymb) ) {
      			i += j;  continue;
	      	} else { break; }
	      } else { break; }
	   } else { break; }
	}
	      
	if ( (i < i_len) && usymb && ri_isIndex(usymb) ) {
	   if ( flag == PrefixId ) {
	   		flag = IndexId;
	   } else if ( flag == PrefixPreWord ) {
	   		flag = IndexPreWord;
	   }
	   
	   for ( ; i < i_len; ) {
         usymb = r_isunicode(cp_str+i);
         j = r_get_utf_ln();
	   	if ( usymb && ri_isIndex(usymb) /* && IS_INDEX(flag)*/ ) {
/* Nemytykh, 02-09-2023	 , below is not correct!! 		
	   		if ( vtype == VarId ) {
	   	   	return 0;
	   		} 
*/	   		
	   	   if ( isIndexMinus(usymb) ) {
	   	   	i += j;  
	   		   continue;
	   	   }
	   	   char * alphabet = IndexAlphabet(usymb);
	   	   if ( (strcmp(alphabet, "Latin") == 0) || (strcmp(alphabet, "Greek") == 0) || 
	   	        (strcmp(alphabet, "Math") == 0)  || (strcmp(alphabet, "Digit") == 0) ) {
	   		   i += j;  
	   	   } else if ( (flag == IndexPreWord) && (strcmp(alphabet, "Cyrillic") == 0) ) { 
	   		   i += j;  
	   	   } else {
	   	   	return 0;
	   	   }
	   	} else {
	   		return 0;
	   	}
	   }
	} else {
		  if (i < i_len) { return 0;}
	};
	return 1;
}

/*
  Зависимости: 
       isIdentifier: (refio.c)
           ri_isIdentifierOrPreWord, isFirstIdChar: (refio.c)
           ri_isunicode, ri_get_utf_ln, (alpha.c)
           ri_isLatin .... (alpha.c)
       параллельные функции в refc:
           isunicode, get_utf_ln (rcleft.c)           
*/
int isIdentifier (char * cp_str) {
	return ri_isIdentifierOrPreWord (cp_str, PrefixId, 0);
}

int isPreWord (char * cp_str) {
	return ri_isIdentifierOrPreWord (cp_str, PrefixPreWord, 0);
}

int isVarIdentifierIndx (char * cp_str) {
	return ri_isIdentifierOrPreWord (cp_str, PrefixId, VarId);
}

// 'ₑₛₜ', ₑ = 0x2091 = 8337 ₛ = 0x209B = 8347 ₜ = 0x209C = 8348
// UTF8 	ₑ = 0xE28291, ₛ = 0xE2829B, ₜ = 0xE2829C 	
int isLowIndexVarType(char * str) {
	utf usymb = r_isunicode(str-3);

	if ( usymb && (r_get_utf_ln() == 3) ) { /* the utf-8 length of the indices is 3 */
	   unsigned long unicode = ri_utf_to_int(usymb);
		switch (unicode) {
			case 0x2091: // 'ₑ' = 0x2091 = 8337
			             return 'e';
			case 0x209B: // 'ₛ' = 0x209B = 8347
			             return 's';
			case 0x209C: // 'ₜ' = 0x209C = 8348
			             return 't';
			default :    return 0;
	   }
	}
	return 0;
}

int isCyrillicInString (char * str) {
	int i;
	utf usymb;
	
	while ( * str ) {
		usymb = r_isunicode(str);
      i = r_get_utf_ln();
      if (usymb && ri_isCyrillic(usymb)) {
      	return 1;
      }
      str += (i ? i : 1);
	}
	return 0;
}

