/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* * $TOG: DbUtil.c /main/13 1998/04/09 17:47:56 mgreess $ * * (c) Copyright 1988, 1989, 1990, 1991, 1992, 1993 * by Hewlett-Packard Company, all rights reserved. * * (c) Copyright 1993, 1994 Hewlett-Packard Company * * (c) Copyright 1993, 1994 International Business Machines Corp. * * (c) Copyright 1993, 1994 Sun Microsystems, Inc. * * (c) Copyright 1993, 1994 Novell, Inc. * */ #include #include #include #include #include #include #ifdef NLS16 #include #endif #include #include /* MAXPATHLEN, MAXHOSTNAMELEN */ #include #include #include #define X_INCLUDE_DIRENT_H #define XOS_USE_XT_LOCKING #include #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef S_ISLNK /* This macro is normally defined in stat.h, but not on USL systems. */ # define S_ISLNK(_M) ((_M & S_IFMT)==S_IFLNK) /* test for symbolic link */ #endif #ifndef CDE_INSTALLATION_TOP #define CDE_INSTALLATION_TOP "/opt/dt" #endif #ifndef CDE_CONFIGURATION_TOP #define CDE_CONFIGURATION_TOP "/etc/opt/dt" #endif #define TRUE 1 #define FALSE 0 #define FILE_INCREMENT 20 /* The following string holds the default value of the Dt database * search path. This default search path has the following major * components: * * $HOME/.dt/types[/%L] A location for the user's personal * actions and filetypes. * * /appconfig/types[/%L] * The DT location for system-wide * customizations. * * /types/[%L] The DT location for default * system-wide actions and filetypes. */ static char DTDATABASESEARCHPATH_DEFAULT[] = "%s/.dt/types/%%L," "%s/.dt/types," CDE_CONFIGURATION_TOP "/appconfig/types/%%L," CDE_CONFIGURATION_TOP "/appconfig/types," CDE_INSTALLATION_TOP "/appconfig/types/%%L," CDE_INSTALLATION_TOP "/appconfig/types"; /**** Substitution records used by XtFindFile() in _DtExpandLang() ****/ static SubstitutionRec langSubstitutions[] = { {'L', (char *)NULL}, {'l', (char *)NULL}, {'t', (char *)NULL}, {'c', (char *)NULL} }; static int nLangSubstitutions = XtNumber(langSubstitutions); /******** Static Function Declarations ********/ static Boolean __testPath( String str ); static void __setupLangSubstitutions( void ); static void __freeLangSubstitutions( void ); static char *_DtExpandLang( char *string ) ; static char _DtIsDir( char *path, char *name) ; static void _DtFreeDirVector( char **dir_vector) ; static void __swap( int i , DtDirPaths *data ); static void _DtSortFiles( int low, int n, DtDirPaths *data) ; /******** End Static Function Declarations ********/ /****************** * * Function Name: __testPath * * Description: * * This function is needed by XtFindFile(). Always returns True. * * Synopsis: * * path = XtFindFile(..., __testPath); * ******************/ static Boolean __testPath(String str) { return True; } /****************** * * Function Name: __setupLangSubstitutions * * Description: * * This function initializes langSubstitutions[] for use by * XtFindFile(). * * Synopsis: * * __setupLangSubstitutions(); * ******************/ static void __setupLangSubstitutions(void) { char *lang; char *languagePart; char *territoryPart; char *codesetPart; char *tlPtr, *ttPtr, *tcPtr, *endPtr; /* * We should really be calling setlocale to determine the "default" * locale but setlocale's return value is not standardized across * the various vendor platforms nor is it consistent within differnt * revs of individual OS's. (e.g. its changing between HP-UX 9.0 and * HP-UX 10.0). The "right" call would be the following line: * * if ((lang = getenv ("LANG")) || (lang = setlocale(LC_C_TYPE,NULL))) * * Here we hard code the default to "C" instead of leaving it NULL. */ languagePart = territoryPart = codesetPart = (char *)NULL; if ((lang = getenv ("LANG")) == (char *)NULL) lang = "C"; lang = XtNewString(lang); /* free'd in __freeLangSubstitutions() */ tlPtr = lang; endPtr = (char *)NULL; if ((ttPtr = DtStrchr(tlPtr, '_')) != (char *)NULL) ttPtr++; if ((tcPtr = DtStrchr(ttPtr ? ttPtr : tlPtr, '.')) != (char *)NULL) { endPtr = tcPtr++; if (*tcPtr != '\0') codesetPart = XtNewString(tcPtr); /* free'd in __freeLangSubstitutions() */ } if (ttPtr) { if (endPtr) { int ttLen = endPtr - ttPtr; if (ttLen > 0) { /* free'd in __freeLangSubstitutions() */ territoryPart = (char *)XtMalloc((ttLen + 1) * sizeof(char)); strncpy(territoryPart, ttPtr, ttLen); territoryPart[ttLen] = '\0'; } } else territoryPart = XtNewString(ttPtr); /* free'd in __freeLangSubstitutions() */ endPtr = ttPtr - 1; } if (endPtr) { int tlLen = endPtr - tlPtr; if (tlLen > 0) { /* free'd in __freeLangSubstitutions() */ languagePart = (char *)XtMalloc((tlLen + 1) * sizeof(char)); strncpy(languagePart, tlPtr, tlLen); languagePart[tlLen] = '\0'; } } else languagePart = XtNewString(tlPtr); /* free'd in __freeLangSubstitutions() */ langSubstitutions[0].substitution = lang; langSubstitutions[1].substitution = languagePart; langSubstitutions[2].substitution = territoryPart; langSubstitutions[3].substitution = codesetPart; } /****************** * * Function Name: __freeLangSubstitutions * * Description: * * This function free's the strings allocated by * __setupLangSubstitutions and placed into langSubstitutions[] * * Synopsis: * * __freeLangSubstitutions(); * ******************/ static void __freeLangSubstitutions(void) { int i; for (i = 0; i < nLangSubstitutions; i++) XtFree(langSubstitutions[i].substitution); } /****************** * * Function Name: _DtExpandLang * * Description: * * This function takes the string "string", and performs the following * replacements: * %L : contents of LANG environment variable. * %l : language part of the LANG environment variable. * %t : territory part of the LANG environment variable. * %c : codeset part of the LANG environment variable. * %% : % (e.g. %%L would be replaced by %L, and * no substitution would be performed on %L) * * If $LANG is not defined, the $LANG is assumed to be "C". * * Synopsis: * * ret_string = _DtExpandLang (string); * * char *ret_string; Returns NULL if "string" is NULL, or it points * to the expanded string. * * char *string; The comma-separated pathnames to expand. * * Note: The caller is responsible for free'ing the returned string. * ******************/ static char * _DtExpandLang( char *string ) { char *thisPath; char *newPath; char *modPath; int pathLen, maxPathLen; int nColons; char *tmpPtr, *tmpPtr1; char *newString; char *tokPtr; if (string == NULL) return (NULL); /* * We're going to use XtFindFile() to perform the replacements; * the colon character ':' is used as a delimiter in XtFindFile, * so we escape all colon characters in our string before * passing it along. */ for (nColons = 0, tmpPtr = string; (tmpPtr = DtStrchr(tmpPtr, ':')) != (char *)NULL; nColons++, tmpPtr++) /* EMPTY */ ; newString = (char *)XtCalloc(1, (strlen(string) + nColons + 1) * sizeof(char)); for (tmpPtr = string; (tmpPtr1 = DtStrchr(tmpPtr, ':')) != (char *)NULL; tmpPtr = tmpPtr1 + 1) { strncat(newString, tmpPtr, tmpPtr1 - tmpPtr); strcat(newString, "%:"); } strcat(newString, tmpPtr); __setupLangSubstitutions(); /* * XtFindFile() assumes that the string into which it's making * substitutions is a path, and therefore it assumes that the * length of the string does not exceed MAXPATHLEN. Since * our string is a series of paths, it CAN exceed MAXPATHLEN. * So, we split our string into individual paths which we then * pass off to XtFindFile(). */ pathLen = maxPathLen = 0; newPath = (char *)NULL; for (thisPath = DtStrtok_r(newString, ",", &tokPtr); thisPath != (char *)NULL; thisPath = DtStrtok_r((char *)NULL, ",", &tokPtr)) { modPath = XtFindFile(thisPath, langSubstitutions, nLangSubstitutions, __testPath); if (modPath) { char *origPath = modPath; int modLen; /* * For some reason, XtFindFile() collapses all '/' * characters EXCEPT at the beginning of the path! * For backwards compatibility, we collapse those here. */ if (*modPath == '/') { while (*(modPath + 1) == '/') modPath++; } modLen = strlen(modPath); if (pathLen + modLen + 2 > maxPathLen) { maxPathLen = ((pathLen + modLen + 2 + MAXPATHLEN) / MAXPATHLEN) * MAXPATHLEN; newPath = (char *)XtRealloc(newPath, maxPathLen * sizeof(char)); } if (pathLen > 0) newPath[pathLen++] = ','; strcpy(&(newPath[pathLen]), modPath); pathLen += modLen; XtFree(origPath); } } __freeLangSubstitutions(); XtFree(newString); return newPath; } /****************** * * Function Name: _DtIsDir * * Description: * * This function tests a pathname to see if it is a directory. * The path name is received in two pieces, which makes it easy * for the calling function to test a bunch of files in a directory * to see if any are subdirectories. * * This function does NOT handle Softbench-style pathnames with * embedded hostnames. * * Synopsis: * * dir = _DtIsDir (path, name); * * char dir; Returns 0 if the item is not a directory, * 1 if it is. * char *path; The first part of the pathname. Typically * the directory containing the item of interest. * char *name; The second half of the pathname. Typically * the name of the item of interest. * ******************/ static char _DtIsDir( char *path, char *name ) { struct stat stat_buf; char *stat_name; stat_name = XtMalloc ((Cardinal)(strlen(path) + strlen(name) + 2)); (void)strcpy (stat_name, path); (void)strcat (stat_name, "/"); (void)strcat (stat_name, name); if(stat (stat_name, &stat_buf)) { stat_buf.st_mode = 0; } XtFree (stat_name); if (stat_buf.st_mode & S_IFDIR) return (TRUE); else return (FALSE); } /****************************** * * Function Name: _DtFreeDirVector * * Description: * * This function frees a database-directory string vector. * * Synoposis: * * FreeDatabaseDirs (dirs); * * char **dirs; The string vector to free. * ********************************/ static void _DtFreeDirVector( char **dir_vector ) { char **v; if (dir_vector) { for (v = dir_vector; *v != NULL; v++) XtFree ((char *)*v); XtFree ((char *)dir_vector); } } /****************************** * * Function Name: __swap * * Description: * * This function exchanges two elements in an array of DtDirPaths. * * Synoposis: * * __swap (i, data); * * int i; The base index to change. * DtDirPaths *data; The data to change. * ********************************/ static void __swap( int i , DtDirPaths *data ) { char *tmp; /* The "names" field of the structure is not touched because * this field is "NULL" for all of the entries. */ tmp = data->dirs[i]; data->dirs[i] = data->dirs[i+1]; data->dirs[i+1] = tmp; tmp = data->paths[i]; data->paths[i] = data->paths[i+1]; data->paths[i+1] = tmp; } /****************************** * * Function Name: _DtSortFiles * * Description: * * Given an index, an array of "char" data and the number of elements to * sort, this function sorts the data. The sorting algorithm is based * on a bubble sort because the number of elements is usually less than * ten. * * Synoposis: * * _DtSortFiles (index, n, data); * * int low; The base of the array to begin the sorting. * int n; The number of elements to sort. * DtDirPaths *data; The data to sort. * ********************************/ static void _DtSortFiles( int low, int n, DtDirPaths *data ) { int i, j; int high = low + n; /* * This sorting routine needs to be able to sort any portion of * an array - it does not always start at element '0'. */ for (i = low; i < (high - 1); i++) for (j = low; j < (high - 1); j++) #ifndef NO_MESSAGE_CATALOG if ((strcoll (data->paths[j], data->paths[j+1])) > 0) #else if ((strcmp (data->paths[j], data->paths[j+1])) > 0) #endif __swap (j, data); } /****************** * * Function Name: _DtFindMatchingFiles * * Description: * * This function takes a string vector of directory names (which * are in "host:/path/file" format) and a filename suffix and * finds all of the files in those directories with the specified * suffix. It returns a string vector of the filenames. * * You will typically first call _DtGetDatabaseDirPaths() to get the * 'dirs' info. * * Use _DtFreeDatabaseDirPaths() to free up the return structure. * * Synopsis: * * filev = _DtFindMatchingFiles (dirs, suffix, sort_files); * * DtDirPaths *filev; A structure containing the names * of all the files that were found. * DtDirPaths *dirs; A structure of directories to be * searched. * char *suffix; The suffix string which is compared * to the end of the filenames. This * string must contain a "." if it is * part of the suffix you want to match * on (e.g. ".c"). * Boolean sort_files; Should the files within a directory be sorted. * * ******************/ DtDirPaths * _DtFindMatchingFiles( DtDirPaths *dirs, char *suffix, Boolean sort_files ) { /* LOCAL VARIABLES */ register DtDirPaths *files; /* An array of pointers to the filenames which have been found. */ int max_files; /* The total number of filenames that can be stored in the "files" array before it must be reallocd. */ int num_found; /* The number of files which have been found. */ register DIR *dirp; /* Variables for walking through the directory entries. */ char * next_file; struct dirent *dp = NULL; char *file_suffix; int suffixLen, nameLen; int nextIndex; register char * next_path; int files_in_this_directory; int base; _Xreaddirparams dirEntryBuf; struct dirent *result; /* CODE */ if (dirs == NULL) return(NULL); files = (DtDirPaths *) XtMalloc((Cardinal)(sizeof(DtDirPaths))); files->dirs = (char **) XtMalloc(sizeof(char *) * FILE_INCREMENT); files->paths = (char **) XtMalloc(sizeof(char *) * FILE_INCREMENT); max_files = FILE_INCREMENT; num_found = 0; nextIndex = 0; /* Process each one of the directories in priority order. */ while (dirs->paths[nextIndex] != NULL) { next_path = dirs->paths[nextIndex]; dirp = opendir (next_path); base = num_found; files_in_this_directory = 0; while ((result = _XReaddir(dirp, dirEntryBuf)) != NULL) { /* Check the name to see if it matches the suffix and is a file. */ if (strlen (result->d_name) >= strlen(suffix)) { /* Find the end of the name and compare it to the suffix. */ /* Get the number of chars (not bytes) in each string */ suffixLen = DtCharCount(suffix); nameLen = DtCharCount(result->d_name); file_suffix = _DtGetNthChar(result->d_name, nameLen - suffixLen); if (file_suffix && (strcmp(file_suffix, suffix) == 0) && !_DtIsDir((char *)next_path, (char *)result->d_name)) { /* The file is a match. See if there is room in the array or whether we need to realloc. The "-1" is to save room for the terminating NULL pointer. */ if (num_found == max_files - 1) { files->dirs = (char **) XtRealloc ((char *)files->dirs, (Cardinal)(sizeof(char *) * (max_files + FILE_INCREMENT))); files->paths = (char **) XtRealloc ((char *)files->paths, (Cardinal)(sizeof(char *) * (max_files + FILE_INCREMENT))); max_files += FILE_INCREMENT; } /* Get some memory and copy the filename to the array. */ files->dirs[num_found] = next_file = (char *) XtMalloc((Cardinal)(strlen(dirs->dirs[nextIndex]) + strlen (result->d_name) + 2)); (void)strcpy(next_file, dirs->dirs[nextIndex]); (void)strcat(next_file, "/"); (void)strcat(next_file, result->d_name); files->paths[num_found] = next_file = (char *) XtMalloc((Cardinal)(strlen(next_path) + strlen (result->d_name) + 2)); (void)strcpy(next_file, next_path); (void)strcat(next_file, "/"); (void)strcat(next_file, result->d_name); num_found++; files_in_this_directory++; } } } closedir (dirp); if (sort_files && (files_in_this_directory > 1)) _DtSortFiles (base, files_in_this_directory, files); nextIndex++; } files->dirs[num_found] = NULL; files->paths[num_found] = NULL; return (files); } /****************************************************************************** * * _DtDbGetDataBaseEnv( ) * ------------------------ * This function provides a PRIVATE API for internal manipulation of the * DTDATABASEDIRPATH environment variable before loading the databases. * -- used by the front panel code in dtwm. * * If the environment variable it returns a default path. * * NOTE: This function returns a freshly malloc'ed string. It is up to * the caller to free it. * ******************************************************************************/ char * _DtDbGetDataBaseEnv( void ) { char *nwh_dir; char *temp_buf; char *temp_s; nwh_dir = getenv ("HOME"); /* * Get the DTDATABASESEARCHPATH environment variable. If it is not set, * create the default value. */ if ( temp_s = getenv ("DTDATABASESEARCHPATH")) if ( *temp_s != 0 ) return XtNewString(temp_s); temp_buf = XtMalloc((2*strlen(nwh_dir)) + strlen(DTDATABASESEARCHPATH_DEFAULT) + 1); sprintf (temp_buf, DTDATABASESEARCHPATH_DEFAULT, nwh_dir, nwh_dir); return temp_buf; } /****************************** * * Function Name: _DtGetDatabaseDirPaths * * Description: * * This function returns a structure containing the external * and internal forms for all of the database directories that must be * searched for Dt database files. * The structure is freed using _DtFreeDatabaseDirPaths(). * * The directories are all guaranteed to be fully-specified names; * i.e. host:/path/dir. * * THIS IS TYPICALLY CALLED BEFORE USING ANY OF THE FOLLOWING: * * DtReadDatabases() * DtPrepareToolboxDirs() * _DtDbRead() * _DtFindMatchingFiles() * * Synoposis: * * DtDirPaths * _DtGetDatabaseDirPaths (); * ********************************/ DtDirPaths * _DtGetDatabaseDirPaths( void ) { XrmValue resource_value; char *rep_type; char *dir_string, *remote_hosts; char *nwh_host; /* Holds the host portion of the user's network-home. */ char **dir_vector; /* The list of directories are turned into a vector of strings. This points to the start of the vector. */ char **hosts_vector; char **next_dir; /* A pointer used to walk through dir_vector. */ char **next_host; char *dir; /* Points to next dir being processed */ int valid_dirs; /* A count of the number of valid directories found. */ char *home; char *nextc; DtDirPaths * ret_paths; char * internal; int i; char *tmp_dir_string; /* Get our host name, and the user's home directory */ nwh_host = _DtGetLocalHostName (); tmp_dir_string = _DtDbGetDataBaseEnv(); dir_string = _DtExpandLang (tmp_dir_string); XtFree (tmp_dir_string); /* Prepare the input vector and the two output vectors. */ dir_vector = _DtVectorizeInPlace (dir_string, ','); ret_paths = (DtDirPaths *)XtMalloc(sizeof(DtDirPaths)); ret_paths->dirs = NULL; ret_paths->paths = NULL; valid_dirs = 0; for (next_dir = dir_vector; *next_dir != NULL; next_dir++) { if (DtStrchr (*next_dir, '/') == NULL){ /* It must be a relative path. */ /* Ignore relative paths */ continue; } /* If the name is not a valid directory, get rid of it. */ if (!_DtIsOpenableDirContext (*next_dir, &internal)) { continue; } else { /* If not already in the list, add it to the structure. */ for (i = 0; i < valid_dirs; i++) { if (strcmp(ret_paths->paths[i], internal) == 0) { break; } } if (i == valid_dirs) { valid_dirs++; ret_paths->dirs = (char **) XtRealloc ((char *)ret_paths->dirs, (Cardinal) (sizeof (char *) * valid_dirs)); /* Make sure the directory name is fully-qualified with a host component. */ if (DtStrchr (*next_dir, ':') != NULL) dir = XtNewString(*next_dir); /* If there is no host component, see if there is an absolute path. */ else if ( #ifdef NLS16 (!is_multibyte || (mblen(*next_dir, MB_LEN_MAX) == 1)) && #endif (**next_dir == '/')) { dir = XtMalloc ((Cardinal) (strlen (nwh_host) + 2 + strlen (*next_dir))); (void) sprintf (dir, "%s:%s", nwh_host, *next_dir); } else dir = XtNewString(*next_dir); ret_paths->dirs[valid_dirs - 1] = dir; ret_paths->paths = (char **) XtRealloc ((char *)ret_paths->paths, (Cardinal) (sizeof (char *) * valid_dirs)); ret_paths->paths[valid_dirs - 1] = internal; } else { XtFree(internal); } } } /* The three vectors must be NULL terminated. */ ret_paths->dirs = (char **) XtRealloc ((char *)ret_paths->dirs, (Cardinal) (sizeof (char *) * (valid_dirs + 1))); ret_paths->dirs[valid_dirs] = NULL; ret_paths->paths = (char **) XtRealloc ((char *)ret_paths->paths, (Cardinal) (sizeof (char *) * (valid_dirs + 1))); ret_paths->paths[valid_dirs] = NULL; XtFree ((char *) dir_string); XtFree ((char *) nwh_host); XtFree ((char *) dir_vector); return(ret_paths); } /*************************** * void _DtFreeDatabaseDirPaths (paths) * * DtDirPaths * paths; * * This function will free up each of the arrays within the directory * information structure, and will then free the structure itself. * **************************/ void _DtFreeDatabaseDirPaths( DtDirPaths *paths ) { _DtFreeDirVector(paths->dirs); _DtFreeDirVector(paths->paths); XtFree((char *)paths); }