blob: 6cff312e6277856560b2be7f89db1e1c5ef56065 [file] [log] [blame]
/***************************************************************************
*
* path.cpp
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 1994-2006 Rogue Wave Software.
*
**************************************************************************/
#include "path.h"
#include "diagnostic.h" // for issue_diag()
#include <cassert> // for assert()
#include <cerrno> // for ERANGE
#include <cstdlib> // for getenv()
#include <cstring> // for strerror()
#include <string> // for string
#ifndef _MSC_VER
# ifdef __linux__
// for symlink()
# ifndef _XOPEN_SOURCE
# define _XOPEN_SOURCE
# endif
# ifndef _XOPEN_SOURCE_EXTENDED
# define _XOPEN_SOURCE_EXTENDED
# endif
# endif // __linux__
# include <unistd.h> // for getcwd()
# include <sys/stat.h> // for struct stat, stat()
#else
# include <direct.h> // for struct _stat
# include <io.h>
# include <windows.h> // for _getcwd()
# include <sys/types.h>
# include <sys/stat.h> // for struct stat, stat()
#endif // _MSC_VER
static char* get_cwd (char* s, std::size_t l)
{
#if !defined (_MSC_VER)
return getcwd (s, l);
#else
return _getcwd (s, l);
#endif
}
#ifndef _MSC_VER
void
create_symlink (const std::string &dir,
const std::string &xname,
const std::string &sname)
{
int ret = 0;
char* pret = 0;
char buf [1024];
if (dir.size ()) {
pret = get_cwd (buf, 1024);
if (pret == 0) {
issue_diag (213, true, 0,
"could not retrieve current working directory\n") ;
}
ret = chdir (dir.c_str ());
if (ret == -1)
issue_diag (214, false, 0, "could not change directory to %s\n",
dir.c_str ()) ;
}
ret = symlink(xname.c_str(), sname.c_str());
#ifdef EEXIST
if (ret == -1 && errno != EEXIST) {
issue_diag (215, false, 0,
"could not create symbolic link to %s "
"locale database (%s)\n",
xname.c_str (), std::strerror (errno)) ;
}
#endif // EEXIST
// go back to previous wd
if (dir.size ()) {
chdir (pret);
}
}
#endif // _MSC_VER
inline int
filemode (const char *path)
{
assert (0 != path);
struct stat buf;
return stat (path, &buf) ? 0 : buf.st_mode;
}
std::string
get_pathname (const std::string &fname,
const std::string &other /* = std::string () */)
{
// use absolute path as given by fname
#if !defined (_MSC_VER)
if (fname.size () && _RWSTD_PATH_SEP == fname [0])
#else
if (fname.size () &&
fname [1] && fname [1] == ':' &&
fname [2] && fname [2] == _RWSTD_PATH_SEP)
#endif
return fname;
std::string pathname;
std::string dir_other (
other.substr (0,other.rfind (_RWSTD_PATH_SEP) + 1));
// OR use the path given through "other", be it relative or absolute
#if !defined (_MSC_VER)
if (other.size () && _RWSTD_PATH_SEP == other [0]) {
#else
if (other.size () &&
other [1] && other [1] == ':' &&
other [2] && other [2] == _RWSTD_PATH_SEP) {
#endif
// other is an absolute path; compose dirname(other) + fname
(pathname += dir_other) += fname;
} else {
pathname.resize (1024);
// other is a relative path; compose cwd() + dirname(other) + fname
while (!get_cwd (&pathname [0], pathname.size ())) {
if (ERANGE != errno) {
issue_diag (213, true, 0,
"could not retrieve current working directory\n");
return fname;
}
// buffer too small, reallocate
pathname.resize (pathname.size () * 2);
}
pathname.resize (std::strlen (pathname.data ()));
if (pathname.size() &&
pathname [pathname.size () - 1] != _RWSTD_PATH_SEP)
pathname += _RWSTD_PATH_SEP;
(pathname += dir_other) += fname;
}
#if !defined (_MSC_VER)
if (S_ISREG (filemode (pathname.c_str ())))
#else
if (S_IFREG & filemode (pathname.c_str ()))
#endif // !defined (_MSC_VER)
return pathname;
// use the value of RWSTD_SRC_ROOT
const char* const src_root = std::getenv ("RWSTD_SRC_ROOT");
if (src_root && *src_root) {
// if the environment variable is not empty, append `fname'
// to it and see if the file exists and names a regular file
// if so, return its pathname
pathname = src_root;
(((pathname += _RWSTD_PATH_SEP) += "src") += _RWSTD_PATH_SEP) += fname;
#if !defined (_MSC_VER)
if (S_ISREG (filemode (pathname.c_str ())))
#else
if (S_IFREG & filemode (pathname.c_str ()))
#endif // !defined (_MSC_VER)
return pathname;
}
// allocate a sufficiently large buffer for the cwd
pathname.resize (1024);
// use current working directory
while (!get_cwd (&pathname [0], pathname.size ())) {
if (ERANGE != errno) {
issue_diag (213, true, 0,
"could not retrieve current working directory\n");
return fname;
}
// buffer too small, reallocate
pathname.resize (pathname.size () * 2);
}
// chop off everything past the terminating NUL
pathname.resize (std::strlen (pathname.data ()));
pathname += fname;
#if !defined (_MSC_VER)
if (S_ISREG (filemode (pathname.c_str ())))
#else
if (S_IFREG & filemode (pathname.c_str ()))
#endif // !defined (_MSC_VER)
return pathname;
return fname;
}
int makedir (const char *name)
{
#if defined (_WIN32) || defined (_WIN64)
if ( 0 == CreateDirectory (name, NULL)
&& GetLastError () != ERROR_ALREADY_EXISTS) {
LPVOID lpMsgBuf;
FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS,
0,
GetLastError (),
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0,
0);
issue_diag (E_CALL, true, 0, (char*)lpMsgBuf);
return -1;
}
#else // if !defined (_WIN{32,64})
if (-1 == mkdir (name, 0755)) {
# ifdef EEXIST
if (errno != EEXIST) {
issue_diag (E_CALL, true, 0, "failed to create directory %s: %s\n",
name, std::strerror (errno));
return -1;
}
# endif // EEXIST
}
#endif // _WIN{32,64}
return 0;
}