Initialize.c revision a3bd7f05
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
129/* *INDENT-OFF* */
130static XrmOptionDescRec const opTable[] = {
131{"+rv",               "*reverseVideo",     XrmoptionNoArg,   (XtPointer) "off"},
132{"+synchronous",      "*synchronous",      XrmoptionNoArg,   (XtPointer) "off"},
133{"-background",       "*background",       XrmoptionSepArg,  (XtPointer) NULL},
134{"-bd",               "*borderColor",      XrmoptionSepArg,  (XtPointer) NULL},
135{"-bg",               "*background",       XrmoptionSepArg,  (XtPointer) NULL},
136{"-bordercolor",      "*borderColor",      XrmoptionSepArg,  (XtPointer) NULL},
137{"-borderwidth",      ".borderWidth",      XrmoptionSepArg,  (XtPointer) NULL},
138{"-bw",               ".borderWidth",      XrmoptionSepArg,  (XtPointer) NULL},
139{"-display",          ".display",          XrmoptionSepArg,  (XtPointer) NULL},
140{"-fg",               "*foreground",       XrmoptionSepArg,  (XtPointer) NULL},
141{"-fn",               "*font",             XrmoptionSepArg,  (XtPointer) NULL},
142{"-font",             "*font",             XrmoptionSepArg,  (XtPointer) NULL},
143{"-foreground",       "*foreground",       XrmoptionSepArg,  (XtPointer) NULL},
144{"-geometry",         ".geometry",         XrmoptionSepArg,  (XtPointer) NULL},
145{"-iconic",           ".iconic",           XrmoptionNoArg,   (XtPointer) "on"},
146{"-name",             ".name",             XrmoptionSepArg,  (XtPointer) NULL},
147{"-reverse",          "*reverseVideo",     XrmoptionNoArg,   (XtPointer) "on"},
148{"-rv",               "*reverseVideo",     XrmoptionNoArg,   (XtPointer) "on"},
149{"-selectionTimeout", ".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/* *INDENT-ON* */
157
158/*
159 * GetHostname - emulates gethostname() on non-bsd systems.
160 */
161
162static void
163GetHostname(char *buf, int maxlen)
164{
165#ifdef USE_UNAME
166    int len;
167    struct utsname name;
168
169    if (maxlen <= 0 || buf == NULL)
170        return;
171
172    uname(&name);
173    len = strlen(name.nodename);
174    if (len >= maxlen)
175        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#ifdef SUNSHLIB
189void
190_XtInherit(void)
191{
192    extern void __XtInherit();
193
194    __XtInherit();
195}
196
197#define _XtInherit __XtInherit
198#endif
199
200#if defined (WIN32) || defined(__CYGWIN__)
201/*
202 * The Symbol _XtInherit is used in two different manners.
203 * First it could be used as a generic function and second
204 * as an absolute address reference, which will be used to
205 * check the initialisation process of several other libraries.
206 * Because of this the symbol must be accessable by all
207 * client dll's and applications.  In unix environments
208 * this is no problem, because the used shared libraries
209 * format (elf) supports this immediatly.  Under Windows
210 * this isn't true, because a functions address in a dll
211 * is different from the same function in another dll or
212 * applications, because the used Portable Executable
213 * File adds a code stub to each client to provide the
214 * exported symbol name.  This stub uses an indirect
215 * pointer to get the original symbol address, which is
216 * then jumped to, like in this example:
217 *
218 * --- client ---                                     --- dll ----
219 *  ...
220 *  call foo
221 *
222 * foo: jmp (*_imp_foo)               ---->           foo: ....
223 *      nop
224 *      nop
225 *
226 * _imp_foo: .long <index of foo in dll export table, is
227 *                  set to the real address by the runtime linker>
228 *
229 * Now it is clear why the clients symbol foo isn't the same
230 * as in the dll and we can think about how to deal which
231 * this two above mentioned requirements, to export this
232 * symbol to all clients and to allow calling this symbol
233 * as a function.  The solution I've used exports the
234 * symbol _XtInherit as data symbol, because global data
235 * symbols are exported to all clients.  But how to deal
236 * with the second requirement, that this symbol should
237 * be used as function.  The Trick is to build a little
238 * code stub in the data section in the exact manner as
239 * above explained.  This is done with the assembler code
240 * below.
241 *
242 * Ralf Habacker
243 *
244 * References:
245 * msdn          http://msdn.microsoft.com/msdnmag/issues/02/02/PE/PE.asp
246 * cygwin-xfree: http://www.cygwin.com/ml/cygwin-xfree/2003-10/msg00000.html
247 */
248
249#ifdef __x86_64__
250asm(".section .trampoline, \"dwx\" \n\
251 .globl _XtInherit        \n\
252 _XtInherit:              \n\
253    jmp *_y(%rip)         \n\
254_y: .quad __XtInherit     \n\
255    .text                 \n");
256#else
257asm(".data\n\
258 .globl __XtInherit        \n\
259 __XtInherit:      jmp *_y \n\
260  _y: .long ___XtInherit   \n\
261    .text                 \n");
262#endif
263
264#define _XtInherit __XtInherit
265#endif
266
267void
268_XtInherit(void)
269{
270    XtErrorMsg("invalidProcedure", "inheritanceProc", XtCXtToolkitError,
271               "Unresolved inheritance operation", NULL, NULL);
272}
273
274void
275XtToolkitInitialize(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
302String
303_XtGetUserName(_XtString dest, int len)
304{
305#ifdef WIN32
306    String ptr = NULL;
307
308    if ((ptr = getenv("USERNAME"))) {
309        (void) strncpy(dest, ptr, len - 1);
310        dest[len - 1] = '\0';
311    }
312    else
313        *dest = '\0';
314#else
315#ifdef X_NEEDS_PWPARAMS
316    _Xgetpwparams pwparams;
317#endif
318    struct passwd *pw;
319    char *ptr;
320
321    if ((ptr = getenv("USER"))) {
322        (void) strncpy(dest, ptr, (size_t) (len - 1));
323        dest[len - 1] = '\0';
324    }
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        }
330        else
331            *dest = '\0';
332    }
333#endif
334    return dest;
335}
336
337static String
338GetRootDirName(_XtString dest, int len)
339{
340#ifdef WIN32
341    register char *ptr1;
342    register char *ptr2 = NULL;
343    int len1 = 0, len2 = 0;
344
345    if (ptr1 = getenv("HOME")) {        /* old, deprecated */
346        len1 = strlen(ptr1);
347    }
348    else if ((ptr1 = getenv("HOMEDRIVE")) && (ptr2 = getenv("HOMEDIR"))) {
349        len1 = strlen(ptr1);
350        len2 = strlen(ptr2);
351    }
352    else if (ptr2 = getenv("USERNAME")) {
353        len1 = strlen(ptr1 = "/users/");
354        len2 = strlen(ptr2);
355    }
356    if ((len1 + len2 + 1) < len)
357        sprintf(dest, "%s%s", ptr1, (ptr2) ? ptr2 : "");
358    else
359        *dest = '\0';
360#else
361#ifdef X_NEEDS_PWPARAMS
362    _Xgetpwparams pwparams;
363#endif
364    static char *ptr;
365
366    if (len <= 0 || dest == NULL)
367        return NULL;
368
369    if ((ptr = getenv("HOME"))) {
370        (void) strncpy(dest, ptr, (size_t) (len - 1));
371        dest[len - 1] = '\0';
372    }
373    else {
374        struct passwd *pw;
375
376        if ((ptr = getenv("USER")))
377            pw = _XGetpwnam(ptr, pwparams);
378        else
379            pw = _XGetpwuid(getuid(), pwparams);
380        if (pw != NULL) {
381            (void) strncpy(dest, pw->pw_dir, (size_t) (len - 1));
382            dest[len - 1] = '\0';
383        }
384        else
385            *dest = '\0';
386    }
387#endif
388    return dest;
389}
390
391static void
392CombineAppUserDefaults(Display *dpy, XrmDatabase *pdb)
393{
394    char *filename;
395    char *path = NULL;
396    Boolean deallocate = False;
397
398    if (!(path = getenv("XUSERFILESEARCHPATH"))) {
399#if !defined(WIN32) || !defined(__MINGW32__)
400        char *old_path;
401        char homedir[PATH_MAX];
402
403        GetRootDirName(homedir, PATH_MAX);
404        if (!(old_path = getenv("XAPPLRESDIR"))) {
405            XtAsprintf(&path,
406                       "%s/%%L/%%N%%C:%s/%%l/%%N%%C:%s/%%N%%C:%s/%%L/%%N:%s/%%l/%%N:%s/%%N",
407                       homedir, homedir, homedir, homedir, homedir, homedir);
408        }
409        else {
410            XtAsprintf(&path,
411                       "%s/%%L/%%N%%C:%s/%%l/%%N%%C:%s/%%N%%C:%s/%%N%%C:%s/%%L/%%N:%s/%%l/%%N:%s/%%N:%s/%%N",
412                       old_path, old_path, old_path, homedir,
413                       old_path, old_path, old_path, homedir);
414        }
415        deallocate = True;
416#endif
417    }
418
419    filename = XtResolvePathname(dpy, NULL, NULL, NULL, path, NULL, 0, NULL);
420    if (filename) {
421        (void) XrmCombineFileDatabase(filename, pdb, False);
422        XtFree(filename);
423    }
424
425    if (deallocate)
426        XtFree(path);
427}
428
429static void
430CombineUserDefaults(Display *dpy, XrmDatabase *pdb)
431{
432    char *dpy_defaults = XResourceManagerString(dpy);
433
434    if (dpy_defaults) {
435        XrmCombineDatabase(XrmGetStringDatabase(dpy_defaults), pdb, False);
436    }
437    else {
438#ifdef __MINGW32__
439        const char *slashDotXdefaults = "/Xdefaults";
440#else
441        const char *slashDotXdefaults = "/.Xdefaults";
442#endif
443        char filename[PATH_MAX];
444
445        (void) GetRootDirName(filename,
446                              PATH_MAX - (int) strlen(slashDotXdefaults) - 1);
447        (void) strcat(filename, slashDotXdefaults);
448        (void) XrmCombineFileDatabase(filename, pdb, False);
449    }
450}
451
452static Bool
453StoreDBEntry(XrmDatabase *db _X_UNUSED,
454             XrmBindingList bindings,
455             XrmQuarkList quarks,
456             XrmRepresentation *type,
457             XrmValuePtr value,
458             XPointer data)
459{
460    XrmQPutResource((XrmDatabase *) data, bindings, quarks, *type, value);
461    return False;
462}
463
464static XrmDatabase
465CopyDB(XrmDatabase db)
466{
467    XrmDatabase copy = NULL;
468    XrmQuark empty = NULLQUARK;
469
470    XrmEnumerateDatabase(db, &empty, &empty, XrmEnumAllLevels,
471                         StoreDBEntry, (XPointer) &copy);
472    return copy;
473}
474
475static String
476_XtDefaultLanguageProc(Display *dpy _X_UNUSED,
477                       String xnl,
478                       XtPointer closure _X_UNUSED)
479{
480    if (!setlocale(LC_ALL, xnl))
481        XtWarning("locale not supported by C library, locale unchanged");
482
483    if (!XSupportsLocale()) {
484        XtWarning("locale not supported by Xlib, locale set to C");
485        setlocale(LC_ALL, "C");
486    }
487    if (!XSetLocaleModifiers(""))
488        XtWarning("X locale modifiers not supported, using default");
489
490    return setlocale(LC_ALL, NULL);     /* re-query in case overwritten */
491}
492
493XtLanguageProc
494XtSetLanguageProc(XtAppContext app, XtLanguageProc proc, XtPointer closure)
495{
496    XtLanguageProc old;
497
498    if (!proc) {
499        proc = _XtDefaultLanguageProc;
500        closure = NULL;
501    }
502
503    if (app) {
504        LOCK_APP(app);
505        LOCK_PROCESS;
506        /* set langProcRec only for this application context */
507        old = app->langProcRec.proc;
508        app->langProcRec.proc = proc;
509        app->langProcRec.closure = closure;
510        UNLOCK_PROCESS;
511        UNLOCK_APP(app);
512    }
513    else {
514        /* set langProcRec for all application contexts */
515        ProcessContext process;
516
517        LOCK_PROCESS;
518        process = _XtGetProcessContext();
519        old = process->globalLangProcRec.proc;
520        process->globalLangProcRec.proc = proc;
521        process->globalLangProcRec.closure = closure;
522        app = process->appContextList;
523        while (app) {
524            app->langProcRec.proc = proc;
525            app->langProcRec.closure = closure;
526            app = app->next;
527        }
528        UNLOCK_PROCESS;
529    }
530    return (old ? old : _XtDefaultLanguageProc);
531}
532
533XrmDatabase
534XtScreenDatabase(Screen *screen)
535{
536    int scrno;
537    Bool doing_def;
538    XrmDatabase db, olddb;
539    XtPerDisplay pd;
540    Status do_fallback;
541    char *scr_resources;
542    Display *dpy = DisplayOfScreen(screen);
543
544    DPY_TO_APPCON(dpy);
545    if (dpy == NULL) {
546        XtErrorMsg("nullDisplay",
547                   "XtScreenDatabase", XtCXtToolkitError,
548                   "XtScreenDatabase requires a non-NULL display",
549                   NULL, NULL);
550    }
551
552    LOCK_APP(app);
553    LOCK_PROCESS;
554    if (screen == DefaultScreenOfDisplay(dpy)) {
555        scrno = DefaultScreen(dpy);
556        doing_def = True;
557    }
558    else {
559        scrno = XScreenNumberOfScreen(screen);
560        doing_def = False;
561    }
562    pd = _XtGetPerDisplay(dpy);
563    if ((db = pd->per_screen_db[scrno])) {
564        UNLOCK_PROCESS;
565        UNLOCK_APP(app);
566        return (doing_def ? XrmGetDatabase(dpy) : db);
567    }
568    scr_resources = XScreenResourceString(screen);
569
570    if (ScreenCount(dpy) == 1) {
571        db = pd->cmd_db;
572        pd->cmd_db = NULL;
573    }
574    else {
575        db = CopyDB(pd->cmd_db);
576    }
577    {                           /* Environment defaults */
578        char filenamebuf[PATH_MAX];
579        char *filename;
580
581        if (!(filename = getenv("XENVIRONMENT"))) {
582            int len;
583
584#ifdef __MINGW32__
585            const char *slashDotXdefaultsDash = "/Xdefaults-";
586#else
587            const char *slashDotXdefaultsDash = "/.Xdefaults-";
588#endif
589
590            (void) GetRootDirName(filename = filenamebuf,
591                                  PATH_MAX -
592                                  (int) strlen(slashDotXdefaultsDash) - 1);
593            (void) strcat(filename, slashDotXdefaultsDash);
594            len = (int) strlen(filename);
595            GetHostname(filename + len, PATH_MAX - len);
596        }
597        (void) XrmCombineFileDatabase(filename, &db, False);
598    }
599    if (scr_resources) {        /* Screen defaults */
600        XrmCombineDatabase(XrmGetStringDatabase(scr_resources), &db, False);
601        XFree(scr_resources);
602    }
603    /* Server or host defaults */
604    if (!pd->server_db)
605        CombineUserDefaults(dpy, &db);
606    else {
607        (void) XrmCombineDatabase(pd->server_db, &db, False);
608        pd->server_db = NULL;
609    }
610
611    if (!db)
612        db = XrmGetStringDatabase("");
613    pd->per_screen_db[scrno] = db;
614    olddb = XrmGetDatabase(dpy);
615    /* set database now, for XtResolvePathname to use */
616    XrmSetDatabase(dpy, db);
617    CombineAppUserDefaults(dpy, &db);
618    do_fallback = 1;
619    {                           /* System app-defaults */
620        char *filename;
621
622        if ((filename = XtResolvePathname(dpy, "app-defaults",
623                                          NULL, NULL, NULL, NULL, 0, NULL))) {
624            do_fallback = !XrmCombineFileDatabase(filename, &db, False);
625            XtFree(filename);
626        }
627    }
628    /* now restore old database, if need be */
629    if (!doing_def)
630        XrmSetDatabase(dpy, olddb);
631    if (do_fallback && pd->appContext->fallback_resources) {    /* Fallback defaults */
632        XrmDatabase fdb = NULL;
633        String *res;
634
635        for (res = pd->appContext->fallback_resources; *res; res++)
636            XrmPutLineResource(&fdb, *res);
637        (void) XrmCombineDatabase(fdb, &db, False);
638    }
639    UNLOCK_PROCESS;
640    UNLOCK_APP(app);
641    return db;
642}
643
644/*
645 * Merge two option tables, allowing the second to over-ride the first,
646 * so that ambiguous abbreviations can be noticed.  The merge attempts
647 * to make the resulting table lexicographically sorted, but succeeds
648 * only if the first source table is sorted.  Though it _is_ recommended
649 * (for optimizations later in XrmParseCommand), it is not required
650 * that either source table be sorted.
651 *
652 * Caller is responsible for freeing the returned option table.
653 */
654
655static void
656_MergeOptionTables(const XrmOptionDescRec *src1,
657                   Cardinal num_src1,
658                   const XrmOptionDescRec *src2,
659                   Cardinal num_src2,
660                   XrmOptionDescRec **dst,
661                   Cardinal *num_dst)
662{
663    XrmOptionDescRec *table, *endP;
664    XrmOptionDescRec *opt1, *dstP;
665    const XrmOptionDescRec *opt2;
666    int i1;
667    Cardinal i2;
668    int dst_len, order;
669    enum { Check, NotSorted, IsSorted } sort_order = Check;
670
671    *dst = table = (XrmOptionDescRec *)
672        __XtMalloc((Cardinal)
673                   (sizeof(XrmOptionDescRec) * (num_src1 + num_src2)));
674
675    (void) memmove(table, src1, sizeof(XrmOptionDescRec) * num_src1);
676    if (num_src2 == 0) {
677        *num_dst = num_src1;
678        return;
679    }
680    endP = &table[dst_len = (int) num_src1];
681    for (opt2 = src2, i2 = 0; i2 < num_src2; opt2++, i2++) {
682        XrmOptionDescRec *whereP;
683        Boolean found;
684
685        found = False;
686        whereP = endP - 1;      /* assume new option goes at the end */
687        for (opt1 = table, i1 = 0; i1 < dst_len; opt1++, i1++) {
688            /* have to walk the entire new table so new list is ordered
689               (if src1 was ordered) */
690            if (sort_order == Check && i1 > 0
691                && strcmp(opt1->option, (opt1 - 1)->option) < 0)
692                sort_order = NotSorted;
693            if ((order = strcmp(opt1->option, opt2->option)) == 0) {
694                /* same option names; just overwrite opt1 with opt2 */
695                *opt1 = *opt2;
696                found = True;
697                break;
698            }
699            /* else */
700            if (sort_order == IsSorted && order > 0) {
701                /* insert before opt1 to preserve order */
702                /* shift rest of table forward to make room for new entry */
703                for (dstP = endP++; dstP > opt1; dstP--)
704                    *dstP = *(dstP - 1);
705                *opt1 = *opt2;
706                dst_len++;
707                found = True;
708                break;
709            }
710            /* else */
711            if (order < 0)
712                /* opt2 sorts after opt1, so remember this position */
713                whereP = opt1;
714        }
715        if (sort_order == Check && i1 == dst_len)
716            sort_order = IsSorted;
717        if (!found) {
718            /* when we get here, whereP points to the last entry in the
719               destination that sorts before "opt2".  Shift rest of table
720               forward and insert "opt2" after whereP. */
721            whereP++;
722            for (dstP = endP++; dstP > whereP; dstP--)
723                *dstP = *(dstP - 1);
724            *whereP = *opt2;
725            dst_len++;
726        }
727    }
728    *num_dst = (Cardinal) dst_len;
729}
730
731/* NOTE: name, class, and type must be permanent strings */
732static Boolean
733_GetResource(Display *dpy,
734             XrmSearchList list,
735             String name,
736             String class,
737             String type,
738             XrmValue *value)
739{
740    XrmRepresentation db_type;
741    XrmValue db_value;
742    XrmName Qname = XrmPermStringToQuark(name);
743    XrmClass Qclass = XrmPermStringToQuark(class);
744    XrmRepresentation Qtype = XrmPermStringToQuark(type);
745
746    if (XrmQGetSearchResource(list, Qname, Qclass, &db_type, &db_value)) {
747        if (db_type == Qtype) {
748            if (Qtype == _XtQString)
749                *(String *) value->addr = db_value.addr;
750            else
751                (void) memmove(value->addr, db_value.addr, value->size);
752            return True;
753        }
754        else {
755            WidgetRec widget;   /* hack, hack */
756
757            memset(&widget, 0, sizeof(widget));
758            widget.core.self = &widget;
759            widget.core.widget_class = coreWidgetClass;
760            widget.core.screen = (Screen *) DefaultScreenOfDisplay(dpy);
761            XtInitializeWidgetClass(coreWidgetClass);
762            if (_XtConvert(&widget, db_type, &db_value, Qtype, value, NULL)) {
763                return True;
764            }
765        }
766    }
767    return False;
768}
769
770XrmDatabase
771_XtPreparseCommandLine(XrmOptionDescRec *urlist,
772                       Cardinal num_urs,
773                       int argc,
774                       _XtString *argv, /* return */
775                       String *applName,
776                       String *displayName,
777                       String *language)
778{
779    XrmDatabase db = NULL;
780    XrmOptionDescRec *options;
781    Cardinal num_options;
782    XrmName name_list[3];
783    XrmName class_list[3];
784    XrmRepresentation type;
785    XrmValue val;
786    _XtString *targv;
787    int targc = argc;
788
789    targv = (_XtString *)
790        __XtMalloc((Cardinal) (sizeof(_XtString *) * (size_t) argc));
791    (void) memmove(targv, argv, sizeof(char *) * (size_t) argc);
792    _MergeOptionTables(opTable, XtNumber(opTable), urlist, num_urs,
793                       &options, &num_options);
794    name_list[0] = class_list[0] = XrmPermStringToQuark(".");
795    name_list[2] = class_list[2] = NULLQUARK;
796    XrmParseCommand(&db, options, (int) num_options, ".", &targc, targv);
797    if (applName) {
798        name_list[1] = XrmPermStringToQuark("name");
799        if (XrmQGetResource(db, name_list, name_list, &type, &val) &&
800            type == _XtQString)
801            *applName = val.addr;
802    }
803    if (displayName) {
804        name_list[1] = XrmPermStringToQuark("display");
805        if (XrmQGetResource(db, name_list, name_list, &type, &val) &&
806            type == _XtQString)
807            *displayName = val.addr;
808    }
809    if (language) {
810        name_list[1] = XrmPermStringToQuark("xnlLanguage");
811        class_list[1] = XrmPermStringToQuark("XnlLanguage");
812        if (XrmQGetResource(db, name_list, class_list, &type, &val) &&
813            type == _XtQString)
814            *language = val.addr;
815    }
816
817    XtFree((char *) targv);
818    XtFree((char *) options);
819    return db;
820}
821
822static void
823GetLanguage(Display *dpy, XtPerDisplay pd)
824{
825    XrmRepresentation type;
826    XrmValue value;
827    XrmName name_list[3];
828    XrmName class_list[3];
829
830    LOCK_PROCESS;
831    if (!pd->language) {
832        name_list[0] = pd->name;
833        name_list[1] = XrmPermStringToQuark("xnlLanguage");
834        class_list[0] = pd->class;
835        class_list[1] = XrmPermStringToQuark("XnlLanguage");
836        name_list[2] = class_list[2] = NULLQUARK;
837        if (!pd->server_db)
838            CombineUserDefaults(dpy, &pd->server_db);
839        if (pd->server_db &&
840            XrmQGetResource(pd->server_db, name_list, class_list, &type, &value)
841            && type == _XtQString)
842            pd->language = (char *) value.addr;
843    }
844
845    if (pd->appContext->langProcRec.proc) {
846        if (!pd->language)
847            pd->language = "";
848        pd->language = (*pd->appContext->langProcRec.proc)
849            (dpy, pd->language, pd->appContext->langProcRec.closure);
850    }
851    else if (!pd->language || pd->language[0] == '\0')  /* R4 compatibility */
852        pd->language = getenv("LANG");
853
854    if (pd->language)
855        pd->language = XtNewString(pd->language);
856    UNLOCK_PROCESS;
857}
858
859static void
860ProcessInternalConnection(XtPointer client_data,
861                          int *fd,
862                          XtInputId *id _X_UNUSED)
863{
864    XProcessInternalConnection((Display *) client_data, *fd);
865}
866
867static void
868ConnectionWatch(Display *dpy,
869                XPointer client_data,
870                int fd,
871                Bool opening,
872                XPointer *watch_data)
873{
874    XtInputId *iptr;
875    XtAppContext app = XtDisplayToApplicationContext(dpy);
876
877    if (opening) {
878        iptr = (XtInputId *) __XtMalloc(sizeof(XtInputId));
879        *iptr = XtAppAddInput(app, fd, (XtPointer) XtInputReadMask,
880                              ProcessInternalConnection, client_data);
881        *watch_data = (XPointer) iptr;
882    }
883    else {
884        iptr = (XtInputId *) *watch_data;
885        XtRemoveInput(*iptr);
886        (void) XtFree(*watch_data);
887    }
888}
889
890void
891_XtDisplayInitialize(Display *dpy,
892                     XtPerDisplay pd,
893                     _Xconst char *name,
894                     XrmOptionDescRec *urlist,
895                     Cardinal num_urs,
896                     int *argc,
897                     char **argv)
898{
899    Boolean tmp_bool;
900    XrmValue value;
901    XrmOptionDescRec *options;
902    Cardinal num_options;
903    XrmDatabase db;
904    XrmName name_list[2];
905    XrmClass class_list[2];
906    XrmHashTable *search_list;
907    int search_list_size = SEARCH_LIST_SIZE;
908
909    GetLanguage(dpy, pd);
910
911    /* Parse the command line and remove Xt arguments from argv */
912    _MergeOptionTables(opTable, XtNumber(opTable), urlist, num_urs,
913                       &options, &num_options);
914    XrmParseCommand(&pd->cmd_db, options, (int) num_options, name, argc, argv);
915
916    db = XtScreenDatabase(DefaultScreenOfDisplay(dpy));
917
918    if (!(search_list = (XrmHashTable *)
919          ALLOCATE_LOCAL(SEARCH_LIST_SIZE * sizeof(XrmHashTable))))
920        _XtAllocError(NULL);
921    name_list[0] = pd->name;
922    class_list[0] = pd->class;
923    name_list[1] = NULLQUARK;
924    class_list[1] = NULLQUARK;
925
926    while (!XrmQGetSearchList(db, name_list, class_list,
927                              search_list, search_list_size)) {
928        XrmHashTable *old = search_list;
929        Cardinal size =
930            (Cardinal) ((size_t) (search_list_size *= 2) *
931                        sizeof(XrmHashTable));
932        if (!(search_list = (XrmHashTable *) ALLOCATE_LOCAL(size)))
933            _XtAllocError(NULL);
934        (void) memmove((char *) search_list, (char *) old, (size >> 1));
935        DEALLOCATE_LOCAL(old);
936    }
937
938    value.size = sizeof(tmp_bool);
939    value.addr = (XtPointer) &tmp_bool;
940    if (_GetResource(dpy, search_list, "synchronous", "Synchronous",
941                     XtRBoolean, &value)) {
942        int i;
943        Display **dpyP = pd->appContext->list;
944
945        pd->appContext->sync = tmp_bool;
946        for (i = pd->appContext->count; i; dpyP++, i--) {
947            (void) XSynchronize(*dpyP, (Bool) tmp_bool);
948        }
949    }
950    else {
951        (void) XSynchronize(dpy, (Bool) pd->appContext->sync);
952    }
953
954    if (_GetResource(dpy, search_list, "reverseVideo", "ReverseVideo",
955                     XtRBoolean, &value)
956        && tmp_bool) {
957        pd->rv = True;
958    }
959
960    value.size = sizeof(pd->multi_click_time);
961    value.addr = (XtPointer) &pd->multi_click_time;
962    if (!_GetResource(dpy, search_list,
963                      "multiClickTime", "MultiClickTime", XtRInt, &value)) {
964        pd->multi_click_time = 200;
965    }
966
967    value.size = sizeof(pd->appContext->selectionTimeout);
968    value.addr = (XtPointer) &pd->appContext->selectionTimeout;
969    (void) _GetResource(dpy, search_list,
970                        "selectionTimeout", "SelectionTimeout", XtRInt, &value);
971
972#ifndef NO_IDENTIFY_WINDOWS
973    value.size = sizeof(pd->appContext->identify_windows);
974    value.addr = (XtPointer) &pd->appContext->identify_windows;
975    (void) _GetResource(dpy, search_list,
976                        "xtIdentifyWindows", "XtDebug", XtRBoolean, &value);
977#endif
978
979    XAddConnectionWatch(dpy, ConnectionWatch, (XPointer) dpy);
980
981    XtFree((XtPointer) options);
982    DEALLOCATE_LOCAL(search_list);
983}
984
985/*      Function Name: XtAppSetFallbackResources
986 *      Description: Sets the fallback resource list that will be loaded
987 *                   at display initialization time.
988 *      Arguments: app_context - the app context.
989 *                 specification_list - the resource specification list.
990 *      Returns: none.
991 */
992
993void
994XtAppSetFallbackResources(XtAppContext app_context, String *specification_list)
995{
996    LOCK_APP(app_context);
997    app_context->fallback_resources = specification_list;
998    UNLOCK_APP(app_context);
999}
1000
1001Widget
1002XtOpenApplication(XtAppContext *app_context_return,
1003                  _Xconst char *application_class,
1004                  XrmOptionDescRec *options,
1005                  Cardinal num_options,
1006                  int *argc_in_out,
1007                  _XtString *argv_in_out,
1008                  String *fallback_resources,
1009                  WidgetClass widget_class,
1010                  ArgList args_in,
1011                  Cardinal num_args_in)
1012{
1013    XtAppContext app_con;
1014    Display *dpy;
1015    register int saved_argc = *argc_in_out;
1016    Widget root;
1017    Arg args[3], *merged_args;
1018    Cardinal num = 0;
1019
1020    XtToolkitInitialize();      /* cannot be moved into _XtAppInit */
1021
1022    dpy = _XtAppInit(&app_con, (String) application_class, options, num_options,
1023                     argc_in_out, &argv_in_out, fallback_resources);
1024
1025    LOCK_APP(app_con);
1026    XtSetArg(args[num], XtNscreen, DefaultScreenOfDisplay(dpy));
1027    num++;
1028    XtSetArg(args[num], XtNargc, saved_argc);
1029    num++;
1030    XtSetArg(args[num], XtNargv, argv_in_out);
1031    num++;
1032
1033    merged_args = XtMergeArgLists(args_in, num_args_in, args, num);
1034    num += num_args_in;
1035
1036    root = XtAppCreateShell(NULL, application_class, widget_class, dpy,
1037                            merged_args, num);
1038
1039    if (app_context_return)
1040        *app_context_return = app_con;
1041
1042    XtFree((XtPointer) merged_args);
1043    XtFree((XtPointer) argv_in_out);
1044    UNLOCK_APP(app_con);
1045    return root;
1046}
1047
1048Widget
1049XtAppInitialize(XtAppContext *app_context_return,
1050                _Xconst char *application_class,
1051                XrmOptionDescRec *options,
1052                Cardinal num_options,
1053                int *argc_in_out,
1054                _XtString *argv_in_out,
1055                String *fallback_resources,
1056                ArgList args_in,
1057                Cardinal num_args_in)
1058{
1059    return XtOpenApplication(app_context_return, application_class,
1060                             options, num_options,
1061                             argc_in_out, argv_in_out, fallback_resources,
1062                             applicationShellWidgetClass, args_in, num_args_in);
1063}
1064
1065Widget
1066XtInitialize(_Xconst _XtString name _X_UNUSED,
1067             _Xconst _XtString classname,
1068             XrmOptionDescRec *options,
1069             Cardinal num_options,
1070             int *argc,
1071             _XtString *argv)
1072{
1073    Widget root;
1074    XtAppContext app_con;
1075    register ProcessContext process = _XtGetProcessContext();
1076
1077    root = XtAppInitialize(&app_con, classname, options, num_options,
1078                           argc, argv, NULL, NULL, (Cardinal) 0);
1079
1080    LOCK_PROCESS;
1081    process->defaultAppContext = app_con;
1082    UNLOCK_PROCESS;
1083    return root;
1084}
1085