1 // $Id: OS_NS_stdlib.cpp 81804 2008-05-29 16:12:07Z vzykov $
3 #include "ace/OS_NS_stdlib.h"
7 "$Id: OS_NS_stdlib.cpp 81804 2008-05-29 16:12:07Z vzykov $")
9 #include "ace/Default_Constants.h"
11 #if !defined (ACE_HAS_INLINED_OSCALLS)
12 # include "ace/OS_NS_stdlib.inl"
13 #endif /* ACE_HAS_INLINED_OSCALLS */
15 #include "ace/OS_Memory.h"
17 #include "ace/OS_NS_unistd.h"
18 #include "ace/OS_NS_ctype.h"
20 #if defined (ACE_LACKS_MKTEMP) \
21 || defined (ACE_LACKS_MKSTEMP) \
22 || defined (ACE_LACKS_REALPATH)
23 # include "ace/OS_NS_stdio.h"
24 # include "ace/OS_NS_sys_stat.h"
25 #endif /* ACE_LACKS_MKTEMP || ACE_LACKS_MKSTEMP || ACE_LACKS_REALPATH */
27 #if defined (ACE_LACKS_MKSTEMP)
28 # include "ace/OS_NS_fcntl.h"
29 # include "ace/OS_NS_ctype.h"
30 # include "ace/OS_NS_sys_time.h"
31 # include "ace/OS_NS_Thread.h"
32 # include "ace/Numeric_Limits.h"
33 #endif /* ACE_LACKS_MKSTEMP */
35 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
37 ACE_EXIT_HOOK
ACE_OS::exit_hook_
= 0;
40 ACE_OS::calloc (size_t elements
, size_t sizeof_elements
)
42 #if !defined (ACE_HAS_WINCE)
43 return ACE_CALLOC_FUNC (elements
, sizeof_elements
);
45 // @@ This will probably not work since it doesn't consider
46 // alignment properly.
47 return ACE_MALLOC_FUNC (elements
* sizeof_elements
);
48 #endif /* ACE_HAS_WINCE */
52 ACE_OS::exit (int status
)
54 ACE_OS_TRACE ("ACE_OS::exit");
56 #if defined (ACE_HAS_NONSTATIC_OBJECT_MANAGER) && !defined (ACE_HAS_WINCE) && !defined (ACE_DOESNT_INSTANTIATE_NONSTATIC_OBJECT_MANAGER)
57 // Shut down the ACE_Object_Manager, if it had registered its exit_hook.
58 // With ACE_HAS_NONSTATIC_OBJECT_MANAGER, the ACE_Object_Manager is
59 // instantiated on the main's stack. ::exit () doesn't destroy it.
62 #endif /* ACE_HAS_NONSTATIC_OBJECT_MANAGER && !ACE_HAS_WINCE && !ACE_DOESNT_INSTANTIATE_NONSTATIC_OBJECT_MANAGER */
64 #if !defined (ACE_HAS_WINCE)
65 # if defined (ACE_WIN32)
66 ::ExitProcess ((UINT
) status
);
69 # endif /* ACE_WIN32 */
71 // @@ This is not exactly the same as ExitProcess. But this is the
72 // closest one I can get.
73 ::TerminateProcess (::GetCurrentProcess (), status
);
74 #endif /* ACE_HAS_WINCE */
78 ACE_OS::free (void *ptr
)
80 ACE_FREE_FUNC (ACE_MALLOC_T (ptr
));
83 // You may be asking yourself, why are we doing this? Well, in winbase.h,
84 // MS didn't follow their normal Api_FunctionA and Api_FunctionW style,
85 // so we have to #undef their define to get access to the unicode version.
86 // And because we don't want to #undef this for the users code, we keep
87 // this method in the .cpp file.
88 #if defined (ACE_WIN32) && defined (UNICODE) && !defined (ACE_USES_TCHAR)
89 #undef GetEnvironmentStrings
90 #endif /* ACE_WIN32 && UNICODE !ACE_USES_TCHAR */
93 ACE_OS::getenvstrings (void)
95 #if defined (ACE_LACKS_ENV)
96 ACE_NOTSUP_RETURN (0);
97 #elif defined (ACE_WIN32)
98 # if defined (ACE_USES_WCHAR)
99 return ::GetEnvironmentStringsW ();
100 # else /* ACE_USES_WCHAR */
101 return ::GetEnvironmentStrings ();
102 # endif /* ACE_USES_WCHAR */
103 #else /* ACE_WIN32 */
104 ACE_NOTSUP_RETURN (0);
105 #endif /* ACE_WIN32 */
108 // Return a dynamically allocated duplicate of <str>, substituting the
109 // environment variables of form $VAR_NAME. Note that the pointer is
110 // allocated with <ACE_OS::malloc> and must be freed by
114 ACE_OS::strenvdup (const ACE_TCHAR
*str
)
116 #if defined (ACE_HAS_WINCE)
117 // WinCE doesn't have environment variables so we just skip it.
118 return ACE_OS::strdup (str
);
119 #elif defined (ACE_LACKS_ENV)
120 ACE_UNUSED_ARG (str
);
121 ACE_NOTSUP_RETURN (0);
123 const ACE_TCHAR
* start
= 0;
124 if ((start
= ACE_OS::strchr (str
, ACE_TEXT ('$'))) != 0)
126 ACE_TCHAR buf
[ACE_DEFAULT_ARGV_BUFSIZ
];
127 size_t var_len
= ACE_OS::strcspn (&start
[1],
128 ACE_TEXT ("$~!#%^&*()-+=\\|/?,.;:'\"`[]{} \t\n\r"));
129 ACE_OS::strncpy (buf
, &start
[1], var_len
);
130 buf
[var_len
++] = ACE_TEXT ('\0');
131 # if defined (ACE_WIN32)
132 // Always use the ACE_TCHAR for Windows.
133 ACE_TCHAR
*temp
= ACE_OS::getenv (buf
);
135 // Use char * for environment on non-Windows.
136 char *temp
= ACE_OS::getenv (ACE_TEXT_ALWAYS_CHAR (buf
));
137 # endif /* ACE_WIN32 */
138 size_t buf_len
= ACE_OS::strlen (str
) + 1;
140 buf_len
+= ACE_OS::strlen (temp
) - var_len
;
141 ACE_TCHAR
* buf_p
= buf
;
142 if (buf_len
> ACE_DEFAULT_ARGV_BUFSIZ
)
145 (ACE_TCHAR
*) ACE_OS::malloc (buf_len
* sizeof (ACE_TCHAR
));
152 ACE_TCHAR
* p
= buf_p
;
153 size_t len
= start
- str
;
154 ACE_OS::strncpy (p
, str
, len
);
158 # if defined (ACE_WIN32)
159 p
= ACE_OS::strecpy (p
, temp
) - 1;
161 p
= ACE_OS::strecpy (p
, ACE_TEXT_CHAR_TO_TCHAR (temp
)) - 1;
162 # endif /* ACE_WIN32 */
166 ACE_OS::strncpy (p
, start
, var_len
);
168 *p
= ACE_TEXT ('\0');
170 ACE_OS::strcpy (p
, &start
[var_len
]);
171 return (buf_p
== buf
) ? ACE_OS::strdup (buf
) : buf_p
;
174 return ACE_OS::strdup (str
);
175 #endif /* ACE_HAS_WINCE */
178 #if !defined (ACE_HAS_ITOA)
180 ACE_OS::itoa_emulation (int value
, char *string
, int radix
)
185 // Short circuit if 0
194 // If negative and base 10, print a - and then do the
197 if (value
< 0 && radix
== 10)
201 ++e
; // Don't overwrite the negative sign.
202 value
= -value
; // Drop negative sign so character selection is correct.
205 // Convert to base <radix>, but in reverse order
209 int mod
= value
% radix
;
210 value
= value
/ radix
;
212 *e
++ = (mod
< 10) ? '0' + mod
: 'a' + mod
- 10;
217 // Now reverse the string to get the correct result
230 #endif /* !ACE_HAS_ITOA */
232 #if defined (ACE_HAS_WCHAR) && defined (ACE_LACKS_ITOW)
234 ACE_OS::itow_emulation (int value
, wchar_t *string
, int radix
)
239 // Short circuit if 0
248 // If negative and base 10, print a - and then do the
251 if (value
< 0 && radix
== 10)
257 // Convert to base <radix>, but in reverse order
261 int mod
= value
% radix
;
262 value
= value
/ radix
;
264 *e
++ = (mod
< 10) ? '0' + mod
: 'a' + mod
- 10;
269 // Now reverse the string to get the correct result
282 #endif /* ACE_HAS_WCHAR && ACE_LACKS_ITOW */
285 ACE_OS::malloc (size_t nbytes
)
287 return ACE_MALLOC_FUNC (nbytes
);
290 #if defined (ACE_LACKS_MKTEMP)
292 ACE_OS::mktemp (ACE_TCHAR
*s
)
294 ACE_OS_TRACE ("ACE_OS::mktemp");
296 // check for null template string failed!
300 ACE_TCHAR
*xxxxxx
= ACE_OS::strstr (s
, ACE_TEXT ("XXXXXX"));
303 // the template string doesn't contain "XXXXXX"!
307 ACE_TCHAR unique_letter
= ACE_TEXT ('a');
310 // Find an unused filename for this process. It is assumed
311 // that the user will open the file immediately after
312 // getting this filename back (so, yes, there is a race
313 // condition if multiple threads in a process use the same
314 // template). This appears to match the behavior of the
315 // SunOS 5.5 mktemp().
316 ACE_OS::sprintf (xxxxxx
,
320 while (ACE_OS::stat (s
, &sb
) >= 0)
322 if (++unique_letter
<= ACE_TEXT ('z'))
323 ACE_OS::sprintf (xxxxxx
,
329 // maximum of 26 unique files per template, per process
330 ACE_OS::sprintf (xxxxxx
, ACE_TEXT ("%s"), ACE_TEXT (""));
338 #endif /* ACE_LACKS_MKTEMP */
341 ACE_OS::realloc (void *ptr
, size_t nbytes
)
343 return ACE_REALLOC_FUNC (ACE_MALLOC_T (ptr
), nbytes
);
346 #if defined (ACE_LACKS_REALPATH) && !defined (ACE_HAS_WINCE)
348 ACE_OS::realpath (const char *file_name
,
351 ACE_OS_TRACE ("ACE_OS::realpath");
355 // Single Unix Specification V3:
356 // Return an error if parameter is a null pointer.
361 if (*file_name
== '\0')
363 // Single Unix Specification V3:
364 // Return an error if the file_name argument points
365 // to an empty string.
372 if (resolved_name
== 0)
374 // Single Unix Specification V3:
375 // Return an error if parameter is a null pointer.
377 // To match glibc realpath() and Win32 _fullpath() behavior,
378 // allocate room for the return value if resolved_name is
380 rpath
= static_cast<char*>(ACE_OS::malloc (PATH_MAX
));
389 rpath
= resolved_name
;
394 if (*file_name
!= '/')
396 // file_name is relative path so CWD needs to be added
397 if (ACE_OS::getcwd (rpath
, PATH_MAX
) == 0)
399 if (resolved_name
== 0)
400 ACE_OS::free (rpath
);
403 dest
= ACE_OS::strchr (rpath
, '\0');
410 #if !defined (ACE_LACKS_SYMLINKS)
411 char expand_buf
[PATH_MAX
]; // Extra buffer needed to expand symbolic links
419 // Skip multiple separators
420 while (*file_name
== '/')
425 // Process one path component
426 while (*file_name
&& *file_name
!= '/')
428 *dest
++ = *file_name
++;
429 if (dest
- rpath
> PATH_MAX
)
431 errno
= ENAMETOOLONG
;
432 if (resolved_name
== 0)
433 ACE_OS::free (rpath
);
438 if (start
== dest
) // Are we done?
440 if (dest
- rpath
> 1)
441 --dest
; // Remove trailing separator if not at root
444 else if (dest
- start
== 1 && *start
== '.')
446 dest
-= 2; // Remove "./"
448 else if (dest
- start
== 2 && *start
== '.' && *(start
+1) == '.')
450 dest
-= 3; // Remove "../"
451 if (dest
> rpath
) // Remove the last path component if not at root
452 while (*--dest
!= '/')
455 # if !defined (ACE_LACKS_SYMLINKS)
461 if (ACE_OS::lstat(rpath
, &st
) < 0)
463 if (resolved_name
== 0)
464 ACE_OS::free (rpath
);
468 // Check if current path is a link
469 if (S_ISLNK (st
.st_mode
))
471 if (++nlinks
> MAXSYMLINKS
)
474 if (resolved_name
== 0)
475 ACE_OS::free (rpath
);
479 char link_buf
[PATH_MAX
];
481 ssize_t link_len
= ACE_OS::readlink (rpath
, link_buf
, PATH_MAX
);
482 int tail_len
= ACE_OS::strlen (file_name
) + 1;
484 // Check if there is room to expand link?
485 if (link_len
+ tail_len
> PATH_MAX
)
487 errno
= ENAMETOOLONG
;
488 if (resolved_name
== 0)
489 ACE_OS::free (rpath
);
493 // Move tail and prefix it with expanded link
494 ACE_OS::memmove (expand_buf
+ link_len
, file_name
, tail_len
);
495 ACE_OS::memcpy (expand_buf
, link_buf
, link_len
);
497 if (*link_buf
== '/') // Absolute link?
501 else // Relative link, remove expanded link component
504 while (*--dest
!= '/')
507 file_name
= expand_buf
; // Source path is now in expand_buf
510 # endif /* ACE_LACKS_SYMLINKS */
517 #endif /* ACE_LACKS_REALPATH && !ACE_HAS_WINCE */
519 #if defined (ACE_LACKS_STRTOL)
521 ACE_OS::strtol_emulation (const char *nptr
, char **endptr
, int base
)
523 register const char *s
= nptr
;
524 register unsigned long acc
;
526 register unsigned long cutoff
;
527 register int neg
= 0, any
, cutlim
;
530 * Skip white space and pick up leading +/- sign if any.
531 * If base is 0, allow 0x for hex and 0 for octal, else
532 * assume decimal; if base is already 16, allow 0x.
536 } while (ACE_OS::ace_isspace(c
));
542 if ((base
== 0 || base
== 16) &&
543 c
== '0' && (*s
== 'x' || *s
== 'X')) {
549 base
= c
== '0' ? 8 : 10;
552 * Compute the cutoff value between legal numbers and illegal
553 * numbers. That is the largest legal value, divided by the
554 * base. An input number that is greater than this value, if
555 * followed by a legal input character, is too big. One that
556 * is equal to this value may be valid or not; the limit
557 * between valid and invalid numbers is then based on the last
558 * digit. For instance, if the range for longs is
559 * [-2147483648..2147483647] and the input base is 10,
560 * cutoff will be set to 214748364 and cutlim to either
561 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
562 * a value > 214748364, or equal but the next digit is > 7 (or 8),
563 * the number is too big, and we will return a range error.
565 * Set any if any `digits' consumed; make it negative to indicate
568 cutoff
= neg
? -(unsigned long)LONG_MIN
: LONG_MAX
;
569 cutlim
= cutoff
% (unsigned long)base
;
570 cutoff
/= (unsigned long)base
;
571 for (acc
= 0, any
= 0;; c
= *s
++) {
572 if (ACE_OS::ace_isdigit(c
))
574 else if (ACE_OS::ace_isalpha(c
))
575 c
-= ACE_OS::ace_isupper(c
) ? 'A' - 10 : 'a' - 10;
580 if (any
< 0 || acc
> cutoff
|| acc
== cutoff
&& c
> cutlim
)
589 acc
= neg
? LONG_MIN
: LONG_MAX
;
594 *endptr
= any
? (char *)s
- 1 : (char *)nptr
;
597 #endif /* ACE_LACKS_STRTOL */
599 #if defined (ACE_LACKS_STRTOUL)
601 ACE_OS::strtoul_emulation (const char *nptr
,
605 register const char *s
= nptr
;
606 register unsigned long acc
;
608 register unsigned long cutoff
;
609 register int neg
= 0, any
, cutlim
;
612 * See strtol for comments as to the logic used.
616 while (ACE_OS::ace_isspace(c
));
624 if ((base
== 0 || base
== 16) &&
625 c
== '0' && (*s
== 'x' || *s
== 'X'))
632 base
= c
== '0' ? 8 : 10;
633 cutoff
= (unsigned long) ULONG_MAX
/ (unsigned long) base
;
634 cutlim
= (unsigned long) ULONG_MAX
% (unsigned long) base
;
636 for (acc
= 0, any
= 0;; c
= *s
++)
638 if (ACE_OS::ace_isdigit(c
))
640 else if (ACE_OS::ace_isalpha(c
))
641 c
-= ACE_OS::ace_isupper(c
) ? 'A' - 10 : 'a' - 10;
646 if (any
< 0 || acc
> cutoff
|| acc
== cutoff
&& c
> cutlim
)
663 *endptr
= any
? (char *) s
- 1 : (char *) nptr
;
666 #endif /* ACE_LACKS_STRTOUL */
668 #if defined (ACE_LACKS_STRTOULL)
670 ACE_OS::strtoull_emulation (const char *nptr
,
674 register const char *s
= nptr
;
675 register ACE_UINT64 acc
;
677 register ACE_UINT64 cutoff
;
678 register int neg
= 0, any
, cutlim
;
681 * See strtol for comments as to the logic used.
685 while (ACE_OS::ace_isspace(c
));
693 if ((base
== 0 || base
== 16) &&
694 c
== '0' && (*s
== 'x' || *s
== 'X'))
701 base
= c
== '0' ? 8 : 10;
703 cutoff
= (ACE_UINT64
) ACE_UINT64_MAX
/ (ACE_UINT64
) base
;
704 cutlim
= (ACE_UINT64
) ACE_UINT64_MAX
% (ACE_UINT64
) base
;
706 for (acc
= 0, any
= 0;; c
= *s
++)
708 if (ACE_OS::ace_isdigit(c
))
710 else if (ACE_OS::ace_isalpha(c
))
711 c
-= ACE_OS::ace_isupper(c
) ? 'A' - 10 : 'a' - 10;
716 if (any
< 0 || acc
> cutoff
|| acc
== cutoff
&& c
> cutlim
)
727 acc
= ACE_UINT64_MAX
;
733 *endptr
= any
? (char *) s
- 1 : (char *) nptr
;
736 #endif /* ACE_LACKS_STRTOULL */
738 #if defined (ACE_LACKS_MKSTEMP)
740 ACE_OS::mkstemp_emulation (ACE_TCHAR
* s
)
745 return ACE_INVALID_HANDLE
;
748 // The "XXXXXX" template to be filled in.
749 ACE_TCHAR
* const t
= ACE_OS::strstr (s
, ACE_TEXT ("XXXXXX"));
754 return ACE_INVALID_HANDLE
;
757 static unsigned int const NUM_RETRIES
= 50;
758 static unsigned int const NUM_CHARS
= 6; // Do not change!
760 // Use ACE_Time_Value::msec(ACE_UINT64&) as opposed to
761 // ACE_Time_Value::msec(void) to avoid truncation.
764 // Use a const ACE_Time_Value to resolve ambiguity between
765 // ACE_Time_Value::msec (long) and ACE_Time_Value::msec(ACE_UINT64&) const.
766 ACE_Time_Value
const now
= ACE_OS::gettimeofday();
769 // Add the process and thread ids to ensure uniqueness.
770 msec
+= ACE_OS::getpid();
771 msec
+= (size_t) ACE_OS::thr_self();
773 // ACE_thread_t may be a char* (returned by ACE_OS::thr_self()) so
774 // we need to use a C-style cast as a catch-all in order to use a
775 // static_cast<> to an integral type.
776 ACE_RANDR_TYPE seed
= static_cast<ACE_RANDR_TYPE
> (msec
);
778 // We only care about UTF-8 / ASCII characters in generated
779 // filenames. A UTF-16 or UTF-32 character could potentially cause
780 // a very large space to be searched in the below do/while() loop,
781 // greatly slowing down this mkstemp() implementation. It is more
782 // practical to limit the search space to UTF-8 / ASCII characters
783 // (i.e. 127 characters).
785 // Note that we can't make this constant static since the compiler
786 // may not inline the return value of ACE_Numeric_Limits::max(),
787 // meaning multiple threads could potentially initialize this value
789 float const MAX_VAL
=
790 static_cast<float> (ACE_Numeric_Limits
<char>::max ());
792 // Use high-order bits rather than low-order ones (e.g. rand() %
793 // MAX_VAL). See Numerical Recipes in C: The Art of Scientific
794 // Computing (William H. Press, Brian P. Flannery, Saul
795 // A. Teukolsky, William T. Vetterling; New York: Cambridge
796 // University Press, 1992 (2nd ed., p. 277).
798 // e.g.: MAX_VAL * rand() / (RAND_MAX + 1.0)
800 // Factor out the constant coefficient.
801 float const coefficient
=
802 static_cast<float> (MAX_VAL
/ (RAND_MAX
+ 1.0f
));
804 // @@ These nested loops may be ineffecient. Improvements are
806 for (unsigned int i
= 0; i
< NUM_RETRIES
; ++i
)
808 for (unsigned int n
= 0; n
< NUM_CHARS
; ++n
)
812 // This do/while() loop allows this alphanumeric character
813 // selection to work for EBCDIC, as well.
816 r
= static_cast<ACE_TCHAR
> (coefficient
* ACE_OS::rand_r (seed
));
818 while (!ACE_OS::ace_isalnum (r
));
823 static int const perms
=
824 #if defined (ACE_WIN32)
825 0; /* Do not share while open. */
827 0600; /* S_IRUSR | S_IWUSR */
828 #endif /* ACE_WIN32 */
830 // Create the file with the O_EXCL bit set to ensure that we're
831 // not subject to a symbolic link attack.
833 // Note that O_EXCL is subject to a race condition over NFS
835 ACE_HANDLE
const handle
= ACE_OS::open (s
,
836 O_RDWR
| O_CREAT
| O_EXCL
,
839 if (handle
!= ACE_INVALID_HANDLE
)
843 errno
= EEXIST
; // Couldn't create a unique temporary file.
844 return ACE_INVALID_HANDLE
;
846 #endif /* ACE_LACKS_MKSTEMP */
848 #if !defined (ACE_HAS_GETPROGNAME) && !defined (ACE_HAS_SETPROGNAME)
849 static const char *__progname
= "";
850 #endif /* !ACE_HAS_GETPROGNAME && !ACE_HAS_SETPROGNAME */
852 #if !defined (ACE_HAS_GETPROGNAME)
854 ACE_OS::getprogname_emulation ()
858 #endif /* !ACE_HAS_GETPROGNAME */
860 #if !defined (ACE_HAS_SETPROGNAME)
862 ACE_OS::setprogname_emulation (const char* progname
)
864 const char *p
= ACE_OS::strrchr (progname
, '/');
868 __progname
= progname
;
870 #endif /* !ACE_HAS_SETPROGNAME */
872 ACE_END_VERSIONED_NAMESPACE_DECL