Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

734 lines
26 KiB

//////////////////////////////////////////////////////////////////////
// PATH.H
//
// Definition of CPath and CDir objects.
//
// History
// =======
// Date Who What
// ---- --- ----
// 07-May-93 mattg Created
// 12-May-93 danw Add operator = and GetDisplayName
// 20-May-93 mattg Added CDir object
// 22-May-93 danw Added ConstructObject and DestructObject
// for collections.
// 11-Jul-93 mattg Added many new methods to CPath and CDir
// Also "TCHAR'ified"
// 20-Jul-93 danw Added relativization functions.
//////////////////////////////////////////////////////////////////////
#ifndef __PATH_H__
#define __PATH_H__
#ifndef _INC_DIRECT
#include <direct.h>
#endif
#ifndef _INC_IO
#include <io.h>
#endif
#ifndef _INC_TCHAR
#include <tchar.h>
#endif
#ifndef _WIN32
#include <ctype.h>
#endif
#ifndef _INC_STAT
#include <sys\stat.h>
#endif
#pragma warning(disable : 4275 4251)
size_t RemoveNewlines(_TCHAR *);
//
// Compatible_GetFileAttributesEx
// g_pGetFileAttributesEx initially points to a function that chooses the new win32 api,
// GetFileAttributesEx if supported, or selects a compatible function that uses FindFirstFile.
//
extern BOOL AFX_DATA (WINAPI *g_pGetFileAttributesEx)( LPCTSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
LPVOID lpFileInformation);
__inline BOOL Compatible_GetFileAttributesEx( LPCTSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId,
LPVOID lpFileInformation)
{
return (*g_pGetFileAttributesEx)( lpFileName, fInfoLevelId, lpFileInformation);
}
//////////////////////////////////////////////////////////////////////
// Classes defined in this file
// CObject
class CPath;
class CDir;
//////////////////////////////////////////////////////////////////////
// Scan a path in see if it contains special charaters that would
// required it to be quoted:
BOOL ScanPathForSpecialCharacters (const TCHAR *pPath);
//////////////////////////////////////////////////////////////////////
// CPath
class LTAPIENTRY CPath : public CObject
{
DECLARE_DYNAMIC(CPath)
friend class CDir;
friend static VOID ConstructElement(CPath *);
friend static VOID DestructElement(CPath *);
protected:
// Data
CString m_strCanon;
int m_ichLastSlash; // used to quickly extract only dir or filename
BOOL m_Flags;
enum PathFlags
{
eIsActualCase = 1,
eWantsRelative = 2,
};
// Canonicalized representation of pathname.
static CMapStringToString c_DirCaseMap;
public:
// Constructors, destructors, initialization methods
inline CPath() { m_ichLastSlash = -1; m_Flags = 0;}
inline CPath(const CPath & path)
{
m_strCanon = path.m_strCanon;
m_ichLastSlash = path.m_ichLastSlash;
m_Flags = path.m_Flags;
}
virtual ~CPath();
inline BOOL GetAlwaysRelative() const { return ((m_Flags & eWantsRelative) != 0); }
inline void SetAlwaysRelative(BOOL bWantsRel = TRUE) { m_Flags =
(bWantsRel) ? m_Flags | eWantsRelative : m_Flags & ~eWantsRelative;}
inline BOOL IsInit() const { ASSERT(this!=NULL); return (m_ichLastSlash > 0); }
BOOL Create(const TCHAR *);
// Initialize the object, given a filename. The resulting
// canonicalized filename will be relative to the current
// directory. For example, if the current directory is
// C:\TEST and the argument is "FOO.C", the resulting
// canonicalized filename will be "C:\TEST\FOO.C". If the
// argument is "..\FOO.C", the resulting canonicalized
// filename will be "C:\FOO.C".
BOOL CreateFromDirAndFilename(const CDir &, const TCHAR *);
// Initialize the object given a directory (CDir object) and
// a filename. This behaves exactly the same as the Create()
// method, except that the Create() method canonicalizes the
// filename relative to the CURRENT directory, whereas this
// method canonicalizes the filename relative to the SPECIFIED
// directory.
BOOL CreateTemporaryName(const CDir &, BOOL fKeep = TRUE);
// Initialize the object given a directory. The resulting
// object will represent a UNIQUE filename in that directory.
// This is useful for creating temporary filenames.
//
// WARNING
// -------
// After this method returns, the filename represented by this
// object will EXIST ON DISK as a zero length file. This is
// to prevent subsequent calls to this method from returning
// the same filename (this method checks to make sure it
// doesn't return the name of an existing file). IT IS YOUR
// RESPONSIBILITY to delete the file one way or another.
//
// If you don't want this behavior, pass FALSE for 'fKeep',
// and the file will not exist on disk. Be aware, though,
// that if you do this, subsequent calls to this method may
// return the same filename.
BOOL ContainsSpecialCharacters () const
{
return ::ScanPathForSpecialCharacters(m_strCanon);
}
// Scan the pathname for special character. We cache this
// information.
inline CPath & operator =(const CPath & path)
{
ASSERT(path.IsInit());
m_strCanon = path.m_strCanon;
m_ichLastSlash = path.m_ichLastSlash;
m_Flags = path.m_Flags;
return(*this);
}
// Assignment operator.
// Query methods
inline const TCHAR * GetFileName() const
{
ASSERT(IsInit());
ASSERT(m_ichLastSlash==m_strCanon.ReverseFind('\\'));
return ((const TCHAR *)m_strCanon + m_ichLastSlash + 1);
}
// Return a pointer to the filename part of the canonicalized
// pathname, i.e., the filename with no leading drive or path
// information. Return whole string if no backslash (not init).
//
// Please do not write through this pointer, as it is pointing
// to internal data!
VOID PostFixNumber();
// Modifies the path by postfixing a number on the end of the path's
// basename. If there is no number on the end of the path's basename
// then the number 1 is postfixed. Otherwise if there already is a
// number on the end of the path's basename then that number is
// incremented by 1 and postfixed on the end of the basename (less the
// original number).
//
// e.g. foo.cpp -> foo1.cpp -> foo2.cpp -> foo3.cpp
VOID GetBaseNameString(CString &) const;
// Creates a CString representing the base name of the fully
// canonicalized pathname. For example, the base name of
// the pathname "C:\FOO\BAR.C" is "BAR".
//
// This method can't return a pointer to internal data like
// some of the other methods since it would have to remove
// the extension in order to do so.
VOID GetDisplayNameString(
CString &,
int cchMax = 16,
BOOL bTakeAllAsDefault = FALSE
) const;
// Creates a CString representing the name of the file
// shortened to cchMax CHARACTERS (TCHARs, not bytes) or
// less. Only the actual characters are counted; the
// terminating '\0' is not considered, so
// CString::GetLength() on the result MAY return as much as
// cchMax. If cchMax is less than the length of the base
// filename, the resulting CString will be empty, unless
// bTakeAllAsDefault is TRUE, in which the base name is
// copied in, regardless of length.
//
// As an example, "C:\SOMEDIR\OTHERDIR\SUBDIR\SPECIAL\FOO.C"
// will be shortened to "C:\...\SPECIAL\FOO.C" if cchMax is 25.
inline const TCHAR * GetExtension() const
{
ASSERT(IsInit());
int iDot = m_strCanon.ReverseFind(_T('.'));
if (iDot < m_ichLastSlash)
iDot = m_strCanon.GetLength();
const TCHAR * retval = ((const TCHAR *)m_strCanon) + iDot;
return retval;
}
// Return a pointer to the extension part of the canonicalized
// pathname. Returns a pointer to the '.' character of the
// extension. If the filename doesn't have an extension,
// the pointer returned will point to the terminating '\0'.
//
// Please do not write through this pointer, as it is pointing
// to internal data!
inline const TCHAR * GetFullPath() const { return(m_strCanon); }
// Return a pointer to the full (canonicalized) pathname.
//
// Please do not write through this pointer, as it is pointing
// to internal data!
inline const TCHAR * GetFullPath(CString & strPath) const { return(strPath = m_strCanon); }
inline BOOL IsActualCase() const { ASSERT(this!=NULL); return ((m_Flags & eIsActualCase)!=0); }
void GetActualCase(BOOL bEntirePath = FALSE);
// Adjusts the paths case to match the actual path and filename
// on disk.
void SetActualCase(LPCTSTR pszFileCase);
// Adjusts the paths case to match the actual path and filename
// on disk, where pszFileCase already contains the correct case
// for just the filename portion.
static void ResetDirMap();
inline operator const TCHAR *() const { return(m_strCanon); }
// Return the fully canonicalized filename as a (const TCHAR *).
// Same thing as GetFullPath(), but more convenient in some
// cases.
//
// Please do not write through this pointer, as it is pointing
// to internal data!
inline BOOL IsUNC() const { return(m_strCanon[0] == _T('\\')); }
// Returns TRUE if the pathname is UNC (e.g.,
// "\\server\share\file"), FALSE if not.
inline BOOL IsEmpty() const { return (m_strCanon.IsEmpty()); }
// Comparison methods
int operator ==(const CPath &) const;
// Returns 1 if the two CPaths are identical, 0 if they are
// different.
inline int operator !=(const CPath & path) const { return(!(operator ==(path))); }
// Returns 1 if the two CPaths are different, 0 if they are
// identical.
// Modification methods
VOID ChangeFileName(const TCHAR *);
// Changes the file name to that specified by the
// (const TCHAR *) argument. The directory portion of the
// pathname remains unchanged. DO NOT pass in anything
// other than a simple filename, i.e., do not pass in
// anything with path modifiers.
VOID ChangeExtension(const TCHAR *);
// Changes the extension of the pathname to be that specified
// by the (const TCHAR *) argument. The argument can either be
// of the form ".EXT" or "EXT". If the current pathname has
// no extension, this is equivalent to adding the new extension.
BOOL GetRelativeName (const CDir&, CString&, BOOL bQuote = FALSE, BOOL bIgnoreAlwaysRelative = FALSE) const;
// Makes the path name relative to the supplied directory and
// placed the result in strResult. Function will only go
// down from the supplied directy (no ..'s). Returns TRUE if
// relativization was successful, or FALSE if not (e.g. if
// string doesn't start with ".\" or ..\ or at least \).
//
// Thus, if the base directory is c:\sushi\vcpp32:
//
// s:\sushi\vcpp32\c\fmake.c => s:\sushi\vcpp32\c\fmake.c
// c:\sushi\vcpp32\c\fmake.c => .\fmake.c
// c:\dolftool\bin\cl.exe => \dolftool\bin\cl.exe
// \\danwhite\tmp\test.cpp => \\danwhite\tmp\test.cpp
// Thus, if the base directory is \\danwhite\c$\sushi\vcpp32:
//
// \\danwhite\c$\dolftool\bin\cl.exe => \dolftool\bin\cl.exe
// \\danwhite\tmp\test.cpp => \\danwhite\tmp\test.cpp
// If bQuote is true, then quotes are put around the relative
// file name. (Useful for writing the filename out to a file)
// If (!bIgnoreAlwaysRelative && GetAlwaysRelative()) is TRUE
// and if the file is on the same drive we will ALWAYS
// relativize it. Thus for the base dir c:\sushi\vcpp32
// c:\dolftool\bin\cl.exe => ..\..\dolftool\bin\cl.exe
BOOL CreateFromDirAndRelative (const CDir&, const TCHAR *);
// THIS FUNCTION IS OBSOLETE. New code should use
// CreateFromDirAndFilename(). The only difference between
// that function and this one is that this one will
// automatically remove quotes from around the relative
// path name (if present).
// Miscellaneous methods
inline BOOL IsReadOnlyOnDisk() const
{
HANDLE h;
ASSERT(IsInit());
h = CreateFile(m_strCanon, GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_NOT_FOUND)
return TRUE;
if (h != INVALID_HANDLE_VALUE)
CloseHandle(h);
return FALSE;
}
// Returns TRUE if the filename represented by this object
// is read-only on disk, FALSE if not. NOT guaranteed to
// work in all circumstances -- for example, will not return
// TRUE for a file on a floppy drive that has been write-
// protected. I don't know of any way to get this information
// from NT (GetFileAttributes doesn't work; GetVolumeInformation
// doesn't work; _access just calls GetFileAttributes; etc.).
// This method WILL correctly detect:
// - Files marked as read-only
// - Files on read-only network drives
inline BOOL ExistsOnDisk() const
{
ASSERT(IsInit());
return(_access(m_strCanon, 00) != -1);
}
// Returns TRUE if the filename represented by this object
// exists on disk, FALSE if not.
inline BOOL CanCreateOnDisk(BOOL fOverwriteOK = FALSE) const
{
ASSERT(IsInit());
if (!fOverwriteOK && ExistsOnDisk())
return(FALSE);
int hFile = _creat(m_strCanon, _S_IREAD | _S_IWRITE);
BOOL fCreate = (hFile != -1);
if (fCreate)
{
VERIFY(_close(hFile) == 0);
VERIFY(_unlink(m_strCanon) == 0);
}
return(fCreate);
}
// Returns TRUE if the filename represented by this object
// can be created on disk, FALSE if not.
inline BOOL DeleteFromDisk() const
{
ASSERT(IsInit());
#ifdef _WIN32
return(DeleteFile((TCHAR *)(const TCHAR *)m_strCanon));
#else
return(remove(m_strCanon) != -1);
#endif
}
// Removes the file represented by this object from the disk.
BOOL GetFileTime(LPFILETIME lpftLastWrite);
BOOL GetFileTime(CString& rstrLastWrite, DWORD dwFlags = DATE_SHORTDATE);
// Returns the last modified time, as either an FILETIME struct or a string
};
// Creation and destruction functions used by CMapPathToOb:
extern const CString AFX_DATA pthEmptyString;
static inline VOID ConstructElement(CPath * pNewData)
{
memcpy(&pNewData->m_strCanon, &pthEmptyString, sizeof(CString));
}
static inline VOID DestructElement(CPath * pOldData)
{
pOldData->m_strCanon.Empty();
}
// File Name Utility Functions
// These are redundant and could be replaced with use of CPath, but are
// kept since they are easier to use and already exist in VRES.
// Remove the drive and directory from a file name.
CString StripPath(LPCTSTR szFilePath);
// Remove the name part of a file path. Return just the drive and directory.
CString StripName(LPCTSTR szFilePath);
// Get only the extension of a file path.
CString GetExtension(LPCTSTR szFilePath);
// Return the path to szFilePath relative to szDirectory. (e.g. if szFilePath
// is "C:\FOO\BAR\CDR.CAR" and szDirectory is "C:\FOO", then "BAR\CDR.CAR"
// is returned. This will never use '..'; if szFilePath is not in szDirectory
// or a sub-directory, then szFilePath is returned unchanged.
//
CString GetRelativeName(LPCTSTR szFilePath, LPCTSTR szDirectory = NULL);
// Makes a file path look like in MRU.
CString GetDisplayName(LPCTSTR szFilePath, int nMaxDisplayLength,
LPCTSTR szDirectory = NULL);
BOOL FileExists(LPCTSTR szFilePath);
BOOL IsFileWritable(LPCTSTR szFilePath);
UINT SushiGetFileTitle(LPCTSTR lpszPathName, LPTSTR lpszTitle, UINT nMax);
//////////////////////////////////////////////////////////////////////
// CDir
//
// The CDir object represents a file system directory on some disk.
//
// A CDir object can be created to represent the current directory,
// to represent the directory of a CPath object (i.e., the directory
// in which a file resides), and to represent a temporary directory.
// Note that a CDir object CANNOT be created given an arbitrary string --
// this is intentional, since this should not be necessary.
//
// The string representation of a CDir object (e.g., operator const TCHAR *())
// MAY or MAY NOT end in '\'. The root directory of a local drive (e.g., C:)
// will end in '\' ("C:\"), while other directories on a local drive will
// not ("C:\OTHERDIR"). The root directory on a REMOTE drive will NOT end
// in '\' ("\\server\share"). Don't make any assumptions about whether or
// not the string representation ends in '\'.
//
// See also several CPath methods which use CDir objects.
class LTAPIENTRY CDir : public CObject
{
DECLARE_DYNAMIC(CDir)
friend class CPath;
friend static VOID ConstructElement(CDir *);
friend static VOID DestructElement(CDir *);
protected:
CString m_strDir;
// Directory name, including drive letter or
// server/share. Do NOT make any assumptions
// about whether or not this ends in '\'!
// Creates multi level directories just fine
BOOL MakeDirectory(LPCTSTR lpszPathName) const;
public:
// Constructors, destructors, initialization methods
inline CDir() {}
inline CDir(const CDir & dir) { m_strDir = dir.m_strDir; }
virtual ~CDir();
BOOL CreateFromCurrent();
// Initialize from the current working directory. This
// may fail if the current working directory is unknown
// or invalid.
BOOL CreateFromPath(const CPath &);
// Initialize based on the directory of the specified
// CPath object. That is, if the CPath object represents
// the file "C:\FOO\BAR\BLIX.C", the resulting directory
// for this object will be "C:\FOO\BAR". Returns FALSE
// on failure.
BOOL CreateFromPath(const TCHAR *pszPath);
// Initialize based on the directory of the specified
// string. That is, if the string contains the file name
// "C:\FOO\BAR\BLIX.C", the generated directory for this
// string will be "C:\FOO\BAR". Returns FALSE on failure.
BOOL CreateTemporaryName();
// Initialize this object to represent a temporary directory
// on disk (e.g., "C:\TMP").
inline BOOL CreateFromString(const TCHAR * sz)
{
return CreateFromStringEx(sz, FALSE);
}
// Create from a string (e.g., "C:\", "C:\TMP", etc.). Please
// do not use this method when another would suffice!
BOOL CreateFromStringEx(const TCHAR * sz, BOOL fRootRelative);
// Create from a string (e.g., "C:\", "C:\TMP", etc.). Please
// do not use this method when another would suffice!
// same as CreateFromString with minor change. Not treating as bug fix to CFS
// due to lateness in VC 4.0 project time
// if fRootRelative true, treat dir ending with colon as relative not root dir
// (actual correct handling)
BOOL ContainsSpecialCharacters () const
{
return ::ScanPathForSpecialCharacters(m_strDir);
}
// Scan the pathname for special character. We cache this information.
inline CDir & operator =(const CDir & dir)
{
m_strDir = dir.m_strDir;
return(*this);
}
// Assignment operator.
// Query methods
inline operator const TCHAR *() const { return(m_strDir); }
// Return the directory name as a (const TCHAR *) string.
inline int GetLength() const { return m_strDir.GetLength(); }
// Returns the length of the directory name
// Miscellaneous methods
BOOL MakeCurrent() const;
// Make this object the current working directory. May fail
// if the directory no longer exists (e.g., a floppy drive).
inline BOOL ExistsOnDisk() const
{
// Tests if the directory exists. We return FALSE
// if <m_strDir> exists but is not a directory
struct _stat statDir;
if (_stat(m_strDir, &statDir) == -1)
return FALSE; // Not found.
else if (!(statDir.st_mode & _S_IFDIR))
return FALSE; // Not a directory.
else
return TRUE;
}
// Returns TRUE if the directory represented by this object
// exists on disk, FALSE if not.
inline BOOL CreateOnDisk() const { return MakeDirectory(m_strDir); }
// Creates the directory on disk. If this fails, returns
// FALSE. If the directory already existed on disk, returns
// TRUE (i.e., that is not an error condition).
inline BOOL RemoveFromDisk() const { return RemoveDirectory(m_strDir); }
// Removes the directory from the disk. If this fails for
// any reason (directory does not exist, directory is not
// empty, etc.), returns FALSE.
BOOL IsRootDir() const;
// Returns TRUE if the directory represented by this object
// is a root directory (e.g., "C:\"), FALSE if not. Note that
// calling this method will NOT tell you whether or not the
// string representation ends in '\', since "\\server\share"
// is a root directory, and does not end in '\'.
inline BOOL IsUNC() const { return(m_strDir[0] == _T('\\')); }
// Returns TRUE if this is a UNC directory, FALSE if not.
VOID AppendSubdirName(const TCHAR *);
// Adds a subdirectory name. For example, if this object
// currently represents "C:\FOO\BAR", and the argument is
// "$AUTSAV$", the resulting object represents
// "C:\FOO\BAR\$AUTSAV$".
//
// WARNING: This method does NO validation of the result --
// it does not check for illegal characters, or for a
// directory name that is too long. In particular, don't
// pass "DIR1/DIR2" as an argument, since no conversion
// (of '/' to '\') will occur.
VOID RemoveLastSubdirName();
// Removes the last component of the directory name. For
// example, if this object currently represents
// "C:\FOO\BAR\$AUTSAV$", after this method it will
// represent "C:\FOO\BAR". If you try to call this method
// when the object represents a root directory (e.g., "C:\"),
// it will ASSERT.
// Comparison methods
int operator ==(const CDir &) const;
// Returns 1 if the two CDirs are identical, 0 if they are
// different.
inline int operator !=(const CDir & dir) const { return(!(operator ==(dir))); }
// Returns 1 if the two CDirs are different, 0 if they are
// identical.
};
// Creation and destruction functions used by CMapDirToOb:
static inline VOID ConstructElement(CDir * pNewData)
{
memcpy(&pNewData->m_strDir, &pthEmptyString, sizeof(CString));
}
static inline VOID DestructElement(CDir * pOldData)
{
pOldData->m_strDir.Empty();
}
///////////////////////////////////////////////////////////////////////////////
// CCurDir
// This class is used to switch the current drive/directory during the
// life of the object and to restore the previous dirve/directory upon
// destruction.
class LTAPIENTRY CCurDir : CDir
{
public:
CCurDir(const char* szPath, BOOL bFile = FALSE);
CCurDir(const CDir& dir);
CCurDir(); // just saves the current directory and resets it
~CCurDir();
CDir m_dir;
};
///////////////////////////////////////////////////////////////////////////////
// CFileOpenReturn
// This class represents the return value from the Common Dialogs
// File.Open. It handles both single and multiple select types.
//
class LTAPIENTRY CFileOpenReturn : CObject
{
BOOL m_bSingle;
BOOL m_bBufferInUse;
BOOL m_bArrayHasChanged;
int m_cbData;
_TCHAR * m_pchData;
// Multiple Files
CPtrArray m_rgszNames;
public:
CFileOpenReturn (const _TCHAR * szRawString = NULL);
~CFileOpenReturn ();
inline BOOL IsSingle () const;
inline BOOL IsDirty() const;
inline BOOL BufferOverflow () const;
//inline int GetLength () const;
// GetBuffer gives permission for something else to directly change the buffer
// ReleaseBuffer signifies that the something else is done with it.
_TCHAR * GetBuffer (int cbBufferNew);
inline void ReleaseBuffer ();
// allows the object to be re-initialized
void ReInit (const _TCHAR * szRawString);
// This supports the dynamic file extension update in OnFileNameOK().
void ChangeExtension (int i, const CString& szExt);
void CopyBuffer (_TCHAR * szTarget);
// This is the function to use to get at the user's selections,
// whether single or multiple.
BOOL GetPathname (int i, CString& strPath) const;
private:
void GenArrayFromBuffer ();
void GenBufferFromArray ();
void ClearNamesArray ();
void SetBuffer (const _TCHAR * szRawString);
};
inline BOOL CFileOpenReturn::IsSingle () const
{
return m_bSingle;
}
inline BOOL CFileOpenReturn::IsDirty() const
{
return m_bArrayHasChanged;
}
inline BOOL CFileOpenReturn::BufferOverflow () const
{
return m_cbData == 2 && m_pchData[0] == '?';
}
///// ReleaseBuffer - Tell object we're done changing the buffer
//
// Processes the raw string
//
///
inline void CFileOpenReturn::ReleaseBuffer ()
{
m_bBufferInUse = FALSE;
GenArrayFromBuffer ();
}
///////////////////////////////////////////////////////////////////////////////
// Smart case helpers.
// These functions are used to do smart casing of paths and file extensions.
extern BOOL GetActualFileCase( CString& rFilename, LPCTSTR lpszDir = NULL );
extern LPCTSTR GetExtensionCase( LPCTSTR lpszFilename, LPCTSTR lpszExtension );
extern BOOL GetDisplayFile(CString &rFilename, CDC *pDC, int &cxPels); // truncates from left
/////////////////////////////////////////////////////////////////////////////
#pragma warning(default : 4275 4251)
#endif // __PATH_H__