1 /*
2    Copyright (c) 1991-1999 Thomas T. Wetmore IV
3 
4    Permission is hereby granted, free of charge, to any person
5    obtaining a copy of this software and associated documentation
6    files (the "Software"), to deal in the Software without
7    restriction, including without limitation the rights to use, copy,
8    modify, merge, publish, distribute, sublicense, and/or sell copies
9    of the Software, and to permit persons to whom the Software is
10    furnished to do so, subject to the following conditions:
11 
12    The above copyright notice and this permission notice shall be
13    included in all copies or substantial portions of the Software.
14 
15    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22    SOFTWARE.
23 */
24 /*=============================================================
25  * init.c -- Initialize LifeLines data structures
26  * Copyright(c) 1991-95 by T.T. Wetmore IV; all rights reserved
27  *   2.3.4 - 24 Jun 93    2.3.5 - 29 Aug 93
28  *   3.0.0 - 05 Oct 94    3.0.2 - 09 Nov 94
29  *   3.0.3 - 21 Sep 95
30  *===========================================================*/
31 
32 #include "sys_inc.h"
33 #include "llstdlib.h"
34 #include "arch.h"
35 #include "btree.h"
36 #include "table.h"
37 #include "translat.h"
38 #include "gedcom.h"
39 #include "gedcomi.h"
40 #include "lloptions.h"
41 #include "codesets.h"
42 #include "menuitem.h"
43 #include "zstr.h"
44 #include "icvt.h"
45 #include "date.h"
46 #include "mychar.h"
47 #include "charprops.h"
48 #include "xlat.h"
49 #include "dbcontext.h"
50 
51 /*********************************************
52  * global/exported variables
53  *********************************************/
54 
55 TABLE tagtable=NULL;		/* table for tag strings */
56 TABLE placabbvs=NULL;	/* table for place abbrevs */
57 STRING editstr=NULL; /* edit command to run to edit (has editfile inside of it) */
58 STRING editfile=NULL; /* file used for editing, name obtained via mktemp */
59 
60 /*********************************************
61  * external/imported variables
62  *********************************************/
63 
64 extern BOOLEAN writeable;
65 extern STRING readpath,readpath_file;
66 extern STRING illegal_char;
67 extern INT opt_finnish, opt_mychar;
68 
69 /*********************************************
70  * local function prototypes
71  *********************************************/
72 
73 static void check_installation_path(void);
74 static BOOLEAN load_configs(STRING configfile, STRING * pmsg);
75 static void post_codesets_hook(void);
76 static void pre_codesets_hook(void);
77 static void update_db_options(void);
78 
79 /*********************************************
80  * local variables
81  *********************************************/
82 
83 static BOOLEAN suppress_reload=FALSE;
84 static char global_conf_path[MAXPATHLEN]="";
85 
86 /*********************************************
87  * local & exported function definitions
88  * body of module
89  *********************************************/
90 
91 /*=================================
92  * init_lifelines_global -- Initialization options & misc. stuff
93  *  This is called before first (or later) database opened
94  *===============================*/
95 BOOLEAN
init_lifelines_global(STRING configfile,STRING * pmsg,void (* notify)(STRING db,BOOLEAN opening))96 init_lifelines_global (STRING configfile, STRING * pmsg, void (*notify)(STRING db, BOOLEAN opening))
97 {
98 	STRING e;
99 	STRING dirvars[] = { "LLPROGRAMS", "LLREPORTS", "LLARCHIVES"
100 		, "LLDATABASES", };
101 	INT i;
102 
103 	check_installation_path();
104 
105 	/* request notification when options change */
106 	register_notify(&update_useropts);
107 	suppress_reload = TRUE;
108 
109 	dbnotify_set(notify);
110 
111 	if (!load_configs(configfile, pmsg)) {
112 		suppress_reload = FALSE;
113 		update_useropts(NULL);
114 		return FALSE;
115 	}
116 
117 	pre_codesets_hook(); /* For MS-Windows user config of console codepages */
118 
119 	/* now that codeset variables are set from config file, lets initialize codesets */
120 	/* although int_codeset can't be determined yet, we need GUI codeset for gettext */
121 	init_codesets();
122 
123 	post_codesets_hook(); /* For Windows, link dynamically to gettext & iconv if available */
124 
125 
126 	/* until we have an internal codeset (which is until we open a database)
127 	we want output in display codeset */
128 	llgettext_init(PACKAGE, gui_codeset_out);
129 
130 	/* read available translation tables */
131 	transl_load_all_tts();
132 	/* set up translations (for first time, will do it again after
133 	loading config table, and then again after loading database */
134 	transl_load_xlats();
135 
136 	/* check if any directories not specified, and try environment
137 	variables, and default to "." */
138 	for (i=0; i<ARRSIZE(dirvars); ++i) {
139 		STRING str = getenv(dirvars[i]);
140 		if (!str)
141 			str = ".";
142 		setoptstr_fallback(dirvars[i], str);
143 	}
144 	/* also check environment variable for editor */
145 	{
146 		STRING str = getenv("LLEDITOR");
147 		if (!str)
148 			str = environ_determine_editor(PROGRAM_LIFELINES);
149 		setoptstr_fallback("LLEDITOR", str);
150 	}
151 	/* editor falls back to platform-specific default */
152 	e = getlloptstr("LLEDITOR", NULL);
153 	/* configure tempfile & edit command */
154 	editfile = environ_determine_tempfile();
155 	if (!editfile) {
156 		*pmsg = strsave("Error creating temp file");
157 		return FALSE;
158 	}
159 	editfile = strsave(editfile );
160 	editstr = (STRING) stdalloc(strlen(e) + strlen(editfile) + 2);
161 	sprintf(editstr, "%s %s", e, editfile);
162 	set_usersort(custom_sort);
163 	suppress_reload = FALSE;
164 	update_useropts(0);
165 
166 	/* Finnish always uses custom character sets */
167 	if (opt_finnish ) {
168 		opt_mychar = TRUE;
169 		mych_set_table(ISO_Latin1);
170 	}
171 
172 
173 	return TRUE;
174 }
175 /*=================================
176  * init_lifelines_postdb --
177  * Initialize stuff maintained in-memory
178  *  which requires the database to already be opened
179  *===============================*/
180 BOOLEAN
init_lifelines_postdb(void)181 init_lifelines_postdb (void)
182 {
183 	STRING emsg;
184 	TABLE dbopts = create_table_str();
185 
186 	tagtable = create_table_str(); /* values are same as keys */
187 	placabbvs = create_table_str();
188 
189 	init_valtab_from_rec("VPLAC", placabbvs, ':', &emsg);
190 	init_valtab_from_rec("VUOPT", dbopts, '=', &emsg);
191 	set_db_options(dbopts);
192 	release_table(dbopts);
193 	init_caches();
194 	init_browse_lists();
195 	if (!openxref(readonly))
196 		return FALSE;
197 
198 
199 	transl_load_xlats();
200 
201 	return TRUE;
202 }
203 /*===================================
204  * close_lifelines -- Close LifeLines
205  *  Close entire lifelines engine - not just
206  *  database (see close_lldb below).
207  *=================================*/
208 void
close_lifelines(void)209 close_lifelines (void)
210 {
211 	lldb_close(&def_lldb); /* make sure database closed */
212 	if (editfile) {
213 		unlink(editfile);
214 		stdfree(editfile);
215 		editfile=NULL;
216 	}
217 	if (editstr) {
218 		stdfree(editstr);
219 		editstr=NULL;
220 	}
221 	term_lloptions();
222 	term_date();
223 	term_codesets();
224 	strfree(&int_codeset);
225 	xlat_shutdown();
226 }
227 /*===================================================
228  * is_codeset_utf8 -- Is this the name of UTF-8 ?
229  *=================================================*/
230 BOOLEAN
is_codeset_utf8(CNSTRING codename)231 is_codeset_utf8 (CNSTRING codename)
232 {
233 	if (!codename || !codename[0]) return FALSE;
234 	if (eqstr("UTF-8", codename)||eqstr("utf-8", codename)||eqstr("65001", codename))
235 		return TRUE;
236 	return FALSE;
237 }
238 /*===================================================
239  * update_useropts -- Set any global variables
240  * dependent on user options
241  *=================================================*/
242 void
update_useropts(VPTR uparm)243 update_useropts (VPTR uparm)
244 {
245 	uparm = uparm; /* unused */
246 	if (suppress_reload)
247 		return;
248 	/* deal with db-specific options */
249 	/* includes setting int_codeset */
250 	if (def_lldb)
251 		update_db_options();
252 	/* in case user changed any codesets */
253 	init_codesets();
254 	/* in case user changed locale (need int_codeset already set) */
255 	uilocale();
256 	/* in case user changed codesets */
257 	/* TODO: Isn't this superfluous, as it was called in update_db_options above ? */
258 	transl_load_xlats();
259 
260 	strupdate(&illegal_char, getlloptstr("IllegalChar", 0));
261 
262 	nodechk_enable(!!getlloptint("nodecheck", 0));
263 }
264 /*==================================================
265  * update_db_options --
266  *  check database-specific options for updates
267  *================================================*/
268 static void
update_db_options(void)269 update_db_options (void)
270 {
271 	TABLE opttab = create_table_str();
272 	CNSTRING str=0;
273 	get_db_options(opttab);
274 
275 	str = valueof_str(opttab, "codeset");
276 	if (!str || !str[0]) {
277 		/*
278 		no specified database/internal codeset
279 		so default to user's default codeset, which
280 		should be from locale
281 		*/
282 		str = get_defcodeset();
283 	}
284 	if (!int_codeset)
285 		strupdate(&int_codeset, "");
286 	if (!eqstr_ex(int_codeset, str)) {
287 		/* database encoding changed */
288 		strupdate(&int_codeset, str);
289 
290 		/* Here is where the global uu8 variable is set
291 		This is a flag if the internal (database) encoding is UTF-8 */
292 		uu8 = is_codeset_utf8(int_codeset);
293 
294 		/* always translate to internal codeset */
295 		set_gettext_codeset(PACKAGE, int_codeset);
296 		/* need to reload all predefined codeset conversions */
297 		transl_load_xlats();
298 		if (uu8) {
299 			charprops_load_utf8();
300 		} else {
301 			charprops_load(int_codeset);
302 		}
303 	}
304 
305 	destroy_table(opttab);
306 }
307 /*==================================================
308  * pre_codesets_hook -- code to run just before initializing codesets
309  * For MS-Windows user config of console codepages
310  *================================================*/
311 static void
pre_codesets_hook(void)312 pre_codesets_hook (void)
313 {
314 #ifdef WIN32
315 	/* On MS-Windows, attempt to set any requested non-standard codepage */
316 	/* Do this now, before init_codesets below */
317 	INT i = getlloptint("ConsoleCodepage", 0);
318 	if (i) {
319 		w_set_oemout_codepage(i);
320 		w_set_oemin_codepage(i);
321 	}
322 #endif
323 }
324 /*==================================================
325  * post_codesets_hook -- code to run just after initializing codesets
326  * For Windows, link dynamically to gettext & iconv if available
327  *================================================*/
328 static void
post_codesets_hook(void)329 post_codesets_hook (void)
330 {
331 	init_win32_gettext_shim();
332 	init_win32_iconv_shim(getlloptstr("iconv.path",""));
333 }
334 /*==================================================
335  * load_configs -- Load global config file(s)
336  * returns FALSE if error, with message in pmsg
337  *================================================*/
338 static BOOLEAN
load_configs(STRING configfile,STRING * pmsg)339 load_configs (STRING configfile, STRING * pmsg)
340 {
341 	INT rtn=0;
342 	STRING str=0;
343 	char cfg_name[MAXPATHLEN];
344 
345 	/* TODO: Should read a system-wide config file */
346 
347 	if (!configfile)
348 		configfile = getenv("LLCONFIGFILE");
349 
350 	*pmsg = NULL;
351 
352 
353 	if (configfile && configfile[0]) {
354 
355 		rtn = load_global_options(configfile, pmsg);
356 		if (rtn == -1) return FALSE;
357 
358 	} else {
359 
360 		/* No config file specified, so load config_file(s) from
361 		   the standard places */
362 
363 		/* look for global config file */
364 		llstrncpy(cfg_name, global_conf_path, sizeof(cfg_name), 0);
365 		llstrapps(cfg_name, sizeof(cfg_name), 0, "/lifelines.conf");
366 		rtn = load_global_options(cfg_name, pmsg);
367 		if (rtn == -1) return FALSE;
368 
369 		/* look for one in user's home directory */
370 		/* TODO: Shouldn't Win32 use getenv("USERPROFILE") ? */
371 		llstrncpy(cfg_name, getenv("HOME") , sizeof(cfg_name), 0);
372 		/*llstrappc(cfg_name, sizeof(cfg_name), '/');*/
373 		llstrapps(cfg_name, sizeof(cfg_name), 0, "/" LINES_CONFIG_FILE);
374 
375 		rtn = load_global_options(cfg_name, pmsg);
376 		if (rtn == -1) return FALSE;
377 
378 		rtn = load_global_options(LINES_CONFIG_FILE, pmsg);
379 		if (rtn == -1) return FALSE;
380 	}
381 
382 	/* allow chaining to one more config file
383 	 * if one was defined for the database
384 	 */
385 	str = getlloptstr("LLCONFIGFILE", NULL);
386 	if (str && str[0]) {
387 		rtn = load_global_options(str, pmsg);
388 		if (rtn == -1) return FALSE;
389 	}
390 	return TRUE;
391 }
392 /*==================================================
393  * check_installation_path -- Figure out installed path
394  *================================================*/
395 static void
check_installation_path(void)396 check_installation_path (void)
397 {
398 	INT maxlen = sizeof(global_conf_path)-1;
399 #ifdef WIN32
400 	/* TODO: Installation should set value in registry
401 	and we should read it here */
402 	strncpy(global_conf_path, "C:\\Program Files\\lifelines", maxlen);
403 #else
404 	/* SYS_CONF_DIR was passed to make in src/gedlib/Makefile.am */
405 	strncpy(global_conf_path, SYS_CONF_DIR, maxlen);
406 #endif
407 	global_conf_path[maxlen] = 0;
408 }
409