Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtSvc / DtUtil1 / DbUtil.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 /*
24  * $TOG: DbUtil.c /main/13 1998/04/09 17:47:56 mgreess $
25  *
26  * (c) Copyright 1988, 1989, 1990, 1991, 1992, 1993 
27  *     by Hewlett-Packard Company, all rights reserved.
28  *
29  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
30  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
31  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
32  * (c) Copyright 1993, 1994 Novell, Inc.                                *
33  */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <sys/types.h>
38
39 #include <dirent.h>
40
41 #include <ctype.h>
42 #include <string.h>
43 #ifdef NLS16
44 #include <limits.h>
45 #endif
46 #include <sys/stat.h>
47 #include <sys/param.h>          /* MAXPATHLEN, MAXHOSTNAMELEN */
48 #include <X11/Xlib.h>
49 #include <X11/Intrinsic.h>
50 #include <X11/StringDefs.h>
51 #define X_INCLUDE_DIRENT_H
52 #define XOS_USE_XT_LOCKING
53 #include <X11/Xos_r.h>
54 #include <Dt/DtP.h>
55 #include <Dt/Connect.h>
56 #include <Dt/FileUtil.h>
57 #include <Dt/DtNlUtils.h>
58 #include <Dt/Action.h>
59 #include <Dt/ActionP.h>
60 #include <Dt/ActionDbP.h>
61 #include <Dt/ActionUtilP.h>
62 #include <Dt/DbUtil.h>
63 #include <Dt/Utility.h>
64
65 #include <Dt/ActionDb.h>
66
67 #ifndef S_ISLNK
68 /* This macro is normally defined in stat.h, but not on USL systems. */
69 #  define S_ISLNK(_M) ((_M & S_IFMT)==S_IFLNK)   /* test for symbolic link */
70 #endif
71
72 #ifndef CDE_INSTALLATION_TOP
73 #define CDE_INSTALLATION_TOP "/opt/dt"
74 #endif
75
76 #ifndef CDE_CONFIGURATION_TOP
77 #define CDE_CONFIGURATION_TOP "/etc/opt/dt"
78 #endif
79
80
81 #define TRUE            1
82 #define FALSE           0
83
84 #define FILE_INCREMENT 20
85
86 /* The following string holds the default value of the Dt database 
87  * search path.  This default search path has the following major
88  * components:
89  *
90  *     $HOME/.dt/types[/%L]        A location for the user's personal
91  *                                  actions and filetypes.
92  *
93  *     <config-location>/appconfig/types[/%L]      
94  *                                  The DT location for system-wide
95  *                                  customizations.
96  *
97  *     <top-of-dt>/types/[%L]          The DT location for default
98  *                                  system-wide actions and filetypes.
99  */
100 static char DTDATABASESEARCHPATH_DEFAULT[] = 
101   "%s/.dt/types/%%L,"
102   "%s/.dt/types,"
103   CDE_CONFIGURATION_TOP "/appconfig/types/%%L,"
104   CDE_CONFIGURATION_TOP "/appconfig/types,"
105   CDE_INSTALLATION_TOP "/appconfig/types/%%L,"
106   CDE_INSTALLATION_TOP "/appconfig/types";
107
108
109 /****   Substitution records used by XtFindFile() in _DtExpandLang()   ****/
110 static SubstitutionRec langSubstitutions[] =
111 {
112     {'L', (char *)NULL},
113     {'l', (char *)NULL},
114     {'t', (char *)NULL},
115     {'c', (char *)NULL}
116 };
117 static int nLangSubstitutions = XtNumber(langSubstitutions);
118
119
120 /********    Static Function Declarations    ********/
121
122 static Boolean __testPath(
123                         String str );
124 static void __setupLangSubstitutions(
125                         void );
126 static void __freeLangSubstitutions(
127                         void );
128 static char *_DtExpandLang(
129                         char *string ) ;
130 static char _DtIsDir( 
131                         char *path,
132                         char *name) ;
133 static void _DtFreeDirVector( 
134                         char **dir_vector) ;
135 static void __swap( 
136                         int i ,
137                         DtDirPaths *data );
138 static void _DtSortFiles( 
139                         int low,
140                         int n, 
141                         DtDirPaths *data) ;
142
143 /********    End Static Function Declarations    ********/
144
145 /******************
146  *
147  * Function Name:  __testPath
148  *
149  * Description:
150  *
151  *      This function is needed by XtFindFile().  Always returns True.
152  *
153  * Synopsis:
154  *
155  *      path = XtFindFile(..., __testPath);
156  *
157  ******************/
158
159 static Boolean
160 __testPath(String str)
161 {
162     return True;
163 }
164
165 /******************
166  *
167  * Function Name:  __setupLangSubstitutions
168  *
169  * Description:
170  *
171  *      This function initializes langSubstitutions[] for use by
172  *      XtFindFile().
173  *
174  * Synopsis:
175  *
176  *      __setupLangSubstitutions();
177  *
178  ******************/
179
180 static void
181 __setupLangSubstitutions(void)
182 {
183     char *lang;
184     char *languagePart;
185     char *territoryPart;
186     char *codesetPart;
187     char *tlPtr, *ttPtr, *tcPtr, *endPtr;
188
189 /*
190  * We should really be calling setlocale to determine the "default"
191  * locale but setlocale's return value is not standardized across
192  * the various vendor platforms nor is it consistent within differnt
193  * revs of individual OS's. (e.g. its changing between HP-UX 9.0 and
194  * HP-UX 10.0).   The "right" call would be the following line:
195  *
196  *  if ((lang = getenv ("LANG")) || (lang = setlocale(LC_C_TYPE,NULL)))
197  *
198  * Here we hard code the default to "C" instead of leaving it NULL.
199  */
200     languagePart = territoryPart = codesetPart = (char *)NULL;
201     if ((lang = getenv ("LANG")) == (char *)NULL)
202         lang = "C";
203
204     lang = XtNewString(lang); /* free'd in __freeLangSubstitutions() */
205
206     tlPtr = lang;
207     endPtr = (char *)NULL;
208     if ((ttPtr = DtStrchr(tlPtr, '_')) != (char *)NULL)
209         ttPtr++;
210
211     if ((tcPtr = DtStrchr(ttPtr ? ttPtr : tlPtr, '.')) != (char *)NULL)
212     {
213         endPtr = tcPtr++;
214         if (*tcPtr != '\0')
215             codesetPart =
216                 XtNewString(tcPtr); /* free'd in __freeLangSubstitutions() */
217     }
218
219     if (ttPtr)
220     {
221         if (endPtr)
222         {
223             int ttLen = endPtr - ttPtr;
224
225             if (ttLen > 0)
226             {
227                 /* free'd in __freeLangSubstitutions() */
228                 territoryPart = (char *)XtMalloc((ttLen + 1) * sizeof(char));
229                 strncpy(territoryPart, ttPtr, ttLen);
230                 territoryPart[ttLen] = '\0';
231             }
232         }
233         else territoryPart =
234                  XtNewString(ttPtr); /* free'd in __freeLangSubstitutions() */
235
236         endPtr = ttPtr - 1;
237     }
238
239     if (endPtr)
240     {
241         int tlLen = endPtr - tlPtr;
242
243         if (tlLen > 0)
244         {
245             /* free'd in __freeLangSubstitutions() */
246             languagePart = (char *)XtMalloc((tlLen + 1) * sizeof(char));
247             strncpy(languagePart, tlPtr, tlLen);
248             languagePart[tlLen] = '\0';
249         }
250     }
251     else languagePart =
252              XtNewString(tlPtr); /* free'd in __freeLangSubstitutions() */
253
254     langSubstitutions[0].substitution = lang;
255     langSubstitutions[1].substitution = languagePart;
256     langSubstitutions[2].substitution = territoryPart;
257     langSubstitutions[3].substitution = codesetPart;
258 }
259
260 /******************
261  *
262  * Function Name:  __freeLangSubstitutions
263  *
264  * Description:
265  *
266  *      This function free's the strings allocated by
267  *      __setupLangSubstitutions and placed into langSubstitutions[]
268  *
269  * Synopsis:
270  *
271  *      __freeLangSubstitutions();
272  *
273  ******************/
274
275 static void
276 __freeLangSubstitutions(void)
277 {
278     int i;
279
280     for (i = 0; i < nLangSubstitutions; i++)
281         XtFree(langSubstitutions[i].substitution);
282 }
283
284 /******************
285  *
286  * Function Name:  _DtExpandLang
287  *
288  * Description:
289  *      
290  *      This function takes the string "string", and performs the following
291  *      replacements:
292  *              %L : contents of LANG environment variable.
293  *              %l : language part of the LANG environment variable.
294  *              %t : territory part of the LANG environment variable.
295  *              %c : codeset part of the LANG environment variable.
296  *              %% : % (e.g. %%L would be replaced by %L, and
297  *                      no substitution would be performed on %L)
298  *
299  *      If $LANG is not defined, the $LANG is assumed to be "C".
300  *
301  * Synopsis:
302  *
303  *      ret_string = _DtExpandLang (string);
304  *
305  *      char *ret_string;       Returns NULL if "string" is NULL, or it points
306  *                              to the expanded string.
307  *
308  *      char *string;           The comma-separated pathnames to expand.
309  *
310  * Note: The caller is responsible for free'ing the returned string.
311  *
312  ******************/
313
314 static char *
315 _DtExpandLang(
316         char *string )
317 {
318     char *thisPath;
319     char *newPath;
320     char *modPath;
321     int pathLen, maxPathLen;
322     int nColons;
323     char *tmpPtr, *tmpPtr1;
324     char *newString;
325     char *tokPtr;
326
327     if (string == NULL)
328         return (NULL);
329
330     /*
331      *  We're going to use XtFindFile() to perform the replacements;
332      *  the colon character ':' is used as a delimiter in XtFindFile,
333      *  so we escape all colon characters in our string before
334      *  passing it along.
335      */
336     for (nColons = 0, tmpPtr = string;
337          (tmpPtr = DtStrchr(tmpPtr, ':')) != (char *)NULL;
338          nColons++, tmpPtr++)
339         /* EMPTY */
340         ;
341
342     newString =
343         (char *)XtCalloc(1, (strlen(string) + nColons + 1) * sizeof(char));
344     for (tmpPtr = string;
345          (tmpPtr1 = DtStrchr(tmpPtr, ':')) != (char *)NULL;
346          tmpPtr = tmpPtr1 + 1)
347     {
348         strncat(newString, tmpPtr, tmpPtr1 - tmpPtr);
349         strcat(newString, "%:");
350     }
351     strcat(newString, tmpPtr);
352
353     __setupLangSubstitutions();
354
355     /*
356      *  XtFindFile() assumes that the string into which it's making
357      *  substitutions is a path, and therefore it assumes that the
358      *  length of the string does not exceed MAXPATHLEN.  Since
359      *  our string is a series of paths, it CAN exceed MAXPATHLEN.
360      *  So, we split our string into individual paths which we then
361      *  pass off to XtFindFile().
362      */
363     pathLen = maxPathLen = 0;
364     newPath = (char *)NULL;
365     for (thisPath = DtStrtok_r(newString, ",", &tokPtr);
366          thisPath != (char *)NULL;
367          thisPath = DtStrtok_r((char *)NULL, ",", &tokPtr))
368     {
369         modPath = XtFindFile(thisPath, langSubstitutions,
370                              nLangSubstitutions, __testPath);
371         if (modPath)
372         {
373             char *origPath = modPath;
374             int modLen;
375
376             /*
377              *  For some reason, XtFindFile() collapses all '/'
378              *  characters EXCEPT at the beginning of the path!
379              *  For backwards compatibility, we collapse those here.
380              */
381             if (*modPath == '/')
382             {
383                 while (*(modPath + 1) == '/')
384                     modPath++;
385             }
386             modLen = strlen(modPath);
387
388             if (pathLen + modLen + 2 > maxPathLen)
389             {
390                 maxPathLen =
391                     ((pathLen + modLen + 2 + MAXPATHLEN) / MAXPATHLEN) *
392                     MAXPATHLEN;
393                 newPath =
394                     (char *)XtRealloc(newPath, maxPathLen * sizeof(char));
395             }
396
397             if (pathLen > 0)
398                 newPath[pathLen++] = ',';
399             strcpy(&(newPath[pathLen]), modPath);
400             pathLen += modLen;
401
402             XtFree(origPath);
403         }
404     }
405
406     __freeLangSubstitutions();
407     XtFree(newString);
408
409     return newPath;
410 }
411
412
413 /******************
414  *
415  * Function Name:  _DtIsDir
416  *
417  * Description:
418  *
419  *      This function tests a pathname to see if it is a directory.
420  *      The path name is received in two pieces, which makes it easy
421  *      for the calling function to test a bunch of files in a directory
422  *      to see if any are subdirectories.
423  *
424  *      This function does NOT handle Softbench-style pathnames with 
425  *      embedded hostnames.
426  *
427  * Synopsis:
428  *
429  *      dir = _DtIsDir (path, name);
430  *
431  *      char dir;               Returns 0 if the item is not a directory, 
432  *                              1 if it is.
433  *      char *path;             The first part of the pathname.  Typically
434  *                              the directory containing the item of interest.
435  *      char *name;             The second half of the pathname.  Typically
436  *                              the name of the item of interest.
437  *
438  ******************/
439
440 static char 
441 _DtIsDir(
442         char *path,
443         char *name )
444 {
445    struct stat stat_buf;
446    char *stat_name;
447    
448    stat_name = XtMalloc ((Cardinal)(strlen(path) + strlen(name) + 2));
449    (void)strcpy (stat_name, path);
450    (void)strcat (stat_name, "/");
451    (void)strcat (stat_name, name);
452    
453    if(stat (stat_name, &stat_buf))
454    {
455         stat_buf.st_mode = 0;
456    }
457    XtFree (stat_name);
458    
459    if (stat_buf.st_mode & S_IFDIR)
460       return (TRUE);
461    else
462       return (FALSE);
463 }
464
465
466 /******************************
467  *
468  * Function Name:  _DtFreeDirVector
469  *
470  * Description:
471  *
472  *      This function frees a database-directory string vector.
473  *
474  * Synoposis:
475  *
476  *      FreeDatabaseDirs (dirs);
477  *
478  *      char **dirs;            The string vector to free.
479  *
480  ********************************/
481
482 static void 
483 _DtFreeDirVector(
484         char **dir_vector )
485 {
486    char **v;
487    
488    if (dir_vector)
489    {
490       for (v = dir_vector; *v != NULL; v++)
491          XtFree ((char *)*v);
492    
493       XtFree ((char *)dir_vector);
494    }
495 }
496
497
498 /******************************
499  *
500  * Function Name:  __swap
501  *
502  * Description:
503  *
504  *      This function exchanges two elements in an array of DtDirPaths.
505  *
506  * Synoposis:
507  *
508  *      __swap (i, data);
509  *
510  *      int i;                  The base index to change.
511  *      DtDirPaths *data;       The data to change.
512  *
513  ********************************/
514
515 static void
516 __swap( 
517         int i ,
518         DtDirPaths *data )
519 {
520    char *tmp;
521
522    /* The "names" field of the structure is not touched because
523     * this field is "NULL" for all of the entries.
524     */
525    tmp = data->dirs[i]; 
526    data->dirs[i] = data->dirs[i+1]; data->dirs[i+1] = tmp;
527
528    tmp = data->paths[i]; 
529    data->paths[i] = data->paths[i+1]; data->paths[i+1] = tmp;
530 }
531
532
533 /******************************
534  *
535  * Function Name:  _DtSortFiles
536  *
537  * Description:
538  *
539  *      Given an index, an array of "char" data and the number of elements to
540  *      sort, this function sorts the data.  The sorting algorithm is based
541  *      on a bubble sort because the number of elements is usually less than
542  *      ten.
543  *
544  * Synoposis:
545  *
546  *      _DtSortFiles (index, n, data);
547  *
548  *      int low;                The base of the array to begin the sorting.
549  *      int n;                  The number of elements to sort.
550  *      DtDirPaths *data;       The data to sort.
551  *
552  ********************************/
553
554 static void
555 _DtSortFiles( 
556         int low,
557         int n,
558         DtDirPaths *data )
559 {
560    int i, j;
561    int high = low + n;  
562
563    /* 
564     * This sorting routine needs to be able to sort any portion of
565     * an array - it does not always start at element '0'.
566     */
567
568    for (i = low; i < (high - 1); i++) 
569       for (j = low; j < (high - 1); j++) 
570 #ifndef NO_MESSAGE_CATALOG
571          if ((strcoll (data->paths[j], data->paths[j+1])) > 0)
572 #else
573          if ((strcmp  (data->paths[j], data->paths[j+1])) > 0)
574 #endif
575             __swap (j, data);
576 }
577
578
579 /******************
580  *
581  * Function Name:  _DtFindMatchingFiles
582  *
583  * Description:
584  *
585  *      This function takes a string vector of directory names (which
586  *      are in "host:/path/file" format) and a filename suffix and
587  *      finds all of the files in those directories with the specified
588  *      suffix.  It returns a string vector of the filenames.
589  *
590  *      You will typically first call _DtGetDatabaseDirPaths() to get the 
591  *      'dirs' info.
592  *
593  *      Use _DtFreeDatabaseDirPaths() to free up the return structure.
594  *
595  * Synopsis:
596  *
597  *      filev = _DtFindMatchingFiles (dirs, suffix, sort_files);
598  *
599  *      DtDirPaths *filev;      A structure containing the names
600  *                              of all the files that were found.
601  *      DtDirPaths *dirs;       A structure of directories to be
602  *                              searched.
603  *      char *suffix;           The suffix string which is compared
604  *                              to the end of the filenames.  This
605  *                              string must contain a "." if it is
606  *                              part of the suffix you want to match
607  *                              on (e.g. ".c").
608  *      Boolean sort_files;     Should the files within a directory be sorted.
609  *
610  *
611  ******************/
612
613 DtDirPaths * 
614 _DtFindMatchingFiles(
615         DtDirPaths *dirs,
616         char *suffix,
617         Boolean sort_files )
618 {
619 /* LOCAL VARIABLES */
620    
621    register DtDirPaths *files;  /* An array of pointers to the filenames which 
622                                 have been found. */
623    int max_files;       /* The total number of filenames that can be 
624                            stored in the "files" array before it must
625                            be reallocd. */
626    int num_found;       /* The number of files which have been found. */
627    register DIR *dirp;          /* Variables for walking through the directory
628                                 entries. */
629    char * next_file;
630    struct dirent *dp = NULL;
631    char *file_suffix;
632    int suffixLen, nameLen;
633    int nextIndex;
634    register char * next_path;
635    int files_in_this_directory;
636    int base;
637
638    _Xreaddirparams dirEntryBuf;
639    struct dirent *result;
640
641 /* CODE */   
642    if (dirs == NULL)
643       return(NULL);
644    
645    files = (DtDirPaths *) XtMalloc((Cardinal)(sizeof(DtDirPaths)));
646    files->dirs = (char **) XtMalloc(sizeof(char *) * FILE_INCREMENT);
647    files->paths = (char **) XtMalloc(sizeof(char *) * FILE_INCREMENT);
648    max_files = FILE_INCREMENT;
649    num_found = 0;
650    nextIndex = 0;
651    
652    /* Process each one of the directories in priority order. */
653    while (dirs->paths[nextIndex] != NULL) {
654
655       next_path = dirs->paths[nextIndex];
656       dirp = opendir (next_path);
657       base = num_found;
658       
659       files_in_this_directory = 0;
660       while ((result = _XReaddir(dirp, dirEntryBuf)) != NULL) {
661
662          /* Check the name to see if it matches the suffix and is
663             a file. */
664          if (strlen (result->d_name) >= strlen(suffix)) 
665          {
666             /* Find the end of the name and compare it to the suffix. */
667             /* Get the number of chars (not bytes) in each string */
668             suffixLen = DtCharCount(suffix);
669             nameLen = DtCharCount(result->d_name);
670             file_suffix = _DtGetNthChar(result->d_name, nameLen - suffixLen);
671             if (file_suffix && (strcmp(file_suffix, suffix) == 0) && 
672                 !_DtIsDir((char *)next_path, (char *)result->d_name))
673             {
674                
675                /* The file is a match.  See if there is room in the array
676                   or whether we need to realloc.  The "-1" is to save room
677                   for the terminating NULL pointer. */
678                if (num_found == max_files - 1) {
679                   files->dirs = (char **) XtRealloc ((char *)files->dirs, 
680                      (Cardinal)(sizeof(char *) * (max_files + FILE_INCREMENT)));
681                   files->paths = (char **) XtRealloc ((char *)files->paths, 
682                      (Cardinal)(sizeof(char *) * (max_files + FILE_INCREMENT)));
683                   max_files += FILE_INCREMENT;
684                }
685                
686                /* Get some memory and copy the filename to the array. */
687                files->dirs[num_found] = next_file = (char *) 
688                    XtMalloc((Cardinal)(strlen(dirs->dirs[nextIndex]) + 
689                              strlen (result->d_name) + 2));
690                (void)strcpy(next_file, dirs->dirs[nextIndex]);
691                (void)strcat(next_file, "/");
692                (void)strcat(next_file, result->d_name);
693
694                files->paths[num_found] = next_file = (char *) 
695                    XtMalloc((Cardinal)(strlen(next_path) + 
696                              strlen (result->d_name) + 2));
697                (void)strcpy(next_file, next_path);
698                (void)strcat(next_file, "/");
699                (void)strcat(next_file, result->d_name);
700         
701                num_found++;
702                files_in_this_directory++;
703
704             }
705          }
706       }
707       closedir (dirp);
708       if (sort_files && (files_in_this_directory > 1))
709          _DtSortFiles (base, files_in_this_directory, files);
710       nextIndex++;
711    }
712    files->dirs[num_found] = NULL;
713    files->paths[num_found] = NULL;
714    return (files);
715    
716 }
717
718 /******************************************************************************
719  *
720  * _DtDbGetDataBaseEnv( )
721  * ------------------------
722  * This function provides a PRIVATE API for internal manipulation of the
723  * DTDATABASEDIRPATH environment variable before loading the databases.
724  *      -- used by the front panel code in dtwm.
725  *
726  * If the environment variable it returns a default path.
727  *
728  * NOTE: This function returns a freshly malloc'ed string.  It is up to 
729  *       the caller to free it.
730  *       
731  ******************************************************************************/
732
733 char *
734 _DtDbGetDataBaseEnv( void )
735 {
736    char *nwh_dir;
737    char *temp_buf;
738    char *temp_s;
739
740    nwh_dir = getenv ("HOME");
741    /* 
742     * Get the DTDATABASESEARCHPATH environment variable.  If it is not set,
743     * create the default value.
744     */
745    if ( temp_s = getenv ("DTDATABASESEARCHPATH"))
746       if ( *temp_s != 0 ) return XtNewString(temp_s);
747
748    temp_buf =
749      XtMalloc((2*strlen(nwh_dir)) + strlen(DTDATABASESEARCHPATH_DEFAULT) + 1);
750    sprintf (temp_buf, DTDATABASESEARCHPATH_DEFAULT, nwh_dir, nwh_dir);
751    return temp_buf;
752
753 }
754
755 /******************************
756  *
757  * Function Name:  _DtGetDatabaseDirPaths
758  *
759  * Description:
760  *
761  *      This function returns a structure containing the external
762  *      and internal forms for all of the database directories that must be 
763  *      searched for Dt database files.  
764  *      The structure is freed using _DtFreeDatabaseDirPaths().
765  *
766  *      The directories are all guaranteed to be fully-specified names;
767  *      i.e. host:/path/dir.  
768  *
769  *      THIS IS TYPICALLY CALLED BEFORE USING ANY OF THE FOLLOWING:
770  *
771  *         DtReadDatabases()
772  *         DtPrepareToolboxDirs()
773  *         _DtDbRead()
774  *         _DtFindMatchingFiles()
775  *
776  * Synoposis:
777  *
778  *      DtDirPaths * _DtGetDatabaseDirPaths ();
779  *
780  ********************************/
781
782 DtDirPaths * 
783 _DtGetDatabaseDirPaths( void )
784 {
785    XrmValue resource_value;
786    char *rep_type;
787    char *dir_string, *remote_hosts;
788    char *nwh_host;              /* Holds the host portion of the user's
789                                    network-home. */
790    char **dir_vector;           /* The list of directories are turned into
791                                    a vector of strings.  This points to the
792                                    start of the vector. */
793    char **hosts_vector;
794    char **next_dir;             /* A pointer used to walk through dir_vector. */
795    char **next_host;
796    char *dir;                   /* Points to next dir being processed */
797    int valid_dirs;              /* A count of the number of valid directories
798                                    found. */
799    char *home;
800    char *nextc;
801    DtDirPaths * ret_paths;
802    char * internal;
803    int i;
804    char *tmp_dir_string;
805
806    /* Get our host name, and the user's home directory */
807    nwh_host = _DtGetLocalHostName ();
808    tmp_dir_string = _DtDbGetDataBaseEnv();
809    dir_string = _DtExpandLang (tmp_dir_string);
810    XtFree (tmp_dir_string);
811
812    /* Prepare the input vector and the two output vectors. */
813    dir_vector = _DtVectorizeInPlace (dir_string, ',');
814    ret_paths = (DtDirPaths *)XtMalloc(sizeof(DtDirPaths));
815    ret_paths->dirs = NULL;
816    ret_paths->paths = NULL;
817    valid_dirs = 0;
818
819    for (next_dir = dir_vector; *next_dir != NULL; next_dir++) {
820
821        if (DtStrchr (*next_dir, '/') == NULL){
822            /* It must be a relative path. */
823            /* Ignore relative paths */
824            continue;
825        }
826
827        /* If the name is not a valid directory, get rid of it. */
828        if (!_DtIsOpenableDirContext (*next_dir, &internal)) {
829            continue;
830        }
831        else {
832            /* If not already in the list, add it to the structure. */
833            for (i = 0; i < valid_dirs; i++)
834            {
835               if (strcmp(ret_paths->paths[i], internal) == 0)
836               {
837                  break;
838               }
839            }
840
841            if (i == valid_dirs)
842            {
843               valid_dirs++;
844               ret_paths->dirs = (char **) XtRealloc ((char *)ret_paths->dirs, 
845                                   (Cardinal) (sizeof (char *) * valid_dirs));
846
847               /* Make sure the directory name is fully-qualified with a host
848                  component. */
849               if (DtStrchr (*next_dir, ':') != NULL)
850                  dir = XtNewString(*next_dir);
851             
852               /* If there is no host component, see if there is 
853                  an absolute path. */
854               else if (
855 #ifdef NLS16
856                    (!is_multibyte || (mblen(*next_dir, MB_LEN_MAX) == 1)) &&
857 #endif
858                    (**next_dir == '/')) {
859                  dir = XtMalloc ((Cardinal) (strlen (nwh_host) + 2 + 
860                                              strlen (*next_dir)));
861                  (void) sprintf (dir, "%s:%s", nwh_host, *next_dir);
862               }
863               else 
864                  dir = XtNewString(*next_dir);
865
866               ret_paths->dirs[valid_dirs - 1] = dir;
867               ret_paths->paths = (char **) XtRealloc ((char *)ret_paths->paths, 
868                                   (Cardinal) (sizeof (char *) * valid_dirs));
869               ret_paths->paths[valid_dirs - 1] = internal;
870            }
871            else {
872               XtFree(internal);
873            }
874        }
875    }
876
877    /* The three vectors must be NULL terminated. */
878    ret_paths->dirs = (char **) XtRealloc ((char *)ret_paths->dirs, 
879                                           (Cardinal) (sizeof (char *) * 
880                                                       (valid_dirs + 1)));
881    ret_paths->dirs[valid_dirs] = NULL;
882    ret_paths->paths = (char **) XtRealloc ((char *)ret_paths->paths, 
883                                            (Cardinal) (sizeof (char *) * 
884                                                        (valid_dirs + 1)));
885    ret_paths->paths[valid_dirs] = NULL;
886    
887    XtFree ((char *) dir_string);
888    XtFree ((char *) nwh_host);
889    XtFree ((char *) dir_vector);
890    return(ret_paths);
891 }
892
893
894 /***************************
895  * void _DtFreeDatabaseDirPaths (paths)
896  *
897  *   DtDirPaths * paths;
898  *
899  * This function will free up each of the arrays within the directory
900  * information structure, and will then free the structure itself.
901  *
902  **************************/
903
904 void 
905 _DtFreeDatabaseDirPaths(
906         DtDirPaths *paths )
907 {
908    _DtFreeDirVector(paths->dirs);
909    _DtFreeDirVector(paths->paths);
910    XtFree((char *)paths);
911 }
912