Initialize.c revision 339a7c43
1/***********************************************************
2Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
3
4Permission is hereby granted, free of charge, to any person obtaining a
5copy of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation
7the rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the
9Software is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice (including the next
12paragraph) shall be included in all copies or substantial portions of the
13Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21DEALINGS IN THE SOFTWARE.
22
23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24
25                        All Rights Reserved
26
27Permission to use, copy, modify, and distribute this software and its
28documentation for any purpose and without fee is hereby granted,
29provided that the above copyright notice appear in all copies and that
30both that copyright notice and this permission notice appear in
31supporting documentation, and that the name of Digital not be
32used in advertising or publicity pertaining to distribution of the
33software without specific, written prior permission.
34
35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41SOFTWARE.
42
43******************************************************************/
44
45/*
46
47Copyright 1987, 1988, 1994, 1998  The Open Group
48
49Permission to use, copy, modify, distribute, and sell this software and its
50documentation for any purpose is hereby granted without fee, provided that
51the above copyright notice appear in all copies and that both that
52copyright notice and this permission notice appear in supporting
53documentation.
54
55The above copyright notice and this permission notice shall be included in
56all copies or substantial portions of the Software.
57
58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64
65Except as contained in this notice, the name of The Open Group shall not be
66used in advertising or otherwise to promote the sale, use or other dealings
67in this Software without prior written authorization from The Open Group.
68
69*/
70
71/* Make sure all wm properties can make it out of the resource manager */
72
73#ifdef HAVE_CONFIG_H
74#include <config.h>
75#endif
76#include "IntrinsicI.h"
77#include "StringDefs.h"
78#include "CoreP.h"
79#include "ShellP.h"
80#include <stdio.h>
81#include <X11/Xlocale.h>
82#ifdef XTHREADS
83#include <X11/Xthreads.h>
84#endif
85#ifndef WIN32
86#define X_INCLUDE_PWD_H
87#define XOS_USE_XT_LOCKING
88#include <X11/Xos_r.h>
89#endif
90
91#include <stdlib.h>
92
93#if (defined(SUNSHLIB) || defined(AIXSHLIB)) && defined(SHAREDCODE)
94/*
95 * If used as a shared library, generate code under a different name so that
96 * the stub routines in sharedlib.c get loaded into the application binary.
97 */
98#define XtToolkitInitialize _XtToolkitInitialize
99#define XtOpenApplication _XtOpenApplication
100#define XtAppInitialize _XtAppInitialize
101#define XtInitialize _XtInitialize
102#endif /* (SUNSHLIB || AIXSHLIB) && SHAREDCODE */
103
104/*
105 * hpux
106 * Hand-patched versions of HP-UX prior to version 7.0 can usefully add
107 * -DUSE_UNAME in the appropriate config file to get long hostnames.
108 */
109
110#ifdef USG
111#define USE_UNAME
112#endif
113
114#ifdef USE_UNAME
115#include <sys/utsname.h>
116#endif
117
118/* some unspecified magic number of expected search levels for Xrm */
119#define SEARCH_LIST_SIZE 1000
120
121/*
122 This is a set of default records describing the command line arguments that
123 Xlib will parse and set into the resource data base.
124
125 This list is applied before the users list to enforce these defaults.  This is
126 policy, which the toolkit avoids but I hate differing programs at this level.
127*/
128
129static XrmOptionDescRec const opTable[] = {
130{"+rv",		"*reverseVideo", XrmoptionNoArg,	(XtPointer) "off"},
131{"+synchronous","*synchronous",	XrmoptionNoArg,		(XtPointer) "off"},
132{"-background",	"*background",	XrmoptionSepArg,	(XtPointer) NULL},
133{"-bd",		"*borderColor",	XrmoptionSepArg,	(XtPointer) NULL},
134{"-bg",		"*background",	XrmoptionSepArg,	(XtPointer) NULL},
135{"-bordercolor","*borderColor",	XrmoptionSepArg,	(XtPointer) NULL},
136{"-borderwidth",".borderWidth",	XrmoptionSepArg,	(XtPointer) NULL},
137{"-bw",		".borderWidth",	XrmoptionSepArg,	(XtPointer) NULL},
138{"-display",	".display",     XrmoptionSepArg,	(XtPointer) NULL},
139{"-fg",		"*foreground",	XrmoptionSepArg,	(XtPointer) NULL},
140{"-fn",		"*font",	XrmoptionSepArg,	(XtPointer) NULL},
141{"-font",	"*font",	XrmoptionSepArg,	(XtPointer) NULL},
142{"-foreground",	"*foreground",	XrmoptionSepArg,	(XtPointer) NULL},
143{"-geometry",	".geometry",	XrmoptionSepArg,	(XtPointer) NULL},
144{"-iconic",	".iconic",	XrmoptionNoArg,		(XtPointer) "on"},
145{"-name",	".name",	XrmoptionSepArg,	(XtPointer) NULL},
146{"-reverse",	"*reverseVideo", XrmoptionNoArg,	(XtPointer) "on"},
147{"-rv",		"*reverseVideo", XrmoptionNoArg,	(XtPointer) "on"},
148{"-selectionTimeout",
149		".selectionTimeout", XrmoptionSepArg,	(XtPointer) NULL},
150{"-synchronous","*synchronous",	XrmoptionNoArg,		(XtPointer) "on"},
151{"-title",	".title",	XrmoptionSepArg,	(XtPointer) NULL},
152{"-xnllanguage",".xnlLanguage",	XrmoptionSepArg,	(XtPointer) NULL},
153{"-xrm",	NULL,		XrmoptionResArg,	(XtPointer) NULL},
154{"-xtsessionID",".sessionID",	XrmoptionSepArg,	(XtPointer) NULL},
155};
156
157
158/*
159 * GetHostname - emulates gethostname() on non-bsd systems.
160 */
161
162static void GetHostname (
163    char *buf,
164    int maxlen)
165{
166#ifdef USE_UNAME
167    int len;
168    struct utsname name;
169
170    if (maxlen <= 0 || buf == NULL)
171	return;
172
173    uname (&name);
174    len = strlen (name.nodename);
175    if (len >= maxlen) len = maxlen;
176    (void) strncpy (buf, name.nodename, len-1);
177    buf[len-1] = '\0';
178#else
179    if (maxlen <= 0 || buf == NULL)
180	return;
181
182    buf[0] = '\0';
183    (void) gethostname (buf, maxlen);
184    buf [maxlen - 1] = '\0';
185#endif
186}
187
188
189#ifdef SUNSHLIB
190void _XtInherit(void)
191{
192    extern void __XtInherit();
193    __XtInherit();
194}
195#define _XtInherit __XtInherit
196#endif
197
198
199#if defined (WIN32) || defined(__CYGWIN__)
200/*
201 * The Symbol _XtInherit is used in two different manners.
202 * First it could be used as a generic function and second
203 * as an absolute address reference, which will be used to
204 * check the initialisation process of several other libraries.
205 * Because of this the symbol must be accessable by all
206 * client dll's and applications.  In unix environments
207 * this is no problem, because the used shared libraries
208 * format (elf) supports this immediatly.  Under Windows
209 * this isn't true, because a functions address in a dll
210 * is different from the same function in another dll or
211 * applications, because the used Portable Executable
212 * File adds a code stub to each client to provide the
213 * exported symbol name.  This stub uses an indirect
214 * pointer to get the original symbol address, which is
215 * then jumped to, like in this example:
216 *
217 * --- client ---                                     --- dll ----
218 *  ...
219 *  call foo
220 *
221 * foo: jmp (*_imp_foo)               ---->           foo: ....
222 *      nop
223 *      nop
224 *
225 * _imp_foo: .long <index of foo in dll export table, is
226 *		    set to the real address by the runtime linker>
227 *
228 * Now it is clear why the clients symbol foo isn't the same
229 * as in the dll and we can think about how to deal which
230 * this two above mentioned requirements, to export this
231 * symbol to all clients and to allow calling this symbol
232 * as a function.  The solution I've used exports the
233 * symbol _XtInherit as data symbol, because global data
234 * symbols are exported to all clients.  But how to deal
235 * with the second requirement, that this symbol should
236 * be used as function.  The Trick is to build a little
237 * code stub in the data section in the exact manner as
238 * above explained.  This is done with the assembler code
239 * below.
240 *
241 * Ralf Habacker
242 *
243 * References:
244 * msdn          http://msdn.microsoft.com/msdnmag/issues/02/02/PE/PE.asp
245 * cygwin-xfree: http://www.cygwin.com/ml/cygwin-xfree/2003-10/msg00000.html
246 */
247
248#ifdef __x86_64__
249asm (".section .trampoline, \"dwx\" \n\
250 .globl _XtInherit        \n\
251 _XtInherit:              \n\
252    jmp *_y(%rip)         \n\
253_y: .quad __XtInherit     \n\
254    .text                 \n");
255#else
256asm (".data\n\
257 .globl __XtInherit        \n\
258 __XtInherit:      jmp *_y \n\
259  _y: .long ___XtInherit   \n\
260    .text                 \n");
261#endif
262
263#define _XtInherit __XtInherit
264#endif
265
266
267void _XtInherit(void)
268{
269    XtErrorMsg("invalidProcedure","inheritanceProc",XtCXtToolkitError,
270            "Unresolved inheritance operation",
271              (String *)NULL, (Cardinal *)NULL);
272}
273
274
275void XtToolkitInitialize(void)
276{
277    static Boolean initialized = False;
278
279    LOCK_PROCESS;
280    if (initialized) {
281	UNLOCK_PROCESS;
282	return;
283    }
284    initialized = True;
285    UNLOCK_PROCESS;
286    /* Resource management initialization */
287    XrmInitialize();
288    _XtResourceListInitialize();
289
290    /* Other intrinsic intialization */
291    _XtConvertInitialize();
292    _XtEventInitialize();
293    _XtTranslateInitialize();
294
295    /* Some apps rely on old (broken) XtAppPeekEvent behavior */
296    if(getenv("XTAPPPEEKEVENT_SKIPTIMER"))
297	XtAppPeekEvent_SkipTimer = True;
298    else
299	XtAppPeekEvent_SkipTimer = False;
300}
301
302
303String _XtGetUserName(
304    String dest,
305    int len)
306{
307#ifdef WIN32
308    String ptr = NULL;
309
310    if ((ptr = getenv("USERNAME"))) {
311	(void) strncpy (dest, ptr, len-1);
312	dest[len-1] = '\0';
313    } else
314	*dest = '\0';
315#else
316#ifdef X_NEEDS_PWPARAMS
317    _Xgetpwparams pwparams;
318#endif
319    struct passwd *pw;
320    char* ptr;
321
322    if ((ptr = getenv("USER"))) {
323	(void) strncpy (dest, ptr, len-1);
324	dest[len-1] = '\0';
325    } else {
326	if ((pw = _XGetpwuid(getuid(),pwparams)) != NULL) {
327	    (void) strncpy (dest, pw->pw_name, len-1);
328	    dest[len-1] = '\0';
329	} else
330	    *dest = '\0';
331    }
332#endif
333    return dest;
334}
335
336
337static String GetRootDirName(
338    String dest,
339    int len)
340{
341#ifdef WIN32
342    register char *ptr1;
343    register char *ptr2 = NULL;
344    int len1 = 0, len2 = 0;
345
346    if (ptr1 = getenv("HOME")) {	/* old, deprecated */
347	len1 = strlen (ptr1);
348    } else if ((ptr1 = getenv("HOMEDRIVE")) && (ptr2 = getenv("HOMEDIR"))) {
349	len1 = strlen (ptr1);
350	len2 = strlen (ptr2);
351    } else if (ptr2 = getenv("USERNAME")) {
352	len1 = strlen (ptr1 = "/users/");
353	len2 = strlen (ptr2);
354    }
355    if ((len1 + len2 + 1) < len)
356	sprintf (dest, "%s%s", ptr1, (ptr2) ? ptr2 : "");
357    else
358	*dest = '\0';
359#else
360#ifdef X_NEEDS_PWPARAMS
361    _Xgetpwparams pwparams;
362#endif
363    struct passwd *pw;
364    static char *ptr;
365
366    if (len <= 0 || dest == NULL)
367	return NULL;
368
369    if ((ptr = getenv("HOME"))) {
370	(void) strncpy (dest, ptr, len-1);
371	dest[len-1] = '\0';
372    } else {
373	if ((ptr = getenv("USER")))
374	    pw = _XGetpwnam(ptr,pwparams);
375	else
376 	    pw = _XGetpwuid(getuid(),pwparams);
377	if (pw != NULL) {
378	    (void) strncpy (dest, pw->pw_dir, len-1);
379	    dest[len-1] = '\0';
380	} else
381	    *dest = '\0';
382    }
383#endif
384    return dest;
385}
386
387static void CombineAppUserDefaults(
388    Display *dpy,
389    XrmDatabase *pdb)
390{
391    char* filename;
392    char* path = NULL;
393    Boolean deallocate = False;
394
395    if (!(path = getenv("XUSERFILESEARCHPATH"))) {
396#if !defined(WIN32) || !defined(__MINGW32__)
397	char *old_path;
398	char homedir[PATH_MAX];
399	GetRootDirName(homedir, PATH_MAX);
400	if (!(old_path = getenv("XAPPLRESDIR"))) {
401	    XtAsprintf(&path,
402		       "%s/%%L/%%N%%C:%s/%%l/%%N%%C:%s/%%N%%C:%s/%%L/%%N:%s/%%l/%%N:%s/%%N",
403		       homedir, homedir, homedir, homedir, homedir, homedir);
404	} else {
405	    XtAsprintf(&path,
406		       "%s/%%L/%%N%%C:%s/%%l/%%N%%C:%s/%%N%%C:%s/%%N%%C:%s/%%L/%%N:%s/%%l/%%N:%s/%%N:%s/%%N",
407		       old_path, old_path, old_path, homedir,
408		       old_path, old_path, old_path, homedir);
409	}
410	deallocate = True;
411#endif
412    }
413
414    filename = XtResolvePathname(dpy, NULL, NULL, NULL, path, NULL, 0, NULL);
415    if (filename) {
416	(void)XrmCombineFileDatabase(filename, pdb, False);
417	XtFree(filename);
418    }
419
420    if (deallocate)
421	XtFree(path);
422}
423
424static void CombineUserDefaults(
425    Display *dpy,
426    XrmDatabase *pdb)
427{
428#ifdef __MINGW32__
429    const char *slashDotXdefaults = "/Xdefaults";
430#else
431    const char *slashDotXdefaults = "/.Xdefaults";
432#endif
433    char *dpy_defaults = XResourceManagerString(dpy);
434
435    if (dpy_defaults) {
436	XrmCombineDatabase(XrmGetStringDatabase(dpy_defaults), pdb, False);
437    } else {
438	char filename[PATH_MAX];
439	(void) GetRootDirName(filename,
440			PATH_MAX - strlen (slashDotXdefaults) - 1);
441	(void) strcat(filename, slashDotXdefaults);
442	(void)XrmCombineFileDatabase(filename, pdb, False);
443    }
444}
445
446/*ARGSUSED*/
447static Bool StoreDBEntry(
448    XrmDatabase		*db,
449    XrmBindingList      bindings,
450    XrmQuarkList	quarks,
451    XrmRepresentation   *type,
452    XrmValuePtr		value,
453    XPointer		data)
454{
455    XrmQPutResource((XrmDatabase *)data, bindings, quarks, *type, value);
456    return False;
457}
458
459static XrmDatabase CopyDB(XrmDatabase db)
460{
461    XrmDatabase copy = NULL;
462    XrmQuark empty = NULLQUARK;
463
464    XrmEnumerateDatabase(db, &empty, &empty, XrmEnumAllLevels,
465			 StoreDBEntry, (XPointer)&copy);
466    return copy;
467}
468
469/*ARGSUSED*/
470static String _XtDefaultLanguageProc(
471    Display   *dpy,	/* unused */
472    String     xnl,
473    XtPointer  closure)	/* unused */
474{
475    if (! setlocale(LC_ALL, xnl))
476	XtWarning("locale not supported by C library, locale unchanged");
477
478    if (! XSupportsLocale()) {
479	XtWarning("locale not supported by Xlib, locale set to C");
480	setlocale(LC_ALL, "C");
481    }
482    if (! XSetLocaleModifiers(""))
483	XtWarning("X locale modifiers not supported, using default");
484
485    return setlocale(LC_ALL, NULL); /* re-query in case overwritten */
486}
487
488XtLanguageProc XtSetLanguageProc(
489    XtAppContext      app,
490    XtLanguageProc    proc,
491    XtPointer         closure)
492{
493    XtLanguageProc    old;
494
495    if (!proc) {
496	proc = _XtDefaultLanguageProc;
497	closure = NULL;
498    }
499
500    if (app) {
501	LOCK_APP(app);
502	LOCK_PROCESS;
503	/* set langProcRec only for this application context */
504        old = app->langProcRec.proc;
505        app->langProcRec.proc = proc;
506        app->langProcRec.closure = closure;
507	UNLOCK_PROCESS;
508	UNLOCK_APP(app);
509    } else {
510	/* set langProcRec for all application contexts */
511        ProcessContext process;
512
513	LOCK_PROCESS;
514        process = _XtGetProcessContext();
515        old = process->globalLangProcRec.proc;
516	process->globalLangProcRec.proc = proc;
517	process->globalLangProcRec.closure = closure;
518        app = process->appContextList;
519        while (app) {
520            app->langProcRec.proc = proc;
521            app->langProcRec.closure = closure;
522	    app = app->next;
523        }
524	UNLOCK_PROCESS;
525    }
526    return (old ? old : _XtDefaultLanguageProc);
527}
528
529XrmDatabase XtScreenDatabase(
530    Screen *screen)
531{
532    int scrno;
533    Bool doing_def;
534    XrmDatabase db, olddb;
535    XtPerDisplay pd;
536    Status do_fallback;
537    char *scr_resources;
538    Display *dpy = DisplayOfScreen(screen);
539    DPY_TO_APPCON(dpy);
540
541    LOCK_APP(app);
542    LOCK_PROCESS;
543    if (screen == DefaultScreenOfDisplay(dpy)) {
544	scrno = DefaultScreen(dpy);
545	doing_def = True;
546    } else {
547	scrno = XScreenNumberOfScreen(screen);
548	doing_def = False;
549    }
550    pd = _XtGetPerDisplay(dpy);
551    if ((db = pd->per_screen_db[scrno])) {
552	UNLOCK_PROCESS;
553	UNLOCK_APP(app);
554	return (doing_def ? XrmGetDatabase(dpy) : db);
555    }
556    scr_resources = XScreenResourceString(screen);
557
558    if (ScreenCount(dpy) == 1) {
559	db = pd->cmd_db;
560	pd->cmd_db = NULL;
561    } else {
562	db = CopyDB(pd->cmd_db);
563    }
564    {   /* Environment defaults */
565	char	filenamebuf[PATH_MAX];
566	char	*filename;
567
568	if (!(filename = getenv("XENVIRONMENT"))) {
569	    int len;
570#ifdef __MINGW32__
571	    const char *slashDotXdefaultsDash = "/Xdefaults-";
572#else
573	    const char *slashDotXdefaultsDash = "/.Xdefaults-";
574#endif
575
576	    (void) GetRootDirName(filename = filenamebuf,
577			PATH_MAX - strlen (slashDotXdefaultsDash) - 1);
578	    (void) strcat(filename, slashDotXdefaultsDash);
579	    len = strlen(filename);
580	    GetHostname (filename+len, PATH_MAX-len);
581	}
582	(void)XrmCombineFileDatabase(filename, &db, False);
583    }
584    if (scr_resources)
585    {   /* Screen defaults */
586	XrmCombineDatabase(XrmGetStringDatabase(scr_resources), &db, False);
587	XFree(scr_resources);
588    }
589    /* Server or host defaults */
590    if (!pd->server_db)
591	CombineUserDefaults(dpy, &db);
592    else {
593	(void) XrmCombineDatabase(pd->server_db, &db, False);
594	pd->server_db = NULL;
595    }
596
597    if (!db)
598	db = XrmGetStringDatabase("");
599    pd->per_screen_db[scrno] = db;
600    olddb = XrmGetDatabase(dpy);
601    /* set database now, for XtResolvePathname to use */
602    XrmSetDatabase(dpy, db);
603    CombineAppUserDefaults(dpy, &db);
604    do_fallback = 1;
605    {   /* System app-defaults */
606	char	*filename;
607
608	if ((filename = XtResolvePathname(dpy, "app-defaults",
609					 NULL, NULL, NULL, NULL, 0, NULL))) {
610	    do_fallback = !XrmCombineFileDatabase(filename, &db, False);
611	    XtFree(filename);
612	}
613    }
614    /* now restore old database, if need be */
615    if (!doing_def)
616	XrmSetDatabase(dpy, olddb);
617    if (do_fallback && pd->appContext->fallback_resources)
618    {   /* Fallback defaults */
619        XrmDatabase fdb = NULL;
620	String *res;
621
622	for (res = pd->appContext->fallback_resources; *res; res++)
623	    XrmPutLineResource(&fdb, *res);
624	(void)XrmCombineDatabase(fdb, &db, False);
625    }
626    UNLOCK_PROCESS;
627    UNLOCK_APP(app);
628    return db;
629}
630
631/*
632 * Merge two option tables, allowing the second to over-ride the first,
633 * so that ambiguous abbreviations can be noticed.  The merge attempts
634 * to make the resulting table lexicographically sorted, but succeeds
635 * only if the first source table is sorted.  Though it _is_ recommended
636 * (for optimizations later in XrmParseCommand), it is not required
637 * that either source table be sorted.
638 *
639 * Caller is responsible for freeing the returned option table.
640 */
641
642static void _MergeOptionTables(
643    const XrmOptionDescRec *src1,
644    Cardinal num_src1,
645    const XrmOptionDescRec *src2,
646    Cardinal num_src2,
647    XrmOptionDescRec **dst,
648    Cardinal *num_dst)
649{
650    XrmOptionDescRec *table, *endP;
651    register XrmOptionDescRec *opt1, *whereP, *dstP;
652    register const XrmOptionDescRec *opt2;
653    int i1;
654    Cardinal i2;
655    int dst_len, order;
656    Boolean found;
657    enum {Check, NotSorted, IsSorted} sort_order = Check;
658
659    *dst = table = (XrmOptionDescRec*)
660	__XtMalloc( sizeof(XrmOptionDescRec) * (num_src1 + num_src2) );
661
662    (void) memmove(table, src1, sizeof(XrmOptionDescRec) * num_src1 );
663    if (num_src2 == 0) {
664	*num_dst = num_src1;
665	return;
666    }
667    endP = &table[dst_len = num_src1];
668    for (opt2 = src2, i2= 0; i2 < num_src2; opt2++, i2++) {
669	found = False;
670	whereP = endP-1;	/* assume new option goes at the end */
671	for (opt1 = table, i1 = 0; i1 < dst_len; opt1++, i1++) {
672	    /* have to walk the entire new table so new list is ordered
673	       (if src1 was ordered) */
674	    if (sort_order == Check && i1 > 0
675		&& strcmp(opt1->option, (opt1-1)->option) < 0)
676		sort_order = NotSorted;
677	    if ((order = strcmp(opt1->option, opt2->option)) == 0) {
678		/* same option names; just overwrite opt1 with opt2 */
679		*opt1 = *opt2;
680		found = True;
681		break;
682		}
683	    /* else */
684	    if (sort_order == IsSorted && order > 0) {
685		/* insert before opt1 to preserve order */
686		/* shift rest of table forward to make room for new entry */
687		for (dstP = endP++; dstP > opt1; dstP--)
688		    *dstP = *(dstP-1);
689		*opt1 = *opt2;
690		dst_len++;
691		found = True;
692		break;
693	    }
694	    /* else */
695	    if (order < 0)
696		/* opt2 sorts after opt1, so remember this position */
697		whereP = opt1;
698	}
699	if (sort_order == Check && i1 == dst_len)
700	    sort_order = IsSorted;
701	if (!found) {
702	   /* when we get here, whereP points to the last entry in the
703	      destination that sorts before "opt2".  Shift rest of table
704	      forward and insert "opt2" after whereP. */
705	    whereP++;
706	    for (dstP = endP++; dstP > whereP; dstP--)
707		*dstP = *(dstP-1);
708	    *whereP = *opt2;
709	    dst_len++;
710	}
711    }
712    *num_dst = dst_len;
713}
714
715
716/* NOTE: name, class, and type must be permanent strings */
717static Boolean _GetResource(
718    Display *dpy,
719    XrmSearchList list,
720    String name,
721    String class,
722    String type,
723    XrmValue* value)
724{
725    XrmRepresentation db_type;
726    XrmValue db_value;
727    XrmName Qname = XrmPermStringToQuark(name);
728    XrmClass Qclass = XrmPermStringToQuark(class);
729    XrmRepresentation Qtype = XrmPermStringToQuark(type);
730
731    if (XrmQGetSearchResource(list, Qname, Qclass, &db_type, &db_value)) {
732	if (db_type == Qtype) {
733	    if (Qtype == _XtQString)
734		*(String*)value->addr = db_value.addr;
735	    else
736		(void) memmove(value->addr, db_value.addr, value->size );
737	    return True;
738	} else {
739	    WidgetRec widget; /* hack, hack */
740	    bzero( &widget, sizeof(widget) );
741	    widget.core.self = &widget;
742	    widget.core.widget_class = coreWidgetClass;
743	    widget.core.screen = (Screen*)DefaultScreenOfDisplay(dpy);
744	    XtInitializeWidgetClass(coreWidgetClass);
745	    if (_XtConvert(&widget,db_type,&db_value,Qtype,value,NULL)) {
746		return True;
747	    }
748	}
749    }
750    return False;
751}
752
753XrmDatabase _XtPreparseCommandLine(
754    XrmOptionDescRec *urlist,
755    Cardinal num_urs,
756    int argc,
757    String *argv,
758    /* return */
759    String *applName,
760    String *displayName,
761    String *language)
762{
763    XrmDatabase db = NULL;
764    XrmOptionDescRec *options;
765    Cardinal num_options;
766    XrmName name_list[3];
767    XrmName class_list[3];
768    XrmRepresentation type;
769    XrmValue val;
770    String *targv;
771    int targc = argc;
772
773    targv = (String *) __XtMalloc(sizeof(char *) * argc);
774    (void) memmove(targv, argv, sizeof(char *) * argc);
775    _MergeOptionTables(opTable, XtNumber(opTable), urlist, num_urs,
776		       &options, &num_options);
777    name_list[0] = class_list[0] = XrmPermStringToQuark(".");
778    name_list[2] = class_list[2] = NULLQUARK;
779    XrmParseCommand(&db, options, num_options, ".", &targc, targv);
780    if (applName) {
781	name_list[1] = XrmPermStringToQuark("name");
782	if (XrmQGetResource(db, name_list, name_list, &type, &val) &&
783	    type == _XtQString)
784	    *applName = val.addr;
785    }
786    if (displayName) {
787	name_list[1] = XrmPermStringToQuark("display");
788	if (XrmQGetResource(db, name_list, name_list, &type, &val) &&
789	    type == _XtQString)
790	    *displayName = val.addr;
791    }
792    if (language) {
793	name_list[1] = XrmPermStringToQuark("xnlLanguage");
794	class_list[1] = XrmPermStringToQuark("XnlLanguage");
795	if (XrmQGetResource(db, name_list, class_list, &type, &val) &&
796	    type == _XtQString)
797	    *language = val.addr;
798    }
799
800    XtFree((char *)targv);
801    XtFree((char *)options);
802    return db;
803}
804
805
806static void GetLanguage(
807    Display *dpy,
808    XtPerDisplay pd)
809{
810    XrmRepresentation type;
811    XrmValue value;
812    XrmName name_list[3];
813    XrmName class_list[3];
814
815    LOCK_PROCESS;
816    if (! pd->language) {
817	name_list[0] = pd->name;
818	name_list[1] = XrmPermStringToQuark("xnlLanguage");
819	class_list[0] = pd->class;
820	class_list[1] = XrmPermStringToQuark("XnlLanguage");
821	name_list[2] = class_list[2] = NULLQUARK;
822	if (!pd->server_db)
823	    CombineUserDefaults(dpy, &pd->server_db);
824	if (pd->server_db &&
825	    XrmQGetResource(pd->server_db,name_list,class_list, &type, &value)
826	    && type == _XtQString)
827	    pd->language = (char *) value.addr;
828    }
829
830    if (pd->appContext->langProcRec.proc) {
831	if (! pd->language) pd->language = "";
832	pd->language = (*pd->appContext->langProcRec.proc)
833	    (dpy, pd->language, pd->appContext->langProcRec.closure);
834    }
835    else if (! pd->language || pd->language[0] == '\0') /* R4 compatibility */
836	pd->language = getenv("LANG");
837
838    if (pd->language) pd->language = XtNewString(pd->language);
839    UNLOCK_PROCESS;
840}
841
842static void ProcessInternalConnection (
843    XtPointer client_data,
844    int* fd,
845    XtInputId* id)
846{
847    XProcessInternalConnection ((Display *) client_data, *fd);
848}
849
850static void ConnectionWatch (
851    Display* dpy,
852    XPointer client_data,
853    int fd,
854    Bool opening,
855    XPointer* watch_data)
856{
857    XtInputId* iptr;
858    XtAppContext app = XtDisplayToApplicationContext(dpy);
859
860    if (opening) {
861	iptr = (XtInputId *) __XtMalloc(sizeof(XtInputId));
862	*iptr = XtAppAddInput(app, fd, (XtPointer) XtInputReadMask,
863			      ProcessInternalConnection, client_data);
864	*watch_data = (XPointer) iptr;
865    } else {
866	iptr = (XtInputId *) *watch_data;
867	XtRemoveInput(*iptr);
868        (void) XtFree(*watch_data);
869    }
870}
871
872void _XtDisplayInitialize(
873	Display *dpy,
874        XtPerDisplay pd,
875	_Xconst char* name,
876	XrmOptionDescRec *urlist,
877	Cardinal num_urs,
878	int *argc,
879	char **argv)
880{
881	Boolean tmp_bool;
882	XrmValue value;
883	XrmOptionDescRec *options;
884	Cardinal num_options;
885	XrmDatabase db;
886	XrmName name_list[2];
887	XrmClass class_list[2];
888	XrmHashTable* search_list;
889	int search_list_size = SEARCH_LIST_SIZE;
890
891	GetLanguage(dpy, pd);
892
893	/* Parse the command line and remove Xt arguments from argv */
894	_MergeOptionTables( opTable, XtNumber(opTable), urlist, num_urs,
895			    &options, &num_options );
896	XrmParseCommand(&pd->cmd_db, options, num_options, name, argc, argv);
897
898	db = XtScreenDatabase(DefaultScreenOfDisplay(dpy));
899
900	if (!(search_list = (XrmHashTable*)
901		       ALLOCATE_LOCAL( SEARCH_LIST_SIZE*sizeof(XrmHashTable))))
902	    _XtAllocError(NULL);
903	name_list[0] = pd->name;
904	class_list[0] = pd->class;
905	name_list[1] = NULLQUARK;
906	class_list[1] = NULLQUARK;
907
908	while (!XrmQGetSearchList(db, name_list, class_list,
909				  search_list, search_list_size)) {
910	    XrmHashTable* old = search_list;
911	    Cardinal size = (search_list_size*=2)*sizeof(XrmHashTable);
912	    if (!(search_list = (XrmHashTable*)ALLOCATE_LOCAL(size)))
913		_XtAllocError(NULL);
914	    (void) memmove((char*)search_list, (char*)old, (size>>1) );
915	    DEALLOCATE_LOCAL(old);
916	}
917
918	value.size = sizeof(tmp_bool);
919	value.addr = (XtPointer)&tmp_bool;
920	if (_GetResource(dpy, search_list, "synchronous", "Synchronous",
921			 XtRBoolean, &value)) {
922	    int i;
923	    Display **dpyP = pd->appContext->list;
924	    pd->appContext->sync = tmp_bool;
925	    for (i = pd->appContext->count; i; dpyP++, i--) {
926		(void) XSynchronize(*dpyP, (Bool)tmp_bool);
927	    }
928	} else {
929	    (void) XSynchronize(dpy, (Bool)pd->appContext->sync);
930	}
931
932	if (_GetResource(dpy, search_list, "reverseVideo", "ReverseVideo",
933			 XtRBoolean, &value)
934	        && tmp_bool) {
935	    pd->rv = True;
936	}
937
938	value.size = sizeof(pd->multi_click_time);
939	value.addr = (XtPointer)&pd->multi_click_time;
940	if (!_GetResource(dpy, search_list,
941			  "multiClickTime", "MultiClickTime",
942			  XtRInt, &value)) {
943	    pd->multi_click_time = 200;
944	}
945
946	value.size = sizeof(pd->appContext->selectionTimeout);
947	value.addr = (XtPointer)&pd->appContext->selectionTimeout;
948	(void)_GetResource(dpy, search_list,
949			   "selectionTimeout", "SelectionTimeout",
950			   XtRInt, &value);
951
952#ifndef NO_IDENTIFY_WINDOWS
953	value.size = sizeof(pd->appContext->identify_windows);
954	value.addr = (XtPointer)&pd->appContext->identify_windows;
955	(void)_GetResource(dpy, search_list,
956			   "xtIdentifyWindows", "XtDebug",
957			   XtRBoolean, &value);
958#endif
959
960	XAddConnectionWatch(dpy, ConnectionWatch, (XPointer) dpy);
961
962	XtFree( (XtPointer)options );
963	DEALLOCATE_LOCAL( search_list );
964}
965
966/*	Function Name: XtAppSetFallbackResources
967 *	Description: Sets the fallback resource list that will be loaded
968 *                   at display initialization time.
969 *	Arguments: app_context - the app context.
970 *                 specification_list - the resource specification list.
971 *	Returns: none.
972 */
973
974void
975XtAppSetFallbackResources(
976    XtAppContext app_context,
977    String *specification_list)
978{
979    LOCK_APP(app_context);
980    app_context->fallback_resources = specification_list;
981    UNLOCK_APP(app_context);
982}
983
984
985Widget XtOpenApplication(XtAppContext *app_context_return,
986			 _Xconst char *application_class,
987			 XrmOptionDescRec *options, Cardinal num_options,
988			 int *argc_in_out, String *argv_in_out,
989			 String *fallback_resources, WidgetClass widget_class,
990			 ArgList args_in, Cardinal num_args_in)
991{
992    XtAppContext app_con;
993    Display * dpy;
994    register int saved_argc = *argc_in_out;
995    Widget root;
996    Arg args[3], *merged_args;
997    Cardinal num = 0;
998
999    XtToolkitInitialize(); /* cannot be moved into _XtAppInit */
1000
1001    dpy = _XtAppInit(&app_con, (String)application_class, options, num_options,
1002		     argc_in_out, &argv_in_out, fallback_resources);
1003
1004    LOCK_APP(app_con);
1005    XtSetArg(args[num], XtNscreen, DefaultScreenOfDisplay(dpy)); num++;
1006    XtSetArg(args[num], XtNargc, saved_argc);	                 num++;
1007    XtSetArg(args[num], XtNargv, argv_in_out);	                 num++;
1008
1009    merged_args = XtMergeArgLists(args_in, num_args_in, args, num);
1010    num += num_args_in;
1011
1012    root = XtAppCreateShell(NULL, application_class, widget_class, dpy,
1013			    merged_args, num);
1014
1015    if (app_context_return)
1016	*app_context_return = app_con;
1017
1018    XtFree((XtPointer)merged_args);
1019    XtFree((XtPointer)argv_in_out);
1020    UNLOCK_APP(app_con);
1021    return root;
1022}
1023
1024
1025Widget
1026XtAppInitialize(
1027    XtAppContext * app_context_return,
1028    _Xconst char* application_class,
1029    XrmOptionDescRec *options,
1030    Cardinal num_options,
1031    int *argc_in_out,
1032    String *argv_in_out,
1033    String *fallback_resources,
1034    ArgList args_in,
1035    Cardinal num_args_in)
1036{
1037    return XtOpenApplication(app_context_return, application_class,
1038			     options, num_options,
1039			     argc_in_out, argv_in_out, fallback_resources,
1040			     applicationShellWidgetClass,
1041			     args_in, num_args_in);
1042}
1043
1044
1045/*ARGSUSED*/
1046Widget
1047XtInitialize(
1048    _Xconst char* name,
1049    _Xconst char* classname,
1050    XrmOptionDescRec *options,
1051    Cardinal num_options,
1052    int *argc,
1053    String *argv)
1054{
1055    Widget root;
1056    XtAppContext app_con;
1057    register ProcessContext process = _XtGetProcessContext();
1058
1059    root = XtAppInitialize(&app_con, classname, options, num_options,
1060			   argc, argv, NULL, NULL, (Cardinal) 0);
1061
1062    LOCK_PROCESS;
1063    process->defaultAppContext = app_con;
1064    UNLOCK_PROCESS;
1065    return root;
1066}
1067