]> git.sur5r.net Git - glabels/blob - src/text-node.c
Imported Upstream version 3.0.0
[glabels] / src / text-node.c
1 /*
2  *  text-node.c
3  *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of gLabels.
6  *
7  *  gLabels is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  gLabels is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include "text-node.h"
24
25 #include <string.h>
26
27 #include "merge.h"
28
29 #include "debug.h"
30
31
32 /*===========================================*/
33 /* Local function prototypes                 */
34 /*===========================================*/
35
36 static glTextNode *extract_text_node  (const gchar         *text,
37                                        gint                *n);
38
39 static gboolean    is_empty_field     (const glTextNode    *text_node,
40                                        const glMergeRecord *record);
41
42
43 /****************************************************************************/
44 /* Expand single node into representative string.                           */
45 /****************************************************************************/
46 gchar *
47 gl_text_node_expand (const glTextNode    *text_node,
48                      const glMergeRecord *record)
49 {
50         gchar *text;
51
52         if (text_node->field_flag) {
53                 if (record == NULL) {
54                         return g_strdup_printf ("${%s}", text_node->data);
55                 } else {
56                         text = gl_merge_eval_key (record, text_node->data);
57                         if (text != NULL) {
58                                 return text;
59                         } else {
60                                 return g_strdup_printf ("%s", "");
61                         }
62                 }
63         } else {
64                 return g_strdup (text_node->data);
65         }
66 }
67
68
69 /*--------------------------------------------------------------------------*/
70 /* PRIVATE.  Is node a field that evaluates empty?                          */
71 /*--------------------------------------------------------------------------*/
72 static gboolean
73 is_empty_field (const glTextNode    *text_node,
74                 const glMergeRecord *record)
75 {
76         gchar    *text;
77         gboolean  ret = FALSE;
78
79         if ( (record != NULL) && text_node->field_flag) {
80                 text = gl_merge_eval_key (record, text_node->data);
81                 if ( (text == NULL) || (text[0] == 0) ) {
82                         ret = TRUE;
83                 }
84                 g_free (text);
85         }
86
87         return ret;
88 }
89
90
91 /****************************************************************************/
92 /* Create a single text node from given text.                               */
93 /****************************************************************************/
94 glTextNode *
95 gl_text_node_new_from_text (const gchar *text)
96 {
97         gint n;
98
99         return extract_text_node (text, &n);
100 }
101
102
103 /*--------------------------------------------------------------------------*/
104 /* PRIVATE.  Create a single text node from given text. n = characters used */
105 /*--------------------------------------------------------------------------*/
106 static glTextNode *
107 extract_text_node (const gchar *text,
108                    gint        *n)
109 {
110         glTextNode *text_node;
111         gchar      *p;
112         gint        m;
113
114         text_node = g_new0 (glTextNode, 1);
115
116         if (strncmp (text, "${", strlen ("${")) == 0) {
117                 /* We are at the beginning of a "FIELD" node */
118                 text_node->field_flag = TRUE;
119                 *n = strlen ("${");
120                 text += *n;
121                 for (p = (gchar *)text, m = 0; *p != 0; p++, m++, (*n)++) {
122                         if (*p == '}') {
123                                 (*n)++;
124                                 break;
125                         }
126                 }
127                 text_node->data = g_strndup (text, m);
128         } else {
129                 /* We are at the beginning of a literal node */
130                 text_node->field_flag = FALSE;
131                 for (p = (gchar *)text, *n = 0; *p != 0; p++, (*n)++) {
132                         if (strncmp (p, "${", strlen ("${")) == 0)
133                                 break;
134                         if (*p == '\n')
135                                 break;
136                 }
137                 text_node->data = g_strndup (text, *n);
138         }
139
140         return text_node;
141 }
142
143
144 /****************************************************************************/
145 /* Copy a single text node.                                                 */
146 /****************************************************************************/
147 glTextNode *
148 gl_text_node_dup (const glTextNode *src)
149 {
150         glTextNode *dst;
151
152         if ( src == NULL ) return NULL;
153
154         dst = g_new0 (glTextNode, 1);
155
156         dst->field_flag = src->field_flag;
157         dst->data = g_strdup (src->data);
158
159         return dst;
160 }
161
162
163 /****************************************************************************/
164 /* Free a single text node.                                                 */
165 /****************************************************************************/
166 void
167 gl_text_node_free (glTextNode **text_node)
168 {
169         if ( *text_node == NULL ) return;
170
171         g_free ((*text_node)->data);
172         (*text_node)->data = NULL;
173         g_free (*text_node);
174         *text_node = NULL;
175 }
176
177
178 /****************************************************************************/
179 /* Compare 2 text nodes for equality.                                       */
180 /****************************************************************************/
181 gboolean
182 gl_text_node_equal (const glTextNode     *text_node1,
183                     const glTextNode     *text_node2)
184 {
185         /* First take care of the case of either or both being NULL. */
186         if ( text_node1 == NULL ) {
187                 return ( text_node2 == NULL );
188         } else {
189                 if ( text_node2 == NULL ) {
190                         return FALSE;
191                 }
192         }
193
194         /* Bail if field flags differ. */
195         if ( text_node1->field_flag != text_node2->field_flag ) {
196                 return FALSE;
197         }
198
199         /* Now take care of the case of either or both data fields being NULL. */
200         if ( text_node1->data == NULL ) {
201                 return ( text_node2->data == NULL );
202         } else {
203                 if ( text_node2->data == NULL ) {
204                         return FALSE;
205                 }
206         }
207
208         /* Field flags are identical, so now compare the data. */
209         return (strcmp (text_node1->data, text_node2->data) == 0);
210 }
211
212
213 /****************************************************************************/
214 /* Expand text lines into single string.                                    */
215 /****************************************************************************/
216 gchar *
217 gl_text_node_lines_expand (GList               *lines,
218                            const glMergeRecord *record)
219 {
220         GList      *p_line, *p_node;
221         glTextNode *text_node;
222         gchar       *text, *old_text, *expanded_node;
223
224         text = g_strdup ("");   /* prime pointer for concatenation */
225         for (p_line = lines; p_line != NULL; p_line = p_line->next) {
226
227                 /* special case: something like ${ADDRESS2} = "" on line by itself. */ 
228                 /*               in such circumstances ignore the line completely.  */
229                 p_node = (GList *)p_line->data;
230                 if (p_node && p_node->next == NULL) {
231                         text_node = (glTextNode *) p_node->data;
232                         if ( is_empty_field (text_node, record) ) {
233                                 continue;
234                         }
235                 }
236
237                 /* expand each node */
238                 for (p_node = (GList *) p_line->data; p_node != NULL;
239                      p_node = p_node->next) {
240                         text_node = (glTextNode *) p_node->data;
241                         old_text = text;
242                         expanded_node = gl_text_node_expand (text_node, record);
243                         text = g_strconcat (text, expanded_node, NULL);
244                         g_free (old_text);
245                         g_free (expanded_node);
246                 }
247
248                 /* append newline to each line, except last. */
249                 if ( p_line->next != NULL ) {
250                         old_text = text;
251                         text = g_strconcat (text, "\n", NULL);
252                         g_free (old_text);
253                 }
254         }
255
256         return text;
257 }
258
259
260 /****************************************************************************/
261 /* Parse a string back into text lines.                                     */
262 /****************************************************************************/
263 GList *
264 gl_text_node_lines_new_from_text (const gchar *text)
265 {
266         GList      *lines, *nodes;
267         glTextNode *text_node;
268         gchar      *p;
269         gint        n;
270
271         lines = NULL;
272         nodes = NULL;
273         for (p = (gchar *)text; *p != 0; p += n) {
274                 if (*p != '\n') {
275                         text_node = extract_text_node (p, &n);
276                         nodes = g_list_append (nodes, text_node);
277                 } else {
278                         n = 1;
279                         lines = g_list_append (lines, nodes);
280                         nodes = NULL;
281                 }
282         }
283         if (*(p - 1) != '\n') {
284                 lines = g_list_append (lines, nodes);
285         }
286
287         return lines;
288 }
289
290
291 /****************************************************************************/
292 /* Copy a list of text lines.                                               */
293 /****************************************************************************/
294 GList *
295 gl_text_node_lines_dup (GList *src_lines)
296 {
297         GList      *dst_lines=NULL;
298         GList      *p_line, *line, *p_node;
299         glTextNode *node;
300
301         for (p_line = src_lines; p_line != NULL; p_line = p_line->next)
302         {
303                 line = NULL;
304                 for (p_node = (GList *) p_line->data; p_node != NULL; p_node = p_node->next)
305                 {
306                         node = gl_text_node_dup ((glTextNode *)p_node->data);
307                         line = g_list_append (line, node);
308                 }
309                 dst_lines = g_list_append (dst_lines, line);
310         }
311
312         return dst_lines;
313 }
314
315
316 /****************************************************************************/
317 /* Free a list of text lines.                                               */
318 /****************************************************************************/
319 void
320 gl_text_node_lines_free (GList **lines)
321 {
322         GList *p_line, *p_node;
323         glTextNode     *text_node;
324
325         for (p_line = *lines; p_line != NULL; p_line = p_line->next)
326         {
327                 for (p_node = (GList *) p_line->data; p_node != NULL; p_node = p_node->next)
328                 {
329                         text_node = (glTextNode *)p_node->data;
330                         p_node->data = NULL;
331                         gl_text_node_free ( &text_node );
332                 }
333                 g_list_free ((GList *) p_line->data);
334                 p_line->data = NULL;
335         }
336
337         g_list_free (*lines);
338         *lines = NULL;
339 }
340
341
342 /****************************************************************************/
343 /* For debugging:  descend and print lines list.                            */
344 /****************************************************************************/
345 void
346 gl_text_node_lines_print (GList * lines )
347 {
348         GList *p_line, *p_node;
349         glTextNode *text_node;
350         gint i_line, i_node;
351
352         for (p_line=lines, i_line=0; p_line != NULL; p_line=p_line->next, i_line++) {
353                 for (p_node = (GList *) p_line->data, i_node=0; p_node != NULL;
354                      p_node = p_node->next, i_node++) {
355                         text_node = (glTextNode *) p_node->data;
356                         g_print( "LINE[%d], NODE[%d] = { %d, \"%s\" }\n",
357                                  i_line, i_node,
358                                  text_node->field_flag, text_node->data );
359
360                 }
361         }
362
363 }
364
365
366
367 /*
368  * Local Variables:       -- emacs
369  * mode: C                -- emacs
370  * c-basic-offset: 8      -- emacs
371  * tab-width: 8           -- emacs
372  * indent-tabs-mode: nil  -- emacs
373  * End:                   -- emacs
374  */