Added extra argument to callback functions: the record/element identifier.
[gedcom-parse.git] / t / 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 <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <locale.h>
29 #include <errno.h>
30 #include <iconv.h>
31 #include "gedcom.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(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_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 void default_cb(Gedcom_elt elt, Gedcom_ctxt ctxt, int level, char *tag,
178                 char *raw_value, int tag_value)
179 {
180   char   *converted = NULL;
181   int    conv_fails = 0;
182   if (raw_value)
183     converted = convert_utf8_to_locale(raw_value, &conv_fails);
184   output(0, "== %d %s (%d) %s (ctxt is %d, conversion failures: %d)\n",
185          level, tag, tag_value, converted, (int)ctxt, conv_fails);
186 }
187
188 void subscribe_callbacks()
189 {
190   gedcom_subscribe_to_record(REC_HEAD, header_start, header_end);
191   gedcom_subscribe_to_record(REC_FAM,  family_start, family_end);
192   gedcom_subscribe_to_record(REC_INDI, rec_start, NULL);
193   gedcom_subscribe_to_record(REC_OBJE, rec_start, NULL);
194   gedcom_subscribe_to_record(REC_NOTE, note_start, NULL);
195   gedcom_subscribe_to_record(REC_REPO, rec_start, NULL);
196   gedcom_subscribe_to_record(REC_SOUR, rec_start, NULL);
197   gedcom_subscribe_to_record(REC_SUBN, rec_start, NULL);
198   gedcom_subscribe_to_record(REC_SUBM, submit_start, NULL);
199   gedcom_subscribe_to_record(REC_USER, rec_start, NULL);
200   gedcom_subscribe_to_element(ELT_HEAD_SOUR, source_start, source_end);
201   gedcom_subscribe_to_element(ELT_SOUR_DATA_EVEN_DATE,
202                               date_start, NULL);
203   gedcom_subscribe_to_element(ELT_SUB_EVT_DATE, date_start, NULL);
204 }
205
206 void gedcom_message_handler(Gedcom_msg_type type, char *msg)
207 {
208   if (type == MESSAGE)
209     output(1, "MESSAGE: ");
210   else if (type == WARNING)
211     output(1, "WARNING: ");
212   else if (type == ERROR)
213     output(1, "ERROR: ");
214   output(1, "%s\n", msg);
215 }
216
217 int main(int argc, char* argv[])
218 {
219   Gedcom_err_mech mech = IMMED_FAIL;
220   int compat_enabled = 1;
221   int debug_level = 0;
222   int run_times   = 1;
223   int bogus       = 0;
224   int result      = 0;
225   char* file_name = NULL;
226
227   if (argc > 1) {
228     int i;
229     for (i=1; i<argc; i++) {
230       if (!strncmp(argv[i], "-da", 4))
231         debug_level = 2;
232       else if (!strncmp(argv[i], "-dg", 4))
233         debug_level = 1;
234       else if (!strncmp(argv[i], "-fi", 4))
235         mech = IMMED_FAIL;
236       else if (!strncmp(argv[i], "-fd", 4))
237         mech = DEFER_FAIL;
238       else if (!strncmp(argv[i], "-fn", 4))
239         mech = IGNORE_ERRORS;
240       else if (!strncmp(argv[i], "-nc", 4))
241         compat_enabled = 0;
242       else if (!strncmp(argv[i], "-h", 3)) {
243         show_help();
244         exit(1);
245       }
246       else if (!strncmp(argv[i], "-2", 3)) {
247         run_times = 2;
248       }
249       else if (!strncmp(argv[i], "-3", 3)) {
250         run_times = 3;
251       }
252       else if (!strncmp(argv[i], "-b", 3)) {
253         bogus = 1;
254       }
255       else if (!strncmp(argv[i], "-q", 3)) {
256         quiet = 1;
257       }
258       else if (strncmp(argv[i], "-", 1)) {
259         file_name = argv[i];
260         break;
261       }
262       else {
263         printf ("Unrecognized option: %s\n", argv[i]);
264         show_help();
265         exit(1);
266       }
267     }
268   }
269   
270   if (!file_name) {
271     printf("No file name given\n");
272     show_help();
273     exit(1);
274   }
275
276   gedcom_init();
277   setlocale(LC_ALL, "");
278   gedcom_set_debug_level(debug_level, NULL);
279   gedcom_set_compat_handling(compat_enabled);
280   gedcom_set_error_handling(mech);
281   gedcom_set_message_handler(gedcom_message_handler);
282   gedcom_set_default_callback(default_cb);
283   
284   subscribe_callbacks();
285   outfile = fopen(OUTFILE, "a");
286   if (!outfile) {
287     printf("Could not open %s for appending\n", OUTFILE);
288   }
289   if (bogus) {
290     output(0, "\n=== Parsing bogus file %s\n", BOGUS_FILE_NAME);
291     gedcom_parse_file(BOGUS_FILE_NAME);
292   }
293   while (run_times-- > 0) {
294     output(0, "\n=== Parsing file %s\n", file_name);
295     result |= gedcom_parse_file(file_name);
296   }
297   fclose(outfile);
298   if (result == 0) {
299     output(1, "Parse succeeded\n");
300     return 0;
301   }
302   else {
303     output(1, "Parse failed\n");
304     return 1;
305   }  
306 }