1 /* $TOG: IconFile.c /main/13 1997/07/18 17:14:37 samborn $ */
2 /*
3 * Motif
4 *
5 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
6 *
7 * These libraries and programs are free software; you can
8 * redistribute them and/or modify them under the terms of the GNU
9 * Lesser General Public License as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * These libraries and programs are distributed in the hope that
14 * they will be useful, but WITHOUT ANY WARRANTY; without even the
15 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 * PURPOSE. See the GNU Lesser General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with these librararies and programs; if not, write
21 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
22 * Floor, Boston, MA 02110-1301 USA
23 *
24 */
25 /*
26 * HISTORY
27 */
28 /* This module references:
29 XmeGetHomeDirName, _XmOSFindPathParts, _XmOSAbsolutePathName (new in Xmos)
30 _XmOSInitPath (new version that uses absolutepath)
31 _XmInImageCache (in ImageCache)
32 XmeGetIconControlInfo (in ColorObj)
33 _XmHash API
34 and it exports:
35 XmeFlushIconFileCache (used by CDE)
36 XmGetIconFileName (used by ImageCache)
37 It is still Dt centric for the PATH variables and the local variables.
38 */
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43
44
45 #include <stdio.h>
46 #include <X11/Xlocale.h>
47
48 #define X_INCLUDE_DIRENT_H
49 #define XOS_USE_XT_LOCKING
50
51 #ifndef NEED_XOS_R_H
52 #include <X11/Xos_r.h> /* Must precede XmI.h to avoid possible redefinitions
53 of MIN() and MAX(). Xos_r.h includes Xos.h */
54 #else
55 #include <Xm/Xmos_r.h>
56 #endif
57
58 #include "XmosI.h"
59
60 #include <Xm/IconFileP.h>
61 #include <Xm/ColorObjP.h>
62 #include "XmI.h"
63 #include "HashI.h"
64
65 #include "ImageCachI.h"
66
67 #define FIX_1427
68
69 /**************** vendor dependant defaults ********/
70 /* All this stuff (cached dir) should be moved and possibly merged
71 in Xmos.c, where it belongs */
72
73
74 #ifndef X_NOT_STDC_ENV
75 #include <stdlib.h>
76 #include <unistd.h>
77 #endif
78
79 #include <sys/types.h>
80
81 #include <fcntl.h>
82 #include <sys/stat.h>
83
84
85 #ifdef USE_GETWD
86 #include <sys/param.h>
87 #define MAX_DIR_PATH_LEN MAXPATHLEN
88 #define getcwd(buf, len) ((char *) getwd(buf))
89 #else
90 #define MAX_DIR_PATH_LEN 1024
91 #endif
92 #define MAX_USER_NAME_LEN 256
93
94 #ifndef S_ISDIR
95 #define S_ISDIR(m) ((m & S_IFMT)==S_IFDIR)
96 #endif
97
98 /**************** end of vendor dependant defaults ********/
99
100
101
102
103 /**************** Icon PATH defines ********/
104
105
106 static XmConst char ABSOLUTE_IPATH[] = "%H%B";
107 static XmConst char ABSOLUTE_PATH[] = "\
108 %P\
109 %S";
110
111
112 /******------------------------------------------********/
113
114 typedef union _DtCachedDirStruct *DtCachedDir;
115
116 typedef struct _DtCommonCachedDirStruct{
117 int cachedDirType;
118 int dirNameLen;
119 String dirName;
120 }DtCommonCachedDirStruct, *DtCommonCachedDir;
121
122 typedef struct _DtValidCachedDirStruct{
123 int cachedDirType;
124 int dirNameLen;
125 String dirName;
126 int numFiles;
127 /*
128 * we allocate both the offsets array and the names themselves in
129 * a heap hanging off the end of this struct
130 */
131 unsigned short nameOffsets[1];
132 /*
133 String names
134 */
135 }DtValidCachedDirStruct, *DtValidCachedDir;
136
137 #define DtVALID_CACHED_DIR 0
138 #define DtINVALID_CACHED_DIR 1
139 #define DtUNCACHED_DIR 2
140
141 #define MAX_CACHE_DIR_SIZE (1L << 16)
142
143 typedef union _DtCachedDirStruct{
144 DtCommonCachedDirStruct common;
145 DtValidCachedDirStruct valid_dir;
146 }DtCachedDirStruct;
147
148 typedef struct _DtCachedDirListStruct{
149 int numDirs;
150 int maxDirs;
151 DtCachedDir *dirs;
152 }DtCachedDirListStruct;
153
154
155 /******** Static Function Declarations ********/
156
157 static DtCachedDir MakeCachedDirEntry(
158 String dirName) ;
159 static int CheckDirCache(
160 String path);
161 static Boolean TestIconFile(
162 String path) ;
163 static Boolean CompareIconNames (XmHashKey key_1, XmHashKey key_2);
164 static XmHashValue HashIconName (XmHashKey key);
165
166 /******** End Static Function Declarations ********/
167
168
169
170
171
172
173 static DtCachedDir
MakeCachedDirEntry(String dirName)174 MakeCachedDirEntry(String dirName)
175 {
176 DIR * fileDesc = NULL;
177 struct dirent *currDirect;
178 DtCachedDir cachedDir = NULL;
179 int cachedDirType;
180
181 if ((fileDesc = opendir (dirName)) == NULL) {
182 /* invalid directory */
183 cachedDirType = DtINVALID_CACHED_DIR;
184 }
185 else {
186 int bufLen, oldBufLen = 0;
187 char stackBuf[MAX_CACHE_DIR_SIZE];
188 char *p;
189 int numFiles = 0;
190 int nameHeapSize = 0;
191 _Xreaddirparams dirEntryBuf;
192
193 /*
194 * Original code was caching each struct direct in stackBuf.
195 * Instead, just cache currDirect->d_name, null-terminated.
196 */
197 cachedDirType = DtVALID_CACHED_DIR;
198 while ((currDirect = _XReaddir(fileDesc, dirEntryBuf)) != NULL) {
199 bufLen = strlen(currDirect->d_name);
200 if (bufLen + oldBufLen + 1 >= MAX_CACHE_DIR_SIZE) {
201 /*
202 * don't cache this one
203 */
204 cachedDirType = DtUNCACHED_DIR;
205 break;
206 } else {
207 (void) memcpy(&(stackBuf[oldBufLen]), currDirect->d_name, bufLen);
208 oldBufLen += bufLen;
209 stackBuf[oldBufLen++] = '\0';
210 }
211 }
212 if (oldBufLen == 0) {
213 /* invalid entry */
214 cachedDirType = DtINVALID_CACHED_DIR;
215 }
216
217 if( cachedDirType == DtVALID_CACHED_DIR)
218 {
219 DtValidCachedDir validDir;
220 String nameHeap;
221 Cardinal i;
222
223 /*
224 * Go through stackBuf and count the length of all
225 * the names. Don't count the nulls.
226 */
227 for (p = stackBuf ; p - stackBuf < oldBufLen;
228 p = p + strlen(p) + 1) {
229
230 numFiles++;
231 nameHeapSize += strlen(p);
232 }
233 /*
234 * we allocate an extra nameOffset to track the length of
235 * the last name
236 */
237 validDir = (DtValidCachedDir)
238 XtMalloc((sizeof(DtValidCachedDirStruct)) +
239 (sizeof(validDir->nameOffsets[0]) * numFiles) +
240 (nameHeapSize));
241
242 validDir->dirNameLen = strlen(dirName);
243 validDir->dirName = dirName;
244 validDir->numFiles = numFiles;
245 cachedDirType =
246 validDir->cachedDirType =
247 DtVALID_CACHED_DIR;
248 validDir->nameOffsets[0] = 0;
249 nameHeap = (String)
250 &(validDir->nameOffsets[numFiles + 1]);
251
252 /* Copy the strings from stackBuf to nameHeap. Omit the nulls. */
253 for (i = 0, p = stackBuf; i < validDir->numFiles;
254 i++, p = p + strlen(p) + 1) {
255
256 validDir->nameOffsets[i + 1] =
257 validDir->nameOffsets[i] + strlen(p);
258 memcpy(&(nameHeap[validDir->nameOffsets[i]]), p, strlen(p));
259 }
260 cachedDir = (DtCachedDir)validDir ;
261 }
262 }
263 switch (cachedDirType) {
264 case DtINVALID_CACHED_DIR:
265 case DtUNCACHED_DIR:
266 cachedDir = (DtCachedDir)
267 XtMalloc(sizeof(DtCommonCachedDirStruct));
268 cachedDir->common.cachedDirType =
269 cachedDirType;
270 cachedDir->common.dirNameLen = strlen(dirName);
271 cachedDir->common.dirName = dirName;
272 break;
273 case DtVALID_CACHED_DIR:
274 break;
275 }
276 if (fileDesc != NULL)
277 closedir(fileDesc);
278 return cachedDir;
279 }
280
281 static DtCachedDirListStruct cacheList;
282
283
284
285 void
XmeFlushIconFileCache(String path)286 XmeFlushIconFileCache(String path)
287 {
288 Cardinal dirNameLen;
289 Cardinal i;
290
291 _XmProcessLock();
292
293 /*
294 * loop thru the dir list. if no path was specified then flush the
295 * entire cache.
296 */
297 if (path)
298 dirNameLen = strlen(path);
299 else
300 dirNameLen = 0;
301 for (i = 0; i < cacheList.numDirs; i++) {
302 DtValidCachedDir currDir;
303
304 currDir = (DtValidCachedDir)cacheList.dirs[i];
305 if (!path ||
306 ((currDir->dirNameLen == dirNameLen) &&
307 (strncmp(currDir->dirName, path, dirNameLen) == 0))) {
308 XtFree(currDir->dirName);
309 XtFree((char *)currDir);
310
311 if (path) {
312 /* ripple down the dir array */
313 for (; i < cacheList.numDirs - 1; i++)
314 cacheList.dirs[i] = cacheList.dirs[i+1];
315 cacheList.numDirs--;
316 _XmProcessUnlock();
317 return;
318 }
319 }
320 }
321 if (path && (i == cacheList.numDirs)) {
322 _XmProcessUnlock();
323 return;
324 }
325 cacheList.numDirs = 0;
326 /* don't free the dirList itself */
327 _XmProcessUnlock();
328 }
329
330
331 #ifndef XTHREADS
332 static String GdirName;
333 static String GleafName;
334 #endif
335
336 static int
CheckDirCache(String path)337 CheckDirCache(String path)
338
339 {
340 String dirName;
341 String filePtr;
342 String suffixPtr;
343 int numDirs, dirNameLen, fileNameLen;
344 Cardinal i, j;
345 char stackString[MAX_DIR_PATH_LEN];
346
347 (void) _XmOSAbsolutePathName(path, &path, stackString);
348 _XmOSFindPathParts(path, &filePtr, &suffixPtr);
349
350 if (path == filePtr) {
351 dirNameLen = 0;
352 fileNameLen = strlen(path);
353 }
354 else {
355 /* take the slash into account */
356 dirNameLen = filePtr - path - 1;
357 fileNameLen = strlen(path) - dirNameLen - 1;
358 }
359
360 /*
361 * set global variable for later use
362 */
363 #ifndef XTHREADS
364 GleafName = filePtr;
365 #endif
366
367 if (dirNameLen == 0) {
368 return DtINVALID_CACHED_DIR;
369 }
370
371 /*
372 * loop thru the dir list. on the last pass create the new cached
373 * dir and process it.
374 */
375 _XmProcessLock();
376
377 numDirs = cacheList.numDirs;
378 for (i = 0; i <= numDirs; i++) {
379 String currName;
380 int currNameLen;
381 String nameHeap;
382 DtValidCachedDir currDir;
383
384 if (i == cacheList.numDirs) {
385
386 /*
387 * we didn't get a hit on the directory list so create a new one
388 */
389 if (cacheList.numDirs == cacheList.maxDirs) {
390 cacheList.maxDirs += 16;
391 cacheList.dirs = (DtCachedDir *)
392 XtRealloc((char *)cacheList.dirs,
393 cacheList.maxDirs * sizeof (DtCachedDir));
394 }
395 dirName = strncpy(XtMalloc(dirNameLen+1), path, dirNameLen);
396 dirName[dirNameLen] = '\0';
397 cacheList.dirs[cacheList.numDirs++] = MakeCachedDirEntry(dirName);
398 }
399 currDir = (DtValidCachedDir)cacheList.dirs[i];
400
401 /*
402 * set global variable
403 */
404 #ifndef XTHREADS
405 GdirName = currDir->dirName;
406 #endif
407
408 if ((currDir->dirNameLen == dirNameLen) &&
409 (strncmp(currDir->dirName, path, dirNameLen) == 0)) {
410
411 switch(currDir->cachedDirType) {
412 case DtINVALID_CACHED_DIR:
413 case DtUNCACHED_DIR:
414 _XmProcessUnlock();
415 return currDir->cachedDirType;
416 break;
417 case DtVALID_CACHED_DIR:
418 nameHeap = (String)
419 &(currDir->nameOffsets[currDir->numFiles + 1]);
420 for (j = 0; j < currDir->numFiles; j++) {
421 /*
422 * nameOffsets has an extra offset to indicate the
423 * end of the last name (to handle border condition
424 */
425 currNameLen = (currDir->nameOffsets[j + 1] -
426 currDir->nameOffsets[j]);
427 if (currNameLen == fileNameLen) {
428 currName = &(nameHeap[currDir->nameOffsets[j]]);
429 if (strncmp(currName, filePtr, currNameLen) == 0) {
430 _XmProcessUnlock();
431 return DtVALID_CACHED_DIR;
432 }
433 }
434 }
435 _XmProcessUnlock();
436 return DtINVALID_CACHED_DIR;
437 }
438 }
439 }
440 _XmProcessUnlock();
441 return DtINVALID_CACHED_DIR;
442 }
443
444 static String
find_slash(String str)445 find_slash(String str)
446 {
447 int n;
448 if (MB_CUR_MAX == 1) {
449 return strchr(str, '/');
450 } else {
451 #ifndef NO_MULTIBYTE
452 while ((n = mblen(str, MB_CUR_MAX)) >0) {
453 #else
454 if (!str) return NULL;
455 while ((n = *str ? 1 : 0) > 0) {
456 #endif
457 #ifndef NO_MULTIBYTE
458 if (n == 1 && *str == '/')
459 return str;
460 str += n;
461 #else
462 if (*str == '/')
463 return str;
464 str++;
465 #endif
466 }
467 return NULL;
468 }
469 }
470
471 static Boolean
472 TestIconFile(String path)
473 {
474 struct stat status;
475 int dirCacheType;
476
477 if (!path || !*path)
478 return False;
479
480 /* if there is no directory information in the name, it's
481 a local file, check here or CheckDirCache will fail */
482
483 if (!find_slash(path)) {
484 dirCacheType = DtUNCACHED_DIR ;
485 #ifndef XTHREADS
486 GleafName = path ;
487 GdirName = "." ;
488 #endif
489 } else
490 dirCacheType = CheckDirCache(path);
491
492 switch(dirCacheType) {
493 case DtVALID_CACHED_DIR:
494 return True;
495
496 case DtINVALID_CACHED_DIR:
497 return False;
498
499 case DtUNCACHED_DIR:
500 return (access(path, R_OK) == 0 && /* exists and is readable */
501 stat(path, &status) == 0 && /* get the status */
502 S_ISDIR(status.st_mode) == 0 /* not a directory */
503 );
504 }
505
506 return False ;
507 }
508
509
510 /*********** Hash table stuff */
511
512
513 typedef struct _DtIconNameEntryRec{
514 String dirName;
515 String leafName;
516 String key_name;
517 }DtIconNameEntryRec, *DtIconNameEntry;
518
519
520 /* Compare two icon names from icon entry rec */
521 static Boolean
522 CompareIconNames (XmHashKey key_1,
523 XmHashKey key_2)
524 {
525 DtIconNameEntry data_1 = (DtIconNameEntry) key_1;
526 DtIconNameEntry data_2 = (DtIconNameEntry) key_2;
527
528 return ((data_1->key_name == data_2->key_name) ||
529 (strcmp(data_1->key_name, data_2->key_name) == 0));
530 }
531
532
533 /* Hash an icon name . */
534 static XmHashValue
535 HashIconName (XmHashKey key)
536 {
537 DtIconNameEntry data = (DtIconNameEntry) key;
538 unsigned int len = strlen(data->key_name);
539
540 return (((len << 8) | data->key_name[0]) << 8) | data->key_name[len];
541 }
542
543
544 String
545 XmGetIconFileName(
546 Screen *screen,
547 String imageInstanceName,
548 String imageClassName,
549 String hostPrefix,
550 unsigned int size)
551 {
552 Display *display = DisplayOfScreen(screen);
553 String fileName = NULL;
554 String names[2];
555 String names_w_size[2];
556 XmConst char *bPath, *iPath;
557 Cardinal i;
558 Boolean useColor;
559 Boolean useMask;
560 Boolean useIconFileCache;
561 Boolean absolute = 0;
562 XtFilePredicate testFileFunc;
563 String homedir = NULL ;
564 static String iconPath = NULL;
565 static String bmPath = NULL;
566 static XmHashTable iconNameCache = NULL;
567 char stackString[MAX_DIR_PATH_LEN];
568
569 #define B_SUB 0
570 #define P_SUB 1
571 #define M_SUB 2
572 #define H_SUB 3
573
574 SubstitutionRec iconSubs[] = {
575 {'B', NULL}, /* bitmap name */
576 {'P', NULL}, /* alternate bitmap name BC */
577 {'M', NULL}, /* magnitude */
578 {'H', NULL}, /* host prefix */
579 };
580
581 XtAppContext app;
582
583 app = XtDisplayToApplicationContext(display);
584
585 _XmAppLock(app);
586
587 /* start by asking some screen state */
588 (void)XmeGetIconControlInfo(screen,
589 &useMask, /* not used here */
590 &useColor,
591 &useIconFileCache);
592
593 _XmProcessLock();
594
595 /* generate the icon paths once per application: iconPath and bmPath */
596 if (!iconNameCache) {
597 Boolean junkBoolean;
598
599 iconNameCache = _XmAllocHashTable(100,
600 CompareIconNames, HashIconName);
601
602 cacheList.numDirs =
603 cacheList.maxDirs = 0;
604 cacheList.dirs = NULL;
605
606 homedir = XmeGetHomeDirName();
607 strcpy(stackString, homedir) ;
608
609 if (useColor) {
610 iconPath = _XmOSInitPath(NULL, "XMICONSEARCHPATH", &junkBoolean);
611 }
612 else {
613 iconPath = _XmOSInitPath(NULL, "XMICONBMSEARCHPATH", &junkBoolean);
614 }
615
616 /* 1.2 path as a fallback */
617 bmPath = _XmOSInitPath(NULL, "XBMLANGPATH", &junkBoolean);
618
619 }
620
621 switch (size) {
622 case XmTINY_ICON_SIZE:
623 iconSubs[M_SUB].substitution = ".t";
624 break;
625 case XmSMALL_ICON_SIZE:
626 iconSubs[M_SUB].substitution = ".s";
627 break;
628 case XmMEDIUM_ICON_SIZE:
629 iconSubs[M_SUB].substitution = ".m";
630 break;
631 case XmLARGE_ICON_SIZE:
632 iconSubs[M_SUB].substitution = ".l";
633 break;
634 case XmUNSPECIFIED_ICON_SIZE:
635 iconSubs[M_SUB].substitution = NULL;
636 break;
637 }
638
639 iconSubs[H_SUB].substitution = hostPrefix;
640
641 if (useIconFileCache)
642 testFileFunc = TestIconFile;
643 else
644 testFileFunc = NULL;
645
646 names[0] = imageInstanceName;
647 names[1] = imageClassName;
648 names_w_size[0] = names_w_size[1] = (String)NULL;
649
650 /** loop over the two names */
651 for (i = 0; i < 2; i++) {
652
653 if (names[i] == NULL)
654 continue;
655
656 if ((absolute = _XmOSAbsolutePathName(names[i], &names[i],
657 stackString)) != FALSE) {
658 iPath = ABSOLUTE_IPATH;
659 bPath = ABSOLUTE_PATH;
660 }
661 else {
662 iPath = iconPath;
663 bPath = bmPath;
664 }
665
666 iconSubs[B_SUB].substitution = names[i];
667 iconSubs[P_SUB].substitution = names[i];
668
669 /* need to add size suffix if size is specified */
670 if (size != XmUNSPECIFIED_ICON_SIZE) {
671 int basenameLen = strlen(names[i]);
672 int sizeLen = strlen(iconSubs[M_SUB].substitution);
673 char * ext_name = XtMalloc(basenameLen + sizeLen + 1);
674 /* XmosP.h takes care of bcopy translation */
675 memmove(&ext_name[0], names[i], basenameLen);
676 memmove(&ext_name[basenameLen],
677 iconSubs[M_SUB].substitution, sizeLen);
678 ext_name[basenameLen + sizeLen] = '\0';
679
680 names_w_size[i] = ext_name;
681
682 } else
683 names_w_size[i] = NULL;
684
685 /*
686 * try to see if its already in the image cache
687 */
688 if (_XmInImageCache(names[i]))
689 fileName = XtNewString(names[i]);
690
691
692 /*
693 * optimization to check all expansions in cache
694 */
695 if (!fileName) {
696 DtIconNameEntry iNameEntry;
697 DtIconNameEntryRec iNameData ;
698
699 iNameData.key_name = (names_w_size[i])?names_w_size[i]:names[i];
700
701 iNameEntry = (DtIconNameEntry)
702 _XmGetHashEntry(iconNameCache, (XmHashKey)&iNameData);
703
704 if (iNameEntry) {
705 int dirLen, leafLen;
706
707 dirLen = strlen(iNameEntry->dirName);
708 leafLen = strlen(iNameEntry->leafName);
709 fileName = XtMalloc(dirLen + leafLen + 2);
710
711 memmove(&fileName[0],
712 iNameEntry->dirName,
713 dirLen);
714 #ifdef FIX_1427
715 if (dirLen == 0) {
716 memmove(&fileName[dirLen], iNameEntry->leafName, leafLen);
717 fileName[dirLen + leafLen] = '\0';
718 } else {
719 #endif
720 fileName[dirLen] = '/';
721 memmove(&fileName[dirLen + 1],
722 iNameEntry->leafName,
723 leafLen);
724
725 fileName[dirLen + leafLen + 1] = '\0';
726 #ifdef FIX_1427
727 }
728 #endif
729 }
730 }
731
732 if (fileName) {
733 /*
734 * CDExc20823 (memory leak): free names_w_size[i]
735 * if it is not NULL.
736 * NOTE: This code could be reorganized to do
737 * _XmInImageCache() at the top of this loop
738 * so we could avoid unnecessary malloc's for
739 * names_w_size, but I wanted to minimize the
740 * code impact of this defect for now.
741 */
742 for (i = 0; i < 2; i++)
743 {
744 if (names_w_size[i] != (String)NULL)
745 XtFree(names_w_size[i]);
746 }
747
748 _XmProcessUnlock();
749 _XmAppUnlock(app);
750 return fileName;
751 }
752
753 /*******************************
754 * first try XPM and then XBM
755 ******************************/
756 fileName =
757 XtResolvePathname(display, "icons", NULL,
758 NULL, iPath, iconSubs,
759 XtNumber(iconSubs),
760 (XtFilePredicate) testFileFunc);
761
762 if (fileName == NULL) {
763 fileName =
764 XtResolvePathname(display, "bitmaps", NULL,
765 NULL, bPath, iconSubs,
766 XtNumber(iconSubs),
767 (XtFilePredicate) testFileFunc);
768 }
769
770 if (fileName)
771 break;
772 }
773 _XmProcessUnlock();
774
775 if (fileName && !absolute) {
776 /* register it in name cache */
777 DtIconNameEntry iNameEntry;
778 String name_used = (names_w_size[i])? names_w_size[i] : names[i] ;
779
780 /** alloc a icon cache entry **/
781 iNameEntry = (DtIconNameEntry) XtMalloc(sizeof(DtIconNameEntryRec));
782 iNameEntry->key_name = XtNewString(name_used);
783
784 #ifndef XTHREADS
785 if (useIconFileCache)
786 {
787 iNameEntry->dirName = XtNewString(GdirName);
788 iNameEntry->leafName = XtNewString(GleafName);
789 }
790 else
791 #endif
792 {
793 String dirName;
794 String filePtr;
795 String suffixPtr;
796 int dirNameLen;
797
798 _XmOSFindPathParts(fileName, &filePtr, &suffixPtr);
799
800 if (fileName == filePtr)
801 dirNameLen = 0;
802 else {
803 /* take the slash into account */
804 dirNameLen = filePtr - fileName - 1;
805 }
806
807 dirName = (String)XtMalloc(dirNameLen + 1);
808 strncpy(dirName, fileName, dirNameLen);
809 dirName[dirNameLen] = '\0';
810
811 iNameEntry->dirName = dirName;
812 iNameEntry->leafName = XtNewString(filePtr);
813 }
814
815 _XmProcessLock();
816 _XmAddHashEntry(iconNameCache, (XmHashKey)iNameEntry,
817 (XtPointer)iNameEntry);
818 _XmProcessUnlock();
819 }
820
821 /*
822 * CDExc20823 (memory leak): free names_w_size[i] if not NULL.
823 */
824 for (i = 0; i < 2; i++)
825 {
826 if (names_w_size[i] != (String)NULL)
827 XtFree(names_w_size[i]);
828 }
829
830 _XmAppUnlock(app);
831 return fileName;
832 }
833
834
835
836
837
838
839
840