1 /***************************************************************************
2                           hebString.cxx - Hebrew string handling
3                              -------------------
4     begin                : Thu Mar  1 13:15:18 IST 2001
5     copyright            : (C) 2001 by Arie Tal
6     email                : tal_arie@yahoo.com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21 
22 #include "hebString.h"
23 #include <string.h>
24 #include <iostream>
25 #include <assert.h>
26 
27 
~hebString()28 hebString::~hebString()
29 {
30     // discard old representation 18/4/97 (to handle memory leakage)
31     for (int j=0; j < last_representation.get_size() ; j++)
32          delete last_representation[j] ;
33 
34     last_representation.clear() ;
35 }
36 
37 //void
38 //hebString::printLocations()
39 //{
40 //   for (int i =0 ; i<last_representation.get_size() ;i++) {
41 //      Locations *locs = last_representation[i]->getLocations() ;
42 //      locs->print() ;
43 //   }
44 //}
45 
46 int
line_count(int line_length)47 hebString::line_count(int line_length)
48 {
49   if (line_length != last_line_length) modified = 1 ;
50 
51   check_recompile(line_length) ;
52 
53   return last_representation.get_size() ;
54 }
55 
56 char *
represent(int line_length,int line_offset)57 hebString::represent(int line_length, int line_offset)
58 {
59     if (line_offset >= line_count(line_length)) // also recompiles if needed
60       return (char *)0 ;
61 
62     return (char *)(const char *)(*last_representation[line_offset]) ;
63 }
64 
65 
check_recompile(int line_width,int line_offset)66 void hebString::check_recompile(int line_width, int line_offset)
67 {
68     if (!modified) return ;
69     int margin = 0 , from=0, len = 0 , comment = -1 ;
70 
71     const char *txt = (const char *)(aString &)(*this) ;
72     if (*txt)
73         if (txt[strlen(txt)-1] != ' ')
74                (aString &)(*this) += " " ;
75 
76     // added this 19/04/97
77      if (line_offset > 0) line_offset-- ;
78 
79     if (line_offset > 0) {
80        margin = last_representation[line_offset-1]->getMargin() ;
81        comment = last_representation[line_offset-1]->getComment() ;
82        from = last_representation[line_offset-1]->getMaxLocation() ;
83     }
84     modeStack stack ;
85     stack.copy(last_representation[line_offset]->getLastModeStack()) ;
86     int count = 0 ;
87     do {
88        recompile_line(line_offset, line_width, from, margin, comment, stack) ;
89        hebSegment *seg = last_representation[line_offset++] ;
90        len = seg->length() ;
91        margin = seg->getMargin() ;
92        comment = seg->getComment() ;
93        from=seg->getMaxLocation() ;
94        count++ ;
95        //assert(count == 1) ;
96     } while ((line_offset < last_representation.get_size()) );// &&
97 //                    !last_representation[line_offset]->noNeedToRecompile(from,margin, line_width, stack)) ;
98     // NOTICE THAT LINES MAY BE DELETED FROM last_representation UPON DELETING CHARACTERS FROM
99     // THE STRING
100     // in case new lines were added
101     if (line_offset >= last_representation.get_size()) {
102         const char *text = (const char *)(aString &)(*this) ;
103         hebStringMode mode = stack.majorMode() ;
104         int len = ((aString *)this)->length() ;
105         int length = 0 ;
106         int count = last_representation.get_size() ;
107         if (count > 0)
108             length = last_representation[count-1]->getMaxLocation() ;
109            while (length < len) {
110               hebSegment *segment = new
111                    hebSegment(he, text, length, startHebrew,   screen, margin, comment, line_width, stack, show_line_end_marks, activeSpelling) ;
112               length += segment->length() ;
113               margin = segment->getMargin() ;
114               comment = segment->getComment() ;
115               last_representation.append(segment) ;
116               if (segment->getModeChanged())
117                    mode = segment->getModeChange() ;
118          }
119         if (mode != stack.majorMode()) { // Major mode was changed here
120             stack.clear() ;
121             stack.push(mode, "", 0) ;
122         }
123         last_stack_depth = stack.depth() ;
124     }
125     modified = 0 ;
126     last_line_length=  line_width ;
127     last_str_mode = stack.majorMode() ;
128 }
129 
130 
recompile_line(int line,int line_width,int from,int margin,int comment,modeStack & stack)131 void hebString::recompile_line(int line, int line_width, int from, int margin, int comment, modeStack& stack)
132 {
133     const char *txt = (const char *)(aString &)(*this) ;
134     if (*txt)
135         if (txt[strlen(txt)-1] != ' ')
136                (aString &)(*this) += " " ;
137     const char *text = (const char *)(aString &)(*this) ;
138 //    int len = ((aString *)this)->length() ;
139     hebSegment *seg = last_representation[line] ;
140     int length = from ;
141     delete seg ;
142     hebSegment *segment = new
143              hebSegment(he, text, length, startHebrew,   screen, margin, comment, line_width, stack,
144                         show_line_end_marks, activeSpelling) ;
145     last_representation[line] = segment ;
146 }
147 
148 
149 
recompile(int line_width,modeStack & activeStack)150 void hebString::recompile(int line_width, modeStack &activeStack)
151 {
152     const char *txt = (const char *)(aString &)(*this) ;
153 
154     // use compiled flag to note that the stack is valid
155     compiled = 1 ;
156 
157     if (*txt)
158         if (txt[strlen(txt)-1] != ' ')
159                (aString &)(*this) += " " ;
160     const char *text = (const char *)(aString &)(*this) ;
161     int len = ((aString *)this)->length() ;
162     int length = 0 ;
163     last_mode_stack.copy(activeStack) ;
164     hebStringMode mode = activeStack.majorMode() ;
165     int margin = 0, comment = -1 ;
166 
167     // discard old representation 18/4/97 (to handle memory leakage)
168     for (int j=0; j < last_representation.get_size() ; j++)
169          delete last_representation[j] ;
170 
171     last_representation.clear() ;
172     // handle the special case where a line is empty!
173     if (len == 0) {
174         hebSegment *segment = new
175              hebSegment(he, " ", length, startHebrew,   screen, margin, comment, line_width,
176                         activeStack, show_line_end_marks,activeSpelling) ;
177         length += segment->length() ;
178         margin = segment->getMargin() ;
179         comment = segment->getComment() ;
180         last_representation.append(segment) ;
181         if (segment->getModeChanged())
182            mode = segment->getModeChange() ;
183      }
184     while (length < len) {
185         hebSegment *segment = new
186              hebSegment(he, text, length, startHebrew,   screen, margin, comment, line_width,
187                         activeStack, show_line_end_marks,activeSpelling) ;
188         length += segment->length() ;
189         margin = segment->getMargin() ;
190         comment = segment->getComment() ;
191         last_representation.append(segment) ;
192         if (segment->getModeChanged())
193            mode = segment->getModeChange() ;
194     }
195     if (mode != activeStack.majorMode()) { // Major mode was changed here
196         activeStack.clear() ;
197         activeStack.push(mode, "", 0) ;
198     }
199     modified = 0 ;
200     last_line_length=  line_width ;
201     last_str_mode = activeStack.majorMode() ;
202     last_stack_depth = activeStack.depth() ;
203 }
204 
205 
respell(int line_width,modeStack & activeStack)206 void hebString::respell(int line_width, modeStack &activeStack)
207 {
208     const char *txt = (const char *)(aString &)(*this) ;
209 
210     // use compiled flag to note that the stack is valid
211     compiled = 1 ;
212 
213     if (*txt)
214         if (txt[strlen(txt)-1] != ' ')
215                (aString &)(*this) += " " ;
216     const char *text = (const char *)(aString &)(*this) ;
217     int len = ((aString *)this)->length() ;
218     int length = 0 ;
219     last_mode_stack.copy(activeStack) ;
220     hebStringMode mode = activeStack.majorMode() ;
221     int margin = 0, comment = -1 ;
222 
223     // discard old representation 18/4/97 (to handle memory leakage)
224     int need_to_recompile = 0 ;
225 
226     for (int j=0; j < last_representation.get_size() ; j++)
227          need_to_recompile += last_representation[j]->getWrongSpelling() ;
228 
229     if (!need_to_recompile)
230             return ;
231 
232     for (int j=0; j < last_representation.get_size() ; j++)
233          delete last_representation[j] ;
234 
235     last_representation.clear() ;
236     // handle the special case where a line is empty!
237     if (len == 0) {
238         hebSegment *segment = new
239              hebSegment(he, " ", length, startHebrew,   screen, margin, comment, line_width,
240                         activeStack, show_line_end_marks,activeSpelling) ;
241         length += segment->length() ;
242         margin = segment->getMargin() ;
243         comment = segment->getComment() ;
244         last_representation.append(segment) ;
245         if (segment->getModeChanged())
246            mode = segment->getModeChange() ;
247      }
248     while (length < len) {
249         hebSegment *segment = new
250              hebSegment(he, text, length, startHebrew,   screen, margin, comment, line_width,
251                         activeStack, show_line_end_marks,activeSpelling) ;
252         length += segment->length() ;
253         margin = segment->getMargin() ;
254         comment = segment->getComment() ;
255         last_representation.append(segment) ;
256         if (segment->getModeChanged())
257            mode = segment->getModeChange() ;
258     }
259     if (mode != activeStack.majorMode()) { // Major mode was changed here
260         activeStack.clear() ;
261         activeStack.push(mode, "", 0) ;
262     }
263     modified = 0 ;
264     last_line_length=  line_width ;
265     last_str_mode = activeStack.majorMode() ;
266     last_stack_depth = activeStack.depth() ;
267 }
268 
269 int
getCurrentXlocation(int line_offset,int x_pos)270 hebString::getCurrentXlocation(int line_offset, int x_pos)
271 {
272     if (line_offset >= last_representation.get_size())
273        return SPLIT_VALUE ; // just a safety guard
274     if (line_offset < 0)
275        return SPLIT_VALUE ;
276     if (x_pos < 0) return SPLIT_VALUE ;
277 
278     Locations *locs = last_representation[line_offset]->getLocations() ;
279 
280     int pos = (*locs)[ x_pos] ;
281     if (pos > 0)
282        return pos ;
283     return -pos ;
284 }
285 
286 int
getCurrentXcode(int line_offset,int x_pos)287 hebString::getCurrentXcode(int line_offset, int x_pos)
288 {
289     if (line_offset >= last_representation.get_size())
290        return SPLIT_VALUE ; // just a safety guard
291     if (line_offset < 0)
292        return SPLIT_VALUE ;
293     if (x_pos < 0) return SPLIT_VALUE ;
294 
295     Locations *locs = last_representation[line_offset]->getLocations() ;
296 
297     return (*locs)[x_pos].getCode() ;
298 }
299 
300 hebStringMode
getCurrentXlang(int line_offset,int x_pos)301 hebString::getCurrentXlang(int line_offset, int x_pos)
302 {
303     if (line_offset >= last_representation.get_size())
304        return StrEnglish ; // just a safety guard
305     if (line_offset < 0)
306        return StrEnglish ;
307     if (x_pos < 0) return StrEnglish ;
308 
309     Locations *locs = last_representation[line_offset]->getLocations() ;
310 
311     int pos = (*locs)[x_pos] ;
312     if (pos > 0)
313        return StrEnglish ;
314     return StrHebrew ;
315 }
316 
317 /*
318 void
319 hebString::delete_ch(int at,int line_length)
320 {
321    Array<int> locations ;
322    aString tmp = (const char *)(aString &)(*this) ;
323    int count = line_count(line_length) ;
324 
325    tmp += replicate(' ',count*line_length - length()) ;
326    calculate_locations(tmp, locations) ;
327    if ((at >=0) && (at < locations.get_size()))
328      _delete_ch(locations[at]) ;
329    locations.clear() ;
330 }
331 */
332 void
_delete_ch(int at,int line_offset)333 hebString::_delete_ch(int at, int line_offset)
334 {
335    modified = 1 ;
336    aString &tmp = (aString &)(*this) ;
337 //   aString tmp2 = "" ;
338    at-- ; // assume at > 0
339 
340    if (at >= tmp.length())
341      return ;
342 
343 //   if (at > 0)
344 //     tmp2 = tmp.at(0,at) ;
345 
346 //   tmp2 += at+1+(const char *)tmp ;
347 //   tmp = tmp2 ;
348    tmp.delete_ch(at) ;
349    for (int i=line_offset+1; i < last_representation.get_size() ; i++)
350         last_representation[i]->updateMinLocation(-1) ;
351              // decrease by one because we deleted a character
352    check_recompile(last_line_length, line_offset) ;
353 }
354 
355 
356 int
_insert_ch(int at,int line_offset,unsigned char ch,int x_pos)357 hebString::_insert_ch(int at, int line_offset, unsigned char ch, int x_pos)
358 {
359    modified = 1 ;
360    aString &tmp = (aString &)(*this) ;
361 //   char before = ' ';
362 //   char before2 = ' ' ;
363    at-- ; // asume at > 0
364 
365    int move = 1 ;
366 
367    if (at > tmp.length()) {
368      tmp += ch ;
369      check_recompile(last_line_length, line_offset) ;
370      return  move;
371    }
372 
373 //   if (at > 0) {
374 //     tmp2 = tmp.at(0,at) ;
375 //     before = *((const char *)tmp+at-1) ;
376 //     if (at > 1) before2 = *((const char *)tmp + at - 2) ;
377 //   }
378 //   if (((ch == '}') || (ch == '{')) && (before != '\\')) {
379 //      if (((before == 'R') || (before == 'L')) && (before2 == '\\'))
380 //           tmp2 += "{" ;
381 //      else tmp2 += ch ; }
382 //   tmp2+=ch ;
383 
384 //   tmp2 += at+(const char *)tmp ;
385    tmp.insert_ch(at,ch) ;
386    for (int i=line_offset+1; i < last_representation.get_size() ; i++)
387         last_representation[i]->updateMinLocation(1) ; // increase by one because we inserted a character
388 // returned the following command
389    check_recompile(last_line_length, line_offset) ;
390    return move ;
391 }
392 /*
393 void
394 hebString::insert_ch(int at, unsigned char ch)
395 {
396 }
397 
398 void
399 hebString::_replace_ch(int at, unsigned char ch)
400 {
401 }
402 
403 void
404 hebString::replace_ch(int at, unsigned char ch)
405 {
406 }
407 */
408 char *
split(int at)409 hebString::split(int at)
410 {
411    modified = 1  ;
412    aString &tmp = (aString &)(*this) ;
413    aString tmp2 = "" ;
414 
415    if (at >0) at-- ; // since curx is now handled from 1 and above
416    if (at > tmp.length())
417      return 0;
418 
419    if (at > 0)
420      tmp2 = tmp.at(0,at) ;
421 
422    work_area = at+(const char *)tmp ;
423    tmp = tmp2 ;
424 
425    return (char *)(const char *)work_area ;
426 }
427 
428