1 /******************************************************************************
2 *******************************************************************************
3 *******************************************************************************
4 
5     Copyright (C) 2013 Ben Martin
6     Copyright 2014-2015, the FontForge Project Developers.
7 
8     This file is part of FontForge.
9 
10     FontForge is free software: you can redistribute it and/or modify
11     it under the terms of the GNU General Public License as published by
12     the Free Software Foundation,either version 3 of the License, or
13     (at your option) any later version.
14 
15     FontForge is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
19 
20     You should have received a copy of the GNU General Public License
21     along with FontForge.  If not, see <http://www.gnu.org/licenses/>.
22 
23     For more details see the COPYING.gplv3 file in the root directory of this
24     distribution.
25 
26 *******************************************************************************
27 *******************************************************************************
28 ******************************************************************************/
29 
30 #include <fontforge-config.h>
31 
32 #include "fvfonts.h"
33 #include "ggadget.h"
34 #include "gwidget.h"
35 #include "uiinterface.h"
36 #include "ustring.h"
37 #include "wordlistparser.h"
38 
39 #include <ctype.h>
40 #include <string.h>
41 
dump_ustr(char * msg,unichar_t * u)42 static void dump_ustr( char* msg, unichar_t* u )
43 {
44     char u8buf[1001];
45     char* pt = u8buf;
46     memset( u8buf, 0, 1000 );
47     printf("%s\n", msg );
48     unichar_t* p = u;
49     unichar_t* e = u + u_strlen( u );
50     for( ; p!=e; ++p )
51     {
52 	unichar_t buf[5];
53 	buf[0] = *p;
54 	buf[1] = '\0';
55 	printf("walk %d %s\n", *p, u_to_c(buf));
56 
57 	pt = utf8_idpb( pt, *p, 0);
58     }
59     printf("%s u8str:%s\n", msg, u8buf );
60 }
61 
62 
Wordlist_getSCName(SplineChar * sc)63 const char* Wordlist_getSCName( SplineChar* sc )
64 {
65     /* printf("Wordlist_getSCName() sc->name:%s\n", sc->name ); */
66     /* printf("Wordlist_getSCName() sc->len :%zd\n", strlen(sc->name) ); */
67     /* printf("Wordlist_getSCName() is three:%d\n", strcmp( sc->name, "three" ) ); */
68 
69     static char ret[ 1024 ];
70     int simple = false;
71     /* If the glyph is unencoded, we need to keep a slash before the name because
72        it doesn't correspond to the codepoint. */
73     if( sc->unicodeenc != -1 ) {
74     if( strlen( sc->name ) == 1 )
75     {
76         char ch = sc->name[0];
77 
78         if( ch >= 'a' && ch <= 'z' )
79             simple = true;
80         else if( ch >= '0' && ch <= '9' )
81             simple = true;
82         if( ch >= 'A' && ch <= 'Z' )
83             simple = true;
84 
85         if( simple )
86         {
87             strcpy( ret, sc->name );
88             return ret;
89         }
90     }
91 
92     if( !strcmp( sc->name, "zero" ))
93         return "0";
94     if( !strcmp( sc->name, "one" ))
95         return "1";
96     if( !strcmp( sc->name, "two" ))
97         return "2";
98     if( !strcmp( sc->name, "three" ))
99         return "3";
100     if( !strcmp( sc->name, "four" ))
101         return "4";
102     if( !strcmp( sc->name, "five" ))
103         return "5";
104     if( !strcmp( sc->name, "six" ))
105         return "6";
106     if( !strcmp( sc->name, "seven" ))
107         return "7";
108     if( !strcmp( sc->name, "eight" ))
109         return "8";
110     if( !strcmp( sc->name, "nine" ))
111         return "9";
112     }
113 
114     snprintf( ret, 1024, "/%s", sc->name );
115     return ret;
116 }
117 
118 
119 
120 static SplineChar*
WordlistEscapedInputStringToRealString_readGlyphName(SplineFont * sf,char * in,char * in_end,char ** updated_in,char * glyphname)121 WordlistEscapedInputStringToRealString_readGlyphName(
122     SplineFont *sf, char* in, char* in_end,
123     char** updated_in, char* glyphname )
124 {
125 //    printf("WordlistEscapedInputStringToRealString_readGlyphName(top)\n");
126 
127     int startedWithBackSlash = (*in == '\\');
128     if( *in != '/' && *in != '\\' )
129 	return 0;
130     // move over the delimiter that we know we are on
131     in++;
132     char* startpos = in;
133 
134     // Get the largest possible 'glyphname' from the input stream.
135     memset( glyphname, '\0', PATH_MAX );
136     char* outname = glyphname;
137     while( *in != '/' && *in != ' ' && *in != ']' && in != in_end )
138     {
139 	*outname = *in;
140 	++outname;
141 	in++;
142     }
143     bool FullMatchEndsOnSpace = 0;
144     char* maxpos = in;
145     char* endpos = maxpos-1;
146 //    printf("WordlistEscapedInputStringToRealString_readGlyphName(x1) -->:%s:<--\n", glyphname);
147 //    printf("WordlistEscapedInputStringToRealString_readGlyphName(x2) %c %p %p\n",*in,startpos,endpos);
148 
149     int loopCounter = 0;
150     int firstLookup = 1;
151     for( ; endpos >= startpos; endpos--, loopCounter++ )
152     {
153 //	printf("WordlistEscapedInputStringToRealString_readGlyphName(trim loop top) gn:%s\n", glyphname );
154 	SplineChar* sc = 0;
155 	if( startedWithBackSlash )
156 	{
157 	    if( glyphname[0] == 'u' )
158 		glyphname++;
159 
160 	    char* endptr = 0;
161 	    long unicodepoint = strtoul( glyphname+1, &endptr, 16 );
162 	    TRACE("AAA glyphname:%s\n", glyphname+1 );
163 	    TRACE("AAA unicodepoint:%ld\n", unicodepoint );
164 	    sc = SFGetChar( sf, unicodepoint, 0 );
165 	    if( sc && endptr )
166 	    {
167 		char* endofglyphname = glyphname + strlen(glyphname);
168 		for( ; endptr < endofglyphname; endptr++ )
169 		    --endpos;
170 	    }
171 	    if( !sc )
172 	    {
173 //		printf("WordlistEscapedInputStringToRealString_readGlyphName() no char found for backslashed unicodepoint:%ld\n", unicodepoint );
174 		strcpy(glyphname,"backslash");
175 		sc = SFGetChar( sf, -1, glyphname );
176 		endpos = startpos;
177 	    }
178 	}
179 	else
180 	{
181 	    if( firstLookup && glyphname[0] == '#' )
182 	    {
183 		char* endptr = 0;
184 		long unicodepoint = strtoul( glyphname+1, &endptr, 16 );
185 //		printf("WordlistEscapedInputStringToRealString_readGlyphName() unicodepoint:%ld\n", unicodepoint );
186 		sc = SFGetChar( sf, unicodepoint, 0 );
187 		if( sc && endptr )
188 		{
189 		    char* endofglyphname = glyphname + strlen(glyphname);
190 //		    printf("endptr:%p endofglyphname:%p\n", endptr, endofglyphname );
191 		    for( ; endptr < endofglyphname; endptr++ )
192 			--endpos;
193 		}
194 	    }
195 	    if( !sc )
196 	    {
197 //		printf("WordlistEscapedInputStringToRealString_readGlyphName(getchar) gn:%s\n", glyphname );
198 		sc = SFGetChar( sf, -1, glyphname );
199 	    }
200 	}
201 
202 	if( sc )
203 	{
204 //	    printf("WordlistEscapedInputStringToRealString_readGlyphName(found!) gn:%s start:%p end:%p\n", glyphname, startpos, endpos );
205 	    if( !loopCounter && FullMatchEndsOnSpace )
206 	    {
207 		endpos++;
208 	    }
209 	    *updated_in = endpos;
210 	    return sc;
211 	}
212 	if( glyphname[0] != '\0' )
213 	    glyphname[ strlen(glyphname)-1 ] = '\0';
214     }
215 
216 
217     *updated_in = endpos;
218 
219     // printf("WordlistEscapedInputStringToRealString_readGlyphName(end) gn:%s\n", glyphname );
220     return 0;
221 }
222 
223 
224 static SplineChar*
u_WordlistEscapedInputStringToRealString_readGlyphName(SplineFont * sf,unichar_t * in,unichar_t * in_end,unichar_t ** updated_in,unichar_t * glyphname)225 u_WordlistEscapedInputStringToRealString_readGlyphName(
226     SplineFont *sf, unichar_t* in, unichar_t* in_end,
227     unichar_t** updated_in, unichar_t* glyphname )
228 {
229     int startedWithBackSlash = (*in == '\\');
230     if( *in != '/' && *in != '\\' )
231 	return 0;
232     bool startsWithBackSlash = *in == '\\';
233     // move over the delimiter that we know we are on
234     in++;
235     unichar_t* startpos = in;
236 
237     // Get the largest possible 'glyphname' from the input stream.
238     memset( glyphname, '\0', PATH_MAX );
239     unichar_t* outname = glyphname;
240     while( *in != '/'
241 	   && ( !startsWithBackSlash || *in != '\\' )
242 	   && *in != ' ' && *in != ']' && in != in_end )
243     {
244 	*outname = *in;
245 	++outname;
246 	in++;
247     }
248     bool FullMatchEndsOnSpace = 0;
249     unichar_t* maxpos = in;
250     unichar_t* endpos = maxpos-1;
251     TRACE("WordlistEscapedInputStringToRealString_readGlyphName(x1) -->:%s:<--\n", u_to_c(glyphname));
252 
253     int loopCounter = 0;
254     int firstLookup = 1;
255     for( ; endpos >= startpos; endpos--, loopCounter++ )
256     {
257 //	printf("WordlistEscapedInputStringToRealString_readGlyphName(trim loop top) gn:%s\n", u_to_c(glyphname) );
258 	SplineChar* sc = 0;
259 
260 	if( startedWithBackSlash )
261 	{
262 	    if( glyphname[0] == 'u' )
263 		glyphname++;
264 
265 	    unichar_t* endptr = 0;
266 	    long unicodepoint = u_strtoul( glyphname+1, &endptr, 16 );
267 	    TRACE("AAA glyphname:%s\n", u_to_c(glyphname+1) );
268 	    TRACE("AAA unicodepoint:%ld\n", unicodepoint );
269 	    sc = SFGetChar( sf, unicodepoint, 0 );
270 	    if( sc && endptr )
271 	    {
272 		unichar_t* endofglyphname = glyphname + u_strlen(glyphname);
273 		/* printf("glyphname:%p\n", glyphname ); */
274 		/* printf("endptr:%p endofglyphname:%p\n", endptr, endofglyphname ); */
275 		for( ; endptr < endofglyphname; endptr++ )
276 		    --endpos;
277 	    }
278 	    if( !sc )
279 	    {
280 //		printf("WordlistEscapedInputStringToRealString_readGlyphName() no char found for backslashed unicodepoint:%ld\n", unicodepoint );
281 		uc_strcpy(glyphname,"backslash");
282 		sc = SFGetChar( sf, -1, u_to_c(glyphname) );
283 		endpos = startpos;
284 	    }
285 	}
286 	else
287 	{
288 	    if( uc_startswith( glyphname, "uni"))
289 	    {
290 		unichar_t* endptr = 0, *tmp_gn;
291 		int gn_len;
292 		long unicodepoint = u_strtoul( glyphname+3, &endptr, 16 );
293 		char c;
294 		SplineChar* tmp = 0;
295 		TRACE("uni prefix, codepoint: %ld\n", unicodepoint );
296 		sc = SFGetChar( sf, unicodepoint, 0 );
297 
298 		/* When text is added after a glyphname with a period (such as "uni1234.alt"
299 		 * the other search heuristics will tend to interpret the period as a glyph
300 		 * and split the string. Here we search for the glyphname trimming off
301 		 * characters at the end in order to find the glyph
302 		 */
303 		gn_len = u_strlen(glyphname);
304 		tmp_gn = malloc((gn_len+1)*sizeof(unichar_t));
305 		u_strncpy(tmp_gn, glyphname, gn_len);
306 		for (int i = gn_len; i>0; i--) {
307 		    tmp_gn[i] = 0;
308 		    tmp = SFGetChar( sf, -1, u_to_c(tmp_gn) );
309 		    TRACE("looking for subst. char: %s\n", u_to_c(tmp_gn));
310 		    if (tmp != NULL) {
311 			TRACE("have subst. char: %s\n", tmp->name ); break;
312 		    }
313 		}
314 		free(tmp_gn);
315 
316 		if (tmp != NULL){
317 		    sc = tmp;
318 		} else {
319 		    if( sc && endptr )
320 		    {
321 		        unichar_t* endofglyphname = glyphname + u_strlen(glyphname);
322 		        //printf("endptr:%p endofglyphname:%p\n", endptr, endofglyphname );
323 		        for( ; endptr < endofglyphname; endptr++ ) --endpos;
324 		    }
325 		}
326 		}
327 
328 		if( firstLookup && glyphname[0] == '#' )
329 		{
330 		unichar_t* endptr = 0;
331 		long unicodepoint = u_strtoul( glyphname+1, &endptr, 16 );
332 //		printf("WordlistEscapedInputStringToRealString_readGlyphName() unicodepoint:%ld\n", unicodepoint );
333 		sc = SFGetChar( sf, unicodepoint, 0 );
334 		if( sc && endptr )
335 		{
336 		    unichar_t* endofglyphname = glyphname + u_strlen(glyphname);
337 //		    printf("endptr:%p endofglyphname:%p\n", endptr, endofglyphname );
338 		    for( ; endptr < endofglyphname; endptr++ )
339 			--endpos;
340 		}
341 	    }
342 	    if( !sc )
343 	    {
344 //		printf("WordlistEscapedInputStringToRealString_readGlyphName(getchar) gn:%s\n", glyphname );
345 		sc = SFGetChar( sf, -1, u_to_c(glyphname) );
346 	    }
347 	}
348 
349 	if( sc )
350 	{
351 //	    printf("WordlistEscapedInputStringToRealString_readGlyphName(found!) gn:%s start:%p end:%p\n", glyphname, startpos, endpos );
352 	    if( !loopCounter && FullMatchEndsOnSpace )
353 	    {
354 		endpos++;
355 	    }
356 	    *updated_in = endpos;
357 	    return sc;
358 	}
359 	if( glyphname[0] != '\0' )
360 	    glyphname[ u_strlen(glyphname)-1 ] = '\0';
361     }
362 
363 
364     *updated_in = endpos;
365 
366     // printf("WordlistEscapedInputStringToRealString_readGlyphName(end) gn:%s\n", glyphname );
367     return 0;
368 }
369 
370 
WordlistEscapedInputStringToRealString_getFakeUnicodeAsScUnicodeEnc(SplineChar * sc,void * udata)371 int WordlistEscapedInputStringToRealString_getFakeUnicodeAsScUnicodeEnc( SplineChar *sc, void* udata )
372 {
373     return( sc->unicodeenc );
374 }
375 
376 
377 //
378 // If there is only one trailing slash, then remove it.
379 //
WordlistTrimTrailingSingleSlash(unichar_t * txt)380 void WordlistTrimTrailingSingleSlash( unichar_t* txt )
381 {
382     int len = u_strlen(txt);
383 //    printf("text changed, len :%d -1:%c -2:%c\n", len, txt[ len-1 ], txt[ len-2 ]  );
384     if( len >= 1 )
385     {
386 	if( len >= 2 && txt[ len-1 ]=='/' && txt[ len-2 ]=='/' )
387 	{
388 	    // nothing
389 	}
390 	else
391 	{
392 	    if( txt[ len-1 ]=='/' )
393 		txt[ len-1 ] = '\0';
394 	}
395     }
396 }
397 
398 
399 
400 /************************************************************/
401 /************************************************************/
402 /************************************************************/
403 
WordListLine_countSelected(WordListLine wll)404 int WordListLine_countSelected( WordListLine wll )
405 {
406     int ret = 0;
407     for( ; wll->sc; wll++ ) {
408 	ret += wll->isSelected;
409     }
410     return ret;
411 }
412 
WordListLine_end(WordListLine wll)413 WordListLine WordListLine_end( WordListLine wll )
414 {
415     for( ; wll->sc; wll++ ) {
416     }
417     return wll;
418 }
419 
WordListLine_size(WordListLine wll)420 int WordListLine_size( WordListLine wll )
421 {
422     int ret = 0;
423     for( ; wll->sc; wll++ ) {
424 	++ret;
425     }
426     return ret;
427 }
428 
429 
WordlistEscapedInputStringToParsedDataComplex(SplineFont * sf,const unichar_t * input_const,WordlistEscapedInputStringToRealString_getFakeUnicodeOfScFunc getUnicodeFunc,void * udata)430 WordListLine WordlistEscapedInputStringToParsedDataComplex(
431     SplineFont* sf,
432     const unichar_t* input_const,
433     WordlistEscapedInputStringToRealString_getFakeUnicodeOfScFunc getUnicodeFunc,
434     void* udata )
435 {
436     unichar_t* input = u_copy( input_const );
437     int input_len = u_strlen(input);
438     WordListChar* ret = calloc( input_len+1, sizeof(WordListChar));
439     WordListChar* out = ret;
440     unichar_t* in     = input;
441     unichar_t* in_end = input + input_len;
442     // trim comment and beyond from input
443     {
444 	unichar_t* p = input;
445 	while( p && p < in_end  )
446 	{
447 	    p = u_strchr( p, '#' );
448 	    if( p > input && *(p-1) == '/' )
449 	    {
450 		p++;
451 		continue;
452 	    }
453 	    if( p )
454 		*p = '\0';
455 	    break;
456 	}
457     }
458     in_end = input + u_strlen(input);
459 
460     int addingGlyphsToSelected = 0;
461     int currentGlyphIndex = -1;
462     for ( ; in < in_end; in++ )
463     {
464 	unichar_t ch = *in;
465 	TRACE("in:%p end:%p got char %d %c\n", in, in_end, ch, ch );
466 	if( ch == '[' )
467 	{
468 	    addingGlyphsToSelected = 1;
469 	    continue;
470 	}
471 	if( ch == ']' )
472 	{
473 	    addingGlyphsToSelected = 0;
474 	    continue;
475 	}
476 	int isSelected = addingGlyphsToSelected;
477 	currentGlyphIndex++;
478 
479 	if( ch == '/' || ch == '\\' )
480 	{
481 	    // start of a glyph name
482 	    unichar_t glyphname[ PATH_MAX+1 ];
483 	    unichar_t* updated_in = 0;
484 	    SplineChar* sc = u_WordlistEscapedInputStringToRealString_readGlyphName( sf, in, in_end, &updated_in, glyphname );
485 	    if( sc )
486 	    {
487 		in = updated_in;
488 		int n = getUnicodeFunc( sc, udata );
489 		if( n == -1 )
490 		{
491 		    /*
492 		     * Okay, this probably means we've got an unencoded glyph (generally
493 		     * used for OpenType substitutions).
494 		     * Redeem the value from the SplineFont datamap instead of fetching from
495 		     * the Unicode identifier.
496 		     */
497 		    n = sf->map->backmap[sc->orig_pos];
498 
499 		    /*
500 		     * Unencoded glyphs have special mappings in the SplineFont that
501 		     * start from 65536 (values beyond Unicode, 65535 being the reserved
502 		     * "frontier" value).
503 		     */
504 		    if ( (sf->map->enc->is_unicodebmp || sf->map->enc->is_unicodefull) && n < 65536 ) {
505 		        TRACE("ToRealString: backmapped position does not match Unicode encoding\n");
506 		        TRACE("orig_pos: %d, backmap: %d, attached unicode enc: %d\n", sc->orig_pos, n, sc->unicodeenc );
507 		        TRACE("ToRealString: INVALID CHAR POSITION, name: %s\n", sc->name );
508 		    }
509 		}
510 
511 		out->sc = sc;
512 		out->isSelected = isSelected;
513 		out->currentGlyphIndex = currentGlyphIndex;
514                 out->n = n;
515 		out++;
516 		/* out = utf8_idpb( out, n, 0 ); */
517 		/* if( !out ) */
518 		/*     printf("ToRealString error on out\n"); */
519 		continue;
520 	    }
521 	}
522 
523 	/* If we reach this point, we're looking based on codepoint. */
524 	SplineChar* sc = SFGetOrMakeChar( sf, (int)ch, 0 );
525 	out->sc = sc;
526 	out->isSelected = isSelected;
527 	out->currentGlyphIndex = currentGlyphIndex;
528 	out++;
529     }
530 
531     free(input);
532     return(ret);
533 }
534 
WordlistEscapedInputStringToParsedData(SplineFont * sf,unichar_t * input_const)535 WordListLine WordlistEscapedInputStringToParsedData(
536     SplineFont* sf,
537     unichar_t* input_const )
538 {
539     WordListLine ret = WordlistEscapedInputStringToParsedDataComplex(
540 	sf, input_const,
541 	WordlistEscapedInputStringToRealString_getFakeUnicodeAsScUnicodeEnc, 0 );
542     return ret;
543 }
544 
545 
546 
547 
548 /************************************************************/
549 /************************************************************/
550 /************************************************************/
551 
WordlistLoadFileToGTextInfo_IsLineBreak(char ch)552 static bool WordlistLoadFileToGTextInfo_IsLineBreak( char ch )
553 {
554     return ch == '\n' || ch == '\r';
555 }
WordlistLoadFileToGTextInfo_isLineAllWhiteSpace(char * buffer)556 static bool WordlistLoadFileToGTextInfo_isLineAllWhiteSpace( char* buffer )
557 {
558     char* p = buffer;
559     for( ; *p; ++p )
560     {
561 	if( !isspace( *p ))
562 	    return false;
563     }
564 
565     return true;
566 }
567 
568 
569 
WordlistLoadFileToGTextInfoBasic(int words_max)570 GTextInfo** WordlistLoadFileToGTextInfoBasic( int words_max )
571 {
572     return WordlistLoadFileToGTextInfo( -1, words_max );
573 }
574 
575 
WordlistLoadFileToGTextInfo(int type,int words_max)576 GTextInfo** WordlistLoadFileToGTextInfo( int type, int words_max )
577 {
578     GTextInfo **words = 0;
579     int cnt;
580     char buffer[PATH_MAX];
581     char *filename, *temp;
582 
583     filename = gwwv_open_filename(type==-1 ? "File of Kerning Words":"File of glyphname lists",NULL,"*.txt",NULL);
584     if ( !filename )
585     {
586 	return 0;
587     }
588     temp = utf82def_copy(filename);
589     GIOChannel* file = g_io_channel_new_file( temp, "r", 0 );
590     free(temp);
591     if ( !file )
592     {
593 	ff_post_error("Could not open", "Could not open %s", filename );
594 	return 0;
595     }
596     free(filename);
597 
598     words = malloc( words_max * sizeof(GTextInfo *));
599 
600     cnt = 0;
601     if ( type==-1 )
602     {
603 	// Kerning words
604 	while( true )
605 	{
606 	    gsize len = 0;
607 	    gchar* buffer = 0;
608 	    GIOStatus status = g_io_channel_read_line( file, &buffer, &len, 0, 0 );
609 
610 //	    printf("getline status:%d \n", status );
611 	    if( status != G_IO_STATUS_NORMAL )
612 		break;
613 
614 	    chomp(buffer);
615 	    if ( buffer[0]=='\0'
616 		 || WordlistLoadFileToGTextInfo_IsLineBreak(buffer[0])
617 		 || WordlistLoadFileToGTextInfo_isLineAllWhiteSpace( buffer ))
618 	    {
619 		free(buffer);
620 		continue;
621 	    }
622 
623 	    words[cnt] = calloc(1,sizeof(GTextInfo));
624 	    words[cnt]->fg = words[cnt]->bg = COLOR_DEFAULT;
625 	    words[cnt]->text = (unichar_t *) utf82def_copy( buffer );
626 	    words[cnt++]->text_is_1byte = true;
627 	    free(buffer);
628 	    if( cnt >= words_max )
629 		break;
630 	}
631     }
632     else
633     {
634 	// glyphname lists
635 	strcpy(buffer,"​");		/* Zero width space: 0x200b, I use as a flag */
636 	gsize bytes_read = 0;
637 	while( G_IO_STATUS_NORMAL == g_io_channel_read_chars( file,
638 							      buffer+3,
639 							      sizeof(buffer)-3,
640 							      &bytes_read,
641 							      0 ))
642 	{
643 	    if ( buffer[3]=='\n' || buffer[3]=='#' )
644 		continue;
645 	    if ( cnt>1000-3 )
646 		break;
647 	    if ( buffer[strlen(buffer)-1]=='\n' )
648 		buffer[strlen(buffer)-1] = '\0';
649 	    words[cnt] = calloc(1,sizeof(GTextInfo));
650 	    words[cnt]->fg = words[cnt]->bg = COLOR_DEFAULT;
651 	    words[cnt]->text = (unichar_t *) copy( buffer );
652 	    words[cnt++]->text_is_1byte = true;
653 	}
654     }
655 
656     g_io_channel_shutdown( file, 1, 0 );
657     g_io_channel_unref( file );
658     if ( cnt!=0 )
659     {
660 	words[cnt] = calloc(1,sizeof(GTextInfo));
661 	words[cnt]->fg = words[cnt]->bg = COLOR_DEFAULT;
662 	words[cnt++]->line = true;
663 	words[cnt] = calloc(1,sizeof(GTextInfo));
664 	words[cnt]->fg = words[cnt]->bg = COLOR_DEFAULT;
665 	words[cnt]->text = (unichar_t *) copy( _("Load Word List...") );
666 	words[cnt]->text_is_1byte = true;
667 	words[cnt++]->userdata = (void *) -1;
668 	words[cnt] = calloc(1,sizeof(GTextInfo));
669 	words[cnt]->fg = words[cnt]->bg = COLOR_DEFAULT;
670 	words[cnt]->text = (unichar_t *) copy( _("Load Glyph Name List...") );
671 	words[cnt]->text_is_1byte = true;
672 	words[cnt++]->userdata = (void *) -2;
673 	words[cnt] = calloc(1,sizeof(GTextInfo));
674     }
675     else
676     {
677 	free(words);
678 	words = 0;
679     }
680     return words;
681 }
682 
683 
Wordlist_MoveByOffset(GGadget * g,int * idx,int offset)684 void Wordlist_MoveByOffset( GGadget* g, int* idx, int offset )
685 {
686     int cidx = *idx;
687     if ( cidx!=-1 )
688     {
689 	int32 len;
690 	GTextInfo **ti = GGadgetGetList(g,&len);
691 	/* We subtract 3 because: There are two lines saying "load * list" */
692 	/*  and then a line with a rule on it which we don't want access to */
693 	if ( cidx+offset >=0 && cidx+offset<len-3 )
694 	{
695 	    cidx += offset;
696 	    *idx = cidx;
697 	    GGadgetSelectOneListItem( g, cidx );
698 	    ti = NULL;
699 	}
700 	Wordlist_touch( g );
701     }
702 }
703 
Wordlist_touch(GGadget * g)704 void Wordlist_touch( GGadget* g )
705 {
706     // Force any extra chars to be setup and drawn
707     GEvent e;
708     e.type=et_controlevent;
709     e.u.control.subtype = et_textchanged;
710     e.u.control.u.tf_changed.from_pulldown = GGadgetGetFirstListSelectedItem(g);
711     GGadgetDispatchEvent( g, &e );
712 }
713 
714 
WordlistLoadToGTextInfo(GGadget * g,int * idx)715 void WordlistLoadToGTextInfo( GGadget* g, int* idx  )
716 {
717     int words_max = 1024*128;
718     GTextInfo** words = WordlistLoadFileToGTextInfoBasic( words_max );
719     if( !words )
720     {
721 	GGadgetSetTitle8(g,"");
722 	return;
723     }
724 
725     if( words[0] )
726     {
727 	GGadgetSetList(g,words,true);
728 	GGadgetSetTitle8(g,(char *) (words[0]->text));
729 	GTextInfoArrayFree(words);
730 	*idx = 0;
731 	GGadgetSelectOneListItem( g, *idx );
732 	Wordlist_touch( g );
733 	return;
734     }
735     return;
736 }
737 
738 
Wordlist_selectedToBitmapArray(GArray * a)739 static GArray* Wordlist_selectedToBitmapArray( GArray* a )
740 {
741     GArray* ret = g_array_new( 1, 1, sizeof(gint) );
742     ret = g_array_set_size( ret, PATH_MAX+1 );
743 
744     int i = 0;
745     for (i = 0; i < a->len; i++)
746     {
747         int v = g_array_index (a, gint, i);
748         int one = 1;
749         g_array_insert_val( ret, v, one );
750     }
751     return ret;
752 }
753 
754 
Wordlist_selectionClear(SplineFont * sf,EncMap * map,unichar_t * txtu)755 unichar_t* Wordlist_selectionClear( SplineFont* sf, EncMap *map, unichar_t* txtu )
756 {
757     static unichar_t ret[ PATH_MAX ];
758     int limit = PATH_MAX;
759     memset( ret, 0, sizeof(unichar_t) * PATH_MAX );
760 
761     unichar_t *dst = ret;
762     const unichar_t *src_end = 0;
763     const unichar_t *src = 0;
764     src_end=txtu+u_strlen(txtu);
765     for ( src=txtu; src < src_end; ++src )
766     {
767 	if( *src != '[' && *src != ']' )
768 	{
769 	    *dst = *src;
770 	    dst++;
771 	}
772     }
773 
774     return ret;
775 }
776 
Wordlist_selectionAdd(SplineFont * sf,EncMap * map,unichar_t * txtu,int offset)777 unichar_t* Wordlist_selectionAdd( SplineFont* sf, EncMap *map, unichar_t* txtu, int offset )
778 {
779     int i = 0;
780     static unichar_t ret[ PATH_MAX ];
781     memset( ret, 0, sizeof(unichar_t) * PATH_MAX );
782 
783     WordlistTrimTrailingSingleSlash( txtu );
784     WordListLine wll = WordlistEscapedInputStringToParsedData( sf, txtu );
785 
786     for( i = 0; wll->sc; wll++, i++ )
787     {
788 	SplineChar* sc = wll->sc;
789         int element_selected = wll->isSelected;
790 
791 	if( i == offset )
792 	    element_selected = 1;
793 
794         if( element_selected )
795         {
796             int pos = map->backmap[ sc->orig_pos ];
797             TRACE("pos1:%d\n", pos );
798             TRACE("map:%d\n", map->map[ pos ] );
799             int gid = pos < 0 || pos >= map->enccount ? -2 : map->map[pos];
800             if( gid == -2 )
801                 continue;
802             if( gid==-1 || !sf->glyphs[gid] )
803                 sc = SFMakeChar( sf, map, pos );
804             else
805                 sc = sf->glyphs[gid];
806         }
807 
808 
809         if( element_selected )
810             uc_strcat( ret, "[" );
811 
812         /* uc_strcat( ret, "/" ); */
813         /* uc_strcat( ret, scarray[i]->name ); */
814         uc_strcat( ret, Wordlist_getSCName( sc ));
815 
816         if( element_selected )
817             uc_strcat( ret, "]" );
818     }
819 
820     return ret;
821 }
822 
823 
Wordlist_advanceSelectedCharsBy(SplineFont * sf,EncMap * map,unichar_t * txtu,int offset)824 unichar_t* Wordlist_advanceSelectedCharsBy( SplineFont* sf, EncMap *map, unichar_t* txtu, int offset )
825 {
826     unichar_t original_data[ PATH_MAX ];
827     static unichar_t ret[ PATH_MAX ];
828     int i = 0;
829 
830     u_strcpy( original_data, txtu );
831     TRACE("Wordlist_advanceSelectedCharsBy(1) %s\n", u_to_c( txtu ));
832     WordlistTrimTrailingSingleSlash( txtu );
833     WordListLine wll = WordlistEscapedInputStringToParsedData( sf, txtu );
834 
835     int selectedCount = WordListLine_countSelected( wll );
836     if( !selectedCount )
837 	wll->isSelected = 1;
838 
839     memset( ret, 0, sizeof(unichar_t) * PATH_MAX );
840     for( i = 0; wll->sc; wll++, i++ )
841     {
842 	SplineChar* sc = wll->sc;
843         int element_selected = wll->isSelected;
844 
845         if( element_selected )
846         {
847             int pos = map->backmap[ sc->orig_pos ];
848             pos += offset;
849             int gid = pos < 0 || pos >= map->enccount ? -2 : map->map[pos];
850             if( gid == -2 )
851 	    {
852 		// we can't find a glyph at the desired position.
853 		// so instead of dropping it we just do not perform the operation
854 		// on this char.
855 		pos -= offset;
856 		gid = pos < 0 || pos >= map->enccount ? -2 : map->map[pos];
857 		if( gid == -2 )
858 		{
859 		    // we can't go back manually!
860 		    u_strcpy( ret, original_data );
861 		    return ret;
862 		}
863 	    }
864 	    if( gid==-1 || !sf->glyphs[gid] )
865                 sc = SFMakeChar( sf, map, pos );
866             else
867                 sc = sf->glyphs[gid];
868         }
869 
870 
871         if( element_selected )
872             uc_strcat( ret, "[" );
873 
874         /* uc_strcat( ret, "/" ); */
875         /* uc_strcat( ret, scarray[i]->name ); */
876         uc_strcat( ret, Wordlist_getSCName( sc ));
877 
878         if( element_selected )
879             uc_strcat( ret, "]" );
880     }
881 
882     return ret;
883 }
884 
885 
886 
887 /**
888  * haveSelection is set to true iff there is 1+ selections i txtu
889  */
Wordlist_selectionStringOnly(unichar_t * txtu,int * haveSelection)890 static unichar_t* Wordlist_selectionStringOnly( unichar_t* txtu, int* haveSelection )
891 {
892     static unichar_t ret[ PATH_MAX ];
893     int limit = PATH_MAX;
894     memset( ret, 0, sizeof(unichar_t) * PATH_MAX );
895     *haveSelection = 0;
896 
897     int inSelection = 0;
898     unichar_t *dst = ret;
899     const unichar_t *src_end = 0;
900     const unichar_t *src = 0;
901     src_end=txtu+u_strlen(txtu);
902     for ( src=txtu; src < src_end; ++src )
903     {
904 	if( *src == '[' )
905 	{
906 	    inSelection = 1;
907 	    *haveSelection = 1;
908 	    continue;
909 	}
910 	if( *src == ']' )
911 	{
912 	    inSelection = 0;
913 	    continue;
914 	}
915 
916 	if( inSelection )
917 	{
918 	    *dst = *src;
919 	    dst++;
920 	}
921     }
922 
923     return ret;
924 }
925 
926 
Wordlist_selectionsEqual(unichar_t * s1,unichar_t * s2)927 bool Wordlist_selectionsEqual( unichar_t* s1, unichar_t* s2 )
928 {
929     static unichar_t s1stripped[ PATH_MAX ];
930     static unichar_t s2stripped[ PATH_MAX ];
931     int s1HasSelection = 0;
932     int s2HasSelection = 0;
933 
934     u_strcpy( s1stripped, Wordlist_selectionStringOnly( s1, &s1HasSelection ));
935     u_strcpy( s2stripped, Wordlist_selectionStringOnly( s2, &s2HasSelection ));
936 
937     if( s1HasSelection && !s2HasSelection )
938 	return false;
939     if( !s1HasSelection && s2HasSelection )
940 	return false;
941 
942     return !u_strcmp( s1stripped, s2stripped );
943 }
944 
945 
WordListLine_toustr(WordListLine wll)946 unichar_t* WordListLine_toustr( WordListLine wll )
947 {
948     unichar_t* ret = calloc( WordListLine_size(wll)+1, sizeof(unichar_t));
949     unichar_t* p = ret;
950     for( ; wll->sc; wll++, p++ ) {
951 	*p = wll->sc->unicodeenc;
952         if (*p == -1) *p = wll->n;
953     }
954     return ret;
955 }
956 
957 
958 
959 
960 
961