1 /*
2  * Motif
3  *
4  * Copyright (c) 1987-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 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 
28 #ifdef REV_INFO
29 #ifndef lint
30 static char rcsid[] = "$TOG: Xmos.c /main/33 1998/01/21 11:07:25 csn $"
31 #endif
32 #endif
33 
34 #include <stdio.h>
35 
36 #ifdef __cplusplus
37 extern "C" { /* some 'locale.h' do not have prototypes (sun) */
38 #endif
39 #include <X11/Xlocale.h>
40 #ifdef __cplusplus
41 } /* Close scope of 'extern "C"' declaration */
42 #endif /* __cplusplus */
43 
44 #include <X11/Xos.h>
45 #ifndef NEED_XPOLL_H
46 #include <X11/Xpoll.h>
47 #else
48 #include <Xm/Xmpoll.h>
49 #endif
50 
51 #ifndef X_NOT_STDC_ENV
52 #include <stdlib.h>
53 #include <unistd.h>
54 #endif
55 
56 #include <ctype.h>		/* for isspace() */
57 
58 #include <sys/time.h>		/* For declaration of select(). */
59 
60 #if defined(NO_REGCOMP) && !defined(NO_REGEX)
61 # ifdef __sgi
62 extern char *regcmp();
63 extern int regex();
64 # elif defined(SVR4)
65 #  include <libgen.h>
66 # elif defined(SYSV)
67 extern char *regcmp();
68 extern int regex();
69 # endif
70 #endif /* NO_REGEX */
71 
72 #ifndef NO_REGCOMP
73 # include <regex.h>
74 #endif /* NO_REGCOMP */
75 
76 #include <sys/stat.h>
77 
78 #define X_INCLUDE_PWD_H
79 #define X_INCLUDE_DIRENT_H
80 #define XOS_USE_XT_LOCKING
81 
82 #ifndef NEED_XOS_R_H
83 #include <X11/Xos_r.h>
84 #else
85 #include <Xm/Xmos_r.h>
86 #endif
87 
88 #include "XmosI.h"
89 #include "XmI.h"
90 
91 #ifdef USE_GETWD
92 # include <sys/param.h>
93 # define MAX_DIR_PATH_LEN    MAXPATHLEN
94 # define getcwd(buf, len)   ((char *) getwd(buf))
95 #else
96 # define MAX_DIR_PATH_LEN    1024
97 #endif
98 #define MAX_USER_NAME_LEN   256
99 
100 #ifndef S_ISDIR
101 # define S_ISDIR(m) ((m & S_IFMT)==S_IFDIR)
102 #endif
103 
104 #ifndef S_ISREG
105 # define S_ISREG(m) ((m & S_IFMT)==S_IFREG)
106 #endif
107 
108 #define FILE_LIST_BLOCK 64
109 
110 typedef struct {
111   unsigned char type ;
112   char file_name[1] ;		/* Must be last entry in structure. */
113 } XmDirCacheRec, **XmDirCache ;
114 
115 
116 /********
117  * Set defaults for resources that are implementation dependant
118  * and may be modified.
119  ********/
120 
121 externaldef(xmos) char _XmSDEFAULT_FONT[] = "fixed";
122 externaldef(xmos) char _XmSDEFAULT_BACKGROUND[] = "#c4c4c4";
123 
124 /**************** end of vendor dependant defaults ********/
125 
126 /********    Static Function Declarations    ********/
127 
128 static String GetCurrentDir(String buf);
129 static String GetQualifiedDir(String dirSpec);
130 static String GetFixedMatchPattern(String pattern);
131 static void FreeDirCache(void);
132 static void ResetCache(char *qDirName);
133 static unsigned char AddEntryToCache(char *entryName, unsigned entryNameLen);
134 static int Wcslen(wchar_t *wcs);
135 
136 /********    End Static Function Declarations    ********/
137 
138 static char *dirCacheName;
139 static unsigned dirCacheNameLen;
140 static XmDirCache dirCache;
141 static unsigned numCacheAlloc;
142 static unsigned numCacheEntries;
143 
144 static void
FreeDirCache(void)145 FreeDirCache(void)
146 {
147   if (dirCacheName != NULL)
148     {
149       XtFree(dirCacheName);
150       dirCacheName = NULL;
151       dirCacheNameLen = 0;
152 
153       while (numCacheEntries)
154 	XtFree((char *) dirCache[--numCacheEntries]);
155     }
156 }
157 
158 static void
ResetCache(char * qDirName)159 ResetCache(char *qDirName)
160 {
161   FreeDirCache();
162 
163   dirCacheNameLen = strlen(qDirName);
164   dirCacheName = XtMalloc(dirCacheNameLen + MAX_USER_NAME_LEN + 1);
165   strcpy(dirCacheName, qDirName);
166 }
167 
168 static unsigned char
AddEntryToCache(char * entryName,unsigned entryNameLen)169 AddEntryToCache(char *entryName,
170 		unsigned entryNameLen)
171 {
172   struct stat statBuf;
173   unsigned char result = 0;
174 
175   if (numCacheEntries == numCacheAlloc)
176     {
177       numCacheAlloc += FILE_LIST_BLOCK;
178       dirCache = (XmDirCache)
179 	XtRealloc((char *) dirCache, numCacheAlloc * sizeof(XmDirCacheRec *));
180     }
181 
182   dirCache[numCacheEntries] = (XmDirCacheRec *)
183     XtMalloc(sizeof(XmDirCacheRec) + entryNameLen);
184   strcpy(dirCache[numCacheEntries]->file_name, entryName);
185 
186   /* Use dirCacheName character array as temporary buffer for full file name.*/
187   strcpy(&dirCacheName[dirCacheNameLen], entryName);
188 
189   if (!stat(dirCacheName, &statBuf))
190     {
191       if (S_ISREG(statBuf.st_mode))
192 	result = XmFILE_REGULAR;
193       else if (S_ISDIR(statBuf.st_mode))
194 	result = XmFILE_DIRECTORY;
195     }
196 
197   /* Restore to dir path only. */
198   dirCacheName[dirCacheNameLen] = '\0';
199 
200   dirCache[numCacheEntries++]->type = result;
201   return result;
202 }
203 
204 /****************************************************************/
205 static String
GetQualifiedDir(String dirSpec)206 GetQualifiedDir(String dirSpec)
207 /*************GENERAL:
208  * dirSpec is a directory name, that can contain relative
209  *   as well as logical reference. This routine resolves all these
210  *   references, so that dirSpec is now suitable for open().
211  * The routine allocates memory for the result, which is guaranteed to be
212  *   of length >= 1.  This memory should eventually be freed using XtFree().
213  ****************/
214 
215 /*************UNIX:
216  * Builds directory name showing descriptive path components.  The result
217  *   is a directory path beginning at the root directory and terminated
218  *   with a '/'.  The path will not contain ".", "..", or "~" components.
219  ****************/
220 {
221   int             dirSpecLen;
222   _Xgetpwparams	  pwd_buf;
223   struct passwd * pwd_value;
224 
225   char *          userDir;
226   int             userDirLen;
227   int             userNameLen;
228   char *          outputBuf;
229   char *          destPtr;
230   char *          srcPtr;
231   char *          scanPtr;
232   char            nameBuf[MAX_USER_NAME_LEN];
233   char            dirbuf[MAX_DIR_PATH_LEN];
234 
235   dirSpecLen = strlen(dirSpec);
236   outputBuf = NULL;
237 
238   switch (*dirSpec)
239     {
240     case '~':
241       if (!(dirSpec[1])  ||  (dirSpec[1] == '/'))
242 	{
243 	  userDir = XmeGetHomeDirName();
244 	  if (*userDir)
245 	    {
246 	      userDirLen = strlen(userDir);
247 	      outputBuf = XtMalloc(userDirLen + dirSpecLen + 2);
248 	      strcpy(outputBuf, userDir);
249 	      strcpy(&outputBuf[userDirLen], (dirSpec + 1));
250 	    }
251 	}
252       else
253 	{
254 	  destPtr = nameBuf;
255 	  userNameLen = 0;
256 	  srcPtr = dirSpec + 1;
257 	  while (*srcPtr  &&  (*srcPtr != '/') &&
258 		 (++userNameLen < MAX_USER_NAME_LEN))
259 	    {
260 	      *destPtr++ = *srcPtr++;
261 	    }
262 	  *destPtr = '\0';
263 
264 	  pwd_value = _XGetpwnam(nameBuf, pwd_buf);
265 	  if (pwd_value != NULL)
266 	    {
267 	      userDirLen = strlen(pwd_value->pw_dir);
268 	      dirSpecLen = strlen(srcPtr);
269 	      outputBuf = XtMalloc(userDirLen + dirSpecLen + 2);
270 	      strcpy(outputBuf, pwd_value->pw_dir);
271 	      strcpy(&outputBuf[userDirLen], srcPtr);
272 	    }
273 	}
274       break;
275 
276     case '/':
277       outputBuf = XtMalloc(dirSpecLen + 2);
278       strcpy(outputBuf, dirSpec);
279       break;
280 
281     default:
282       if ((destPtr = GetCurrentDir(dirbuf)) != NULL)
283 	{
284 	  userDirLen = strlen(destPtr);
285 	  outputBuf = XtMalloc(userDirLen + dirSpecLen + 3);
286 	  strcpy(outputBuf, destPtr);
287 	  outputBuf[userDirLen++] = '/';
288 	  strcpy(&outputBuf[userDirLen], dirSpec);
289 	}
290       break;
291     }
292 
293   if (!outputBuf)
294     {
295       outputBuf = XtMalloc(2);
296       outputBuf[0] = '/';
297       outputBuf[1] = '\0';
298     }
299   else
300     {
301       userDirLen = strlen(outputBuf);
302       if (outputBuf[userDirLen - 1]  !=  '/')
303         {
304 	  outputBuf[userDirLen] = '/';
305 	  outputBuf[++userDirLen] = '\0';
306 	}
307       /* The string in outputBuf is assumed to begin and end with a '/'. */
308       scanPtr = outputBuf;
309       while (*++scanPtr)               /* Skip past '/'. */
310         {
311 	  /* scanPtr now points to non-NULL character following '/'. */
312 	  if (scanPtr[0] == '.')
313             {
314 	      if (scanPtr[1] == '/')
315                 {
316 		  /* Have "./", so just erase (overwrite with shift).
317 		   */
318 		  destPtr = scanPtr;
319 		  srcPtr = &scanPtr[2];
320 		  while ((*destPtr++ = *srcPtr++) != '\0')
321 		    /*EMPTY*/;
322 		  --scanPtr;     /* Leave scanPtr at preceding '/'. */
323 		  continue;
324 		}
325 	      else
326                 {
327 		  if ((scanPtr[1] == '.')  &&  (scanPtr[2] == '/'))
328                     {
329 		      /* Have "../", so back up one directory. */
330 		      srcPtr = &scanPtr[2];
331 		      --scanPtr;      /* Move scanPtr to preceding '/'.*/
332 		      if (scanPtr != outputBuf)
333                         {
334 			  while ((*--scanPtr != '/'))
335 			    /*EMPTY*/;        /* Now move to previous '/'.*/
336 			}
337 		      destPtr = scanPtr;
338 		      while ((*++destPtr = *++srcPtr) != '\0')
339 			/*EMPTY*/;		/* Overwrite "../" with shift.*/
340 		      continue;
341 		    }
342 		}
343 	    }
344 	  else
345             {
346 	      /* Check for embedded "//".  Posix allows a leading double
347 	       *   slash (and Apollos require it).
348 	       */
349 	      if (*scanPtr == '/')
350                 {
351 		  if ((scanPtr > (outputBuf + 1)) ||
352 		      (scanPtr[1] == '/'))
353                     {
354 		      /* Have embedded "//" (other than root specification),
355 		       *   so erase with shift and reset scanPtr.
356 		       */
357 		      srcPtr = scanPtr;
358 		      --scanPtr;
359 		      destPtr = scanPtr;
360 		      while ((*++destPtr = *++srcPtr) != '\0')
361 			/*EMPTY*/;
362 		    }
363 		  continue;
364 		}
365 	    }
366 	  while (*++scanPtr != '/')
367 	    /*EMPTY*/;
368 	}
369     }
370 
371   return outputBuf;
372 }
373 
374 /****************************************************************/
375 String
_XmOSFindPatternPart(String fileSpec)376 _XmOSFindPatternPart(String fileSpec)
377 /****************GENERAL:
378  * fileSpec is made of a directory part and a pattern part.
379  * Returns the pointer to the first character of the pattern part
380  ****************/
381 
382 /****************UNIX:
383  * Returns the pointer to the character following the '/' of the name segment
384  *   which contains a wildcard or which is not followed by a '/'.
385  ****************/
386 {
387   char *          lookAheadPtr = fileSpec;
388   char *          maskPtr;
389   Boolean         hasWildcards;
390   char            prevChar;
391   char            prev2Char ;
392 
393   /* Stop at final name segment or if wildcards were found. */
394   do {
395     maskPtr = lookAheadPtr;
396     hasWildcards = FALSE;
397     prevChar = '\0';
398     prev2Char = '\0';
399     while ((*lookAheadPtr != '/') && !hasWildcards && *lookAheadPtr)
400       {
401 	switch (*lookAheadPtr)
402 	  {
403 	  case '*':
404 	  case '?':
405 	  case '[':
406 	    if ((prevChar != '\\')  ||  (prev2Char == '\\'))
407 	      {
408 		hasWildcards = TRUE;
409 		break;
410 	      }
411 	  }
412 	prev2Char = prevChar;
413 	prevChar = *lookAheadPtr;
414 #ifndef NO_MULTIBYTE
415 	lookAheadPtr += ((MB_CUR_MAX > 1) ?
416 			 abs(mblen(lookAheadPtr, MB_CUR_MAX)) : 1);
417 #else
418 	lookAheadPtr++;
419 #endif
420       }
421   } while (!hasWildcards  &&  *lookAheadPtr++);
422 
423   if (*maskPtr == '/')
424     ++maskPtr;
425 
426   return(maskPtr);
427 }
428 
429 /****************************************************************/
430 void
_XmOSQualifyFileSpec(String dirSpec,String filterSpec,String * pQualifiedDir,String * pQualifiedPattern)431 _XmOSQualifyFileSpec(String  dirSpec,
432 		     String  filterSpec,
433 		     String *pQualifiedDir,      /* Cannot be NULL.*/
434 		     String *pQualifiedPattern)  /* Cannot be NULL.*/
435 /************GENERAL:
436  * dirSpec, filterSpec can contain relative or logical reference.
437  * dirSpec cannot contain pattern characters.
438  * if filterSpec does not specify all for its last segment, a pattern
439  * for 'all' is added.
440  * Use GetQualifiedDir() for dirSpec.
441  ****************/
442 
443 /************UNIX:
444  * 'all' is '*' and '/' is the delimiter.
445  ****************/
446 {
447   int filterLen;
448   int dirLen;
449   char *fSpec;
450   char *remFSpec;
451   char *maskPtr;
452   char *dSpec;
453   char *dPtr;
454 
455   if (!dirSpec)
456     dirSpec = "";
457   if (!filterSpec)
458     filterSpec = "";
459 
460   filterLen = strlen(filterSpec);
461 
462   /* Allocate extra for NULL character and for the appended '*' (as needed). */
463   fSpec = XtMalloc(filterLen + 2);
464   strcpy(fSpec, filterSpec);
465 
466   /* If fSpec ends with a '/' or is a null string, add '*' since this is
467    *   the interpretation.
468    */
469   if (!filterLen  ||  (fSpec[filterLen - 1] == '/'))
470     {
471       fSpec[filterLen] = '*';
472       fSpec[filterLen + 1] = '\0';
473     }
474 
475   /* Some parts of fSpec may be copied to dSpec, so allocate "filterLen"
476    *   extra, plus some for added literals.
477    */
478   dirLen = strlen(dirSpec);
479   dSpec = XtMalloc(filterLen + dirLen + 4);
480   strcpy(dSpec, dirSpec);
481   dPtr = dSpec + dirLen;
482 
483   /* Check for cases when the specified filter overrides anything
484    *   in the dirSpec.
485    */
486   remFSpec = fSpec;
487   switch(*fSpec)
488     {
489     case '/':
490       dSpec[0] = '/';
491       dSpec[1] = '\0';
492       dPtr = dSpec + 1;
493       ++remFSpec;
494       break;
495 
496     case '~':
497       dPtr = dSpec;
498       while ((*dPtr = *remFSpec)  &&  (*remFSpec++ != '/'))
499 	++dPtr;
500       *dPtr = '\0';
501       break;
502     }
503 
504   /* If directory spec. is not null, then make sure that it has a
505    *   trailing '/', to be prepared for appending from filter spec.
506    */
507   if (*dSpec  &&  (*(dPtr - 1) != '/'))
508     {
509       *dPtr++ = '/';
510       *dPtr = '\0';
511     }
512 
513   maskPtr = _XmOSFindPatternPart(remFSpec);
514 
515   if (maskPtr != remFSpec)
516     {
517       do {
518 	*dPtr++ = *remFSpec++;
519       } while (remFSpec != maskPtr);
520       *dPtr = '\0';
521     }
522 
523   if (remFSpec != fSpec)
524     {
525       /* Shift remaining filter spec. to the beginning of the buffer. */
526       remFSpec = fSpec;
527       while ((*remFSpec++ = *maskPtr++) != '\0')
528 	/*EMPTY*/;
529     }
530 
531   *pQualifiedDir = GetQualifiedDir(dSpec);
532   *pQualifiedPattern = fSpec;
533   XtFree(dSpec);
534 }
535 
536 /****************************************************************/
537 static String
GetFixedMatchPattern(String pattern)538 GetFixedMatchPattern(String pattern)
539 /**********GENERAL:
540  * The pattern parameter is converted to the format required of the
541  *   the regular expression library routines.
542  * Memory is allocated and returned with the result.  This memory
543  *   should eventually be freed by a call to XtFree().
544  ****************/
545 
546 /**********UNIX:
547  * '/' is used as a delimiter for the pattern.
548  ****************/
549 {
550   register char *bufPtr;
551   char *outputBuf;
552   char lastchar = '\0';
553   int len;
554 
555   outputBuf = XtCalloc(2, strlen(pattern) + 4);
556 
557   bufPtr = outputBuf;
558   *bufPtr++ = '^';
559 
560 #ifndef NO_MULTIBYTE
561   while ((len = mblen(pattern, MB_CUR_MAX)) > 0)
562 #else
563   while ((len = *pattern ? 1 : 0))
564 #endif
565     {
566       if (len <= 1)
567 	{
568 	  if (*pattern == '/')
569 	    break;
570 
571 	  if (lastchar == '\\')
572 	    *bufPtr++ = *pattern;
573 	  else
574 	    {
575 	      switch(*pattern)
576 		{
577 		case '.':
578 		  *bufPtr++ = '\\';
579 		  *bufPtr++ = '.';
580 		  break;
581 
582 		case '?':
583 		  *bufPtr++ = '.';
584 		  break;
585 
586 		case '*':
587 		  *bufPtr++ = '.';
588 		  *bufPtr++ = '*';
589 		  break;
590 
591 		default:
592 		  *bufPtr++ = *pattern;
593 		  break;
594 		}
595 	    }
596 	  lastchar = *pattern;
597 	  ++pattern;
598 	}
599       else
600 	{
601 	  strncpy(bufPtr, pattern, len);
602 	  bufPtr += len;
603 	  pattern += len;
604 	  lastchar = '\0';
605 	}
606     }
607 
608   *bufPtr++ = '$';
609   *bufPtr = '\0';
610 
611   return outputBuf;
612 }
613 
614 /****************************************************************/
615 void
_XmOSGetDirEntries(String qualifiedDir,String matchPattern,unsigned int fileType,int matchDotsLiterally,int listWithFullPath,String ** pEntries,unsigned int * pNumEntries,unsigned int * pNumAlloc)616      _XmOSGetDirEntries(String          qualifiedDir,
617 			String          matchPattern,
618 #if NeedWidePrototypes
619 			unsigned int fileType,
620 			int matchDotsLiterally,
621 			int listWithFullPath,
622 #else
623 			unsigned char fileType,
624 			Boolean matchDotsLiterally,
625 			Boolean listWithFullPath,
626 #endif /* NeedWidePrototypes */
627 			String * *      pEntries, /* Cannot be NULL. */
628 			unsigned int *  pNumEntries, /* Cannot be NULL. */
629 			unsigned int *  pNumAlloc) /* Cannot be NULL. */
630 
631 /***********GENERAL:
632  * This routine opens the specified directory and builds a buffer containing
633  * a series of strings containing the full path of each file in the directory
634  * The memory allocated should eventually be freed using XtFree.
635  * The 'qualifiedDir' parameter must be a fully qualified directory path
636  * The matchPattern parameter must be in the proper form for a regular
637  * expression parsing.
638  * If the location pointed to by pEntries is NULL, this routine allocates
639  *   and returns a list to *pEntries, though the list may have no entries.
640  *   pEntries, pEndIndex, pNumAlloc are updated as required for memory
641  *   management.
642  ****************/
643 
644 /***********UNIX:
645  * Fully qualified directory means begins with '/', does not have
646  * embedded "." or "..", but does not need trailing '/'.
647  * Regular expression parsing is regcmp or re_comp.
648  * Directory entries are also Unix dependent.
649  ****************/
650 
651 {
652   char *          fixedMatchPattern;
653   String          entryPtr;
654   DIR *           dirStream = NULL;
655   struct stat     statBuf;
656   Boolean         entryTypeOK;
657   unsigned int    dirLen = strlen(qualifiedDir);
658   Boolean         useCache = FALSE;
659   Boolean         loadCache = FALSE;
660   unsigned        readCacheIndex = 0;
661   unsigned char   dirFileType = 0;
662 #ifndef NO_REGCOMP
663   regex_t         preg;
664   int             comp_status = 0;
665 #elif !defined(NO_REGEX)
666   char *          compiledRE = NULL;
667 #endif /* NO_REGCOMP */
668 /****************/
669 
670   _XmProcessLock();
671 
672   if (!*pEntries)
673     {
674       *pNumEntries = 0;
675       *pNumAlloc = FILE_LIST_BLOCK;
676       *pEntries = (String *) XtMalloc(FILE_LIST_BLOCK * sizeof(char *));
677     }
678   fixedMatchPattern = GetFixedMatchPattern(matchPattern);
679 
680   if (fixedMatchPattern)
681     {
682       if (!*fixedMatchPattern)
683 	{
684 	  XtFree(fixedMatchPattern);
685 	  fixedMatchPattern = NULL;
686 	}
687       else
688 	{
689 #ifndef NO_REGCOMP
690 	  comp_status = regcomp(&preg, fixedMatchPattern, REG_NOSUB);
691 	  if (comp_status)
692 #elif !defined(NO_REGEX)
693             compiledRE = (char *)regcmp(fixedMatchPattern, (char *) NULL);
694 	  if (!compiledRE)
695 #else
696           if (re_comp(fixedMatchPattern))
697 #endif
698 	    {
699 	      XtFree(fixedMatchPattern);
700 	      fixedMatchPattern = NULL;
701 	    }
702 	}
703     }
704 
705   if ((dirCacheName != NULL) &&
706       !strcmp(qualifiedDir, dirCacheName))
707     {
708       useCache = TRUE;
709       readCacheIndex = 0;
710     }
711   else
712     {
713       if (!strcmp(matchPattern, "*") &&
714 	  (fileType == XmFILE_DIRECTORY) &&
715 	  !matchDotsLiterally)
716 	{
717 	  /* This test is a incestual way of knowing that we are searching
718 	   * a directory to fill the directory list.  We can thereby conclude
719 	   * that a subsequent call will be made to search the same directory
720 	   * to fill the file list.  Since a "stat" of every file is very
721 	   * performance-expensive, we will cache the directory used for
722 	   * a directory list search and subsequently use the results for
723 	   * the file list search.
724 	   */
725 	  loadCache = TRUE;
726 	}
727       dirStream = opendir(qualifiedDir);
728     }
729 
730   if (dirStream || useCache)
731     {
732       unsigned loopCount = 0;
733       _Xreaddirparams dirEntryBuf;
734 
735       if (loadCache)
736 	ResetCache(qualifiedDir);
737 
738       /* The POSIX specification for the "readdir" routine makes
739        *  it OPTIONAL to return the "." and ".." entries in a
740        *  directory.  The algorithm used here depends on these
741        *  entries being included in the directory list.  So, we
742        *  will first handle "." and ".." explicitly, then ignore
743        *  them later if they happen to be returned by "readdir".
744        */
745       while (TRUE)
746 	{
747 	  char *dirName;
748 	  unsigned dirNameLen = 0;
749 
750 	  if (loopCount < 2)
751 	    {
752 	      if (loopCount == 0)
753 		{
754 		  /* Do current directory the first time through. */
755 		  dirName = ".";
756 		  dirNameLen = 1;
757 		}
758 	      else
759 		{
760 		  /* Do parent directory the second time through. */
761 		  dirName = "..";
762 		  dirNameLen = 2;
763 		}
764 	      ++loopCount;
765 
766 	      if (useCache || loadCache)
767 		dirFileType = XmFILE_DIRECTORY;
768 	    }
769 	  else
770 	    {
771 	      struct dirent * dirEntry;
772 
773 	      do {
774 		if (useCache)
775 		  {
776 		    if (readCacheIndex == numCacheEntries)
777 		      {
778 			dirName = NULL;
779 			break;
780 		      }
781 		    else
782 		      {
783 			dirFileType = dirCache[readCacheIndex]->type;
784 			dirName = dirCache[readCacheIndex++]->file_name;
785 			dirNameLen = strlen(dirName);
786 		      }
787 		  }
788 		else
789 		  {
790 		    if ((dirEntry = _XReaddir(dirStream, dirEntryBuf)) == NULL)
791 		      {
792 			dirName = NULL;
793 			break;
794 		      }
795 		    dirName = dirEntry->d_name;
796 		    dirNameLen = strlen(dirName);
797 		    if (loadCache)
798 		      dirFileType = AddEntryToCache(dirName, dirNameLen);
799 		  }
800 		/* Check to see if directory entry is "." or "..",
801 		 *  since these have already been processed.
802 		 *  So if/when readdir returns these directories,
803 		 *  we just ignore them.
804 		 */
805 	      } while (((dirNameLen == 1) && (dirName[0] == '.')) ||
806 		       ((dirNameLen == 2) &&
807 			(dirName[0] == '.') && (dirName[1] == '.')));
808 
809 	      if (dirName == NULL)
810 		break;             /* Exit from outer loop. */
811 	    }
812 	  if (fixedMatchPattern)
813 	    {
814 #ifndef NO_REGCOMP
815 	      if (regexec(&preg, dirName, 0, NULL, 0))
816 #else /* NO_REGCOMP */
817 #  ifndef NO_REGEX
818               if (!regex(compiledRE, dirName))
819 #  else
820               if (!re_exec(dirName))
821 #  endif
822 #endif /* NO_REGCOMP */
823 		continue;
824 	    }
825 	  if (matchDotsLiterally &&
826 	      (dirName[0] == '.') &&
827 	      (*matchPattern != '.'))
828 	    continue;
829 	  if (*pNumEntries == *pNumAlloc)
830 	    {
831 	      *pNumAlloc += FILE_LIST_BLOCK;
832 	      *pEntries = (String *)
833 		XtRealloc((char*) *pEntries, (*pNumAlloc* sizeof(char *)));
834 	    }
835 	  entryPtr = XtMalloc(dirNameLen + dirLen + 1);
836 	  strcpy(entryPtr, qualifiedDir);
837 	  strcpy(&entryPtr[dirLen], dirName);
838 
839 	  /* Now screen entry according to type. */
840 	  entryTypeOK = FALSE;
841 
842 	  if (fileType == XmFILE_ANY_TYPE)
843 	    {
844 	      entryTypeOK = TRUE;
845 	    }
846 	  else if (useCache || loadCache)
847 	    {
848 	      if (dirFileType == fileType)
849 		entryTypeOK = TRUE;
850 	    }
851 	  else
852 	    {
853 	      if (!stat(entryPtr, &statBuf))
854 		{
855 		  switch (fileType)
856 		    {
857 		    case XmFILE_REGULAR:
858 		      if (S_ISREG(statBuf.st_mode))
859 			entryTypeOK = TRUE;
860 		      break;
861 
862 		    case XmFILE_DIRECTORY:
863 		      if (S_ISDIR(statBuf.st_mode))
864 			entryTypeOK = TRUE;
865 		      break;
866 		    }
867 		}
868 	    }
869 	  if (entryTypeOK)
870 	    {
871 	      if (listWithFullPath)
872 		{
873 		  (*pEntries)[(*pNumEntries)++] = entryPtr;
874 		}
875 	      else
876 		{
877 		  /* This is ONLY for BC in a (apparently unused) API, (w/o
878 		   *  full path) so don't worry too much about efficiency.
879 		   */
880 		  XtFree(entryPtr);
881 		  entryPtr = XtMalloc(dirNameLen + 1);
882 		  strcpy(entryPtr, dirName);
883 		  (*pEntries)[(*pNumEntries)++] = entryPtr;
884 		}
885 	    }
886 	  else
887 	    XtFree(entryPtr);
888 	}
889       if (!useCache)
890 	closedir(dirStream);
891     }
892 #ifndef NO_REGCOMP
893   if (!comp_status)
894     regfree(&preg);
895 #else /* NO_REGCOMP */
896 #  ifndef NO_REGEX
897   if (compiledRE)
898     {
899       /* Use free instead of XtFree since malloc is inside of regex(). */
900       free(compiledRE);
901     }
902 #  endif
903 #endif /* NO_REGCOMP */
904   XtFree(fixedMatchPattern);
905 
906   if (!loadCache)
907     FreeDirCache();
908   _XmProcessUnlock();
909 }
910 
911 /****************************************************************
912  * _XmOSBuildFileList:
913  *
914  * GENERAL:
915  * The 'dirPath' parameter must be a qualified directory path.
916  * The 'pattern' parameter must be valid as a suffix to dirPath.
917  * typeMask is an Xm constant coming from Xm.h.
918  *
919  * UNIX:
920  * Qualified directory path means no match characters, with '/'
921  * at end.
922  ****************************************************************/
923 void
_XmOSBuildFileList(String dirPath,String pattern,unsigned int typeMask,String ** pEntries,unsigned int * pNumEntries,unsigned int * pNumAlloc)924 _XmOSBuildFileList(String          dirPath,
925 		   String          pattern,
926 #if NeedWidePrototypes
927 		   unsigned int typeMask,
928 #else
929 		   unsigned char typeMask,
930 #endif /* NeedWidePrototypes */
931 		   String * *      pEntries,       /* Cannot be NULL. */
932 		   unsigned int *  pNumEntries,    /* Cannot be NULL. */
933 		   unsigned int *  pNumAlloc)      /* Cannot be NULL. */
934 {
935   String          qualifiedDir;
936   String          nextPatternPtr;
937   String *        localEntries;
938   unsigned int    localNumEntries;
939   unsigned int    localNumAlloc;
940   unsigned int    entryIndex;
941 
942   qualifiedDir = GetQualifiedDir(dirPath);
943   nextPatternPtr = pattern;
944   while (*nextPatternPtr  &&  (*nextPatternPtr != '/'))
945     ++nextPatternPtr;
946 
947   if (!*nextPatternPtr)
948     {
949       /* At lowest level directory, so simply return matching entries.*/
950       _XmOSGetDirEntries(qualifiedDir, pattern, typeMask, FALSE, TRUE,
951 			 pEntries, pNumEntries, pNumAlloc);
952     }
953   else
954     {
955       ++nextPatternPtr;               /* Move past '/' character.*/
956       localEntries = NULL;
957       _XmOSGetDirEntries(qualifiedDir, pattern, XmFILE_DIRECTORY, TRUE, TRUE,
958 			 &localEntries, &localNumEntries, &localNumAlloc);
959       entryIndex = 0;
960       while (entryIndex < localNumEntries)
961 	{
962 	  _XmOSBuildFileList(localEntries[entryIndex], nextPatternPtr,
963 			     typeMask, pEntries, pNumEntries, pNumAlloc);
964 	  XtFree(localEntries[entryIndex]);
965 	  ++entryIndex;
966 	}
967       XtFree((char*)localEntries);
968     }
969   XtFree(qualifiedDir);
970 }
971 
972 /****************************************************************
973  * GENERAL:
974  * The routine must return an integer less than, equal to, or
975  * greater than 0 according as the first argument is to be
976  * considered less than, equal to, or greater than the second.
977  ****************************************************************/
978 
979 int
_XmOSFileCompare(XmConst void * sp1,XmConst void * sp2)980 _XmOSFileCompare(XmConst void *sp1,
981 		 XmConst void *sp2)
982 {
983   return strcmp(*((XmConst String *) sp1), *((XmConst String *) sp2));
984 }
985 
986 /*************************************************************************
987  *
988  *   Path code, used in Mwm and Xm.
989  *   Returned pointer should not be freed!
990  *
991  *************************************************************************/
992 
993 String
XmeGetHomeDirName(void)994 XmeGetHomeDirName(void)
995 {
996   uid_t uid;
997   _Xgetpwparams	pwd_buf;
998   struct passwd * pwd_value;
999 
1000   char *ptr = NULL;
1001   static char empty = '\0';
1002   static char *homeDir = NULL;
1003 
1004   _XmProcessLock();
1005   if (homeDir == NULL)
1006     {
1007       if ((ptr = (char *)getenv("HOME")) == NULL)
1008 	{
1009 	  if ((ptr = (char *)getenv(USER_VAR)) != NULL)
1010 	    pwd_value = _XGetpwnam(ptr, pwd_buf);
1011 	  else
1012 	    {
1013 	      uid = getuid();
1014 	      pwd_value = _XGetpwuid(uid, pwd_buf);
1015             }
1016 
1017 	  if (pwd_value != NULL)
1018 	    ptr = pwd_value->pw_dir;
1019 	  else
1020 	    ptr = NULL;
1021         }
1022 
1023       if (ptr != NULL)
1024 	{
1025 	  homeDir = XtMalloc (strlen(ptr) + 1);
1026 	  strcpy (homeDir, ptr);
1027 	}
1028       else
1029 	{
1030 	  homeDir = &empty;
1031 	}
1032     }
1033 
1034   _XmProcessUnlock();
1035   return homeDir;
1036 }
1037 
1038 #ifndef LIBDIR
1039 #define LIBDIR "/usr/lib/X11"
1040 #endif
1041 #ifndef INCDIR
1042 #define INCDIR "/usr/include/X11"
1043 #endif
1044 
1045 static XmConst char libdir[] = LIBDIR;
1046 static XmConst char incdir[] = INCDIR;
1047 
1048 /*************************************************************************
1049  *
1050  *   When the locale contains a codeset, the Toolkit's default path fail
1051  *   to search for the directory with only language and territory.
1052  *
1053  *   For example, when locale is "zh_TW.dechanyu", directories searched
1054  *   should be :
1055  *
1056  *   1. zh_TW.dechanyu       (%L)
1057  *   2. zh_TW                (%l_%t)
1058  *   3. zh                   (%l)
1059  *
1060  *************************************************************************/
1061 
1062 static XmConst char XAPPLRES_DEFAULT[] = "\
1063 %%P\
1064 %%S:\
1065 %s/%%L/%%T/%%N/%%P\
1066 %%S:\
1067 %s/%%l_%%t/%%T/%%N/%%P\
1068 %%S:\
1069 %s/%%l/%%T/%%N/%%P\
1070 %%S:\
1071 %s/%%T/%%N/%%P\
1072 %%S:\
1073 %s/%%L/%%T/%%P\
1074 %%S:\
1075 %s/%%l_%%t/%%T/%%P\
1076 %%S:\
1077 %s/%%l/%%T/%%P\
1078 %%S:\
1079 %s/%%T/%%P\
1080 %%S:\
1081 %s/%%T/%%P\
1082 %%S:\
1083 %s/%%P\
1084 %%S:\
1085 %s/%%L/%%T/%%N/%%P\
1086 %%S:\
1087 %s/%%l_%%t/%%T/%%N/%%P\
1088 %%S:\
1089 %s/%%l/%%T/%%N/%%P\
1090 %%S:\
1091 %s/%%T/%%N/%%P\
1092 %%S:\
1093 %s/%%L/%%T/%%P\
1094 %%S:\
1095 %s/%%l_%%t/%%T/%%P\
1096 %%S:\
1097 %s/%%l/%%T/%%P\
1098 %%S:\
1099 %s/%%T/%%P\
1100 %%S:\
1101 %s/%%T/%%P\
1102 %%S";
1103 
1104 static XmConst char PATH_DEFAULT[] = "\
1105 %%P\
1106 %%S:\
1107 %s/%%L/%%T/%%N/%%P\
1108 %%S:\
1109 %s/%%l_%%t/%%T/%%N/%%P\
1110 %%S:\
1111 %s/%%l/%%T/%%N/%%P\
1112 %%S:\
1113 %s/%%T/%%N/%%P\
1114 %%S:\
1115 %s/%%L/%%T/%%P\
1116 %%S:\
1117 %s/%%l_%%t/%%T/%%P\
1118 %%S:\
1119 %s/%%l/%%T/%%P\
1120 %%S:\
1121 %s/%%T/%%P\
1122 %%S:\
1123 %s/%%P\
1124 %%S:\
1125 %s/%%L/%%T/%%N/%%P\
1126 %%S:\
1127 %s/%%l_%%t/%%T/%%N/%%P\
1128 %%S:\
1129 %s/%%l/%%T/%%N/%%P\
1130 %%S:\
1131 %s/%%T/%%N/%%P\
1132 %%S:\
1133 %s/%%L/%%T/%%P\
1134 %%S:\
1135 %s/%%l_%%t/%%T/%%P\
1136 %%S:\
1137 %s/%%l/%%T/%%P\
1138 %%S:\
1139 %s/%%T/%%P\
1140 %%S:\
1141 %s/%%T/%%P\
1142 %%S";
1143 
1144 static XmConst char ABSOLUTE_PATH[] = "\
1145 %P\
1146 %S";
1147 
1148 /*
1149  * buf must be of length MAX_DIR_PATH_LEN
1150  */
1151 static String
GetCurrentDir(String buf)1152 GetCurrentDir(String 	buf)
1153 {
1154     String pwd = getenv ("PWD");
1155     struct stat stat1, stat2;
1156 
1157     if (pwd
1158 	&& stat (pwd, &stat1) == 0
1159 	&& stat (".", &stat2) == 0
1160 	&& stat1.st_dev == stat2.st_dev
1161 	&& stat1.st_ino == stat2.st_ino) {
1162 	/* Use PWD environment variable */
1163 	strcpy(buf, pwd);
1164 	return pwd ;
1165     }
1166 
1167     return getcwd(buf, MAX_DIR_PATH_LEN) ;
1168 }
1169 
1170 #ifdef notdef
1171     /* old way */
1172     String pwd = NULL;
1173 
1174     if ((pwd = getenv("PWD")) != NULL)
1175 	strcpy(buf, pwd);
1176     if (!pwd) pwd = getcwd(buf, MAX_DIR_PATH_LEN)
1177     return pwd ;
1178 #endif
1179 
1180 
1181 /*
1182  * buf must be of length MAX_DIR_PATH_LEN
1183  */
1184 Boolean
_XmOSAbsolutePathName(String path,String * pathRtn,String buf)1185 _XmOSAbsolutePathName(String path, String *pathRtn, String buf)
1186 {
1187     Boolean 	doubleDot = False;
1188 
1189     *pathRtn = path;
1190 
1191     if (path[0] == '/')
1192       return True;
1193 
1194     if (path[0] == '.') {
1195 	if (path[1] == '/')
1196 	  doubleDot = False;
1197 	else if ((path[1] == '.') &&
1198 		 (path[2] == '/'))
1199 	  doubleDot = True;
1200 
1201 	if (GetCurrentDir(buf) != NULL) {
1202 	    if (doubleDot) {
1203 		String filePart, suffixPart;
1204 		_XmOSFindPathParts(buf, &filePart, &suffixPart);
1205 		(void) strcpy(filePart, &path[2]);
1206 	    }
1207 	    else {
1208 		(void) strcat(buf, &path[1]);
1209 	    }
1210 	    *pathRtn = buf;
1211 	    return True;
1212 	}
1213 	else {
1214 	    XmeWarning(NULL, "Cannot find current dir");
1215 	    return True;
1216 	}
1217     }
1218     return False;
1219 }
1220 
1221 String
_XmOSInitPath(String file_name,String env_pathname,Boolean * user_path)1222 _XmOSInitPath(String   file_name,
1223 	      String   env_pathname,
1224 	      Boolean *user_path)
1225 {
1226   String path;
1227   String old_path;
1228   char stackString[MAX_DIR_PATH_LEN];
1229   String homedir = stackString ;
1230   String local_path;
1231 
1232   *user_path = False;
1233 
1234   if (file_name && _XmOSAbsolutePathName(file_name, &file_name, homedir)) {
1235       path = XtNewString(ABSOLUTE_PATH);
1236   }
1237   else
1238     {
1239       local_path = (char *)getenv (env_pathname);
1240       if (local_path  == NULL)
1241 	{
1242 	  homedir = XmeGetHomeDirName();
1243 	  old_path = (char *)getenv ("XAPPLRESDIR");
1244 	  if (old_path == NULL)
1245 	    {
1246 	      path = XtCalloc(1, (9*strlen(homedir) + strlen(PATH_DEFAULT) +
1247 				  8*strlen(libdir) + strlen(incdir) + 1));
1248 	      sprintf(path, PATH_DEFAULT, homedir, homedir, homedir,
1249 		      homedir, homedir, homedir, homedir, homedir, homedir,
1250 		      libdir, libdir, libdir, libdir, libdir, libdir, libdir,
1251 		      libdir, incdir);
1252 	    }
1253 	  else
1254 	    {
1255 	      path = XtCalloc(1, (8*strlen(old_path) + 2*strlen(homedir) +
1256 				  strlen(XAPPLRES_DEFAULT) + 8*strlen(libdir) +
1257 				  strlen(incdir) + 1));
1258 	      sprintf(path, XAPPLRES_DEFAULT,
1259 		      old_path, old_path, old_path, old_path, old_path,
1260 		      old_path, old_path, old_path, homedir, homedir,
1261 		      libdir, libdir, libdir, libdir, libdir, libdir, libdir,
1262 		      libdir, incdir);
1263 	    }
1264 	}
1265       else
1266 	{
1267 	  path = XtMalloc(strlen(local_path) + 1);
1268 	  strcpy (path, local_path);
1269 	  *user_path = True;
1270 	}
1271     }
1272 
1273   return path;
1274 }
1275 
1276 int
XmeMicroSleep(long usecs)1277 XmeMicroSleep(long usecs)
1278 {
1279   struct timeval      timeoutVal;
1280 
1281   /* split the micro seconds in seconds and remainder */
1282   timeoutVal.tv_sec = usecs/1000000;
1283   timeoutVal.tv_usec = usecs - timeoutVal.tv_sec*1000000;
1284 
1285   return Select(0, NULL, NULL, NULL, &timeoutVal);
1286 }
1287 
1288 /************************************************************************
1289  *
1290  *	XmeGetLocalizedString	Map an X11 R5 XPCS string in a locale
1291  *				sensitive XmString.
1292  *
1293  *		reserved	Reserved for future use.
1294  *		widget		The widget id.
1295  *		resource	The resource name.
1296  *		string		The input 8859-1 value.
1297  *
1298  ************************************************************************/
1299 
1300 /*ARGSUSED*/
1301 XmString
XmeGetLocalizedString(char * reserved,Widget widget,char * resource,String string)1302 XmeGetLocalizedString(char *reserved,		/* unused */
1303 		      Widget widget,		/* unused */
1304 		      char *resource,		/* unused */
1305 		      String string)
1306 {
1307   return XmStringCreateLocalized(string);
1308 }
1309 
1310 /************************************************************************
1311  *									*
1312  *    _XmOSBuildFileName						*
1313  *									*
1314  *	Build an absolute file name from a directory and file.		*
1315  *	Handle case where 'file' is already absolute.			*
1316  *	Return value should be freed by XtFree()			*
1317  *									*
1318  ************************************************************************/
1319 
1320 String
_XmOSBuildFileName(String path,String file)1321 _XmOSBuildFileName(String path,
1322 		   String file)
1323 {
1324   String fileName;
1325 
1326   if (file[0] == '/')
1327     {
1328       fileName = XtMalloc (strlen (file) + 1);
1329       strcpy (fileName, file);
1330     }
1331   else
1332     {
1333       fileName = XtMalloc (strlen(path) + strlen (file) + 2);
1334       strcpy (fileName, path);
1335       strcat (fileName, "/");
1336       strcat (fileName, file);
1337     }
1338 
1339   return fileName;
1340 }
1341 
1342 
1343 
1344 /************************************************************
1345  *
1346  *  return poiinter to the file and the suffix
1347  *        /usr/foo/bar.xpm returns &"bar.xpm" and &"xpm"
1348  *
1349  ************************************************************/
1350 
1351 void
_XmOSFindPathParts(String path,String * filenameRtn,String * suffixRtn)1352 _XmOSFindPathParts(String  path,
1353 	      String *filenameRtn,
1354 	      String *suffixRtn)
1355 {
1356   String	filename = path, suffix = NULL;
1357   String	s;
1358   /*
1359    * maybe a problem for I18N - probably: filenames may be multibyte!!!
1360    */
1361 #define FILESEP '/'
1362 #define SUFFIXSEP '.'
1363 
1364   s = path;
1365   while (*s)
1366     {
1367       if (*s == FILESEP)
1368 	{
1369 	  filename = s++;
1370 	}
1371       else if (*s == SUFFIXSEP)
1372 	{
1373 	  suffix = s++;
1374 	}
1375       else
1376 	s++;
1377     }
1378 
1379   if (suffix < filename)
1380     suffix = NULL;
1381 
1382   if ((*filenameRtn = filename) != NULL)
1383     {
1384       if (filename != path)
1385 	(*filenameRtn)++;
1386     }
1387 
1388   if ((*suffixRtn = suffix) != NULL)
1389     (*suffixRtn)++;
1390 }
1391 
1392 
1393 
1394 /************************************************************
1395  *
1396  *  Add _m to the imageName:
1397  *        transform /usr/foo/bar.xpm in /usr/foo/bar_m.xpm
1398  *        or        joe in joe_m
1399  *
1400  ************************************************************/
1401 
1402 void
_XmOSGenerateMaskName(String imageName,String maskNameBuf)1403 _XmOSGenerateMaskName(
1404     String	imageName,
1405     String	maskNameBuf)
1406 {
1407     String 	file, suffix;
1408     int		len;
1409 
1410     _XmOSFindPathParts(imageName, &file, &suffix);
1411 
1412     if (suffix) {
1413 	len = (int)(suffix - imageName) - 1;
1414 	/* point before the '.' */
1415 	suffix--;
1416     }
1417     else
1418       len = strlen(imageName);
1419 
1420     strncpy(maskNameBuf, imageName, len);
1421     maskNameBuf += len;
1422     strcpy(maskNameBuf, "_m");
1423     if (suffix)
1424       strcpy(maskNameBuf+2, suffix);
1425     else
1426       maskNameBuf[2] = '\0';
1427 }
1428 
1429 
1430 
1431 /*ARGSUSED*/
1432 Status
_XmOSGetInitialCharsDirection(XtPointer characters,XmTextType type,XmStringTag locale,unsigned int * num_bytes,XmDirection * direction)1433 _XmOSGetInitialCharsDirection(XtPointer     characters,
1434 			      XmTextType    type,
1435 			      XmStringTag   locale, /* unused */
1436 			      unsigned int *num_bytes,
1437 			      XmDirection  *direction)
1438 {
1439   /* ??? This is a temporary stub implementation. */
1440   switch (type)
1441     {
1442     case XmWIDECHAR_TEXT:
1443       *num_bytes = Wcslen((wchar_t*) characters) * sizeof(wchar_t);
1444       *direction = XmLEFT_TO_RIGHT;
1445       return Success;
1446 
1447     case XmCHARSET_TEXT:
1448     case XmMULTIBYTE_TEXT:
1449       *num_bytes = strlen((char*) characters);
1450       *direction = XmLEFT_TO_RIGHT;
1451       return Success;
1452 
1453     default:
1454       *num_bytes = 0;
1455       *direction = XmDEFAULT_DIRECTION;
1456       return ~Success;
1457     }
1458 }
1459 
1460 /*ARGSUSED*/
1461 XmDirection
_XmOSGetCharDirection(XtPointer character,XmTextType type,XmStringTag locale)1462 _XmOSGetCharDirection(XtPointer   character, /* unused */
1463 		      XmTextType  type,
1464 		      XmStringTag locale) /* unused */
1465 {
1466   /* ??? This is a temporary stub implementation. */
1467   switch (type)
1468     {
1469     case XmWIDECHAR_TEXT:
1470     case XmCHARSET_TEXT:
1471     case XmMULTIBYTE_TEXT:
1472       return XmLEFT_TO_RIGHT;
1473 
1474     default:
1475       return XmDEFAULT_DIRECTION;
1476     }
1477 }
1478 
1479 static int
Wcslen(wchar_t * wcs)1480 Wcslen(wchar_t *wcs)
1481 {
1482   /* Count characters, not bytes. */
1483   wchar_t *ptr = wcs;
1484   if (ptr != NULL)
1485     while (*ptr++)
1486       /*EMPTY*/;
1487 
1488   return (ptr - wcs);
1489 }
1490 
1491 typedef struct XmOSMethodEntryRec {
1492   String    method_id;
1493   XtPointer method;
1494   XtPointer os_data;
1495   XtPointer reserved;   /* for future use - fonts & such?*/
1496 } XmOSMethodEntry;
1497 
1498 
1499 static XmOSMethodEntry method_table[] = {
1500   {
1501     XmMCharDirection,
1502     (XtPointer)_XmOSGetCharDirection,
1503     NULL, NULL
1504   },
1505 
1506   {
1507     XmMInitialCharsDirection,
1508     (XtPointer)_XmOSGetInitialCharsDirection,
1509     NULL, NULL
1510   },
1511 
1512   { NULL, NULL, NULL, NULL}
1513 };
1514 
1515 /****************************************************************
1516  * XmOSGetMethod:
1517  *   get the function that implements the requested method.
1518  ****************************************************************/
1519 
1520 /*ARGSUSED*/
1521 XmOSMethodStatus
XmOSGetMethod(Widget w,String method_id,XtPointer * method,XtPointer * os_data)1522 XmOSGetMethod(Widget w,		/* unused */
1523 	      String method_id,
1524 	      XtPointer *method,
1525 	      XtPointer *os_data)
1526 {
1527   int i;
1528 
1529   if (method == NULL)
1530     return XmOS_METHOD_NULL;
1531 
1532   for (i = 0; method_table[i].method_id; i++)
1533     if (method_id == method_table[i].method_id)
1534       {
1535 	if (*method == NULL || (method_table[i].method != NULL &&
1536 				*method != method_table[i].method))
1537 	  {
1538 	    *method = method_table[i].method;
1539 	    if (os_data) *os_data = method_table[i].os_data;
1540 	    return XmOS_METHOD_REPLACED;
1541 	  }
1542 	else
1543 	  {
1544 	    if (os_data) *os_data = method_table[i].os_data;
1545 	    return XmOS_METHOD_DEFAULTED;
1546 	  }
1547       }
1548 
1549   for (i = 0; method_table[i].method_id; i++)
1550     if (strcmp(method_id, method_table[i].method_id) == 0)
1551       {
1552 	if (*method == NULL || (method_table[i].method != NULL &&
1553 				*method != method_table[i].method))
1554 	  {
1555 	    *method = method_table[i].method;
1556 	    if (os_data) *os_data = method_table[i].os_data;
1557 	    return XmOS_METHOD_REPLACED;
1558 	  }
1559 	else
1560 	  {
1561 	    if (os_data) *os_data = method_table[i].os_data;
1562 	    return XmOS_METHOD_DEFAULTED;
1563 	  }
1564       }
1565 
1566   return XmOS_METHOD_DEFAULTED;
1567 }
1568 
1569 /*
1570  * This routine is used by Label (and LabelG) to determine which
1571  * character in the label string matches the Mnemonic keysym, and
1572  * thus should be underlined.
1573  *
1574  * Parameters:
1575  *	keysym - Specifies the keysym to be converted.
1576  *	locale - Specifies the locale to convert into.  NULL => current locale.
1577  *	buffer - A buffer allocated by the caller to hold the (at most one)
1578  *		multibyte character that corresponds to the keysym.
1579  *
1580  * Return value:
1581  *	The number of bytes written into the buffer.
1582  */
1583 
1584 /*ARGSUSED*/
1585 int
_XmOSKeySymToCharacter(KeySym keysym,char * locale,char * buffer)1586 _XmOSKeySymToCharacter(KeySym keysym,
1587 		       char  *locale,
1588 		       char  *buffer)
1589 {
1590   /*
1591    * This implementation is exceptionally stupid, but works in the
1592    * common case of ISO8859-1 locales and keysyms.
1593    *
1594    * Vendors who use more exotic encodings (e.g. roman8) should
1595    * replace this code with something appropriate.
1596    */
1597 
1598   /* Maybe we should generate a warning for non-Latin 1 encodings */
1599   /* outside the range 0..127? */
1600   *buffer = (keysym & 0xFF);
1601 
1602   return 1;
1603 }
1604 
1605 /* ****************************************************** **
1606 ** Threading stuff. Stuck here to allow easier debugging.
1607 ** ****************************************************** */
1608 /*
1609 static unsigned int _lockCounter = 0;
1610 static unsigned int _unlockCounter = 0;
1611 static int _outstandingLockCounter = 0;
1612 int _debugProcessLocking = 0;
1613 
1614 void _XmProcessLock()
1615 {
1616     _lockCounter++;
1617     _outstandingLockCounter++;
1618 #if defined(XTHREADS) && defined(XUSE_MTSAFE_API)
1619     XtProcessLock();
1620 #endif
1621     if(_debugProcessLocking)
1622     {
1623         fprintf(stderr, "File: %s, line: %d - _XmProcessLock() - _lockCounter = %d, _outstandingLockCounter = %d\n", __FILE__, __LINE__,
1624             _lockCounter, _outstandingLockCounter);
1625     }
1626 }
1627 
1628 
1629 void _XmProcessUnlock()
1630 {
1631     _unlockCounter++;
1632     _outstandingLockCounter--;
1633 #if defined(XTHREADS) && defined(XUSE_MTSAFE_API)
1634     XtProcessUnlock();
1635 #endif
1636     if(_debugProcessLocking)
1637     {
1638         fprintf(stderr, "File: %s, line: %d - _XmProcessUnlock() - _unlockCounter = %d, _outstandingLockCounter = %d\n", __FILE__, __LINE__,
1639             _unlockCounter, _outstandingLockCounter);
1640     }
1641 }
1642 */
1643