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 >l; 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