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