]> git.sur5r.net Git - glabels/blob - src/text-node.c
Imported Upstream version 2.2.8
[glabels] / src / text-node.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 /*
4  *  (GLABELS) Label and Business Card Creation program for GNOME
5  *
6  *  text_node.c:  text node module
7  *
8  *  Copyright (C) 2001-2002  Jim Evins <evins@snaught.com>.
9  *
10  *  This program 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 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program 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 this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23  */
24
25 #include <config.h>
26
27 #include "text-node.h"
28
29 #include <string.h>
30
31 #include "merge.h"
32
33 #include "debug.h"
34
35 /*===========================================*/
36 /* Local function prototypes                 */
37 /*===========================================*/
38
39 static glTextNode *extract_text_node  (gchar          *text,
40                                        gint           *n);
41
42 static gboolean    is_empty_field     (glTextNode     *text_node,
43                                        glMergeRecord  *record);
44
45 \f
46 /****************************************************************************/
47 /* Expand single node into representative string.                           */
48 /****************************************************************************/
49 gchar *
50 gl_text_node_expand (glTextNode    *text_node,
51                      glMergeRecord *record)
52 {
53         gchar *text;
54
55         if (text_node->field_flag) {
56                 if (record == NULL) {
57                         return g_strdup_printf ("${%s}", text_node->data);
58                 } else {
59                         text = gl_merge_eval_key (record, text_node->data);
60                         if (text != NULL) {
61                                 return text;
62                         } else {
63                                 return g_strdup_printf ("%s", "");
64                         }
65                 }
66         } else {
67                 return g_strdup (text_node->data);
68         }
69 }
70
71 /*--------------------------------------------------------------------------*/
72 /* PRIVATE.  Is node a field that evaluates empty?                          */
73 /*--------------------------------------------------------------------------*/
74 static gboolean
75 is_empty_field (glTextNode    *text_node,
76                 glMergeRecord *record)
77 {
78         gchar    *text;
79         gboolean  ret = FALSE;
80
81         if ( (record != NULL) && text_node->field_flag) {
82                 text = gl_merge_eval_key (record, text_node->data);
83                 if ( (text == NULL) || (text[0] == 0) ) {
84                         ret = TRUE;
85                 }
86                 g_free (text);
87         }
88
89         return ret;
90 }
91
92 /****************************************************************************/
93 /* Create a single text node from given text.                               */
94 /****************************************************************************/
95 glTextNode *
96 gl_text_node_new_from_text (gchar *text)
97 {
98         gint n;
99
100         return extract_text_node (text, &n);
101 }
102
103 /*--------------------------------------------------------------------------*/
104 /* PRIVATE.  Create a single text node from given text. n = characters used */
105 /*--------------------------------------------------------------------------*/
106 static glTextNode *
107 extract_text_node (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 = 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 = 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 /* Copy a single text node.                                                 */
145 /****************************************************************************/
146 glTextNode *
147 gl_text_node_dup (glTextNode *src)
148 {
149         glTextNode *dst;
150
151         if ( src == NULL ) return NULL;
152
153         dst = g_new0 (glTextNode, 1);
154
155         dst->field_flag = src->field_flag;
156         dst->data = g_strdup (src->data);
157
158         return dst;
159 }
160
161 /****************************************************************************/
162 /* Free a single text node.                                                 */
163 /****************************************************************************/
164 void
165 gl_text_node_free (glTextNode **text_node)
166 {
167         if ( *text_node == NULL ) return;
168
169         g_free ((*text_node)->data);
170         (*text_node)->data = NULL;
171         g_free (*text_node);
172         *text_node = NULL;
173 }
174
175 /****************************************************************************/
176 /* Compare 2 text nodes for equality.                                       */
177 /****************************************************************************/
178 gboolean
179 gl_text_node_equal (glTextNode     *text_node1,
180                     glTextNode     *text_node2)
181 {
182         /* First take care of the case of either or both being NULL. */
183         if ( text_node1 == NULL ) {
184                 return ( text_node2 == NULL );
185         } else {
186                 if ( text_node2 == NULL ) {
187                         return FALSE;
188                 }
189         }
190
191         /* Bail if field flags differ. */
192         if ( text_node1->field_flag != text_node2->field_flag ) {
193                 return FALSE;
194         }
195
196         /* Now take care of the case of either or both data fields being NULL. */
197         if ( text_node1->data == NULL ) {
198                 return ( text_node2->data == NULL );
199         } else {
200                 if ( text_node2->data == NULL ) {
201                         return FALSE;
202                 }
203         }
204
205         /* Field flags are identical, so now compare the data. */
206         return (strcmp (text_node1->data, text_node2->data) == 0);
207 }
208
209 /****************************************************************************/
210 /* Expand text lines into single string.                                    */
211 /****************************************************************************/
212 gchar *
213 gl_text_node_lines_expand (GList         *lines,
214                            glMergeRecord *record)
215 {
216         GList      *p_line, *p_node;
217         glTextNode *text_node;
218         gchar       *text, *old_text, *expanded_node;
219
220         text = g_strdup ("");   /* prime pointer for concatenation */
221         for (p_line = lines; p_line != NULL; p_line = p_line->next) {
222
223                 /* special case: something like ${ADDRESS2} = "" on line by itself. */ 
224                 /*               in such circumstances ignore the line completely.  */
225                 p_node = (GList *)p_line->data;
226                 if (p_node && p_node->next == NULL) {
227                         text_node = (glTextNode *) p_node->data;
228                         if ( is_empty_field (text_node, record) ) {
229                                 continue;
230                         }
231                 }
232
233                 /* expand each node */
234                 for (p_node = (GList *) p_line->data; p_node != NULL;
235                      p_node = p_node->next) {
236                         text_node = (glTextNode *) p_node->data;
237                         old_text = text;
238                         expanded_node = gl_text_node_expand (text_node, record);
239                         text = g_strconcat (text, expanded_node, NULL);
240                         g_free (old_text);
241                         g_free (expanded_node);
242                 }
243
244                 /* append newline to each line, except last. */
245                 if ( p_line->next != NULL ) {
246                         old_text = text;
247                         text = g_strconcat (text, "\n", NULL);
248                         g_free (old_text);
249                 }
250         }
251
252         return text;
253 }
254
255 /****************************************************************************/
256 /* Parse a string back into text lines.                                     */
257 /****************************************************************************/
258 GList *
259 gl_text_node_lines_new_from_text (gchar *text)
260 {
261         GList      *lines, *nodes;
262         glTextNode *text_node;
263         gchar      *p;
264         gint        n;
265
266         lines = NULL;
267         nodes = NULL;
268         for (p = text; *p != 0; p += n) {
269                 if (*p != '\n') {
270                         text_node = extract_text_node (p, &n);
271                         nodes = g_list_append (nodes, text_node);
272                 } else {
273                         n = 1;
274                         lines = g_list_append (lines, nodes);
275                         nodes = NULL;
276                 }
277         }
278         if (*(p - 1) != '\n') {
279                 lines = g_list_append (lines, nodes);
280         }
281
282         return lines;
283 }
284
285 /****************************************************************************/
286 /* Copy a list of text lines.                                               */
287 /****************************************************************************/
288 GList *
289 gl_text_node_lines_dup (GList *src_lines)
290 {
291         GList      *dst_lines=NULL;
292         GList      *p_line, *line, *p_node;
293         glTextNode *node;
294
295         for (p_line = src_lines; p_line != NULL; p_line = p_line->next)
296         {
297                 line = NULL;
298                 for (p_node = (GList *) p_line->data; p_node != NULL; p_node = p_node->next)
299                 {
300                         node = gl_text_node_dup ((glTextNode *)p_node->data);
301                         line = g_list_append (line, node);
302                 }
303                 dst_lines = g_list_append (dst_lines, line);
304         }
305
306         return dst_lines;
307 }
308
309 /****************************************************************************/
310 /* Free a list of text lines.                                               */
311 /****************************************************************************/
312 void
313 gl_text_node_lines_free (GList **lines)
314 {
315         GList *p_line, *p_node;
316         glTextNode     *text_node;
317
318         for (p_line = *lines; p_line != NULL; p_line = p_line->next)
319         {
320                 for (p_node = (GList *) p_line->data; p_node != NULL; p_node = p_node->next)
321                 {
322                         text_node = (glTextNode *)p_node->data;
323                         p_node->data = NULL;
324                         gl_text_node_free ( &text_node );
325                 }
326                 g_list_free ((GList *) p_line->data);
327                 p_line->data = NULL;
328         }
329
330         g_list_free (*lines);
331         *lines = NULL;
332 }
333
334 /****************************************************************************/
335 /* For debugging:  descend and print lines list.                            */
336 /****************************************************************************/
337 void
338 gl_text_node_lines_print (GList * lines )
339 {
340         GList *p_line, *p_node;
341         glTextNode *text_node;
342         gint i_line, i_node;
343
344         for (p_line=lines, i_line=0; p_line != NULL; p_line=p_line->next, i_line++) {
345                 for (p_node = (GList *) p_line->data, i_node=0; p_node != NULL;
346                      p_node = p_node->next, i_node++) {
347                         text_node = (glTextNode *) p_node->data;
348                         g_print( "LINE[%d], NODE[%d] = { %d, \"%s\" }\n",
349                                  i_line, i_node,
350                                  text_node->field_flag, text_node->data );
351
352                 }
353         }
354
355 }
356