bfab56347ce37a7a46a6b9463720d849e714399c
[oweals/cde.git] / cde / programs / dtlogin / util.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /* (c) Copyright 1997 The Open Group */
24 /*                                                                      *
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.                                *
29  */
30 /*
31  * xdm - display manager daemon
32  *
33  * $TOG: util.c /main/15 1998/04/06 13:22:20 mgreess $
34  *
35  * Copyright 1988 Massachusetts Institute of Technology
36  *
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.
46  *
47  * Author:  Keith Packard, MIT X Consortium
48  */
49
50 /*
51  * util.c
52  *
53  * various utility routines
54  */
55
56
57 #include    <sys/stat.h>
58 #include    <setjmp.h>
59 #include    <string.h>
60 #include    <dirent.h>
61 #include    <nl_types.h>
62
63 # include   <sys/signal.h>
64
65 # ifndef NULL
66 #  define NULL 0
67 # endif
68
69
70 # include       "dm.h"
71 # include       "vgmsg.h"
72 nl_catd         nl_fd = (nl_catd)-1;    /* message catalog file descriptor */
73
74 #if !defined(NL_CAT_LOCALE)
75 #define NL_CAT_LOCALE 0
76 #endif
77
78 #if !defined (ENABLE_DYNAMIC_LANGLIST)
79 #define LANGLISTSIZE    2048
80 char    languageList[LANGLISTSIZE];     /* global list of languages     */
81 #endif /* ENABLE_DYNAMIC_LANGLIST */
82
83 /***************************************************************************
84  *
85  *  Local procedure declarations
86  *
87  ***************************************************************************/
88
89 static char * makeEnv( 
90                         char *name,
91                         char *value) ;
92
93 static SIGVAL MakeLangAbort(
94                         int arg );
95                         
96 static int MatchesFileSuffix(const char *filename, const char *suffix);
97
98 static void   ScanNLSDir(
99                         char * dirname );
100
101 /********    End Local Function Declarations    ********/
102
103
104 /***************************************************************************
105  *
106  *  ReadCatalog
107  *
108  *  read a string from the message catalog
109  ***************************************************************************/
110
111 unsigned char *
112 ReadCatalog( int set_num, int msg_num, char *def_str )
113 {
114     static Bool alreadyopen = False;
115     char *s;
116
117     if (alreadyopen == False)
118     {
119       char *curNlsPath, *newNlsPath;
120       int newNlsPathLen;
121
122       alreadyopen = True;
123
124      /*
125       * Desktop message catalogs are in DT directory, so append desktop
126       * search paths to current NLSPATH.
127       */
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"
132
133       curNlsPath = getenv("NLSPATH");
134       if (curNlsPath && strlen(curNlsPath) == 0)
135       {
136         curNlsPath = NULL;
137       }
138  
139      /*
140       * 7 is "NLSPATH"
141       * 1 is "="
142       * <length of NLS_PATH_STRING>
143       * 1 for null byte
144       */
145       newNlsPathLen = 7 + 1 + strlen(NLS_PATH_STRING) + 1;
146
147       if (curNlsPath != NULL)
148       {
149        /*
150         * 1 is ":"
151         * <length of curNlsPath>
152         */
153         newNlsPathLen += (1 + strlen(curNlsPath));
154       }
155
156       newNlsPath = malloc(newNlsPathLen);  /* placed in environ, do not free */
157       
158       if (curNlsPath != NULL)
159       {
160         sprintf(newNlsPath, "NLSPATH=%s:%s", curNlsPath, NLS_PATH_STRING);
161       }
162       else
163       {
164         sprintf(newNlsPath, "NLSPATH=%s", NLS_PATH_STRING);
165       }
166      
167      /*
168       * Store new NLSPATH in environment. Note this memory cannot be freed 
169       */
170       putenv(newNlsPath);
171   
172      /*
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'.
176       */
177       nl_fd = catopen("dtlogin", NL_CAT_LOCALE);
178     }
179
180     s = catgets(nl_fd,set_num,msg_num,def_str);
181     
182     return((unsigned char *)s);
183 }
184
185 void
186 printEnv( char **e )
187 {
188         while (*e)
189                 Debug ("    %s\n", *e++);
190 }
191
192 static char * 
193 makeEnv( char *name, char *value )
194 {
195         char    *result;
196
197         result = malloc ((unsigned) (strlen (name) + strlen (value) + 2));
198         if (!result) {
199                 LogOutOfMem(
200                   ReadCatalog(MC_LOG_SET,MC_LOG_MAKEENV,MC_DEF_LOG_MAKEENV));
201                 return 0;
202         }
203
204         if (*value) {
205                    sprintf (result, "%s=%s", name, value);
206         }
207         else {
208                 sprintf (result, "%s", name);
209         }
210
211         return result;
212 }
213
214 char * 
215 getEnv( char **e, char *name )
216 {
217     int l = strlen (name);
218
219     while (*e) {
220         if ((int) strlen (*e) > l &&
221             !strncmp (*e, name, l) &&
222             (*e)[l] == '=')
223           return (*e) + l + 1;
224
225         ++e;
226     }
227     return 0;
228 }
229
230 char ** 
231 setEnv( char **e, char *name, char *value )
232 {
233     char        **new, **old;
234     char        *newe;
235     int         envsize;
236     int         l;
237
238     l = strlen (name);
239     newe = makeEnv (name, value);
240     if (!newe) {
241         LogOutOfMem(ReadCatalog(MC_LOG_SET,MC_LOG_SETENV,MC_DEF_LOG_SETENV));
242         return e;
243     }
244     if (e) {
245         for (old = e; *old; old++)
246             if ((int) strlen (*old) > l &&
247                 !strncmp (*old, name, l) &&
248                 (*old)[l] == '=')
249               break;
250
251         if (*old) {
252                 free (*old);
253                 *old = newe;
254                 return e;
255         }
256         envsize = old - e;
257         new = (char **)
258               realloc((char *) e, (unsigned) ((envsize + 2) * sizeof (char *)));
259     } else {
260         envsize = 0;
261         new = (char **) malloc (2 * sizeof (char *));
262     }
263     if (!new) {
264         LogOutOfMem(ReadCatalog(MC_LOG_SET,MC_LOG_SETENV,MC_DEF_LOG_SETENV));
265         free (newe);
266         return e;
267     }
268     new[envsize] = newe;
269     new[envsize+1] = 0;
270     return new;
271 }
272
273 void
274 freeEnv (char **env)
275 {
276     char    **e;
277
278     if (env)
279     {
280         for (e = env; *e; e++)
281             free (*e);
282         free (env);
283     }
284 }
285
286 # define isblank(c)     ((c) == ' ' || c == '\t')
287
288 char ** 
289 parseArgs( char **argv, char *string )
290 {
291         char    *word;
292         char    *save;
293         int     i;
294
295         i = 0;
296         while (argv && argv[i])
297                 ++i;
298         if (!argv) {
299                 argv = (char **) malloc (sizeof (char *));
300                 if (!argv) {
301                         LogOutOfMem(ReadCatalog(
302                           MC_LOG_SET,MC_LOG_PARSEARGS,MC_DEF_LOG_PARSEARGS));
303                         return 0;
304                 }
305         }
306         word = string;
307         for (;;) {
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,
315                                           MC_LOG_PARSEARGS,
316                                           MC_DEF_LOG_PARSEARGS));
317                                         if (argv)
318                                                 free ((char *) argv);
319                                         if (save)
320                                                 free (save);
321                                         return 0;
322                                 }
323                                 argv[i] = strncpy (save, word, string-word);
324                                 argv[i][string-word] = '\0';
325                                 i++;
326                         }
327                         if (!*string)
328                                 break;
329                         word = string + 1;
330                 }
331                 ++string;
332         }
333         argv[i] = 0;
334         return argv;
335 }
336
337 void
338 CleanUpChild( void )
339 {
340 /*
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.
346  */
347 #ifdef __osf__
348         setsid();
349         sigsetmask(0);
350 #else
351 #if defined (SYSV) || defined (SVR4) || defined(linux)
352 #if !defined (USL) && !defined(__uxp__)
353         setpgrp ();
354 #endif  /* USL */
355 #else
356         setpgrp (0, getpid ());
357         sigsetmask (0);
358 #endif
359 #endif /* __osf__ */
360 #ifdef SIGCHLD
361         (void) signal (SIGCHLD, SIG_DFL);
362 #endif
363         (void) signal (SIGTERM, SIG_DFL);
364         (void) signal (SIGPIPE, SIG_DFL);
365         (void) signal (SIGALRM, SIG_DFL);
366         (void) signal (SIGHUP, SIG_DFL);
367         CloseOnFork ();
368 }
369
370 char * * 
371 parseEnv( char **e, char *string )
372 {
373
374     char *s1, *s2, *t1, *t2;
375     
376     s1 = s2 = strdup(string);
377     
378     while ((t1 = strtok(s1," \t")) != NULL ) {
379         if ( (t2 = strchr(t1,'=')) != NULL ) {
380             *t2++ = '\0';
381             e = setEnv(e, t1, t2);
382         }
383         
384         s1 = NULL;
385     }
386
387     free(s2);
388     return (e);
389 }    
390
391
392
393
394 /*************************************<->*************************************
395  *
396  *  Cursor GetHourGlass ()
397  *
398  *
399  *  Description:
400  *  -----------
401  *  Builds and returns the appropriate Hourglass cursor
402  *
403  *
404  *  Inputs:
405  *  ------
406  *  dpy = display
407  * 
408  *  Outputs:
409  *  -------
410  *  Return = cursor.
411  *
412  *  Comments:
413  *  --------
414  *  None. (None doesn't count as a comment)
415  * 
416  *************************************<->***********************************/
417
418 #define time32_width 32
419 #define time32_height 32
420 #define time32_x_hot 15
421 #define time32_y_hot 15
422 static unsigned char time32_bits[] = {
423    0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
424    0x8c, 0x00, 0x00, 0x31, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
425    0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
426    0x8c, 0x00, 0x00, 0x31, 0x0c, 0x7f, 0xfe, 0x30, 0x0c, 0xfe, 0x7f, 0x30,
427    0x0c, 0xfc, 0x3f, 0x30, 0x0c, 0xf8, 0x1f, 0x30, 0x0c, 0xe0, 0x07, 0x30,
428    0x0c, 0x80, 0x01, 0x30, 0x0c, 0x80, 0x01, 0x30, 0x0c, 0x60, 0x06, 0x30,
429    0x0c, 0x18, 0x18, 0x30, 0x0c, 0x04, 0x20, 0x30, 0x0c, 0x02, 0x40, 0x30,
430    0x0c, 0x01, 0x80, 0x30, 0x8c, 0x00, 0x00, 0x31, 0x4c, 0x80, 0x01, 0x32,
431    0x4c, 0xc0, 0x03, 0x32, 0x4c, 0xf0, 0x1f, 0x32, 0x4c, 0xff, 0xff, 0x32,
432    0xcc, 0xff, 0xff, 0x33, 0x8c, 0xff, 0xff, 0x31, 0xfe, 0xff, 0xff, 0x7f,
433    0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00};
434
435 #define time32m_width 32
436 #define time32m_height 32
437 static unsigned char time32m_bits[] = {
438    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
439    0xcf, 0x00, 0x00, 0xf3, 0x6e, 0x00, 0x00, 0x76, 0x6e, 0x00, 0x00, 0x76,
440    0x6e, 0x00, 0x00, 0x76, 0x6e, 0x00, 0x00, 0x76, 0x6e, 0x00, 0x00, 0x76,
441    0xce, 0x00, 0x00, 0x73, 0x8e, 0x7f, 0xfe, 0x71, 0x0e, 0xff, 0xff, 0x70,
442    0x0e, 0xfe, 0x7f, 0x70, 0x0e, 0xfc, 0x3f, 0x70, 0x0e, 0xf8, 0x1f, 0x70,
443    0x0e, 0xe0, 0x07, 0x70, 0x0e, 0xe0, 0x07, 0x70, 0x0e, 0x78, 0x1e, 0x70,
444    0x0e, 0x1c, 0x38, 0x70, 0x0e, 0x06, 0x60, 0x70, 0x0e, 0x03, 0xc0, 0x70,
445    0x8e, 0x01, 0x80, 0x71, 0xce, 0x00, 0x00, 0x73, 0x6e, 0x80, 0x01, 0x76,
446    0x6e, 0xc0, 0x03, 0x76, 0x6e, 0xf0, 0x1f, 0x76, 0x6e, 0xff, 0xff, 0x76,
447    0xee, 0xff, 0xff, 0x77, 0xcf, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff,
448    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
449
450
451 #define time16_x_hot 7
452 #define time16_y_hot 7
453 #define time16_width 16
454 #define time16_height 16
455 static unsigned char time16_bits[] = {
456    0x00, 0x00, 0xfe, 0x7f, 0x14, 0x28, 0x14, 0x28, 0x14, 0x28, 0x24, 0x24,
457    0x44, 0x22, 0x84, 0x21, 0x84, 0x21, 0x44, 0x22, 0x24, 0x24, 0x14, 0x28,
458    0x94, 0x29, 0xd4, 0x2b, 0xfe, 0x7f, 0x00, 0x00};
459
460 #define time16m_width 16
461 #define time16m_height 16
462 static unsigned char time16m_bits[] = {
463    0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
464    0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
465    0xfe, 0x7f, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff};
466
467
468 Cursor GetHourGlass (Display *dpy)
469 {
470     char        *bits;
471     char        *maskBits;
472     unsigned int width;
473     unsigned int height;
474     unsigned int xHotspot;
475     unsigned int yHotspot;
476     Pixmap       pixmap;
477     Pixmap       maskPixmap;
478     XColor       xcolors[2];
479     unsigned int cWidth;
480     unsigned int cHeight;
481     int          useLargeCursors = 0;
482     Cursor       waitCursor;
483
484     if (XQueryBestCursor (dpy, DefaultRootWindow(dpy), 
485         32, 32, &cWidth, &cHeight))
486     {
487         if ((cWidth >= 32) && (cHeight >= 32))
488         {
489             useLargeCursors = 1;
490         }
491     }
492
493     if (useLargeCursors)
494     {
495         width = time32_width;
496         height = time32_height;
497         bits = (char *)time32_bits;
498         maskBits = (char *)time32m_bits;
499         xHotspot = time32_x_hot;
500         yHotspot = time32_y_hot;
501     }
502     else
503     {
504         width = time16_width;
505         height = time16_height;
506         bits = (char *)time16_bits;
507         maskBits = (char *)time16m_bits;
508         xHotspot = time16_x_hot;
509         yHotspot = time16_y_hot;
510     }
511
512     pixmap = XCreateBitmapFromData (dpy, 
513                      DefaultRootWindow(dpy), bits, 
514                      width, height);
515
516     maskPixmap = XCreateBitmapFromData (dpy, 
517                      DefaultRootWindow(dpy), maskBits, 
518                      width, height);
519
520     xcolors[0].pixel = BlackPixelOfScreen(DefaultScreenOfDisplay(dpy));
521     xcolors[1].pixel = WhitePixelOfScreen(DefaultScreenOfDisplay(dpy));
522
523     XQueryColors (dpy, 
524                   DefaultColormapOfScreen(DefaultScreenOfDisplay
525                                           (dpy)), xcolors, 2);
526
527     waitCursor = XCreatePixmapCursor (dpy, pixmap, maskPixmap,
528                                       &(xcolors[0]), &(xcolors[1]),
529                                       xHotspot, yHotspot);
530     XFreePixmap (dpy, pixmap);
531     XFreePixmap (dpy, maskPixmap);
532
533     return (waitCursor);
534 }
535
536
537
538
539 /*************************************<->*************************************
540  *
541  *  void SetHourGlassCursor
542  *
543  *
544  *  Description:
545  *  -----------
546  *  sets the window cursor to an hourglass
547  *
548  *
549  *  Inputs:
550  *  ------
551  *  dpy = display
552  *  w   = window
553  * 
554  *  Outputs:
555  *  -------
556  *  None
557  *
558  *  Comments:
559  *  --------
560  *  None. (None doesn't count as a comment)
561  * 
562  *************************************<->***********************************/
563
564 void 
565 SetHourGlassCursor( Display *dpy, Window w )
566 {
567     Cursor      cursor;
568     
569     XUndefineCursor(dpy, w);
570     
571     cursor = GetHourGlass(dpy);
572
573     XDefineCursor(dpy, w, cursor);
574     XFreeCursor(dpy, cursor);
575     XFlush(dpy);
576 }
577
578 #if !defined (ENABLE_DYNAMIC_LANGLIST)
579 /***************************************************************************
580  *
581  *  MakeLangList
582  *
583  *  Generate the list of languages installed on the host.
584  *  Result is stored the global array "languageList"
585  *  
586  ***************************************************************************/
587
588 #define DELIM           " \t"   /* delimiters in language list             */
589
590 static jmp_buf  langJump;
591
592 static SIGVAL
593 MakeLangAbort( int arg )
594
595 {
596     longjmp (langJump, 1);
597 }
598
599 void
600 MakeLangList( void )
601 {
602     register int i, j;
603
604     char        *lang[500];             /* sort list for languages         */
605     int         nlang;                  /* total number of languages       */
606     char        *p, *s;
607     char        *savelist;
608
609     /*
610      *  build language list from set of languages installed on the host...
611      *  Wrap a timer around it so it doesn't hang things up too long.
612      *  langListTimeout resource  by default is 30 seconds to scan NLS dir. 
613      */
614
615     p = languageList;
616     strcpy( p, "C");
617
618     signal (SIGALRM, MakeLangAbort);
619     alarm ((unsigned) langListTimeout);
620
621     if (!setjmp (langJump)) {
622         ScanNLSDir(DEF_NLS_DIR);
623     }
624     else {
625         LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_SCAN,MC_DEF_LOG_NO_SCAN),
626                    DEF_NLS_DIR, langListTimeout);
627     }
628
629     alarm (0);
630     signal (SIGALRM, SIG_DFL);
631
632
633     /*
634      *  sort the list to eliminate duplicates and replace in global array...
635      */
636
637     p = savelist = strdup(languageList);
638     nlang = 0;
639
640     while ( (s = strtok(p, DELIM)) != NULL ) {
641
642         if ( nlang == 0 ) {
643             lang[0] = s;
644             lang[++nlang] = 0;
645             p = NULL;
646             continue;
647         }
648
649         for (i = nlang; i > 0 && strcmp(s,lang[i-1]) < 0; i--);
650
651         if (i==0 || strcmp(s,lang[i-1]) != 0 ) {
652             for (j = nlang; j > i; j--)
653                 lang[j] = lang[j-1];
654
655             lang[i] = s;
656             lang[++nlang] = 0;
657         }
658
659         p = NULL;
660     }
661
662
663     p = languageList;
664     strcpy(p,"");
665
666     for ( i = 0; i < nlang; i++) {
667         strcat(p, lang[i]);
668         strcat(p, " ");
669     }
670
671     free(savelist);
672
673 }        
674
675
676 static int
677 MatchesFileSuffix(const char *filename, const char *suffix)
678 {
679     int         retval = 0;
680 #if defined(_AIX) || defined(SVR4) || defined (__osf__) || defined(linux) || \
681         defined(CSRG_BASED)
682     int         different = 1;
683              
684     /*
685      * The assumption here is that the use of strrstr is
686      * to determine if "dp->d_name" ends in ".cat".
687      */
688     if (strlen(filename) >= strlen(suffix)) {
689       different = strcmp(filename + (strlen(filename) - strlen (suffix)), suffix);
690     }
691
692     return (different == 0);
693 #else
694     return (strrstr(filename, suffix) != NULL);
695 #endif
696 }
697
698 /***************************************************************************
699  *
700  *  ScanNLSDir
701  *
702  *  Scan a directory structure to see if it contains an installed language.
703  *  If so, the name of the language is appended to a global list of languages.
704  *
705  *  Scan method and scan directory will vary by platform. 
706  *
707  ***************************************************************************/
708
709
710 static void
711 ScanNLSDir(char *dirname)
712
713 #if defined(_AIX)
714 /*
715  * Search installed locale names for AIX 3.2.5
716  */
717 {
718     DIR *dirp;
719     struct dirent *dp;
720
721     /*  Search valid locales which are locale database files in
722      *  /usr/lib/nls/loc.
723      *  File name is "??_??" which can be used as LANG variable.
724      */
725     if((dirp = opendir(dirname)) != NULL)
726     {
727         while((dp = readdir(dirp)) != NULL)
728         {
729             if(strlen(dp->d_name) == 5 && dp->d_name[2] == '_')
730             {
731                 if((int) strlen(languageList) + 7 < LANGLISTSIZE )
732                 {
733                     strcat(languageList, " ");
734                     strcat(languageList, dp->d_name);
735                 }
736             }
737         }
738         closedir(dirp);
739     }
740 }
741
742 #elif defined(hpV4)
743
744 #define LOCALE          "locale.inf"
745 #define LOCALEOLD       "locale.def"
746 #define COLLATE8        "collate8"
747 #define MAILX           "mailx"
748 #define ELM             "elm"
749 #define MSGCAT          ".cat"
750 #define DOT             "."
751 #define DOTDOT          ".."
752
753 /*
754  * Scan for installed locales on HP platform.
755  */
756 {
757     /***************************************************************************
758      *  Scan supplied NLS directory structure to see if it contains an
759      *  installed language.  If so, the name of the language is appended
760      *  to a global list of languages.
761      *
762      *  This routine is recursively called as a directory structure is
763      *  traversed.
764      *
765      *************************************************************************/
766
767     DIR *dirp;
768     struct dirent *dp;
769     struct stat statb;
770
771     char buf[1024];
772     
773     /*
774      *  Scan input directory, looking for a LOCALE file. If a sub-directory
775      *  is found, recurse down into it...
776      */
777     if ( (dirp = opendir(dirname)) != NULL )
778     {
779         while ( (dp = readdir(dirp)) != NULL )
780         {
781             /*
782              *  ignore files that are known not to be candidates...
783              */
784             if ( MatchesFileSuffix(dp->d_name, MSGCAT) ||
785                  (strcmp (dp->d_name, COLLATE8) == 0 ) ||
786                  (strcmp (dp->d_name, MAILX)    == 0 ) ||
787                  (strcmp (dp->d_name, ELM)      == 0 ) ||
788                  (strcmp (dp->d_name, DOT)      == 0 ) ||
789                  (strcmp (dp->d_name, DOTDOT)   == 0 ) )
790               continue;
791
792
793             /*
794              *  check to see if this is the locale file...
795              */
796             if ( (strcmp(dp->d_name, LOCALEOLD) == 0 ) ||
797                  (strcmp(dp->d_name, LOCALE)    == 0 ) )
798             {
799                 char *p, *s;
800
801                 /*
802                  *  Convert directory name to language name...
803                  */
804                 if ( (p = strstr(dirname, DEF_NLS_DIR)) != NULL )
805                 {
806                     p += strlen(DEF_NLS_DIR);
807                     if ( *p == '/' )
808                       p++;
809
810                     s = p;
811                     while ( (p = strchr(s,'/')) != NULL )
812                       *p = '.';
813
814                     /*
815                      *  append to global list of languages...
816                      */
817                     if ((int) (strlen(languageList)+strlen(s)+2) < LANGLISTSIZE)
818                     {
819                         strcat(languageList, " ");
820                         strcat(languageList, s);
821                     }
822                 }
823
824                 continue;
825             }
826         
827             /*
828              *  if this file is a directory, scan it also...
829              */
830             strcpy(buf, dirname);
831             strcat(buf, "/");
832             strcat(buf, dp->d_name);
833
834             if  (stat(buf, &statb) == 0  &&  S_ISDIR(statb.st_mode))
835               ScanNLSDir(buf);
836         }
837
838         closedir(dirp);
839     }
840 }
841
842 #elif defined(__osf__)
843
844 #if defined(__osf__obsoleted)
845 #define LANGUAGE_LIST_CMD       "/bin/locale -a"
846 /*
847  * Scan for installed locales on DEC platform
848  */
849 {
850     FILE        *f;
851     char        locale[MAXPATHLEN];
852
853     if (NULL == (f = popen(LANGUAGE_LIST_CMD, "r")))
854       return;
855
856     while (NULL != fgets(locale, sizeof(locale), f))
857     {
858         if  (locale[0] != '.' &&
859              LANGLISTSIZE > (int) (strlen(languageList) + strlen(locale) + 2))
860         {
861             int len = strlen(locale);
862
863             if ('\n' == locale[len-1])
864               locale[len-1] = '\0';
865             strcat(languageList, " ");
866             strcat(languageList, locale);
867         }
868     }
869
870     pclose(f);
871 }
872
873 #else
874
875 {
876 #include <fnmatch.h>
877     char *str, *p;
878     char **ignore = NULL;
879     int num_ignore = 0;
880     int max_ignore = 0;
881     int listlen = 0;
882     const char *delim = " \t";
883     DIR *dirp;
884     struct dirent *entp;
885
886     /*
887      * Convert the string of locale patterns to an array.  It will
888      * be easier to loop through when we start matching locales.
889      */
890
891     if (!(str = strdup(ignoreLocales)))
892         return;
893
894     for (p = strtok(str, delim); p; p = strtok(NULL, delim)) {
895         if (num_ignore >= max_ignore) {
896             max_ignore += 16;
897             if (!(ignore = realloc(ignore, max_ignore * sizeof(char *)))) {
898                 free(str);
899                 return;
900             }
901         }
902
903         ignore[num_ignore++] = p;
904     }
905
906     /*
907      * Assume that each file of the form ??_??* is a locale.  If
908      * the locale doesn't match any of the ignore patterns, add it
909      * to the language list with a space separator.
910      *
911      * Seed the list with C and POSIX.  They're built into libc
912      * and don't have locale files.  Checking ignoreLocales for them
913      * isn't worth the effort.
914      */
915
916     strcpy(languageList, "C POSIX");
917     listlen = strlen(languageList);
918
919     if (dirp = opendir(dirname)) {
920         while (entp = readdir(dirp)) {
921             int namelen = strlen(entp->d_name);
922             if (namelen >= 5 && entp->d_name[2] == '_') {
923                 int  i, match = 0;
924                 for (i = 0; i < num_ignore; i++) {
925                     if (!fnmatch(ignore[i], entp->d_name, 0)) {
926                         match = 1;
927                         break;
928                     }
929                 }
930
931                 if (match)
932                     continue;
933
934                 /* 1 for space-separator, 1 for null-terminator */
935                 if (listlen + 1 + namelen + 1 > LANGLISTSIZE)
936                     break;
937
938                 languageList[listlen++] = ' ';
939
940                 strcpy(&languageList[listlen], entp->d_name);
941                 listlen += namelen;
942             }
943         }
944
945         languageList[listlen++] = '\0';
946         closedir(dirp);
947     }
948
949     free(ignore);
950     free(str);
951 }
952 #endif /* __osf__obsoleted__ */
953
954 #elif defined(__uxp__) || defined(USL)
955
956 #define LC_COLLATE      "LC_COLLATE"
957 #define LC_CTYPE        "LC_CTYPE"
958 #define LC_MESSAGES     "LC_MESSAGES"
959 #define LC_MONETARY     "LC_MONETARY"
960 #define LC_NUMERIC      "LC_NUMERIC"
961 #define LC_TIME         "LC_TIME"
962
963 /*
964  * Scan for installed locales on Fujitsu and Novell/SCO platforms.
965  */
966 {
967     DIR *nls_dirp, *locale_dirp;
968     struct dirent *dp;
969     char* locale; 
970     char locale_path[MAXPATHLEN];
971     struct stat locale_stat;
972     int retval;
973
974     /* 
975      * To determin the fully installed locale list, check several locations.
976      */
977     if((nls_dirp = opendir(dirname)) != NULL)
978     {
979         while((dp = readdir(nls_dirp)) != NULL)
980         {
981             int is_locale = 0;
982
983             locale = dp->d_name;
984
985             /*
986              * A locale is indicated by a directory which has one or more
987              * of the following subdirectories:
988              *          LC_COLLATE
989              *          LC_CTYPE
990              *          LC_MESSAGES
991              *          LC_MONETARY
992              *          LC_NUMERIC
993              *          LC_TIME
994              */
995             (void) sprintf(locale_path, "%s/%s", dirname, locale);
996             retval = stat(locale_path, &locale_stat);
997             if ( (0 != retval) || (! S_ISDIR(locale_stat.st_mode)) )
998               continue;
999
1000             if (NULL == (locale_dirp = opendir(locale_path)) )
1001               continue;
1002             
1003             is_locale = FALSE;
1004             while (NULL != (dp = readdir(locale_dirp)) &&
1005                    FALSE == is_locale)
1006             {
1007                 if ((0 == strcmp(dp->d_name, LC_COLLATE)) ||
1008                     (0 == strcmp(dp->d_name, LC_CTYPE)) ||
1009                     (0 == strcmp(dp->d_name, LC_MESSAGES)) ||
1010                     (0 == strcmp(dp->d_name, LC_MONETARY)) ||
1011                     (0 == strcmp(dp->d_name, LC_NUMERIC)) ||
1012                     (0 == strcmp(dp->d_name, LC_TIME)) )
1013                   is_locale = 1;
1014             }
1015
1016             closedir(locale_dirp);
1017
1018             if (is_locale &&
1019                 LANGLISTSIZE > (int) (strlen(languageList)+strlen(locale)+2) )
1020             {
1021                 strcat(languageList, " ");
1022                 strcat(languageList, locale);
1023             }
1024         }
1025
1026         closedir(nls_dirp);
1027     }
1028 }
1029
1030 #else /* !_AIX && !hpV4 && !__osf__ !sun && !USL && !__uxp__ */
1031 /*
1032  * Scan for installed locales on generic platform
1033  */
1034 {
1035     DIR *dirp;
1036     struct dirent *dp;
1037     char* locale; 
1038     char locale_path[MAXPATHLEN];
1039     struct stat locale_stat;
1040     int retval;
1041
1042     /* 
1043      * To determin the fully installed locale list, check several locations.
1044      */
1045     if(NULL != (dirp = opendir(dirname)))
1046     {
1047         while((dp = readdir(dirp)) != NULL)
1048         {
1049             locale = dp->d_name;
1050
1051             if ( (strcmp(dp->d_name, ".") == 0) ||
1052                  (strcmp(dp->d_name, "..") == 0) )
1053               continue;
1054
1055             if (locale[0] != '.' &&
1056                 LANGLISTSIZE > (int) (strlen(languageList)+strlen(locale)+2));
1057             {
1058                 (void) sprintf(locale_path, "%s/%s", dirname, locale);
1059                 retval = stat(locale_path, &locale_stat);
1060
1061                 if (0 == retval && S_ISDIR(locale_stat.st_mode))
1062                 {
1063                     strcat(languageList, " ");
1064                     strcat(languageList, locale);
1065                 }
1066             }
1067         }
1068         closedir(dirp);
1069     }
1070 }
1071
1072 #endif
1073
1074 #endif /* ENABLE_DYNAMIC_LANGLIST */
1075
1076 #ifdef _AIX
1077 #define ENVFILE "/etc/environment"
1078
1079 /* Refer to the LANG environment variable, first.
1080  * Or, search a line which includes "LANG=XX_XX" in /etc/environment.
1081  * If succeeded, set the value to d->language.
1082  */
1083 void
1084 SetDefaultLanguage(struct display *d)
1085 {
1086     FILE *file;
1087     char lineBuf[160];
1088     int n;
1089     char *p;
1090     char *lang = NULL;
1091
1092     if((lang = getenv( "LANG" )) == NULL ) {
1093         if((file = fopen(ENVFILE, "r")) != NULL) {
1094             while(fgets(lineBuf, sizeof(lineBuf) - 1, file)) {
1095                 n = strlen(lineBuf);
1096                 if(n > 1 && lineBuf[0] != '#') {
1097                     if(lineBuf[n - 1] == '\n')
1098                         lineBuf[n - 1] = '\0';
1099                     if((p = strstr(lineBuf, "LANG=")) != NULL) {
1100                         p += 5;
1101                         if(strlen(p) == 5 && p[2] == '_') {
1102                             lang = p;
1103                             break;
1104                         }
1105                     }
1106                 }
1107             }
1108             fclose(file);
1109         }
1110     }
1111     if(lang != NULL && strlen(lang) > 0) {
1112     /*
1113      * If LANG is set for hft, we need to change it for X.
1114      * Currently there are four hft LANG variables.
1115      */
1116         d->language = (char *)malloc(strlen(lang)+1);
1117         if(strcmp(lang, "En_JP") == 0)
1118             strcpy(d->language, "Ja_JP");
1119         else if(strcmp(lang, "en_JP") == 0)
1120             strcpy(d->language, "ja_JP");
1121         else if(strcmp(lang, "en_KR") == 0)
1122             strcpy(d->language, "ko_KR");
1123         else if(strcmp(lang, "en_TW") == 0)
1124             strcpy(d->language, "zh_TW");
1125         else
1126             strcpy(d->language, lang);
1127     }
1128 }
1129 #endif /* _AIX */
1130
1131
1132 char **
1133 setLang( struct display *d, char **env , char *langptr)
1134 {
1135     char  langlist[LANGLISTSIZE];
1136     int   s = 0;
1137     char *element = NULL;
1138     int   set_def_lang = FALSE;
1139  
1140  
1141     if (NULL != langptr)
1142       Debug("setLang():  langlist = %s\n", langptr);
1143     else
1144       Debug("setLang():  langlist = NULL\n");
1145
1146     if (langptr)
1147       snprintf(langlist, sizeof(langlist), "%s", langptr);
1148     else
1149       snprintf(langlist, sizeof(langlist), "%s", getEnv(env, "LANGLIST"));
1150
1151     if (strlen(langlist) > 0) {
1152         element = strtok(langlist, DELIM);
1153         while(element) {
1154             set_def_lang = FALSE;
1155             if (strcmp(element,d->language) == 0){
1156                 env = setEnv(env, "LANG",  d->language);
1157                 break;
1158             }
1159             else
1160               set_def_lang = TRUE;
1161  
1162             s += strlen(element) +1;
1163             element = strtok(langlist+s, DELIM);
1164         }
1165     } else
1166       set_def_lang = TRUE;
1167  
1168     if (set_def_lang) {
1169         env = setEnv(env, "LANG", "C");
1170         d->language = strdup("C");
1171     }
1172     return env;
1173 }
1174
1175 static char localHostbuf[256];
1176 static int  gotLocalHostname;
1177
1178 char *
1179 localHostname ()
1180 {
1181     if (!gotLocalHostname)
1182     {
1183         XmuGetHostname (localHostbuf, sizeof (localHostbuf) - 1);
1184         gotLocalHostname = 1;
1185     }
1186     return localHostbuf;
1187 }
1188