/*
This file is part of Highlight.
Highlight is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Highlight is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Highlight. If not, see <http://www.gnu.org/licenses/>.
*/
#include "platform_fs.h"
// includes for recursive getFileNames() function
#ifdef _WIN32
#include <windows.h>
#include <sys/stat.h>
#else
#include <cerrno>
#include <dirent.h>
#include <sys/stat.h>
#ifdef __VMS
#include <unixlib.h>
#include <rms.h>
#include <ssdef.h>
#include <stsdef.h>
#include <lib$routines.h>
#include <starlet.h>
#endif /* __VMS */
#endif
#include <algorithm>
#include <cerrno>
#include <iostream>
#ifdef _WIN32
#include <windows.h>
#else
#include <cstring>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
#endif
using std::string;
using std::vector;
namespace Platform
{
#ifdef _WIN32
const char pathSeparator = '\\';
#ifndef QT
std::string getAppPath()
{
char pathAndName[MAX_PATH], path[MAX_PATH], drive[3];
GetModuleFileName(NULL, pathAndName, MAX_PATH);
_splitpath(pathAndName, drive, path, 0, 0);
return std::string(drive)+path;
}
#endif
std::string getHomePath()
{
return "";
}
int isColorEscCapable() {
return 0;
}
int isDarkTerminal() {
return 1;
}
std::string getTempFilePath(){
char tmpPath[MAX_PATH], tmpFile[MAX_PATH];
if (!GetTempPath(MAX_PATH, tmpPath))
return "";
if (!GetTempFileName(tmpPath, "hlt", 0, tmpFile))
return "";
return std::string(tmpFile);
}
#else
const char pathSeparator = '/';
std::string getAppPath()
{
return "";
}
std::string getHomePath()
{
struct passwd *pw = getpwuid(getuid());
return pw != nullptr ? string(pw->pw_dir) : "";
}
int isColorEscCapable() {
if (!isatty(fileno(stdout)) || !isatty(fileno(stdin))){
return 0;
}
char* colorOption=getenv("COLORTERM");
if (colorOption!=nullptr) {
if (!strncmp(colorOption, "truecolor", 9)){
return 2;
}
}
colorOption=getenv("TERM");
if (colorOption!=nullptr) {
if (!strncmp(colorOption, "xterm-256color", 14)){
return 1;
}
}
return 0;
}
int isDarkTerminal() {
char* colorOption=getenv("COLORFGBG");
if (colorOption!=nullptr) {
if (!strncmp(colorOption, "0;15", 4)){
return 0;
}
}
return 1;
}
std::string getTempFilePath(){
std::string path("/tmp");
char* tempOption=getenv("TEMP");
if (tempOption) path=string(tempOption);
char tmpPath[100];
snprintf(tmpPath, sizeof tmpPath-1, "/highlight%d.lua", getpid());
path += tmpPath;
return path;
}
#endif
bool getDirectoryEntries ( vector<string> &fileList,
string wildcard,
bool recursiveSearch )
{
if ( !wildcard.empty() ) {
#ifdef _WIN32
// avoid cmd shell file pattern expansion
if ( wildcard.size()>2 && wildcard[0]=='\'' && wildcard[wildcard.size()-1]=='\'' ) {
wildcard = wildcard.substr (1, wildcard.size()-2);
}
#endif
string directory_path;
string::size_type Pos = wildcard.find_last_of ( pathSeparator );
if ( Pos == string::npos ) {
directory_path = ".";
} else {
directory_path = wildcard.substr ( 0, Pos );
wildcard = wildcard.substr ( Pos + 1 );
}
getFileNames ( directory_path, wildcard, fileList );
}
return ! ( fileList.empty() );
}
#ifdef _WIN32 // Windows specific
/**
* WINDOWS function to resolve wildcards and recurse into sub directories.
* The fileName vector is filled with the path and names of files to process.
*
* @param directory The path of the directory to be processed.
* @param wildcard The wildcard to be processed (e.g. *.cpp).
* @param filenam An empty vector which will be filled with the path and names of files to process.
*/
void getFileNames ( const string &directory,const string &wildcard, vector<string> &fileName )
{
vector<string> subDirectory; // sub directories of directory
WIN32_FIND_DATA FindFileData; // for FindFirstFile and FindNextFile
// Find the first file in the directory
string firstFile = directory + "\\*";
HANDLE hFind = FindFirstFile ( firstFile.c_str(), &FindFileData );
if ( hFind == INVALID_HANDLE_VALUE )
return;
// save files and sub directories
do {
// skip hidden or read only
if ( FindFileData.cFileName[0] == '.'
|| ( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN )
|| ( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY ) )
continue;
// if a sub directory and recursive, save sub directory
if ( ( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) && true ) {
string subDirectoryPath = directory + pathSeparator + FindFileData.cFileName;
subDirectory.push_back ( subDirectoryPath );
continue;
}
// save the file name
string filePathName = directory + pathSeparator + FindFileData.cFileName;
// save file name if wildcard match
if ( wildcmp ( wildcard.c_str(), FindFileData.cFileName ) ) {
fileName.push_back ( filePathName );
}
} while ( FindNextFile ( hFind, &FindFileData ) != 0 );
// check for processing error
FindClose ( hFind );
DWORD dwError = GetLastError();
if ( dwError != ERROR_NO_MORE_FILES )
return;
// recurse into sub directories
// if not doing recursive subDirectory is empty
for ( unsigned i = 0; i < subDirectory.size(); i++ ) {
getFileNames ( subDirectory[i], wildcard, fileName );
continue;
}
return;
}
#else // not _WIN32
/**
* LINUX function to resolve wildcards and recurse into sub directories.
* The fileName vector is filled with the path and names of files to process.
*
* @param directory The path of the directory to be processed.
* @param wildcard The wildcard to be processed (e.g. *.cpp).
* @param filenam An empty vector which will be filled with the path and names of files to process.
*/
void getFileNames ( const string &directory,const string &wildcard, vector<string> &fileName )
{
struct dirent *entry; // entry from readdir()
struct stat statbuf; // entry from stat()
vector<string> subDirectory; // sub directories of this directory
// errno is defined in <errno.h> and is set for errors in opendir, readdir, or stat
errno = 0;
DIR *dp = opendir ( directory.c_str() );
if ( errno ) return;
// save files and sub directories
while ( ( entry = readdir ( dp ) ) != nullptr ) {
// get file status
string entryFilepath = directory + pathSeparator + entry->d_name;
if ( -1 == stat ( entryFilepath.c_str(), &statbuf ) || errno) {
closedir ( dp );
return;
}
// skip hidden
if ( entry->d_name[0] == '.' )
continue;
// if a sub directory and recursive, save sub directory
if ( S_ISDIR ( statbuf.st_mode ) && /*g_isRecursive*/ true ) { ///TODO
subDirectory.push_back ( entryFilepath );
continue;
}
// if a file, save file name
if ( S_ISREG ( statbuf.st_mode ) ) {
// save file name if wildcard match
if ( wildcmp ( wildcard.c_str(), entry->d_name ) ) {
fileName.push_back ( entryFilepath );
}
}
}
closedir ( dp );
if ( errno ) return;
// recurse into sub directories
// if not doing recursive, subDirectory is empty
if ( subDirectory.size() > 1 )
sort ( subDirectory.begin(), subDirectory.end() );
for ( unsigned i = 0; i < subDirectory.size(); i++ ) {
getFileNames ( subDirectory[i], wildcard, fileName );
continue;
}
return;
}
#endif
// From The Code Project http://www.codeproject.com/string/wildcmp.asp
// Written by Jack Handy - jakkhandy@hotmail.com
// Modified to compare case insensitive for Windows (the LC macro)
int wildcmp ( const char *wild, const char *data )
{
const char *cp = nullptr, *mp = nullptr;
bool cmpval;
while ( ( *data ) && ( *wild != '*' ) ) {
#ifdef _WIN32
cmpval = ( tolower ( *wild ) != tolower ( *data ) ) && ( *wild != '?' );
#else
cmpval = ( *wild != *data ) && ( *wild != '?' );
#endif
if ( cmpval ) {
return 0;
}
wild++;
data++;
}
while ( *data ) {
if ( *wild == '*' ) {
if ( !*++wild ) {
return 1;
}
mp = wild;
cp = data+1;
} else {
#ifdef _WIN32
cmpval = ( tolower ( *wild ) == tolower ( *data ) || ( *wild == '?' ) );
#else
cmpval = ( *wild == *data ) || ( *wild == '?' );
#endif
if ( cmpval ) {
wild++;
data++;
} else {
wild = mp;
data = cp++;
}
}
}
while ( *wild == '*' ) {
wild++;
}
return !*wild;
}
bool fileExists(const string &fName)
{
struct stat fileInfo;
return !stat(fName.c_str(),&fileInfo);
}
//-D_FILE_OFFSET_BITS=64
//268435456 256 MB
off_t fileSize(const string& fName) {
struct stat fileInfo;
if(stat(fName.c_str(), &fileInfo) != 0) {
return 0;
}
return fileInfo.st_size;
}
}