diff options
author | Michael J. Spencer <bigcheesegs@gmail.com> | 2010-11-29 18:16:10 +0000 |
---|---|---|
committer | Michael J. Spencer <bigcheesegs@gmail.com> | 2010-11-29 18:16:10 +0000 |
commit | 1f6efa3996dd1929fbc129203ce5009b620e6969 (patch) | |
tree | 6b782914982f90d3a983bcefef98b8ef68ab2961 /include/llvm/Support | |
parent | 9363f739cdc3bd02e8516a25de0090f52ae12fbb (diff) | |
download | external_llvm-1f6efa3996dd1929fbc129203ce5009b620e6969.tar.gz external_llvm-1f6efa3996dd1929fbc129203ce5009b620e6969.tar.bz2 external_llvm-1f6efa3996dd1929fbc129203ce5009b620e6969.zip |
Merge System into Support.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@120298 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include/llvm/Support')
43 files changed, 4876 insertions, 18 deletions
diff --git a/include/llvm/Support/AIXDataTypesFix.h b/include/llvm/Support/AIXDataTypesFix.h new file mode 100644 index 0000000000..8dbf02f282 --- /dev/null +++ b/include/llvm/Support/AIXDataTypesFix.h @@ -0,0 +1,25 @@ +//===-- llvm/System/AIXDataTypesFix.h - Fix datatype defs ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file overrides default system-defined types and limits which cannot be +// done in DataTypes.h.in because it is processed by autoheader first, which +// comments out any #undef statement +// +//===----------------------------------------------------------------------===// + +// No include guards desired! + +#ifndef SUPPORT_DATATYPES_H +#error "AIXDataTypesFix.h must only be included via DataTypes.h!" +#endif + +// GCC is strict about defining large constants: they must have LL modifier. +// These will be defined properly at the end of DataTypes.h +#undef INT64_MAX +#undef INT64_MIN diff --git a/include/llvm/Support/Alarm.h b/include/llvm/Support/Alarm.h new file mode 100644 index 0000000000..7c284167c2 --- /dev/null +++ b/include/llvm/Support/Alarm.h @@ -0,0 +1,51 @@ +//===- llvm/System/Alarm.h - Alarm Generation support ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides an operating system independent interface to alarm(2) +// type functionality. The Alarm class allows a one-shot alarm to be set up +// at some number of seconds in the future. When the alarm triggers, a method +// is called to process the event +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_ALARM_H +#define LLVM_SYSTEM_ALARM_H + +namespace llvm { +namespace sys { + + /// This function registers an alarm to trigger some number of \p seconds in + /// the future. When that time arrives, the AlarmStatus function will begin + /// to return 1 instead of 0. The user must poll the status of the alarm by + /// making occasional calls to AlarmStatus. If the user sends an interrupt + /// signal, AlarmStatus will begin returning -1, even if the alarm event + /// occurred. + /// @returns nothing + void SetupAlarm( + unsigned seconds ///< Number of seconds in future when alarm arrives + ); + + /// This function terminates the alarm previously set up + /// @returns nothing + void TerminateAlarm(); + + /// This function acquires the status of the alarm. + /// @returns -1=cancelled, 0=untriggered, 1=triggered + int AlarmStatus(); + + /// Sleep for n seconds. Warning: mixing calls to Sleep() and other *Alarm + /// calls may be a bad idea on some platforms (source: Linux man page). + /// @returns nothing. + void Sleep(unsigned n); + + +} // End sys namespace +} // End llvm namespace + +#endif diff --git a/include/llvm/Support/Allocator.h b/include/llvm/Support/Allocator.h index f3c53d14e5..b080e222a1 100644 --- a/include/llvm/Support/Allocator.h +++ b/include/llvm/Support/Allocator.h @@ -16,7 +16,7 @@ #include "llvm/Support/AlignOf.h" #include "llvm/Support/MathExtras.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include <algorithm> #include <cassert> #include <cstdlib> diff --git a/include/llvm/Support/Atomic.h b/include/llvm/Support/Atomic.h new file mode 100644 index 0000000000..914bda9db3 --- /dev/null +++ b/include/llvm/Support/Atomic.h @@ -0,0 +1,39 @@ +//===- llvm/System/Atomic.h - Atomic Operations -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys atomic operations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_ATOMIC_H +#define LLVM_SYSTEM_ATOMIC_H + +#include "llvm/Support/DataTypes.h" + +namespace llvm { + namespace sys { + void MemoryFence(); + +#ifdef _MSC_VER + typedef long cas_flag; +#else + typedef uint32_t cas_flag; +#endif + cas_flag CompareAndSwap(volatile cas_flag* ptr, + cas_flag new_value, + cas_flag old_value); + cas_flag AtomicIncrement(volatile cas_flag* ptr); + cas_flag AtomicDecrement(volatile cas_flag* ptr); + cas_flag AtomicAdd(volatile cas_flag* ptr, cas_flag val); + cas_flag AtomicMul(volatile cas_flag* ptr, cas_flag val); + cas_flag AtomicDiv(volatile cas_flag* ptr, cas_flag val); + } +} + +#endif diff --git a/include/llvm/Support/COFF.h b/include/llvm/Support/COFF.h index 46fe269a23..673925593e 100644 --- a/include/llvm/Support/COFF.h +++ b/include/llvm/Support/COFF.h @@ -23,7 +23,7 @@ #ifndef LLVM_SUPPORT_WIN_COFF_H #define LLVM_SUPPORT_WIN_COFF_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include <cstring> namespace llvm { diff --git a/include/llvm/Support/ConstantRange.h b/include/llvm/Support/ConstantRange.h index 792b4107b1..96e770951f 100644 --- a/include/llvm/Support/ConstantRange.h +++ b/include/llvm/Support/ConstantRange.h @@ -33,7 +33,7 @@ #define LLVM_SUPPORT_CONSTANT_RANGE_H #include "llvm/ADT/APInt.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/include/llvm/Support/DataTypes.h.cmake b/include/llvm/Support/DataTypes.h.cmake new file mode 100644 index 0000000000..72c451873c --- /dev/null +++ b/include/llvm/Support/DataTypes.h.cmake @@ -0,0 +1,189 @@ +/*===-- include/Support/DataTypes.h - Define fixed size types -----*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file contains definitions to figure out the size of _HOST_ data types.*| +|* This file is important because different host OS's define different macros,*| +|* which makes portability tough. This file exports the following *| +|* definitions: *| +|* *| +|* [u]int(32|64)_t : typedefs for signed and unsigned 32/64 bit system types*| +|* [U]INT(8|16|32|64)_(MIN|MAX) : Constants for the min and max values. *| +|* *| +|* No library is required when using these functinons. *| +|* *| +|*===----------------------------------------------------------------------===*/ + +/* Please leave this file C-compatible. */ + +#ifndef SUPPORT_DATATYPES_H +#define SUPPORT_DATATYPES_H + +#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H} +#cmakedefine HAVE_INTTYPES_H ${HAVE_INTTYPES_H} +#cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H} +#cmakedefine HAVE_UINT64_T ${HAVE_UINT64_T} +#cmakedefine HAVE_U_INT64_T ${HAVE_U_INT64_T} + +#ifdef __cplusplus +#include <cmath> +#else +#include <math.h> +#endif + +#ifndef _MSC_VER + +/* Note that this header's correct operation depends on __STDC_LIMIT_MACROS + being defined. We would define it here, but in order to prevent Bad Things + happening when system headers or C++ STL headers include stdint.h before we + define it here, we define it on the g++ command line (in Makefile.rules). */ +#if !defined(__STDC_LIMIT_MACROS) +# error "Must #define __STDC_LIMIT_MACROS before #including Support/DataTypes.h" +#endif + +#if !defined(__STDC_CONSTANT_MACROS) +# error "Must #define __STDC_CONSTANT_MACROS before " \ + "#including Support/DataTypes.h" +#endif + +/* Note that <inttypes.h> includes <stdint.h>, if this is a C99 system. */ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#ifdef _AIX +#include "llvm/Support/AIXDataTypesFix.h" +#endif + +/* Handle incorrect definition of uint64_t as u_int64_t */ +#ifndef HAVE_UINT64_T +#ifdef HAVE_U_INT64_T +typedef u_int64_t uint64_t; +#else +# error "Don't have a definition for uint64_t on this platform" +#endif +#endif + +#ifdef _OpenBSD_ +#define INT8_MAX 127 +#define INT8_MIN -128 +#define UINT8_MAX 255 +#define INT16_MAX 32767 +#define INT16_MIN -32768 +#define UINT16_MAX 65535 +#define INT32_MAX 2147483647 +#define INT32_MIN -2147483648 +#define UINT32_MAX 4294967295U +#endif + +#else /* _MSC_VER */ +/* Visual C++ doesn't provide standard integer headers, but it does provide + built-in data types. */ +#include <stdlib.h> +#include <stddef.h> +#include <sys/types.h> +#ifdef __cplusplus +#include <cmath> +#else +#include <math.h> +#endif +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed int ssize_t; +#ifndef INT8_MAX +# define INT8_MAX 127 +#endif +#ifndef INT8_MIN +# define INT8_MIN -128 +#endif +#ifndef UINT8_MAX +# define UINT8_MAX 255 +#endif +#ifndef INT16_MAX +# define INT16_MAX 32767 +#endif +#ifndef INT16_MIN +# define INT16_MIN -32768 +#endif +#ifndef UINT16_MAX +# define UINT16_MAX 65535 +#endif +#ifndef INT32_MAX +# define INT32_MAX 2147483647 +#endif +#ifndef INT32_MIN +# define INT32_MIN -2147483648 +#endif +#ifndef UINT32_MAX +# define UINT32_MAX 4294967295U +#endif +/* Certain compatibility updates to VC++ introduce the `cstdint' + * header, which defines the INT*_C macros. On default installs they + * are absent. */ +#ifndef INT8_C +# define INT8_C(C) C##i8 +#endif +#ifndef UINT8_C +# define UINT8_C(C) C##ui8 +#endif +#ifndef INT16_C +# define INT16_C(C) C##i16 +#endif +#ifndef UINT16_C +# define UINT16_C(C) C##ui16 +#endif +#ifndef INT32_C +# define INT32_C(C) C##i32 +#endif +#ifndef UINT32_C +# define UINT32_C(C) C##ui32 +#endif +#ifndef INT64_C +# define INT64_C(C) C##i64 +#endif +#ifndef UINT64_C +# define UINT64_C(C) C##ui64 +#endif +#endif /* _MSC_VER */ + +/* Set defaults for constants which we cannot find. */ +#if !defined(INT64_MAX) +# define INT64_MAX 9223372036854775807LL +#endif +#if !defined(INT64_MIN) +# define INT64_MIN ((-INT64_MAX)-1) +#endif +#if !defined(UINT64_MAX) +# define UINT64_MAX 0xffffffffffffffffULL +#endif + +#if __GNUC__ > 3 +#define END_WITH_NULL __attribute__((sentinel)) +#else +#define END_WITH_NULL +#endif + +#ifndef HUGE_VALF +#define HUGE_VALF (float)HUGE_VAL +#endif + +#endif /* SUPPORT_DATATYPES_H */ diff --git a/include/llvm/Support/DataTypes.h.in b/include/llvm/Support/DataTypes.h.in new file mode 100644 index 0000000000..6537f3010f --- /dev/null +++ b/include/llvm/Support/DataTypes.h.in @@ -0,0 +1,111 @@ +/*===-- include/System/DataTypes.h - Define fixed size types -----*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file contains definitions to figure out the size of _HOST_ data types.*| +|* This file is important because different host OS's define different macros,*| +|* which makes portability tough. This file exports the following *| +|* definitions: *| +|* *| +|* [u]int(32|64)_t : typedefs for signed and unsigned 32/64 bit system types*| +|* [U]INT(8|16|32|64)_(MIN|MAX) : Constants for the min and max values. *| +|* *| +|* No library is required when using these functions. *| +|* *| +|*===----------------------------------------------------------------------===*/ + +/* Please leave this file C-compatible. */ + +#ifndef SUPPORT_DATATYPES_H +#define SUPPORT_DATATYPES_H + +#undef HAVE_SYS_TYPES_H +#undef HAVE_INTTYPES_H +#undef HAVE_STDINT_H +#undef HAVE_UINT64_T +#undef HAVE_U_INT64_T + +#ifdef __cplusplus +#include <cmath> +#else +#include <math.h> +#endif + +/* Note that this header's correct operation depends on __STDC_LIMIT_MACROS + being defined. We would define it here, but in order to prevent Bad Things + happening when system headers or C++ STL headers include stdint.h before we + define it here, we define it on the g++ command line (in Makefile.rules). */ +#if !defined(__STDC_LIMIT_MACROS) +# error "Must #define __STDC_LIMIT_MACROS before #including System/DataTypes.h" +#endif + +#if !defined(__STDC_CONSTANT_MACROS) +# error "Must #define __STDC_CONSTANT_MACROS before " \ + "#including System/DataTypes.h" +#endif + +/* Note that <inttypes.h> includes <stdint.h>, if this is a C99 system. */ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#ifdef _AIX +#include "llvm/System/AIXDataTypesFix.h" +#endif + +/* Handle incorrect definition of uint64_t as u_int64_t */ +#ifndef HAVE_UINT64_T +#ifdef HAVE_U_INT64_T +typedef u_int64_t uint64_t; +#else +# error "Don't have a definition for uint64_t on this platform" +#endif +#endif + +#ifdef _OpenBSD_ +#define INT8_MAX 127 +#define INT8_MIN -128 +#define UINT8_MAX 255 +#define INT16_MAX 32767 +#define INT16_MIN -32768 +#define UINT16_MAX 65535 +#define INT32_MAX 2147483647 +#define INT32_MIN -2147483648 +#define UINT32_MAX 4294967295U +#endif + +/* Set defaults for constants which we cannot find. */ +#if !defined(INT64_MAX) +# define INT64_MAX 9223372036854775807LL +#endif +#if !defined(INT64_MIN) +# define INT64_MIN ((-INT64_MAX)-1) +#endif +#if !defined(UINT64_MAX) +# define UINT64_MAX 0xffffffffffffffffULL +#endif + +#if __GNUC__ > 3 +#define END_WITH_NULL __attribute__((sentinel)) +#else +#define END_WITH_NULL +#endif + +#ifndef HUGE_VALF +#define HUGE_VALF (float)HUGE_VAL +#endif + +#endif /* SUPPORT_DATATYPES_H */ diff --git a/include/llvm/Support/Disassembler.h b/include/llvm/Support/Disassembler.h new file mode 100644 index 0000000000..6d1cc0fdcb --- /dev/null +++ b/include/llvm/Support/Disassembler.h @@ -0,0 +1,35 @@ +//===- llvm/Support/Disassembler.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the necessary glue to call external disassembler +// libraries. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_DISASSEMBLER_H +#define LLVM_SYSTEM_DISASSEMBLER_H + +#include "llvm/Support/DataTypes.h" +#include <string> + +namespace llvm { +namespace sys { + +/// This function returns true, if there is possible to use some external +/// disassembler library. False otherwise. +bool hasDisassembler(); + +/// This function provides some "glue" code to call external disassembler +/// libraries. +std::string disassembleBuffer(uint8_t* start, size_t length, uint64_t pc = 0); + +} +} + +#endif // LLVM_SYSTEM_DISASSEMBLER_H diff --git a/include/llvm/Support/DynamicLibrary.h b/include/llvm/Support/DynamicLibrary.h new file mode 100644 index 0000000000..745b8f8b5b --- /dev/null +++ b/include/llvm/Support/DynamicLibrary.h @@ -0,0 +1,86 @@ +//===-- llvm/System/DynamicLibrary.h - Portable Dynamic Library -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the sys::DynamicLibrary class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_DYNAMIC_LIBRARY_H +#define LLVM_SYSTEM_DYNAMIC_LIBRARY_H + +#include <string> + +namespace llvm { +namespace sys { + + /// This class provides a portable interface to dynamic libraries which also + /// might be known as shared libraries, shared objects, dynamic shared + /// objects, or dynamic link libraries. Regardless of the terminology or the + /// operating system interface, this class provides a portable interface that + /// allows dynamic libraries to be loaded and searched for externally + /// defined symbols. This is typically used to provide "plug-in" support. + /// It also allows for symbols to be defined which don't live in any library, + /// but rather the main program itself, useful on Windows where the main + /// executable cannot be searched. + class DynamicLibrary { + DynamicLibrary(); // DO NOT IMPLEMENT + public: + /// This function allows a library to be loaded without instantiating a + /// DynamicLibrary object. Consequently, it is marked as being permanent + /// and will only be unloaded when the program terminates. This returns + /// false on success or returns true and fills in *ErrMsg on failure. + /// @brief Open a dynamic library permanently. + /// + /// NOTE: This function is not thread safe. + /// + static bool LoadLibraryPermanently(const char *filename, + std::string *ErrMsg = 0); + + /// This function will search through all previously loaded dynamic + /// libraries for the symbol \p symbolName. If it is found, the addressof + /// that symbol is returned. If not, null is returned. Note that this will + /// search permanently loaded libraries (LoadLibraryPermanently) as well + /// as ephemerally loaded libraries (constructors). + /// @throws std::string on error. + /// @brief Search through libraries for address of a symbol + /// + /// NOTE: This function is not thread safe. + /// + static void *SearchForAddressOfSymbol(const char *symbolName); + + /// @brief Convenience function for C++ophiles. + /// + /// NOTE: This function is not thread safe. + /// + static void *SearchForAddressOfSymbol(const std::string &symbolName) { + return SearchForAddressOfSymbol(symbolName.c_str()); + } + + /// This functions permanently adds the symbol \p symbolName with the + /// value \p symbolValue. These symbols are searched before any + /// libraries. + /// @brief Add searchable symbol/value pair. + /// + /// NOTE: This function is not thread safe. + /// + static void AddSymbol(const char *symbolName, void *symbolValue); + + /// @brief Convenience function for C++ophiles. + /// + /// NOTE: This function is not thread safe. + /// + static void AddSymbol(const std::string &symbolName, void *symbolValue) { + AddSymbol(symbolName.c_str(), symbolValue); + } + }; + +} // End sys namespace +} // End llvm namespace + +#endif // LLVM_SYSTEM_DYNAMIC_LIBRARY_H diff --git a/include/llvm/Support/ELF.h b/include/llvm/Support/ELF.h index bf5ab2dc3b..93e7304fc5 100644 --- a/include/llvm/Support/ELF.h +++ b/include/llvm/Support/ELF.h @@ -20,7 +20,7 @@ #ifndef LLVM_SUPPORT_ELF_H #define LLVM_SUPPORT_ELF_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include <cstring> namespace llvm { diff --git a/include/llvm/Support/Endian.h b/include/llvm/Support/Endian.h index dc88a129e1..f62eab0702 100644 --- a/include/llvm/Support/Endian.h +++ b/include/llvm/Support/Endian.h @@ -15,8 +15,8 @@ #define LLVM_SUPPORT_ENDIAN_H #include "llvm/Config/config.h" -#include "llvm/System/Host.h" -#include "llvm/System/SwapByteOrder.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/SwapByteOrder.h" #include "llvm/Support/type_traits.h" namespace llvm { diff --git a/include/llvm/Support/Errno.h b/include/llvm/Support/Errno.h new file mode 100644 index 0000000000..6e292ba626 --- /dev/null +++ b/include/llvm/Support/Errno.h @@ -0,0 +1,34 @@ +//===- llvm/System/Errno.h - Portable+convenient errno handling -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares some portable and convenient functions to deal with errno. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_ERRNO_H +#define LLVM_SYSTEM_ERRNO_H + +#include <string> + +namespace llvm { +namespace sys { + +/// Returns a string representation of the errno value, using whatever +/// thread-safe variant of strerror() is available. Be sure to call this +/// immediately after the function that set errno, or errno may have been +/// overwritten by an intervening call. +std::string StrError(); + +/// Like the no-argument version above, but uses \p errnum instead of errno. +std::string StrError(int errnum); + +} // namespace sys +} // namespace llvm + +#endif // LLVM_SYSTEM_ERRNO_H diff --git a/include/llvm/Support/FEnv.h b/include/llvm/Support/FEnv.h new file mode 100644 index 0000000000..042e43928b --- /dev/null +++ b/include/llvm/Support/FEnv.h @@ -0,0 +1,56 @@ +//===- llvm/System/FEnv.h - Host floating-point exceptions ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides an operating system independent interface to +// floating-point exception interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_FENV_H +#define LLVM_SYSTEM_FENV_H + +#include "llvm/Config/config.h" +#include <cerrno> +#ifdef HAVE_FENV_H +#include <fenv.h> +#endif + +// FIXME: Clang's #include handling apparently doesn't work for libstdc++'s +// fenv.h; see PR6907 for details. +#if defined(__clang__) && defined(_GLIBCXX_FENV_H) +#undef HAVE_FENV_H +#endif + +namespace llvm { +namespace sys { + +/// llvm_fenv_clearexcept - Clear the floating-point exception state. +static inline void llvm_fenv_clearexcept() { +#ifdef HAVE_FENV_H + feclearexcept(FE_ALL_EXCEPT); +#endif + errno = 0; +} + +/// llvm_fenv_testexcept - Test if a floating-point exception was raised. +static inline bool llvm_fenv_testexcept() { + int errno_val = errno; + if (errno_val == ERANGE || errno_val == EDOM) + return true; +#ifdef HAVE_FENV_H + if (fetestexcept(FE_ALL_EXCEPT & ~FE_INEXACT)) + return true; +#endif + return false; +} + +} // End sys namespace +} // End llvm namespace + +#endif diff --git a/include/llvm/Support/FileUtilities.h b/include/llvm/Support/FileUtilities.h index d0dd4a7598..748ce7cea7 100644 --- a/include/llvm/Support/FileUtilities.h +++ b/include/llvm/Support/FileUtilities.h @@ -15,7 +15,7 @@ #ifndef LLVM_SUPPORT_FILEUTILITIES_H #define LLVM_SUPPORT_FILEUTILITIES_H -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" namespace llvm { diff --git a/include/llvm/Support/GraphWriter.h b/include/llvm/Support/GraphWriter.h index 2d29e525fb..7573ef0dc9 100644 --- a/include/llvm/Support/GraphWriter.h +++ b/include/llvm/Support/GraphWriter.h @@ -26,7 +26,7 @@ #include "llvm/Support/DOTGraphTraits.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/GraphTraits.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" #include <vector> #include <cassert> diff --git a/include/llvm/Support/Host.h b/include/llvm/Support/Host.h new file mode 100644 index 0000000000..4fbf5c177c --- /dev/null +++ b/include/llvm/Support/Host.h @@ -0,0 +1,66 @@ +//===- llvm/System/Host.h - Host machine characteristics --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Methods for querying the nature of the host machine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_HOST_H +#define LLVM_SYSTEM_HOST_H + +#include "llvm/ADT/StringMap.h" +#include <string> + +namespace llvm { +namespace sys { + + inline bool isLittleEndianHost() { + union { + int i; + char c; + }; + i = 1; + return c; + } + + inline bool isBigEndianHost() { + return !isLittleEndianHost(); + } + + /// getHostTriple() - Return the target triple of the running + /// system. + /// + /// The target triple is a string in the format of: + /// CPU_TYPE-VENDOR-OPERATING_SYSTEM + /// or + /// CPU_TYPE-VENDOR-KERNEL-OPERATING_SYSTEM + std::string getHostTriple(); + + /// getHostCPUName - Get the LLVM name for the host CPU. The particular format + /// of the name is target dependent, and suitable for passing as -mcpu to the + /// target which matches the host. + /// + /// \return - The host CPU name, or empty if the CPU could not be determined. + std::string getHostCPUName(); + + /// getHostCPUFeatures - Get the LLVM names for the host CPU features. + /// The particular format of the names are target dependent, and suitable for + /// passing as -mattr to the target which matches the host. + /// + /// \param Features - A string mapping feature names to either + /// true (if enabled) or false (if disabled). This routine makes no guarantees + /// about exactly which features may appear in this map, except that they are + /// all valid LLVM feature names. + /// + /// \return - True on success. + bool getHostCPUFeatures(StringMap<bool> &Features); +} +} + +#endif diff --git a/include/llvm/Support/IncludeFile.h b/include/llvm/Support/IncludeFile.h new file mode 100644 index 0000000000..42abb2d7a1 --- /dev/null +++ b/include/llvm/Support/IncludeFile.h @@ -0,0 +1,79 @@ +//===- llvm/System/IncludeFile.h - Ensure Linking Of Library ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the FORCE_DEFINING_FILE_TO_BE_LINKED and DEFINE_FILE_FOR +// macros. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_INCLUDEFILE_H +#define LLVM_SYSTEM_INCLUDEFILE_H + +/// This macro is the public interface that IncludeFile.h exports. This gives +/// us the option to implement the "link the definition" capability in any +/// manner that we choose. All header files that depend on a specific .cpp +/// file being linked at run time should use this macro instead of the +/// IncludeFile class directly. +/// +/// For example, foo.h would use:<br/> +/// <tt>FORCE_DEFINING_FILE_TO_BE_LINKED(foo)</tt><br/> +/// +/// And, foo.cp would use:<br/> +/// <tt>DEFINING_FILE_FOR(foo)</tt><br/> +#ifdef __GNUC__ +// If the `used' attribute is available, use it to create a variable +// with an initializer that will force the linking of the defining file. +#define FORCE_DEFINING_FILE_TO_BE_LINKED(name) \ + namespace llvm { \ + extern const char name ## LinkVar; \ + __attribute__((used)) static const char *const name ## LinkObj = \ + &name ## LinkVar; \ + } +#else +// Otherwise use a constructor call. +#define FORCE_DEFINING_FILE_TO_BE_LINKED(name) \ + namespace llvm { \ + extern const char name ## LinkVar; \ + static const IncludeFile name ## LinkObj ( &name ## LinkVar ); \ + } +#endif + +/// This macro is the counterpart to FORCE_DEFINING_FILE_TO_BE_LINKED. It should +/// be used in a .cpp file to define the name referenced in a header file that +/// will cause linkage of the .cpp file. It should only be used at extern level. +#define DEFINING_FILE_FOR(name) \ + namespace llvm { const char name ## LinkVar = 0; } + +namespace llvm { + +/// This class is used in the implementation of FORCE_DEFINING_FILE_TO_BE_LINKED +/// macro to make sure that the implementation of a header file is included +/// into a tool that uses the header. This is solely +/// to overcome problems linking .a files and not getting the implementation +/// of compilation units we need. This is commonly an issue with the various +/// Passes but also occurs elsewhere in LLVM. We like to use .a files because +/// they link faster and provide the smallest executables. However, sometimes +/// those executables are too small, if the program doesn't reference something +/// that might be needed, especially by a loaded share object. This little class +/// helps to resolve that problem. The basic strategy is to use this class in +/// a header file and pass the address of a variable to the constructor. If the +/// variable is defined in the header file's corresponding .cpp file then all +/// tools/libraries that \#include the header file will require the .cpp as +/// well. +/// For example:<br/> +/// <tt>extern int LinkMyCodeStub;</tt><br/> +/// <tt>static IncludeFile LinkMyModule(&LinkMyCodeStub);</tt><br/> +/// @brief Class to ensure linking of corresponding object file. +struct IncludeFile { + explicit IncludeFile(const void *); +}; + +} + +#endif diff --git a/include/llvm/Support/LICENSE.TXT b/include/llvm/Support/LICENSE.TXT new file mode 100644 index 0000000000..3479b3fd74 --- /dev/null +++ b/include/llvm/Support/LICENSE.TXT @@ -0,0 +1,6 @@ +LLVM System Interface Library +------------------------------------------------------------------------------- +The LLVM System Interface Library is licensed under the Illinois Open Source +License and has the following additional copyright: + +Copyright (C) 2004 eXtensible Systems, Inc. diff --git a/include/llvm/Support/MachO.h b/include/llvm/Support/MachO.h index 964ac6a845..69043b6c79 100644 --- a/include/llvm/Support/MachO.h +++ b/include/llvm/Support/MachO.h @@ -14,7 +14,7 @@ #ifndef LLVM_SUPPORT_MACHO_H #define LLVM_SUPPORT_MACHO_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" // NOTE: The enums in this file are intentially named to be different than those // in the headers in /usr/include/mach (on darwin systems) to avoid conflicts diff --git a/include/llvm/Support/ManagedStatic.h b/include/llvm/Support/ManagedStatic.h index a6b3341c16..53e73ad35f 100644 --- a/include/llvm/Support/ManagedStatic.h +++ b/include/llvm/Support/ManagedStatic.h @@ -14,8 +14,8 @@ #ifndef LLVM_SUPPORT_MANAGED_STATIC_H #define LLVM_SUPPORT_MANAGED_STATIC_H -#include "llvm/System/Atomic.h" -#include "llvm/System/Threading.h" +#include "llvm/Support/Atomic.h" +#include "llvm/Support/Threading.h" namespace llvm { diff --git a/include/llvm/Support/MathExtras.h b/include/llvm/Support/MathExtras.h index 1b58b3f83c..6740786dec 100644 --- a/include/llvm/Support/MathExtras.h +++ b/include/llvm/Support/MathExtras.h @@ -14,7 +14,7 @@ #ifndef LLVM_SUPPORT_MATHEXTRAS_H #define LLVM_SUPPORT_MATHEXTRAS_H -#include "llvm/System/SwapByteOrder.h" +#include "llvm/Support/SwapByteOrder.h" namespace llvm { diff --git a/include/llvm/Support/Memory.h b/include/llvm/Support/Memory.h new file mode 100644 index 0000000000..9b0df31ab0 --- /dev/null +++ b/include/llvm/Support/Memory.h @@ -0,0 +1,96 @@ +//===- llvm/System/Memory.h - Memory Support --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::Memory class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_MEMORY_H +#define LLVM_SYSTEM_MEMORY_H + +#include "llvm/Support/DataTypes.h" +#include <string> + +namespace llvm { +namespace sys { + + /// This class encapsulates the notion of a memory block which has an address + /// and a size. It is used by the Memory class (a friend) as the result of + /// various memory allocation operations. + /// @see Memory + /// @brief Memory block abstraction. + class MemoryBlock { + public: + MemoryBlock() : Address(0), Size(0) { } + MemoryBlock(void *addr, size_t size) : Address(addr), Size(size) { } + void *base() const { return Address; } + size_t size() const { return Size; } + private: + void *Address; ///< Address of first byte of memory area + size_t Size; ///< Size, in bytes of the memory area + friend class Memory; + }; + + /// This class provides various memory handling functions that manipulate + /// MemoryBlock instances. + /// @since 1.4 + /// @brief An abstraction for memory operations. + class Memory { + public: + /// This method allocates a block of Read/Write/Execute memory that is + /// suitable for executing dynamically generated code (e.g. JIT). An + /// attempt to allocate \p NumBytes bytes of virtual memory is made. + /// \p NearBlock may point to an existing allocation in which case + /// an attempt is made to allocate more memory near the existing block. + /// + /// On success, this returns a non-null memory block, otherwise it returns + /// a null memory block and fills in *ErrMsg. + /// + /// @brief Allocate Read/Write/Execute memory. + static MemoryBlock AllocateRWX(size_t NumBytes, + const MemoryBlock *NearBlock, + std::string *ErrMsg = 0); + + /// This method releases a block of Read/Write/Execute memory that was + /// allocated with the AllocateRWX method. It should not be used to + /// release any memory block allocated any other way. + /// + /// On success, this returns false, otherwise it returns true and fills + /// in *ErrMsg. + /// @brief Release Read/Write/Execute memory. + static bool ReleaseRWX(MemoryBlock &block, std::string *ErrMsg = 0); + + + /// InvalidateInstructionCache - Before the JIT can run a block of code + /// that has been emitted it must invalidate the instruction cache on some + /// platforms. + static void InvalidateInstructionCache(const void *Addr, size_t Len); + + /// setExecutable - Before the JIT can run a block of code, it has to be + /// given read and executable privilege. Return true if it is already r-x + /// or the system is able to change its previlege. + static bool setExecutable (MemoryBlock &M, std::string *ErrMsg = 0); + + /// setWritable - When adding to a block of code, the JIT may need + /// to mark a block of code as RW since the protections are on page + /// boundaries, and the JIT internal allocations are not page aligned. + static bool setWritable (MemoryBlock &M, std::string *ErrMsg = 0); + + /// setRangeExecutable - Mark the page containing a range of addresses + /// as executable. + static bool setRangeExecutable(const void *Addr, size_t Size); + + /// setRangeWritable - Mark the page containing a range of addresses + /// as writable. + static bool setRangeWritable(const void *Addr, size_t Size); + }; +} +} + +#endif diff --git a/include/llvm/Support/MemoryBuffer.h b/include/llvm/Support/MemoryBuffer.h index f29ddd1fea..aaa49f5479 100644 --- a/include/llvm/Support/MemoryBuffer.h +++ b/include/llvm/Support/MemoryBuffer.h @@ -15,7 +15,7 @@ #define LLVM_SUPPORT_MEMORYBUFFER_H #include "llvm/ADT/StringRef.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include <string> namespace llvm { diff --git a/include/llvm/Support/MemoryObject.h b/include/llvm/Support/MemoryObject.h index e193ca2f2b..dec0f134b3 100644 --- a/include/llvm/Support/MemoryObject.h +++ b/include/llvm/Support/MemoryObject.h @@ -10,7 +10,7 @@ #ifndef MEMORYOBJECT_H #define MEMORYOBJECT_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/include/llvm/Support/Mutex.h b/include/llvm/Support/Mutex.h new file mode 100644 index 0000000000..edd258d2fc --- /dev/null +++ b/include/llvm/Support/Mutex.h @@ -0,0 +1,154 @@ +//===- llvm/System/Mutex.h - Mutex Operating System Concept -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::Mutex class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_MUTEX_H +#define LLVM_SYSTEM_MUTEX_H + +#include "llvm/Support/Threading.h" +#include <cassert> + +namespace llvm +{ + namespace sys + { + /// @brief Platform agnostic Mutex class. + class MutexImpl + { + /// @name Constructors + /// @{ + public: + + /// Initializes the lock but doesn't acquire it. if \p recursive is set + /// to false, the lock will not be recursive which makes it cheaper but + /// also more likely to deadlock (same thread can't acquire more than + /// once). + /// @brief Default Constructor. + explicit MutexImpl(bool recursive = true); + + /// Releases and removes the lock + /// @brief Destructor + ~MutexImpl(); + + /// @} + /// @name Methods + /// @{ + public: + + /// Attempts to unconditionally acquire the lock. If the lock is held by + /// another thread, this method will wait until it can acquire the lock. + /// @returns false if any kind of error occurs, true otherwise. + /// @brief Unconditionally acquire the lock. + bool acquire(); + + /// Attempts to release the lock. If the lock is held by the current + /// thread, the lock is released allowing other threads to acquire the + /// lock. + /// @returns false if any kind of error occurs, true otherwise. + /// @brief Unconditionally release the lock. + bool release(); + + /// Attempts to acquire the lock without blocking. If the lock is not + /// available, this function returns false quickly (without blocking). If + /// the lock is available, it is acquired. + /// @returns false if any kind of error occurs or the lock is not + /// available, true otherwise. + /// @brief Try to acquire the lock. + bool tryacquire(); + + //@} + /// @name Platform Dependent Data + /// @{ + private: + void* data_; ///< We don't know what the data will be + + /// @} + /// @name Do Not Implement + /// @{ + private: + MutexImpl(const MutexImpl & original); + void operator=(const MutexImpl &); + /// @} + }; + + + /// SmartMutex - A mutex with a compile time constant parameter that + /// indicates whether this mutex should become a no-op when we're not + /// running in multithreaded mode. + template<bool mt_only> + class SmartMutex : public MutexImpl { + unsigned acquired; + bool recursive; + public: + explicit SmartMutex(bool rec = true) : + MutexImpl(rec), acquired(0), recursive(rec) { } + + bool acquire() { + if (!mt_only || llvm_is_multithreaded()) { + return MutexImpl::acquire(); + } else { + // Single-threaded debugging code. This would be racy in + // multithreaded mode, but provides not sanity checks in single + // threaded mode. + assert((recursive || acquired == 0) && "Lock already acquired!!"); + ++acquired; + return true; + } + } + + bool release() { + if (!mt_only || llvm_is_multithreaded()) { + return MutexImpl::release(); + } else { + // Single-threaded debugging code. This would be racy in + // multithreaded mode, but provides not sanity checks in single + // threaded mode. + assert(((recursive && acquired) || (acquired == 1)) && + "Lock not acquired before release!"); + --acquired; + return true; + } + } + + bool tryacquire() { + if (!mt_only || llvm_is_multithreaded()) + return MutexImpl::tryacquire(); + else return true; + } + + private: + SmartMutex(const SmartMutex<mt_only> & original); + void operator=(const SmartMutex<mt_only> &); + }; + + /// Mutex - A standard, always enforced mutex. + typedef SmartMutex<false> Mutex; + + template<bool mt_only> + class SmartScopedLock { + SmartMutex<mt_only>& mtx; + + public: + SmartScopedLock(SmartMutex<mt_only>& m) : mtx(m) { + mtx.acquire(); + } + + ~SmartScopedLock() { + mtx.release(); + } + }; + + typedef SmartScopedLock<false> ScopedLock; + } +} + +#endif diff --git a/include/llvm/Support/MutexGuard.h b/include/llvm/Support/MutexGuard.h index 9958b97a3e..cd13bfe6ee 100644 --- a/include/llvm/Support/MutexGuard.h +++ b/include/llvm/Support/MutexGuard.h @@ -15,7 +15,7 @@ #ifndef LLVM_SUPPORT_MUTEXGUARD_H #define LLVM_SUPPORT_MUTEXGUARD_H -#include "llvm/System/Mutex.h" +#include "llvm/Support/Mutex.h" namespace llvm { /// Instances of this class acquire a given Mutex Lock when constructed and diff --git a/include/llvm/Support/Path.h b/include/llvm/Support/Path.h new file mode 100644 index 0000000000..7d5c297c95 --- /dev/null +++ b/include/llvm/Support/Path.h @@ -0,0 +1,738 @@ +//===- llvm/System/Path.h - Path Operating System Concept -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::Path class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_PATH_H +#define LLVM_SYSTEM_PATH_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/TimeValue.h" +#include <set> +#include <string> +#include <vector> + +namespace llvm { +namespace sys { + + /// This structure provides basic file system information about a file. It + /// is patterned after the stat(2) Unix operating system call but made + /// platform independent and eliminates many of the unix-specific fields. + /// However, to support llvm-ar, the mode, user, and group fields are + /// retained. These pertain to unix security and may not have a meaningful + /// value on non-Unix platforms. However, the other fields should + /// always be applicable on all platforms. The structure is filled in by + /// the PathWithStatus class. + /// @brief File status structure + class FileStatus { + public: + uint64_t fileSize; ///< Size of the file in bytes + TimeValue modTime; ///< Time of file's modification + uint32_t mode; ///< Mode of the file, if applicable + uint32_t user; ///< User ID of owner, if applicable + uint32_t group; ///< Group ID of owner, if applicable + uint64_t uniqueID; ///< A number to uniquely ID this file + bool isDir : 1; ///< True if this is a directory. + bool isFile : 1; ///< True if this is a file. + + FileStatus() : fileSize(0), modTime(0,0), mode(0777), user(999), + group(999), uniqueID(0), isDir(false), isFile(false) { } + + TimeValue getTimestamp() const { return modTime; } + uint64_t getSize() const { return fileSize; } + uint32_t getMode() const { return mode; } + uint32_t getUser() const { return user; } + uint32_t getGroup() const { return group; } + uint64_t getUniqueID() const { return uniqueID; } + }; + + /// This class provides an abstraction for the path to a file or directory + /// in the operating system's filesystem and provides various basic operations + /// on it. Note that this class only represents the name of a path to a file + /// or directory which may or may not be valid for a given machine's file + /// system. The class is patterned after the java.io.File class with various + /// extensions and several omissions (not relevant to LLVM). A Path object + /// ensures that the path it encapsulates is syntactically valid for the + /// operating system it is running on but does not ensure correctness for + /// any particular file system. That is, a syntactically valid path might + /// specify path components that do not exist in the file system and using + /// such a Path to act on the file system could produce errors. There is one + /// invalid Path value which is permitted: the empty path. The class should + /// never allow a syntactically invalid non-empty path name to be assigned. + /// Empty paths are required in order to indicate an error result in some + /// situations. If the path is empty, the isValid operation will return + /// false. All operations will fail if isValid is false. Operations that + /// change the path will either return false if it would cause a syntactically + /// invalid path name (in which case the Path object is left unchanged) or + /// throw an std::string exception indicating the error. The methods are + /// grouped into four basic categories: Path Accessors (provide information + /// about the path without accessing disk), Disk Accessors (provide + /// information about the underlying file or directory), Path Mutators + /// (change the path information, not the disk), and Disk Mutators (change + /// the disk file/directory referenced by the path). The Disk Mutator methods + /// all have the word "disk" embedded in their method name to reinforce the + /// notion that the operation modifies the file system. + /// @since 1.4 + /// @brief An abstraction for operating system paths. + class Path { + /// @name Constructors + /// @{ + public: + /// Construct a path to the root directory of the file system. The root + /// directory is a top level directory above which there are no more + /// directories. For example, on UNIX, the root directory is /. On Windows + /// it is file:///. Other operating systems may have different notions of + /// what the root directory is or none at all. In that case, a consistent + /// default root directory will be used. + static Path GetRootDirectory(); + + /// Construct a path to a unique temporary directory that is created in + /// a "standard" place for the operating system. The directory is + /// guaranteed to be created on exit from this function. If the directory + /// cannot be created, the function will throw an exception. + /// @returns an invalid path (empty) on error + /// @param ErrMsg Optional place for an error message if an error occurs + /// @brief Constrct a path to an new, unique, existing temporary + /// directory. + static Path GetTemporaryDirectory(std::string* ErrMsg = 0); + + /// Construct a vector of sys::Path that contains the "standard" system + /// library paths suitable for linking into programs. + /// @brief Construct a path to the system library directory + static void GetSystemLibraryPaths(std::vector<sys::Path>& Paths); + + /// Construct a vector of sys::Path that contains the "standard" bitcode + /// library paths suitable for linking into an llvm program. This function + /// *must* return the value of LLVM_LIB_SEARCH_PATH as well as the value + /// of LLVM_LIBDIR. It also must provide the System library paths as + /// returned by GetSystemLibraryPaths. + /// @see GetSystemLibraryPaths + /// @brief Construct a list of directories in which bitcode could be + /// found. + static void GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths); + + /// Find the path to a library using its short name. Use the system + /// dependent library paths to locate the library. + /// @brief Find a library. + static Path FindLibrary(std::string& short_name); + + /// Construct a path to the default LLVM configuration directory. The + /// implementation must ensure that this is a well-known (same on many + /// systems) directory in which llvm configuration files exist. For + /// example, on Unix, the /etc/llvm directory has been selected. + /// @brief Construct a path to the default LLVM configuration directory + static Path GetLLVMDefaultConfigDir(); + + /// Construct a path to the LLVM installed configuration directory. The + /// implementation must ensure that this refers to the "etc" directory of + /// the LLVM installation. This is the location where configuration files + /// will be located for a particular installation of LLVM on a machine. + /// @brief Construct a path to the LLVM installed configuration directory + static Path GetLLVMConfigDir(); + + /// Construct a path to the current user's home directory. The + /// implementation must use an operating system specific mechanism for + /// determining the user's home directory. For example, the environment + /// variable "HOME" could be used on Unix. If a given operating system + /// does not have the concept of a user's home directory, this static + /// constructor must provide the same result as GetRootDirectory. + /// @brief Construct a path to the current user's "home" directory + static Path GetUserHomeDirectory(); + + /// Construct a path to the current directory for the current process. + /// @returns The current working directory. + /// @brief Returns the current working directory. + static Path GetCurrentDirectory(); + + /// Return the suffix commonly used on file names that contain an + /// executable. + /// @returns The executable file suffix for the current platform. + /// @brief Return the executable file suffix. + static StringRef GetEXESuffix(); + + /// Return the suffix commonly used on file names that contain a shared + /// object, shared archive, or dynamic link library. Such files are + /// linked at runtime into a process and their code images are shared + /// between processes. + /// @returns The dynamic link library suffix for the current platform. + /// @brief Return the dynamic link library suffix. + static StringRef GetDLLSuffix(); + + /// GetMainExecutable - Return the path to the main executable, given the + /// value of argv[0] from program startup and the address of main itself. + /// In extremis, this function may fail and return an empty path. + static Path GetMainExecutable(const char *argv0, void *MainAddr); + + /// This is one of the very few ways in which a path can be constructed + /// with a syntactically invalid name. The only *legal* invalid name is an + /// empty one. Other invalid names are not permitted. Empty paths are + /// provided so that they can be used to indicate null or error results in + /// other lib/System functionality. + /// @brief Construct an empty (and invalid) path. + Path() : path() {} + Path(const Path &that) : path(that.path) {} + + /// This constructor will accept a char* or std::string as a path. No + /// checking is done on this path to determine if it is valid. To + /// determine validity of the path, use the isValid method. + /// @param p The path to assign. + /// @brief Construct a Path from a string. + explicit Path(StringRef p); + + /// This constructor will accept a character range as a path. No checking + /// is done on this path to determine if it is valid. To determine + /// validity of the path, use the isValid method. + /// @param StrStart A pointer to the first character of the path name + /// @param StrLen The length of the path name at StrStart + /// @brief Construct a Path from a string. + Path(const char *StrStart, unsigned StrLen); + + /// @} + /// @name Operators + /// @{ + public: + /// Makes a copy of \p that to \p this. + /// @returns \p this + /// @brief Assignment Operator + Path &operator=(const Path &that) { + path = that.path; + return *this; + } + + /// Makes a copy of \p that to \p this. + /// @param that A StringRef denoting the path + /// @returns \p this + /// @brief Assignment Operator + Path &operator=(StringRef that); + + /// Compares \p this Path with \p that Path for equality. + /// @returns true if \p this and \p that refer to the same thing. + /// @brief Equality Operator + bool operator==(const Path &that) const; + + /// Compares \p this Path with \p that Path for inequality. + /// @returns true if \p this and \p that refer to different things. + /// @brief Inequality Operator + bool operator!=(const Path &that) const { return !(*this == that); } + + /// Determines if \p this Path is less than \p that Path. This is required + /// so that Path objects can be placed into ordered collections (e.g. + /// std::map). The comparison is done lexicographically as defined by + /// the std::string::compare method. + /// @returns true if \p this path is lexicographically less than \p that. + /// @brief Less Than Operator + bool operator<(const Path& that) const; + + /// @} + /// @name Path Accessors + /// @{ + public: + /// This function will use an operating system specific algorithm to + /// determine if the current value of \p this is a syntactically valid + /// path name for the operating system. The path name does not need to + /// exist, validity is simply syntactical. Empty paths are always invalid. + /// @returns true iff the path name is syntactically legal for the + /// host operating system. + /// @brief Determine if a path is syntactically valid or not. + bool isValid() const; + + /// This function determines if the contents of the path name are empty. + /// That is, the path name has a zero length. This does NOT determine if + /// if the file is empty. To get the length of the file itself, Use the + /// PathWithStatus::getFileStatus() method and then the getSize() method + /// on the returned FileStatus object. + /// @returns true iff the path is empty. + /// @brief Determines if the path name is empty (invalid). + bool isEmpty() const { return path.empty(); } + + /// This function returns the last component of the path name. The last + /// component is the file or directory name occuring after the last + /// directory separator. If no directory separator is present, the entire + /// path name is returned (i.e. same as toString). + /// @returns StringRef containing the last component of the path name. + /// @brief Returns the last component of the path name. + StringRef getLast() const; + + /// This function strips off the path and suffix of the file or directory + /// name and returns just the basename. For example /a/foo.bar would cause + /// this function to return "foo". + /// @returns StringRef containing the basename of the path + /// @brief Get the base name of the path + StringRef getBasename() const; + + /// This function strips off the suffix of the path beginning with the + /// path separator ('/' on Unix, '\' on Windows) and returns the result. + StringRef getDirname() const; + + /// This function strips off the path and basename(up to and + /// including the last dot) of the file or directory name and + /// returns just the suffix. For example /a/foo.bar would cause + /// this function to return "bar". + /// @returns StringRef containing the suffix of the path + /// @brief Get the suffix of the path + StringRef getSuffix() const; + + /// Obtain a 'C' string for the path name. + /// @returns a 'C' string containing the path name. + /// @brief Returns the path as a C string. + const char *c_str() const { return path.c_str(); } + const std::string &str() const { return path; } + + + /// size - Return the length in bytes of this path name. + size_t size() const { return path.size(); } + + /// empty - Returns true if the path is empty. + unsigned empty() const { return path.empty(); } + + /// @} + /// @name Disk Accessors + /// @{ + public: + /// This function determines if the path name is absolute, as opposed to + /// relative. + /// @brief Determine if the path is absolute. + bool isAbsolute() const; + + /// This function determines if the path name is absolute, as opposed to + /// relative. + /// @brief Determine if the path is absolute. + static bool isAbsolute(const char *NameStart, unsigned NameLen); + + /// This function opens the file associated with the path name provided by + /// the Path object and reads its magic number. If the magic number at the + /// start of the file matches \p magic, true is returned. In all other + /// cases (file not found, file not accessible, etc.) it returns false. + /// @returns true if the magic number of the file matches \p magic. + /// @brief Determine if file has a specific magic number + bool hasMagicNumber(StringRef magic) const; + + /// This function retrieves the first \p len bytes of the file associated + /// with \p this. These bytes are returned as the "magic number" in the + /// \p Magic parameter. + /// @returns true if the Path is a file and the magic number is retrieved, + /// false otherwise. + /// @brief Get the file's magic number. + bool getMagicNumber(std::string& Magic, unsigned len) const; + + /// This function determines if the path name in the object references an + /// archive file by looking at its magic number. + /// @returns true if the file starts with the magic number for an archive + /// file. + /// @brief Determine if the path references an archive file. + bool isArchive() const; + + /// This function determines if the path name in the object references an + /// LLVM Bitcode file by looking at its magic number. + /// @returns true if the file starts with the magic number for LLVM + /// bitcode files. + /// @brief Determine if the path references a bitcode file. + bool isBitcodeFile() const; + + /// This function determines if the path name in the object references a + /// native Dynamic Library (shared library, shared object) by looking at + /// the file's magic number. The Path object must reference a file, not a + /// directory. + /// @returns true if the file starts with the magic number for a native + /// shared library. + /// @brief Determine if the path references a dynamic library. + bool isDynamicLibrary() const; + + /// This function determines if the path name in the object references a + /// native object file by looking at it's magic number. The term object + /// file is defined as "an organized collection of separate, named + /// sequences of binary data." This covers the obvious file formats such + /// as COFF and ELF, but it also includes llvm ir bitcode, archives, + /// libraries, etc... + /// @returns true if the file starts with the magic number for an object + /// file. + /// @brief Determine if the path references an object file. + bool isObjectFile() const; + + /// This function determines if the path name references an existing file + /// or directory in the file system. + /// @returns true if the pathname references an existing file or + /// directory. + /// @brief Determines if the path is a file or directory in + /// the file system. + bool exists() const; + + /// This function determines if the path name references an + /// existing directory. + /// @returns true if the pathname references an existing directory. + /// @brief Determines if the path is a directory in the file system. + bool isDirectory() const; + + /// This function determines if the path name references an + /// existing symbolic link. + /// @returns true if the pathname references an existing symlink. + /// @brief Determines if the path is a symlink in the file system. + bool isSymLink() const; + + /// This function determines if the path name references a readable file + /// or directory in the file system. This function checks for + /// the existence and readability (by the current program) of the file + /// or directory. + /// @returns true if the pathname references a readable file. + /// @brief Determines if the path is a readable file or directory + /// in the file system. + bool canRead() const; + + /// This function determines if the path name references a writable file + /// or directory in the file system. This function checks for the + /// existence and writability (by the current program) of the file or + /// directory. + /// @returns true if the pathname references a writable file. + /// @brief Determines if the path is a writable file or directory + /// in the file system. + bool canWrite() const; + + /// This function checks that what we're trying to work only on a regular + /// file. Check for things like /dev/null, any block special file, or + /// other things that aren't "regular" regular files. + /// @returns true if the file is S_ISREG. + /// @brief Determines if the file is a regular file + bool isRegularFile() const; + + /// This function determines if the path name references an executable + /// file in the file system. This function checks for the existence and + /// executability (by the current program) of the file. + /// @returns true if the pathname references an executable file. + /// @brief Determines if the path is an executable file in the file + /// system. + bool canExecute() const; + + /// This function builds a list of paths that are the names of the + /// files and directories in a directory. + /// @returns true if an error occurs, true otherwise + /// @brief Build a list of directory's contents. + bool getDirectoryContents( + std::set<Path> &paths, ///< The resulting list of file & directory names + std::string* ErrMsg ///< Optional place to return an error message. + ) const; + + /// @} + /// @name Path Mutators + /// @{ + public: + /// The path name is cleared and becomes empty. This is an invalid + /// path name but is the *only* invalid path name. This is provided + /// so that path objects can be used to indicate the lack of a + /// valid path being found. + /// @brief Make the path empty. + void clear() { path.clear(); } + + /// This method sets the Path object to \p unverified_path. This can fail + /// if the \p unverified_path does not pass the syntactic checks of the + /// isValid() method. If verification fails, the Path object remains + /// unchanged and false is returned. Otherwise true is returned and the + /// Path object takes on the path value of \p unverified_path + /// @returns true if the path was set, false otherwise. + /// @param unverified_path The path to be set in Path object. + /// @brief Set a full path from a StringRef + bool set(StringRef unverified_path); + + /// One path component is removed from the Path. If only one component is + /// present in the path, the Path object becomes empty. If the Path object + /// is empty, no change is made. + /// @returns false if the path component could not be removed. + /// @brief Removes the last directory component of the Path. + bool eraseComponent(); + + /// The \p component is added to the end of the Path if it is a legal + /// name for the operating system. A directory separator will be added if + /// needed. + /// @returns false if the path component could not be added. + /// @brief Appends one path component to the Path. + bool appendComponent(StringRef component); + + /// A period and the \p suffix are appended to the end of the pathname. + /// The precondition for this function is that the Path reference a file + /// name (i.e. isFile() returns true). If the Path is not a file, no + /// action is taken and the function returns false. If the path would + /// become invalid for the host operating system, false is returned. When + /// the \p suffix is empty, no action is performed. + /// @returns false if the suffix could not be added, true if it was. + /// @brief Adds a period and the \p suffix to the end of the pathname. + bool appendSuffix(StringRef suffix); + + /// The suffix of the filename is erased. The suffix begins with and + /// includes the last . character in the filename after the last directory + /// separator and extends until the end of the name. If no . character is + /// after the last directory separator, then the file name is left + /// unchanged (i.e. it was already without a suffix) but the function + /// returns false. + /// @returns false if there was no suffix to remove, true otherwise. + /// @brief Remove the suffix from a path name. + bool eraseSuffix(); + + /// The current Path name is made unique in the file system. Upon return, + /// the Path will have been changed to make a unique file in the file + /// system or it will not have been changed if the current path name is + /// already unique. + /// @throws std::string if an unrecoverable error occurs. + /// @brief Make the current path name unique in the file system. + bool makeUnique( bool reuse_current /*= true*/, std::string* ErrMsg ); + + /// The current Path name is made absolute by prepending the + /// current working directory if necessary. + void makeAbsolute(); + + /// @} + /// @name Disk Mutators + /// @{ + public: + /// This method attempts to make the file referenced by the Path object + /// available for reading so that the canRead() method will return true. + /// @brief Make the file readable; + bool makeReadableOnDisk(std::string* ErrMsg = 0); + + /// This method attempts to make the file referenced by the Path object + /// available for writing so that the canWrite() method will return true. + /// @brief Make the file writable; + bool makeWriteableOnDisk(std::string* ErrMsg = 0); + + /// This method attempts to make the file referenced by the Path object + /// available for execution so that the canExecute() method will return + /// true. + /// @brief Make the file readable; + bool makeExecutableOnDisk(std::string* ErrMsg = 0); + + /// This method allows the last modified time stamp and permission bits + /// to be set on the disk object referenced by the Path. + /// @throws std::string if an error occurs. + /// @returns true on error. + /// @brief Set the status information. + bool setStatusInfoOnDisk(const FileStatus &SI, + std::string *ErrStr = 0) const; + + /// This method attempts to create a directory in the file system with the + /// same name as the Path object. The \p create_parents parameter controls + /// whether intermediate directories are created or not. if \p + /// create_parents is true, then an attempt will be made to create all + /// intermediate directories, as needed. If \p create_parents is false, + /// then only the final directory component of the Path name will be + /// created. The created directory will have no entries. + /// @returns true if the directory could not be created, false otherwise + /// @brief Create the directory this Path refers to. + bool createDirectoryOnDisk( + bool create_parents = false, ///< Determines whether non-existent + ///< directory components other than the last one (the "parents") + ///< are created or not. + std::string* ErrMsg = 0 ///< Optional place to put error messages. + ); + + /// This method attempts to create a file in the file system with the same + /// name as the Path object. The intermediate directories must all exist + /// at the time this method is called. Use createDirectoriesOnDisk to + /// accomplish that. The created file will be empty upon return from this + /// function. + /// @returns true if the file could not be created, false otherwise. + /// @brief Create the file this Path refers to. + bool createFileOnDisk( + std::string* ErrMsg = 0 ///< Optional place to put error messages. + ); + + /// This is like createFile except that it creates a temporary file. A + /// unique temporary file name is generated based on the contents of + /// \p this before the call. The new name is assigned to \p this and the + /// file is created. Note that this will both change the Path object + /// *and* create the corresponding file. This function will ensure that + /// the newly generated temporary file name is unique in the file system. + /// @returns true if the file couldn't be created, false otherwise. + /// @brief Create a unique temporary file + bool createTemporaryFileOnDisk( + bool reuse_current = false, ///< When set to true, this parameter + ///< indicates that if the current file name does not exist then + ///< it will be used without modification. + std::string* ErrMsg = 0 ///< Optional place to put error messages + ); + + /// This method renames the file referenced by \p this as \p newName. The + /// file referenced by \p this must exist. The file referenced by + /// \p newName does not need to exist. + /// @returns true on error, false otherwise + /// @brief Rename one file as another. + bool renamePathOnDisk(const Path& newName, std::string* ErrMsg); + + /// This method attempts to destroy the file or directory named by the + /// last component of the Path. If the Path refers to a directory and the + /// \p destroy_contents is false, an attempt will be made to remove just + /// the directory (the final Path component). If \p destroy_contents is + /// true, an attempt will be made to remove the entire contents of the + /// directory, recursively. If the Path refers to a file, the + /// \p destroy_contents parameter is ignored. + /// @param destroy_contents Indicates whether the contents of a destroyed + /// @param Err An optional string to receive an error message. + /// directory should also be destroyed (recursively). + /// @returns false if the file/directory was destroyed, true on error. + /// @brief Removes the file or directory from the filesystem. + bool eraseFromDisk(bool destroy_contents = false, + std::string *Err = 0) const; + + + /// MapInFilePages - This is a low level system API to map in the file + /// that is currently opened as FD into the current processes' address + /// space for read only access. This function may return null on failure + /// or if the system cannot provide the following constraints: + /// 1) The pages must be valid after the FD is closed, until + /// UnMapFilePages is called. + /// 2) Any padding after the end of the file must be zero filled, if + /// present. + /// 3) The pages must be contiguous. + /// + /// This API is not intended for general use, clients should use + /// MemoryBuffer::getFile instead. + static const char *MapInFilePages(int FD, uint64_t FileSize); + + /// UnMapFilePages - Free pages mapped into the current process by + /// MapInFilePages. + /// + /// This API is not intended for general use, clients should use + /// MemoryBuffer::getFile instead. + static void UnMapFilePages(const char *Base, uint64_t FileSize); + + /// @} + /// @name Data + /// @{ + protected: + // Our win32 implementation relies on this string being mutable. + mutable std::string path; ///< Storage for the path name. + + + /// @} + }; + + /// This class is identical to Path class except it allows you to obtain the + /// file status of the Path as well. The reason for the distinction is one of + /// efficiency. First, the file status requires additional space and the space + /// is incorporated directly into PathWithStatus without an additional malloc. + /// Second, obtaining status information is an expensive operation on most + /// operating systems so we want to be careful and explicity about where we + /// allow this operation in LLVM. + /// @brief Path with file status class. + class PathWithStatus : public Path { + /// @name Constructors + /// @{ + public: + /// @brief Default constructor + PathWithStatus() : Path(), status(), fsIsValid(false) {} + + /// @brief Copy constructor + PathWithStatus(const PathWithStatus &that) + : Path(static_cast<const Path&>(that)), status(that.status), + fsIsValid(that.fsIsValid) {} + + /// This constructor allows construction from a Path object + /// @brief Path constructor + PathWithStatus(const Path &other) + : Path(other), status(), fsIsValid(false) {} + + /// This constructor will accept a char* or std::string as a path. No + /// checking is done on this path to determine if it is valid. To + /// determine validity of the path, use the isValid method. + /// @brief Construct a Path from a string. + explicit PathWithStatus( + StringRef p ///< The path to assign. + ) : Path(p), status(), fsIsValid(false) {} + + /// This constructor will accept a character range as a path. No checking + /// is done on this path to determine if it is valid. To determine + /// validity of the path, use the isValid method. + /// @brief Construct a Path from a string. + explicit PathWithStatus( + const char *StrStart, ///< Pointer to the first character of the path + unsigned StrLen ///< Length of the path. + ) : Path(StrStart, StrLen), status(), fsIsValid(false) {} + + /// Makes a copy of \p that to \p this. + /// @returns \p this + /// @brief Assignment Operator + PathWithStatus &operator=(const PathWithStatus &that) { + static_cast<Path&>(*this) = static_cast<const Path&>(that); + status = that.status; + fsIsValid = that.fsIsValid; + return *this; + } + + /// Makes a copy of \p that to \p this. + /// @returns \p this + /// @brief Assignment Operator + PathWithStatus &operator=(const Path &that) { + static_cast<Path&>(*this) = static_cast<const Path&>(that); + fsIsValid = false; + return *this; + } + + /// @} + /// @name Methods + /// @{ + public: + /// This function returns status information about the file. The type of + /// path (file or directory) is updated to reflect the actual contents + /// of the file system. + /// @returns 0 on failure, with Error explaining why (if non-zero) + /// @returns a pointer to a FileStatus structure on success. + /// @brief Get file status. + const FileStatus *getFileStatus( + bool forceUpdate = false, ///< Force an update from the file system + std::string *Error = 0 ///< Optional place to return an error msg. + ) const; + + /// @} + /// @name Data + /// @{ + private: + mutable FileStatus status; ///< Status information. + mutable bool fsIsValid; ///< Whether we've obtained it or not + + /// @} + }; + + /// This enumeration delineates the kinds of files that LLVM knows about. + enum LLVMFileType { + Unknown_FileType = 0, ///< Unrecognized file + Bitcode_FileType, ///< Bitcode file + Archive_FileType, ///< ar style archive file + ELF_Relocatable_FileType, ///< ELF Relocatable object file + ELF_Executable_FileType, ///< ELF Executable image + ELF_SharedObject_FileType, ///< ELF dynamically linked shared lib + ELF_Core_FileType, ///< ELF core image + Mach_O_Object_FileType, ///< Mach-O Object file + Mach_O_Executable_FileType, ///< Mach-O Executable + Mach_O_FixedVirtualMemorySharedLib_FileType, ///< Mach-O Shared Lib, FVM + Mach_O_Core_FileType, ///< Mach-O Core File + Mach_O_PreloadExecutable_FileType, ///< Mach-O Preloaded Executable + Mach_O_DynamicallyLinkedSharedLib_FileType, ///< Mach-O dynlinked shared lib + Mach_O_DynamicLinker_FileType, ///< The Mach-O dynamic linker + Mach_O_Bundle_FileType, ///< Mach-O Bundle file + Mach_O_DynamicallyLinkedSharedLibStub_FileType, ///< Mach-O Shared lib stub + COFF_FileType ///< COFF object file or lib + }; + + /// This utility function allows any memory block to be examined in order + /// to determine its file type. + LLVMFileType IdentifyFileType(const char*magic, unsigned length); + + /// This function can be used to copy the file specified by Src to the + /// file specified by Dest. If an error occurs, Dest is removed. + /// @returns true if an error occurs, false otherwise + /// @brief Copy one file to another. + bool CopyFile(const Path& Dest, const Path& Src, std::string* ErrMsg); + + /// This is the OS-specific path separator: a colon on Unix or a semicolon + /// on Windows. + extern const char PathSeparator; +} + +} + +#endif diff --git a/include/llvm/Support/PathV2.h b/include/llvm/Support/PathV2.h new file mode 100644 index 0000000000..b85da0a40a --- /dev/null +++ b/include/llvm/Support/PathV2.h @@ -0,0 +1,979 @@ +//===- llvm/System/PathV2.h - Path Operating System Concept -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::path namespace. It is designed after +// TR2/boost filesystem (v3), but modified to remove exception handling and the +// path class. +// +// All functions return an error_code and their actual work via the last out +// argument. The out argument is defined if and only if errc::success is +// returned. A function may return any error code in the generic or system +// category. However, they shall be equivalent to any error conditions listed +// in each functions respective documentation if the condition applies. [ note: +// this does not guarantee that error_code will be in the set of explicitly +// listed codes, but it does guarantee that if any of the explicitly listed +// errors occur, the correct error_code will be used ]. All functions may +// return errc::not_enough_memory if there is not enough memory to complete the +// operation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/system_error.h" +#include <ctime> +#include <iterator> +#include <string> + +namespace llvm { + +// Forward decls. +class StringRef; +class Twine; + +namespace sys { +namespace path { + +/// @name Lexical Component Iterator +/// @{ + +/// @brief Path iterator. +/// +/// This is a bidirectional iterator that iterates over the individual +/// components in \a path. The forward traversal order is as follows: +/// * The root-name element, if present. +/// * The root-directory element, if present. +/// * Each successive filename element, if present. +/// * Dot, if one or more trailing non-root slash characters are present. +/// The backwards traversal order is the reverse of forward traversal. +/// +/// Iteration examples. Each component is separated by ',': +/// / => / +/// /foo => /,foo +/// foo/ => foo,. +/// /foo/bar => /,foo,bar +/// ../ => ..,. +/// C:\foo\bar => C:,/,foo,bar +/// +class const_iterator { + StringRef Path; //< The entire path. + StringRef Component; //< The current component. + +public: + typedef const StringRef value_type; + typedef value_type &reference; + typedef value_type *pointer; + typedef std::bidirectional_iterator_tag iterator_category; + reference operator*() const; + pointer operator->() const; + const_iterator &operator++(); // preincrement + const_iterator &operator++(int); // postincrement + const_iterator &operator--(); // predecrement + const_iterator &operator--(int); // postdecrement + bool operator==(const const_iterator &RHS) const; + bool operator!=(const const_iterator &RHS) const; + + const_iterator(); //< Default construct end iterator. + const_iterator(const StringRef &path); +}; + +/// @} +/// @name Lexical Modifiers +/// @{ + +/// @brief Make \a path an absolute path. +/// +/// Makes \a path absolute using the current directory if it is not already. An +/// empty \a path will result in the current directory. +/// +/// /absolute/path => /absolute/path +/// relative/../path => <current-directory>/path +/// +/// @param path A path that is modified to be an absolute path. +/// @returns errc::success if \a path has been made absolute, otherwise a +/// platform specific error_code. +error_code make_absolute(SmallVectorImpl<char> &path); + +/// @brief Remove the last component from \a path if it exists. +/// +/// directory/filename.cpp => directory/ +/// directory/ => directory/ +/// +/// @param path A path that is modified to not have a file component. +/// @returns errc::success if \a path's file name has been removed (or there was +/// not one to begin with), otherwise a platform specific error_code. +error_code remove_filename(SmallVectorImpl<char> &path); + +/// @brief Replace the file extension of \a path with \a extension. +/// +/// ./filename.cpp => ./filename.extension +/// ./filename => ./filename.extension +/// ./ => ? TODO: decide what semantics this has. +/// +/// @param path A path that has its extension replaced with \a extension. +/// @param extension The extension to be added. It may be empty. It may also +/// optionally start with a '.', if it does not, one will be +/// prepended. +/// @returns errc::success if \a path's extension has been replaced, otherwise a +/// platform specific error_code. +error_code replace_extension(SmallVectorImpl<char> &path, + const Twine &extension); + +/// @brief Append to path. +/// +/// /foo + bar/f => /foo/bar/f +/// /foo/ + bar/f => /foo/bar/f +/// foo + bar/f => foo/bar/f +/// +/// @param path Set to \a path + \a component. +/// @param component The component to be appended to \a path. +/// @returns errc::success if \a component has been appended to \a path, +/// otherwise a platform specific error_code. +error_code append(SmallVectorImpl<char> &path, const Twine &component); + +/// @brief Append to path. +/// +/// /foo + [bar,f] => /foo/bar/f +/// /foo/ + [bar,f] => /foo/bar/f +/// foo + [bar,f] => foo/bar/f +/// +/// @param path Set to \a path + [\a begin, \a end). +/// @param begin Start of components to append. +/// @param end One past the end of components to append. +/// @returns errc::success if [\a begin, \a end) has been appended to \a path, +/// otherwise a platform specific error_code. +error_code append(SmallVectorImpl<char> &path, + const_iterator begin, const_iterator end); + +/// @} +/// @name Transforms (or some other better name) +/// @{ + +/// Convert path to the native form. This is used to give paths to users and +/// operating system calls in the platform's normal way. For example, on Windows +/// all '/' are converted to '\'. +/// +/// @param path A path that is transformed to native format. +/// @param result Holds the result of the transformation. +/// @returns errc::success if \a path has been transformed and stored in result, +/// otherwise a platform specific error_code. +error_code native(const Twine &path, SmallVectorImpl<char> &result); + +/// @} +/// @name Lexical Observers +/// @{ + +/// @brief Get the current path. +/// +/// @param result Holds the current path on return. +/// @results errc::success if the current path has been stored in result, +/// otherwise a platform specific error_code. +error_code current_path(SmallVectorImpl<char> &result); + +// The following are purely lexical. + +/// @brief Is the current path valid? +/// +/// @param path Input path. +/// @param result Set to true if the path is valid, false if it is not. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_valid(const Twine &path, bool &result); + +/// @brief Get root name. +/// +/// //net/hello => //net +/// c:/hello => c: (on Windows, on other platforms nothing) +/// /hello => <empty> +/// +/// @param path Input path. +/// @param result Set to the root name of \a path if it has one, otherwise "". +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code root_name(const StringRef &path, StringRef &result); + +/// @brief Get root directory. +/// +/// /goo/hello => / +/// c:/hello => / +/// d/file.txt => <empty> +/// +/// @param path Input path. +/// @param result Set to the root directory of \a path if it has one, otherwise +/// "". +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code root_directory(const StringRef &path, StringRef &result); + +/// @brief Get root path. +/// +/// Equivalent to root_name + root_directory. +/// +/// @param path Input path. +/// @param result Set to the root path of \a path if it has one, otherwise "". +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code root_path(const StringRef &path, StringRef &result); + +/// @brief Get relative path. +/// +/// C:\hello\world => hello\world +/// foo/bar => foo/bar +/// /foo/bar => foo/bar +/// +/// @param path Input path. +/// @param result Set to the path starting after root_path if one exists, +/// otherwise "". +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code relative_path(const StringRef &path, StringRef &result); + +/// @brief Get parent path. +/// +/// / => <empty> +/// /foo => / +/// foo/../bar => foo/.. +/// +/// @param path Input path. +/// @param result Set to the parent path of \a path if one exists, otherwise "". +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code parent_path(const StringRef &path, StringRef &result); + +/// @brief Get filename. +/// +/// /foo.txt => foo.txt +/// . => . +/// .. => .. +/// / => / +/// +/// @param path Input path. +/// @param result Set to the filename part of \a path. This is defined as the +/// last component of \a path. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code filename(const StringRef &path, StringRef &result); + +/// @brief Get stem. +/// +/// If filename contains a dot but not solely one or two dots, result is the +/// substring of filename ending at (but not including) the last dot. Otherwise +/// it is filename. +/// +/// /foo/bar.txt => bar +/// /foo/bar => bar +/// /foo/.txt => <empty> +/// /foo/. => . +/// /foo/.. => .. +/// +/// @param path Input path. +/// @param result Set to the stem of \a path. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code stem(const StringRef &path, StringRef &result); + +/// @brief Get extension. +/// +/// If filename contains a dot but not solely one or two dots, result is the +/// substring of filename starting at (and including) the last dot, and ending +/// at the end of \a path. Otherwise "". +/// +/// /foo/bar.txt => .txt +/// /foo/bar => <empty> +/// /foo/.txt => .txt +/// +/// @param path Input path. +/// @param result Set to the extension of \a path. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code extension(const StringRef &path, StringRef &result); + +/// @brief Has root name? +/// +/// root_name != "" +/// +/// @param path Input path. +/// @param result Set to true if the path has a root name, false otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code has_root_name(const Twine &path, bool &result); + +/// @brief Has root directory? +/// +/// root_directory != "" +/// +/// @param path Input path. +/// @param result Set to true if the path has a root directory, false otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code has_root_directory(const Twine &path, bool &result); + +/// @brief Has root path? +/// +/// root_path != "" +/// +/// @param path Input path. +/// @param result Set to true if the path has a root path, false otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code has_root_path(const Twine &path, bool &result); + +/// @brief Has relative path? +/// +/// relative_path != "" +/// +/// @param path Input path. +/// @param result Set to true if the path has a relative path, false otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code has_relative_path(const Twine &path, bool &result); + +/// @brief Has parent path? +/// +/// parent_path != "" +/// +/// @param path Input path. +/// @param result Set to true if the path has a parent path, false otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code has_parent_path(const Twine &path, bool &result); + +/// @brief Has filename? +/// +/// filename != "" +/// +/// @param path Input path. +/// @param result Set to true if the path has a filename, false otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code has_filename(const Twine &path, bool &result); + +/// @brief Has stem? +/// +/// stem != "" +/// +/// @param path Input path. +/// @param result Set to true if the path has a stem, false otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code has_stem(const Twine &path, bool &result); + +/// @brief Has extension? +/// +/// extension != "" +/// +/// @param path Input path. +/// @param result Set to true if the path has a extension, false otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code has_extension(const Twine &path, bool &result); + +/// @brief Is path absolute? +/// +/// @param path Input path. +/// @param result Set to true if the path is absolute, false if it is not. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_absolute(const Twine &path, bool &result); + +/// @brief Is path relative? +/// +/// @param path Input path. +/// @param result Set to true if the path is relative, false if it is not. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_relative(const Twine &path, bool &result); +// end purely lexical. + +} // end namespace path + +namespace fs { + +/// file_type - An "enum class" enumeration for the file system's view of the +/// type. +struct file_type { + enum _ { + status_error, + file_not_found, + regular_file, + directory_file, + symlink_file, + block_file, + character_file, + fifo_file, + socket_file, + type_unknown + }; + + file_type(_ v) : v_(v) {} + explicit file_type(int v) : v_(_(v)) {} + operator int() const {return v_;} + +private: + int v_; +}; + +/// copy_option - An "enum class" enumeration of copy semantics for copy +/// operations. +struct copy_option { + enum _ { + fail_if_exists, + overwrite_if_exists + }; + + copy_option(_ v) : v_(v) {} + explicit copy_option(int v) : v_(_(v)) {} + operator int() const {return v_;} + +private: + int v_; +}; + +/// space_info - Self explanatory. +struct space_info { + uint64_t capacity; + uint64_t free; + uint64_t available; +}; + +/// file_status - Represents the result of a call to stat and friends. It has +/// a platform specific member to store the result. +class file_status +{ + // implementation defined status field. +public: + explicit file_status(file_type v=file_type::status_error); + + file_type type() const; + void type(file_type v); +}; + +/// @} +/// @name Physical Operators +/// @{ + +/// @brief Copy the file at \a from to the path \a to. +/// +/// @param from The path to copy the file from. +/// @param to The path to copy the file to. +/// @param copt Behavior if \a to already exists. +/// @returns errc::success if the file has been successfully copied. +/// errc::file_exists if \a to already exists and \a copt == +/// copy_option::fail_if_exists. Otherwise a platform specific +/// error_code. +error_code copy_file(const Twine &from, const Twine &to, + copy_option copt = copy_option::fail_if_exists); + +/// @brief Create all the non-existent directories in path. +/// +/// @param path Directories to create. +/// @param existed Set to true if \a path already existed, false otherwise. +/// @returns errc::success if is_directory(path) and existed have been set, +/// otherwise a platform specific error_code. +error_code create_directories(const Twine &path, bool &existed); + +/// @brief Create the directory in path. +/// +/// @param path Directory to create. +/// @param existed Set to true if \a path already existed, false otherwise. +/// @returns errc::success if is_directory(path) and existed have been set, +/// otherwise a platform specific error_code. +error_code create_directory(const Twine &path, bool &existed); + +/// @brief Create a hard link from \a from to \a to. +/// +/// @param to The path to hard link to. +/// @param from The path to hard link from. This is created. +/// @returns errc::success if exists(to) && exists(from) && equivalent(to, from) +/// , otherwise a platform specific error_code. +error_code create_hard_link(const Twine &to, const Twine &from); + +/// @brief Create a symbolic link from \a from to \a to. +/// +/// @param to The path to symbolically link to. +/// @param from The path to symbolically link from. This is created. +/// @returns errc::success if exists(to) && exists(from) && is_symlink(from), +/// otherwise a platform specific error_code. +error_code create_symlink(const Twine &to, const Twine &from); + +/// @brief Remove path. Equivalent to POSIX remove(). +/// +/// @param path Input path. +/// @param existed Set to true if \a path existed, false if it did not. +/// undefined otherwise. +/// @results errc::success if path has been removed and existed has been +/// successfully set, otherwise a platform specific error_code. +error_code remove(const Twine &path, bool &existed); + +/// @brief Recursively remove all files below \a path, then \a path. Files are +/// removed as if by POSIX remove(). +/// +/// @param path Input path. +/// @param num_removed Number of files removed. +/// @results errc::success if path has been removed and num_removed has been +/// successfully set, otherwise a platform specific error_code. +error_code remove_all(const Twine &path, uint32_t &num_removed); + +/// @brief Rename \a from to \a to. Files are renamed as if by POSIX rename(). +/// +/// @param from The path to rename from. +/// @param to The path to rename to. This is created. +error_code rename(const Twine &from, const Twine &to); + +/// @brief Resize path to size. File is resized as if by POSIX truncate(). +/// +/// @param path Input path. +/// @param size Size to resize to. +/// @returns errc::success if \a path has been resized to \a size, otherwise a +/// platform specific error_code. +error_code resize_file(const Twine &path, uint64_t size); + +/// @brief Make file readable. +/// +/// @param path Input path. +/// @param value If true, make readable, else, make unreadable. +/// @results errc::success if readability has been successfully set, otherwise a +/// platform specific error_code. +error_code set_read(const Twine &path, bool value); + +/// @brief Make file writeable. +/// +/// @param path Input path. +/// @param value If true, make writeable, else, make unwriteable. +/// @results errc::success if writeability has been successfully set, otherwise +/// a platform specific error_code. +error_code set_write(const Twine &path, bool value); + +/// @brief Make file executable. +/// +/// @param path Input path. +/// @param value If true, make executable, else, make unexecutable. +/// @results errc::success if executability has been successfully set, otherwise +/// a platform specific error_code. +error_code set_execute(const Twine &path, bool value); + +/// @} +/// @name Physical Observers +/// @{ + +/// @brief Does file exist? +/// +/// @param status A file_status previously returned from stat. +/// @param result Set to true if the file represented by status exists, false if +/// it does not. Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code exists(file_status status, bool &result); + +/// @brief Does file exist? +/// +/// @param path Input path. +/// @param result Set to true if the file represented by status exists, false if +/// it does not. Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code exists(const Twine &path, bool &result); + +/// @brief Do paths represent the same thing? +/// +/// @param A Input path A. +/// @param B Input path B. +/// @param result Set to true if stat(A) and stat(B) have the same device and +/// inode (or equivalent). +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code equivalent(const Twine &A, const Twine &B, bool &result); + +/// @brief Get file size. +/// +/// @param path Input path. +/// @param result Set to the size of the file in \a path. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code file_size(const Twine &path, uint64_t &result); + +/// @brief Does status represent a directory? +/// +/// @param status A file_status previously returned from stat. +/// @param result Set to true if the file represented by status is a directory, +/// false if it is not. Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_directory(file_status status, bool &result); + +/// @brief Is path a directory? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a directory, false if it is not. +/// Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_directory(const Twine &path, bool &result); + +/// @brief Is path an empty file? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a an empty file, false if it is not. +/// Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_empty(const Twine &path, bool &result); + +/// @brief Does status represent a regular file? +/// +/// @param status A file_status previously returned from stat. +/// @param result Set to true if the file represented by status is a regular +/// file, false if it is not. Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_regular_file(file_status status, bool &result); + +/// @brief Is path a regular file? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a regular file, false if it is not. +/// Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_regular_file(const Twine &path, bool &result); + +/// @brief Does status represent something that exists but is not a directory, +/// regular file, or symlink? +/// +/// @param status A file_status previously returned from stat. +/// @param result Set to true if the file represented by status exists, but is +/// not a directory, regular file, or a symlink, false if it does +/// not. Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_other(file_status status, bool &result); + +/// @brief Is path something that exists but is not a directory, +/// regular file, or symlink? +/// +/// @param path Input path. +/// @param result Set to true if \a path exists, but is not a directory, regular +/// file, or a symlink, false if it does not. Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_other(const Twine &path, bool &result); + +/// @brief Does status represent a symlink? +/// +/// @param status A file_status previously returned from stat. +/// @param result Set to true if the file represented by status is a symlink, +/// false if it is not. Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_symlink(file_status status, bool &result); + +/// @brief Is path a symlink? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a symlink, false if it is not. +/// Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_symlink(const Twine &path, bool &result); + +/// @brief Get last write time without changing it. +/// +/// @param path Input path. +/// @param result Set to the last write time (UNIX time) of \a path if it +/// exists. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code last_write_time(const Twine &path, std::time_t &result); + +/// @brief Set last write time. +/// +/// @param path Input path. +/// @param value Time to set (UNIX time) \a path's last write time to. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code set_last_write_time(const Twine &path, std::time_t value); + +/// @brief Read a symlink's value. +/// +/// @param path Input path. +/// @param result Set to the value of the symbolic link \a path. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code read_symlink(const Twine &path, SmallVectorImpl<char> &result); + +/// @brief Get disk space usage information. +/// +/// @param path Input path. +/// @param result Set to the capacity, free, and available space on the device +/// \a path is on. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code disk_space(const Twine &path, space_info &result); + +/// @brief Get file status as if by POSIX stat(). +/// +/// @param path Input path. +/// @param result Set to the file status. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code status(const Twine &path, file_status &result); + +/// @brief Is status available? +/// +/// @param path Input path. +/// @param result Set to true if status() != status_error. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code status_known(const Twine &path, bool &result); + +/// @brief Get file status as if by POSIX lstat(). +/// +/// Does not resolve symlinks. +/// +/// @param path Input path. +/// @param result Set to the file status. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code symlink_status(const Twine &path, file_status &result); + +/// @brief Get the temporary directory. +/// +/// @param result Set to the temporary directory. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +/// @see unique_file +error_code temp_directory_path(SmallVectorImpl<char> &result); + +/// @brief Generate a unique path and open it as a file. +/// +/// Generates a unique path suitable for a temporary file and then opens it as a +/// file. The name is based on \a model with '%' replaced by a random char in +/// [0-9a-f]. +/// +/// This is an atomic operation. Either the file is created and opened, or the +/// file system is left untouched. +/// +/// clang-%%-%%-%%-%%-%%.s => <current-directory>/clang-a0-b1-c2-d3-e4.s +/// +/// @param model Name to base unique path off of. +/// @param result Set to the opened file. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +/// @see temp_directory_path +error_code unique_file(const Twine &model, void* i_have_not_decided_the_ty_yet); + +/// @brief Canonicalize path. +/// +/// Sets result to the file system's idea of what path is. The result is always +/// absolute and has the same capitalization as the file system. +/// +/// @param path Input path. +/// @param result Set to the canonicalized version of \a path. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code canonicalize(const Twine &path, SmallVectorImpl<char> &result); + +/// @brief Are \a path's first bytes \a magic? +/// +/// @param path Input path. +/// @param magic Byte sequence to compare \a path's first len(magic) bytes to. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code has_magic(const Twine &path, const Twine &magic); + +/// @brief Get \a path's first \a len bytes. +/// +/// @param path Input path. +/// @param len Number of magic bytes to get. +/// @param result Set to the first \a len bytes in the file pointed to by +/// \a path. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code get_magic(const Twine &path, uint32_t len, + SmallVectorImpl<char> &result); + +/// @brief Is file bitcode? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a bitcode file, false if it is not, +/// undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_bitcode(const Twine &path, bool &result); + +/// @brief Is file a dynamic library? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a dynamic library, false if it is +/// not, undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_dynamic_library(const Twine &path, bool &result); + +/// @brief Is an object file? +/// +/// @param path Input path. +/// @param result Set to true if \a path is an object file, false if it is not, +/// undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_object_file(const Twine &path, bool &result); + +/// @brief Can file be read? +/// +/// @param path Input path. +/// @param result Set to true if \a path is readable, false it it is not, +/// undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code can_read(const Twine &path, bool &result); + +/// @brief Can file be written? +/// +/// @param path Input path. +/// @param result Set to true if \a path is writeable, false it it is not, +/// undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code can_write(const Twine &path, bool &result); + +/// @brief Can file be executed? +/// +/// @param path Input path. +/// @param result Set to true if \a path is executable, false it it is not, +/// undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code can_execute(const Twine &path, bool &result); + +/// @brief Get library paths the system linker uses. +/// +/// @param result Set to the list of system library paths. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code GetSystemLibraryPaths(SmallVectorImpl<std::string> &result); + +/// @brief Get bitcode library paths the system linker uses +/// + LLVM_LIB_SEARCH_PATH + LLVM_LIBDIR. +/// +/// @param result Set to the list of bitcode library paths. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code GetBitcodeLibraryPaths(SmallVectorImpl<std::string> &result); + +/// @brief Find a library. +/// +/// Find the path to a library using its short name. Use the system +/// dependent library paths to locate the library. +/// +/// c => /usr/lib/libc.so +/// +/// @param short_name Library name one would give to the system linker. +/// @param result Set to the absolute path \a short_name represents. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code FindLibrary(const Twine &short_name, SmallVectorImpl<char> &result); + +/// @brief Get absolute path of main executable. +/// +/// @param argv0 The program name as it was spelled on the command line. +/// @param MainAddr Address of some symbol in the executable (not in a library). +/// @param result Set to the absolute path of the current executable. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code GetMainExecutable(const char *argv0, void *MainAddr, + SmallVectorImpl<char> &result); + +/// @} +/// @name Iterators +/// @{ + +/// directory_entry - A single entry in a directory. Caches the status either +/// from the result of the iteration syscall, or the first time status or +/// symlink_status is called. +class directory_entry { + std::string Path; + mutable file_status Status; + mutable file_status SymlinkStatus; + +public: + explicit directory_entry(const Twine &path, file_status st = file_status(), + file_status symlink_st = file_status()); + + void assign(const Twine &path, file_status st = file_status(), + file_status symlink_st = file_status()); + void replace_filename(const Twine &filename, file_status st = file_status(), + file_status symlink_st = file_status()); + + const SmallVectorImpl<char> &path() const; + error_code status(file_status &result) const; + error_code symlink_status(file_status &result) const; + + bool operator==(const directory_entry& rhs) const; + bool operator!=(const directory_entry& rhs) const; + bool operator< (const directory_entry& rhs) const; + bool operator<=(const directory_entry& rhs) const; + bool operator> (const directory_entry& rhs) const; + bool operator>=(const directory_entry& rhs) const; +}; + +/// directory_iterator - Iterates through the entries in path. There is no +/// operator++ because we need an error_code. If it's really needed we can make +/// it call report_fatal_error on error. +class directory_iterator { + // implementation directory iterator status + +public: + explicit directory_iterator(const Twine &path, error_code &ec); + // No operator++ because we need error_code. + directory_iterator &increment(error_code &ec); + + const directory_entry &operator*() const; + const directory_entry *operator->() const; + + // Other members as required by + // C++ Std, 24.1.1 Input iterators [input.iterators] +}; + +/// recursive_directory_iterator - Same as directory_iterator except for it +/// recurses down into child directories. +class recursive_directory_iterator { + uint16_t Level; + bool HasNoPushRequest; + // implementation directory iterator status + +public: + explicit recursive_directory_iterator(const Twine &path, error_code &ec); + // No operator++ because we need error_code. + directory_iterator &increment(error_code &ec); + + const directory_entry &operator*() const; + const directory_entry *operator->() const; + + // observers + /// Gets the current level. path is at level 0. + int level() const; + /// Returns true if no_push has been called for this directory_entry. + bool no_push_request() const; + + // modifiers + /// Goes up one level if Level > 0. + void pop(); + /// Does not go down into the current directory_entry. + void no_push(); + + // Other members as required by + // C++ Std, 24.1.1 Input iterators [input.iterators] +}; + +/// @} + +} // end namespace fs +} // end namespace sys +} // end namespace llvm diff --git a/include/llvm/Support/PointerLikeTypeTraits.h b/include/llvm/Support/PointerLikeTypeTraits.h index b851404800..8370821392 100644 --- a/include/llvm/Support/PointerLikeTypeTraits.h +++ b/include/llvm/Support/PointerLikeTypeTraits.h @@ -15,7 +15,7 @@ #ifndef LLVM_SUPPORT_POINTERLIKETYPETRAITS_H #define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/include/llvm/Support/Process.h b/include/llvm/Support/Process.h new file mode 100644 index 0000000000..cb861d75c0 --- /dev/null +++ b/include/llvm/Support/Process.h @@ -0,0 +1,146 @@ +//===- llvm/System/Process.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::Process class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_PROCESS_H +#define LLVM_SYSTEM_PROCESS_H + +#include "llvm/Support/TimeValue.h" + +namespace llvm { +namespace sys { + + /// This class provides an abstraction for getting information about the + /// currently executing process. + /// @since 1.4 + /// @brief An abstraction for operating system processes. + class Process { + /// @name Accessors + /// @{ + public: + /// This static function will return the operating system's virtual memory + /// page size. + /// @returns The number of bytes in a virtual memory page. + /// @brief Get the virtual memory page size + static unsigned GetPageSize(); + + /// This static function will return the total amount of memory allocated + /// by the process. This only counts the memory allocated via the malloc, + /// calloc and realloc functions and includes any "free" holes in the + /// allocated space. + /// @brief Return process memory usage. + static size_t GetMallocUsage(); + + /// This static function will return the total memory usage of the + /// process. This includes code, data, stack and mapped pages usage. Notei + /// that the value returned here is not necessarily the Running Set Size, + /// it is the total virtual memory usage, regardless of mapped state of + /// that memory. + static size_t GetTotalMemoryUsage(); + + /// This static function will set \p user_time to the amount of CPU time + /// spent in user (non-kernel) mode and \p sys_time to the amount of CPU + /// time spent in system (kernel) mode. If the operating system does not + /// support collection of these metrics, a zero TimeValue will be for both + /// values. + static void GetTimeUsage( + TimeValue& elapsed, + ///< Returns the TimeValue::now() giving current time + TimeValue& user_time, + ///< Returns the current amount of user time for the process + TimeValue& sys_time + ///< Returns the current amount of system time for the process + ); + + /// This static function will return the process' current user id number. + /// Not all operating systems support this feature. Where it is not + /// supported, the function should return 65536 as the value. + static int GetCurrentUserId(); + + /// This static function will return the process' current group id number. + /// Not all operating systems support this feature. Where it is not + /// supported, the function should return 65536 as the value. + static int GetCurrentGroupId(); + + /// This function makes the necessary calls to the operating system to + /// prevent core files or any other kind of large memory dumps that can + /// occur when a program fails. + /// @brief Prevent core file generation. + static void PreventCoreFiles(); + + /// This function determines if the standard input is connected directly + /// to a user's input (keyboard probably), rather than coming from a file + /// or pipe. + static bool StandardInIsUserInput(); + + /// This function determines if the standard output is connected to a + /// "tty" or "console" window. That is, the output would be displayed to + /// the user rather than being put on a pipe or stored in a file. + static bool StandardOutIsDisplayed(); + + /// This function determines if the standard error is connected to a + /// "tty" or "console" window. That is, the output would be displayed to + /// the user rather than being put on a pipe or stored in a file. + static bool StandardErrIsDisplayed(); + + /// This function determines if the given file descriptor is connected to + /// a "tty" or "console" window. That is, the output would be displayed to + /// the user rather than being put on a pipe or stored in a file. + static bool FileDescriptorIsDisplayed(int fd); + + /// This function determines the number of columns in the window + /// if standard output is connected to a "tty" or "console" + /// window. If standard output is not connected to a tty or + /// console, or if the number of columns cannot be determined, + /// this routine returns zero. + static unsigned StandardOutColumns(); + + /// This function determines the number of columns in the window + /// if standard error is connected to a "tty" or "console" + /// window. If standard error is not connected to a tty or + /// console, or if the number of columns cannot be determined, + /// this routine returns zero. + static unsigned StandardErrColumns(); + + /// This function determines whether the terminal connected to standard + /// output supports colors. If standard output is not connected to a + /// terminal, this function returns false. + static bool StandardOutHasColors(); + + /// This function determines whether the terminal connected to standard + /// error supports colors. If standard error is not connected to a + /// terminal, this function returns false. + static bool StandardErrHasColors(); + + /// Whether changing colors requires the output to be flushed. + /// This is needed on systems that don't support escape sequences for + /// changing colors. + static bool ColorNeedsFlush(); + + /// This function returns the colorcode escape sequences. + /// If ColorNeedsFlush() is true then this function will change the colors + /// and return an empty escape sequence. In that case it is the + /// responsibility of the client to flush the output stream prior to + /// calling this function. + static const char *OutputColor(char c, bool bold, bool bg); + + /// Same as OutputColor, but only enables the bold attribute. + static const char *OutputBold(bool bg); + + /// Resets the terminals colors, or returns an escape sequence to do so. + static const char *ResetColor(); + /// @} + }; +} +} + +#endif diff --git a/include/llvm/Support/Program.h b/include/llvm/Support/Program.h new file mode 100644 index 0000000000..872f7e5f06 --- /dev/null +++ b/include/llvm/Support/Program.h @@ -0,0 +1,157 @@ +//===- llvm/System/Program.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::Program class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_PROGRAM_H +#define LLVM_SYSTEM_PROGRAM_H + +#include "llvm/Support/Path.h" + +namespace llvm { +namespace sys { + + // TODO: Add operations to communicate with the process, redirect its I/O, + // etc. + + /// This class provides an abstraction for programs that are executable by the + /// operating system. It provides a platform generic way to find executable + /// programs from the path and to execute them in various ways. The sys::Path + /// class is used to specify the location of the Program. + /// @since 1.4 + /// @brief An abstraction for finding and executing programs. + class Program { + /// Opaque handle for target specific data. + void *Data_; + + // Noncopyable. + Program(const Program& other); + Program& operator=(const Program& other); + + /// @name Methods + /// @{ + public: + + Program(); + ~Program(); + + /// Return process ID of this program. + unsigned GetPid() const; + + /// This function executes the program using the \p arguments provided. The + /// invoked program will inherit the stdin, stdout, and stderr file + /// descriptors, the environment and other configuration settings of the + /// invoking program. If Path::executable() does not return true when this + /// function is called then a std::string is thrown. + /// @returns false in case of error, true otherwise. + /// @see FindProgramByName + /// @brief Executes the program with the given set of \p args. + bool Execute + ( const Path& path, ///< sys::Path object providing the path of the + ///< program to be executed. It is presumed this is the result of + ///< the FindProgramByName method. + const char** args, ///< A vector of strings that are passed to the + ///< program. The first element should be the name of the program. + ///< The list *must* be terminated by a null char* entry. + const char ** env = 0, ///< An optional vector of strings to use for + ///< the program's environment. If not provided, the current program's + ///< environment will be used. + const sys::Path** redirects = 0, ///< An optional array of pointers to + ///< Paths. If the array is null, no redirection is done. The array + ///< should have a size of at least three. If the pointer in the array + ///< are not null, then the inferior process's stdin(0), stdout(1), + ///< and stderr(2) will be redirected to the corresponding Paths. + ///< When an empty Path is passed in, the corresponding file + ///< descriptor will be disconnected (ie, /dev/null'd) in a portable + ///< way. + unsigned memoryLimit = 0, ///< If non-zero, this specifies max. amount + ///< of memory can be allocated by process. If memory usage will be + ///< higher limit, the child is killed and this call returns. If zero + ///< - no memory limit. + std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string + ///< instance in which error messages will be returned. If the string + ///< is non-empty upon return an error occurred while invoking the + ///< program. + ); + + /// This function waits for the program to exit. This function will block + /// the current program until the invoked program exits. + /// @returns an integer result code indicating the status of the program. + /// A zero or positive value indicates the result code of the program. A + /// negative value is the signal number on which it terminated. + /// @see Execute + /// @brief Waits for the program to exit. + int Wait + ( const Path& path, ///< The path to the child process executable. + unsigned secondsToWait, ///< If non-zero, this specifies the amount + ///< of time to wait for the child process to exit. If the time + ///< expires, the child is killed and this call returns. If zero, + ///< this function will wait until the child finishes or forever if + ///< it doesn't. + std::string* ErrMsg ///< If non-zero, provides a pointer to a string + ///< instance in which error messages will be returned. If the string + ///< is non-empty upon return an error occurred while waiting. + ); + + /// This function terminates the program. + /// @returns true if an error occured. + /// @see Execute + /// @brief Terminates the program. + bool Kill + ( std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string + ///< instance in which error messages will be returned. If the string + ///< is non-empty upon return an error occurred while killing the + ///< program. + ); + + /// This static constructor (factory) will attempt to locate a program in + /// the operating system's file system using some pre-determined set of + /// locations to search (e.g. the PATH on Unix). Paths with slashes are + /// returned unmodified. + /// @returns A Path object initialized to the path of the program or a + /// Path object that is empty (invalid) if the program could not be found. + /// @brief Construct a Program by finding it by name. + static Path FindProgramByName(const std::string& name); + + // These methods change the specified standard stream (stdin, + // stdout, or stderr) to binary mode. They return true if an error + // occurred + static bool ChangeStdinToBinary(); + static bool ChangeStdoutToBinary(); + static bool ChangeStderrToBinary(); + + /// A convenience function equivalent to Program prg; prg.Execute(..); + /// prg.Wait(..); + /// @see Execute, Wait + static int ExecuteAndWait(const Path& path, + const char** args, + const char ** env = 0, + const sys::Path** redirects = 0, + unsigned secondsToWait = 0, + unsigned memoryLimit = 0, + std::string* ErrMsg = 0); + + /// A convenience function equivalent to Program prg; prg.Execute(..); + /// @see Execute + static void ExecuteNoWait(const Path& path, + const char** args, + const char ** env = 0, + const sys::Path** redirects = 0, + unsigned memoryLimit = 0, + std::string* ErrMsg = 0); + + /// @} + + }; +} +} + +#endif diff --git a/include/llvm/Support/RWMutex.h b/include/llvm/Support/RWMutex.h new file mode 100644 index 0000000000..0d4cb81de3 --- /dev/null +++ b/include/llvm/Support/RWMutex.h @@ -0,0 +1,173 @@ +//===- RWMutex.h - Reader/Writer Mutual Exclusion Lock ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::RWMutex class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_RWMUTEX_H +#define LLVM_SYSTEM_RWMUTEX_H + +#include "llvm/Support/Threading.h" +#include <cassert> + +namespace llvm +{ + namespace sys + { + /// @brief Platform agnostic RWMutex class. + class RWMutexImpl + { + /// @name Constructors + /// @{ + public: + + /// Initializes the lock but doesn't acquire it. + /// @brief Default Constructor. + explicit RWMutexImpl(); + + /// Releases and removes the lock + /// @brief Destructor + ~RWMutexImpl(); + + /// @} + /// @name Methods + /// @{ + public: + + /// Attempts to unconditionally acquire the lock in reader mode. If the + /// lock is held by a writer, this method will wait until it can acquire + /// the lock. + /// @returns false if any kind of error occurs, true otherwise. + /// @brief Unconditionally acquire the lock in reader mode. + bool reader_acquire(); + + /// Attempts to release the lock in reader mode. + /// @returns false if any kind of error occurs, true otherwise. + /// @brief Unconditionally release the lock in reader mode. + bool reader_release(); + + /// Attempts to unconditionally acquire the lock in reader mode. If the + /// lock is held by any readers, this method will wait until it can + /// acquire the lock. + /// @returns false if any kind of error occurs, true otherwise. + /// @brief Unconditionally acquire the lock in writer mode. + bool writer_acquire(); + + /// Attempts to release the lock in writer mode. + /// @returns false if any kind of error occurs, true otherwise. + /// @brief Unconditionally release the lock in write mode. + bool writer_release(); + + //@} + /// @name Platform Dependent Data + /// @{ + private: + void* data_; ///< We don't know what the data will be + + /// @} + /// @name Do Not Implement + /// @{ + private: + RWMutexImpl(const RWMutexImpl & original); + void operator=(const RWMutexImpl &); + /// @} + }; + + /// SmartMutex - An R/W mutex with a compile time constant parameter that + /// indicates whether this mutex should become a no-op when we're not + /// running in multithreaded mode. + template<bool mt_only> + class SmartRWMutex : public RWMutexImpl { + unsigned readers, writers; + public: + explicit SmartRWMutex() : RWMutexImpl(), readers(0), writers(0) { } + + bool reader_acquire() { + if (!mt_only || llvm_is_multithreaded()) + return RWMutexImpl::reader_acquire(); + + // Single-threaded debugging code. This would be racy in multithreaded + // mode, but provides not sanity checks in single threaded mode. + ++readers; + return true; + } + + bool reader_release() { + if (!mt_only || llvm_is_multithreaded()) + return RWMutexImpl::reader_release(); + + // Single-threaded debugging code. This would be racy in multithreaded + // mode, but provides not sanity checks in single threaded mode. + assert(readers > 0 && "Reader lock not acquired before release!"); + --readers; + return true; + } + + bool writer_acquire() { + if (!mt_only || llvm_is_multithreaded()) + return RWMutexImpl::writer_acquire(); + + // Single-threaded debugging code. This would be racy in multithreaded + // mode, but provides not sanity checks in single threaded mode. + assert(writers == 0 && "Writer lock already acquired!"); + ++writers; + return true; + } + + bool writer_release() { + if (!mt_only || llvm_is_multithreaded()) + return RWMutexImpl::writer_release(); + + // Single-threaded debugging code. This would be racy in multithreaded + // mode, but provides not sanity checks in single threaded mode. + assert(writers == 1 && "Writer lock not acquired before release!"); + --writers; + return true; + } + + private: + SmartRWMutex(const SmartRWMutex<mt_only> & original); + void operator=(const SmartRWMutex<mt_only> &); + }; + typedef SmartRWMutex<false> RWMutex; + + /// ScopedReader - RAII acquisition of a reader lock + template<bool mt_only> + struct SmartScopedReader { + SmartRWMutex<mt_only>& mutex; + + explicit SmartScopedReader(SmartRWMutex<mt_only>& m) : mutex(m) { + mutex.reader_acquire(); + } + + ~SmartScopedReader() { + mutex.reader_release(); + } + }; + typedef SmartScopedReader<false> ScopedReader; + + /// ScopedWriter - RAII acquisition of a writer lock + template<bool mt_only> + struct SmartScopedWriter { + SmartRWMutex<mt_only>& mutex; + + explicit SmartScopedWriter(SmartRWMutex<mt_only>& m) : mutex(m) { + mutex.writer_acquire(); + } + + ~SmartScopedWriter() { + mutex.writer_release(); + } + }; + typedef SmartScopedWriter<false> ScopedWriter; + } +} + +#endif diff --git a/include/llvm/Support/Signals.h b/include/llvm/Support/Signals.h new file mode 100644 index 0000000000..da98d0ca8f --- /dev/null +++ b/include/llvm/Support/Signals.h @@ -0,0 +1,59 @@ +//===- llvm/System/Signals.h - Signal Handling support ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for dealing with the possibility of +// unix signals occuring while your program is running. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_SIGNALS_H +#define LLVM_SYSTEM_SIGNALS_H + +#include "llvm/Support/Path.h" + +namespace llvm { +namespace sys { + + /// This function runs all the registered interrupt handlers, including the + /// removal of files registered by RemoveFileOnSignal. + void RunInterruptHandlers(); + + /// This function registers signal handlers to ensure that if a signal gets + /// delivered that the named file is removed. + /// @brief Remove a file if a fatal signal occurs. + bool RemoveFileOnSignal(const Path &Filename, std::string* ErrMsg = 0); + + /// This function removes a file from the list of files to be removed on + /// signal delivery. + void DontRemoveFileOnSignal(const Path &Filename); + + /// When an error signal (such as SIBABRT or SIGSEGV) is delivered to the + /// process, print a stack trace and then exit. + /// @brief Print a stack trace if a fatal signal occurs. + void PrintStackTraceOnErrorSignal(); + + /// AddSignalHandler - Add a function to be called when an abort/kill signal + /// is delivered to the process. The handler can have a cookie passed to it + /// to identify what instance of the handler it is. + void AddSignalHandler(void (*FnPtr)(void *), void *Cookie); + + /// This function registers a function to be called when the user "interrupts" + /// the program (typically by pressing ctrl-c). When the user interrupts the + /// program, the specified interrupt function is called instead of the program + /// being killed, and the interrupt function automatically disabled. Note + /// that interrupt functions are not allowed to call any non-reentrant + /// functions. An null interrupt function pointer disables the current + /// installed function. Note also that the handler may be executed on a + /// different thread on some platforms. + /// @brief Register a function to be called when ctrl-c is pressed. + void SetInterruptFunction(void (*IF)()); +} // End sys namespace +} // End llvm namespace + +#endif diff --git a/include/llvm/Support/Solaris.h b/include/llvm/Support/Solaris.h new file mode 100644 index 0000000000..15adb7472c --- /dev/null +++ b/include/llvm/Support/Solaris.h @@ -0,0 +1,40 @@ +/*===- llvm/System/Solaris.h ------------------------------------*- C++ -*-===* + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------===* + * + * This file contains portability fixes for Solaris hosts. + * + *===----------------------------------------------------------------------===*/ + +#ifndef LLVM_SYSTEM_SOLARIS_H +#define LLVM_SYSTEM_SOLARIS_H + +#include <sys/types.h> +#include <sys/regset.h> + +#undef CS +#undef DS +#undef ES +#undef FS +#undef GS +#undef SS +#undef EAX +#undef ECX +#undef EDX +#undef EBX +#undef ESP +#undef EBP +#undef ESI +#undef EDI +#undef EIP +#undef UESP +#undef EFL +#undef ERR +#undef TRAPNO + +#endif diff --git a/include/llvm/Support/SwapByteOrder.h b/include/llvm/Support/SwapByteOrder.h new file mode 100644 index 0000000000..6c0592c05a --- /dev/null +++ b/include/llvm/Support/SwapByteOrder.h @@ -0,0 +1,101 @@ +//===- SwapByteOrder.h - Generic and optimized byte swaps -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares generic and optimized functions to swap the byte order of +// an integral type. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_SWAP_BYTE_ORDER_H +#define LLVM_SYSTEM_SWAP_BYTE_ORDER_H + +#include "llvm/Support/DataTypes.h" +#include <cstddef> +#include <limits> + +namespace llvm { +namespace sys { + +/// SwapByteOrder_16 - This function returns a byte-swapped representation of +/// the 16-bit argument. +inline uint16_t SwapByteOrder_16(uint16_t value) { +#if defined(_MSC_VER) && !defined(_DEBUG) + // The DLL version of the runtime lacks these functions (bug!?), but in a + // release build they're replaced with BSWAP instructions anyway. + return _byteswap_ushort(value); +#else + uint16_t Hi = value << 8; + uint16_t Lo = value >> 8; + return Hi | Lo; +#endif +} + +/// SwapByteOrder_32 - This function returns a byte-swapped representation of +/// the 32-bit argument. +inline uint32_t SwapByteOrder_32(uint32_t value) { +#if defined(__llvm__) || \ +(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && !defined(__ICC) + return __builtin_bswap32(value); +#elif defined(_MSC_VER) && !defined(_DEBUG) + return _byteswap_ulong(value); +#else + uint32_t Byte0 = value & 0x000000FF; + uint32_t Byte1 = value & 0x0000FF00; + uint32_t Byte2 = value & 0x00FF0000; + uint32_t Byte3 = value & 0xFF000000; + return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24); +#endif +} + +/// SwapByteOrder_64 - This function returns a byte-swapped representation of +/// the 64-bit argument. +inline uint64_t SwapByteOrder_64(uint64_t value) { +#if defined(__llvm__) || \ +(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && !defined(__ICC) + return __builtin_bswap64(value); +#elif defined(_MSC_VER) && !defined(_DEBUG) + return _byteswap_uint64(value); +#else + uint64_t Hi = SwapByteOrder_32(uint32_t(value)); + uint32_t Lo = SwapByteOrder_32(uint32_t(value >> 32)); + return (Hi << 32) | Lo; +#endif +} + +inline unsigned char SwapByteOrder(unsigned char C) { return C; } +inline signed char SwapByteOrder(signed char C) { return C; } +inline char SwapByteOrder(char C) { return C; } + +inline unsigned short SwapByteOrder(unsigned short C) { return SwapByteOrder_16(C); } +inline signed short SwapByteOrder( signed short C) { return SwapByteOrder_16(C); } + +inline unsigned int SwapByteOrder(unsigned int C) { return SwapByteOrder_32(C); } +inline signed int SwapByteOrder( signed int C) { return SwapByteOrder_32(C); } + +#if __LONG_MAX__ == __INT_MAX__ +inline unsigned long SwapByteOrder(unsigned long C) { return SwapByteOrder_32(C); } +inline signed long SwapByteOrder( signed long C) { return SwapByteOrder_32(C); } +#elif __LONG_MAX__ == __LONG_LONG_MAX__ +inline unsigned long SwapByteOrder(unsigned long C) { return SwapByteOrder_64(C); } +inline signed long SwapByteOrder( signed long C) { return SwapByteOrder_64(C); } +#else +#error "Unknown long size!" +#endif + +inline unsigned long long SwapByteOrder(unsigned long long C) { + return SwapByteOrder_64(C); +} +inline signed long long SwapByteOrder(signed long long C) { + return SwapByteOrder_64(C); +} + +} // end namespace sys +} // end namespace llvm + +#endif diff --git a/include/llvm/Support/ThreadLocal.h b/include/llvm/Support/ThreadLocal.h new file mode 100644 index 0000000000..155a4db818 --- /dev/null +++ b/include/llvm/Support/ThreadLocal.h @@ -0,0 +1,54 @@ +//===- llvm/System/ThreadLocal.h - Thread Local Data ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_THREAD_LOCAL_H +#define LLVM_SYSTEM_THREAD_LOCAL_H + +#include "llvm/Support/Threading.h" +#include <cassert> + +namespace llvm { + namespace sys { + // ThreadLocalImpl - Common base class of all ThreadLocal instantiations. + // YOU SHOULD NEVER USE THIS DIRECTLY. + class ThreadLocalImpl { + void* data; + public: + ThreadLocalImpl(); + virtual ~ThreadLocalImpl(); + void setInstance(const void* d); + const void* getInstance(); + void removeInstance(); + }; + + /// ThreadLocal - A class used to abstract thread-local storage. It holds, + /// for each thread, a pointer a single object of type T. + template<class T> + class ThreadLocal : public ThreadLocalImpl { + public: + ThreadLocal() : ThreadLocalImpl() { } + + /// get - Fetches a pointer to the object associated with the current + /// thread. If no object has yet been associated, it returns NULL; + T* get() { return static_cast<T*>(getInstance()); } + + // set - Associates a pointer to an object with the current thread. + void set(T* d) { setInstance(d); } + + // erase - Removes the pointer associated with the current thread. + void erase() { removeInstance(); } + }; + } +} + +#endif diff --git a/include/llvm/Support/Threading.h b/include/llvm/Support/Threading.h new file mode 100644 index 0000000000..371a8625ae --- /dev/null +++ b/include/llvm/Support/Threading.h @@ -0,0 +1,59 @@ +//===-- llvm/System/Threading.h - Control multithreading mode --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// TThis file defines llvm_start_multithreaded() and friends. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_THREADING_H +#define LLVM_SYSTEM_THREADING_H + +namespace llvm { + /// llvm_start_multithreaded - Allocate and initialize structures needed to + /// make LLVM safe for multithreading. The return value indicates whether + /// multithreaded initialization succeeded. LLVM will still be operational + /// on "failed" return, and will still be safe for hosting threading + /// applications in the JIT, but will not be safe for concurrent calls to the + /// LLVM APIs. + /// THIS MUST EXECUTE IN ISOLATION FROM ALL OTHER LLVM API CALLS. + bool llvm_start_multithreaded(); + + /// llvm_stop_multithreaded - Deallocate structures necessary to make LLVM + /// safe for multithreading. + /// THIS MUST EXECUTE IN ISOLATION FROM ALL OTHER LLVM API CALLS. + void llvm_stop_multithreaded(); + + /// llvm_is_multithreaded - Check whether LLVM is executing in thread-safe + /// mode or not. + bool llvm_is_multithreaded(); + + /// acquire_global_lock - Acquire the global lock. This is a no-op if called + /// before llvm_start_multithreaded(). + void llvm_acquire_global_lock(); + + /// release_global_lock - Release the global lock. This is a no-op if called + /// before llvm_start_multithreaded(). + void llvm_release_global_lock(); + + /// llvm_execute_on_thread - Execute the given \arg UserFn on a separate + /// thread, passing it the provided \arg UserData. + /// + /// This function does not guarantee that the code will actually be executed + /// on a separate thread or honoring the requested stack size, but tries to do + /// so where system support is available. + /// + /// \param UserFn - The callback to execute. + /// \param UserData - An argument to pass to the callback function. + /// \param RequestedStackSize - If non-zero, a requested size (in bytes) for + /// the thread stack. + void llvm_execute_on_thread(void (*UserFn)(void*), void *UserData, + unsigned RequestedStackSize = 0); +} + +#endif diff --git a/include/llvm/Support/TimeValue.h b/include/llvm/Support/TimeValue.h new file mode 100644 index 0000000000..e1227118c2 --- /dev/null +++ b/include/llvm/Support/TimeValue.h @@ -0,0 +1,382 @@ +//===-- TimeValue.h - Declare OS TimeValue Concept --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file declares the operating system TimeValue concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/DataTypes.h" +#include <string> + +#ifndef LLVM_SYSTEM_TIMEVALUE_H +#define LLVM_SYSTEM_TIMEVALUE_H + +namespace llvm { +namespace sys { + /// This class is used where a precise fixed point in time is required. The + /// range of TimeValue spans many hundreds of billions of years both past and + /// present. The precision of TimeValue is to the nanosecond. However, the + /// actual precision of its values will be determined by the resolution of + /// the system clock. The TimeValue class is used in conjunction with several + /// other lib/System interfaces to specify the time at which a call should + /// timeout, etc. + /// @since 1.4 + /// @brief Provides an abstraction for a fixed point in time. + class TimeValue { + + /// @name Constants + /// @{ + public: + + /// A constant TimeValue representing the smallest time + /// value permissable by the class. MinTime is some point + /// in the distant past, about 300 billion years BCE. + /// @brief The smallest possible time value. + static const TimeValue MinTime; + + /// A constant TimeValue representing the largest time + /// value permissable by the class. MaxTime is some point + /// in the distant future, about 300 billion years AD. + /// @brief The largest possible time value. + static const TimeValue MaxTime; + + /// A constant TimeValue representing the base time, + /// or zero time of 00:00:00 (midnight) January 1st, 2000. + /// @brief 00:00:00 Jan 1, 2000 UTC. + static const TimeValue ZeroTime; + + /// A constant TimeValue for the Posix base time which is + /// 00:00:00 (midnight) January 1st, 1970. + /// @brief 00:00:00 Jan 1, 1970 UTC. + static const TimeValue PosixZeroTime; + + /// A constant TimeValue for the Win32 base time which is + /// 00:00:00 (midnight) January 1st, 1601. + /// @brief 00:00:00 Jan 1, 1601 UTC. + static const TimeValue Win32ZeroTime; + + /// @} + /// @name Types + /// @{ + public: + typedef int64_t SecondsType; ///< Type used for representing seconds. + typedef int32_t NanoSecondsType;///< Type used for representing nanoseconds. + + enum TimeConversions { + NANOSECONDS_PER_SECOND = 1000000000, ///< One Billion + MICROSECONDS_PER_SECOND = 1000000, ///< One Million + MILLISECONDS_PER_SECOND = 1000, ///< One Thousand + NANOSECONDS_PER_MICROSECOND = 1000, ///< One Thousand + NANOSECONDS_PER_MILLISECOND = 1000000,///< One Million + NANOSECONDS_PER_POSIX_TICK = 100, ///< Posix tick is 100 Hz (10ms) + NANOSECONDS_PER_WIN32_TICK = 100 ///< Win32 tick is 100 Hz (10ms) + }; + + /// @} + /// @name Constructors + /// @{ + public: + /// Caller provides the exact value in seconds and nanoseconds. The + /// \p nanos argument defaults to zero for convenience. + /// @brief Explicit constructor + explicit TimeValue (SecondsType seconds, NanoSecondsType nanos = 0) + : seconds_( seconds ), nanos_( nanos ) { this->normalize(); } + + /// Caller provides the exact value as a double in seconds with the + /// fractional part representing nanoseconds. + /// @brief Double Constructor. + explicit TimeValue( double new_time ) + : seconds_( 0 ) , nanos_ ( 0 ) { + SecondsType integer_part = static_cast<SecondsType>( new_time ); + seconds_ = integer_part; + nanos_ = static_cast<NanoSecondsType>( (new_time - + static_cast<double>(integer_part)) * NANOSECONDS_PER_SECOND ); + this->normalize(); + } + + /// This is a static constructor that returns a TimeValue that represents + /// the current time. + /// @brief Creates a TimeValue with the current time (UTC). + static TimeValue now(); + + /// @} + /// @name Operators + /// @{ + public: + /// Add \p that to \p this. + /// @returns this + /// @brief Incrementing assignment operator. + TimeValue& operator += (const TimeValue& that ) { + this->seconds_ += that.seconds_ ; + this->nanos_ += that.nanos_ ; + this->normalize(); + return *this; + } + + /// Subtract \p that from \p this. + /// @returns this + /// @brief Decrementing assignment operator. + TimeValue& operator -= (const TimeValue &that ) { + this->seconds_ -= that.seconds_ ; + this->nanos_ -= that.nanos_ ; + this->normalize(); + return *this; + } + + /// Determine if \p this is less than \p that. + /// @returns True iff *this < that. + /// @brief True if this < that. + int operator < (const TimeValue &that) const { return that > *this; } + + /// Determine if \p this is greather than \p that. + /// @returns True iff *this > that. + /// @brief True if this > that. + int operator > (const TimeValue &that) const { + if ( this->seconds_ > that.seconds_ ) { + return 1; + } else if ( this->seconds_ == that.seconds_ ) { + if ( this->nanos_ > that.nanos_ ) return 1; + } + return 0; + } + + /// Determine if \p this is less than or equal to \p that. + /// @returns True iff *this <= that. + /// @brief True if this <= that. + int operator <= (const TimeValue &that) const { return that >= *this; } + + /// Determine if \p this is greater than or equal to \p that. + /// @returns True iff *this >= that. + /// @brief True if this >= that. + int operator >= (const TimeValue &that) const { + if ( this->seconds_ > that.seconds_ ) { + return 1; + } else if ( this->seconds_ == that.seconds_ ) { + if ( this->nanos_ >= that.nanos_ ) return 1; + } + return 0; + } + + /// Determines if two TimeValue objects represent the same moment in time. + /// @brief True iff *this == that. + /// @brief True if this == that. + int operator == (const TimeValue &that) const { + return (this->seconds_ == that.seconds_) && + (this->nanos_ == that.nanos_); + } + + /// Determines if two TimeValue objects represent times that are not the + /// same. + /// @return True iff *this != that. + /// @brief True if this != that. + int operator != (const TimeValue &that) const { return !(*this == that); } + + /// Adds two TimeValue objects together. + /// @returns The sum of the two operands as a new TimeValue + /// @brief Addition operator. + friend TimeValue operator + (const TimeValue &tv1, const TimeValue &tv2); + + /// Subtracts two TimeValue objects. + /// @returns The difference of the two operands as a new TimeValue + /// @brief Subtraction operator. + friend TimeValue operator - (const TimeValue &tv1, const TimeValue &tv2); + + /// @} + /// @name Accessors + /// @{ + public: + + /// Returns only the seconds component of the TimeValue. The nanoseconds + /// portion is ignored. No rounding is performed. + /// @brief Retrieve the seconds component + SecondsType seconds() const { return seconds_; } + + /// Returns only the nanoseconds component of the TimeValue. The seconds + /// portion is ignored. + /// @brief Retrieve the nanoseconds component. + NanoSecondsType nanoseconds() const { return nanos_; } + + /// Returns only the fractional portion of the TimeValue rounded down to the + /// nearest microsecond (divide by one thousand). + /// @brief Retrieve the fractional part as microseconds; + uint32_t microseconds() const { + return nanos_ / NANOSECONDS_PER_MICROSECOND; + } + + /// Returns only the fractional portion of the TimeValue rounded down to the + /// nearest millisecond (divide by one million). + /// @brief Retrieve the fractional part as milliseconds; + uint32_t milliseconds() const { + return nanos_ / NANOSECONDS_PER_MILLISECOND; + } + + /// Returns the TimeValue as a number of microseconds. Note that the value + /// returned can overflow because the range of a uint64_t is smaller than + /// the range of a TimeValue. Nevertheless, this is useful on some operating + /// systems and is therefore provided. + /// @brief Convert to a number of microseconds (can overflow) + uint64_t usec() const { + return seconds_ * MICROSECONDS_PER_SECOND + + ( nanos_ / NANOSECONDS_PER_MICROSECOND ); + } + + /// Returns the TimeValue as a number of milliseconds. Note that the value + /// returned can overflow because the range of a uint64_t is smaller than + /// the range of a TimeValue. Nevertheless, this is useful on some operating + /// systems and is therefore provided. + /// @brief Convert to a number of milliseconds (can overflow) + uint64_t msec() const { + return seconds_ * MILLISECONDS_PER_SECOND + + ( nanos_ / NANOSECONDS_PER_MILLISECOND ); + } + + /// Converts the TimeValue into the corresponding number of "ticks" for + /// Posix, correcting for the difference in Posix zero time. + /// @brief Convert to unix time (100 nanoseconds since 12:00:00a Jan 1,1970) + uint64_t toPosixTime() const { + uint64_t result = seconds_ - PosixZeroTime.seconds_; + result += nanos_ / NANOSECONDS_PER_POSIX_TICK; + return result; + } + + /// Converts the TimeValue into the corresponding number of seconds + /// since the epoch (00:00:00 Jan 1,1970). + uint64_t toEpochTime() const { + return seconds_ - PosixZeroTime.seconds_; + } + + /// Converts the TimeValue into the corresponding number of "ticks" for + /// Win32 platforms, correcting for the difference in Win32 zero time. + /// @brief Convert to windows time (seconds since 12:00:00a Jan 1, 1601) + uint64_t toWin32Time() const { + uint64_t result = seconds_ - Win32ZeroTime.seconds_; + result += nanos_ / NANOSECONDS_PER_WIN32_TICK; + return result; + } + + /// Provides the seconds and nanoseconds as results in its arguments after + /// correction for the Posix zero time. + /// @brief Convert to timespec time (ala POSIX.1b) + void getTimespecTime( uint64_t& seconds, uint32_t& nanos ) const { + seconds = seconds_ - PosixZeroTime.seconds_; + nanos = nanos_; + } + + /// Provides conversion of the TimeValue into a readable time & date. + /// @returns std::string containing the readable time value + /// @brief Convert time to a string. + std::string str() const; + + /// @} + /// @name Mutators + /// @{ + public: + /// The seconds component of the TimeValue is set to \p sec without + /// modifying the nanoseconds part. This is useful for whole second + /// arithmetic. + /// @brief Set the seconds component. + void seconds (SecondsType sec ) { + this->seconds_ = sec; + this->normalize(); + } + + /// The nanoseconds component of the TimeValue is set to \p nanos without + /// modifying the seconds part. This is useful for basic computations + /// involving just the nanoseconds portion. Note that the TimeValue will be + /// normalized after this call so that the fractional (nanoseconds) portion + /// will have the smallest equivalent value. + /// @brief Set the nanoseconds component using a number of nanoseconds. + void nanoseconds ( NanoSecondsType nanos ) { + this->nanos_ = nanos; + this->normalize(); + } + + /// The seconds component remains unchanged. + /// @brief Set the nanoseconds component using a number of microseconds. + void microseconds ( int32_t micros ) { + this->nanos_ = micros * NANOSECONDS_PER_MICROSECOND; + this->normalize(); + } + + /// The seconds component remains unchanged. + /// @brief Set the nanoseconds component using a number of milliseconds. + void milliseconds ( int32_t millis ) { + this->nanos_ = millis * NANOSECONDS_PER_MILLISECOND; + this->normalize(); + } + + /// @brief Converts from microsecond format to TimeValue format + void usec( int64_t microseconds ) { + this->seconds_ = microseconds / MICROSECONDS_PER_SECOND; + this->nanos_ = NanoSecondsType(microseconds % MICROSECONDS_PER_SECOND) * + NANOSECONDS_PER_MICROSECOND; + this->normalize(); + } + + /// @brief Converts from millisecond format to TimeValue format + void msec( int64_t milliseconds ) { + this->seconds_ = milliseconds / MILLISECONDS_PER_SECOND; + this->nanos_ = NanoSecondsType(milliseconds % MILLISECONDS_PER_SECOND) * + NANOSECONDS_PER_MILLISECOND; + this->normalize(); + } + + /// Converts the \p seconds argument from PosixTime to the corresponding + /// TimeValue and assigns that value to \p this. + /// @brief Convert seconds form PosixTime to TimeValue + void fromEpochTime( SecondsType seconds ) { + seconds_ = seconds + PosixZeroTime.seconds_; + nanos_ = 0; + this->normalize(); + } + + /// Converts the \p win32Time argument from Windows FILETIME to the + /// corresponding TimeValue and assigns that value to \p this. + /// @brief Convert seconds form Windows FILETIME to TimeValue + void fromWin32Time( uint64_t win32Time ) { + this->seconds_ = win32Time / 10000000 + Win32ZeroTime.seconds_; + this->nanos_ = NanoSecondsType(win32Time % 10000000) * 100; + } + + /// @} + /// @name Implementation + /// @{ + private: + /// This causes the values to be represented so that the fractional + /// part is minimized, possibly incrementing the seconds part. + /// @brief Normalize to canonical form. + void normalize(); + + /// @} + /// @name Data + /// @{ + private: + /// Store the values as a <timeval>. + SecondsType seconds_;///< Stores the seconds part of the TimeVal + NanoSecondsType nanos_; ///< Stores the nanoseconds part of the TimeVal + /// @} + + }; + +inline TimeValue operator + (const TimeValue &tv1, const TimeValue &tv2) { + TimeValue sum (tv1.seconds_ + tv2.seconds_, tv1.nanos_ + tv2.nanos_); + sum.normalize (); + return sum; +} + +inline TimeValue operator - (const TimeValue &tv1, const TimeValue &tv2) { + TimeValue difference (tv1.seconds_ - tv2.seconds_, tv1.nanos_ - tv2.nanos_ ); + difference.normalize (); + return difference; +} + +} +} + +#endif diff --git a/include/llvm/Support/Timer.h b/include/llvm/Support/Timer.h index f959136f86..404cb6d6c8 100644 --- a/include/llvm/Support/Timer.h +++ b/include/llvm/Support/Timer.h @@ -15,7 +15,7 @@ #ifndef LLVM_SUPPORT_TIMER_H #define LLVM_SUPPORT_TIMER_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/StringRef.h" #include <cassert> #include <string> diff --git a/include/llvm/Support/Valgrind.h b/include/llvm/Support/Valgrind.h new file mode 100644 index 0000000000..5ec79c3c55 --- /dev/null +++ b/include/llvm/Support/Valgrind.h @@ -0,0 +1,32 @@ +//===- llvm/System/Valgrind.h - Communication with Valgrind -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Methods for communicating with a valgrind instance this program is running +// under. These are all no-ops unless LLVM was configured on a system with the +// valgrind headers installed and valgrind is controlling this process. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_VALGRIND_H +#define LLVM_SYSTEM_VALGRIND_H + +#include <stddef.h> + +namespace llvm { +namespace sys { + // True if Valgrind is controlling this process. + bool RunningOnValgrind(); + + // Discard valgrind's translation of code in the range [Addr .. Addr + Len). + // Otherwise valgrind may continue to execute the old version of the code. + void ValgrindDiscardTranslations(const void *Addr, size_t Len); +} +} + +#endif diff --git a/include/llvm/Support/raw_ostream.h b/include/llvm/Support/raw_ostream.h index ae21d2a040..95904ea2f3 100644 --- a/include/llvm/Support/raw_ostream.h +++ b/include/llvm/Support/raw_ostream.h @@ -15,7 +15,7 @@ #define LLVM_SUPPORT_RAW_OSTREAM_H #include "llvm/ADT/StringRef.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { class format_object_base; diff --git a/include/llvm/Support/system_error.h b/include/llvm/Support/system_error.h new file mode 100644 index 0000000000..c17e7bf798 --- /dev/null +++ b/include/llvm/Support/system_error.h @@ -0,0 +1,911 @@ +//===---------------------------- system_error ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This was lifted from libc++ and modified for C++03. This is called +// system_error even though it does not define that class because that's what +// it's called in C++0x. We don't define system_error because it is only used +// for exception handling, which we don't use in LLVM. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_SYSTEM_ERROR_H +#define LLVM_SYSTEM_SYSTEM_ERROR_H + +/* + system_error synopsis + +namespace std +{ + +class error_category +{ +public: + virtual ~error_category(); + + error_category(const error_category&) = delete; + error_category& operator=(const error_category&) = delete; + + virtual const char* name() const = 0; + virtual error_condition default_error_condition(int ev) const; + virtual bool equivalent(int code, const error_condition& condition) const; + virtual bool equivalent(const error_code& code, int condition) const; + virtual std::string message(int ev) const = 0; + + bool operator==(const error_category& rhs) const; + bool operator!=(const error_category& rhs) const; + bool operator<(const error_category& rhs) const; +}; + +const error_category& generic_category(); +const error_category& system_category(); + +template <class T> struct is_error_code_enum + : public false_type {}; + +template <class T> struct is_error_condition_enum + : public false_type {}; + +class error_code +{ +public: + // constructors: + error_code(); + error_code(int val, const error_category& cat); + template <class ErrorCodeEnum> + error_code(ErrorCodeEnum e); + + // modifiers: + void assign(int val, const error_category& cat); + template <class ErrorCodeEnum> + error_code& operator=(ErrorCodeEnum e); + void clear(); + + // observers: + int value() const; + const error_category& category() const; + error_condition default_error_condition() const; + std::string message() const; + explicit operator bool() const; +}; + +// non-member functions: +bool operator<(const error_code& lhs, const error_code& rhs); +template <class charT, class traits> + basic_ostream<charT,traits>& + operator<<(basic_ostream<charT,traits>& os, const error_code& ec); + +class error_condition +{ +public: + // constructors: + error_condition(); + error_condition(int val, const error_category& cat); + template <class ErrorConditionEnum> + error_condition(ErrorConditionEnum e); + + // modifiers: + void assign(int val, const error_category& cat); + template <class ErrorConditionEnum> + error_condition& operator=(ErrorConditionEnum e); + void clear(); + + // observers: + int value() const; + const error_category& category() const; + std::string message() const; + explicit operator bool() const; +}; + +bool operator<(const error_condition& lhs, const error_condition& rhs); + +class system_error + : public runtime_error +{ +public: + system_error(error_code ec, const std::string& what_arg); + system_error(error_code ec, const char* what_arg); + system_error(error_code ec); + system_error(int ev, const error_category& ecat, const std::string& what_arg); + system_error(int ev, const error_category& ecat, const char* what_arg); + system_error(int ev, const error_category& ecat); + + const error_code& code() const throw(); + const char* what() const throw(); +}; + +enum class errc +{ + address_family_not_supported, // EAFNOSUPPORT + address_in_use, // EADDRINUSE + address_not_available, // EADDRNOTAVAIL + already_connected, // EISCONN + argument_list_too_long, // E2BIG + argument_out_of_domain, // EDOM + bad_address, // EFAULT + bad_file_descriptor, // EBADF + bad_message, // EBADMSG + broken_pipe, // EPIPE + connection_aborted, // ECONNABORTED + connection_already_in_progress, // EALREADY + connection_refused, // ECONNREFUSED + connection_reset, // ECONNRESET + cross_device_link, // EXDEV + destination_address_required, // EDESTADDRREQ + device_or_resource_busy, // EBUSY + directory_not_empty, // ENOTEMPTY + executable_format_error, // ENOEXEC + file_exists, // EEXIST + file_too_large, // EFBIG + filename_too_long, // ENAMETOOLONG + function_not_supported, // ENOSYS + host_unreachable, // EHOSTUNREACH + identifier_removed, // EIDRM + illegal_byte_sequence, // EILSEQ + inappropriate_io_control_operation, // ENOTTY + interrupted, // EINTR + invalid_argument, // EINVAL + invalid_seek, // ESPIPE + io_error, // EIO + is_a_directory, // EISDIR + message_size, // EMSGSIZE + network_down, // ENETDOWN + network_reset, // ENETRESET + network_unreachable, // ENETUNREACH + no_buffer_space, // ENOBUFS + no_child_process, // ECHILD + no_link, // ENOLINK + no_lock_available, // ENOLCK + no_message_available, // ENODATA + no_message, // ENOMSG + no_protocol_option, // ENOPROTOOPT + no_space_on_device, // ENOSPC + no_stream_resources, // ENOSR + no_such_device_or_address, // ENXIO + no_such_device, // ENODEV + no_such_file_or_directory, // ENOENT + no_such_process, // ESRCH + not_a_directory, // ENOTDIR + not_a_socket, // ENOTSOCK + not_a_stream, // ENOSTR + not_connected, // ENOTCONN + not_enough_memory, // ENOMEM + not_supported, // ENOTSUP + operation_canceled, // ECANCELED + operation_in_progress, // EINPROGRESS + operation_not_permitted, // EPERM + operation_not_supported, // EOPNOTSUPP + operation_would_block, // EWOULDBLOCK + owner_dead, // EOWNERDEAD + permission_denied, // EACCES + protocol_error, // EPROTO + protocol_not_supported, // EPROTONOSUPPORT + read_only_file_system, // EROFS + resource_deadlock_would_occur, // EDEADLK + resource_unavailable_try_again, // EAGAIN + result_out_of_range, // ERANGE + state_not_recoverable, // ENOTRECOVERABLE + stream_timeout, // ETIME + text_file_busy, // ETXTBSY + timed_out, // ETIMEDOUT + too_many_files_open_in_system, // ENFILE + too_many_files_open, // EMFILE + too_many_links, // EMLINK + too_many_symbolic_link_levels, // ELOOP + value_too_large, // EOVERFLOW + wrong_protocol_type // EPROTOTYPE +}; + +template <> struct is_error_condition_enum<errc> : true_type { } + +error_code make_error_code(errc e); +error_condition make_error_condition(errc e); + +// Comparison operators: +bool operator==(const error_code& lhs, const error_code& rhs); +bool operator==(const error_code& lhs, const error_condition& rhs); +bool operator==(const error_condition& lhs, const error_code& rhs); +bool operator==(const error_condition& lhs, const error_condition& rhs); +bool operator!=(const error_code& lhs, const error_code& rhs); +bool operator!=(const error_code& lhs, const error_condition& rhs); +bool operator!=(const error_condition& lhs, const error_code& rhs); +bool operator!=(const error_condition& lhs, const error_condition& rhs); + +template <> struct hash<std::error_code>; + +} // std + +*/ + +#include "llvm/Config/config.h" +#include "llvm/Support/type_traits.h" +#include <cerrno> +#include <string> + +// This must be here instead of a .inc file because it is used in the definition +// of the enum values below. +#ifdef LLVM_ON_WIN32 + // VS 2008 needs this for some of the defines below. +# include <WinSock2.h> + + // The following numbers were taken from VS2010. +# ifndef EAFNOSUPPORT +# define EAFNOSUPPORT WSAEAFNOSUPPORT +# endif +# ifndef EADDRINUSE +# define EADDRINUSE WSAEADDRINUSE +# endif +# ifndef EADDRNOTAVAIL +# define EADDRNOTAVAIL WSAEADDRNOTAVAIL +# endif +# ifndef EISCONN +# define EISCONN WSAEISCONN +# endif +# ifndef E2BIG +# define E2BIG WSAE2BIG +# endif +# ifndef EDOM +# define EDOM WSAEDOM +# endif +# ifndef EFAULT +# define EFAULT WSAEFAULT +# endif +# ifndef EBADF +# define EBADF WSAEBADF +# endif +# ifndef EBADMSG +# define EBADMSG 104 +# endif +# ifndef EPIPE +# define EPIPE WSAEPIPE +# endif +# ifndef ECONNABORTED +# define ECONNABORTED WSAECONNABORTED +# endif +# ifndef EALREADY +# define EALREADY WSAEALREADY +# endif +# ifndef ECONNREFUSED +# define ECONNREFUSED WSAECONNREFUSED +# endif +# ifndef ECONNRESET +# define ECONNRESET WSAECONNRESET +# endif +# ifndef EXDEV +# define EXDEV WSAEXDEV +# endif +# ifndef EDESTADDRREQ +# define EDESTADDRREQ WSAEDESTADDRREQ +# endif +# ifndef EBUSY +# define EBUSY WSAEBUSY +# endif +# ifndef ENOTEMPTY +# define ENOTEMPTY WSAENOTEMPTY +# endif +# ifndef ENOEXEC +# define ENOEXEC WSAENOEXEC +# endif +# ifndef EEXIST +# define EEXIST WSAEEXIST +# endif +# ifndef EFBIG +# define EFBIG WSAEFBIG +# endif +# ifndef ENAMETOOLONG +# define ENAMETOOLONG WSAENAMETOOLONG +# endif +# ifndef ENOSYS +# define ENOSYS WSAENOSYS +# endif +# ifndef EHOSTUNREACH +# define EHOSTUNREACH WSAEHOSTUNREACH +# endif +# ifndef EIDRM +# define EIDRM 111 +# endif +# ifndef EILSEQ +# define EILSEQ WSAEILSEQ +# endif +# ifndef ENOTTY +# define ENOTTY WSAENOTTY +# endif +# ifndef EINTR +# define EINTR WSAEINTR +# endif +# ifndef EINVAL +# define EINVAL WSAEINVAL +# endif +# ifndef ESPIPE +# define ESPIPE WSAESPIPE +# endif +# ifndef EIO +# define EIO WSAEIO +# endif +# ifndef EISDIR +# define EISDIR WSAEISDIR +# endif +# ifndef EMSGSIZE +# define EMSGSIZE WSAEMSGSIZE +# endif +# ifndef ENETDOWN +# define ENETDOWN WSAENETDOWN +# endif +# ifndef ENETRESET +# define ENETRESET WSAENETRESET +# endif +# ifndef ENETUNREACH +# define ENETUNREACH WSAENETUNREACH +# endif +# ifndef ENOBUFS +# define ENOBUFS WSAENOBUFS +# endif +# ifndef ECHILD +# define ECHILD WSAECHILD +# endif +# ifndef ENOLINK +# define ENOLINK 121 +# endif +# ifndef ENOLCK +# define ENOLCK WSAENOLCK +# endif +# ifndef ENODATA +# define ENODATA 120 +# endif +# ifndef ENOMSG +# define ENOMSG 122 +# endif +# ifndef ENOPROTOOPT +# define ENOPROTOOPT WSAENOPROTOOPT +# endif +# ifndef ENOSPC +# define ENOSPC WSAENOSPC +# endif +# ifndef ENOSR +# define ENOSR 124 +# endif +# ifndef ENXIO +# define ENXIO WSAENXIO +# endif +# ifndef ENODEV +# define ENODEV WSAENODEV +# endif +# ifndef ENOENT +# define ENOENT WSAENOENT +# endif +# ifndef ESRCH +# define ESRCH WSAESRCH +# endif +# ifndef ENOTDIR +# define ENOTDIR WSAENOTDIR +# endif +# ifndef ENOTSOCK +# define ENOTSOCK WSAENOTSOCK +# endif +# ifndef ENOSTR +# define ENOSTR 125 +# endif +# ifndef ENOTCONN +# define ENOTCONN WSAENOTCONN +# endif +# ifndef ENOMEM +# define ENOMEM WSAENOMEM +# endif +# ifndef ENOTSUP +# define ENOTSUP 129 +# endif +# ifndef ECANCELED +# define ECANCELED 105 +# endif +# ifndef EINPROGRESS +# define EINPROGRESS WSAEINPROGRESS +# endif +# ifndef EPERM +# define EPERM WSAEPERM +# endif +# ifndef EOPNOTSUPP +# define EOPNOTSUPP WSAEOPNOTSUPP +# endif +# ifndef EWOULDBLOCK +# define EWOULDBLOCK WSAEWOULDBLOCK +# endif +# ifndef EOWNERDEAD +# define EOWNERDEAD 133 +# endif +# ifndef EACCES +# define EACCES WSAEACCES +# endif +# ifndef EPROTO +# define EPROTO 134 +# endif +# ifndef EPROTONOSUPPORT +# define EPROTONOSUPPORT WSAEPROTONOSUPPORT +# endif +# ifndef EROFS +# define EROFS WSAEROFS +# endif +# ifndef EDEADLK +# define EDEADLK WSAEDEADLK +# endif +# ifndef EAGAIN +# define EAGAIN WSAEAGAIN +# endif +# ifndef ERANGE +# define ERANGE WSAERANGE +# endif +# ifndef ENOTRECOVERABLE +# define ENOTRECOVERABLE 127 +# endif +# ifndef ETIME +# define ETIME 137 +# endif +# ifndef ETXTBSY +# define ETXTBSY 139 +# endif +# ifndef ETIMEDOUT +# define ETIMEDOUT WSAETIMEDOUT +# endif +# ifndef ENFILE +# define ENFILE WSAENFILE +# endif +# ifndef EMFILE +# define EMFILE WSAEMFILE +# endif +# ifndef EMLINK +# define EMLINK WSAEMLINK +# endif +# ifndef ELOOP +# define ELOOP WSAELOOP +# endif +# ifndef EOVERFLOW +# define EOVERFLOW 132 +# endif +# ifndef EPROTOTYPE +# define EPROTOTYPE WSAEPROTOTYPE +# endif +#endif + +namespace llvm { + +template <class T, T v> +struct integral_constant { + typedef T value_type; + static const value_type value = v; + typedef integral_constant<T,v> type; + operator value_type() { return value; } +}; + +typedef integral_constant<bool, true> true_type; +typedef integral_constant<bool, false> false_type; + +// is_error_code_enum + +template <class Tp> struct is_error_code_enum : public false_type {}; + +// is_error_condition_enum + +template <class Tp> struct is_error_condition_enum : public false_type {}; + +// Some error codes are not present on all platforms, so we provide equivalents +// for them: + +//enum class errc +struct errc { +enum _ { + success = 0, + address_family_not_supported = EAFNOSUPPORT, + address_in_use = EADDRINUSE, + address_not_available = EADDRNOTAVAIL, + already_connected = EISCONN, + argument_list_too_long = E2BIG, + argument_out_of_domain = EDOM, + bad_address = EFAULT, + bad_file_descriptor = EBADF, +#ifdef EBADMSG + bad_message = EBADMSG, +#else + bad_message = EINVAL, +#endif + broken_pipe = EPIPE, + connection_aborted = ECONNABORTED, + connection_already_in_progress = EALREADY, + connection_refused = ECONNREFUSED, + connection_reset = ECONNRESET, + cross_device_link = EXDEV, + destination_address_required = EDESTADDRREQ, + device_or_resource_busy = EBUSY, + directory_not_empty = ENOTEMPTY, + executable_format_error = ENOEXEC, + file_exists = EEXIST, + file_too_large = EFBIG, + filename_too_long = ENAMETOOLONG, + function_not_supported = ENOSYS, + host_unreachable = EHOSTUNREACH, + identifier_removed = EIDRM, + illegal_byte_sequence = EILSEQ, + inappropriate_io_control_operation = ENOTTY, + interrupted = EINTR, + invalid_argument = EINVAL, + invalid_seek = ESPIPE, + io_error = EIO, + is_a_directory = EISDIR, + message_size = EMSGSIZE, + network_down = ENETDOWN, + network_reset = ENETRESET, + network_unreachable = ENETUNREACH, + no_buffer_space = ENOBUFS, + no_child_process = ECHILD, +#ifdef ENOLINK + no_link = ENOLINK, +#else + no_link = EINVAL, +#endif + no_lock_available = ENOLCK, +#ifdef ENODATA + no_message_available = ENODATA, +#else + no_message_available = ENOMSG, +#endif + no_message = ENOMSG, + no_protocol_option = ENOPROTOOPT, + no_space_on_device = ENOSPC, +#ifdef ENOSR + no_stream_resources = ENOSR, +#else + no_stream_resources = ENOMEM, +#endif + no_such_device_or_address = ENXIO, + no_such_device = ENODEV, + no_such_file_or_directory = ENOENT, + no_such_process = ESRCH, + not_a_directory = ENOTDIR, + not_a_socket = ENOTSOCK, +#ifdef ENOSTR + not_a_stream = ENOSTR, +#else + not_a_stream = EINVAL, +#endif + not_connected = ENOTCONN, + not_enough_memory = ENOMEM, + not_supported = ENOTSUP, +#ifdef ECANCELED + operation_canceled = ECANCELED, +#else + operation_canceled = EINVAL, +#endif + operation_in_progress = EINPROGRESS, + operation_not_permitted = EPERM, + operation_not_supported = EOPNOTSUPP, + operation_would_block = EWOULDBLOCK, +#ifdef EOWNERDEAD + owner_dead = EOWNERDEAD, +#else + owner_dead = EINVAL, +#endif + permission_denied = EACCES, +#ifdef EPROTO + protocol_error = EPROTO, +#else + protocol_error = EINVAL, +#endif + protocol_not_supported = EPROTONOSUPPORT, + read_only_file_system = EROFS, + resource_deadlock_would_occur = EDEADLK, + resource_unavailable_try_again = EAGAIN, + result_out_of_range = ERANGE, +#ifdef ENOTRECOVERABLE + state_not_recoverable = ENOTRECOVERABLE, +#else + state_not_recoverable = EINVAL, +#endif +#ifdef ETIME + stream_timeout = ETIME, +#else + stream_timeout = ETIMEDOUT, +#endif + text_file_busy = ETXTBSY, + timed_out = ETIMEDOUT, + too_many_files_open_in_system = ENFILE, + too_many_files_open = EMFILE, + too_many_links = EMLINK, + too_many_symbolic_link_levels = ELOOP, + value_too_large = EOVERFLOW, + wrong_protocol_type = EPROTOTYPE +}; + + _ v_; + + errc(_ v) : v_(v) {} + operator int() const {return v_;} +}; + +template <> struct is_error_condition_enum<errc> : true_type { }; + +template <> struct is_error_condition_enum<errc::_> : true_type { }; + +class error_condition; +class error_code; + +// class error_category + +class _do_message; + +class error_category +{ +public: + virtual ~error_category(); + +private: + error_category(); + error_category(const error_category&);// = delete; + error_category& operator=(const error_category&);// = delete; + +public: + virtual const char* name() const = 0; + virtual error_condition default_error_condition(int _ev) const; + virtual bool equivalent(int _code, const error_condition& _condition) const; + virtual bool equivalent(const error_code& _code, int _condition) const; + virtual std::string message(int _ev) const = 0; + + bool operator==(const error_category& _rhs) const {return this == &_rhs;} + + bool operator!=(const error_category& _rhs) const {return !(*this == _rhs);} + + bool operator< (const error_category& _rhs) const {return this < &_rhs;} + + friend class _do_message; +}; + +class _do_message : public error_category +{ +public: + virtual std::string message(int ev) const; +}; + +const error_category& generic_category(); +const error_category& system_category(); + +class error_condition +{ + int _val_; + const error_category* _cat_; +public: + error_condition() : _val_(0), _cat_(&generic_category()) {} + + error_condition(int _val, const error_category& _cat) + : _val_(_val), _cat_(&_cat) {} + + template <class E> + error_condition(E _e, typename enable_if_c< + is_error_condition_enum<E>::value + >::type* = 0) + {*this = make_error_condition(_e);} + + void assign(int _val, const error_category& _cat) { + _val_ = _val; + _cat_ = &_cat; + } + + template <class E> + typename enable_if_c + < + is_error_condition_enum<E>::value, + error_condition& + >::type + operator=(E _e) + {*this = make_error_condition(_e); return *this;} + + void clear() { + _val_ = 0; + _cat_ = &generic_category(); + } + + int value() const {return _val_;} + + const error_category& category() const {return *_cat_;} + std::string message() const; + + // explicit + operator bool() const {return _val_ != 0;} +}; + +inline error_condition make_error_condition(errc _e) { + return error_condition(static_cast<int>(_e), generic_category()); +} + +inline bool operator<(const error_condition& _x, const error_condition& _y) { + return _x.category() < _y.category() + || (_x.category() == _y.category() && _x.value() < _y.value()); +} + +// error_code + +class error_code { + int _val_; + const error_category* _cat_; +public: + error_code() : _val_(0), _cat_(&system_category()) {} + + error_code(int _val, const error_category& _cat) + : _val_(_val), _cat_(&_cat) {} + + template <class E> + error_code(E _e, typename enable_if_c< + is_error_code_enum<E>::value + >::type* = 0) { + *this = make_error_code(_e); + } + + void assign(int _val, const error_category& _cat) { + _val_ = _val; + _cat_ = &_cat; + } + + template <class E> + typename enable_if_c + < + is_error_code_enum<E>::value, + error_code& + >::type + operator=(E _e) + {*this = make_error_code(_e); return *this;} + + void clear() { + _val_ = 0; + _cat_ = &system_category(); + } + + int value() const {return _val_;} + + const error_category& category() const {return *_cat_;} + + error_condition default_error_condition() const + {return _cat_->default_error_condition(_val_);} + + std::string message() const; + + // explicit + operator bool() const {return _val_ != 0;} +}; + +inline error_code make_error_code(errc _e) { + return error_code(static_cast<int>(_e), generic_category()); +} + +inline bool operator<(const error_code& _x, const error_code& _y) { + return _x.category() < _y.category() + || (_x.category() == _y.category() && _x.value() < _y.value()); +} + +inline bool operator==(const error_code& _x, const error_code& _y) { + return _x.category() == _y.category() && _x.value() == _y.value(); +} + +inline bool operator==(const error_code& _x, const error_condition& _y) { + return _x.category().equivalent(_x.value(), _y) + || _y.category().equivalent(_x, _y.value()); +} + +inline bool operator==(const error_condition& _x, const error_code& _y) { + return _y == _x; +} + +inline bool operator==(const error_condition& _x, const error_condition& _y) { + return _x.category() == _y.category() && _x.value() == _y.value(); +} + +inline bool operator!=(const error_code& _x, const error_code& _y) { + return !(_x == _y); +} + +inline bool operator!=(const error_code& _x, const error_condition& _y) { + return !(_x == _y); +} + +inline bool operator!=(const error_condition& _x, const error_code& _y) { + return !(_x == _y); +} + +inline bool operator!=(const error_condition& _x, const error_condition& _y) { + return !(_x == _y); +} + +// system_error + +} // end namespace llvm + +// This needs to stay here for KillTheDoctor. +#ifdef LLVM_ON_WIN32 +// FIXME: These two headers really really really need to be removed from here. +// Not only is it a violation of System, they define the stupid min and +// max macros :(. +#include <Windows.h> +#include <WinError.h> + +namespace llvm { + +// To construct an error_code after an API error: +// +// error_code( ::GetLastError(), system_category() ) +struct windows_error { +enum _ { + success = 0, + // These names and values are based on Windows winerror.h + // This is not a complete list. + invalid_function = ERROR_INVALID_FUNCTION, + file_not_found = ERROR_FILE_NOT_FOUND, + path_not_found = ERROR_PATH_NOT_FOUND, + too_many_open_files = ERROR_TOO_MANY_OPEN_FILES, + access_denied = ERROR_ACCESS_DENIED, + invalid_handle = ERROR_INVALID_HANDLE, + arena_trashed = ERROR_ARENA_TRASHED, + not_enough_memory = ERROR_NOT_ENOUGH_MEMORY, + invalid_block = ERROR_INVALID_BLOCK, + bad_environment = ERROR_BAD_ENVIRONMENT, + bad_format = ERROR_BAD_FORMAT, + invalid_access = ERROR_INVALID_ACCESS, + outofmemory = ERROR_OUTOFMEMORY, + invalid_drive = ERROR_INVALID_DRIVE, + current_directory = ERROR_CURRENT_DIRECTORY, + not_same_device = ERROR_NOT_SAME_DEVICE, + no_more_files = ERROR_NO_MORE_FILES, + write_protect = ERROR_WRITE_PROTECT, + bad_unit = ERROR_BAD_UNIT, + not_ready = ERROR_NOT_READY, + bad_command = ERROR_BAD_COMMAND, + crc = ERROR_CRC, + bad_length = ERROR_BAD_LENGTH, + seek = ERROR_SEEK, + not_dos_disk = ERROR_NOT_DOS_DISK, + sector_not_found = ERROR_SECTOR_NOT_FOUND, + out_of_paper = ERROR_OUT_OF_PAPER, + write_fault = ERROR_WRITE_FAULT, + read_fault = ERROR_READ_FAULT, + gen_failure = ERROR_GEN_FAILURE, + sharing_violation = ERROR_SHARING_VIOLATION, + lock_violation = ERROR_LOCK_VIOLATION, + wrong_disk = ERROR_WRONG_DISK, + sharing_buffer_exceeded = ERROR_SHARING_BUFFER_EXCEEDED, + handle_eof = ERROR_HANDLE_EOF, + handle_disk_full = ERROR_HANDLE_DISK_FULL, + rem_not_list = ERROR_REM_NOT_LIST, + dup_name = ERROR_DUP_NAME, + bad_net_path = ERROR_BAD_NETPATH, + network_busy = ERROR_NETWORK_BUSY, + file_exists = ERROR_FILE_EXISTS, + cannot_make = ERROR_CANNOT_MAKE, + broken_pipe = ERROR_BROKEN_PIPE, + open_failed = ERROR_OPEN_FAILED, + buffer_overflow = ERROR_BUFFER_OVERFLOW, + disk_full = ERROR_DISK_FULL, + lock_failed = ERROR_LOCK_FAILED, + busy = ERROR_BUSY, + cancel_violation = ERROR_CANCEL_VIOLATION, + already_exists = ERROR_ALREADY_EXISTS +}; + _ v_; + + windows_error(_ v) : v_(v) {} + explicit windows_error(DWORD v) : v_(_(v)) {} + operator int() const {return v_;} +}; + + +template <> struct is_error_code_enum<windows_error> : true_type { }; + +template <> struct is_error_code_enum<windows_error::_> : true_type { }; + +inline error_code make_error_code(windows_error e) { + return error_code(static_cast<int>(e), system_category()); +} + +} // end namespace llvm + +#endif // LLVM_ON_WINDOWS + +#endif |