Added compatibility for PAF 4.
[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 "utf8tools.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 #define MAXFAMILY 100
71 char family_xreftags[MAXFAMILY][255];
72 int  family_nr = 1;
73
74 Gedcom_ctxt family_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
75                          char *raw_value, int tag_value,
76                          Gedcom_val parsed_value)
77 {
78   struct xref_value *xr = GEDCOM_XREF_PTR(xref);
79   output(1, "Family start, xref is %s\n", xr->string);
80   if (family_nr < MAXFAMILY) {
81     strcpy(family_xreftags[family_nr], xr->string);
82   }
83   xr->object = (Gedcom_ctxt)int_to_void_ptr(family_nr);
84   return (Gedcom_ctxt)int_to_void_ptr(family_nr++);
85 }
86
87 Gedcom_ctxt rec_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
88                       char *raw_value, int tag_value,
89                       Gedcom_val parsed_value)
90 {
91   char* xref_str = NULL;
92   if (! GEDCOM_IS_NULL(xref))
93     xref_str = GEDCOM_XREF_PTR(xref)->string;
94   output(1, "Rec %s start, xref is %s\n", tag, xref_str);
95   return (Gedcom_ctxt)int_to_void_ptr(tag_value);
96 }
97
98 Gedcom_ctxt note_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
99                        char *raw_value, int tag_value,
100                        Gedcom_val parsed_value)
101 {
102   output(1, "== %d %s (%d) %s (xref is %s)\n",
103          level, tag, tag_value, GEDCOM_STRING(parsed_value),
104          GEDCOM_XREF_PTR(xref)->string);
105   return (Gedcom_ctxt)int_to_void_ptr(tag_value);
106 }
107
108 void family_end(Gedcom_rec rec, Gedcom_ctxt self, Gedcom_val parsed_value)
109 {
110   char* family_xref = "<NOTSAVED>";
111   int   family_nr = void_ptr_to_int(self);
112   if (family_nr < MAXFAMILY)
113     family_xref = family_xreftags[void_ptr_to_int(self)];
114   output(1, "Family end, xref is %s\n", family_xref);
115 }
116
117 Gedcom_ctxt submit_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
118                          char *raw_value, int tag_value,
119                          Gedcom_val parsed_value)
120 {
121   output(1, "Submitter, xref is %s\n", GEDCOM_XREF_PTR(xref)->string);
122   return (Gedcom_ctxt)10000;
123 }
124
125 Gedcom_ctxt source_start(Gedcom_elt elt, Gedcom_ctxt parent, int level,
126                          char *tag, char* raw_value,
127                          int tag_value, Gedcom_val parsed_value)
128 {
129   Gedcom_ctxt self = (Gedcom_ctxt)(void_ptr_to_int(parent) + 1000);
130   output(1, "Source is %s (ctxt is %ld, parent is %ld)\n",
131          GEDCOM_STRING(parsed_value), void_ptr_to_int(self),
132          void_ptr_to_int(parent));
133   return self;
134 }
135
136 void source_end(Gedcom_elt elt, Gedcom_ctxt parent, Gedcom_ctxt self,
137                 Gedcom_val parsed_value)
138 {
139   output(1, "Source context %ld in parent %ld\n",
140          void_ptr_to_int(self), void_ptr_to_int(parent));
141 }
142
143 Gedcom_ctxt head_note_start(Gedcom_elt elt, Gedcom_ctxt parent, int level,
144                             char *tag, char* raw_value,
145                             int tag_value, Gedcom_val parsed_value)
146 {
147   Gedcom_ctxt self = (Gedcom_ctxt)(void_ptr_to_int(parent));
148   output(1, "Note: %s (ctxt is %ld, parent is %ld)\n",
149          GEDCOM_STRING(parsed_value), void_ptr_to_int(self),
150          void_ptr_to_int(parent));
151   return self;
152 }
153
154 void head_note_end(Gedcom_elt elt, Gedcom_ctxt parent, Gedcom_ctxt self,
155                    Gedcom_val parsed_value)
156 {
157   output(1, "Complete note:\n%s\n", GEDCOM_STRING(parsed_value));
158 }
159
160 Gedcom_ctxt date_start(Gedcom_elt elt, Gedcom_ctxt parent, int level,
161                        char *tag, char* raw_value,
162                        int tag_value, Gedcom_val parsed_value)
163 {
164   struct date_value dv;
165   Gedcom_ctxt self = (Gedcom_ctxt)(void_ptr_to_int(parent) + 1000);
166   dv = GEDCOM_DATE(parsed_value);
167   output(1, "Contents of the date_value:\n");
168   output(1, "  raw value: %s\n", raw_value);
169   output(1, "  type: %d\n", dv.type);
170   output(1, "  date1:\n");
171   output(1, "    calendar type: %d\n", dv.date1.cal);
172   output(1, "    day: %s\n", dv.date1.day_str);
173   output(1, "    month: %s\n", dv.date1.month_str);
174   output(1, "    year: %s\n", dv.date1.year_str);
175   output(1, "    date type: %d\n", dv.date1.type);
176   output(1, "    sdn1: %ld\n", dv.date1.sdn1);
177   output(1, "    sdn2: %ld\n", dv.date1.sdn2);
178   output(1, "  date2:\n");
179   output(1, "    calendar type: %d\n", dv.date2.cal);
180   output(1, "    day: %s\n", dv.date2.day_str);
181   output(1, "    month: %s\n", dv.date2.month_str);
182   output(1, "    year: %s\n", dv.date2.year_str);
183   output(1, "    date type: %d\n", dv.date2.type);
184   output(1, "    sdn1: %ld\n", dv.date2.sdn1);
185   output(1, "    sdn2: %ld\n", dv.date2.sdn2);
186   output(1, "  phrase: %s\n", dv.phrase);
187   return self;
188 }
189
190 Gedcom_ctxt age_start(Gedcom_elt elt, Gedcom_ctxt parent, int level,
191                       char *tag, char *raw_value,
192                       int tag_value, Gedcom_val parsed_value)
193 {
194   struct age_value age;
195   Gedcom_ctxt self = (Gedcom_ctxt)(void_ptr_to_int(parent) + 1000);
196   age = GEDCOM_AGE(parsed_value);
197   output(1, "Contents of the age_value:\n");
198   output(1, "  raw value: %s\n", raw_value);
199   output(1, "  type: %d\n", age.type);
200   output(1, "  modifier: %d\n", age.mod);
201   output(1, "  years: %d\n", age.years);
202   output(1, "  months: %d\n", age.months);
203   output(1, "  days: %d\n", age.days);
204   output(1, "  phrase: %s\n", age.phrase);
205   return self;
206 }
207
208 void default_cb(Gedcom_elt elt, Gedcom_ctxt ctxt, int level, char *tag,
209                 char *raw_value, int tag_value)
210 {
211   char   *converted = NULL;
212   int    conv_fails = 0;
213   if (raw_value)
214     converted = convert_utf8_to_locale(raw_value, &conv_fails);
215   output(0, "== %d %s (%d) %s (ctxt is %ld, conversion failures: %d)\n",
216          level, tag, tag_value, converted, void_ptr_to_int(ctxt), conv_fails);
217   total_conv_fails += conv_fails;
218 }
219
220 void subscribe_callbacks()
221 {
222   gedcom_subscribe_to_record(REC_HEAD, header_start, header_end);
223   gedcom_subscribe_to_record(REC_FAM,  family_start, family_end);
224   gedcom_subscribe_to_record(REC_INDI, rec_start, NULL);
225   gedcom_subscribe_to_record(REC_OBJE, rec_start, NULL);
226   gedcom_subscribe_to_record(REC_NOTE, note_start, NULL);
227   gedcom_subscribe_to_record(REC_REPO, rec_start, NULL);
228   gedcom_subscribe_to_record(REC_SOUR, rec_start, NULL);
229   gedcom_subscribe_to_record(REC_SUBN, rec_start, NULL);
230   gedcom_subscribe_to_record(REC_SUBM, submit_start, NULL);
231   gedcom_subscribe_to_record(REC_USER, rec_start, NULL);
232   gedcom_subscribe_to_element(ELT_HEAD_SOUR, source_start, source_end);
233   gedcom_subscribe_to_element(ELT_HEAD_NOTE, head_note_start, head_note_end);
234   gedcom_subscribe_to_element(ELT_SOUR_DATA_EVEN_DATE,
235                               date_start, NULL);
236   gedcom_subscribe_to_element(ELT_SUB_EVT_DATE, date_start, NULL);
237   gedcom_subscribe_to_element(ELT_SUB_FAM_EVT_AGE, age_start, NULL);
238 }
239
240 void gedcom_message_handler(Gedcom_msg_type type, char *msg)
241 {
242   if (type == MESSAGE)
243     output(1, "MESSAGE: ");
244   else if (type == WARNING)
245     output(1, "WARNING: ");
246   else if (type == ERROR)
247     output(1, "ERROR: ");
248   output(1, "%s\n", msg);
249 }
250
251 int main(int argc, char* argv[])
252 {
253   Gedcom_err_mech mech = IMMED_FAIL;
254   int compat_enabled = 1;
255   int debug_level = 0;
256   int run_times   = 1;
257   int bogus       = 0;
258   int result      = 0;
259   char* outfilename = NULL;
260   char* file_name = NULL;
261
262   if (argc > 1) {
263     int i;
264     for (i=1; i<argc; i++) {
265       if (!strncmp(argv[i], "-da", 4))
266         debug_level = 2;
267       else if (!strncmp(argv[i], "-dg", 4))
268         debug_level = 1;
269       else if (!strncmp(argv[i], "-fi", 4))
270         mech = IMMED_FAIL;
271       else if (!strncmp(argv[i], "-fd", 4))
272         mech = DEFER_FAIL;
273       else if (!strncmp(argv[i], "-fn", 4))
274         mech = IGNORE_ERRORS;
275       else if (!strncmp(argv[i], "-nc", 4))
276         compat_enabled = 0;
277       else if (!strncmp(argv[i], "-h", 3)) {
278         show_help();
279         exit(1);
280       }
281       else if (!strncmp(argv[i], "-2", 3)) {
282         run_times = 2;
283       }
284       else if (!strncmp(argv[i], "-3", 3)) {
285         run_times = 3;
286       }
287       else if (!strncmp(argv[i], "-b", 3)) {
288         bogus = 1;
289       }
290       else if (!strncmp(argv[i], "-q", 3)) {
291         output_set_quiet(1);
292       }
293       else if (!strncmp(argv[i], "-o", 3)) {
294         i++;
295         if (i < argc) {
296           outfilename = argv[i];
297         }
298         else {
299           printf ("Missing output file name\n");
300           show_help();
301           exit(1);
302         }
303       }
304       else if (strncmp(argv[i], "-", 1)) {
305         file_name = argv[i];
306         break;
307       }
308       else {
309         printf ("Unrecognized option: %s\n", argv[i]);
310         show_help();
311         exit(1);
312       }
313     }
314   }
315   
316   if (!file_name) {
317     printf("No file name given\n");
318     show_help();
319     exit(1);
320   }
321
322   gedcom_init();
323   setlocale(LC_ALL, "");
324   gedcom_set_debug_level(debug_level, NULL);
325   gedcom_set_compat_handling(compat_enabled);
326   gedcom_set_error_handling(mech);
327   gedcom_set_message_handler(gedcom_message_handler);
328   gedcom_set_default_callback(default_cb);
329   
330   subscribe_callbacks();
331   output_open(outfilename);
332   if (bogus) {
333     output(0, "\n=== Parsing bogus file %s\n", BOGUS_FILE_NAME);
334     gedcom_parse_file(BOGUS_FILE_NAME);
335   }
336   while (run_times-- > 0) {
337     output(0, "\n=== Parsing file %s\n", simple_base_name(file_name));
338     result |= gedcom_parse_file(file_name);
339     output(0, "\n=== Total conversion failures: %d\n", total_conv_fails);
340   }
341   if (result == 0) {
342     output(1, "Parse succeeded\n");
343   }
344   else {
345     output(1, "Parse failed\n");
346   }
347   output_close();
348   return result;
349 }