Pass complete concatenated text in end callback.
[gedcom-parse.git] / t / src / standalone.c
1 /* Test program for the Gedcom library.
2    Copyright (C) 2001, 2002 The Genes Development Team
3    This file is part of the Gedcom parser library.
4    Contributed by Peter Verthez <Peter.Verthez@advalvas.be>, 2001.
5
6    The Gedcom parser library is free software; you can redistribute it
7    and/or modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The Gedcom parser library is distributed in the hope that it will be
12    useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the Gedcom parser library; if not, write to the
18    Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 /* $Id$ */
22 /* $Name$ */
23
24 #include "gedcom.h"
25 #include "output.h"
26 #include "portability.h"
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <locale.h>
31 #include <errno.h>
32 #include <iconv.h>
33 #include "utf8.h"
34
35 #define BOGUS_FILE_NAME "bogus.ged"
36 int total_conv_fails = 0;
37
38 void show_help ()
39 {
40   printf("gedcom-parse test program for libgedcom\n\n");
41   printf("Usage:  testgedcom [options] file\n");
42   printf("Options:\n");
43   printf("  -h    Show this help text\n");
44   printf("  -nc   Disable compatibility mode\n");
45   printf("  -fi   Fail immediately on errors\n");
46   printf("  -fd   Deferred fail on errors, but parse completely\n");
47   printf("  -fn   No fail on errors\n");
48   printf("  -dg   Debug setting: only libgedcom debug messages\n");
49   printf("  -da   Debug setting: libgedcom + yacc debug messages\n");
50   printf("  -2    Run the test parse 2 times instead of once\n");
51   printf("  -3    Run the test parse 3 times instead of once\n");
52   printf("  -b    Parse a bogus file (bogus.ged) before parsing the main file\n");
53   printf("  -q    No output to standard output\n");
54   printf("  -o <outfile>  File to generate output to (def. testgedcom.out)\n");
55 }
56
57 Gedcom_ctxt header_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
58                          char *raw_value, int tag_value,
59                          Gedcom_val parsed_value)
60 {
61   output(1, "Header start\n");
62   return (Gedcom_ctxt)1;
63 }
64
65 void header_end(Gedcom_rec rec, Gedcom_ctxt self, Gedcom_val parsed_value)
66 {
67   output(1, "Header end, context is %ld\n", void_ptr_to_int(self));
68 }
69
70 char family_xreftags[100][255];
71 int  family_nr = 1;
72
73 Gedcom_ctxt family_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
74                          char *raw_value, int tag_value,
75                          Gedcom_val parsed_value)
76 {
77   struct xref_value *xr = GEDCOM_XREF_PTR(xref);
78   output(1, "Family start, xref is %s\n", xr->string);
79   strcpy(family_xreftags[family_nr], xr->string);
80   xr->object = (Gedcom_ctxt)int_to_void_ptr(family_nr);
81   return (Gedcom_ctxt)int_to_void_ptr(family_nr++);
82 }
83
84 Gedcom_ctxt rec_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
85                       char *raw_value, int tag_value,
86                       Gedcom_val parsed_value)
87 {
88   char* xref_str = NULL;
89   if (! GEDCOM_IS_NULL(xref))
90     xref_str = GEDCOM_XREF_PTR(xref)->string;
91   output(1, "Rec %s start, xref is %s\n", tag, xref_str);
92   return (Gedcom_ctxt)int_to_void_ptr(tag_value);
93 }
94
95 Gedcom_ctxt note_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
96                        char *raw_value, int tag_value,
97                        Gedcom_val parsed_value)
98 {
99   output(1, "== %d %s (%d) %s (xref is %s)\n",
100          level, tag, tag_value, GEDCOM_STRING(parsed_value),
101          GEDCOM_XREF_PTR(xref)->string);
102   return (Gedcom_ctxt)int_to_void_ptr(tag_value);
103 }
104
105 void family_end(Gedcom_rec rec, Gedcom_ctxt self, Gedcom_val parsed_value)
106 {
107   output(1, "Family end, xref is %s\n",
108          family_xreftags[void_ptr_to_int(self)]);
109 }
110
111 Gedcom_ctxt submit_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
112                          char *raw_value, int tag_value,
113                          Gedcom_val parsed_value)
114 {
115   output(1, "Submitter, xref is %s\n", GEDCOM_XREF_PTR(xref)->string);
116   return (Gedcom_ctxt)10000;
117 }
118
119 Gedcom_ctxt source_start(Gedcom_elt elt, Gedcom_ctxt parent, int level,
120                          char *tag, char* raw_value,
121                          int tag_value, Gedcom_val parsed_value)
122 {
123   Gedcom_ctxt self = (Gedcom_ctxt)(void_ptr_to_int(parent) + 1000);
124   output(1, "Source is %s (ctxt is %ld, parent is %ld)\n",
125          GEDCOM_STRING(parsed_value), void_ptr_to_int(self),
126          void_ptr_to_int(parent));
127   return self;
128 }
129
130 void source_end(Gedcom_elt elt, Gedcom_ctxt parent, Gedcom_ctxt self,
131                 Gedcom_val parsed_value)
132 {
133   output(1, "Source context %ld in parent %ld\n",
134          void_ptr_to_int(self), void_ptr_to_int(parent));
135 }
136
137 Gedcom_ctxt head_note_start(Gedcom_elt elt, Gedcom_ctxt parent, int level,
138                             char *tag, char* raw_value,
139                             int tag_value, Gedcom_val parsed_value)
140 {
141   Gedcom_ctxt self = (Gedcom_ctxt)(void_ptr_to_int(parent));
142   output(1, "Note: %s (ctxt is %ld, parent is %ld)\n",
143          GEDCOM_STRING(parsed_value), void_ptr_to_int(self),
144          void_ptr_to_int(parent));
145   return self;
146 }
147
148 void head_note_end(Gedcom_elt elt, Gedcom_ctxt parent, Gedcom_ctxt self,
149                    Gedcom_val parsed_value)
150 {
151   output(1, "Complete note:\n%s\n", GEDCOM_STRING(parsed_value));
152 }
153
154 Gedcom_ctxt date_start(Gedcom_elt elt, Gedcom_ctxt parent, int level,
155                        char *tag, char* raw_value,
156                        int tag_value, Gedcom_val parsed_value)
157 {
158   struct date_value dv;
159   Gedcom_ctxt self = (Gedcom_ctxt)(void_ptr_to_int(parent) + 1000);
160   dv = GEDCOM_DATE(parsed_value);
161   output(1, "Contents of the date_value:\n");
162   output(1, "  raw value: %s\n", raw_value);
163   output(1, "  type: %d\n", dv.type);
164   output(1, "  date1:\n");
165   output(1, "    calendar type: %d\n", dv.date1.cal);
166   output(1, "    day: %s\n", dv.date1.day_str);
167   output(1, "    month: %s\n", dv.date1.month_str);
168   output(1, "    year: %s\n", dv.date1.year_str);
169   output(1, "    date type: %d\n", dv.date1.type);
170   output(1, "    sdn1: %ld\n", dv.date1.sdn1);
171   output(1, "    sdn2: %ld\n", dv.date1.sdn2);
172   output(1, "  date2:\n");
173   output(1, "    calendar type: %d\n", dv.date2.cal);
174   output(1, "    day: %s\n", dv.date2.day_str);
175   output(1, "    month: %s\n", dv.date2.month_str);
176   output(1, "    year: %s\n", dv.date2.year_str);
177   output(1, "    date type: %d\n", dv.date2.type);
178   output(1, "    sdn1: %ld\n", dv.date2.sdn1);
179   output(1, "    sdn2: %ld\n", dv.date2.sdn2);
180   output(1, "  phrase: %s\n", dv.phrase);
181   return self;
182 }
183
184 Gedcom_ctxt age_start(Gedcom_elt elt, Gedcom_ctxt parent, int level,
185                       char *tag, char *raw_value,
186                       int tag_value, Gedcom_val parsed_value)
187 {
188   struct age_value age;
189   Gedcom_ctxt self = (Gedcom_ctxt)(void_ptr_to_int(parent) + 1000);
190   age = GEDCOM_AGE(parsed_value);
191   output(1, "Contents of the age_value:\n");
192   output(1, "  raw value: %s\n", raw_value);
193   output(1, "  type: %d\n", age.type);
194   output(1, "  modifier: %d\n", age.mod);
195   output(1, "  years: %d\n", age.years);
196   output(1, "  months: %d\n", age.months);
197   output(1, "  days: %d\n", age.days);
198   output(1, "  phrase: %s\n", age.phrase);
199   return self;
200 }
201
202 void default_cb(Gedcom_elt elt, Gedcom_ctxt ctxt, int level, char *tag,
203                 char *raw_value, int tag_value)
204 {
205   char   *converted = NULL;
206   int    conv_fails = 0;
207   if (raw_value)
208     converted = convert_utf8_to_locale(raw_value, &conv_fails);
209   output(0, "== %d %s (%d) %s (ctxt is %ld, conversion failures: %d)\n",
210          level, tag, tag_value, converted, void_ptr_to_int(ctxt), conv_fails);
211   total_conv_fails += conv_fails;
212 }
213
214 void subscribe_callbacks()
215 {
216   gedcom_subscribe_to_record(REC_HEAD, header_start, header_end);
217   gedcom_subscribe_to_record(REC_FAM,  family_start, family_end);
218   gedcom_subscribe_to_record(REC_INDI, rec_start, NULL);
219   gedcom_subscribe_to_record(REC_OBJE, rec_start, NULL);
220   gedcom_subscribe_to_record(REC_NOTE, note_start, NULL);
221   gedcom_subscribe_to_record(REC_REPO, rec_start, NULL);
222   gedcom_subscribe_to_record(REC_SOUR, rec_start, NULL);
223   gedcom_subscribe_to_record(REC_SUBN, rec_start, NULL);
224   gedcom_subscribe_to_record(REC_SUBM, submit_start, NULL);
225   gedcom_subscribe_to_record(REC_USER, rec_start, NULL);
226   gedcom_subscribe_to_element(ELT_HEAD_SOUR, source_start, source_end);
227   gedcom_subscribe_to_element(ELT_HEAD_NOTE, head_note_start, head_note_end);
228   gedcom_subscribe_to_element(ELT_SOUR_DATA_EVEN_DATE,
229                               date_start, NULL);
230   gedcom_subscribe_to_element(ELT_SUB_EVT_DATE, date_start, NULL);
231   gedcom_subscribe_to_element(ELT_SUB_FAM_EVT_AGE, age_start, NULL);
232 }
233
234 void gedcom_message_handler(Gedcom_msg_type type, char *msg)
235 {
236   if (type == MESSAGE)
237     output(1, "MESSAGE: ");
238   else if (type == WARNING)
239     output(1, "WARNING: ");
240   else if (type == ERROR)
241     output(1, "ERROR: ");
242   output(1, "%s\n", msg);
243 }
244
245 int main(int argc, char* argv[])
246 {
247   Gedcom_err_mech mech = IMMED_FAIL;
248   int compat_enabled = 1;
249   int debug_level = 0;
250   int run_times   = 1;
251   int bogus       = 0;
252   int result      = 0;
253   char* outfilename = NULL;
254   char* file_name = NULL;
255
256   if (argc > 1) {
257     int i;
258     for (i=1; i<argc; i++) {
259       if (!strncmp(argv[i], "-da", 4))
260         debug_level = 2;
261       else if (!strncmp(argv[i], "-dg", 4))
262         debug_level = 1;
263       else if (!strncmp(argv[i], "-fi", 4))
264         mech = IMMED_FAIL;
265       else if (!strncmp(argv[i], "-fd", 4))
266         mech = DEFER_FAIL;
267       else if (!strncmp(argv[i], "-fn", 4))
268         mech = IGNORE_ERRORS;
269       else if (!strncmp(argv[i], "-nc", 4))
270         compat_enabled = 0;
271       else if (!strncmp(argv[i], "-h", 3)) {
272         show_help();
273         exit(1);
274       }
275       else if (!strncmp(argv[i], "-2", 3)) {
276         run_times = 2;
277       }
278       else if (!strncmp(argv[i], "-3", 3)) {
279         run_times = 3;
280       }
281       else if (!strncmp(argv[i], "-b", 3)) {
282         bogus = 1;
283       }
284       else if (!strncmp(argv[i], "-q", 3)) {
285         output_set_quiet(1);
286       }
287       else if (!strncmp(argv[i], "-o", 3)) {
288         i++;
289         if (i < argc) {
290           outfilename = argv[i];
291         }
292         else {
293           printf ("Missing output file name\n");
294           show_help();
295           exit(1);
296         }
297       }
298       else if (strncmp(argv[i], "-", 1)) {
299         file_name = argv[i];
300         break;
301       }
302       else {
303         printf ("Unrecognized option: %s\n", argv[i]);
304         show_help();
305         exit(1);
306       }
307     }
308   }
309   
310   if (!file_name) {
311     printf("No file name given\n");
312     show_help();
313     exit(1);
314   }
315
316   gedcom_init();
317   setlocale(LC_ALL, "");
318   gedcom_set_debug_level(debug_level, NULL);
319   gedcom_set_compat_handling(compat_enabled);
320   gedcom_set_error_handling(mech);
321   gedcom_set_message_handler(gedcom_message_handler);
322   gedcom_set_default_callback(default_cb);
323   
324   subscribe_callbacks();
325   output_open(outfilename);
326   if (bogus) {
327     output(0, "\n=== Parsing bogus file %s\n", BOGUS_FILE_NAME);
328     gedcom_parse_file(BOGUS_FILE_NAME);
329   }
330   while (run_times-- > 0) {
331     output(0, "\n=== Parsing file %s\n", simple_base_name(file_name));
332     result |= gedcom_parse_file(file_name);
333     output(0, "\n=== Total conversion failures: %d\n", total_conv_fails);
334   }
335   if (result == 0) {
336     output(1, "Parse succeeded\n");
337   }
338   else {
339     output(1, "Parse failed\n");
340   }
341   output_close();
342   return result;
343 }