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