Restructure output from tests.
[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 <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <locale.h>
30 #include <errno.h>
31 #include <iconv.h>
32 #include "utf8-locale.h"
33
34 #define BOGUS_FILE_NAME "Makefile.am"
35 int total_conv_fails = 0;
36
37 void show_help ()
38 {
39   printf("gedcom-parse test program for libgedcom\n\n");
40   printf("Usage:  testgedcom [options] file\n");
41   printf("Options:\n");
42   printf("  -h    Show this help text\n");
43   printf("  -nc   Disable compatibility mode\n");
44   printf("  -fi   Fail immediately on errors\n");
45   printf("  -fd   Deferred fail on errors, but parse completely\n");
46   printf("  -fn   No fail on errors\n");
47   printf("  -dg   Debug setting: only libgedcom debug messages\n");
48   printf("  -da   Debug setting: libgedcom + yacc debug messages\n");
49   printf("  -2    Run the test parse 2 times instead of once\n");
50   printf("  -3    Run the test parse 3 times instead of once\n");
51   printf("  -b    Parse a bogus file before parsing the main file\n");
52   printf("  -q    No output to standard output\n");
53   printf("  -o <outfile>  File to generate output to (def. testgedcom.out)\n");
54 }
55
56 Gedcom_ctxt header_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
57                          char *raw_value, int tag_value,
58                          Gedcom_val parsed_value)
59 {
60   output(1, "Header start\n");
61   return (Gedcom_ctxt)1;
62 }
63
64 void header_end(Gedcom_rec rec, Gedcom_ctxt self)
65 {
66   output(1, "Header end, context is %d\n", (int)self);
67 }
68
69 char family_xreftags[100][255];
70 int  family_nr = 1;
71
72 Gedcom_ctxt family_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
73                          char *raw_value, int tag_value,
74                          Gedcom_val parsed_value)
75 {
76   struct xref_value *xr = GEDCOM_XREF_PTR(xref);
77   output(1, "Family start, xref is %s\n", xr->string);
78   strcpy(family_xreftags[family_nr], xr->string);
79   xr->object = (Gedcom_ctxt)family_nr;
80   return (Gedcom_ctxt)(family_nr++);
81 }
82
83 Gedcom_ctxt rec_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
84                       char *raw_value, int tag_value,
85                       Gedcom_val parsed_value)
86 {
87   char* xref_str = NULL;
88   if (! GEDCOM_IS_NULL(xref))
89     xref_str = GEDCOM_XREF_PTR(xref)->string;
90   output(1, "Rec %s start, xref is %s\n", tag, xref_str);
91   return (Gedcom_ctxt)tag_value;
92 }
93
94 Gedcom_ctxt note_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
95                        char *raw_value, int tag_value,
96                        Gedcom_val parsed_value)
97 {
98   output(1, "== %d %s (%d) %s (xref is %s)\n",
99          level, tag, tag_value, GEDCOM_STRING(parsed_value),
100          GEDCOM_XREF_PTR(xref)->string);
101   return (Gedcom_ctxt)tag_value;
102 }
103
104 void family_end(Gedcom_rec rec, Gedcom_ctxt self)
105 {
106   output(1, "Family end, xref is %s\n", family_xreftags[(int)self]);
107 }
108
109 Gedcom_ctxt submit_start(Gedcom_rec rec, int level, Gedcom_val xref, char *tag,
110                          char *raw_value, int tag_value,
111                          Gedcom_val parsed_value)
112 {
113   output(1, "Submitter, xref is %s\n", GEDCOM_XREF_PTR(xref)->string);
114   return (Gedcom_ctxt)10000;
115 }
116
117 Gedcom_ctxt source_start(Gedcom_elt elt, Gedcom_ctxt parent, int level,
118                          char *tag, char* raw_value,
119                          int tag_value, Gedcom_val parsed_value)
120 {
121   Gedcom_ctxt self = (Gedcom_ctxt)((int) parent + 1000);
122   output(1, "Source is %s (ctxt is %d, parent is %d)\n",
123          GEDCOM_STRING(parsed_value), (int) self, (int) parent);
124   return self;
125 }
126
127 void source_end(Gedcom_elt elt, Gedcom_ctxt parent, Gedcom_ctxt self,
128                 Gedcom_val parsed_value)
129 {
130   output(1, "Source context %d in parent %d\n", (int)self, (int)parent);
131 }
132
133 Gedcom_ctxt date_start(Gedcom_elt elt, Gedcom_ctxt parent, int level,
134                        char *tag, char* raw_value,
135                        int tag_value, Gedcom_val parsed_value)
136 {
137   struct date_value dv;
138   Gedcom_ctxt self = (Gedcom_ctxt)((int) parent + 1000);
139   dv = GEDCOM_DATE(parsed_value);
140   output(1, "Contents of the date_value:\n");
141   output(1, "  raw value: %s\n", raw_value);
142   output(1, "  type: %d\n", dv.type);
143   output(1, "  date1:\n");
144   output(1, "    calendar type: %d\n", dv.date1.cal);
145   output(1, "    day: %s\n", dv.date1.day_str);
146   output(1, "    month: %s\n", dv.date1.month_str);
147   output(1, "    year: %s\n", dv.date1.year_str);
148   output(1, "    date type: %d\n", dv.date1.type);
149   output(1, "    sdn1: %ld\n", dv.date1.sdn1);
150   output(1, "    sdn2: %ld\n", dv.date1.sdn2);
151   output(1, "  date2:\n");
152   output(1, "    calendar type: %d\n", dv.date2.cal);
153   output(1, "    day: %s\n", dv.date2.day_str);
154   output(1, "    month: %s\n", dv.date2.month_str);
155   output(1, "    year: %s\n", dv.date2.year_str);
156   output(1, "    date type: %d\n", dv.date2.type);
157   output(1, "    sdn1: %ld\n", dv.date2.sdn1);
158   output(1, "    sdn2: %ld\n", dv.date2.sdn2);
159   output(1, "  phrase: %s\n", dv.phrase);
160   return self;
161 }
162
163 Gedcom_ctxt age_start(Gedcom_elt elt, Gedcom_ctxt parent, int level,
164                       char *tag, char *raw_value,
165                       int tag_value, Gedcom_val parsed_value)
166 {
167   struct age_value age;
168   Gedcom_ctxt self = (Gedcom_ctxt)((int) parent + 1000);
169   age = GEDCOM_AGE(parsed_value);
170   output(1, "Contents of the age_value:\n");
171   output(1, "  raw value: %s\n", raw_value);
172   output(1, "  type: %d\n", age.type);
173   output(1, "  modifier: %d\n", age.mod);
174   output(1, "  years: %d\n", age.years);
175   output(1, "  months: %d\n", age.months);
176   output(1, "  days: %d\n", age.days);
177   output(1, "  phrase: %s\n", age.phrase);
178   return self;
179 }
180
181 void default_cb(Gedcom_elt elt, Gedcom_ctxt ctxt, int level, char *tag,
182                 char *raw_value, int tag_value)
183 {
184   char   *converted = NULL;
185   int    conv_fails = 0;
186   if (raw_value)
187     converted = convert_utf8_to_locale(raw_value, &conv_fails);
188   output(0, "== %d %s (%d) %s (ctxt is %d, conversion failures: %d)\n",
189          level, tag, tag_value, converted, (int)ctxt, conv_fails);
190   total_conv_fails += conv_fails;
191 }
192
193 void subscribe_callbacks()
194 {
195   gedcom_subscribe_to_record(REC_HEAD, header_start, header_end);
196   gedcom_subscribe_to_record(REC_FAM,  family_start, family_end);
197   gedcom_subscribe_to_record(REC_INDI, rec_start, NULL);
198   gedcom_subscribe_to_record(REC_OBJE, rec_start, NULL);
199   gedcom_subscribe_to_record(REC_NOTE, note_start, NULL);
200   gedcom_subscribe_to_record(REC_REPO, rec_start, NULL);
201   gedcom_subscribe_to_record(REC_SOUR, rec_start, NULL);
202   gedcom_subscribe_to_record(REC_SUBN, rec_start, NULL);
203   gedcom_subscribe_to_record(REC_SUBM, submit_start, NULL);
204   gedcom_subscribe_to_record(REC_USER, rec_start, NULL);
205   gedcom_subscribe_to_element(ELT_HEAD_SOUR, source_start, source_end);
206   gedcom_subscribe_to_element(ELT_SOUR_DATA_EVEN_DATE,
207                               date_start, NULL);
208   gedcom_subscribe_to_element(ELT_SUB_EVT_DATE, date_start, NULL);
209   gedcom_subscribe_to_element(ELT_SUB_FAM_EVT_AGE, age_start, NULL);
210 }
211
212 void gedcom_message_handler(Gedcom_msg_type type, char *msg)
213 {
214   if (type == MESSAGE)
215     output(1, "MESSAGE: ");
216   else if (type == WARNING)
217     output(1, "WARNING: ");
218   else if (type == ERROR)
219     output(1, "ERROR: ");
220   output(1, "%s\n", msg);
221 }
222
223 int main(int argc, char* argv[])
224 {
225   Gedcom_err_mech mech = IMMED_FAIL;
226   int compat_enabled = 1;
227   int debug_level = 0;
228   int run_times   = 1;
229   int bogus       = 0;
230   int result      = 0;
231   char* outfilename = NULL;
232   char* file_name = NULL;
233
234   if (argc > 1) {
235     int i;
236     for (i=1; i<argc; i++) {
237       if (!strncmp(argv[i], "-da", 4))
238         debug_level = 2;
239       else if (!strncmp(argv[i], "-dg", 4))
240         debug_level = 1;
241       else if (!strncmp(argv[i], "-fi", 4))
242         mech = IMMED_FAIL;
243       else if (!strncmp(argv[i], "-fd", 4))
244         mech = DEFER_FAIL;
245       else if (!strncmp(argv[i], "-fn", 4))
246         mech = IGNORE_ERRORS;
247       else if (!strncmp(argv[i], "-nc", 4))
248         compat_enabled = 0;
249       else if (!strncmp(argv[i], "-h", 3)) {
250         show_help();
251         exit(1);
252       }
253       else if (!strncmp(argv[i], "-2", 3)) {
254         run_times = 2;
255       }
256       else if (!strncmp(argv[i], "-3", 3)) {
257         run_times = 3;
258       }
259       else if (!strncmp(argv[i], "-b", 3)) {
260         bogus = 1;
261       }
262       else if (!strncmp(argv[i], "-q", 3)) {
263         output_set_quiet(1);
264       }
265       else if (!strncmp(argv[i], "-o", 3)) {
266         i++;
267         if (i < argc) {
268           outfilename = argv[i];
269         }
270         else {
271           printf ("Missing output file name\n");
272           show_help();
273           exit(1);
274         }
275       }
276       else if (strncmp(argv[i], "-", 1)) {
277         file_name = argv[i];
278         break;
279       }
280       else {
281         printf ("Unrecognized option: %s\n", argv[i]);
282         show_help();
283         exit(1);
284       }
285     }
286   }
287   
288   if (!file_name) {
289     printf("No file name given\n");
290     show_help();
291     exit(1);
292   }
293
294   gedcom_init();
295   setlocale(LC_ALL, "");
296   gedcom_set_debug_level(debug_level, NULL);
297   gedcom_set_compat_handling(compat_enabled);
298   gedcom_set_error_handling(mech);
299   gedcom_set_message_handler(gedcom_message_handler);
300   gedcom_set_default_callback(default_cb);
301   
302   subscribe_callbacks();
303   output_open(outfilename);
304   if (bogus) {
305     output(0, "\n=== Parsing bogus file %s\n", BOGUS_FILE_NAME);
306     gedcom_parse_file(BOGUS_FILE_NAME);
307   }
308   while (run_times-- > 0) {
309     output(0, "\n=== Parsing file %s\n", file_name);
310     result |= gedcom_parse_file(file_name);
311     output(0, "\n=== Total conversion failures: %d\n", total_conv_fails);
312   }
313   if (result == 0) {
314     output(1, "Parse succeeded\n");
315   }
316   else {
317     output(1, "Parse failed\n");
318   }
319   output_close();
320   return result;
321 }