blob: 847e1dfe5139aedcbe8c2ed2c43b87552daec4fc [file] [log] [blame]
/** \file filename.hpp .
-----------------------------------------------------------------------------
* 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.
-----------------------------------------------------------------------------
\brief A filename class
-------------------------------------------------------------------------- */
#ifndef __UIMA_FILENAME_HPP
#define __UIMA_FILENAME_HPP
/* ----------------------------------------------------------------------- */
/* Interface dependencies */
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* Implementation dependencies */
/* ----------------------------------------------------------------------- */
#include "apr_file_info.h"
#include "apr_strings.h"
#include "apr_lib.h"
#include "uima/exceptions.hpp"
#include "uima/msg.h"
/* ----------------------------------------------------------------------- */
/* Constants */
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* Types / Classes */
/* ----------------------------------------------------------------------- */
namespace uima {
namespace util {
/**
* The class <tt> FilenameCl</tt> is used to maintain filenames with all of its
* (operating system specific) constituents: drive, path, base name and extension.
* \code
???
\endcode
*/
class Filename {
public:
/** @name Constructors */
/*@{*/
/** create an empty filename */
Filename(void);
/** create a filename based on a filename given as a C string */
Filename(const char * filename);
/** create a filename based on a path, a filename and an optional extension,
all given as C strings */
Filename(const char * cpszPath,
const char * cpszFilename,
const char * cpszExtension = 0);
/** copy constructor */
Filename(const Filename & filename);
/** destructor */
~Filename(void);
/*@}*/
/** @name Assignment operations */
/*@{*/
/** assign new complete filename */
Filename & operator = (const Filename & filename);
/** @name Properties */
/*@{*/
/** determine whether a file exists for filename on file system */
bool isExistent(void) const;
/** determine whether path has an absolute path specification */
bool isAbsolute(void) const;
/** return the size of this file in bytes.
\note If the file does not exist a size of 0 bytes is returned. */
unsigned long getFileSize(void) const;
/** @name Parts */
/*@{*/
/** return full filename as a C string pointer */
const char * getAsCString(void) const {
return fname;
}
operator const char* (void) const {
return fname;
}
/** return the name part of this filename without the path but with the extension.
\note If the filename part is empty, the function returns a pointer
to an empty string, <em> not</em> a NULL pointer. */
const char * getName(void) const;
/** return the extension only, starting with the dot (e.g. ".so")
\note If there is no extension, the function returns a pointer
to an empty string, <em> not</em> a NULL pointer. */
const char * getExtension(void) const;
/** return the length of the complete filename */
size_t getLength(void) const;
/** assign a new entry from a path, optional filename and optional extension. */
void setNew(const char * cpszPath,
const char * cpszName = 0,
const char * cpszExtension = 0);
/** assign a new filename - keep current path.
filename may include extension or not */
void setNewName(const char * cpszName);
/** assign a new extension - keep current path and filename.
Specified extension must include the extension dot (".") */
void setNewExtension(const char * cpszExtension);
/** convert to an absolute name in native format with appropriate directory separators. */
void normalizeAbsolute(void);
/** convert to a name in native format with appropriate directory separators. */
void normalize(void);
/** copy path value to buffer pointed to by <tt> pszPath</tt>.
If a path does not exist for this object, <tt> pszPath</tt> is set to the empty string.
The path is returned with a terminating path separator character. */
void extractPath(char * pszPath) const;
/** copy base name (without path or extension) to buffer pointed to by <tt> pszBaseName</tt>. */
void extractBaseName(char * pszBaseName) const;
/** return TRUE if base names match (basic name part witout extension) */
bool matchesBase(const Filename & crclFilename) const;
/** search for file in a list of search paths and return TRUE if found */
bool determinePath(const char* searchPaths);
/*@}*/
protected:
/* --- functions --- */
private:
void createPool(void);
apr_pool_t * fnPool;
char * fname;
}
; /* Filename */
/* ----------------------------------------------------------------------- */
/* Implementation */
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
inline Filename::Filename(void) {
createPool();
fname = NULL;
}
/* ----------------------------------------------------------------------- */
inline Filename::Filename(const char* filename) {
createPool();
fname = apr_pstrdup(fnPool, filename);
}
/* ----------------------------------------------------------------------- */
inline Filename::Filename(const char * cpszPath, const char * cpszName,
const char * cpszExtension) {
const char * fn;
apr_status_t rv;
createPool();
if ( cpszExtension != NULL )
fn = apr_pstrcat( fnPool,cpszName,cpszExtension,NULL );
else
fn = cpszName;
// Add directory separator if necessary & normalize etc.
rv = apr_filepath_merge(&fname, cpszPath, fn, APR_FILEPATH_NATIVE, fnPool);
if (rv != APR_SUCCESS)
fname = NULL;
}
/* ----------------------------------------------------------------------- */
inline Filename::Filename(const Filename & filename) {
createPool();
fname = apr_pstrdup(fnPool, filename.getAsCString());
}
/* ----------------------------------------------------------------------- */
inline Filename::~Filename(void) {
if (fnPool != NULL)
apr_pool_destroy(fnPool);
}
/* ----------------------------------------------------------------------- */
inline void Filename::createPool(void) {
if (apr_pool_create(&fnPool, NULL) != APR_SUCCESS) {
fnPool = NULL;
UIMA_EXC_THROW_NEW(ExcOutOfMemory,
UIMA_ERR_ENGINE_OUT_OF_MEMORY,
UIMA_MSG_ID_EXC_OUT_OF_MEMORY,
ErrorMessage(UIMA_MSG_ID_EXCON_CREATING_POOL_FOR_CLASS,"uima::util::Filename"),
ErrorInfo::unrecoverable);
}
}
/* ----------------------------------------------------------------------- */
inline Filename & Filename::operator = (const Filename & filename) {
// Must make a copy since RHS & its pool may disappear
fname = apr_pstrdup(fnPool, filename.getAsCString());
return *this;
}
/* ----------------------------------------------------------------------- */
inline const char * Filename::getName(void) const {
if (fname == NULL)
return NULL;
else
return apr_filepath_name_get(fname);
// Probably returns a ptr to the end portion of fname so no memory allocated
}
/* ----------------------------------------------------------------------- */
inline const char * Filename::getExtension(void) const {
if (fname == NULL)
return NULL;
else {
const char* cpszExtn = strrchr(apr_filepath_name_get(fname), '.');
return (cpszExtn!=NULL ? cpszExtn : "");
}
}
/* ----------------------------------------------------------------------- */
inline size_t Filename::getLength(void) const {
if (fname == NULL)
return 0;
else
return strlen(fname);
}
/* ----------------------------------------------------------------------- */
inline void Filename::extractPath(char * pszPath) const {
if (fname == NULL)
*pszPath = '\0';
else {
// Get length of path up to the filename, copy with trailing separator and append a 0
unsigned long len = apr_filepath_name_get(fname) - fname;
strncpy(pszPath, fname, len);
pszPath[len] = '\0';
}
}
/* ----------------------------------------------------------------------- */
inline void Filename::extractBaseName(char * pszBaseName) const {
if (fname == NULL)
*pszBaseName = '\0';
else {
// Get name after part and strip off extension (if any)
const char* cpszName = apr_filepath_name_get(fname);
const char* cpszExtn = strrchr(cpszName, '.');
unsigned long len = cpszExtn==NULL ? strlen(cpszName) : cpszExtn - cpszName;
strncpy(pszBaseName, cpszName, len);
pszBaseName[len] = '\0';
}
}
/* ----------------------------------------------------------------------- */
inline bool Filename::isExistent(void) const {
apr_finfo_t finfo;
apr_status_t rv;
// Check if can determine type (file, directory, pipe ...)
rv = apr_stat(&finfo, fname, APR_FINFO_TYPE, fnPool);
return !(APR_STATUS_IS_ENOENT(rv));
}
/* ----------------------------------------------------------------------- */
inline bool Filename::isAbsolute(void) const {
apr_status_t rv;
const char * root;
const char * fn = fname;
// Modifies arg fn ... returns success if finds the root (?:\ on Windows)
rv = apr_filepath_root(&root, &fn, 0, fnPool);
return rv == APR_SUCCESS;
}
/* ----------------------------------------------------------------------- */
inline bool Filename::matchesBase(const Filename & crclFilename) const {
const char * cpszName1, * cpszName2, * cpszExtn1, * cpszExtn2;
unsigned long len1, len2;
if (fname == NULL)
return FALSE;
cpszName1 = apr_filepath_name_get(fname);
cpszExtn1 = strrchr(cpszName1, '.');
len1 = cpszExtn1==NULL ? strlen(cpszName1) : cpszExtn1 - cpszName1;
cpszName2 = crclFilename.getName();
if (cpszName2 == NULL)
return FALSE;
cpszExtn2 = strrchr(cpszName2, '.');
len2 = cpszExtn2==NULL ? strlen(cpszName2) : cpszExtn2 - cpszName2;
return (len1 == len2 && strncmp(cpszName1, cpszName2, len1) == 0);
}
/* ----------------------------------------------------------------------- */
inline void Filename::setNew(const char * cpszPath, const char * cpszName,
const char * cpszExtension) {
// create new string from the 3 parts
// The path must end in a separator & the extension must start with a '.'
fname = apr_pstrcat( fnPool,cpszPath,cpszName,cpszExtension,NULL );
return;
}
/* ----------------------------------------------------------------------- */
inline void Filename::setNewName(const char * cpszName) {
if (fname == NULL)
return;
// If new name is longer than old (or old had none) remove old
// and create a new entry by concatenating new filename.
char * pszName = (char*) apr_filepath_name_get(fname);
if (strlen(pszName) >= strlen(cpszName))
strcpy( pszName,cpszName );
else {
*pszName = '\0';
fname = apr_pstrcat( fnPool,fname,cpszName,NULL );
}
return;
}
/* ----------------------------------------------------------------------- */
inline void Filename::setNewExtension(const char * cpszExtension) {
const char * cpszName;
char * pszExtn;
if (fname == NULL || cpszExtension == NULL)
return;
// If new extension not longer than old replace in place, otherwise
// remove old and create a new entry by concatenating new extension.
cpszName = apr_filepath_name_get(fname);
pszExtn = CONST_CAST(char *, strrchr(cpszName, '.'));
if ( pszExtn == NULL )
fname = apr_pstrcat( fnPool,fname,cpszExtension,NULL );
else {
if (strlen(pszExtn) >= strlen(cpszExtension))
strcpy(pszExtn, cpszExtension);
else {
*pszExtn = '\0';
fname = apr_pstrcat( fnPool,fname,cpszExtension,NULL );
}
}
return;
}
/* ----------------------------------------------------------------------- */
inline unsigned long Filename::getFileSize(void) const {
apr_finfo_t finfo;
apr_status_t rv;
rv = apr_stat(&finfo, fname, APR_FINFO_SIZE, fnPool);
return rv == APR_SUCCESS ? finfo.size : 0;
}
/* ----------------------------------------------------------------------- */
inline void Filename::normalizeAbsolute(void) {
apr_status_t rv;
char* newname;
if (fname == NULL)
return;
rv = apr_filepath_merge(&newname, NULL, fname, APR_FILEPATH_NATIVE, fnPool);
if (rv == APR_SUCCESS)
fname = newname;
return;
}
/* ----------------------------------------------------------------------- */
inline void Filename::normalize(void) {
apr_status_t rv;
char* newname;
if (fname == NULL)
return;
rv = apr_filepath_merge(&newname, ".", fname, APR_FILEPATH_NATIVE, fnPool);
if (rv == APR_SUCCESS)
fname = newname;
return;
}
/* ----------------------------------------------------------------------- */
inline bool Filename::determinePath(const char* searchPaths) {
apr_array_header_t * pathElts;
char * name;
if (fname == NULL)
return FALSE;
// Drop any existing path
name = (char*) apr_filepath_name_get(fname);
apr_filepath_list_split(&pathElts, searchPaths, fnPool); // Cannot fail!
for ( int i = 0; i < pathElts->nelts; ++i ) {
apr_filepath_merge(&fname, ((char**)pathElts->elts)[i], name, APR_FILEPATH_NATIVE, fnPool);
if (isExistent())
return TRUE;
}
return FALSE;
}
} // namespace util
} // namespace uima
#endif /* __UIMA_FILENAME_HPP */
/* <EOF> */