summaryrefslogtreecommitdiff
path: root/firmware/bidi.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/bidi.c')
-rw-r--r--firmware/bidi.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/firmware/bidi.c b/firmware/bidi.c
new file mode 100644
index 0000000000..765d3dab24
--- /dev/null
+++ b/firmware/bidi.c
@@ -0,0 +1,184 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Gadi Cohen
11 *
12 * Largely based on php_hebrev by Zeev Suraski <zeev@php.net>
13 * Heavily modified by Gadi Cohen aka Kinslayer <dragon@wastelands.net>
14 *
15 * All files in this archive are subject to the GNU General Public License.
16 * See the file COPYING in the source tree root for full license agreement.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include <stdio.h>
23#include <string.h>
24#include <ctype.h>
25#include "file.h"
26#include "lcd.h"
27
28#define _HEB_BUFFER_LENGTH MAX_PATH + LCD_WIDTH/2 + 3 + 2 + 2
29#define _HEB_BLOCK_TYPE_ENG 1
30#define _HEB_BLOCK_TYPE_HEB 0
31#define _HEB_ORIENTATION_LTR 1
32#define _HEB_ORIENTATION_RTL 0
33
34#define ischar(c) (((((unsigned char) c)>=193) && (((unsigned char) c)<=250)) ? 1 : 0)
35#define _isblank(c) (((((unsigned char) c)==' ' || ((unsigned char) c)=='\t')) ? 1 : 0)
36#define _isnewline(c) (((((unsigned char) c)=='\n' || ((unsigned char) c)=='\r')) ? 1 : 0)
37#define XOR(a,b) ((a||b) && !(a&&b))
38
39bool bidi_support_enabled = false;
40
41unsigned char *bidi_l2v(const unsigned char *str, int orientation)
42{
43 static unsigned char buf_heb_str[_HEB_BUFFER_LENGTH];
44 static unsigned char buf_broken_str[_HEB_BUFFER_LENGTH];
45 const unsigned char *tmp;
46 unsigned char *heb_str, *target, *opposite_target, *broken_str;
47 int block_start, block_end, block_type, block_length, i;
48 int block_ended;
49 long max_chars=0;
50 int begin, end, char_count, orig_begin;
51
52 if (!str || !*str)
53 return "";
54
55 tmp = str;
56 block_start=block_end=0;
57 block_ended=0;
58
59 heb_str = buf_heb_str;
60 if (orientation) {
61 target = heb_str;
62 opposite_target = heb_str + strlen(str);
63 } else {
64 target = heb_str + strlen(str);
65 opposite_target = heb_str;
66 *target = 0;
67 target--;
68 }
69
70 block_length=0;
71 if (ischar(*tmp))
72 block_type = _HEB_BLOCK_TYPE_HEB;
73 else
74 block_type = _HEB_BLOCK_TYPE_ENG;
75
76 do {
77 while((XOR(ischar((int)*(tmp+1)),block_type)
78 || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1))
79 || (int)*(tmp+1)=='\n')
80 && block_end<(int)strlen(str)-1) {
81 tmp++;
82 block_end++;
83 block_length++;
84 }
85
86 if (block_type != orientation) {
87 while ((_isblank((int)*tmp) || ispunct((int)*tmp))
88 && *tmp!='/' && *tmp!='-' && block_end>block_start) {
89 tmp--;
90 block_end--;
91 }
92 }
93
94 for (i=block_start; i<=block_end; i++) {
95 *target = (block_type == orientation) ? *(str+i) : *(str+block_end-i+block_start);
96 if (block_type!=orientation) {
97 switch (*target) {
98 case '(':
99 *target = ')';
100 break;
101 case ')':
102 *target = '(';
103 break;
104 default:
105 break;
106 }
107 }
108 target += orientation ? 1 : -1;
109 }
110 block_type = !block_type;
111 block_start=block_end+1;
112 } while(block_end<(int)strlen(str)-1);
113
114 broken_str = buf_broken_str;
115 begin=end=strlen(str)-1;
116 target = broken_str;
117
118 while (1) {
119 char_count=0;
120 while ((!max_chars || char_count<max_chars) && begin>0) {
121 char_count++;
122 begin--;
123 if (begin<=0 || _isnewline(heb_str[begin])) {
124 while(begin>0 && _isnewline(heb_str[begin-1])) {
125 begin--;
126 char_count++;
127 }
128 break;
129 }
130 }
131 if (char_count==max_chars) { /* try to avoid breaking words */
132 int new_char_count = char_count;
133 int new_begin = begin;
134
135 while (new_char_count>0) {
136 if (_isblank(heb_str[new_begin]) ||
137 _isnewline(heb_str[new_begin])) {
138 break;
139 }
140 new_begin++;
141 new_char_count--;
142 }
143 if (new_char_count>0) {
144 char_count=new_char_count;
145 begin=new_begin;
146 }
147 }
148 orig_begin=begin;
149
150 if (_isblank(heb_str[begin])) {
151 heb_str[begin]='\n';
152 }
153
154 /* skip leading newlines */
155 while (begin<=end && _isnewline(heb_str[begin])) {
156 begin++;
157 }
158
159 /* copy content */
160 for (i=begin; i<=end; i++) {
161 *target = heb_str[i];
162 target++;
163 }
164
165 for (i=orig_begin; i<=end && _isnewline(heb_str[i]); i++) {
166 *target = heb_str[i];
167 target++;
168 }
169 begin=orig_begin;
170
171 if (begin<=0) {
172 *target = 0;
173 break;
174 }
175 begin--;
176 end=begin;
177 }
178 return broken_str;
179}
180
181void set_bidi_support(bool setting)
182{
183 bidi_support_enabled = setting;
184}