diff options
Diffstat (limited to 'support/fribidixetex/src')
-rw-r--r-- | support/fribidixetex/src/fribidixetex-bidi.c | 1041 | ||||
-rw-r--r-- | support/fribidixetex/src/fribidixetex-bidi.h | 11 | ||||
-rw-r--r-- | support/fribidixetex/src/fribidixetex-defines.h | 24 | ||||
-rw-r--r-- | support/fribidixetex/src/fribidixetex-dict.c | 145 | ||||
-rw-r--r-- | support/fribidixetex/src/fribidixetex-dict.h | 16 | ||||
-rw-r--r-- | support/fribidixetex/src/fribidixetex-ignore.c | 20 | ||||
-rw-r--r-- | support/fribidixetex/src/fribidixetex-ignore.h | 6 | ||||
-rw-r--r-- | support/fribidixetex/src/fribidixetex-io.c | 110 | ||||
-rw-r--r-- | support/fribidixetex/src/fribidixetex-io.h | 15 | ||||
-rw-r--r-- | support/fribidixetex/src/fribidixetex-util.c | 28 | ||||
-rw-r--r-- | support/fribidixetex/src/fribidixetex-util.h | 9 | ||||
-rw-r--r-- | support/fribidixetex/src/fribidixetex.c | 184 |
12 files changed, 1609 insertions, 0 deletions
diff --git a/support/fribidixetex/src/fribidixetex-bidi.c b/support/fribidixetex/src/fribidixetex-bidi.c new file mode 100644 index 0000000000..dd3a0ebb67 --- /dev/null +++ b/support/fribidixetex/src/fribidixetex-bidi.c @@ -0,0 +1,1041 @@ +#include "fribidixetex-defines.h" +#include "fribidixetex-bidi.h" +#include "fribidixetex-util.h" +#include "fribidixetex-dict.h" +#include "fribidixetex-ignore.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "fribidixetex-io.h" + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef min +#define min(x,y) ((x) < (y) ? (x) : (y)) +#endif + +#ifndef max +#define max(x,y) ((x) > (y) ? (x) : (y)) +#endif + + +/***********************/ +/* Global Data */ + +typedef struct COMMAND { + char *name; + struct COMMAND *next; +} + bidi_cmd_t; + +bidi_cmd_t *bidi_command_list; + +enum { MODE_BIDIOFF, MODE_BIDION, MODE_BIDILTR }; + + +static int bidi_mode; +static FriBidiLevel bidi_embed[MAX_LINE_SIZE]; +static FriBidiChar translation_buffer[MAX_LINE_SIZE]; + +/* only ASCII charrecters mirroring are + * supported - the coded below 128 according to + * http://www.unicode.org/Public/4.1.0/ucd/BidiMirroring.txt */ + +/* TODO: implement full mirroring list according to unicode + * standard */ +static const char *bidi_mirror_list[][2] = +{ + {"(", ")"}, + {")", "("}, + {"<", ">"}, + {">", "<"}, + {"[", "]"}, + {"]", "["}, + {"\\{","\\}"}, + {"\\}","\\{"}, + {NULL,NULL} +}; + +static const char *bidi_hack_list[][2] = +{ + {"---","{\\fribidixetexemdash}"}, + {"--","{\\fribidixetexendash}"}, + {NULL,NULL} +}; + +/********/ +/* TAGS */ +/********/ + +#define TAG_BIDI_ON "%BIDION" +#define TAG_BIDI_OFF "%BIDIOFF" +#define TAG_BIDI_NEW_TAG "%BIDITAG" +#define TAG_BIDI_LTR "%BIDILTR" +#define TAG_BIDI_DIC_TAG "%BIDIDICTAG" +#define TAG_BIDI_DIC_ENV "%BIDIDICENV" + +#define TAG_RTL "\\fribidixetexRLE{" +#define TAG_LTR "\\fribidixetexLRE{" +#define TAG_CLOSE "}" + +#define TAG_LATIN_NUM "\\fribidixetexlatinnumbers{" +#define TAG_NONLATIN_NUM "\\fribidixetexnonlatinnumbers{" + +/***********************/ + +/* Compares begining of string U and C + * for example "Hello!" == "Hel" */ +static int bidi_strieq_u_a(const FriBidiChar *u,const char *c) +{ + while(*u && *c) { + if(*u!=*c) + return 0; + u++; c++; + } + if(*u ==0 && *c!=0) { + return 0; + } + return 1; +} + +static int bidi_strlen(FriBidiChar *in) +{ + int len; + for(len=0;*in;len++) in++; + return len; +} + +/* Safe functions for adding charrecters to buffer + * if the line is too long the program just exits */ + +static void bidi_add_char_u(FriBidiChar *out,int *new_len, + int limit,FriBidiChar ch) +{ + if(*new_len+2<limit){ + out[*new_len]=ch; + ++*new_len; + out[*new_len]=0; + } + else { + fprintf(stderr,"The line is too long: line %d\n",io_line_number); + exit(1); + } +} +static void bidi_add_str_c(FriBidiChar *out,int *new_len, + int limit,const char *str) +{ + while(*str){ + bidi_add_char_u(out,new_len,limit,*str); + str++; + } +} + +/* Function looks if the first charrecter or sequence + * in "in" is mirrored charrecter and returns its mirrot + * in this case. If it is not mirrored then returns NULL */ +static const char *bidi_one_mirror(FriBidiChar *in,int *size, + const char *list[][2]) +{ + int pos=0; + while(list[pos][0]) { + if(bidi_strieq_u_a(in,list[pos][0])) { + *size=strlen(list[pos][0]); + return list[pos][1]; + } + pos++; + } + return NULL; +} + +static const char *bidi_mirror(FriBidiChar *in,int *size, + int replace_minus) +{ + const char *ptr; + if((ptr=bidi_one_mirror(in,size,bidi_mirror_list))!=NULL) { + return ptr; + } + if(replace_minus) { + return bidi_one_mirror(in,size,bidi_hack_list); + } + return NULL; +} + + +/* Returns the minimal embedding level for required direction */ +int bidi_basic_level(int is_rtl) +{ + if(is_rtl) + return 1; + return 0; +} + +void bidi_add_command(const char *name) +{ + bidi_cmd_t *new_cmd; + char *new_text; + + new_cmd=(bidi_cmd_t*)utl_malloc(sizeof(bidi_cmd_t)); + new_text=(char*)utl_malloc(strlen(name)+1); + + new_cmd->next=bidi_command_list; + new_cmd->name=new_text; + strcpy(new_text,name); + bidi_command_list = new_cmd; +} + +int bidi_is_cmd_char(FriBidiChar ch) +{ + if( ('a'<= ch && ch <='z') || ('A' <=ch && ch <= 'Z') ) + return 1; + return 0; +} + +/* Verirfies wether then text of length "len" is + * in command list */ +int bidi_in_cmd_list(FriBidiChar *text,int len) +{ + int i; + bidi_cmd_t *p; + for(p=bidi_command_list;p;p=p->next) { + for(i=0;i<len;i++) { + if(text[i]!=p->name[i]) + break; + } + if(i==len && p->name[len]==0){ + return 1; + } + } + return 0; +} + + +/* Find special charrecters */ +int bidi_is_latex_special_char(FriBidiChar *text) +{ + if(text[0]!='\\') + return FALSE; + /* Special charrecters according to lshort.pdf + * # $ % ^ & _ { } ~ \, "{}" should be mirrored + * thus not included to the list */ + switch (text[1]) { + case '#' : + case '$' : + case '%' : + case '^' : + case '&' : + case '_' : + case '\\': + return TRUE; + default : + return FALSE; + } + +} + + +/*Verifies wether the next string is command + * ie: "\\[a-zA-Z]+" or "\\[a-zA-Z]+\*" */ +int bidi_is_command(FriBidiChar *text,int *command_length) +{ + int len; + + if(bidi_is_latex_special_char(text)) { + /* Charrecters like \\ or \$ that should be treated + * as `commands' */ + *command_length=2; + return TRUE; + } + + if(*text != '\\' || !bidi_is_cmd_char(text[1])) { + return FALSE; + } + len=1; + while(bidi_is_cmd_char(text[len])) { + len++; + } + if(text[len] == '*') { + len++; + } + *command_length = len; + return TRUE; +} + +/* This is implementation of state machine with stack + * that distinguishs between text and commands */ + +/* STACK VALUES */ +enum { + EMPTY, + SQ_BRACKET ,SQ_BRACKET_IGN, + BRACKET, BRACKET_IGN, + CMD_BRACKET, CMD_BRACKET_IGN +}; +/* STATES */ +enum { ST_NO, ST_NORM, ST_IGN }; + +/* Used for ignore commands */ +int bidi_is_ignore(int top) +{ + return top == SQ_BRACKET_IGN + || top== BRACKET_IGN + || top == CMD_BRACKET_IGN; +} + +int bidi_state_on_left_br(int top,int *after_command_state) +{ + int ign_addon; + int push,state = *after_command_state; + if(bidi_is_ignore(top) || state == ST_IGN) { + ign_addon = 1; + } + else { + ign_addon = 0; + } + + if(state) { + push = CMD_BRACKET; + } + else{ + push = BRACKET; + } + + *after_command_state = ST_NO; + return push + ign_addon; +} + +int bidi_state_on_left_sq_br(int top,int *after_command_state) +{ + int push; + if(bidi_is_ignore(top) || *after_command_state == ST_IGN) { + push = SQ_BRACKET_IGN; + } + else { + push = SQ_BRACKET; + } + *after_command_state = ST_NO; + return push; +} + +void bidi_state_on_right_br(int top,int *after_command_state) +{ + if(top == CMD_BRACKET) { + *after_command_state = ST_NORM; + } + else if(top == BRACKET || top == BRACKET_IGN) { + *after_command_state = ST_NO; + } + else {/*top == CMD_BRACKET_IGN*/ + *after_command_state = ST_IGN; + } +} + +void bidi_state_on_right_sq_br(int top,int *after_command_state) +{ + if(top == SQ_BRACKET_IGN) { + *after_command_state = ST_IGN; + } + else { /* top == SQ_BRACKET */ + *after_command_state = ST_NORM; + } +} +/* Using marks "$$" */ +int bidi_calc_equation_inline(FriBidiChar *in) +{ + int len=1; + while(in[len] && in[len]!='$') { + if(in[len]=='\\' && (in[len+1]=='$' || in[len+1]=='\\')) { + len+=2; + } + else { + len++; + } + } + if(in[len]=='$') + len++; + return len; +} + +/* using \[ and \] marks */ +int bidi_calc_equation_display(FriBidiChar *in) +{ + int len=2; + while(in[len]){ + if(in[len]=='\\' && in[len+1]=='\\') + len+=2; + else if(in[len]=='\\' && in[len+1]==']') + return len+2; + else + len++; + } + return len; +} + +/* Support of equations */ +int bidi_calc_equation(FriBidiChar *in) +{ + if(*in=='$') + return bidi_calc_equation_inline(in); + else + return bidi_calc_equation_display(in); +} + +/* This function parses the text "in" in marks places that + * should be ignored by fribidi in "is_command" as true */ +void bidi_mark_commands(FriBidiChar *in,int len,char *is_command,int is_rtl) +{ + + char *parthness_stack; + int stack_size=0; + int cmd_len,top; + int after_command_state=ST_NO; + int mark,pos,symbol,i,push; + + /* Assumption - depth of stack can not be bigger then text length */ + parthness_stack = utl_malloc(len); + + pos=0; + + while(pos<len) { + + top = stack_size == 0 ? EMPTY : parthness_stack[stack_size-1]; + symbol=in[pos]; +#ifdef DEBUG_STATE_MACHINE + printf("pos=%d sybol=%c state=%d top=%d\n", + pos,(symbol < 127 ? symbol : '#'),after_command_state,top); +#endif + if(bidi_is_command(in+pos,&cmd_len)) { + for(i=0;i<cmd_len;i++) { + is_command[i+pos]=TRUE; + } + if(bidi_in_cmd_list(in+pos+1,cmd_len-1)) { + after_command_state = ST_IGN; + } + else { + after_command_state = ST_NORM; + } + pos+=cmd_len; + continue; + } + else if(symbol=='$' || (symbol=='\\' && in[pos+1]=='[')) { + cmd_len=bidi_calc_equation(in+pos); + + for(i=0;i<cmd_len;i++) { + is_command[i+pos]=TRUE; + } + pos+=cmd_len; + continue; + } + else if( symbol == '{' ) { + push = bidi_state_on_left_br(top,&after_command_state); + parthness_stack[stack_size++] = push; + mark=TRUE; + } + else if(symbol == '[' && after_command_state) { + push = bidi_state_on_left_sq_br(top,&after_command_state); + parthness_stack[stack_size++] = push; + mark=TRUE; + } + else if(symbol == ']' && (top == SQ_BRACKET || top == SQ_BRACKET_IGN)){ + bidi_state_on_right_sq_br(top,&after_command_state); + stack_size--; + mark=TRUE; + } + else if(symbol == '}' && (BRACKET <= top && top <= CMD_BRACKET_IGN)) { + bidi_state_on_right_br(top,&after_command_state); + stack_size--; + mark=TRUE; + } + else { + mark = bidi_is_ignore(top); + after_command_state = ST_NO; + } + is_command[pos++]=mark; + } + + utl_free(parthness_stack); +} + +#if ( FRIBIDI_MAJOR_VERSION * 100 + FRIBIDI_MINOR_VERSION ) > 10 // 0.10 +static void get_bidi_levels(FriBidiChar *in,int length,int is_rtl,FriBidiLevel *embed) +{ + FriBidiCharType *types = utl_malloc(sizeof(FriBidiCharType)*length); + FriBidiParType direction = is_rtl ? FRIBIDI_PAR_RTL : FRIBIDI_PAR_LTR; + + fribidi_get_bidi_types(in,length,types); + fribidi_get_par_embedding_levels(types,length,&direction,embed); + + utl_free(types); +} + +#else // old fribidi +static void get_bidi_levels(FriBidiChar *in,int length,int is_rtl,FriBidiLevel *embed) +{ + FriBidiCharType direction; + if(is_rtl) + direction = FRIBIDI_TYPE_RTL; + else + direction = FRIBIDI_TYPE_LTR; + + fribidi_log2vis_get_embedding_levels(in,length,&direction,embed); +} +#endif + +/* This function marks embedding levels at for text "in", + * it ignores different tags */ +void bidi_tag_tolerant_fribidi_l2v( FriBidiChar *in,int len, + int is_rtl, + FriBidiLevel *embed, + char *is_command) +{ + int in_pos,out_pos,cmd_len,i; + FriBidiChar *in_tmp; + FriBidiLevel *embed_tmp,fill_level; + + in_tmp=(FriBidiChar*)utl_malloc(sizeof(FriBidiChar)*(len+1)); + embed_tmp=(FriBidiLevel*)utl_malloc(sizeof(FriBidiLevel)*len); + + /********************************************** + * This is main parser that marks commands * + * across the text i.e. marks non text * + **********************************************/ + bidi_mark_commands(in,len,is_command,is_rtl); + + /**********************************************/ + /* Copy all the data without tags for fribidi */ + /**********************************************/ + in_pos=0; + out_pos=0; + + while(in_pos<len) { + if(is_command[in_pos]){ + in_pos++; + continue; + } + /* Copy to buffer */ + in_tmp[out_pos]=in[in_pos]; + out_pos++; + in_pos++; + } + + /*************** + * RUN FRIBIDI * + ***************/ + + /* Note - you must take the new size for firibidi */ + get_bidi_levels(in_tmp,out_pos,is_rtl,embed_tmp); + + /**************************************************** + * Return the tags and fill missing embedding level * + ****************************************************/ + in_pos=0; + out_pos=0; + + while(in_pos<len) { + if(is_command[in_pos]){ + /* Find the length of the part that + * has a command/tag */ + for(cmd_len=0;in_pos+cmd_len<len;cmd_len++) { + if(!is_command[cmd_len+in_pos]) + break; + } + + if(in_pos == 0 || in_pos + cmd_len == len){ + /* When we on start/end assume basic direction */ + fill_level = bidi_basic_level(is_rtl); + } + else { + /* Fill with minimum on both sides */ + fill_level = min(embed_tmp[out_pos-1],embed_tmp[out_pos]); + } + + for(i=0;i<cmd_len;i++){ + embed[in_pos]=fill_level; + in_pos++; + } + continue; + } + /* Retrieve embedding */ + embed[in_pos]=embed_tmp[out_pos]; + out_pos++; + in_pos++; + } + + /* Not forget to free */ + utl_free(embed_tmp); + utl_free(in_tmp); +} + +int bidi_only_latin_number(FriBidiLevel *levels,FriBidiChar *string) +{ + FriBidiChar ch; + while(*string && (*levels & 1)==0 ) { + ch=*string; + if(ch>127) { /* other foreign language */ + return 0; + } + if(('a'<=ch && ch<='z') || ('A'<=ch && ch<='Z')) { + /* Find latin characters */ + return 0; + } + string++; + levels++; + } + return 1; +} + +int bidi_only_nonlatin_number(FriBidiLevel *levels,FriBidiChar *string) +{ + FriBidiChar ch; + while(*string && (*levels & 1)==0 ) { + ch=*string; + if('0'<=ch && ch<='9') { /* Find latin numbers */ + return 0; + } + if(('a'<=ch && ch<='z') || ('A'<=ch && ch<='Z')) { + /* Find latin characters */ + return 0; + } + string++; + levels++; + } + return 1; +} + +/* Mark Unicode LRM & RLM charrecters */ +int bidi_is_directional_mark(FriBidiChar c) +{ + if(c==0x200F || c==0x200E) { + return 1; + } + return 0; +} + +/* The function that parses line and adds required \R \L tags */ +void bidi_add_tags(FriBidiChar *in,FriBidiChar *out,int limit, + int is_rtl,int replace_minus,int no_mirroring) +{ + int len,new_len,level,new_level,brakets; + int i,size; + int is_number_env=0; + + const char *tag; + char *is_command; + + + len=bidi_strlen(in); + + is_command=(char*)utl_malloc(len); + + bidi_tag_tolerant_fribidi_l2v(in,len,is_rtl,bidi_embed,is_command); + + level=bidi_basic_level(is_rtl); + + new_len=0; + out[0]=0; + brakets=0; + for(i=0,new_len=0;i<len;i++){ + new_level=bidi_embed[i]; + + if(new_level>level) { + /* LTR Direction according to odd/even value of level */ + is_number_env=FALSE; + if((new_level & 1) == 0) { + if(bidi_only_latin_number(bidi_embed+i,in+i)){ + tag=TAG_LATIN_NUM; + is_number_env=TRUE; + } + else if(bidi_only_nonlatin_number(bidi_embed+i,in+i)){ + tag=TAG_NONLATIN_NUM; + is_number_env=TRUE; + } + else { + tag=TAG_LTR; + } + } + else { + tag=TAG_RTL; + } + brakets++; + bidi_add_str_c(out,&new_len,limit,tag); + } + else if(new_level<level) { + bidi_add_str_c(out,&new_len,limit,TAG_CLOSE); + brakets--; + } + + if( + (new_level & 1)!=0 + && !is_command[i] + && !no_mirroring + && (tag=bidi_mirror(in+i,&size,replace_minus))!=NULL) + { + /* Replace charrecter with its mirror only in case + * we are in RTL direction */ + + /* Note this can be a sequence like "\{" */ + bidi_add_str_c(out,&new_len,limit,tag); + i+=size-1; + } + else if( + (new_level & 1)!=1 + && is_number_env + && replace_minus + && !is_command[i] + && (tag=bidi_one_mirror(in+i,&size,bidi_hack_list))!=NULL) + { + /* Replace "--/---" with a tag "\tex{en|em}dash" only in LTR + * direction only if this is nubmers environment */ + + bidi_add_str_c(out,&new_len,limit,tag); + i+=size-1; + } + else if(bidi_is_directional_mark(in[i])){ + /* Do nothing -- erase marks that are + * not actual charrecters and thus not presented in fonts */ + } + else { + bidi_add_char_u(out,&new_len,limit,in[i]); + } + level=new_level; + } + /* Fill all missed brakets */ + while(brakets){ + bidi_add_str_c(out,&new_len,limit,TAG_CLOSE); + brakets--; + } + utl_free(is_command); +} + +/*************************/ +/* T R A N S L A T I O N */ +/*************************/ + +static void bidi_error(char *text) +{ + fprintf(stderr,"ERROR in line %d: `%s'\n",io_line_number,text); + exit(1); +} + + +static int is_hebrew_tag(FriBidiChar buffer[MAX_COMMAND_LEN],FriBidiChar **ptr) +{ + FriBidiChar *tmp_ptr = *ptr; + int size=0; + if(!dict_is_hebrew_letter(*tmp_ptr)) { + return FALSE; + } + while(dict_is_hebrew_letter(*tmp_ptr)) { + if(size<MAX_COMMAND_LEN-1) { + buffer[size]=*tmp_ptr; + tmp_ptr++; + size++; + } + else { + bidi_error("Hebrew tag is too long"); + return FALSE; + } + } + buffer[size]=0; + *ptr=tmp_ptr; + return TRUE; + +} + +static int is_ascii_tag(char buffer[MAX_COMMAND_LEN],FriBidiChar **ptr) +{ + FriBidiChar *tmp_ptr = *ptr; + int size=0; + if(!bidi_is_cmd_char(*tmp_ptr)) { + return FALSE; + } + while(bidi_is_cmd_char(*tmp_ptr)) { + if(size<MAX_COMMAND_LEN-1) { + buffer[size]=*tmp_ptr; + tmp_ptr++; + size++; + } + else { + /* No warning need - no limit */ + return FALSE; + } + } + buffer[size]=0; + *ptr=tmp_ptr; + return TRUE; + +} + + +static char const *is_tag_begin_or_end(FriBidiChar **ptr) +{ + char ascii_tag[MAX_COMMAND_LEN]; + char *trans=NULL; + FriBidiChar *tmp_ptr=*ptr; + FriBidiChar unicode_tag[MAX_COMMAND_LEN]; + + if(is_ascii_tag(ascii_tag,&tmp_ptr) || + ( + is_hebrew_tag(unicode_tag,&tmp_ptr) + && (trans=dict_translate_tag(unicode_tag)) + ) + ) + { + if(trans) strcpy(ascii_tag,trans); + + if(strcmp(ascii_tag,"begin")==0){ + *ptr=tmp_ptr; + return "begin"; + } + else if(strcmp(ascii_tag,"end")==0){ + *ptr=tmp_ptr; + return "end"; + } + else { + return NULL; + } + } + else { + return NULL; + } +} + +#define is_open_bracket(x) ( **(x) == '{' ? ++*(x) : FALSE ) +#define is_close_bracket(x) ( **(x) == '}' ? ++*(x) : FALSE ) + +static const char *is_heb_word(FriBidiChar **ptr,trans_func_t tras_func) +{ + FriBidiChar *tmp_ptr=*ptr; + FriBidiChar unicode_tag[MAX_COMMAND_LEN]; + char *trans; + if(is_hebrew_tag(unicode_tag,&tmp_ptr)) { + if((trans=tras_func(unicode_tag))!=NULL) { + *ptr=tmp_ptr; + return trans; + } + else { + bidi_error("Unknown hebrew tag - not translated"); + return NULL; + } + } + else { + return NULL; + } +} + +#define is_heb_environment(x) is_heb_word((x),dict_translate_env) +#define is_heb_tag(x) is_heb_word((x),dict_translate_tag) + +static char *is_hebrew_command(FriBidiChar *text,int *length) +{ + char const *tag_txt,*env_txt; + + static char buffer[MAX_COMMAND_LEN*2+3]; + /* The command can consist at most of name of tag, + * environment and breakets */ + + FriBidiChar *end_ptr; + if(*text!='\\') { + return NULL; + } + + end_ptr=text+1; + if((tag_txt = is_tag_begin_or_end(&end_ptr))!=NULL + && is_open_bracket(&end_ptr) + && (env_txt=is_heb_environment(&end_ptr))!=NULL + && is_close_bracket(&end_ptr)) + { + *length=end_ptr-text; + strcpy(buffer,"\\"); + strcat(buffer,tag_txt); + strcat(buffer,"{"); + strcat(buffer,env_txt); + strcat(buffer,"}"); + return buffer; + } + + end_ptr=text+1; + if((tag_txt=is_heb_tag(&end_ptr))!=NULL){ + *length=end_ptr-text; + strcpy(buffer,"\\"); + strcat(buffer,tag_txt); + return buffer; + } + return NULL; +} + +void bidi_translate_tags(FriBidiChar *in,FriBidiChar *out,int limit) +{ + int ptr; + int new_length,cmd_len; + char *tr_command; + ptr=0; + new_length=0; + + out[0]=0; + + while(in[ptr]) { + /* In case there is \\ before hebrew word */ + if(in[ptr]=='\\' && in[ptr+1]=='\\'){ + ptr+=2; + bidi_add_str_c(out,&new_length,limit,"\\\\"); + continue; + } + else if((tr_command = is_hebrew_command(in+ptr,&cmd_len))!=NULL) { + ptr+=cmd_len; + bidi_add_str_c(out,&new_length,limit,tr_command); + } + else { + bidi_add_char_u(out,&new_length,limit,in[ptr]); + ptr++; + } + } + +} + +void bidi_grammar_skip_blank(FriBidiChar **ptr) +{ + FriBidiChar ch; + while((ch=**ptr)==' ' || ch=='\t' || ch=='\r' || ch=='\n') + ++*ptr; +} + +/* + * format is following: + * "lh" - latin word, hebrew word, + * "l" - one latin word + * parameters are (FriBidiChar *) for h and (char *) for l + */ +int bidi_grammar(FriBidiChar *in,char *tagname,char *format, + FriBidiChar hebrew[MAX_COMMAND_LEN], + char ascii[MAX_COMMAND_LEN]) +{ + if(!bidi_strieq_u_a(in,tagname)) { + return 0; + } + + in+=strlen(tagname); + + bidi_grammar_skip_blank(&in); + + while(*format) { + if(*format=='h'){ + if(!is_hebrew_tag(hebrew,&in)){ + bidi_error("Hebrew word expected"); + } + } + else if(*format == 'l') { + if(!is_ascii_tag(ascii,&in)){ + bidi_error("Latin word expected"); + } + } + else { + fprintf(stderr,"Internall error\n"); + exit(1); + } + format++; + bidi_grammar_skip_blank(&in); + } + if(*in!=0) { + bidi_error("Unexpected charrecter"); + } + return 1; +} + +void bidi_parse_fribidixetex_command(FriBidiChar *in) +{ + FriBidiChar unicode[MAX_COMMAND_LEN]; + char ascii[MAX_COMMAND_LEN]; + + if(bidi_grammar(in,TAG_BIDI_ON,"",NULL,NULL)) { + bidi_mode = MODE_BIDION; + } + else if(bidi_grammar(in,TAG_BIDI_OFF,"",NULL,NULL)) { + bidi_mode = MODE_BIDIOFF; + } + else if(bidi_grammar(in,TAG_BIDI_LTR,"",NULL,NULL)) { + bidi_mode = MODE_BIDILTR; + } + else if(bidi_grammar(in,TAG_BIDI_NEW_TAG,"l",NULL,ascii)) { + bidi_add_command(ascii); + } + else if(bidi_grammar(in,TAG_BIDI_DIC_TAG,"hl",unicode,ascii)) { + dict_add_tans(unicode,ascii,DICT_TAG); + } + else if(bidi_grammar(in,TAG_BIDI_DIC_ENV,"hl",unicode,ascii)) { + dict_add_tans(unicode,ascii,DICT_ENV); + } + else { + bidi_error("Unknown fribidixetex command"); + } +} + +/********************* + * M A I N L O O P * + *********************/ + +/* Main line processing function */ +int bidi_process(FriBidiChar *in,FriBidiChar *out, + int replace_minus,int tranlate_only,int no_mirroring) +{ + int i,is_rtl; + + if(bidi_strieq_u_a(in,"%BIDI")) { + bidi_parse_fribidixetex_command(in); + return 0; + } + + if(bidi_mode != MODE_BIDIOFF) { + is_rtl = (bidi_mode == MODE_BIDION); + if(tranlate_only) { + /* In case of translation only put directly to output buffer */ + bidi_translate_tags(in,out,MAX_LINE_SIZE); + } + else { /* Normal processing */ + /* Translate hebrew tags to ascii tags */ + bidi_translate_tags(in,translation_buffer,MAX_LINE_SIZE); + + /* Apply BiDi algorithm */ + bidi_add_tags(translation_buffer,out,MAX_LINE_SIZE, + is_rtl ,replace_minus,no_mirroring); + } + } + else { + for(i=0;in[i];i++){ + out[i]=in[i]; + } + out[i]=0; + } + return 1; +} + +void bidi_finish(void) +{ + bidi_cmd_t *tmp; + while(bidi_command_list) { + tmp=bidi_command_list; + bidi_command_list=bidi_command_list->next; + utl_free(tmp->name); + utl_free(tmp); + } + if(bidi_mode != MODE_BIDIOFF) { + fprintf(stderr,"Warning: No %%BIDIOFF Tag at the end of the file\n"); + } +} + +void bidi_init(FILE *f_out) +{ + int i; + + bidi_mode = MODE_BIDIOFF; + + for(i=0;ignore_tags_list[i][0];i++) { + bidi_add_command(ignore_tags_list[i]); + } + +} diff --git a/support/fribidixetex/src/fribidixetex-bidi.h b/support/fribidixetex/src/fribidixetex-bidi.h new file mode 100644 index 0000000000..9f4e586caf --- /dev/null +++ b/support/fribidixetex/src/fribidixetex-bidi.h @@ -0,0 +1,11 @@ +#ifndef _BIDI_H_ +#define _BIDI_H_ +#include <stdio.h> +#include <fribidi/fribidi.h> + +void bidi_init(FILE *f_out); +int bidi_process(FriBidiChar *in,FriBidiChar *out, + int replace_minus,int tranlate_only,int no_mirroring); +void bidi_finish(void); + +#endif diff --git a/support/fribidixetex/src/fribidixetex-defines.h b/support/fribidixetex/src/fribidixetex-defines.h new file mode 100644 index 0000000000..fcbf3c8c29 --- /dev/null +++ b/support/fribidixetex/src/fribidixetex-defines.h @@ -0,0 +1,24 @@ +#ifndef _DEFINES_H_ +#define _DEFINES_H_ + +enum { ENC_UTF_8 , ENC_ISO_8859_8, ENC_CP1255 }; + +/*******************/ +/* PROJECT DEFINES */ +/*******************/ + +#define MAX_LINE_SIZE 32768 +/* Maximal size of input/output line in the text */ + +#define MAX_COMMAND_LEN 128 +/* Maxima length of defined command */ + +#define ENC_DEFAULT ENC_UTF_8 +/* The default IO encoding - UTF-8 */ + + +#define MAX_USER_TRANSLATIONS 500 + +/*******************/ + +#endif /* _DEFINES_H_ */ diff --git a/support/fribidixetex/src/fribidixetex-dict.c b/support/fribidixetex/src/fribidixetex-dict.c new file mode 100644 index 0000000000..fc2225d1c2 --- /dev/null +++ b/support/fribidixetex/src/fribidixetex-dict.c @@ -0,0 +1,145 @@ +#include "fribidixetex-dict.h" +#include "fribidixetex-defines.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/*********************** + * D A T A * + ***********************/ + + +typedef struct +{ + wchar_t hebrew[MAX_COMMAND_LEN]; + char ascii[MAX_COMMAND_LEN]; +} + dict_t; + +#define LETTER_ALEPH L'א' +#define LETTER_TAV L'ת' + +#define SIZEOF_ARRAY(x) (sizeof(x)/sizeof(x[0])) + +dict_t dict_utf8_tags_perm[] = +{ + { L"ש", "L" }, + { L"י", "R" }, + { L"התחל", "begin" }, + { L"סיים", "end" }, + { L"כותרת", "title" }, + { L"תוכןעניינים", "tableofcontents" }, + { L"צורכותרת", "maketitle" }, + { L"מחבר", "author" }, + { L"תאריך", "date" }, + { L"חלק", "part" }, + { L"פרק", "chapter" }, + { L"סעיף", "section" }, + { L"תתסעיף", "subsection"}, + { L"תתתתסעיף", "subsubsection"}, + { L"הדגש", "emph" }, + { L"פריט", "item" }, + { L"נק", "item" }, + { L"תג", "label" }, + { L"ראה", "ref" }, + { L"הערתשוליים", "footnote" }, + { L"צטט", "cite" }, + { L"נקודות", "ldots" }, +}; + +dict_t dict_utf8_envs_perm[] = +{ + { L"פירוט","itemize"}, + { L"תיאור","description" }, + { L"מספור", "enumerate" }, + { L"שיר", "verse" }, + { L"מסמך", "document" }, + { L"תקציר", "abstract" }, +}; + +/*************/ +/* User tags */ +/*************/ + +int user_tags_size=0; +int user_envs_size=0; + +dict_t dict_utf8_tags_user[MAX_USER_TRANSLATIONS]; +dict_t dict_utf8_envs_user[MAX_USER_TRANSLATIONS]; + + +/**************/ + + +int dict_is_hebrew_letter(FriBidiChar ch) +{ + return (LETTER_ALEPH<=ch && ch<=LETTER_TAV); + /* Range from alef to tav in Unicode */ +} + +char *dict_find(FriBidiChar *str,dict_t *dictionary,int size) +{ + wchar_t *wstr; + int i; + FriBidiChar *bstr; + + for(i=0;i<size;i++){ + wstr=dictionary[i].hebrew; + bstr=str; + while(*bstr && *wstr && *bstr == (FriBidiChar)*wstr){ + bstr++; + wstr++; + } + if(*bstr==0 && *wstr==0){ + return dictionary[i].ascii; + } + } + return NULL; +} + + +char *dict_translate_env(FriBidiChar *str) +{ + char *ptr; + ptr=dict_find(str,dict_utf8_envs_perm,SIZEOF_ARRAY(dict_utf8_envs_perm)); + if(ptr== NULL) + return dict_find(str,dict_utf8_envs_user,user_envs_size); + return ptr; +} +char *dict_translate_tag(FriBidiChar *str) +{ + char *ptr; + ptr=dict_find(str,dict_utf8_tags_perm,SIZEOF_ARRAY(dict_utf8_tags_perm)); + if(ptr==NULL) + return dict_find(str,dict_utf8_tags_user,user_tags_size); + return ptr; +} + +void dict_set_tag(dict_t *entry,FriBidiChar *uni,char *ascii) +{ + int i; + for(i=0;uni[i];i++) + entry->hebrew[i]=uni[i]; + entry->hebrew[i]=0; + strcpy(entry->ascii,ascii); +} + +void dict_add_tans(FriBidiChar *tag_uni,char *tag_ascii,int type) +{ + if(type == DICT_ENV) { + if(user_envs_size>=MAX_USER_TRANSLATIONS) { + fprintf(stderr,"Too many evironments translations added\n"); + exit(1); + } + dict_set_tag(dict_utf8_envs_user+user_envs_size,tag_uni,tag_ascii); + user_envs_size++; + } + else { + if(user_tags_size>=MAX_USER_TRANSLATIONS) { + fprintf(stderr,"Too many tags translations added\n"); + exit(1); + } + dict_set_tag(dict_utf8_tags_user+user_tags_size,tag_uni,tag_ascii); + user_tags_size++; + } +} diff --git a/support/fribidixetex/src/fribidixetex-dict.h b/support/fribidixetex/src/fribidixetex-dict.h new file mode 100644 index 0000000000..d852a1e7a3 --- /dev/null +++ b/support/fribidixetex/src/fribidixetex-dict.h @@ -0,0 +1,16 @@ +#ifndef _DICT_H_ +#define _DICT_H_ +#include <fribidi/fribidi.h> + +enum {DICT_ENV, DICT_TAG}; + +int dict_is_hebrew_letter(FriBidiChar ch); + +typedef char *(*trans_func_t)(FriBidiChar *str); +char *dict_translate_env(FriBidiChar *str); +char *dict_translate_tag(FriBidiChar *str); + +void dict_add_tans(FriBidiChar *tag_uni,char *tag_ascii,int type); + + +#endif diff --git a/support/fribidixetex/src/fribidixetex-ignore.c b/support/fribidixetex/src/fribidixetex-ignore.c new file mode 100644 index 0000000000..c155d79303 --- /dev/null +++ b/support/fribidixetex/src/fribidixetex-ignore.c @@ -0,0 +1,20 @@ +/* All the tags that their content + * should be ignored by fribidixetex */ +const char *ignore_tags_list[] = +{ + "begin", "end", "fribidixetexRLE", "fribidixetexLRE", "fribidixetexlatinnumbers", "fribidixetexnonlatinnumbers", + "input", "include", "includegraphics", "includeonly", + "hspace", "vspace", "hspace*", "vspace*", + "ref", "label", "includegraphics", + "bibliographystyle", + "parbox", + "newenvironment", "newtheorem", + "persianmathdigitsfamily", + "fontfamily", "fontseries", "fontshape", + "rmdefault", "sfdefault", "ttdefault", + "bfdefault", "itdefault", "sldefault", "scdefault", + "pagenumbering", "pagestyle", "thispagestyle", + "setcounter", "stepcounter", "setlength", "addtolength" + "bibitem", "cite" ,"" +}; + diff --git a/support/fribidixetex/src/fribidixetex-ignore.h b/support/fribidixetex/src/fribidixetex-ignore.h new file mode 100644 index 0000000000..3d94f7c483 --- /dev/null +++ b/support/fribidixetex/src/fribidixetex-ignore.h @@ -0,0 +1,6 @@ +#ifndef _IGNORE_H_ +#define _IGNORE_H_ + +extern const char *ignore_tags_list[]; + +#endif diff --git a/support/fribidixetex/src/fribidixetex-io.c b/support/fribidixetex/src/fribidixetex-io.c new file mode 100644 index 0000000000..5d497162ed --- /dev/null +++ b/support/fribidixetex/src/fribidixetex-io.c @@ -0,0 +1,110 @@ +#include <fribidi/fribidi.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "fribidixetex-io.h" + +static char text_buffer[MAX_LINE_SIZE]; +int io_line_number; + +void io_init(void) +{ + io_line_number=0; +} + +int io_read_line(FriBidiChar *text,int encoding,FILE *f) +{ + int len_char,len_uni; + if(fgets(text_buffer,MAX_LINE_SIZE-1,f)==NULL) { + return 0; + } + + len_char=strlen(text_buffer); + + if(len_char==MAX_LINE_SIZE - 2) { + fprintf(stderr,"Warning: line %d is too long\n",io_line_number+1); + } + if(len_char>0 && text_buffer[len_char-1]=='\n') { + io_line_number++; + text_buffer[len_char-1]=0; + len_char--; + } + switch(encoding) { + case ENC_ISO_8859_8: + len_uni=fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_ISO8859_8,text_buffer,len_char,text); + text[len_uni]=0; + break; + case ENC_CP1255: + len_uni=fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_CP1255,text_buffer,len_char,text); +#if ( FRIBIDI_MAJOR_VERSION * 100 + FRIBIDI_MINOR_VERSION ) <= 10 // 0.10 + { + int i; + for(i=0;i<len_uni;i++) { + if(text[i]==253 || text[i]==254) + text[i] += (0x200E - 253); + } + } +#endif + text[len_uni]=0; + break; + case ENC_UTF_8: + if(len_char >= 3 && memcmp(text_buffer,"\xEF\xBB\xBF",3) == 0) { + // remove BOM, support Win32 Notepad + len_uni=fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,text_buffer+3,len_char-3,text); + } + else { + len_uni=fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,text_buffer,len_char,text); + } + text[len_uni]=0; + break; + default: + fprintf(stderr,"Internal error - wrong encoding\n"); + exit(1); + } + return 1; +} + +void io_write_line(FriBidiChar *text,int encoding,FILE *f) +{ + int len,char_len,tmp_len; + /* Find legth of buffer */ + for(len=0;text[len] && len<MAX_LINE_SIZE-1;len++) /* NOTHING */; + + if(len>=MAX_LINE_SIZE-1) { + fprintf(stderr,"Internall error - unterminated line\n"); + exit(1); + } + + if(encoding == ENC_ISO_8859_8) { + char_len=fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_ISO8859_8,text,len,text_buffer); + text_buffer[char_len]=0; + fprintf(f,"%s\n",text_buffer); + } + else if(encoding == ENC_CP1255) { + char_len=fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_CP1255,text,len,text_buffer); + text_buffer[char_len]=0; + fprintf(f,"%s\n",text_buffer); + } + else if(encoding == ENC_UTF_8) { + while(len) { + /* Because maybe |unicode| < |utf8| + * in order to prevetn overflow */ + if(len>MAX_LINE_SIZE/8){ + tmp_len=MAX_LINE_SIZE/8; + } + else { + tmp_len = len; + } + char_len=fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8,text,tmp_len,text_buffer); + text_buffer[char_len]=0; + fprintf(f,"%s",text_buffer); + len -= tmp_len; + text += tmp_len; + } + fprintf(f,"\n"); + } + else { + fprintf(stderr,"Internal error - wrong encoding\n"); + exit(1); + } +} diff --git a/support/fribidixetex/src/fribidixetex-io.h b/support/fribidixetex/src/fribidixetex-io.h new file mode 100644 index 0000000000..63145d0519 --- /dev/null +++ b/support/fribidixetex/src/fribidixetex-io.h @@ -0,0 +1,15 @@ +#ifndef _IO_H_ +#define _IO_H_ + +#include <stdio.h> +#include <fribidi/fribidi.h> +#include "fribidixetex-defines.h" + +int io_read_line(FriBidiChar *text,int encoding,FILE *f); +void io_write_line(FriBidiChar *text,int encoding,FILE *f); + +void io_init(void); + +extern int io_line_number; + +#endif diff --git a/support/fribidixetex/src/fribidixetex-util.c b/support/fribidixetex/src/fribidixetex-util.c new file mode 100644 index 0000000000..12ebed6245 --- /dev/null +++ b/support/fribidixetex/src/fribidixetex-util.c @@ -0,0 +1,28 @@ +#include <stdlib.h> +#include <stdio.h> +#include "fribidixetex-util.h" + +void *utl_malloc(size_t size) +{ + void *ptr; + ptr=malloc(size); + if(!ptr) { + fprintf(stderr,"Out of memory\n"); + exit(1); + } + return ptr; +} +void *utl_realloc(void *inptr,size_t size) +{ + void *ptr; + ptr=realloc(inptr,size); + if(!ptr) { + fprintf(stderr,"Out of memory\n"); + exit(1); + } + return ptr; +} +void utl_free(void *ptr) +{ + free(ptr); +} diff --git a/support/fribidixetex/src/fribidixetex-util.h b/support/fribidixetex/src/fribidixetex-util.h new file mode 100644 index 0000000000..84eedeb28c --- /dev/null +++ b/support/fribidixetex/src/fribidixetex-util.h @@ -0,0 +1,9 @@ +#ifndef _UTL_H_ +#define _UTL_H_ +#include <stdlib.h> + +void *utl_malloc(size_t size); +void *utl_realloc(void *ptr,size_t size); +void utl_free(void *ptr); + +#endif diff --git a/support/fribidixetex/src/fribidixetex.c b/support/fribidixetex/src/fribidixetex.c new file mode 100644 index 0000000000..0df17b4e03 --- /dev/null +++ b/support/fribidixetex/src/fribidixetex.c @@ -0,0 +1,184 @@ +/*********************************/ +/* Copyright Vafa Khalighi 2016 */ +/* Copyright Khaled Hosny 2015 */ +/* Copyright Artyom Tonkikh 2007 */ +/* License GPL */ +/*********************************/ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <fribidi/fribidi.h> + +#include "fribidixetex-defines.h" +#include "fribidixetex-io.h" +#include "fribidixetex-bidi.h" + +void help(void) +{ + fprintf(stderr, + "usage: fribidixetex [ parameters ] [ inputfilename ]\n" + " -o file_name.tex - output file name\n" + " -e utf8 | iso8859-8 | cp1255 - encoding\n" + " -t utf8 | iso8859-8 | cp1255 - output encoding\n" + " -d transalte only - not apply bidi\n" + " this is usefull for latex2html that has native\n" + " bidirectional support\n" + " -m replace '--' & '---'\n" + " by '\\fribidixetexLRE{--} & \\fribidixetexLRE{'---'}\n" + " -n no mirroring - do not mirror parethesis\n" + " for engines that do that natively (like XeTeX)\n" + ); + exit(1); +} + + +/* Read cmd line parameters */ +void read_parameters(int argc,char **argv, + char **fname_in,char **fname_out, + int *encoding,int *out_encoding, + int *replace_minus,int *transalte_only, + int *no_mirroring) +{ + int i; + int cnt1=0,cnt2=0,cnt3=0,cnt4=0; + int *ptr; + + for(i=1;i<argc;i++){ + if(strcmp(argv[i],"-h")==0) { + help(); + } + else if(strcmp(argv[i],"-d")==0) { + *transalte_only = 1; + } + else if(strcmp(argv[i],"-m")==0) { + *replace_minus = 1; + } + else if(strcmp(argv[i],"-n")==0) { + *no_mirroring = 1; + } + else if(strcmp(argv[i],"-o")==0) { + i++; + if(i>=argc){ + help(); + } + *fname_out = argv[i]; + cnt1++; + } + else if(strcmp(argv[i],"-e")==0 || strcmp(argv[i],"-t")==0) { + if(i+1>=argc){ + help(); + } + + if(argv[i][1]=='e'){ + ptr=encoding; + cnt2++; + } + else{ + ptr=out_encoding; + cnt4++; + } + i++; + if(strcmp(argv[i],"utf8")==0) { + *ptr=ENC_UTF_8; + } + else if(strcmp(argv[i],"cp1255")==0) { + *ptr=ENC_CP1255; + } + else if(strcmp(argv[i],"iso8859-8")==0) { + *ptr=ENC_ISO_8859_8; + } + else { + help(); + } + } + else { + *fname_in=argv[i]; + cnt3++; + } + } + if(cnt1>1 || cnt2>1 || cnt3>1 || cnt4>1){ + help(); + } +} + +/* Global buffers */ + +static FriBidiChar text_line_in[MAX_LINE_SIZE]; +static FriBidiChar text_line_out[MAX_LINE_SIZE]; + +/**************************** + ******** M A I N *********** + ****************************/ +int main(int argc,char **argv) +{ + char *fname_in=NULL,*fname_out=NULL; + int encoding=ENC_DEFAULT,out_encoding = -1; + int replace_minus = 0; + int transalte_only = 0; + int no_mirroring = 0; + + FILE *f_in,*f_out; + + /****************** + * Inicialization * + ******************/ + + read_parameters(argc,argv,&fname_in,&fname_out, + &encoding,&out_encoding, + &replace_minus,&transalte_only, + &no_mirroring); + if(out_encoding == -1) { + out_encoding = encoding; + } + + if(!fname_in) { + f_in = stdin; + } + else { + if(!(f_in=fopen(fname_in,"r"))) { + fprintf(stderr,"Failed to open %s for reading\n",fname_in); + exit(1); + } + } + + if(!fname_out) { + f_out = stdout; + } + else { + if(!(f_out=fopen(fname_out,"w"))) { + fprintf(stderr,"Failed to open %s for writing\n",fname_out); + exit(1); + } + } + + + /************* + * Main loop * + *************/ + + io_init(); + + bidi_init(f_out); + + while(io_read_line(text_line_in,encoding,f_in)) { + + if(bidi_process(text_line_in,text_line_out, + replace_minus,transalte_only,no_mirroring)) + { + /*If there is something to print */ + io_write_line(text_line_out,out_encoding,f_out); + } + + } + + /********** + * Finish * + **********/ + + if(f_out!=stdout) fclose(f_out); + if(f_in!=stdin) fclose(f_in); + + bidi_finish(); + + return 0; +} |