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