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