2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* (c) Copyright 1997 The Open Group */
25 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
26 * (c) Copyright 1993, 1994 International Business Machines Corp. *
27 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
28 * (c) Copyright 1993, 1994 Novell, Inc. *
31 * xdm - display manager daemon
33 * $TOG: util.c /main/15 1998/04/06 13:22:20 mgreess $
35 * Copyright 1988 Massachusetts Institute of Technology
37 * Permission to use, copy, modify, and distribute this software and its
38 * documentation for any purpose and without fee is hereby granted, provided
39 * that the above copyright notice appear in all copies and that both that
40 * copyright notice and this permission notice appear in supporting
41 * documentation, and that the name of M.I.T. not be used in advertising or
42 * publicity pertaining to distribution of the software without specific,
43 * written prior permission. M.I.T. makes no representations about the
44 * suitability of this software for any purpose. It is provided "as is"
45 * without express or implied warranty.
47 * Author: Keith Packard, MIT X Consortium
53 * various utility routines
63 # include <sys/signal.h>
72 nl_catd nl_fd = (nl_catd)-1; /* message catalog file descriptor */
74 #if !defined(NL_CAT_LOCALE)
75 #define NL_CAT_LOCALE 0
78 #if !defined (ENABLE_DYNAMIC_LANGLIST)
79 #define LANGLISTSIZE 2048
80 char languageList[LANGLISTSIZE]; /* global list of languages */
81 #endif /* ENABLE_DYNAMIC_LANGLIST */
83 /***************************************************************************
85 * Local procedure declarations
87 ***************************************************************************/
89 static char * makeEnv(
93 static SIGVAL MakeLangAbort(
96 static int MatchesFileSuffix(const char *filename, const char *suffix);
98 static void ScanNLSDir(
101 /******** End Local Function Declarations ********/
104 /***************************************************************************
108 * read a string from the message catalog
109 ***************************************************************************/
112 ReadCatalog( int set_num, int msg_num, char *def_str )
114 static Bool alreadyopen = False;
117 if (alreadyopen == False)
119 char *curNlsPath, *newNlsPath;
125 * Desktop message catalogs are in DT directory, so append desktop
126 * search paths to current NLSPATH.
128 #define NLS_PATH_STRING CDE_INSTALLATION_TOP "/nls/msg/%L/%N.cat:" \
129 CDE_INSTALLATION_TOP "/lib/nls/msg/%L/%N.cat:" \
130 CDE_INSTALLATION_TOP "/lib/nls/msg/%l/%t/%c/%N.cat:" \
131 CDE_INSTALLATION_TOP "/lib/nls/msg/%l/%c/%N.cat"
133 curNlsPath = getenv("NLSPATH");
134 if (curNlsPath && strlen(curNlsPath) == 0)
142 * <length of NLS_PATH_STRING>
145 newNlsPathLen = 7 + 1 + strlen(NLS_PATH_STRING) + 1;
147 if (curNlsPath != NULL)
151 * <length of curNlsPath>
153 newNlsPathLen += (1 + strlen(curNlsPath));
156 newNlsPath = malloc(newNlsPathLen); /* placed in environ, do not free */
158 if (curNlsPath != NULL)
160 sprintf(newNlsPath, "NLSPATH=%s:%s", curNlsPath, NLS_PATH_STRING);
164 sprintf(newNlsPath, "NLSPATH=%s", NLS_PATH_STRING);
168 * Store new NLSPATH in environment. Note this memory cannot be freed
173 * Open message catalog. Note, if invalid descriptor returned (ie
174 * msg catalog could not be opened), subsequent call to catgets() using
175 * that descriptor will return 'def_str'.
177 nl_fd = catopen("dtlogin", NL_CAT_LOCALE);
180 s = catgets(nl_fd,set_num,msg_num,def_str);
182 return((unsigned char *)s);
189 Debug (" %s\n", *e++);
193 makeEnv( char *name, char *value )
197 result = malloc ((unsigned) (strlen (name) + strlen (value) + 2));
200 ReadCatalog(MC_LOG_SET,MC_LOG_MAKEENV,MC_DEF_LOG_MAKEENV));
205 sprintf (result, "%s=%s", name, value);
208 sprintf (result, "%s", name);
215 getEnv( char **e, char *name )
217 int l = strlen (name);
220 if ((int) strlen (*e) > l &&
221 !strncmp (*e, name, l) &&
231 setEnv( char **e, char *name, char *value )
239 newe = makeEnv (name, value);
241 LogOutOfMem(ReadCatalog(MC_LOG_SET,MC_LOG_SETENV,MC_DEF_LOG_SETENV));
245 for (old = e; *old; old++)
246 if ((int) strlen (*old) > l &&
247 !strncmp (*old, name, l) &&
258 realloc((char *) e, (unsigned) ((envsize + 2) * sizeof (char *)));
261 new = (char **) malloc (2 * sizeof (char *));
264 LogOutOfMem(ReadCatalog(MC_LOG_SET,MC_LOG_SETENV,MC_DEF_LOG_SETENV));
280 for (e = env; *e; e++)
286 # define isblank(c) ((c) == ' ' || c == '\t')
289 parseArgs( char **argv, char *string )
296 while (argv && argv[i])
299 argv = (char **) malloc (sizeof (char *));
301 LogOutOfMem(ReadCatalog(
302 MC_LOG_SET,MC_LOG_PARSEARGS,MC_DEF_LOG_PARSEARGS));
308 if (!*string || isblank (*string)) {
309 if (word != string) {
310 argv = (char **) realloc ((char *) argv,
311 (unsigned) ((i + 2) * sizeof (char *)));
312 save = malloc ((unsigned) (string - word + 1));
313 if (!argv || !save) {
314 LogOutOfMem(ReadCatalog(MC_LOG_SET,
316 MC_DEF_LOG_PARSEARGS));
318 free ((char *) argv);
323 argv[i] = strncpy (save, word, string-word);
324 argv[i][string-word] = '\0';
341 * On i386/i486 platforms setprrp() functions causes the mouse not
342 * to work. Since in the daemon mode the parent daemon has already
343 * executed a setpgrp it is a process and session leader. Since it
344 * has also gotten rid of the controlling terminal there is no great
345 * harm in not making the sub-daemons as leaders.
347 #if defined (SYSV) || defined (SVR4) || defined(__linux__)
350 setpgrp (0, getpid ());
354 (void) signal (SIGCHLD, SIG_DFL);
356 (void) signal (SIGTERM, SIG_DFL);
357 (void) signal (SIGPIPE, SIG_DFL);
358 (void) signal (SIGALRM, SIG_DFL);
359 (void) signal (SIGHUP, SIG_DFL);
364 parseEnv( char **e, char *string )
367 char *s1, *s2, *t1, *t2;
369 s1 = s2 = strdup(string);
371 while ((t1 = strtok(s1," \t")) != NULL ) {
372 if ( (t2 = strchr(t1,'=')) != NULL ) {
374 e = setEnv(e, t1, t2);
387 /*************************************<->*************************************
389 * Cursor GetHourGlass ()
394 * Builds and returns the appropriate Hourglass cursor
407 * None. (None doesn't count as a comment)
409 *************************************<->***********************************/
411 #define time32_width 32
412 #define time32_height 32
413 #define time32_x_hot 15
414 #define time32_y_hot 15
415 static unsigned char time32_bits[] = {
416 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
417 0x8c, 0x00, 0x00, 0x31, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
418 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
419 0x8c, 0x00, 0x00, 0x31, 0x0c, 0x7f, 0xfe, 0x30, 0x0c, 0xfe, 0x7f, 0x30,
420 0x0c, 0xfc, 0x3f, 0x30, 0x0c, 0xf8, 0x1f, 0x30, 0x0c, 0xe0, 0x07, 0x30,
421 0x0c, 0x80, 0x01, 0x30, 0x0c, 0x80, 0x01, 0x30, 0x0c, 0x60, 0x06, 0x30,
422 0x0c, 0x18, 0x18, 0x30, 0x0c, 0x04, 0x20, 0x30, 0x0c, 0x02, 0x40, 0x30,
423 0x0c, 0x01, 0x80, 0x30, 0x8c, 0x00, 0x00, 0x31, 0x4c, 0x80, 0x01, 0x32,
424 0x4c, 0xc0, 0x03, 0x32, 0x4c, 0xf0, 0x1f, 0x32, 0x4c, 0xff, 0xff, 0x32,
425 0xcc, 0xff, 0xff, 0x33, 0x8c, 0xff, 0xff, 0x31, 0xfe, 0xff, 0xff, 0x7f,
426 0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00};
428 #define time32m_width 32
429 #define time32m_height 32
430 static unsigned char time32m_bits[] = {
431 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
432 0xcf, 0x00, 0x00, 0xf3, 0x6e, 0x00, 0x00, 0x76, 0x6e, 0x00, 0x00, 0x76,
433 0x6e, 0x00, 0x00, 0x76, 0x6e, 0x00, 0x00, 0x76, 0x6e, 0x00, 0x00, 0x76,
434 0xce, 0x00, 0x00, 0x73, 0x8e, 0x7f, 0xfe, 0x71, 0x0e, 0xff, 0xff, 0x70,
435 0x0e, 0xfe, 0x7f, 0x70, 0x0e, 0xfc, 0x3f, 0x70, 0x0e, 0xf8, 0x1f, 0x70,
436 0x0e, 0xe0, 0x07, 0x70, 0x0e, 0xe0, 0x07, 0x70, 0x0e, 0x78, 0x1e, 0x70,
437 0x0e, 0x1c, 0x38, 0x70, 0x0e, 0x06, 0x60, 0x70, 0x0e, 0x03, 0xc0, 0x70,
438 0x8e, 0x01, 0x80, 0x71, 0xce, 0x00, 0x00, 0x73, 0x6e, 0x80, 0x01, 0x76,
439 0x6e, 0xc0, 0x03, 0x76, 0x6e, 0xf0, 0x1f, 0x76, 0x6e, 0xff, 0xff, 0x76,
440 0xee, 0xff, 0xff, 0x77, 0xcf, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff,
441 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
444 #define time16_x_hot 7
445 #define time16_y_hot 7
446 #define time16_width 16
447 #define time16_height 16
448 static unsigned char time16_bits[] = {
449 0x00, 0x00, 0xfe, 0x7f, 0x14, 0x28, 0x14, 0x28, 0x14, 0x28, 0x24, 0x24,
450 0x44, 0x22, 0x84, 0x21, 0x84, 0x21, 0x44, 0x22, 0x24, 0x24, 0x14, 0x28,
451 0x94, 0x29, 0xd4, 0x2b, 0xfe, 0x7f, 0x00, 0x00};
453 #define time16m_width 16
454 #define time16m_height 16
455 static unsigned char time16m_bits[] = {
456 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
457 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
458 0xfe, 0x7f, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff};
461 Cursor GetHourGlass (Display *dpy)
467 unsigned int xHotspot;
468 unsigned int yHotspot;
473 unsigned int cHeight;
474 int useLargeCursors = 0;
477 if (XQueryBestCursor (dpy, DefaultRootWindow(dpy),
478 32, 32, &cWidth, &cHeight))
480 if ((cWidth >= 32) && (cHeight >= 32))
488 width = time32_width;
489 height = time32_height;
490 bits = (char *)time32_bits;
491 maskBits = (char *)time32m_bits;
492 xHotspot = time32_x_hot;
493 yHotspot = time32_y_hot;
497 width = time16_width;
498 height = time16_height;
499 bits = (char *)time16_bits;
500 maskBits = (char *)time16m_bits;
501 xHotspot = time16_x_hot;
502 yHotspot = time16_y_hot;
505 pixmap = XCreateBitmapFromData (dpy,
506 DefaultRootWindow(dpy), bits,
509 maskPixmap = XCreateBitmapFromData (dpy,
510 DefaultRootWindow(dpy), maskBits,
513 xcolors[0].pixel = BlackPixelOfScreen(DefaultScreenOfDisplay(dpy));
514 xcolors[1].pixel = WhitePixelOfScreen(DefaultScreenOfDisplay(dpy));
517 DefaultColormapOfScreen(DefaultScreenOfDisplay
520 waitCursor = XCreatePixmapCursor (dpy, pixmap, maskPixmap,
521 &(xcolors[0]), &(xcolors[1]),
523 XFreePixmap (dpy, pixmap);
524 XFreePixmap (dpy, maskPixmap);
532 /*************************************<->*************************************
534 * void SetHourGlassCursor
539 * sets the window cursor to an hourglass
553 * None. (None doesn't count as a comment)
555 *************************************<->***********************************/
558 SetHourGlassCursor( Display *dpy, Window w )
562 XUndefineCursor(dpy, w);
564 cursor = GetHourGlass(dpy);
566 XDefineCursor(dpy, w, cursor);
567 XFreeCursor(dpy, cursor);
571 #if !defined (ENABLE_DYNAMIC_LANGLIST)
572 /***************************************************************************
576 * Generate the list of languages installed on the host.
577 * Result is stored the global array "languageList"
579 ***************************************************************************/
581 #define DELIM " \t" /* delimiters in language list */
583 static jmp_buf langJump;
586 MakeLangAbort( int arg )
589 longjmp (langJump, 1);
597 char *lang[500]; /* sort list for languages */
598 int nlang; /* total number of languages */
603 * build language list from set of languages installed on the host...
604 * Wrap a timer around it so it doesn't hang things up too long.
605 * langListTimeout resource by default is 30 seconds to scan NLS dir.
611 signal (SIGALRM, MakeLangAbort);
612 alarm ((unsigned) langListTimeout);
614 if (!setjmp (langJump)) {
615 ScanNLSDir(DEF_NLS_DIR);
618 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_SCAN,MC_DEF_LOG_NO_SCAN),
619 DEF_NLS_DIR, langListTimeout);
623 signal (SIGALRM, SIG_DFL);
627 * sort the list to eliminate duplicates and replace in global array...
630 p = savelist = strdup(languageList);
633 while ( (s = strtok(p, DELIM)) != NULL ) {
642 for (i = nlang; i > 0 && strcmp(s,lang[i-1]) < 0; i--);
644 if (i==0 || strcmp(s,lang[i-1]) != 0 ) {
645 for (j = nlang; j > i; j--)
659 for ( i = 0; i < nlang; i++) {
670 MatchesFileSuffix(const char *filename, const char *suffix)
673 #if defined(_AIX) || defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
677 * The assumption here is that the use of strrstr is
678 * to determine if "dp->d_name" ends in ".cat".
680 if (strlen(filename) >= strlen(suffix)) {
681 different = strcmp(filename + (strlen(filename) - strlen (suffix)), suffix);
684 return (different == 0);
686 return (strrstr(filename, suffix) != NULL);
690 /***************************************************************************
694 * Scan a directory structure to see if it contains an installed language.
695 * If so, the name of the language is appended to a global list of languages.
697 * Scan method and scan directory will vary by platform.
699 ***************************************************************************/
703 ScanNLSDir(char *dirname)
707 * Search installed locale names for AIX 3.2.5
713 /* Search valid locales which are locale database files in
715 * File name is "??_??" which can be used as LANG variable.
717 if((dirp = opendir(dirname)) != NULL)
719 while((dp = readdir(dirp)) != NULL)
721 if(strlen(dp->d_name) == 5 && dp->d_name[2] == '_')
723 if((int) strlen(languageList) + 7 < LANGLISTSIZE )
725 strcat(languageList, " ");
726 strcat(languageList, dp->d_name);
736 #define LOCALE "locale.inf"
737 #define LOCALEOLD "locale.def"
738 #define COLLATE8 "collate8"
739 #define MAILX "mailx"
741 #define MSGCAT ".cat"
746 * Scan for installed locales on HP platform.
749 /***************************************************************************
750 * Scan supplied NLS directory structure to see if it contains an
751 * installed language. If so, the name of the language is appended
752 * to a global list of languages.
754 * This routine is recursively called as a directory structure is
757 *************************************************************************/
766 * Scan input directory, looking for a LOCALE file. If a sub-directory
767 * is found, recurse down into it...
769 if ( (dirp = opendir(dirname)) != NULL )
771 while ( (dp = readdir(dirp)) != NULL )
774 * ignore files that are known not to be candidates...
776 if ( MatchesFileSuffix(dp->d_name, MSGCAT) ||
777 (strcmp (dp->d_name, COLLATE8) == 0 ) ||
778 (strcmp (dp->d_name, MAILX) == 0 ) ||
779 (strcmp (dp->d_name, ELM) == 0 ) ||
780 (strcmp (dp->d_name, DOT) == 0 ) ||
781 (strcmp (dp->d_name, DOTDOT) == 0 ) )
786 * check to see if this is the locale file...
788 if ( (strcmp(dp->d_name, LOCALEOLD) == 0 ) ||
789 (strcmp(dp->d_name, LOCALE) == 0 ) )
794 * Convert directory name to language name...
796 if ( (p = strstr(dirname, DEF_NLS_DIR)) != NULL )
798 p += strlen(DEF_NLS_DIR);
803 while ( (p = strchr(s,'/')) != NULL )
807 * append to global list of languages...
809 if ((int) (strlen(languageList)+strlen(s)+2) < LANGLISTSIZE)
811 strcat(languageList, " ");
812 strcat(languageList, s);
820 * if this file is a directory, scan it also...
822 strcpy(buf, dirname);
824 strcat(buf, dp->d_name);
826 if (stat(buf, &statb) == 0 && S_ISDIR(statb.st_mode))
834 #else /* !_AIX && !hpV4 */
836 * Scan for installed locales on generic platform
842 char locale_path[MAXPATHLEN];
843 struct stat locale_stat;
847 * To determin the fully installed locale list, check several locations.
849 if(NULL != (dirp = opendir(dirname)))
851 while((dp = readdir(dirp)) != NULL)
855 if ( (strcmp(dp->d_name, ".") == 0) ||
856 (strcmp(dp->d_name, "..") == 0) )
859 if (locale[0] != '.' &&
860 LANGLISTSIZE > (int) (strlen(languageList)+strlen(locale)+2));
862 (void) sprintf(locale_path, "%s/%s", dirname, locale);
863 retval = stat(locale_path, &locale_stat);
865 if (0 == retval && S_ISDIR(locale_stat.st_mode))
867 strcat(languageList, " ");
868 strcat(languageList, locale);
878 #endif /* ENABLE_DYNAMIC_LANGLIST */
881 #define ENVFILE "/etc/environment"
883 /* Refer to the LANG environment variable, first.
884 * Or, search a line which includes "LANG=XX_XX" in /etc/environment.
885 * If succeeded, set the value to d->language.
888 SetDefaultLanguage(struct display *d)
896 if((lang = getenv( "LANG" )) == NULL ) {
897 if((file = fopen(ENVFILE, "r")) != NULL) {
898 while(fgets(lineBuf, sizeof(lineBuf) - 1, file)) {
900 if(n > 1 && lineBuf[0] != '#') {
901 if(lineBuf[n - 1] == '\n')
902 lineBuf[n - 1] = '\0';
903 if((p = strstr(lineBuf, "LANG=")) != NULL) {
905 if(strlen(p) == 5 && p[2] == '_') {
915 if(lang != NULL && strlen(lang) > 0) {
917 * If LANG is set for hft, we need to change it for X.
918 * Currently there are four hft LANG variables.
920 d->language = (char *)malloc(strlen(lang)+1);
921 if(strcmp(lang, "En_JP") == 0)
922 strcpy(d->language, "Ja_JP");
923 else if(strcmp(lang, "en_JP") == 0)
924 strcpy(d->language, "ja_JP");
925 else if(strcmp(lang, "en_KR") == 0)
926 strcpy(d->language, "ko_KR");
927 else if(strcmp(lang, "en_TW") == 0)
928 strcpy(d->language, "zh_TW");
930 strcpy(d->language, lang);
937 setLang( struct display *d, char **env , char *langptr)
939 char langlist[LANGLISTSIZE];
941 char *element = NULL;
942 int set_def_lang = FALSE;
946 Debug("setLang(): langlist = %s\n", langptr);
948 Debug("setLang(): langlist = NULL\n");
951 snprintf(langlist, sizeof(langlist), "%s", langptr);
953 snprintf(langlist, sizeof(langlist), "%s", getEnv(env, "LANGLIST"));
955 if (strlen(langlist) > 0) {
956 element = strtok(langlist, DELIM);
958 set_def_lang = FALSE;
959 if (strcmp(element,d->language) == 0){
960 env = setEnv(env, "LANG", d->language);
966 s += strlen(element) +1;
967 element = strtok(langlist+s, DELIM);
973 env = setEnv(env, "LANG", "C");
974 d->language = strdup("C");
979 static char localHostbuf[256];
980 static int gotLocalHostname;
985 if (!gotLocalHostname)
987 XmuGetHostname (localHostbuf, sizeof (localHostbuf) - 1);
988 gotLocalHostname = 1;