0703d42e52a88e4f11e47658e53af9edc3a80f99
[idzebra-moved-to-github.git] / recctrl / csvread.c
1 /* $Id: csvread.c,v 1.1 2005-12-05 12:18:41 marc Exp $
2    Copyright (C) 1995-2005
3    Index Data ApS
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23
24
25 #include <yaz/log.h>
26 #include <yaz/nmem.h>
27 #include <yaz/yaz-util.h>
28
29 /* #include <d1_absyn.h> */
30 #include <idzebra/data1.h>
31 #include <idzebra/recgrs.h>
32
33 /* #include <assert.h> */
34 #include <ctype.h>
35
36 /*
37 struct csv_getc_info {
38     char *buf;
39     int buf_size;
40     int size;
41     int off;
42     off_t moffset;
43     void *fh;
44     int (*readf)(void *, char *, size_t);
45     WRBUF wrbuf;
46 };
47 */
48
49 static struct csv_t {
50   NMEM nmem;
51   int buf_size;
52   char *buf;
53   int name_size;
54   int value_size;
55   char *value;
56   char field_char;
57   char record_char;
58   char string_char;
59   char *root_element;
60   int field_line;
61   int lower_case;
62   int max_nr_fields;
63   int nr_fields;
64   /* char *field_names; */
65   char **field_name;
66 };
67
68
69 static void grs_config_csv(void *clientData, Res res, const char *args)
70 {
71   int i;
72   struct csv_t *csvp = (struct csv_t*) clientData;
73
74   yaz_log (YLOG_LOG, "Called CSV filter grs_config_csv");
75   yaz_log (YLOG_LOG, "'%s'", args);
76
77   csvp->buf_size = 64;
78   csvp->buf = nmem_malloc(csvp->nmem, csvp->buf_size);
79   csvp->name_size = 256;
80   csvp->value_size = 4096;
81   csvp->value = nmem_malloc(csvp->nmem, csvp->value_size);
82
83   csvp->field_char = '|';
84   csvp->record_char = '\n';
85   csvp->string_char = 0;    
86   csvp->root_element = nmem_strdup(csvp->nmem, "csv");
87   csvp->field_line = 1;
88   csvp->lower_case = 1;
89   csvp->max_nr_fields = 512;
90   csvp->nr_fields = 0;
91   /* csvp->field_names = 0; */ /*nmem_strdup(csvp->nmem, "a|b|c|d|e");*/
92
93   csvp->field_name 
94     = nmem_malloc(csvp->nmem, 
95                   sizeof(*(csvp->field_name)) * csvp->max_nr_fields);
96   for (i = 0; i < csvp->max_nr_fields; i++){
97     csvp->field_name[i] = 0; 
98   }
99
100   /* know field names from config file */
101   /*if (strlen(csvp->field_names))
102     yaz_log (YLOG_LOG, "CSV filter grs_config_csv field names");
103   */
104
105   yaz_log (YLOG_LOG, "Ended CSV filter grs_config_csv");
106 }
107
108
109 static data1_node *grs_read_csv (struct grs_read_info *gri)
110 {
111   data1_node *root_node = 0;
112   data1_node *node = 0;
113   struct csv_t *csvp = (struct csv_t *)gri->clientData;
114   int field_nr = 0; 
115   int end_of_record = 0;
116   int read_header = 0;
117   int read_bytes = 0;
118   char *cb = csvp->buf;
119   char *cv = csvp->value; 
120
121   yaz_log (YLOG_LOG, "Called CSV filter grs_read_csv");
122
123   /* if on start of first line, read header line for dynamic configure */ 
124   if(csvp->field_line && gri->offset == 0)
125     read_header = 1;
126
127   while (!end_of_record){
128
129 #if 0    
130     /* configure grs.csv filter with first line in file containing field 
131        name information */
132     if (read_header){
133       yaz_log (YLOG_LOG, "CSV filter grs_read_csv reading header line");
134       
135       /* create new memory for fieldname and value */
136       if (old_nr_fields < csvp->nr_fields){
137         yaz_log(YLOG_LOG, 
138                 "CSV filter grs_read_csv name:'%d' ", csvp->nr_fields);
139         old_nr_fields = csvp->nr_fields;
140         csvp->field_name[csvp->nr_fields] 
141           = nmem_malloc(csvp->nmem, csvp->name_size);
142         csvp->field_value[csvp->nr_fields] 
143           = nmem_malloc(csvp->nmem, csvp->value_size);
144
145         /* read buf and copy values to field_name[] */  
146         read_bytes = (*gri->readf)(gri->fh, csvp->buf, csvp->buf_size);
147        gri-> offset = (*gri->tellf)(gri->fh);
148         /* yaz_log(YLOG_LOG, "CSV filter grs_read_csv offset:'%d' ", offset); */
149         read_header = 0;
150       }
151     } else {
152       /* read buf and copy values to field_value[] */  
153       read_bytes = (*gri->readf)(gri->fh, csvp->buf, csvp->buf_size);
154       gri->offset = (*gri->tellf)(gri->fh);
155       yaz_log(YLOG_LOG, "CSV filter grs_read_csv offset:'%d' ", offset);
156     }
157     
158 #endif
159
160
161     /* read new buffer from file */  
162     read_bytes = (*gri->readf)(gri->fh, csvp->buf, csvp->buf_size);
163
164     yaz_log (YLOG_LOG, "CSV filter grs_read_csv read_bytes  %d", read_bytes);
165     yaz_log (YLOG_LOG, "CSV filter grs_read_csv csvp->buf %s", csvp->buf);
166
167     gri->offset = (*gri->tellf)(gri->fh);
168     yaz_log(YLOG_LOG, "CSV filter grs_read_csv gri->offset:'%d' ", 
169             (int)gri->offset);
170
171     /* work on buffer */
172     cb = csvp->buf;
173     while ((cb - csvp->buf < read_bytes)
174            && (cv - csvp->value < csvp->value_size)
175            && !end_of_record){
176
177       if (*cb == csvp->field_char){
178         /* if field finished */
179         *cv = '\0';
180         if (read_header){
181           /* read field names from header line */
182           if (csvp->nr_fields < csvp->max_nr_fields){
183             csvp->nr_fields++;
184               yaz_log (YLOG_LOG, "CSV filter grs_read_csv header %d %s", 
185                        field_nr, csvp->value);
186           } else {
187             yaz_log (YLOG_WARN, "CSV filter grs_read_csv header %d %s "
188                      "exceeds configured max number of fields %d", 
189                      field_nr, csvp->value, csvp->max_nr_fields);
190           }
191         } else {
192           /* process following value line fields */
193           if (field_nr < csvp->nr_fields){
194             /* less or qual fields number */
195             yaz_log (YLOG_LOG, "CSV filter grs_read_csv value %d %s", 
196                      field_nr, csvp->value);
197           } else {
198           /* too many fields */
199             yaz_log (YLOG_WARN, "CSV filter grs_read_csv value %d %s "
200                      "exceeds dynamic configured number of fields %d", 
201                      field_nr, csvp->value, csvp->nr_fields);
202           }
203           
204         }
205         cb++;
206         cv = csvp->value;
207         field_nr++;
208       } else if (*cb == csvp->record_char){
209         /* if record finished */
210         *cv = '\0';
211         cb++;
212         cv = csvp->value;
213         field_nr = 0;
214         if (read_header){
215           read_header = 0;
216           yaz_log (YLOG_LOG, "CSV filter grs_read_csv header end");
217         } else {
218           end_of_record = 1;
219           yaz_log (YLOG_LOG, "CSV filter grs_read_csv record end");
220         }
221       } else {
222         /* just plain char to be stored in value */
223         if (csvp->lower_case && read_header){
224           *cv = tolower(*cb);
225         } else {
226           *cv = *cb;
227         }
228          cb++;
229          cv++;
230       }
231     }
232   
233       
234     /* if (gri->endf)
235       (*gri->endf)(gri->fh, offset - 1);  */
236   }
237
238   /* try to build GRS node and document */
239   /*
240   root_node = data1_mk_root(gri->dh, gri->mem, cvsp->root_name);
241   node = data1_mk_node2(gri->dh, gri->mem, DATA1N_data, root_node);
242   node = data1_mk_tag(gri->dh, gri->mem, "pr_name_gn", 0, node);  
243   data1_mk_text_n(gri->dh, gri->mem, csvp->buf, read_bytes, node);
244   */
245   if (!root_node){
246     yaz_log (YLOG_WARN, "empty CSV record of type '%s' "
247              "near file offset %d "
248              "or missing abstract syntax file '%s.abs'",
249              csvp->root_element, (int)gri->offset, csvp->root_element);
250     return 0;
251   }
252
253   yaz_log (YLOG_LOG, "Ended CSV filter grs_read_csv");
254   return root_node;
255 }
256
257 static void *grs_init_csv(Res res, RecType recType)
258 {
259   yaz_log (YLOG_LOG, "Called CSV filter grs_init_csv");
260   NMEM m = nmem_create();
261   struct csv_t *csvp = (struct csv_t *) nmem_malloc(m, sizeof(*csvp));
262   csvp->nmem = m;
263   yaz_log (YLOG_LOG, "Ended CSV filter grs_init_csv");
264   return csvp;
265 }
266
267 static void grs_destroy_csv(void *clientData)
268 {
269   struct csv_t *csvp = (struct csv_t*) clientData;
270
271   yaz_log (YLOG_LOG, "Called CSV filter grs_destroy_csv");
272
273   nmem_destroy(csvp->nmem);
274   clientData = 0;
275
276   yaz_log (YLOG_LOG, "Ended CSV filter grs_destroy_csv");
277 }
278
279 static int grs_extract_csv(void *clientData, struct recExtractCtrl *ctrl)
280 {
281   int res;
282   /* struct csv_t *csvp = (struct csv_t*) clientData; */
283
284   yaz_log (YLOG_LOG, "Called CSV filter grs_extract_csv");
285   yaz_log (YLOG_LOG, "recExtractCtr fh     %d", (int)ctrl->fh);
286   yaz_log (YLOG_LOG, "recExtractCtr offset %d", (int)ctrl->offset);
287
288   res = zebra_grs_extract(clientData, ctrl, grs_read_csv);
289
290   yaz_log (YLOG_LOG, "recExtractCtr fh     %d", (int)ctrl->fh);
291   yaz_log (YLOG_LOG, "recExtractCtr offset %d", (int)ctrl->offset);
292   yaz_log (YLOG_LOG, "Ended CSV filter grs_extract_csv");
293
294   return res;
295 }
296
297 static int grs_retrieve_csv(void *clientData, struct recRetrieveCtrl *ctrl)
298 {
299   int res;
300   /* struct csv_t *csvp = (struct csv_t*) clientData; */
301   
302   yaz_log (YLOG_LOG, "Called CSV filter grs_retrieve_csv");
303   res = zebra_grs_retrieve(clientData, ctrl, grs_read_csv);
304   yaz_log (YLOG_LOG, "Ended CSV filter grs_retrieve_csv");
305
306   return res;
307 }
308
309 static struct recType grs_type_csv =
310 {
311     0,
312     "grs.csv",
313     grs_init_csv,
314     grs_config_csv,
315     grs_destroy_csv,
316     grs_extract_csv,
317     grs_retrieve_csv
318 };
319
320 RecType
321 #ifdef IDZEBRA_STATIC_GRS_CSV
322 idzebra_filter_grs_csv
323 #else
324 idzebra_filter
325 #endif
326
327 [] = {
328     &grs_type_csv,
329     0,
330 };