Keep parsed values in date if parse was OK, but no valid date.
[gedcom-parse.git] / gedcom / multilex.c
1 /* The lexer multiplexer for Gedcom.
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_internal.h"
25 #include "multilex.h"
26 #include "encoding.h"
27 #include "encoding_state.h"
28 #include "xref.h"
29
30 int line_no = 0;
31
32 typedef int (*lex_func)(void);
33 lex_func lf;
34
35 #define NEW_MODEL_FILE "new.ged"
36
37 int lexer_init(Encoding enc, FILE* f)
38 {
39   if (enc == ONE_BYTE) {
40     lf  = &gedcom_1byte_lex;
41     gedcom_1byte_myinit(f);
42     set_read_encoding_width(enc);
43     return open_conv_to_internal("ASCII");
44   }
45   else if (enc == TWO_BYTE_HILO) {
46     lf  = &gedcom_hilo_lex;
47     gedcom_hilo_myinit(f);
48     set_read_encoding_width(enc);
49     return open_conv_to_internal("UNICODE");
50   }
51   else if (enc == TWO_BYTE_LOHI) {
52     lf  = &gedcom_lohi_lex;
53     gedcom_lohi_myinit(f);
54     set_read_encoding_width(enc);
55     return open_conv_to_internal("UNICODE");
56   }
57   else {
58     return 0;
59   }
60 }
61
62 void lexer_close()
63 {
64   close_conv_to_internal();
65 }
66
67 int gedcom_lex()
68 {
69   return (*lf)();
70 }
71
72 void rewind_file(FILE* f)
73 {
74   if (fseek(f, 0, 0) != 0)
75     gedcom_warning(_("Error positioning input file: %s"), strerror(errno));
76 }
77
78 int determine_encoding(FILE* f)
79 {
80   char first[2];
81   int read;
82
83   set_read_encoding_bom(WITHOUT_BOM);
84   read = fread(first, 1, 2, f);
85   if (read != 2) {
86     gedcom_warning(_("Error reading from input file: %s"), strerror(errno));
87     rewind_file(f);
88     return ONE_BYTE;
89   }
90   else if ((first[0] == '0') && (first[1] == ' ')) {
91     gedcom_debug_print("One-byte encoding");
92     rewind_file(f);
93     return ONE_BYTE;
94   }
95   else if ((first[0] == '\0') && (first[1] == '0')) {
96     gedcom_debug_print("Two-byte encoding, high-low");
97     rewind_file(f);
98     return TWO_BYTE_HILO;
99   }
100   else if ((first[0] == '\xFE') && (first[1] == '\xFF')) {
101     gedcom_debug_print("Two-byte encoding, high-low, with BOM");
102     set_read_encoding_bom(WITH_BOM);
103     return TWO_BYTE_HILO;
104   }
105   else if ((first[0] == '0') && (first[1] == '\0')) {
106     gedcom_debug_print("Two-byte encoding, low-high");
107     rewind_file(f);
108     return TWO_BYTE_LOHI;
109   }
110   else if ((first[0] == '\xFF') && (first[1] == '\xFE')) {
111     gedcom_debug_print("Two-byte encoding, low-high, with BOM");
112     set_read_encoding_bom(WITH_BOM);
113     return TWO_BYTE_LOHI;
114   }
115   else if ((first[0] == '\xEF') && (first[1] == '\xBB')) {
116     read = fread(first, 1, 1, f);
117     if (read != 1) {
118       gedcom_warning(_("Error reading from input file: %s"), strerror(errno));
119       rewind_file(f);
120     }
121     else if (first[0] == '\xBF') {
122       set_read_encoding_bom(WITH_BOM);
123       gedcom_debug_print("UTF-8 encoding, with BOM");
124     }
125     else {
126       gedcom_warning(_("Unknown encoding, falling back to one-byte"));
127       rewind_file(f);
128     }
129     return ONE_BYTE;
130   }
131   else {
132     gedcom_warning(_("Unknown encoding, falling back to one-byte"));
133     rewind_file(f);
134     return ONE_BYTE;
135   }
136 }
137
138 int init_called = 0;
139
140 int gedcom_init()
141 {
142   init_called = 1;
143   update_gconv_search_path();
144   init_encodings();
145   if (!setlocale(LC_ALL, "")
146       || ! bindtextdomain(PACKAGE, LOCALEDIR)
147       || ! bind_textdomain_codeset(PACKAGE, INTERNAL_ENCODING))
148     return 1;
149   else
150     return 0;
151 }
152
153 int gedcom_parse_file(const char* file_name)
154 {
155   Encoding enc;
156   int result = 1;
157   FILE* file;
158
159   if (!init_called) {
160     gedcom_error(_("Internal error: GEDCOM parser not initialized"));
161   }
162   else {
163     file = fopen(file_name, "r");
164     if (!file) {
165       gedcom_error(_("Could not open file '%s': %s"),
166                    file_name, strerror(errno));
167     }
168     else {
169       line_no = 1;
170       enc = determine_encoding(file);
171       
172       if (lexer_init(enc, file)) {
173         line_no = 0;
174         make_xref_table();
175         result = gedcom_parse();
176         line_no = 0;
177         if (result == 0)
178           result = check_xref_table();
179       }
180       lexer_close();
181       fclose(file);
182     }
183   }
184
185   return result;
186 }
187
188 int gedcom_new_model()
189 {
190   int result = 1;
191   FILE* file;
192
193   file = fopen(NEW_MODEL_FILE, "r");
194   if (file) {
195     fclose(file);
196     result = gedcom_parse_file(NEW_MODEL_FILE);
197   }
198   else {
199     char* filename = (char*) malloc(strlen(PKGDATADIR) + strlen(NEW_MODEL_FILE)
200                                     + 2);
201     if (!filename)
202       MEMORY_ERROR;
203     else {
204       sprintf(filename, "%s/%s", PKGDATADIR, NEW_MODEL_FILE);
205       result = gedcom_parse_file(filename);
206       free(filename);
207     }
208   }
209   return result;
210 }
211
212 int gedcom_check_version(int major, int minor, int patch)
213 {
214   if (major < GEDCOM_PARSE_VERSION_MAJOR)
215     return 1;
216   else if (major > GEDCOM_PARSE_VERSION_MAJOR)
217     return 0;
218   else if (minor < GEDCOM_PARSE_VERSION_MINOR)
219     return 1;
220   else if (minor > GEDCOM_PARSE_VERSION_MINOR)
221     return 0;
222   else if (patch <= GEDCOM_PARSE_VERSION_PATCH)
223     return 1;
224   else
225     return 0;
226 }