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