Initialize.c revision 9e7bcd65
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
248asm (".data\n\
249 .globl __XtInherit        \n\
250 __XtInherit:      jmp *_y \n\
251  _y: .long ___XtInherit   \n\
252    .text                 \n");
253
254#define _XtInherit __XtInherit
255#endif
256
257
258void _XtInherit(void)
259{
260    XtErrorMsg("invalidProcedure","inheritanceProc",XtCXtToolkitError,
261            "Unresolved inheritance operation",
262              (String *)NULL, (Cardinal *)NULL);
263}
264
265
266void XtToolkitInitialize(void)
267{
268    static Boolean initialized = False;
269
270    LOCK_PROCESS;
271    if (initialized) {
272	UNLOCK_PROCESS;
273	return;
274    }
275    initialized = True;
276    UNLOCK_PROCESS;
277    /* Resource management initialization */
278    XrmInitialize();
279    _XtResourceListInitialize();
280
281    /* Other intrinsic intialization */
282    _XtConvertInitialize();
283    _XtEventInitialize();
284    _XtTranslateInitialize();
285
286    /* Some apps rely on old (broken) XtAppPeekEvent behavior */
287    if(getenv("XTAPPPEEKEVENT_SKIPTIMER"))
288	XtAppPeekEvent_SkipTimer = True;
289    else
290	XtAppPeekEvent_SkipTimer = False;
291}
292
293
294String _XtGetUserName(
295    String dest,
296    int len)
297{
298#ifdef WIN32
299    String ptr = NULL;
300
301    if ((ptr = getenv("USERNAME"))) {
302	(void) strncpy (dest, ptr, len-1);
303	dest[len-1] = '\0';
304    } else
305	*dest = '\0';
306#else
307#ifdef X_NEEDS_PWPARAMS
308    _Xgetpwparams pwparams;
309#endif
310    struct passwd *pw;
311    char* ptr;
312
313    if ((ptr = getenv("USER"))) {
314	(void) strncpy (dest, ptr, len-1);
315	dest[len-1] = '\0';
316    } else {
317	if ((pw = _XGetpwuid(getuid(),pwparams)) != NULL) {
318	    (void) strncpy (dest, pw->pw_name, len-1);
319	    dest[len-1] = '\0';
320	} else
321	    *dest = '\0';
322    }
323#endif
324    return dest;
325}
326
327
328static String GetRootDirName(
329    String dest,
330    int len)
331{
332#ifdef WIN32
333    register char *ptr1;
334    register char *ptr2 = NULL;
335    int len1 = 0, len2 = 0;
336
337    if (ptr1 = getenv("HOME")) {	/* old, deprecated */
338	len1 = strlen (ptr1);
339    } else if ((ptr1 = getenv("HOMEDRIVE")) && (ptr2 = getenv("HOMEDIR"))) {
340	len1 = strlen (ptr1);
341	len2 = strlen (ptr2);
342    } else if (ptr2 = getenv("USERNAME")) {
343	len1 = strlen (ptr1 = "/users/");
344	len2 = strlen (ptr2);
345    }
346    if ((len1 + len2 + 1) < len)
347	sprintf (dest, "%s%s", ptr1, (ptr2) ? ptr2 : "");
348    else
349	*dest = '\0';
350#else
351#ifdef X_NEEDS_PWPARAMS
352    _Xgetpwparams pwparams;
353#endif
354    struct passwd *pw;
355    static char *ptr;
356
357    if (len <= 0 || dest == NULL)
358	return NULL;
359
360    if ((ptr = getenv("HOME"))) {
361	(void) strncpy (dest, ptr, len-1);
362	dest[len-1] = '\0';
363    } else {
364	if ((ptr = getenv("USER")))
365	    pw = _XGetpwnam(ptr,pwparams);
366	else
367 	    pw = _XGetpwuid(getuid(),pwparams);
368	if (pw != NULL) {
369	    (void) strncpy (dest, pw->pw_dir, len-1);
370	    dest[len-1] = '\0';
371	} else
372	    *dest = '\0';
373    }
374#endif
375    return dest;
376}
377
378static void CombineAppUserDefaults(
379    Display *dpy,
380    XrmDatabase *pdb)
381{
382    char* filename;
383    char* path = NULL;
384    Boolean deallocate = False;
385
386    if (!(path = getenv("XUSERFILESEARCHPATH"))) {
387#if !defined(WIN32) || !defined(__MINGW32__)
388	char *old_path;
389	char homedir[PATH_MAX];
390	GetRootDirName(homedir, PATH_MAX);
391	if (!(old_path = getenv("XAPPLRESDIR"))) {
392	    XtAsprintf(&path,
393		       "%s/%%L/%%N%%C:%s/%%l/%%N%%C:%s/%%N%%C:%s/%%L/%%N:%s/%%l/%%N:%s/%%N",
394		       homedir, homedir, homedir, homedir, homedir, homedir);
395	} else {
396	    XtAsprintf(&path,
397		       "%s/%%L/%%N%%C:%s/%%l/%%N%%C:%s/%%N%%C:%s/%%N%%C:%s/%%L/%%N:%s/%%l/%%N:%s/%%N:%s/%%N",
398		       old_path, old_path, old_path, homedir,
399		       old_path, old_path, old_path, homedir);
400	}
401	deallocate = True;
402#endif
403    }
404
405    filename = XtResolvePathname(dpy, NULL, NULL, NULL, path, NULL, 0, NULL);
406    if (filename) {
407	(void)XrmCombineFileDatabase(filename, pdb, False);
408	XtFree(filename);
409    }
410
411    if (deallocate)
412	XtFree(path);
413}
414
415static void CombineUserDefaults(
416    Display *dpy,
417    XrmDatabase *pdb)
418{
419#ifdef __MINGW32__
420    const char *slashDotXdefaults = "/Xdefaults";
421#else
422    const char *slashDotXdefaults = "/.Xdefaults";
423#endif
424    char *dpy_defaults = XResourceManagerString(dpy);
425
426    if (dpy_defaults) {
427	XrmCombineDatabase(XrmGetStringDatabase(dpy_defaults), pdb, False);
428    } else {
429	char filename[PATH_MAX];
430	(void) GetRootDirName(filename,
431			PATH_MAX - strlen (slashDotXdefaults) - 1);
432	(void) strcat(filename, slashDotXdefaults);
433	(void)XrmCombineFileDatabase(filename, pdb, False);
434    }
435}
436
437/*ARGSUSED*/
438static Bool StoreDBEntry(
439    XrmDatabase		*db,
440    XrmBindingList      bindings,
441    XrmQuarkList	quarks,
442    XrmRepresentation   *type,
443    XrmValuePtr		value,
444    XPointer		data)
445{
446    XrmQPutResource((XrmDatabase *)data, bindings, quarks, *type, value);
447    return False;
448}
449
450static XrmDatabase CopyDB(XrmDatabase db)
451{
452    XrmDatabase copy = NULL;
453    XrmQuark empty = NULLQUARK;
454
455    XrmEnumerateDatabase(db, &empty, &empty, XrmEnumAllLevels,
456			 StoreDBEntry, (XPointer)&copy);
457    return copy;
458}
459
460/*ARGSUSED*/
461static String _XtDefaultLanguageProc(
462    Display   *dpy,	/* unused */
463    String     xnl,
464    XtPointer  closure)	/* unused */
465{
466    if (! setlocale(LC_ALL, xnl))
467	XtWarning("locale not supported by C library, locale unchanged");
468
469    if (! XSupportsLocale()) {
470	XtWarning("locale not supported by Xlib, locale set to C");
471	setlocale(LC_ALL, "C");
472    }
473    if (! XSetLocaleModifiers(""))
474	XtWarning("X locale modifiers not supported, using default");
475
476    return setlocale(LC_ALL, NULL); /* re-query in case overwritten */
477}
478
479XtLanguageProc XtSetLanguageProc(
480    XtAppContext      app,
481    XtLanguageProc    proc,
482    XtPointer         closure)
483{
484    XtLanguageProc    old;
485
486    if (!proc) {
487	proc = _XtDefaultLanguageProc;
488	closure = NULL;
489    }
490
491    if (app) {
492	LOCK_APP(app);
493	LOCK_PROCESS;
494	/* set langProcRec only for this application context */
495        old = app->langProcRec.proc;
496        app->langProcRec.proc = proc;
497        app->langProcRec.closure = closure;
498	UNLOCK_PROCESS;
499	UNLOCK_APP(app);
500    } else {
501	/* set langProcRec for all application contexts */
502        ProcessContext process;
503
504	LOCK_PROCESS;
505        process = _XtGetProcessContext();
506        old = process->globalLangProcRec.proc;
507	process->globalLangProcRec.proc = proc;
508	process->globalLangProcRec.closure = closure;
509        app = process->appContextList;
510        while (app) {
511            app->langProcRec.proc = proc;
512            app->langProcRec.closure = closure;
513	    app = app->next;
514        }
515	UNLOCK_PROCESS;
516    }
517    return (old ? old : _XtDefaultLanguageProc);
518}
519
520XrmDatabase XtScreenDatabase(
521    Screen *screen)
522{
523    int scrno;
524    Bool doing_def;
525    XrmDatabase db, olddb;
526    XtPerDisplay pd;
527    Status do_fallback;
528    char *scr_resources;
529    Display *dpy = DisplayOfScreen(screen);
530    DPY_TO_APPCON(dpy);
531
532    LOCK_APP(app);
533    LOCK_PROCESS;
534    if (screen == DefaultScreenOfDisplay(dpy)) {
535	scrno = DefaultScreen(dpy);
536	doing_def = True;
537    } else {
538	scrno = XScreenNumberOfScreen(screen);
539	doing_def = False;
540    }
541    pd = _XtGetPerDisplay(dpy);
542    if ((db = pd->per_screen_db[scrno])) {
543	UNLOCK_PROCESS;
544	UNLOCK_APP(app);
545	return (doing_def ? XrmGetDatabase(dpy) : db);
546    }
547    scr_resources = XScreenResourceString(screen);
548
549    if (ScreenCount(dpy) == 1) {
550	db = pd->cmd_db;
551	pd->cmd_db = NULL;
552    } else {
553	db = CopyDB(pd->cmd_db);
554    }
555    {   /* Environment defaults */
556	char	filenamebuf[PATH_MAX];
557	char	*filename;
558
559	if (!(filename = getenv("XENVIRONMENT"))) {
560	    int len;
561#ifdef __MINGW32__
562	    const char *slashDotXdefaultsDash = "/Xdefaults-";
563#else
564	    const char *slashDotXdefaultsDash = "/.Xdefaults-";
565#endif
566
567	    (void) GetRootDirName(filename = filenamebuf,
568			PATH_MAX - strlen (slashDotXdefaultsDash) - 1);
569	    (void) strcat(filename, slashDotXdefaultsDash);
570	    len = strlen(filename);
571	    GetHostname (filename+len, PATH_MAX-len);
572	}
573	(void)XrmCombineFileDatabase(filename, &db, False);
574    }
575    if (scr_resources)
576    {   /* Screen defaults */
577	XrmCombineDatabase(XrmGetStringDatabase(scr_resources), &db, False);
578	XFree(scr_resources);
579    }
580    /* Server or host defaults */
581    if (!pd->server_db)
582	CombineUserDefaults(dpy, &db);
583    else {
584	(void) XrmCombineDatabase(pd->server_db, &db, False);
585	pd->server_db = NULL;
586    }
587
588    if (!db)
589	db = XrmGetStringDatabase("");
590    pd->per_screen_db[scrno] = db;
591    olddb = XrmGetDatabase(dpy);
592    /* set database now, for XtResolvePathname to use */
593    XrmSetDatabase(dpy, db);
594    CombineAppUserDefaults(dpy, &db);
595    do_fallback = 1;
596    {   /* System app-defaults */
597	char	*filename;
598
599	if ((filename = XtResolvePathname(dpy, "app-defaults",
600					 NULL, NULL, NULL, NULL, 0, NULL))) {
601	    do_fallback = !XrmCombineFileDatabase(filename, &db, False);
602	    XtFree(filename);
603	}
604    }
605    /* now restore old database, if need be */
606    if (!doing_def)
607	XrmSetDatabase(dpy, olddb);
608    if (do_fallback && pd->appContext->fallback_resources)
609    {   /* Fallback defaults */
610        XrmDatabase fdb = NULL;
611	String *res;
612
613	for (res = pd->appContext->fallback_resources; *res; res++)
614	    XrmPutLineResource(&fdb, *res);
615	(void)XrmCombineDatabase(fdb, &db, False);
616    }
617    UNLOCK_PROCESS;
618    UNLOCK_APP(app);
619    return db;
620}
621
622/*
623 * Merge two option tables, allowing the second to over-ride the first,
624 * so that ambiguous abbreviations can be noticed.  The merge attempts
625 * to make the resulting table lexicographically sorted, but succeeds
626 * only if the first source table is sorted.  Though it _is_ recommended
627 * (for optimizations later in XrmParseCommand), it is not required
628 * that either source table be sorted.
629 *
630 * Caller is responsible for freeing the returned option table.
631 */
632
633static void _MergeOptionTables(
634    const XrmOptionDescRec *src1,
635    Cardinal num_src1,
636    const XrmOptionDescRec *src2,
637    Cardinal num_src2,
638    XrmOptionDescRec **dst,
639    Cardinal *num_dst)
640{
641    XrmOptionDescRec *table, *endP;
642    register XrmOptionDescRec *opt1, *whereP, *dstP;
643    register const XrmOptionDescRec *opt2;
644    int i1;
645    Cardinal i2;
646    int dst_len, order;
647    Boolean found;
648    enum {Check, NotSorted, IsSorted} sort_order = Check;
649
650    *dst = table = (XrmOptionDescRec*)
651	__XtMalloc( sizeof(XrmOptionDescRec) * (num_src1 + num_src2) );
652
653    (void) memmove(table, src1, sizeof(XrmOptionDescRec) * num_src1 );
654    if (num_src2 == 0) {
655	*num_dst = num_src1;
656	return;
657    }
658    endP = &table[dst_len = num_src1];
659    for (opt2 = src2, i2= 0; i2 < num_src2; opt2++, i2++) {
660	found = False;
661	whereP = endP-1;	/* assume new option goes at the end */
662	for (opt1 = table, i1 = 0; i1 < dst_len; opt1++, i1++) {
663	    /* have to walk the entire new table so new list is ordered
664	       (if src1 was ordered) */
665	    if (sort_order == Check && i1 > 0
666		&& strcmp(opt1->option, (opt1-1)->option) < 0)
667		sort_order = NotSorted;
668	    if ((order = strcmp(opt1->option, opt2->option)) == 0) {
669		/* same option names; just overwrite opt1 with opt2 */
670		*opt1 = *opt2;
671		found = True;
672		break;
673		}
674	    /* else */
675	    if (sort_order == IsSorted && order > 0) {
676		/* insert before opt1 to preserve order */
677		/* shift rest of table forward to make room for new entry */
678		for (dstP = endP++; dstP > opt1; dstP--)
679		    *dstP = *(dstP-1);
680		*opt1 = *opt2;
681		dst_len++;
682		found = True;
683		break;
684	    }
685	    /* else */
686	    if (order < 0)
687		/* opt2 sorts after opt1, so remember this position */
688		whereP = opt1;
689	}
690	if (sort_order == Check && i1 == dst_len)
691	    sort_order = IsSorted;
692	if (!found) {
693	   /* when we get here, whereP points to the last entry in the
694	      destination that sorts before "opt2".  Shift rest of table
695	      forward and insert "opt2" after whereP. */
696	    whereP++;
697	    for (dstP = endP++; dstP > whereP; dstP--)
698		*dstP = *(dstP-1);
699	    *whereP = *opt2;
700	    dst_len++;
701	}
702    }
703    *num_dst = dst_len;
704}
705
706
707/* NOTE: name, class, and type must be permanent strings */
708static Boolean _GetResource(
709    Display *dpy,
710    XrmSearchList list,
711    String name,
712    String class,
713    String type,
714    XrmValue* value)
715{
716    XrmRepresentation db_type;
717    XrmValue db_value;
718    XrmName Qname = XrmPermStringToQuark(name);
719    XrmClass Qclass = XrmPermStringToQuark(class);
720    XrmRepresentation Qtype = XrmPermStringToQuark(type);
721
722    if (XrmQGetSearchResource(list, Qname, Qclass, &db_type, &db_value)) {
723	if (db_type == Qtype) {
724	    if (Qtype == _XtQString)
725		*(String*)value->addr = db_value.addr;
726	    else
727		(void) memmove(value->addr, db_value.addr, value->size );
728	    return True;
729	} else {
730	    WidgetRec widget; /* hack, hack */
731	    bzero( &widget, sizeof(widget) );
732	    widget.core.self = &widget;
733	    widget.core.widget_class = coreWidgetClass;
734	    widget.core.screen = (Screen*)DefaultScreenOfDisplay(dpy);
735	    XtInitializeWidgetClass(coreWidgetClass);
736	    if (_XtConvert(&widget,db_type,&db_value,Qtype,value,NULL)) {
737		return True;
738	    }
739	}
740    }
741    return False;
742}
743
744XrmDatabase _XtPreparseCommandLine(
745    XrmOptionDescRec *urlist,
746    Cardinal num_urs,
747    int argc,
748    String *argv,
749    /* return */
750    String *applName,
751    String *displayName,
752    String *language)
753{
754    XrmDatabase db = NULL;
755    XrmOptionDescRec *options;
756    Cardinal num_options;
757    XrmName name_list[3];
758    XrmName class_list[3];
759    XrmRepresentation type;
760    XrmValue val;
761    String *targv;
762    int targc = argc;
763
764    targv = (String *) __XtMalloc(sizeof(char *) * argc);
765    (void) memmove(targv, argv, sizeof(char *) * argc);
766    _MergeOptionTables(opTable, XtNumber(opTable), urlist, num_urs,
767		       &options, &num_options);
768    name_list[0] = class_list[0] = XrmPermStringToQuark(".");
769    name_list[2] = class_list[2] = NULLQUARK;
770    XrmParseCommand(&db, options, num_options, ".", &targc, targv);
771    if (applName) {
772	name_list[1] = XrmPermStringToQuark("name");
773	if (XrmQGetResource(db, name_list, name_list, &type, &val) &&
774	    type == _XtQString)
775	    *applName = val.addr;
776    }
777    if (displayName) {
778	name_list[1] = XrmPermStringToQuark("display");
779	if (XrmQGetResource(db, name_list, name_list, &type, &val) &&
780	    type == _XtQString)
781	    *displayName = val.addr;
782    }
783    if (language) {
784	name_list[1] = XrmPermStringToQuark("xnlLanguage");
785	class_list[1] = XrmPermStringToQuark("XnlLanguage");
786	if (XrmQGetResource(db, name_list, class_list, &type, &val) &&
787	    type == _XtQString)
788	    *language = val.addr;
789    }
790
791    XtFree((char *)targv);
792    XtFree((char *)options);
793    return db;
794}
795
796
797static void GetLanguage(
798    Display *dpy,
799    XtPerDisplay pd)
800{
801    XrmRepresentation type;
802    XrmValue value;
803    XrmName name_list[3];
804    XrmName class_list[3];
805
806    LOCK_PROCESS;
807    if (! pd->language) {
808	name_list[0] = pd->name;
809	name_list[1] = XrmPermStringToQuark("xnlLanguage");
810	class_list[0] = pd->class;
811	class_list[1] = XrmPermStringToQuark("XnlLanguage");
812	name_list[2] = class_list[2] = NULLQUARK;
813	if (!pd->server_db)
814	    CombineUserDefaults(dpy, &pd->server_db);
815	if (pd->server_db &&
816	    XrmQGetResource(pd->server_db,name_list,class_list, &type, &value)
817	    && type == _XtQString)
818	    pd->language = (char *) value.addr;
819    }
820
821    if (pd->appContext->langProcRec.proc) {
822	if (! pd->language) pd->language = "";
823	pd->language = (*pd->appContext->langProcRec.proc)
824	    (dpy, pd->language, pd->appContext->langProcRec.closure);
825    }
826    else if (! pd->language || pd->language[0] == '\0') /* R4 compatibility */
827	pd->language = getenv("LANG");
828
829    if (pd->language) pd->language = XtNewString(pd->language);
830    UNLOCK_PROCESS;
831}
832
833static void ProcessInternalConnection (
834    XtPointer client_data,
835    int* fd,
836    XtInputId* id)
837{
838    XProcessInternalConnection ((Display *) client_data, *fd);
839}
840
841static void ConnectionWatch (
842    Display* dpy,
843    XPointer client_data,
844    int fd,
845    Bool opening,
846    XPointer* watch_data)
847{
848    XtInputId* iptr;
849    XtAppContext app = XtDisplayToApplicationContext(dpy);
850
851    if (opening) {
852	iptr = (XtInputId *) __XtMalloc(sizeof(XtInputId));
853	*iptr = XtAppAddInput(app, fd, (XtPointer) XtInputReadMask,
854			      ProcessInternalConnection, client_data);
855	*watch_data = (XPointer) iptr;
856    } else {
857	iptr = (XtInputId *) *watch_data;
858	XtRemoveInput(*iptr);
859        (void) XtFree(*watch_data);
860    }
861}
862
863void _XtDisplayInitialize(
864	Display *dpy,
865        XtPerDisplay pd,
866	_Xconst char* name,
867	XrmOptionDescRec *urlist,
868	Cardinal num_urs,
869	int *argc,
870	char **argv)
871{
872	Boolean tmp_bool;
873	XrmValue value;
874	XrmOptionDescRec *options;
875	Cardinal num_options;
876	XrmDatabase db;
877	XrmName name_list[2];
878	XrmClass class_list[2];
879	XrmHashTable* search_list;
880	int search_list_size = SEARCH_LIST_SIZE;
881
882	GetLanguage(dpy, pd);
883
884	/* Parse the command line and remove Xt arguments from argv */
885	_MergeOptionTables( opTable, XtNumber(opTable), urlist, num_urs,
886			    &options, &num_options );
887	XrmParseCommand(&pd->cmd_db, options, num_options, name, argc, argv);
888
889	db = XtScreenDatabase(DefaultScreenOfDisplay(dpy));
890
891	if (!(search_list = (XrmHashTable*)
892		       ALLOCATE_LOCAL( SEARCH_LIST_SIZE*sizeof(XrmHashTable))))
893	    _XtAllocError(NULL);
894	name_list[0] = pd->name;
895	class_list[0] = pd->class;
896	name_list[1] = NULLQUARK;
897	class_list[1] = NULLQUARK;
898
899	while (!XrmQGetSearchList(db, name_list, class_list,
900				  search_list, search_list_size)) {
901	    XrmHashTable* old = search_list;
902	    Cardinal size = (search_list_size*=2)*sizeof(XrmHashTable);
903	    if (!(search_list = (XrmHashTable*)ALLOCATE_LOCAL(size)))
904		_XtAllocError(NULL);
905	    (void) memmove((char*)search_list, (char*)old, (size>>1) );
906	    DEALLOCATE_LOCAL(old);
907	}
908
909	value.size = sizeof(tmp_bool);
910	value.addr = (XtPointer)&tmp_bool;
911	if (_GetResource(dpy, search_list, "synchronous", "Synchronous",
912			 XtRBoolean, &value)) {
913	    int i;
914	    Display **dpyP = pd->appContext->list;
915	    pd->appContext->sync = tmp_bool;
916	    for (i = pd->appContext->count; i; dpyP++, i--) {
917		(void) XSynchronize(*dpyP, (Bool)tmp_bool);
918	    }
919	} else {
920	    (void) XSynchronize(dpy, (Bool)pd->appContext->sync);
921	}
922
923	if (_GetResource(dpy, search_list, "reverseVideo", "ReverseVideo",
924			 XtRBoolean, &value)
925	        && tmp_bool) {
926	    pd->rv = True;
927	}
928
929	value.size = sizeof(pd->multi_click_time);
930	value.addr = (XtPointer)&pd->multi_click_time;
931	if (!_GetResource(dpy, search_list,
932			  "multiClickTime", "MultiClickTime",
933			  XtRInt, &value)) {
934	    pd->multi_click_time = 200;
935	}
936
937	value.size = sizeof(pd->appContext->selectionTimeout);
938	value.addr = (XtPointer)&pd->appContext->selectionTimeout;
939	(void)_GetResource(dpy, search_list,
940			   "selectionTimeout", "SelectionTimeout",
941			   XtRInt, &value);
942
943#ifndef NO_IDENTIFY_WINDOWS
944	value.size = sizeof(pd->appContext->identify_windows);
945	value.addr = (XtPointer)&pd->appContext->identify_windows;
946	(void)_GetResource(dpy, search_list,
947			   "xtIdentifyWindows", "XtDebug",
948			   XtRBoolean, &value);
949#endif
950
951	XAddConnectionWatch(dpy, ConnectionWatch, (XPointer) dpy);
952
953	XtFree( (XtPointer)options );
954	DEALLOCATE_LOCAL( search_list );
955}
956
957/*	Function Name: XtAppSetFallbackResources
958 *	Description: Sets the fallback resource list that will be loaded
959 *                   at display initialization time.
960 *	Arguments: app_context - the app context.
961 *                 specification_list - the resource specification list.
962 *	Returns: none.
963 */
964
965void
966XtAppSetFallbackResources(
967    XtAppContext app_context,
968    String *specification_list)
969{
970    LOCK_APP(app_context);
971    app_context->fallback_resources = specification_list;
972    UNLOCK_APP(app_context);
973}
974
975
976Widget XtOpenApplication(XtAppContext *app_context_return,
977			 _Xconst char *application_class,
978			 XrmOptionDescRec *options, Cardinal num_options,
979			 int *argc_in_out, String *argv_in_out,
980			 String *fallback_resources, WidgetClass widget_class,
981			 ArgList args_in, Cardinal num_args_in)
982{
983    XtAppContext app_con;
984    Display * dpy;
985    register int saved_argc = *argc_in_out;
986    Widget root;
987    Arg args[3], *merged_args;
988    Cardinal num = 0;
989
990    XtToolkitInitialize(); /* cannot be moved into _XtAppInit */
991
992    dpy = _XtAppInit(&app_con, (String)application_class, options, num_options,
993		     argc_in_out, &argv_in_out, fallback_resources);
994
995    LOCK_APP(app_con);
996    XtSetArg(args[num], XtNscreen, DefaultScreenOfDisplay(dpy)); num++;
997    XtSetArg(args[num], XtNargc, saved_argc);	                 num++;
998    XtSetArg(args[num], XtNargv, argv_in_out);	                 num++;
999
1000    merged_args = XtMergeArgLists(args_in, num_args_in, args, num);
1001    num += num_args_in;
1002
1003    root = XtAppCreateShell(NULL, application_class, widget_class, dpy,
1004			    merged_args, num);
1005
1006    if (app_context_return)
1007	*app_context_return = app_con;
1008
1009    XtFree((XtPointer)merged_args);
1010    XtFree((XtPointer)argv_in_out);
1011    UNLOCK_APP(app_con);
1012    return root;
1013}
1014
1015
1016Widget
1017XtAppInitialize(
1018    XtAppContext * app_context_return,
1019    _Xconst char* application_class,
1020    XrmOptionDescRec *options,
1021    Cardinal num_options,
1022    int *argc_in_out,
1023    String *argv_in_out,
1024    String *fallback_resources,
1025    ArgList args_in,
1026    Cardinal num_args_in)
1027{
1028    return XtOpenApplication(app_context_return, application_class,
1029			     options, num_options,
1030			     argc_in_out, argv_in_out, fallback_resources,
1031			     applicationShellWidgetClass,
1032			     args_in, num_args_in);
1033}
1034
1035
1036/*ARGSUSED*/
1037Widget
1038XtInitialize(
1039    _Xconst char* name,
1040    _Xconst char* classname,
1041    XrmOptionDescRec *options,
1042    Cardinal num_options,
1043    int *argc,
1044    String *argv)
1045{
1046    Widget root;
1047    XtAppContext app_con;
1048    register ProcessContext process = _XtGetProcessContext();
1049
1050    root = XtAppInitialize(&app_con, classname, options, num_options,
1051			   argc, argv, NULL, NULL, (Cardinal) 0);
1052
1053    LOCK_PROCESS;
1054    process->defaultAppContext = app_con;
1055    UNLOCK_PROCESS;
1056    return root;
1057}
1058