]> git.sur5r.net Git - glabels/blob - glabels2/src/merge-text.c
Initial revision
[glabels] / glabels2 / src / merge-text.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  merge_text.c:  text-file merge backend module
5  *
6  *  Copyright (C) 2001  Jim Evins <evins@snaught.com>.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21  */
22
23 #include <config.h>
24
25 #include <gnome.h>
26
27 #include "merge-text.h"
28
29 #include "debug.h"
30
31 #define LINE_BUF_LEN 1024
32
33 /*===========================================*/
34 /* Private types                             */
35 /*===========================================*/
36
37 /*===========================================*/
38 /* Private globals                           */
39 /*===========================================*/
40
41 /*===========================================*/
42 /* Local function prototypes                 */
43 /*===========================================*/
44 static GList * split_fields( gchar *line, gchar delim );
45 static void free_fields( GList **fields );
46
47 \f
48 /****************************************************************************/
49 /* Open merge source.                                                       */
50 /****************************************************************************/
51 glMergeInput *
52 gl_merge_text_open (glMergeType type,
53                     GList * field_defs,
54                     gchar * src)
55 {
56         FILE *fp;
57         glMergeInput *input;
58
59         fp = fopen (src, "r");
60         if (fp == NULL) {
61                 return NULL;
62         }
63
64         input = g_new0 (glMergeInput, 1);
65         input->type = type;
66         input->field_defs = field_defs;
67         input->handle = fp;
68
69         return input;
70 }
71
72 /****************************************************************************/
73 /* Close merge source.                                                      */
74 /****************************************************************************/
75 void
76 gl_merge_text_close (glMergeInput * input)
77 {
78         if (input != NULL) {
79
80                 fclose ((FILE *) input->handle);
81                 g_free (input);
82
83         }
84 }
85
86 /****************************************************************************/
87 /* Get next record from merge source, NULL if no records left (i.e EOF)     */
88 /****************************************************************************/
89 glMergeRecord *
90 gl_merge_text_get_record (glMergeInput * input)
91 {
92         gchar delim, *loc;
93         GList *fields, *p;
94         gint  i_field;
95         glMergeRecord *record = NULL;
96         glMergeField *field;
97         gchar line[LINE_BUF_LEN];
98
99         if (input != NULL) {
100
101                 switch (input->type) {
102                 case GL_MERGE_TEXT_TAB:
103                         delim = '\t';
104                         break;
105                 case GL_MERGE_TEXT_COLON:
106                         delim = ':';
107                         break;
108                 case GL_MERGE_TEXT_COMMA:
109                         delim = ',';
110                         break;
111                 default:
112                         g_warning ("Unexpected merge type");
113                         return NULL;
114                 }
115
116                 while (fgets (line, LINE_BUF_LEN, (FILE *) input->handle) !=
117                        NULL) {
118                         if (TRUE /* TODO: skip blank lines or comments */ ) {
119                                 g_strchomp (line);
120                                 record = g_new0 (glMergeRecord, 1);
121                                 record->select_flag = TRUE;
122                                 fields = split_fields (line, delim);
123                                 i_field = 1;
124                                 for (p=fields; p != NULL; p=p->next) {
125                                         loc =
126                                             g_strdup_printf ("%d", i_field++);
127                                         field = g_new0 (glMergeField, 1);
128                                         field->value = g_strdup (p->data);
129                                         field->key =
130                                             gl_merge_find_key (input->
131                                                                field_defs, loc);
132                                         record->field_list =
133                                                 g_list_append (record->field_list, field);
134                                         g_free (loc);
135                                 }
136                                 free_fields (&fields);
137                                 return record;
138                         }
139                 }
140
141         }
142         return NULL;
143 }
144
145 /****************************************************************************/
146 /* Retrieve a list of raw fields (columns in this case)                     */
147 /****************************************************************************/
148 GList *
149 gl_merge_text_get_raw_record (glMergeInput * input)
150 {
151         GList *list = NULL;
152         gchar line[LINE_BUF_LEN], delim;
153         GList *fields, *p;
154         gint i_field;
155         glMergeRawField *raw_field;
156
157         if (input != NULL) {
158
159                 switch (input->type) {
160                 case GL_MERGE_TEXT_TAB:
161                         delim = '\t';
162                         break;
163                 case GL_MERGE_TEXT_COLON:
164                         delim = ':';
165                         break;
166                 case GL_MERGE_TEXT_COMMA:
167                         delim = ',';
168                         break;
169                 default:
170                         g_warning ("Unexpected merge type");
171                         return NULL;
172                 }
173
174                 while (fgets (line, LINE_BUF_LEN, (FILE *) input->handle)
175                        != NULL) {
176                         if (TRUE /* TODO: skip blank lines or comments */ ) {
177                                 g_strchomp (line);
178                                 fields = split_fields (line, delim);
179                                 i_field = 1;
180                                 for (p=fields; p != NULL; p=p->next) {
181                                         raw_field =
182                                                 g_new0 (glMergeRawField, 1);
183                                         raw_field->loc =
184                                                 g_strdup_printf ("%d",
185                                                                  i_field++);
186                                         raw_field->value = g_strdup (p->data);
187                                         list = g_list_append (list, raw_field);
188                                 }
189                                 free_fields (&fields);
190                                 break;
191                         }
192                 }
193
194         }
195         return list;
196 }
197
198 /*---------------------------------------------------------------------------*/
199 /* PRIVATE.  Split out fields by delimiter while decoding things like "\n".  */
200 /*---------------------------------------------------------------------------*/
201 static GList * split_fields ( gchar *line,
202                               gchar delim )
203 {
204         GList *list = NULL;
205         GString *string;
206         gchar *c;
207         enum { NORMAL, ESCAPED } state;
208
209         g_return_val_if_fail (line != NULL, NULL);
210
211         state = NORMAL;
212         string = g_string_new( "" );
213         for ( c=line; *c!=0; c++ ) {
214
215                 switch (state) {
216
217                 case NORMAL:
218                         if ( *c == '\\' ) {
219                                 state = ESCAPED;
220                         } else if ( *c != delim ) {
221                                 string = g_string_append_c (string, *c);
222                         } else {
223                                 list = g_list_append (list,
224                                                       g_strdup (string->str));
225                                 string = g_string_assign( string, "" );
226                         }
227                         break;
228
229                 case ESCAPED:
230                         switch (*c) {
231                         case 'n':
232                                 string = g_string_append_c (string, '\n');
233                                 break;
234                         case 't':
235                                 string = g_string_append_c (string, '\t');
236                                 break;
237                         default:
238                                 string = g_string_append_c (string, *c);
239                                 break;
240                         }
241                         state = NORMAL;
242                         break;
243
244                 default:
245                         g_assert_not_reached();
246                         break;
247                 }
248
249         }
250         list = g_list_append( list, g_strdup(string->str) );
251         g_string_free( string, TRUE );
252
253         return list;
254 }
255
256 /*---------------------------------------------------------------------------*/
257 /* Free list of fields.                                                      */
258 /*---------------------------------------------------------------------------*/
259 void
260 free_fields (GList ** list)
261 {
262         GList *p;
263
264         for (p = *list; p != NULL; p = p->next) {
265                 g_free (p->data);
266                 p->data = NULL;
267         }
268
269         g_list_free (*list);
270         *list = NULL;
271 }
272