Initialize.c revision 0568f49b
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, (size_t) 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              NULL, 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    _XtString 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, (size_t) (len-1));
324	dest[len-1] = '\0';
325    } else {
326	if ((pw = _XGetpwuid(getuid(),pwparams)) != NULL) {
327	    (void) strncpy (dest, pw->pw_name, (size_t)(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    _XtString 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    static char *ptr;
364
365    if (len <= 0 || dest == NULL)
366	return NULL;
367
368    if ((ptr = getenv("HOME"))) {
369	(void) strncpy (dest, ptr, (size_t)(len-1));
370	dest[len-1] = '\0';
371    } else {
372        struct passwd *pw;
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, (size_t)(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    char *dpy_defaults = XResourceManagerString(dpy);
429
430    if (dpy_defaults) {
431	XrmCombineDatabase(XrmGetStringDatabase(dpy_defaults), pdb, False);
432    } else {
433#ifdef __MINGW32__
434	const char *slashDotXdefaults = "/Xdefaults";
435#else
436	const char *slashDotXdefaults = "/.Xdefaults";
437#endif
438	char filename[PATH_MAX];
439	(void) GetRootDirName(filename,
440			PATH_MAX - (int)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 - (int)strlen (slashDotXdefaultsDash) - 1);
578	    (void) strcat(filename, slashDotXdefaultsDash);
579	    len = (int)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    XrmOptionDescRec *opt1, *dstP;
652    const XrmOptionDescRec *opt2;
653    int i1;
654    Cardinal i2;
655    int dst_len, order;
656    enum {Check, NotSorted, IsSorted} sort_order = Check;
657
658    *dst = table = (XrmOptionDescRec*)
659	__XtMalloc( (Cardinal)(sizeof(XrmOptionDescRec) * (num_src1 + num_src2) ));
660
661    (void) memmove(table, src1, sizeof(XrmOptionDescRec) * num_src1 );
662    if (num_src2 == 0) {
663	*num_dst = num_src1;
664	return;
665    }
666    endP = &table[dst_len = (int)num_src1];
667    for (opt2 = src2, i2= 0; i2 < num_src2; opt2++, i2++) {
668        XrmOptionDescRec *whereP;
669        Boolean found;
670
671	found = False;
672	whereP = endP-1;	/* assume new option goes at the end */
673	for (opt1 = table, i1 = 0; i1 < dst_len; opt1++, i1++) {
674	    /* have to walk the entire new table so new list is ordered
675	       (if src1 was ordered) */
676	    if (sort_order == Check && i1 > 0
677		&& strcmp(opt1->option, (opt1-1)->option) < 0)
678		sort_order = NotSorted;
679	    if ((order = strcmp(opt1->option, opt2->option)) == 0) {
680		/* same option names; just overwrite opt1 with opt2 */
681		*opt1 = *opt2;
682		found = True;
683		break;
684		}
685	    /* else */
686	    if (sort_order == IsSorted && order > 0) {
687		/* insert before opt1 to preserve order */
688		/* shift rest of table forward to make room for new entry */
689		for (dstP = endP++; dstP > opt1; dstP--)
690		    *dstP = *(dstP-1);
691		*opt1 = *opt2;
692		dst_len++;
693		found = True;
694		break;
695	    }
696	    /* else */
697	    if (order < 0)
698		/* opt2 sorts after opt1, so remember this position */
699		whereP = opt1;
700	}
701	if (sort_order == Check && i1 == dst_len)
702	    sort_order = IsSorted;
703	if (!found) {
704	   /* when we get here, whereP points to the last entry in the
705	      destination that sorts before "opt2".  Shift rest of table
706	      forward and insert "opt2" after whereP. */
707	    whereP++;
708	    for (dstP = endP++; dstP > whereP; dstP--)
709		*dstP = *(dstP-1);
710	    *whereP = *opt2;
711	    dst_len++;
712	}
713    }
714    *num_dst = (Cardinal)dst_len;
715}
716
717
718/* NOTE: name, class, and type must be permanent strings */
719static Boolean _GetResource(
720    Display *dpy,
721    XrmSearchList list,
722    String name,
723    String class,
724    String type,
725    XrmValue* value)
726{
727    XrmRepresentation db_type;
728    XrmValue db_value;
729    XrmName Qname = XrmPermStringToQuark(name);
730    XrmClass Qclass = XrmPermStringToQuark(class);
731    XrmRepresentation Qtype = XrmPermStringToQuark(type);
732
733    if (XrmQGetSearchResource(list, Qname, Qclass, &db_type, &db_value)) {
734	if (db_type == Qtype) {
735	    if (Qtype == _XtQString)
736		*(String*)value->addr = db_value.addr;
737	    else
738		(void) memmove(value->addr, db_value.addr, value->size );
739	    return True;
740	} else {
741	    WidgetRec widget; /* hack, hack */
742	    memset( &widget, 0, sizeof(widget) );
743	    widget.core.self = &widget;
744	    widget.core.widget_class = coreWidgetClass;
745	    widget.core.screen = (Screen*)DefaultScreenOfDisplay(dpy);
746	    XtInitializeWidgetClass(coreWidgetClass);
747	    if (_XtConvert(&widget,db_type,&db_value,Qtype,value,NULL)) {
748		return True;
749	    }
750	}
751    }
752    return False;
753}
754
755XrmDatabase _XtPreparseCommandLine(
756    XrmOptionDescRec *urlist,
757    Cardinal num_urs,
758    int argc,
759    _XtString *argv,
760    /* return */
761    String *applName,
762    String *displayName,
763    String *language)
764{
765    XrmDatabase db = NULL;
766    XrmOptionDescRec *options;
767    Cardinal num_options;
768    XrmName name_list[3];
769    XrmName class_list[3];
770    XrmRepresentation type;
771    XrmValue val;
772    _XtString *targv;
773    int targc = argc;
774
775    targv = (_XtString *) __XtMalloc((Cardinal)(sizeof(_XtString*) * (size_t)argc));
776    (void) memmove(targv, argv, sizeof(char *) * (size_t) argc);
777    _MergeOptionTables(opTable, XtNumber(opTable), urlist, num_urs,
778		       &options, &num_options);
779    name_list[0] = class_list[0] = XrmPermStringToQuark(".");
780    name_list[2] = class_list[2] = NULLQUARK;
781    XrmParseCommand(&db, options, (int) num_options, ".", &targc, targv);
782    if (applName) {
783	name_list[1] = XrmPermStringToQuark("name");
784	if (XrmQGetResource(db, name_list, name_list, &type, &val) &&
785	    type == _XtQString)
786	    *applName = val.addr;
787    }
788    if (displayName) {
789	name_list[1] = XrmPermStringToQuark("display");
790	if (XrmQGetResource(db, name_list, name_list, &type, &val) &&
791	    type == _XtQString)
792	    *displayName = val.addr;
793    }
794    if (language) {
795	name_list[1] = XrmPermStringToQuark("xnlLanguage");
796	class_list[1] = XrmPermStringToQuark("XnlLanguage");
797	if (XrmQGetResource(db, name_list, class_list, &type, &val) &&
798	    type == _XtQString)
799	    *language = val.addr;
800    }
801
802    XtFree((char *)targv);
803    XtFree((char *)options);
804    return db;
805}
806
807
808static void GetLanguage(
809    Display *dpy,
810    XtPerDisplay pd)
811{
812    XrmRepresentation type;
813    XrmValue value;
814    XrmName name_list[3];
815    XrmName class_list[3];
816
817    LOCK_PROCESS;
818    if (! pd->language) {
819	name_list[0] = pd->name;
820	name_list[1] = XrmPermStringToQuark("xnlLanguage");
821	class_list[0] = pd->class;
822	class_list[1] = XrmPermStringToQuark("XnlLanguage");
823	name_list[2] = class_list[2] = NULLQUARK;
824	if (!pd->server_db)
825	    CombineUserDefaults(dpy, &pd->server_db);
826	if (pd->server_db &&
827	    XrmQGetResource(pd->server_db,name_list,class_list, &type, &value)
828	    && type == _XtQString)
829	    pd->language = (char *) value.addr;
830    }
831
832    if (pd->appContext->langProcRec.proc) {
833	if (! pd->language) pd->language = "";
834	pd->language = (*pd->appContext->langProcRec.proc)
835	    (dpy, pd->language, pd->appContext->langProcRec.closure);
836    }
837    else if (! pd->language || pd->language[0] == '\0') /* R4 compatibility */
838	pd->language = getenv("LANG");
839
840    if (pd->language) pd->language = XtNewString(pd->language);
841    UNLOCK_PROCESS;
842}
843
844static void ProcessInternalConnection (
845    XtPointer client_data,
846    int* fd,
847    XtInputId* id)
848{
849    XProcessInternalConnection ((Display *) client_data, *fd);
850}
851
852static void ConnectionWatch (
853    Display* dpy,
854    XPointer client_data,
855    int fd,
856    Bool opening,
857    XPointer* watch_data)
858{
859    XtInputId* iptr;
860    XtAppContext app = XtDisplayToApplicationContext(dpy);
861
862    if (opening) {
863	iptr = (XtInputId *) __XtMalloc(sizeof(XtInputId));
864	*iptr = XtAppAddInput(app, fd, (XtPointer) XtInputReadMask,
865			      ProcessInternalConnection, client_data);
866	*watch_data = (XPointer) iptr;
867    } else {
868	iptr = (XtInputId *) *watch_data;
869	XtRemoveInput(*iptr);
870        (void) XtFree(*watch_data);
871    }
872}
873
874void _XtDisplayInitialize(
875	Display *dpy,
876        XtPerDisplay pd,
877	_Xconst char* name,
878	XrmOptionDescRec *urlist,
879	Cardinal num_urs,
880	int *argc,
881	char **argv)
882{
883	Boolean tmp_bool;
884	XrmValue value;
885	XrmOptionDescRec *options;
886	Cardinal num_options;
887	XrmDatabase db;
888	XrmName name_list[2];
889	XrmClass class_list[2];
890	XrmHashTable* search_list;
891	int search_list_size = SEARCH_LIST_SIZE;
892
893	GetLanguage(dpy, pd);
894
895	/* Parse the command line and remove Xt arguments from argv */
896	_MergeOptionTables( opTable, XtNumber(opTable), urlist, num_urs,
897			    &options, &num_options );
898	XrmParseCommand(&pd->cmd_db, options, (int) num_options, name, argc, argv);
899
900	db = XtScreenDatabase(DefaultScreenOfDisplay(dpy));
901
902	if (!(search_list = (XrmHashTable*)
903		       ALLOCATE_LOCAL( SEARCH_LIST_SIZE*sizeof(XrmHashTable))))
904	    _XtAllocError(NULL);
905	name_list[0] = pd->name;
906	class_list[0] = pd->class;
907	name_list[1] = NULLQUARK;
908	class_list[1] = NULLQUARK;
909
910	while (!XrmQGetSearchList(db, name_list, class_list,
911				  search_list, search_list_size)) {
912	    XrmHashTable* old = search_list;
913	    Cardinal size = (Cardinal) ((size_t)(search_list_size *= 2)*sizeof(XrmHashTable));
914	    if (!(search_list = (XrmHashTable*)ALLOCATE_LOCAL(size)))
915		_XtAllocError(NULL);
916	    (void) memmove((char*)search_list, (char*)old, (size>>1) );
917	    DEALLOCATE_LOCAL(old);
918	}
919
920	value.size = sizeof(tmp_bool);
921	value.addr = (XtPointer)&tmp_bool;
922	if (_GetResource(dpy, search_list, "synchronous", "Synchronous",
923			 XtRBoolean, &value)) {
924	    int i;
925	    Display **dpyP = pd->appContext->list;
926	    pd->appContext->sync = tmp_bool;
927	    for (i = pd->appContext->count; i; dpyP++, i--) {
928		(void) XSynchronize(*dpyP, (Bool)tmp_bool);
929	    }
930	} else {
931	    (void) XSynchronize(dpy, (Bool)pd->appContext->sync);
932	}
933
934	if (_GetResource(dpy, search_list, "reverseVideo", "ReverseVideo",
935			 XtRBoolean, &value)
936	        && tmp_bool) {
937	    pd->rv = True;
938	}
939
940	value.size = sizeof(pd->multi_click_time);
941	value.addr = (XtPointer)&pd->multi_click_time;
942	if (!_GetResource(dpy, search_list,
943			  "multiClickTime", "MultiClickTime",
944			  XtRInt, &value)) {
945	    pd->multi_click_time = 200;
946	}
947
948	value.size = sizeof(pd->appContext->selectionTimeout);
949	value.addr = (XtPointer)&pd->appContext->selectionTimeout;
950	(void)_GetResource(dpy, search_list,
951			   "selectionTimeout", "SelectionTimeout",
952			   XtRInt, &value);
953
954#ifndef NO_IDENTIFY_WINDOWS
955	value.size = sizeof(pd->appContext->identify_windows);
956	value.addr = (XtPointer)&pd->appContext->identify_windows;
957	(void)_GetResource(dpy, search_list,
958			   "xtIdentifyWindows", "XtDebug",
959			   XtRBoolean, &value);
960#endif
961
962	XAddConnectionWatch(dpy, ConnectionWatch, (XPointer) dpy);
963
964	XtFree( (XtPointer)options );
965	DEALLOCATE_LOCAL( search_list );
966}
967
968/*	Function Name: XtAppSetFallbackResources
969 *	Description: Sets the fallback resource list that will be loaded
970 *                   at display initialization time.
971 *	Arguments: app_context - the app context.
972 *                 specification_list - the resource specification list.
973 *	Returns: none.
974 */
975
976void
977XtAppSetFallbackResources(
978    XtAppContext app_context,
979    String *specification_list)
980{
981    LOCK_APP(app_context);
982    app_context->fallback_resources = specification_list;
983    UNLOCK_APP(app_context);
984}
985
986
987Widget XtOpenApplication(XtAppContext *app_context_return,
988			 _Xconst char *application_class,
989			 XrmOptionDescRec *options, Cardinal num_options,
990			 int *argc_in_out, _XtString *argv_in_out,
991			 String *fallback_resources, WidgetClass widget_class,
992			 ArgList args_in, Cardinal num_args_in)
993{
994    XtAppContext app_con;
995    Display * dpy;
996    register int saved_argc = *argc_in_out;
997    Widget root;
998    Arg args[3], *merged_args;
999    Cardinal num = 0;
1000
1001    XtToolkitInitialize(); /* cannot be moved into _XtAppInit */
1002
1003    dpy = _XtAppInit(&app_con, (String)application_class, options, num_options,
1004		     argc_in_out, &argv_in_out, fallback_resources);
1005
1006    LOCK_APP(app_con);
1007    XtSetArg(args[num], XtNscreen, DefaultScreenOfDisplay(dpy)); num++;
1008    XtSetArg(args[num], XtNargc, saved_argc);	                 num++;
1009    XtSetArg(args[num], XtNargv, argv_in_out);	                 num++;
1010
1011    merged_args = XtMergeArgLists(args_in, num_args_in, args, num);
1012    num += num_args_in;
1013
1014    root = XtAppCreateShell(NULL, application_class, widget_class, dpy,
1015			    merged_args, num);
1016
1017    if (app_context_return)
1018	*app_context_return = app_con;
1019
1020    XtFree((XtPointer)merged_args);
1021    XtFree((XtPointer)argv_in_out);
1022    UNLOCK_APP(app_con);
1023    return root;
1024}
1025
1026
1027Widget
1028XtAppInitialize(
1029    XtAppContext * app_context_return,
1030    _Xconst char* application_class,
1031    XrmOptionDescRec *options,
1032    Cardinal num_options,
1033    int *argc_in_out,
1034    _XtString *argv_in_out,
1035    String *fallback_resources,
1036    ArgList args_in,
1037    Cardinal num_args_in)
1038{
1039    return XtOpenApplication(app_context_return, application_class,
1040			     options, num_options,
1041			     argc_in_out, argv_in_out, fallback_resources,
1042			     applicationShellWidgetClass,
1043			     args_in, num_args_in);
1044}
1045
1046
1047/*ARGSUSED*/
1048Widget
1049XtInitialize(
1050    _Xconst _XtString name,
1051    _Xconst _XtString classname,
1052    XrmOptionDescRec *options,
1053    Cardinal num_options,
1054    int *argc,
1055    _XtString *argv)
1056{
1057    Widget root;
1058    XtAppContext app_con;
1059    register ProcessContext process = _XtGetProcessContext();
1060
1061    root = XtAppInitialize(&app_con, classname, options, num_options,
1062			   argc, argv, NULL, NULL, (Cardinal) 0);
1063
1064    LOCK_PROCESS;
1065    process->defaultAppContext = app_con;
1066    UNLOCK_PROCESS;
1067    return root;
1068}
1069