phoenix-firestorm/indra/llcommon/lltempredirect.cpp

139 lines
3.5 KiB
C++

/**
* @file lltempredirect.cpp
* @author Nat Goodspeed
* @date 2019-10-31
* @brief Implementation for lltempredirect.
*
* $LicenseInfo:firstyear=2019&license=viewerlgpl$
* Copyright (c) 2019, Linden Research, Inc.
* $/LicenseInfo$
*/
// Precompiled header
#include "linden_common.h"
// associated header
#include "lltempredirect.h"
// STL headers
// std headers
#if !LL_WINDOWS
# include <unistd.h>
#else
# include <io.h>
#endif // !LL_WINDOWS
// external library headers
// other Linden headers
/*****************************************************************************
* llfd
*****************************************************************************/
// We could restate the implementation of each of llfd::close(), etc., but
// this is way more succinct.
#if LL_WINDOWS
#define fhclose _close
#define fhdup _dup
#define fhdup2 _dup2
#define fhfdopen _fdopen
#define fhfileno _fileno
#else
#define fhclose ::close
#define fhdup ::dup
#define fhdup2 ::dup2
#define fhfdopen ::fdopen
#define fhfileno ::fileno
#endif
int llfd::close(int fd)
{
return fhclose(fd);
}
int llfd::dup(int target)
{
return fhdup(target);
}
int llfd::dup2(int target, int reference)
{
return fhdup2(target, reference);
}
FILE* llfd::open(int fd, const char* mode)
{
return fhfdopen(fd, mode);
}
int llfd::fileno(FILE* stream)
{
return fhfileno(stream);
}
/*****************************************************************************
* LLTempRedirect
*****************************************************************************/
LLTempRedirect::LLTempRedirect():
mOrigTarget(-1), // -1 is an invalid file descriptor
mReference(-1)
{}
LLTempRedirect::LLTempRedirect(FILE* target, FILE* reference):
LLTempRedirect((target? fhfileno(target) : -1),
(reference? fhfileno(reference) : -1))
{}
LLTempRedirect::LLTempRedirect(int target, int reference):
// capture a duplicate file descriptor for the file originally targeted by
// 'reference'
mOrigTarget((reference >= 0)? fhdup(reference) : -1),
mReference(reference)
{
if (target >= 0 && reference >= 0)
{
// As promised, force 'reference' to refer to 'target'. This first
// implicitly closes 'reference', which is why we first capture a
// duplicate so the original target file stays open.
fhdup2(target, reference);
}
}
LLTempRedirect::LLTempRedirect(LLTempRedirect&& other)
{
mOrigTarget = other.mOrigTarget;
mReference = other.mReference;
// other LLTempRedirect must be in moved-from state so its destructor
// won't repeat the same operations as ours!
other.mOrigTarget = -1;
other.mReference = -1;
}
LLTempRedirect::~LLTempRedirect()
{
reset();
}
void LLTempRedirect::reset()
{
// If this instance was default-constructed (or constructed with an
// invalid file descriptor), skip the following.
if (mOrigTarget >= 0)
{
// Restore mReference to point to mOrigTarget. This implicitly closes
// the duplicate created by our constructor of its 'target' file
// descriptor.
fhdup2(mOrigTarget, mReference);
// mOrigTarget has served its purpose
fhclose(mOrigTarget);
}
// assign these because reset() is also responsible for a "moved from"
// instance
mOrigTarget = -1;
mReference = -1;
}
LLTempRedirect& LLTempRedirect::operator=(LLTempRedirect&& other)
{
reset();
std::swap(mOrigTarget, other.mOrigTarget);
std::swap(mReference, other.mReference);
return *this;
}