dtlogin: Resolve all -Wformat-security warnings
[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         defined(CSRG_BASED)
684     char        *pch;
685              
686     /*
687      * The assumption here is that the use of strrstr is
688      * to determine if "dp->d_name" ends in ".cat".
689      */
690     pch = filename;
691     if ((int) strlen(filename) >= (int) strlen(suffix))
692       pch = (char *)
693             strcmp(filename + (strlen(filename) - strlen (suffix)), suffix);
694
695     return (pch == NULL);
696 #else
697     return (strrstr(filename, suffix) != NULL);
698 #endif
699 }
700
701 /***************************************************************************
702  *
703  *  ScanNLSDir
704  *
705  *  Scan a directory structure to see if it contains an installed language.
706  *  If so, the name of the language is appended to a global list of languages.
707  *
708  *  Scan method and scan directory will vary by platform. 
709  *
710  ***************************************************************************/
711
712
713 static void
714 ScanNLSDir(char *dirname)
715
716 #if defined(_AIX)
717 /*
718  * Search installed locale names for AIX 3.2.5
719  */
720 {
721     DIR *dirp;
722     struct dirent *dp;
723
724     /*  Search valid locales which are locale database files in
725      *  /usr/lib/nls/loc.
726      *  File name is "??_??" which can be used as LANG variable.
727      */
728     if((dirp = opendir(dirname)) != NULL)
729     {
730         while((dp = readdir(dirp)) != NULL)
731         {
732             if(strlen(dp->d_name) == 5 && dp->d_name[2] == '_')
733             {
734                 if((int) strlen(languageList) + 7 < LANGLISTSIZE )
735                 {
736                     strcat(languageList, " ");
737                     strcat(languageList, dp->d_name);
738                 }
739             }
740         }
741         closedir(dirp);
742     }
743 }
744
745 #elif defined(hpV4)
746
747 #define LOCALE          "locale.inf"
748 #define LOCALEOLD       "locale.def"
749 #define COLLATE8        "collate8"
750 #define MAILX           "mailx"
751 #define ELM             "elm"
752 #define MSGCAT          ".cat"
753 #define DOT             "."
754 #define DOTDOT          ".."
755
756 /*
757  * Scan for installed locales on HP platform.
758  */
759 {
760     /***************************************************************************
761      *  Scan supplied NLS directory structure to see if it contains an
762      *  installed language.  If so, the name of the language is appended
763      *  to a global list of languages.
764      *
765      *  This routine is recursively called as a directory structure is
766      *  traversed.
767      *
768      *************************************************************************/
769
770     DIR *dirp;
771     struct dirent *dp;
772     struct stat statb;
773
774     char buf[1024];
775     
776     /*
777      *  Scan input directory, looking for a LOCALE file. If a sub-directory
778      *  is found, recurse down into it...
779      */
780     if ( (dirp = opendir(dirname)) != NULL )
781     {
782         while ( (dp = readdir(dirp)) != NULL )
783         {
784             /*
785              *  ignore files that are known not to be candidates...
786              */
787             if ( MatchesFileSuffix(dp->d_name, MSGCAT) ||
788                  (strcmp (dp->d_name, COLLATE8) == 0 ) ||
789                  (strcmp (dp->d_name, MAILX)    == 0 ) ||
790                  (strcmp (dp->d_name, ELM)      == 0 ) ||
791                  (strcmp (dp->d_name, DOT)      == 0 ) ||
792                  (strcmp (dp->d_name, DOTDOT)   == 0 ) )
793               continue;
794
795
796             /*
797              *  check to see if this is the locale file...
798              */
799             if ( (strcmp(dp->d_name, LOCALEOLD) == 0 ) ||
800                  (strcmp(dp->d_name, LOCALE)    == 0 ) )
801             {
802                 char *p, *s;
803
804                 /*
805                  *  Convert directory name to language name...
806                  */
807                 if ( (p = strstr(dirname, DEF_NLS_DIR)) != NULL )
808                 {
809                     p += strlen(DEF_NLS_DIR);
810                     if ( *p == '/' )
811                       p++;
812
813                     s = p;
814                     while ( (p = strchr(s,'/')) != NULL )
815                       *p = '.';
816
817                     /*
818                      *  append to global list of languages...
819                      */
820                     if ((int) (strlen(languageList)+strlen(s)+2) < LANGLISTSIZE)
821                     {
822                         strcat(languageList, " ");
823                         strcat(languageList, s);
824                     }
825                 }
826
827                 continue;
828             }
829         
830             /*
831              *  if this file is a directory, scan it also...
832              */
833             strcpy(buf, dirname);
834             strcat(buf, "/");
835             strcat(buf, dp->d_name);
836
837             if  (stat(buf, &statb) == 0  &&  S_ISDIR(statb.st_mode))
838               ScanNLSDir(buf);
839         }
840
841         closedir(dirp);
842     }
843 }
844
845 #elif defined(__osf__)
846
847 #if defined(__osf__obsoleted)
848 #define LANGUAGE_LIST_CMD       "/bin/locale -a"
849 /*
850  * Scan for installed locales on DEC platform
851  */
852 {
853     FILE        *f;
854     char        locale[MAXPATHLEN];
855
856     if (NULL == (f = popen(LANGUAGE_LIST_CMD, "r")))
857       return;
858
859     while (NULL != fgets(locale, sizeof(locale), f))
860     {
861         if  (locale[0] != '.' &&
862              LANGLISTSIZE > (int) (strlen(languageList) + strlen(locale) + 2))
863         {
864             int len = strlen(locale);
865
866             if ('\n' == locale[len-1])
867               locale[len-1] = '\0';
868             strcat(languageList, " ");
869             strcat(languageList, locale);
870         }
871     }
872
873     pclose(f);
874 }
875
876 #else
877
878 {
879 #include <fnmatch.h>
880     char *str, *p;
881     char **ignore = NULL;
882     int num_ignore = 0;
883     int max_ignore = 0;
884     int listlen = 0;
885     const char *delim = " \t";
886     DIR *dirp;
887     struct dirent *entp;
888
889     /*
890      * Convert the string of locale patterns to an array.  It will
891      * be easier to loop through when we start matching locales.
892      */
893
894     if (!(str = strdup(ignoreLocales)))
895         return;
896
897     for (p = strtok(str, delim); p; p = strtok(NULL, delim)) {
898         if (num_ignore >= max_ignore) {
899             max_ignore += 16;
900             if (!(ignore = realloc(ignore, max_ignore * sizeof(char *)))) {
901                 free(str);
902                 return;
903             }
904         }
905
906         ignore[num_ignore++] = p;
907     }
908
909     /*
910      * Assume that each file of the form ??_??* is a locale.  If
911      * the locale doesn't match any of the ignore patterns, add it
912      * to the language list with a space separator.
913      *
914      * Seed the list with C and POSIX.  They're built into libc
915      * and don't have locale files.  Checking ignoreLocales for them
916      * isn't worth the effort.
917      */
918
919     strcpy(languageList, "C POSIX");
920     listlen = strlen(languageList);
921
922     if (dirp = opendir(dirname)) {
923         while (entp = readdir(dirp)) {
924             int namelen = strlen(entp->d_name);
925             if (namelen >= 5 && entp->d_name[2] == '_') {
926                 int  i, match = 0;
927                 for (i = 0; i < num_ignore; i++) {
928                     if (!fnmatch(ignore[i], entp->d_name, 0)) {
929                         match = 1;
930                         break;
931                     }
932                 }
933
934                 if (match)
935                     continue;
936
937                 /* 1 for space-separator, 1 for null-terminator */
938                 if (listlen + 1 + namelen + 1 > LANGLISTSIZE)
939                     break;
940
941                 languageList[listlen++] = ' ';
942
943                 strcpy(&languageList[listlen], entp->d_name);
944                 listlen += namelen;
945             }
946         }
947
948         languageList[listlen++] = '\0';
949         closedir(dirp);
950     }
951
952     free(ignore);
953     free(str);
954 }
955 #endif /* __osf__obsoleted__ */
956
957 #elif defined(sun)
958 /*
959  * Scan for installed locales on Sun platform.
960  */
961 {
962     DIR *dirp;
963     struct dirent *dp;
964     char* filename; 
965     char path1[MAXPATHLEN], path2[MAXPATHLEN];
966     struct stat stat1, stat2;
967     int retval1, retval2;
968
969     /* 
970      * To determin the fully installed locale list, check several locations.
971      */
972     if((dirp = opendir(DEF_X11_NLS_SHARE_DIR)) != NULL)
973     {
974         while((dp = readdir(dirp)) != NULL)
975         {
976             filename = dp->d_name;
977
978             if  ( filename[0] != '.' &&
979                  (int)(strlen(languageList) +
980                        strlen(filename) + 2) < LANGLISTSIZE)
981             {
982                 (void) sprintf(path1, "%s/%s", DEF_X11_NLS_LIB_DIR, filename);
983                 (void) sprintf(path2, "%s/%s", dirname, filename);
984                 retval1 = stat(path1, &stat1);
985                 retval2 = stat(path2, &stat2);
986
987                 if ( retval1==0 && retval2==0 &&
988                      S_ISDIR(stat1.st_mode) && S_ISDIR(stat2.st_mode) )
989                 {
990                     strcat(languageList, " ");
991                     strcat(languageList, filename);
992                 }
993             }
994         }
995         closedir(dirp);
996     }
997 }
998
999 #elif defined(__uxp__) || defined(USL)
1000
1001 #define LC_COLLATE      "LC_COLLATE"
1002 #define LC_CTYPE        "LC_CTYPE"
1003 #define LC_MESSAGES     "LC_MESSAGES"
1004 #define LC_MONETARY     "LC_MONETARY"
1005 #define LC_NUMERIC      "LC_NUMERIC"
1006 #define LC_TIME         "LC_TIME"
1007
1008 /*
1009  * Scan for installed locales on Fujitsu and Novell/SCO platforms.
1010  */
1011 {
1012     DIR *nls_dirp, *locale_dirp;
1013     struct dirent *dp;
1014     char* locale; 
1015     char locale_path[MAXPATHLEN];
1016     struct stat locale_stat;
1017     int retval;
1018
1019     /* 
1020      * To determin the fully installed locale list, check several locations.
1021      */
1022     if((nls_dirp = opendir(dirname)) != NULL)
1023     {
1024         while((dp = readdir(nls_dirp)) != NULL)
1025         {
1026             int is_locale = 0;
1027
1028             locale = dp->d_name;
1029
1030             /*
1031              * A locale is indicated by a directory which has one or more
1032              * of the following subdirectories:
1033              *          LC_COLLATE
1034              *          LC_CTYPE
1035              *          LC_MESSAGES
1036              *          LC_MONETARY
1037              *          LC_NUMERIC
1038              *          LC_TIME
1039              */
1040             (void) sprintf(locale_path, "%s/%s", dirname, locale);
1041             retval = stat(locale_path, &locale_stat);
1042             if ( (0 != retval) || (! S_ISDIR(locale_stat.st_mode)) )
1043               continue;
1044
1045             if (NULL == (locale_dirp = opendir(locale_path)) )
1046               continue;
1047             
1048             is_locale = FALSE;
1049             while (NULL != (dp = readdir(locale_dirp)) &&
1050                    FALSE == is_locale)
1051             {
1052                 if ((0 == strcmp(dp->d_name, LC_COLLATE)) ||
1053                     (0 == strcmp(dp->d_name, LC_CTYPE)) ||
1054                     (0 == strcmp(dp->d_name, LC_MESSAGES)) ||
1055                     (0 == strcmp(dp->d_name, LC_MONETARY)) ||
1056                     (0 == strcmp(dp->d_name, LC_NUMERIC)) ||
1057                     (0 == strcmp(dp->d_name, LC_TIME)) )
1058                   is_locale = 1;
1059             }
1060
1061             closedir(locale_dirp);
1062
1063             if (is_locale &&
1064                 LANGLISTSIZE > (int) (strlen(languageList)+strlen(locale)+2) )
1065             {
1066                 strcat(languageList, " ");
1067                 strcat(languageList, locale);
1068             }
1069         }
1070
1071         closedir(nls_dirp);
1072     }
1073 }
1074
1075 #else /* !_AIX && !hpV4 && !__osf__ !sun && !USL && !__uxp__ */
1076 /*
1077  * Scan for installed locales on generic platform
1078  */
1079 {
1080     DIR *dirp;
1081     struct dirent *dp;
1082     char* locale; 
1083     char locale_path[MAXPATHLEN];
1084     struct stat locale_stat;
1085     int retval;
1086
1087     /* 
1088      * To determin the fully installed locale list, check several locations.
1089      */
1090     if(NULL != (dirp = opendir(dirname)))
1091     {
1092         while((dp = readdir(dirp)) != NULL)
1093         {
1094             locale = dp->d_name;
1095
1096             if ( (strcmp(dp->d_name, ".") == 0) ||
1097                  (strcmp(dp->d_name, "..") == 0) )
1098               continue;
1099
1100             if (locale[0] != '.' &&
1101                 LANGLISTSIZE > (int) (strlen(languageList)+strlen(locale)+2));
1102             {
1103                 (void) sprintf(locale_path, "%s/%s", dirname, locale);
1104                 retval = stat(locale_path, &locale_stat);
1105
1106                 if (0 == retval && S_ISDIR(locale_stat.st_mode))
1107                 {
1108                     strcat(languageList, " ");
1109                     strcat(languageList, locale);
1110                 }
1111             }
1112         }
1113         closedir(dirp);
1114     }
1115 }
1116
1117 #endif
1118
1119 #endif /* ENABLE_DYNAMIC_LANGLIST */
1120
1121 #ifdef _AIX
1122 #define ENVFILE "/etc/environment"
1123
1124 /* Refer to the LANG environment variable, first.
1125  * Or, search a line which includes "LANG=XX_XX" in /etc/environment.
1126  * If succeeded, set the value to d->language.
1127  */
1128 void
1129 SetDefaultLanguage(struct display *d)
1130 {
1131     FILE *file;
1132     char lineBuf[160];
1133     int n;
1134     char *p;
1135     char *lang = NULL;
1136
1137     if((lang = getenv( "LANG" )) == NULL ) {
1138         if((file = fopen(ENVFILE, "r")) != NULL) {
1139             while(fgets(lineBuf, sizeof(lineBuf) - 1, file)) {
1140                 n = strlen(lineBuf);
1141                 if(n > 1 && lineBuf[0] != '#') {
1142                     if(lineBuf[n - 1] == '\n')
1143                         lineBuf[n - 1] = '\0';
1144                     if((p = strstr(lineBuf, "LANG=")) != NULL) {
1145                         p += 5;
1146                         if(strlen(p) == 5 && p[2] == '_') {
1147                             lang = p;
1148                             break;
1149                         }
1150                     }
1151                 }
1152             }
1153             fclose(file);
1154         }
1155     }
1156     if(lang != NULL && strlen(lang) > 0) {
1157     /*
1158      * If LANG is set for hft, we need to change it for X.
1159      * Currently there are four hft LANG variables.
1160      */
1161         d->language = (char *)malloc(strlen(lang)+1);
1162         if(strcmp(lang, "En_JP") == 0)
1163             strcpy(d->language, "Ja_JP");
1164         else if(strcmp(lang, "en_JP") == 0)
1165             strcpy(d->language, "ja_JP");
1166         else if(strcmp(lang, "en_KR") == 0)
1167             strcpy(d->language, "ko_KR");
1168         else if(strcmp(lang, "en_TW") == 0)
1169             strcpy(d->language, "zh_TW");
1170         else
1171             strcpy(d->language, lang);
1172     }
1173 }
1174 #endif /* _AIX */
1175
1176
1177 char **
1178 setLang( struct display *d, char **env , char *langptr)
1179 {
1180     char  langlist[LANGLISTSIZE];
1181     int   s = 0;
1182     char *element = NULL;
1183     int   set_def_lang = FALSE;
1184  
1185  
1186     if (NULL != langptr)
1187       Debug("setLang():  langlist = %s\n", langptr);
1188     else
1189       Debug("setLang():  langlist = NULL\n");
1190
1191     if (langptr)
1192       strcpy(langlist, langptr);
1193     else
1194       strcpy(langlist, getEnv(env, "LANGLIST"));
1195
1196     if (langlist && (int) strlen(langlist) > 0) {
1197         element = strtok(langlist, DELIM);
1198         while(element) {
1199             set_def_lang = FALSE;
1200             if (strcmp(element,d->language) == 0){
1201                 env = setEnv(env, "LANG",  d->language);
1202                 break;
1203             }
1204             else
1205               set_def_lang = TRUE;
1206  
1207             s += strlen(element) +1;
1208             element = strtok(langlist+s, DELIM);
1209         }
1210     } else
1211       set_def_lang = TRUE;
1212  
1213     if (set_def_lang) {
1214         env = setEnv(env, "LANG", "C");
1215         d->language = strdup("C");
1216     }
1217     return env;
1218 }
1219
1220 static char localHostbuf[256];
1221 static int  gotLocalHostname;
1222
1223 char *
1224 localHostname ()
1225 {
1226     if (!gotLocalHostname)
1227     {
1228         XmuGetHostname (localHostbuf, sizeof (localHostbuf) - 1);
1229         gotLocalHostname = 1;
1230     }
1231     return localHostbuf;
1232 }
1233