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