7868cf24b9dba1898a756422c6518e606ea4f1ef
[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)
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)
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 date_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   struct date_value dv;
142   Gedcom_ctxt self = (Gedcom_ctxt)(void_ptr_to_int(parent) + 1000);
143   dv = GEDCOM_DATE(parsed_value);
144   output(1, "Contents of the date_value:\n");
145   output(1, "  raw value: %s\n", raw_value);
146   output(1, "  type: %d\n", dv.type);
147   output(1, "  date1:\n");
148   output(1, "    calendar type: %d\n", dv.date1.cal);
149   output(1, "    day: %s\n", dv.date1.day_str);
150   output(1, "    month: %s\n", dv.date1.month_str);
151   output(1, "    year: %s\n", dv.date1.year_str);
152   output(1, "    date type: %d\n", dv.date1.type);
153   output(1, "    sdn1: %ld\n", dv.date1.sdn1);
154   output(1, "    sdn2: %ld\n", dv.date1.sdn2);
155   output(1, "  date2:\n");
156   output(1, "    calendar type: %d\n", dv.date2.cal);
157   output(1, "    day: %s\n", dv.date2.day_str);
158   output(1, "    month: %s\n", dv.date2.month_str);
159   output(1, "    year: %s\n", dv.date2.year_str);
160   output(1, "    date type: %d\n", dv.date2.type);
161   output(1, "    sdn1: %ld\n", dv.date2.sdn1);
162   output(1, "    sdn2: %ld\n", dv.date2.sdn2);
163   output(1, "  phrase: %s\n", dv.phrase);
164   return self;
165 }
166
167 Gedcom_ctxt age_start(Gedcom_elt elt, Gedcom_ctxt parent, int level,
168                       char *tag, char *raw_value,
169                       int tag_value, Gedcom_val parsed_value)
170 {
171   struct age_value age;
172   Gedcom_ctxt self = (Gedcom_ctxt)(void_ptr_to_int(parent) + 1000);
173   age = GEDCOM_AGE(parsed_value);
174   output(1, "Contents of the age_value:\n");
175   output(1, "  raw value: %s\n", raw_value);
176   output(1, "  type: %d\n", age.type);
177   output(1, "  modifier: %d\n", age.mod);
178   output(1, "  years: %d\n", age.years);
179   output(1, "  months: %d\n", age.months);
180   output(1, "  days: %d\n", age.days);
181   output(1, "  phrase: %s\n", age.phrase);
182   return self;
183 }
184
185 void default_cb(Gedcom_elt elt, Gedcom_ctxt ctxt, int level, char *tag,
186                 char *raw_value, int tag_value)
187 {
188   char   *converted = NULL;
189   int    conv_fails = 0;
190   if (raw_value)
191     converted = convert_utf8_to_locale(raw_value, &conv_fails);
192   output(0, "== %d %s (%d) %s (ctxt is %ld, conversion failures: %d)\n",
193          level, tag, tag_value, converted, void_ptr_to_int(ctxt), conv_fails);
194   total_conv_fails += conv_fails;
195 }
196
197 void subscribe_callbacks()
198 {
199   gedcom_subscribe_to_record(REC_HEAD, header_start, header_end);
200   gedcom_subscribe_to_record(REC_FAM,  family_start, family_end);
201   gedcom_subscribe_to_record(REC_INDI, rec_start, NULL);
202   gedcom_subscribe_to_record(REC_OBJE, rec_start, NULL);
203   gedcom_subscribe_to_record(REC_NOTE, note_start, NULL);
204   gedcom_subscribe_to_record(REC_REPO, rec_start, NULL);
205   gedcom_subscribe_to_record(REC_SOUR, rec_start, NULL);
206   gedcom_subscribe_to_record(REC_SUBN, rec_start, NULL);
207   gedcom_subscribe_to_record(REC_SUBM, submit_start, NULL);
208   gedcom_subscribe_to_record(REC_USER, rec_start, NULL);
209   gedcom_subscribe_to_element(ELT_HEAD_SOUR, source_start, source_end);
210   gedcom_subscribe_to_element(ELT_SOUR_DATA_EVEN_DATE,
211                               date_start, NULL);
212   gedcom_subscribe_to_element(ELT_SUB_EVT_DATE, date_start, NULL);
213   gedcom_subscribe_to_element(ELT_SUB_FAM_EVT_AGE, age_start, NULL);
214 }
215
216 void gedcom_message_handler(Gedcom_msg_type type, char *msg)
217 {
218   if (type == MESSAGE)
219     output(1, "MESSAGE: ");
220   else if (type == WARNING)
221     output(1, "WARNING: ");
222   else if (type == ERROR)
223     output(1, "ERROR: ");
224   output(1, "%s\n", msg);
225 }
226
227 int main(int argc, char* argv[])
228 {
229   Gedcom_err_mech mech = IMMED_FAIL;
230   int compat_enabled = 1;
231   int debug_level = 0;
232   int run_times   = 1;
233   int bogus       = 0;
234   int result      = 0;
235   char* outfilename = NULL;
236   char* file_name = NULL;
237
238   if (argc > 1) {
239     int i;
240     for (i=1; i<argc; i++) {
241       if (!strncmp(argv[i], "-da", 4))
242         debug_level = 2;
243       else if (!strncmp(argv[i], "-dg", 4))
244         debug_level = 1;
245       else if (!strncmp(argv[i], "-fi", 4))
246         mech = IMMED_FAIL;
247       else if (!strncmp(argv[i], "-fd", 4))
248         mech = DEFER_FAIL;
249       else if (!strncmp(argv[i], "-fn", 4))
250         mech = IGNORE_ERRORS;
251       else if (!strncmp(argv[i], "-nc", 4))
252         compat_enabled = 0;
253       else if (!strncmp(argv[i], "-h", 3)) {
254         show_help();
255         exit(1);
256       }
257       else if (!strncmp(argv[i], "-2", 3)) {
258         run_times = 2;
259       }
260       else if (!strncmp(argv[i], "-3", 3)) {
261         run_times = 3;
262       }
263       else if (!strncmp(argv[i], "-b", 3)) {
264         bogus = 1;
265       }
266       else if (!strncmp(argv[i], "-q", 3)) {
267         output_set_quiet(1);
268       }
269       else if (!strncmp(argv[i], "-o", 3)) {
270         i++;
271         if (i < argc) {
272           outfilename = argv[i];
273         }
274         else {
275           printf ("Missing output file name\n");
276           show_help();
277           exit(1);
278         }
279       }
280       else if (strncmp(argv[i], "-", 1)) {
281         file_name = argv[i];
282         break;
283       }
284       else {
285         printf ("Unrecognized option: %s\n", argv[i]);
286         show_help();
287         exit(1);
288       }
289     }
290   }
291   
292   if (!file_name) {
293     printf("No file name given\n");
294     show_help();
295     exit(1);
296   }
297
298   gedcom_init();
299   setlocale(LC_ALL, "");
300   gedcom_set_debug_level(debug_level, NULL);
301   gedcom_set_compat_handling(compat_enabled);
302   gedcom_set_error_handling(mech);
303   gedcom_set_message_handler(gedcom_message_handler);
304   gedcom_set_default_callback(default_cb);
305   
306   subscribe_callbacks();
307   output_open(outfilename);
308   if (bogus) {
309     output(0, "\n=== Parsing bogus file %s\n", BOGUS_FILE_NAME);
310     gedcom_parse_file(BOGUS_FILE_NAME);
311   }
312   while (run_times-- > 0) {
313     output(0, "\n=== Parsing file %s\n", simple_base_name(file_name));
314     result |= gedcom_parse_file(file_name);
315     output(0, "\n=== Total conversion failures: %d\n", total_conv_fails);
316   }
317   if (result == 0) {
318     output(1, "Parse succeeded\n");
319   }
320   else {
321     output(1, "Parse failed\n");
322   }
323   output_close();
324   return result;
325 }