2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $TOG: FileListUtils.c /main/11 1999/10/14 13:17:49 mgreess $ */
24 /************************************<+>*************************************
25 ****************************************************************************
27 ** File: FileListUtils.c
29 ** Project: DtHelp library
31 ** Description: Locates and lists all files (volumes) accessible via the
34 ** (c) Copyright 1993, 1994 Hewlett-Packard Company
35 ** (c) Copyright 1993, 1994 International Business Machines Corp.
36 ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
37 ** (c) Copyright 1993, 1994 Novell, Inc.
40 ****************************************************************************
41 ************************************<+>*************************************/
53 #include <sys/param.h> /* MAXPATHLEN */
55 #define X_INCLUDE_DIRENT_H
56 #define XOS_USE_XT_LOCKING
57 #include <X11/Xos_r.h>
63 #include "bufioI.h" /* for AccessI.h */
66 #include "StringFuncsI.h"
67 #include "FileUtilsI.h"
68 #include "FileListUtilsI.h"
71 /******** constants *********/
72 #define LANG_C_STR "C"
75 /******** types *********/
77 /******** public global variables *********/
79 /******** variables *********/
80 static const char * PeriodStr = ".";
81 static const char * DirSlashStr = "/";
82 static const char * PathSeparator = ":";
84 /******** functions *********/
87 /*****************************************************************************
88 * Function: GetExtension()
90 * locate the '.' of the filename extension, if present
92 *****************************************************************************/
93 static char * GetExtension(
97 if (_DtHelpCeStrrchr(filename,PeriodStr,MB_CUR_MAX,&ext) == 0 ) return ext;
98 else return ""; /* do NOT return a NULL*/
103 /*****************************************************************************
104 * Function: SpecialStrcmp()
106 * Tests the args for NULL pointers. If both are NULL or if
107 * both aren't NULL and are the same string, then returns 0.
108 * If one arg is NULL and other isn't, or if strings are
109 * different, returns -1 or +1.
111 *****************************************************************************/
112 static int SpecialStrcmp(
118 if(NULL == str2) return 0; /* str1 == str2 */
119 return -1; /* str1 < str2 */
121 if(NULL == str2) return 1; /* str1 > str2 */
122 return(strcmp(str1,str2)); /* str1 ? str2 */
128 /*****************************************************************************
129 * Function: FileInfoMatchesP()
131 * Compares the info of an existing file entry with test file info
132 * and determines whether they match.
133 * Returns: True or False
135 *****************************************************************************/
136 static Boolean FileInfoMatchesP(
137 _DtHelpFileEntry file1,
138 _DtHelpFileEntry file2,
141 /* no duplicate files allowed: compare doc stamps */
142 /* note: currently am not comparing nameKey nor returning
143 a placement (-1,+1) val from the compare. */
144 if ( ( (compareFlags & _DtHELP_FILE_NAME) == 0
145 || SpecialStrcmp(file1->fileName,file2->fileName) == 0)
146 && ( (compareFlags & _DtHELP_FILE_TITLE) == 0
147 || SpecialStrcmp(file1->fileTitle,file2->fileTitle) == 0)
148 && ( (compareFlags & _DtHELP_FILE_IDSTR) == 0
149 || SpecialStrcmp(file1->docId,file2->docId) == 0)
150 && ( (compareFlags & _DtHELP_FILE_TIME) == 0
151 || SpecialStrcmp(file1->timeStamp,file2->timeStamp) == 0) )
158 /*****************************************************************************
159 * Function: _DtHelpFileIsSameP()
161 * Compares the info of two files and determines whether they match.
162 * Returns: True or False
164 *****************************************************************************/
165 Boolean _DtHelpFileIsSameP(
168 _DtHelpFileInfoProc infoProc,
170 XtPointer pDisplayArea)
172 _DtHelpFileRec file1, file2;
176 /* get filenames without path */
177 if (_DtHelpCeStrrchr(fileName1, DirSlashStr, MB_CUR_MAX, &fileName) == 0)
178 fileName1 = fileName + 1;
179 if (_DtHelpCeStrrchr(fileName2, DirSlashStr, MB_CUR_MAX, &fileName) == 0)
180 fileName2 = fileName + 1;
182 /* init the structs */
183 memset(&file1,0,sizeof(file1));
184 memset(&file2,0,sizeof(file2));
185 file1.fileName = fileName1;
186 file2.fileName = fileName2;
188 /* get info on the files */
189 (*infoProc)(pDisplayArea,fileName1,NULL,NULL,
190 &file1.docId,&file1.timeStamp,&file1.nameKey,
192 (*infoProc)(pDisplayArea,fileName2,NULL,NULL,
193 &file2.docId,&file2.timeStamp,&file2.nameKey,
196 ret = FileInfoMatchesP(&file1,&file2,compareFlags);
199 XtFree(file1.timeStamp);
201 XtFree(file2.timeStamp);
207 /*****************************************************************************
208 * Function: ScanDirForFiles
210 * scan a directory looking for files with a matching suffix
211 * returns number of files found in this directory
213 *****************************************************************************/
214 static int ScanDirForFiles(
216 const char * suffixList[],
217 _DtHelpFileList * in_out_list,
218 XmFontList * io_fontList,
221 _DtHelpFileInfoProc infoProc,
222 XtPointer pDisplayArea,
225 _DtHelpFileScanProcCB scanProc,
226 XtPointer clientData)
229 char fullName [MAXPATHLEN + 2];
232 struct dirent *result;
233 _Xreaddirparams dirEntryBuf;
235 /* open the directory */
236 pDir = opendir (dirpath);
237 if (pDir == NULL) return 0; /* RETURN */
239 /* build the pathname */
240 strcpy (fullName, dirpath);
241 strcat (fullName, DirSlashStr);
242 ptr = fullName + strlen (fullName);
245 * Scan through the files looking for matching suffixes
247 while ((result = _XReaddir(pDir, dirEntryBuf)) != NULL) {
248 const char * matchedSuffix;
251 /* Skip over any "." and ".." entries. */
252 if ((strcmp(result->d_name, ".") == 0) ||
253 (strcmp(result->d_name, "..") == 0))
256 /* get working values */
257 ext = GetExtension (result->d_name);
258 matchedSuffix = ""; /* default (==>no suffix to match) */
260 /* try to match with a suffix, if specified */
261 if (NULL != suffixList)
263 const char * * pSuffix;
264 matchedSuffix = NULL;
265 for (pSuffix = suffixList;
266 NULL != *pSuffix && NULL == matchedSuffix;
269 if (strcmp(ext,*pSuffix) == 0)
270 matchedSuffix = *pSuffix;
274 /* and a match is found */
275 if ( NULL != matchedSuffix )
279 /* then generate the full path and add to the list */
280 strcpy (ptr, result->d_name);
281 if (_DtHelpFileListAddFile(in_out_list,io_fontList,&mod,
282 fullName,ptr,infoProc,compareFlags,sortFlags,pDisplayArea))
285 if (scanProc) (*scanProc)(count + foundFilesCnt,clientData);
287 *ret_mod |= mod; /* accumulate mods */
289 } /* while more entries */
291 /* close the directory stream */
299 /******************************************************************************
300 * Function: _DtHelpFileListGetMatch ()
303 * fileListHead head of the list
304 * fullFilePath fullFilePath to file to find
305 * infoProc will deliver info on the file
306 * pDisplayArea used to interpret vol info
308 * Returns: pointer to matching _DtHelpFileList entry
309 * or NULL if none is found
311 * Purpose: Looks for a file list entry for the file
312 * identified by fullFilePath.
313 * The infoProc routine gets info about the file
314 * to be matched, and uses that when comparing
315 * with the file list. This allows more
316 * than one file with the same name to be in
317 * the list and be discriminated on the basis
320 *****************************************************************************/
321 _DtHelpFileList _DtHelpFileListGetMatch (
322 _DtHelpFileList fileListHead,
324 _DtHelpFileInfoProc infoProc,
326 XtPointer pDisplayArea)
328 _DtHelpFileList next;
331 /* zero the record */
332 memset (&file,0,sizeof(file));
334 if (NULL == fileListHead || NULL == fullFilePath) return NULL; /* RETURN */
336 /* get filename without path */
337 file.fileName = fullFilePath;
338 if (_DtHelpCeStrrchr(fullFilePath,DirSlashStr,MB_CUR_MAX,&file.fileName) == 0)
341 /* if an info proc, use it, otherwise make due */
343 (*infoProc)(pDisplayArea,fullFilePath,
344 NULL,NULL,&file.docId,&file.timeStamp,&file.nameKey,
347 file.nameKey = _DtHelpCeStrHashToKey(file.fileName);
350 while ( (next = _DtHelpFileListGetNext(fileListHead, next)) != NULL )
352 if ( FileInfoMatchesP(next,&file,compareFlags) )
353 break; /* next is the matching entry */
356 /* fileName is part of fullFilePath */
358 XtFree(file.timeStamp);
366 /******************************************************************************
367 * Function: int _DtHelpFileListGetNext ()
370 * fileListHead head of the list
371 * curFile current entry in the list
373 * Returns: pointer to next _DtHelpFileList entry
374 * or NULL if end of list has been reached
376 * Purpose: Gets the next file in the list
378 *****************************************************************************/
379 _DtHelpFileList _DtHelpFileListGetNext (
380 _DtHelpFileList fileListHead,
381 _DtHelpFileList curFile)
383 /* could do a sanity test on curFile here */
384 if ( curFile ) return curFile->next;
385 else return fileListHead;
390 /******************************************************************************
391 * Function: int _DtHelpFileFreeEntry ()
395 * Purpose: free the contents of an entry
397 *****************************************************************************/
398 void _DtHelpFileFreeEntry (
399 _DtHelpFileEntry entry)
401 if(NULL == entry) return;
402 XmStringFree(entry->fileTitleXmStr);
403 XtFree(entry->docId);
404 XtFree(entry->timeStamp);
405 XtFree(entry->fileTitle);
406 XtFree((char *) entry->fileName);
407 XtFree((char *) entry->fullFilePath);
408 XtFree((char *) entry->clientData);
409 XtFree((char *) entry);
414 /******************************************************************************
415 * Function: int _DtHelpFileListAddFile ()
419 * Returns: True if added a new entry
420 * False if entry not added because already present
421 * or an error occurred
426 * ENOMEM memory allocation error
428 * Purpose: adds a file to the file list if its not already present
430 *****************************************************************************/
431 Boolean _DtHelpFileListAddFile (
432 _DtHelpFileList * in_out_list,
433 XmFontList * io_fontList,
437 _DtHelpFileInfoProc infoProc,
440 XtPointer pDisplayArea)
442 _DtHelpFileList next;
443 _DtHelpFileList prev;
444 _DtHelpFileList newList;
445 _DtHelpFileRec addFile;
449 typedef int (*_CEStrcollProc)(const char *,const char *);
450 extern _CEStrcollProc _DtHelpCeGetStrcollProc();
451 _CEStrcollProc strcollfn = _DtHelpCeGetStrcollProc();
453 /* init the variable */
454 memset(&addFile, 0, sizeof(addFile));
456 /* if no full file path, go look for it */
457 if (NULL == fullFilePath || fullFilePath[0] == EOS)
458 return False; /* RETURN : incomplete file spec */
460 /* trace any links; _DtHelpFileTraceLinks may chg actualPath ptr */
461 actualPath = XtNewString(fullFilePath);
462 if ( _DtHelpFileTraceLinks(&actualPath) == False )
465 return False; /* RETURN: invalid file */
467 fullFilePath = actualPath;
469 /* if no filespec, get it */
470 if (NULL == fileName)
472 fileName = fullFilePath;
473 if(_DtHelpCeStrrchr(fullFilePath, DirSlashStr, MB_CUR_MAX,&fileName)==0)
476 addFile.fileName = fileName;
478 /* if an info proc, use it, otherwise make due */
481 (*infoProc)(pDisplayArea,fullFilePath,
482 &addFile.fileTitle,&addFile.fileTitleXmStr,
483 &addFile.docId,&addFile.timeStamp,&addFile.nameKey,
484 io_fontList,ret_mod);
488 nameKey = _DtHelpCeStrHashToKey(fileName);
491 /* look for prior existance and position */
493 while ( (next = _DtHelpFileListGetNext(*in_out_list, next)) != NULL )
495 if ( FileInfoMatchesP(next,&addFile,compareFlags) )
497 XtFree(addFile.docId);
498 XtFree(addFile.timeStamp);
499 XtFree(addFile.fileTitle);
500 XmStringFree(addFile.fileTitleXmStr);
501 XtFree(fullFilePath);
502 return False; /* RETURN : repeat entry */
505 /* insert lexically according to title */
506 /* use case insensitive NLS collating for ordering */
507 if ( (sortFlags & _DtHELP_FILE_TITLE)
508 && (*strcollfn) (addFile.fileTitle, next->fileTitle) <= 0 )
509 break; /* BREAK: insert after prev, before next */
511 /* FIX: add support for other sorting here */
512 /* if ( (sortFlags & _DtHELP_FILE_DIR) */
513 /* if ( (sortFlags & _DtHELP_FILE_TIME) */
514 /* if ( (sortFlags & _DtHELP_FILE_IDSTR) */
515 /* if ( (sortFlags & _DtHELP_FILE_LOCALE) */
517 prev = next; /* save ref to prior entry */
519 /* if dup not found, fall thru, with prev valid */
521 /* no matching path, so create, initialize, and append to list */
522 newList = (_DtHelpFileList) XtCalloc(1, sizeof(_DtHelpFileRec));
525 XtFree(addFile.docId);
526 XtFree(addFile.timeStamp);
527 XtFree(addFile.fileTitle);
528 XmStringFree(addFile.fileTitleXmStr);
529 XtFree(fullFilePath);
530 return False; /* RETURN : error */
533 /* init the contents */
534 newList->fullFilePath = fullFilePath; /* copy made earlier */
535 newList->fileName = XtNewString(addFile.fileName);
536 newList->nameKey = addFile.nameKey;
537 newList->docId = (addFile.docId == &empty ? NULL : addFile.docId);
538 newList->timeStamp = (addFile.timeStamp == &empty ? NULL : addFile.timeStamp);
539 newList->fileTitle = addFile.fileTitle;
540 newList->fileTitleXmStr = addFile.fileTitleXmStr;
541 if (next) newList->next = next;
542 if (prev) prev->next = newList;
543 else *in_out_list = newList;
545 return True; /* created new entry */
550 /******************************************************************************
551 * Function: int _DtHelpFileListScanPaths ()
554 * type: subdirectories to search (%T)
555 * suffix: extension of the files to find (%S)
556 * searchHomeDir: boolean flag
557 * in_out_list: manages list of files generated
559 * Returns: count of files added to the list or -1
564 * Purpose: Scans all paths of given type looking for files with the suffixes
566 *****************************************************************************/
567 int _DtHelpFileListScanPaths (
568 _DtHelpFileList * in_out_list,
569 XmFontList * io_fontList,
572 const char * suffixList[],
573 Boolean searchHomeDir,
574 _DtHelpFileInfoProc infoProc,
575 XtPointer pDisplayArea,
576 int sysPathCompareFlags,
577 int otherPathCompareFlags,
579 _DtHelpFileScanProcCB scanProc,
580 XtPointer clientData)
590 char * paths[_DtHELP_FILE_NUM_PATHS];
591 char ** scannedPaths = NULL;
592 int scannedPathsCnt = 0;
594 /* get the search paths */
595 _DtHelpFileGetSearchPaths( paths, searchHomeDir );
598 loc = _DtHelpGetLocale();
599 if (NULL == loc || EOS == loc[0]) loc = strdup(LANG_C_STR);
602 if (scanProc) (*scanProc)(0,clientData);
604 /* outer loop is once for each path */
606 for ( curPathIndex = 0;
607 curPathIndex < _DtHELP_FILE_NUM_PATHS;
610 curPath = paths[curPathIndex];
611 if (NULL == curPath) continue;
613 /* set the comparison flags */
614 /* This enables implementation of different policies for
615 listing files that are found, e.g. only list the first file
616 of a given name found in the SYS search path, while listing
617 same named files that have different times & ids in the
619 compareFlags = sysPathCompareFlags;
620 if (_DtHELP_FILE_SYS_PATH != curPathIndex)
621 compareFlags = otherPathCompareFlags;
623 /* find the files in that path */
627 /* look for next subpath separator and insert and EOS if found */
628 if (_DtHelpCeStrchr(curPath,PathSeparator,MB_CUR_MAX,&ptr)==0)
631 /* generate the (directory) path using all the variables
632 and fix it up to remove the unwanted stuff involving the filename*/
633 pathName = _DtHelpCeExpandPathname(curPath,
634 NULL, type, NULL, loc, NULL, 0);
636 && _DtHelpCeStrrchr(pathName,DirSlashStr,MB_CUR_MAX,&slashptr) == 0)
639 /* restore the subpath separator and advance past it */
640 if (ptr) *ptr++ = *PathSeparator;
642 /* if its a directory; scan for matching files in it */
643 if ( pathName != NULL
645 && access (pathName, R_OK | X_OK) == 0
646 && stat (pathName, &status) == 0
647 && S_ISDIR(status.st_mode)) /* a dir */
650 /* check that we haven't already scanned it */
651 for ( i=0; i<scannedPathsCnt; i++ )
652 if (strcmp(scannedPaths[i],pathName) == 0) break;
654 /* scan it if haven't already */
655 if ( i == scannedPathsCnt )
657 foundFilesCnt += ScanDirForFiles(
659 in_out_list,io_fontList,ret_mod,
660 foundFilesCnt,infoProc,pDisplayArea,
661 compareFlags,sortFlags,scanProc,clientData);
663 /* add to list of scanned */
664 scannedPaths = (char **) XtRealloc((char *)scannedPaths,
665 (scannedPathsCnt+1) * sizeof(char *) );
666 scannedPaths[scannedPathsCnt++] = strdup(pathName);
667 } /* if haven' scanned already */
668 } /* if a directory */
672 printf("Unknown dir: %s\n", pathName);
673 printf("Access: %d, stat: %d, IS_DIR: %d, mode: %x\n",
674 access (pathName, R_OK | X_OK),
675 stat (pathName, &status),
676 S_ISDIR(status.st_mode),
681 if (pathName) free (pathName);
683 } while (curPath && *curPath); /* while more subpaths */
684 } /* for all paths */
686 /* free all scanned paths */
687 while ( scannedPathsCnt-- > 0 ) XtFree(scannedPaths[scannedPathsCnt]);
688 XtFree((char *)scannedPaths);
691 return foundFilesCnt;