1 /*
2  *  parseMarkup.c
3  *
4  *  See the file "license.terms" for information on usage and redistribution
5  *  of this file, and for a DISCLAIMER OF ALL WARRANTIES.
6  *
7  */
8 
9 /*
10     The GtkTextBuffer has no default tags, whereas the Pango description requires
11     a conventionalized set of descriptors. In order to guareentee correct display
12     and editing of markupstrings, a protected set of markup tags need to created.
13     Following this, any markup strings to be inserted can be added with safety.
14 
15 
16 */
17 
18 
19 /*
20     History:
21 
22     2011-09  began module development
23 
24 */
25 
26 #include "gnocl.h"
27 
28 /* list to hold names of applied tags */
29 static GSList *tagList = NULL;
30 
31 
32 static void applyTags ( GtkTextBuffer *buffer, GtkTextIter *iter );
33 
34 /* remove range of characters from string */
strcremove(char * str,char * dest,int first,int last)35 char * strcremove ( char *str, char *dest, int first, int last )
36 {
37 
38 	g_print ( "%s 1 first = %d ; last = %d\n", __FUNCTION__, first, last );
39 
40 	int j = 0;
41 	char *ptr;
42 	ptr = str;
43 
44 	while ( j < strlen ( str ) )
45 	{
46 		g_print ( "j = %d\n", j );
47 
48 		if ( j >= first && j <= last )
49 		{
50 			g_print ( "remove %c\n", *str + j );
51 			//*str++;
52 		}
53 
54 		else
55 		{
56 			//*dest++ =
57 			//*ptr++;
58 		}
59 
60 		j++;
61 
62 	}
63 
64 	*dest = '/0';
65 
66 	return dest;
67 }
68 
69 
70 /* insert character in string, return new string */
strcinsert(char * str,char * dest,char * c,int i)71 char * strcinsert ( char *str, char *dest, char *c, int i )
72 {
73 
74 	//g_print ( "%s 1\n", __FUNCTION__ );
75 
76 	int j = 0;
77 
78 	while ( j < i )
79 	{
80 		*dest++ = *str++;
81 		j++;
82 	}
83 
84 	//g_print ( "%s 2\n", __FUNCTION__ );
85 
86 	*dest++ = c;
87 
88 	//g_print ( "%s 3\n", __FUNCTION__ );
89 
90 	while ( j < strlen ( str ) )
91 	{
92 		*dest++ = *str++;
93 		j++;
94 	}
95 
96 	//g_print ( "%s 4\n", __FUNCTION__ );
97 
98 	*dest = '/0';
99 
100 	//g_print ( "%s 5\n", __FUNCTION__ );
101 
102 	return dest;
103 }
104 
105 
106 /**
107 \brief  delete substring
108         http://www.timeflash.net/tutorials/cc/16-how-to-remove-a-substring-from-a-string-in-c-and-c.html
109 **/
strdstr(char * str,char * substr)110 char* strdstr ( char* str, char* substr )
111 {
112 #ifdef DEBUG_PANGO_MARKUP
113 	g_print ( "FUNC: %s\n", __FUNCTION__ );
114 #endif
115 
116 
117 	int i, j, p, match;
118 
119 	char newstr [strlen ( str ) ];
120 
121 	for ( i = 0 ; i < strlen ( str ) ; ++i )
122 	{
123 		if ( str[i] == substr[j] )
124 		{
125 			match = 1;
126 
127 			for ( j = 1; j < strlen ( substr ); ++j )
128 			{
129 				if ( str[i+j] != substr[j] )
130 				{
131 					j = 0;
132 					match = 0;
133 				}
134 			}
135 
136 			if ( match )
137 			{
138 				i += strlen ( substr ) - 1;
139 				j = 0;
140 			}
141 		}
142 
143 		else
144 		{
145 			newstr[p] = str[i];
146 			++p;
147 		}
148 	}
149 
150 	newstr[p] = '\0';
151 
152 	return newstr;
153 }
154 
155 
156 /**
157     String concatenation
158     http://rosettacode.org/wiki/String_concatenation#C
159 **/
sconcat(const char * s1,const char * s2)160 static char *sconcat ( const char *s1, const char *s2 )
161 {
162 	char *s0 = ( char * ) malloc ( strlen ( s1 ) + strlen ( s2 ) + 1 );
163 	strcpy ( s0, s1 );
164 	strcat ( s0, s2 );
165 	return s0;
166 }
167 
168 /**
169     Strip a set of characters from a string
170     http://rosettacode.org/wiki/Strip_a_set_of_characters_from_a_string#C
171     done
172 **/
173 /* checks if character exists in list */
contains(char character,char * list)174 static int contains ( char character, char * list )
175 {
176 	while ( *list )
177 	{
178 		if ( character == *list )
179 			return 1;
180 
181 		++list;
182 	}
183 
184 	return 0;
185 }
186 
187 
188 
removeChar(char * str,char garbage)189 char * removeChar ( char *str, char garbage )
190 {
191 
192 #if 1
193 	g_print ( "FUNC: %s\n", __FUNCTION__ );
194 #endif
195 
196 	char *src, *dst;
197 
198 	for ( src = dst = str; *src != '\0'; src++ )
199 	{
200 		*dst = *src;
201 
202 		if ( *dst != garbage ) dst++;
203 	}
204 
205 	*dst = '\0';
206 
207 	g_print ( "%s\n", dst );
208 
209 	return dst;
210 }
211 
212 
213 /**
214 \brief
215 **/
strip_chars(char * string,char * chars)216 static int strip_chars ( char * string, char * chars )
217 {
218 
219 	int i = 0;
220 	int j = strlen ( string );
221 	int l = strlen ( chars );
222 
223 	char newstr[strlen ( string ) ];
224 	int c = 0;
225 	int k = 0;
226 
227 	strcpy ( newstr, string );
228 
229 	char *f;
230 	f = string;
231 
232 	/* search through string till match found */
233 	while ( i < j )
234 	{
235 
236 		/* check for chars, in string */
237 		if ( strncmp ( f + i, chars, l ) != -1 )
238 		{
239 			g_print ( "got tag %s\n", chars );
240 			i += l - 1;
241 			/* remove matching tag */
242 		}
243 
244 		else
245 		{
246 			/*
247 			newstr[c] = string[i];
248 			g_print ( "plain text %c\n", newstr[c] );
249 			newstr[c+1] = '\0';
250 			g_print ( "      string = %s\n", newstr );
251 			*/
252 			c++;
253 			i++;
254 
255 		}
256 
257 	}
258 
259 	g_print ( "string = %s : newstr = %s\n", string, newstr );
260 
261 	strcpy ( string, newstr );
262 
263 	string[j] = '\0';
264 
265 	return c;
266 }
267 
268 /**
269     search for first occurance of p in s, starting from i
270     done
271 **/
strnfrst(char * s,char * p,int i)272 static int strnfrst ( char *s, char *p, int i )
273 {
274 	char *f;
275 	int l;
276 
277 	l = strlen ( p ); /* length of search string */
278 	f = s + i;
279 
280 	/* search through string till match found */
281 	while ( *f != '\0' )
282 	{
283 		if ( !strncmp ( f, p, l ) )
284 			return f - s;
285 
286 		f++;
287 	}
288 
289 	return -1;
290 }
291 
292 
293 
294 
295 /**
296     extract a range of characters from string s starting from position a to position b
297     done
298 **/
strrng(char * dest,const char * src,int a,int b)299 static char *strrng ( char *dest, const char *src, int a, int b )
300 {
301 	unsigned i, j;
302 
303 	j = 0;
304 
305 	for ( i = a; i < b; i++ )
306 	{
307 		dest[j++] = src[i];
308 	}
309 
310 	dest[j] = '\0';
311 	return dest;
312 
313 }
314 
315 /*
316 char *strcpy(char *dest, const char *src)
317 {
318   unsigned i;
319   for (i=0; src[i] != '\0'; ++i)
320     dest[i] = src[i];
321   dest[i] = '\0';
322   return dest;
323 }
324 */
325 
326 
327 
328 
329 /**
330     gettag
331     get name of next tag in string, starting at position i
332     return updated value of i
333 
334     test-string = "<b>bold</b>   <i>italic</i>   <u>underline</u>   <s>strikethrough</s>"
335 
336 **/
getTag(char * str,char * tag,int i)337 static int getTag ( char *str, char *tag, int i )
338 {
339 #if 1
340 	g_print ( "%s\n", __FUNCTION__ );
341 #endif
342 	int j;
343 
344 	if ( strcmp ( str , "<" ) )
345 	{
346 		/* handle a tag */
347 		j = strnfrst ( str, ">", i );
348 		//strrng ( tag, str, ++i, j );
349 		strrng ( tag, str, i, j + 1  );
350 		return j;
351 	}
352 
353 	return i;
354 }
355 
356 
357 /**
358 \brief
359 **/
getText(char * str,char * txt,int i)360 static int getText ( char *str, char *txt, int i )
361 {
362 
363 	int j;
364 	g_print ( "%s 1 ", __FUNCTION__ );
365 	j = strnfrst ( str, "<", i );
366 	g_print ( "2 %d", j );
367 
368 	if ( j < 0 )
369 	{
370 		j = strlen ( str );
371 
372 		g_print ( "3 %d", j );
373 		strrng ( txt, str, i, strlen ( str ) );
374 
375 	}
376 
377 	else
378 	{
379 		strrng ( txt, str, i, j );
380 	}
381 
382 	g_print ( "4 " );
383 	return j;
384 }
385 
386 /**
387 \brief
388 **/
gnoclMarkupInsertTest(GtkTextBuffer * buffer,GtkTextIter * iter)389 int gnoclMarkupInsertTest ( GtkTextBuffer *buffer, GtkTextIter *iter )
390 {
391 	g_print ( "FUNC: %s\n", __FUNCTION__ );
392 
393 	gint i;
394 
395 	for ( i = 0 ; i < 100; i++ )
396 		gtk_text_buffer_insert_with_tags_by_name ( buffer, iter, "H ", -1, "b", "i" );
397 
398 }
399 
400 /**
401 \brief	Add tag from list of active tags.
402 **/
addTag(gchar * tag)403 void addTag ( gchar *tag )
404 {
405 #if 1
406 	g_print ( "FUNC: %s\n", __FUNCTION__ );
407 #endif
408 
409 	if ( g_slist_find ( tagList, tag ) == NULL )
410 	{
411 		g_print ( "\tAdded %s\n", tag );
412 		tagList = g_slist_prepend ( tagList, tag );
413 		g_print ( "list length = %d\n", g_slist_length ( tagList ) );
414 	}
415 }
416 
417 /**
418 \brief	Remove tag from list of active tags.
419 **/
removeTag(gchar * tag)420 void removeTag ( gchar *tag )
421 {
422 #if 1
423 	g_print ( "FUNC: %s\n", __FUNCTION__ );
424 #endif
425 
426 	gchar *tmp;
427 	tmp = tag;
428 
429 	tagList = g_slist_remove_all  ( tagList, tmp );
430 	tmp = str_replace ( tag, "/", "" );
431 
432 	g_print ( "\tRemoved %s\n", tmp );
433 	tagList = g_slist_remove_all  ( tagList, tmp );
434 	g_print ( "list length = %d\n", g_slist_length ( tagList ) );
435 
436 }
437 
438 
439 
440 
441 /**
442 \brief
443 **/
handleTag(gchar tag[])444 void handleTag ( gchar tag[] )
445 {
446 #if 1
447 	g_print ( "FUNC: %s %s\n", __FUNCTION__, tag );
448 #endif
449 
450 
451 	if ( tag[1] == '/' )
452 	{
453 		g_print ( "\tremove tag\n" );
454 		removeTag ( tag );
455 	}
456 
457 	else
458 	{
459 		g_print ( "\tadd tag\n" );
460 		addTag ( tag );
461 	}
462 
463 
464 }
465 
466 /**
467 \brief
468 \todo	test the legality of the markup string.
469 		swap &gtl; for ">" etc..
470 **/
gnoclInsertMarkup(GtkTextBuffer * buffer,GtkTextIter * iter,gchar markup_text[])471 int gnoclInsertMarkup ( GtkTextBuffer *buffer, GtkTextIter *iter, gchar markup_text[] )
472 {
473 #if 1
474 	g_print ( "FUNC: %s\n", __FUNCTION__ );
475 #endif
476 
477 	GtkTextMark *tagStart, *tagEnd;
478 	GSList *lptr = NULL;
479 	GtkTextIter *tagIter;
480 
481 	/* interate through pango string, determine, text or markup */
482 	int i, j;
483 
484 
485 	const char tag[256];
486 	char txt[10];
487 	gchar *ch1, *ch2;
488 
489 	//gchar tmp[strlen ( markup_text ) ];
490 	//sprintf ( tmp, "%s", markup_text );
491 
492 
493 	i = 0;
494 
495 	/* initialize the text */
496 	while ( i < strlen ( markup_text ) )
497 	{
498 		//ch1 = tmp[i];
499 		//ch2 = tmp[i+1];
500 
501 		if ( markup_text[i] == '<' )
502 		{
503 			g_print ( "1-1 %d\n", i );
504 			i = getTag ( markup_text, tag, i );
505 			handleTag ( tag );
506 			g_print ( "1-2 %d\n", i );
507 		}
508 
509 		else
510 		{
511 			g_print ( "2\n" );
512 			//sprintf ( txt, "%c", ch1 );
513 			ch2 = &markup_text[i];
514 			tagIter = gtk_text_iter_copy ( iter );
515 
516 			//applyTags ( buffer,  iter );
517 			gtk_text_buffer_insert  ( buffer, iter, &markup_text[i], 1 );
518 
519 			//gtk_text_iter_forward_char (iter);
520 
521 			/* problems occuring here */
522 			applyTags ( buffer,  iter );
523 
524 			g_print ( "ch = %c\n",  markup_text[i] );
525 
526 		}
527 
528 		i++;
529 
530 		for ( lptr = ( GSList * ) tagList; lptr != NULL; lptr = lptr->next )
531 		{
532 			g_print ( "tagList\n-----tag = %s\n-----\n", lptr->data );
533 		}
534 
535 
536 
537 	}
538 
539 	/* free memory */
540 	//g_slist_free ( tagList );
541 
542 
543 
544 
545 	g_print ( "==========\n" );
546 	return 0;
547 }
548 
549 /**
550 **/
applyTags(GtkTextBuffer * buffer,GtkTextIter * iter)551 void applyTags ( GtkTextBuffer *buffer, GtkTextIter *iter )
552 {
553 #if 0
554 	g_print ( "FUNC: %s\n", __FUNCTION__ );
555 #endif
556 	GtkTextIter *end;
557 	GSList *p = NULL;
558 	gint i;
559 
560 	GtkTextTagTable *table;
561 
562 	table = gtk_text_buffer_get_tag_table ( buffer );
563 
564 	end =  gtk_text_iter_copy ( iter );
565 	gtk_text_iter_set_offset  ( end, 1 );
566 
567 	i = 1;
568 
569 	/* iterate through tagList */
570 	for ( p = ( GSList * ) tagList; p != NULL; p = p->next )
571 	{
572 
573 
574 		if ( gtk_text_tag_table_lookup ( table, p->data ) != NULL )
575 		{
576 
577 			if ( strncmp ( p->data, "</", 2 ) != 0 )
578 			{
579 				g_print ( "\t applying tag = %s (%d)\n", p->data, i++ );
580 				gtk_text_buffer_apply_tag_by_name  ( buffer, p->data, iter, end );
581 			}
582 		}
583 	}
584 
585 }
586 
587