optimize for C source code
[idzebra-moved-to-github.git] / recctrl / csvread.c
1 /* $Id: csvread.c,v 1.3 2005-12-06 15:36:38 adam 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 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->field_name[csvp->nr_fields] 
184               = nmem_strdup(csvp->nmem, csvp->value);
185             
186             csvp->nr_fields++;
187             yaz_log (YLOG_LOG, "CSV filter grs_read_csv field %d name '%s'", 
188                        field_nr, csvp->value);
189           } else {
190             yaz_log (YLOG_WARN, "CSV filter grs_read_csv field %d name '%s' "
191                      "exceeds configured max number of fields %d", 
192                      field_nr, csvp->value, csvp->max_nr_fields);
193           }
194         } else {
195           /* process following value line fields */
196           if (field_nr < csvp->nr_fields){
197             /* less or qual fields number */
198             yaz_log (YLOG_LOG, "CSV filter grs_read_csv field %d %s: '%s'", 
199                      field_nr, csvp->field_name[field_nr], csvp->value);
200           } else {
201           /* too many fields */
202             yaz_log (YLOG_WARN, "CSV filter grs_read_csv field value %d %s "
203                      "exceeds dynamic configured number of fields %d", 
204                      field_nr, csvp->value, csvp->nr_fields);
205           }
206           
207         }
208         /* advance buffer and proceed to next field */
209         cb++;
210         cv = csvp->value;
211         field_nr++;
212       } else if (*cb == csvp->record_char){
213         /* if record finished */
214         /* advance buffer and proceed to record */
215         *cv = '\0';
216         cb++;
217         cv = csvp->value;
218         field_nr = 0;
219         if (read_header){
220           read_header = 0;
221           yaz_log (YLOG_LOG, "CSV filter grs_read_csv header end");
222         } else {
223           end_of_record = 1;
224           yaz_log (YLOG_LOG, "CSV filter grs_read_csv record end");
225         }
226       } else {
227         /* just plain char to be stored in value, no special action at all */
228         if (csvp->lower_case && read_header){
229           *cv = tolower(*cb);
230         } else {
231           *cv = *cb;
232         }
233          cb++;
234          cv++;
235       }
236     }
237   
238       
239     /* if (gri->endf)
240       (*gri->endf)(gri->fh, offset - 1);  */
241   }
242
243   /* try to build GRS node and document */
244   
245   root_node = data1_mk_root(gri->dh, gri->mem, csvp->root_element);
246   node = data1_mk_node2(gri->dh, gri->mem, DATA1N_data, root_node);
247   node = data1_mk_tag(gri->dh, gri->mem, "pr_name_gn", 0, node);  
248   data1_mk_text_n(gri->dh, gri->mem, csvp->buf, read_bytes, node);
249   
250   if (!root_node){
251     yaz_log (YLOG_WARN, "empty CSV record of type '%s' "
252              "near file offset %d "
253              "or missing abstract syntax file '%s.abs'",
254              csvp->root_element, (int)gri->offset, csvp->root_element);
255     return 0;
256   }
257
258   yaz_log (YLOG_LOG, "Ended CSV filter grs_read_csv");
259   return root_node;
260 }
261
262 static void *grs_init_csv(Res res, RecType recType)
263 {
264   NMEM m = nmem_create();
265   struct csv_t *csvp = (struct csv_t *) nmem_malloc(m, sizeof(*csvp));
266   yaz_log (YLOG_LOG, "Called CSV filter grs_init_csv");
267   csvp->nmem = m;
268   yaz_log (YLOG_LOG, "Ended CSV filter grs_init_csv");
269   return csvp;
270 }
271
272 static void grs_destroy_csv(void *clientData)
273 {
274   struct csv_t *csvp = (struct csv_t*) clientData;
275
276   yaz_log (YLOG_LOG, "Called CSV filter grs_destroy_csv");
277
278   nmem_destroy(csvp->nmem);
279   clientData = 0;
280
281   yaz_log (YLOG_LOG, "Ended CSV filter grs_destroy_csv");
282 }
283
284 static int grs_extract_csv(void *clientData, struct recExtractCtrl *ctrl)
285 {
286   int res;
287   /* struct csv_t *csvp = (struct csv_t*) clientData; */
288
289   yaz_log (YLOG_LOG, "Called CSV filter grs_extract_csv");
290   yaz_log (YLOG_LOG, "recExtractCtr fh     %d", (int)ctrl->fh);
291   yaz_log (YLOG_LOG, "recExtractCtr offset %d", (int)ctrl->offset);
292
293   res = zebra_grs_extract(clientData, ctrl, grs_read_csv);
294
295   yaz_log (YLOG_LOG, "recExtractCtr fh     %d", (int)ctrl->fh);
296   yaz_log (YLOG_LOG, "recExtractCtr offset %d", (int)ctrl->offset);
297   yaz_log (YLOG_LOG, "Ended CSV filter grs_extract_csv");
298
299   return res;
300 }
301
302 static int grs_retrieve_csv(void *clientData, struct recRetrieveCtrl *ctrl)
303 {
304   int res;
305   /* struct csv_t *csvp = (struct csv_t*) clientData; */
306   
307   yaz_log (YLOG_LOG, "Called CSV filter grs_retrieve_csv");
308   res = zebra_grs_retrieve(clientData, ctrl, grs_read_csv);
309   yaz_log (YLOG_LOG, "Ended CSV filter grs_retrieve_csv");
310
311   return res;
312 }
313
314 static struct recType grs_type_csv =
315 {
316     0,
317     "grs.csv",
318     grs_init_csv,
319     grs_config_csv,
320     grs_destroy_csv,
321     grs_extract_csv,
322     grs_retrieve_csv
323 };
324
325 RecType
326 #ifdef IDZEBRA_STATIC_GRS_CSV
327 idzebra_filter_grs_csv
328 #else
329 idzebra_filter
330 #endif
331
332 [] = {
333     &grs_type_csv,
334     0,
335 };