#include"filetools.h" #include"lyx_gui_misc.h" #include"FileInfo.h" #include"pathstack.h"// I know it's OS/2 specific (SMiyata) #include"gettext.h"
// Which part of this is still necessary? (JMarc). #if HAVE_DIRENT_H # include <dirent.h> # define NAMLEN(dirent) strlen((dirent)->d_name) #else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen # if HAVE_SYS_NDIR_H # include <sys/ndir.h> # endif # if HAVE_SYS_DIR_H # include <sys/dir.h> # endif # if HAVE_NDIR_H # include <ndir.h> # endif #endif
// Substitutes spaces with underscores in filename (and path)
LString SpaceLess(LString const & file)
{
LString name = OnlyFilename(file);
LString path = OnlyPath(file); // Substitute chars that LaTeX can't handle with safe ones
name.subst('~','-');
name.subst('$','S');
name.subst('%','_');
name.subst('\'','_');
// Substitute some more chars that LaTeX or /bin/sh can't handle -ck-
name.subst('`', '_');
name.subst('"', '_');
name.subst('&', 'G');
name.subst('|', 'I');
name.subst(';', ':');
name.subst('(', 'c');
name.subst(')', 'C');
name.subst('<', 'k');
name.subst('>', 'K');
LString temp = AddName(path, name); // Replace spaces with underscores, also in directory
temp.subst(' ','_');
return temp;
}
/// Returns an unique name to be used as a temporary file.
LString TmpFileName(LString const & dir, LString const & mask)
{// With all these temporary variables, it should be safe enough :-) (JMarc)
LString tmpdir; if (dir.empty())
tmpdir = system_tempdir; else
tmpdir = dir;
LString tmpfl = AddName(tmpdir, mask);
// find a uniq postfix for the filename... // using the pid, and...
tmpfl += int(getpid()); // a short string...
LString ret;
FileInfo fnfo; for (int a='a'; a<= 'z'; a++) for (int b='a'; b<= 'z'; b++) for (int c='a'; c<= 'z'; c++) { // if this is not enough I have no idea what // to do.
ret = tmpfl + char(a) + char(b) + char(c); // check if the file exist if (!fnfo.newFile(ret).exist()) return ret;
}
lyxerr.print("Not able to find a uniq tmpfile name."); return LString();
}
// Is a file readable ? bool IsFileReadable (LString const & path)
{
FileInfo file(path); if (file.isOK() && file.readable()) returntrue; else returnfalse;
}
// Is a file read_only? // return 1 read-write // 0 read_only // -1 error (doesn't exist, no access, anything else) int IsFileWriteable (LString const & path)
{
FilePtr fp(path, FilePtr::update); if (!fp()) { if ((errno == EACCES) || (errno == EROFS)) { //fp = FilePtr(path, FilePtr::read);
fp.reopen(path, FilePtr::read); if (fp()) { return0;
}
} return -1;
} return1;
}
//returns 1: dir writeable // 0: not writeable // -1: error- couldn't find out int IsDirWriteable (LString const & path)
{
LString tmpfl = TmpFileName(path);
if (tmpfl.empty()) {
WriteFSAlert(_("LyX Internal Error!"),
_("Could not test if directory is writeable")); return -1;
} else {
FilePtr fp(tmpfl, FilePtr::truncate); if (!fp()) { if (errno == EACCES) { return0;
} else {
WriteFSAlert(_("LyX Internal Error!"),
_("Cannot open directory test file")); return -1;
}
}
} if (remove (tmpfl.c_str())) {
WriteFSAlert(_("LyX Internal Error!"),
_("Created test file but cannot remove it?")); return -1;
} return1;
}
// Uses a string of paths separated by ";"s to find a file to open. // Can't cope with pathnames with a ';' in them. Returns full path to file. // If path entry begins with $$LyX/, use system_lyxdir // If path entry begins with $$User/, use user_lyxdir // Example: "$$User/doc;$$LyX/doc"
LString FileOpenSearch (LString const & path, LString const & name,
LString const & ext)
{
LString real_file, path_element;
LString tmppath = path; bool notfound = true;
tmppath.split(path_element, ';');
while (notfound && !path_element.empty()) {
if (!path_element.suffixIs('/'))
path_element+='/';
path_element.subst("$$LyX",system_lyxdir);
path_element.subst("$$User",user_lyxdir);
// Returns the real name of file name in directory path, with optional // extension ext.
LString FileSearch(LString const & path, LString const & name,
LString const & ext)
{
LString fullname;
LString tmp;
// if `name' is an absolute path, we ignore the setting of `path' // Expand Environmentvariables in 'name'
LString tmpname = ReplaceEnvironmentPath(name);
fullname = MakeAbsPath(tmpname,path);
// search first without extension, then with it. if (IsFileReadable(fullname)) return fullname; elseif(ext.empty()) return LString(); else { // Is it not more reasonable to use ChangeExtension()? (SMiyata)
fullname += '.';
fullname += ext; if (IsFileReadable(fullname)) return fullname; else return LString();
}
}
// Search the file name.ext in the subdirectory dir of // 1) user_lyxdir // 2) build_lyxdir (if not empty) // 3) system_lyxdir
LString LibFileSearch(LString const & dir, LString const & name,
LString const & ext)
{
LString fullname = FileSearch(AddPath(user_lyxdir,dir), name,
ext); if (!fullname.empty()) return fullname;
if (!build_lyxdir.empty())
fullname = FileSearch(AddPath(build_lyxdir,dir),
name, ext); if (!fullname.empty()) return fullname;
// Should supposedly help with some automountd-stuff... // Fortunately no need to patch for OS/2 support
LString safer_getcwd ()
{
LString temp = getenv ("PWD"); if (temp.empty()) {
temp = getenv ("CWD"); if (temp.empty())
temp = GetCWD();
} return temp;
}
// Returns current working directory
LString GetCWD ()
{ int n = 256; // Assume path is less than 256 chars char * err; char * tbuf = newchar [n];
LString result;
// Safe. Hopefully all getcwds behave this way! while (((err = getcwd (tbuf, n)) == NULL) && (errno == ERANGE)) { // Buffer too small, double the buffersize and try again delete[] tbuf;
n = 2*n;
tbuf = newchar [n];
}
if (err) result = tbuf; delete[] tbuf; return result;
}
// Strip filename from path name
LString OnlyPath(LString const &Filename)
{ // If empty filename, return empty if (Filename.empty()) return Filename;
// Find last / or start of filename int j = Filename.length() - 1; for (; j > 0 && Filename[j] != '/'; j--);
if (Filename[j] != '/') return"./"; else { // Strip to pathname
LString temp = Filename; return temp.substring(0, j);
}
}
// Convert relative path into absolute path based on a basepath. // If relpath is absolute, just use that. // If basepath is empty, use CWD as base.
LString MakeAbsPath(LString const &RelPath, LString const &BasePath)
{ // checks for already absolute path if (AbsolutePath(RelPath)) #ifdef __EMX__ if(RelPath[0]!='/') #endif return RelPath;
while (!RTemp.empty()) { // Split by next /
RTemp.split(Temp, '/');
if (Temp==".") continue; if (Temp=="..") { // Remove one level of TempBase int i = TempBase.length()-2; #ifndef __EMX__ if (i<0) i=0; while (i>0 && TempBase[i] != '/') i--; if (i>0) #else if (i<2) i=2; while (i>2 && TempBase[i] != '/') i--; if (i>2) #endif
TempBase.substring(0, i); else
TempBase += '/';
} else { // Add this piece to TempBase if (!TempBase.suffixIs('/'))
TempBase += '/';
TempBase += Temp;
}
}
// returns absolute path return TempBase;
}
// Correctly append filename to the pathname. // If pathname is '.', then don't use pathname. // Chops any path of filename.
LString AddName(LString const &Path, LString const &FileName)
{ // Get basename
LString Basename = OnlyFilename(FileName);
LString buf;
if (Path != "." && Path != "./" && !Path.empty()) {
buf = Path; if (!Path.suffixIs('/'))
buf += '/';
}
return buf + Basename;
}
// Strips path from filename
LString OnlyFilename(LString const &Filename)
{ // If empty filename, return empty if (Filename.empty()) return Filename;
int j; // Find last / or start of filename for (j=Filename.length()-1; Filename[j] != '/' && j>0; j--);
// Create absolute path. If impossible, don't do anything // Supports ./ and ~/. Later we can add support for ~logname/. (Asger)
LString ExpandPath(LString const &path)
{ // checks for already absolute path
LString RTemp = ReplaceEnvironmentPath(path); if (AbsolutePath(RTemp)) return RTemp;
LString Temp;
LString copy(RTemp);
// Split by next /
RTemp.split(Temp, '/');
if (Temp==".") { return GetCWD() + '/' + RTemp;
} elseif (Temp=="~") { return getEnvPath("HOME") + '/' + RTemp;
} elseif (Temp=="..") { return MakeAbsPath(copy);
} else // Don't know how to handle this return copy;
}
if (AbsolutePath(path))
RTemp = path; else // Make implicit current directory explicit
RTemp = "./" +path;
while (!RTemp.empty()) { // Split by next /
RTemp.split(Temp, '/');
if (Temp==".") {
TempBase = "./";
} elseif (Temp=="..") { // Remove one level of TempBase int i = TempBase.length()-2; while (i>0 && TempBase[i] != '/')
i--; if (i>=0 && TempBase[i] == '/')
TempBase.substring(0, i); else
TempBase = "../";
} else {
TempBase += Temp + '/';
}
}
// returns absolute path return TempBase;
}
// // Search ${...} as Variable-Name inside the string and replace it with // the denoted environmentvariable // Allow Variables according to // variable := '$' '{' [A-Za-z_]{[A-Za-z_0-9]*} '}' //
LString ReplaceEnvironmentPath(LString const &path)
{ // // CompareChar: Environmentvariables starts with this character // PathChar: Next path component start with this character // while CompareChar found do: // Split String with PathChar // Search Environmentvariable // if found: Replace Strings // constchar CompareChar = '$'; constchar FirstChar = '{'; constchar EndChar = '}'; constchar UnderscoreChar = '_'; const LString EndString(EndChar); const LString FirstString(FirstChar); const LString CompareString(CompareChar); const LString RegExp("*}*"); // Exist EndChar inside a String?
if (path.empty()) return path; // nothing to do.
// first: Search for a '$' - Sign.
LString copy(path);
LString result1(copy); // for split-calls
LString result0 = copy.split(result1, CompareChar); while (!result0.empty()) {
LString copy1(result0); // contains String after $
// Check, if there is an EndChar inside original String.
if (!copy1.regexMatch(RegExp)) { // No EndChar inside. So we are finished
result1 += CompareString + result0;
result0 = LString(); continue;
}
LString res1;
LString res0 = copy1.split(res1, EndChar); // Now res1 holds the environmentvariable // First, check, if Contents is ok. if (res1.empty()) { // No environmentvariable. Continue Loop.
result1 += CompareString + FirstString;
result0 = res0; continue;
} // check contents of res1 constchar *res1_contents = res1.c_str(); if (*res1_contents != FirstChar) { // Again No Environmentvariable
result1 += CompareString;
result0 = res0;
}
// Check for variable names // Situation ${} is detected as "No Environmentvariable" constchar *cp1 = res1_contents+1; bool result = isalpha((unsignedchar) *cp1) || (*cp1 == UnderscoreChar);
++cp1; while (*cp1 && result) {
result = isalnum((unsignedchar) *cp1) ||
(*cp1 == UnderscoreChar);
++cp1;
}
if (!result) { // no correct variable name
result1 += CompareString + res1 + EndString;
result0 = res0.split(res1, CompareChar);
result1 += res1; continue;
}
// Make relative path out of two absolute paths
LString MakeRelPath(LString const & abspath, LString const & basepath) // Makes relative path out of absolute path. If it is deeper than basepath, // it's easy. If basepath and abspath share something (they are all deeper // than some directory), it'll be rendered using ..'s. If they are completely // different, then the absolute path will be used as relative path.
{ // This is a hack. It should probaly be done in another way. Lgb. if (abspath.empty()) return"<unknown_path>";
// Find first different character int i = 0; while (i < abslen && i < baselen && abspath[i] == basepath[i]) ++i;
// Go back to last / if (i < abslen && i < baselen
|| (i<abslen && abspath[i] != '/' && i==baselen)
|| (i<baselen && basepath[i] != '/' && i==abslen))
{ if (i) --i; // here was the last match while (i && abspath[i] != '/') --i;
}
if (i == 0) { // actually no match - cannot make it relative return abspath;
}
// Count how many dirs there are in basepath above match // and append as many '..''s into relpath
LString buf; int j = i; while (j < baselen) { if (basepath[j] == '/') { if (j+1 == baselen) break;
buf += "../";
}
++j;
}
// Append relative stuff from common directory to abspath if (abspath[i] == '/') ++i; for (; i<abslen; ++i)
buf += abspath[i]; // Remove trailing / if (buf.suffixIs('/'))
buf.substring(0,buf.length()-2); // Substitute empty with . if (buf.empty())
buf = '.'; return buf;
}
// Append sub-directory(ies) to a path in an intelligent way
LString AddPath(LString const & path, LString const & path2)
{
LString buf;
if (!path.empty() && path != "." && path != "./") {
buf = path; if (!path.suffixIs('/'))
buf += '/';
}
if (!path2.empty()){ int p2start = 0; while (path2[p2start] == '/') p2start++;
int p2end = path2.length()-1; while (path2[p2end] == '/') p2end--;
/* Changeextensionofoldnametoextension. Stripspathoffifno_path==true. Ifnoextensiononoldname,justappends.
*/
LString ChangeExtension(LString const & oldname, LString const & extension, bool no_path)
{ int n = oldname.length()-1; int dot;
// Make sure the extension includes the dot, if not empty
LString ext; if (!extension.empty() && extension[0] != '.')
ext = "." + extension; else
ext = extension;
// Go back to the first dot not crossing any / for (dot=n; dot>=0 && oldname[dot]!='.' && oldname[dot]!='/'; dot--);
if (dot==-1 || oldname[dot]!='.') // If no extension was found, we use the end of the string
dot = n; else // Remove the dot, because the new extension includes it
dot--;
// "path" points to last / or 0 if path is wanted int path = 0; if (no_path) { for (path=dot; path && oldname[path]!='/';path--); if (oldname[path]=='/')
path++;
} else
path = 0;
LString result = oldname;
result.substring(path,dot); if (!ext.empty())
result += ext; return result;
}
// Creates a nice compact path for displaying
LString MakeDisplayPath (LString const & path, int threshold)
{ constint l1 = path.length();
// First, we try a relative path compared to home
LString home = getEnvPath("HOME");
LString relhome = MakeRelPath(path, home);
int l2 = relhome.length();
LString prefix;
// If we backup from home or don't have a relative path, // this try is no good if (relhome.prefixIs("../") || AbsolutePath(relhome)) { // relative path was no good, just use the original path
relhome = path;
l2 = l1;
} else {
prefix = "~/";
}
// Is the path too long? if (l2 > threshold) { // Yes, shortend it
prefix += ".../";
LString temp;
while (relhome.length()>threshold)
relhome.split(temp, '/');
// Did we shortend everything away? if (relhome.empty()) { // Yes, filename in itself is too long. // Pick the start and the end of the filename.
relhome = OnlyFilename(path);
LString head = relhome;
head.substring(0, threshold/2 - 3);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.