#define _Noreturn namespace sys; #define set _set #define uint _uint #define strlen _strlen default: #undef __BLOCKS__ #include #include #if !defined(ECERE_BOOTSTRAP) // quick fix for now #if defined(__WIN32__) #define WIN32_LEAN_AND_MEAN #define String _String #include #undef String #else #include #endif #endif #undef uint #undef set #undef strlen private: import "instance" default extern Platform runtimePlatform; #define IS_ALUNDER(ch) ((ch) == '_' || isalnum((ch))) public define DIR_SEP = (__runtimePlatform == win32) ? '\\' : '/'; public define DIR_SEPS = (__runtimePlatform == win32) ? "\\" : "/"; // Maximum length for a vsnprintf string public define MAX_F_STRING = 1025; // Maximum length for a directories and filenames strings public define MAX_EXTENSION = 17; // 16 + \0 public define MAX_FILENAME = 274; // 256 chars + extension + dot + \0 public define MAX_DIRECTORY = 534; // 8 levels + 8 separators + \0 public define MAX_LOCATION = 797; // directory + filename + separator + \0 // --- File related String functions --- public char * GetExtension(const char * string, char * output) { int c; int len = strlen(string); int limit = Max(0, len-MAX_EXTENSION); output[0] = '\0'; for(c = len; c>=limit; c--) { char ch = string[c]; if(ch == '.') { strcpy(output, string+c+1); break; } else if(ch == '/' || ch == '\\') break; } return output; } public char * StripLastDirectory(const char * string, char * output) { int c; if(runtimePlatform == win32 && !strcmp(string, "\\\\")) { strcpy(output, "/"); return output; } else { int len = strlen(string); for(c = len-2; c>=0; c--) if(string[c] == '/' || string[c] == '\\') break; else if(string[c] == '>' || (string[c] == ':' && c == 0)) { c++; break; } if((runtimePlatform == win32) ? (c >= 0) : (c > 0)) { memmove(output, string, c); if(c > 0) { if(runtimePlatform == win32 && c == 1 && output[0] == '\\' && output[1] == '\\') output[2] = '\0'; else output[c] = '\0'; } else strcpy(output, DIR_SEPS); return output; } else { // Return root on UNIX instead of null... if(c == 0) { strcpy(output, DIR_SEPS); return output; } else { strcpy(output, ""); return null; } } } } public char * SplitDirectory(const char * string, char * part, char * rest) { int len = 0; char ch; int c = 0; for(;(ch = string[c]) && (ch == '/' || ch == '\\'); c++); if(c) part[len++] = DIR_SEP; else { for(;(ch = string[c]) && (ch != '/' && ch != '\\'); c++) { if(len < MAX_FILENAME) part[len++] = ch; } } for(;(ch = string[c]) && (ch == '/' || ch == '\\'); c++); memmove(rest, string + c, strlen(string + c) + 1); for(c = strlen(rest); c >= 0; c--) if(ch != '/' && ch != '\\') break; if(c > 0) rest[c] = '\0'; part[len] = '\0'; return rest; } public char * GetLastDirectory(const char * string, char * output) { int c; int len = string ? strlen(string) : 0; for(c = len-2; c>=0; c--) if(string[c] == '/' || string[c] == '\\' || string[c] == ':' || string[c] == '>') break; c++; if(c >= 0) memmove(output, string+c, strlen(string+c)+1); else output[0] = '\0'; len = strlen(output); if(len > 1 && (output[len-1] == '\\' || output[len-1] == '/')) output[len-1] = '\0'; return output; } public bool SplitArchivePath(const char * fileName, char * archiveName, const char * * archiveFile) { // Support Archives if(fileName[0] == '<') { int c = strlen(fileName); for(;c>0 && fileName[c] != '>'; c--); if(c > 0) { strncpy(archiveName, fileName + 1, c - 1); archiveName[c - 1] = '\0'; *archiveFile = fileName + c + 1; return true; } } else if(fileName[0] == ':') { strcpy(archiveName, ":"); *archiveFile = fileName + 1; return true; } return false; } public char * PathCatSlash(char * string, const char * addedPath) { bool modified = false; if(addedPath) { char fileName[MAX_LOCATION] = "", archiveName[MAX_LOCATION] = ""; const char * file = null; int c = 0; bool isURL = false; bool isArchive = SplitArchivePath(string, archiveName, &file); char * urlFileName = null; char * protocolSymbol; strcpy(fileName, isArchive ? file : string); if(!isArchive) // TODO: Support for PathCat'ing .. outside of archive { protocolSymbol = (fileName[0] && fileName[0] != '.' && fileName[0] != '/' && fileName[0] != '\\' && fileName[1] != ':') ? strstr(fileName, "://") : null; if(protocolSymbol) { char * slash = strstr(protocolSymbol + 3, "/"); isURL = true; if(slash) urlFileName = slash; else urlFileName = fileName + strlen(fileName); } } protocolSymbol = (addedPath[0] && addedPath[0] != '.' && addedPath[0] != '/' && addedPath[0] != '\\' && addedPath[1] != ':') ? strstr(addedPath, "://") : null; if(protocolSymbol) { int len = protocolSymbol - addedPath + 3; memcpy(fileName, addedPath, len); fileName[len] = 0; isURL = true; c = len; } else if(__runtimePlatform == win32) { if(addedPath[0] && addedPath[1] == ':' && addedPath[0] != '<') { fileName[0] = (char)toupper(addedPath[0]); fileName[1] = ':'; fileName[2] = '\0'; c = 2; modified = true; } else if(addedPath[0] == '\\' && addedPath[1] == '\\') { fileName[0] = fileName[1] = '\\'; fileName[2] = '\0'; c = 2; modified = true; } // A drive needs to be selected /* TOCHECK: Cutting this out, can't handle relative path else if(fileName[0] == '/' && !archiveName[0] && strcmp(addedPath, "/")) return null; */ } if(!modified && isURL && (addedPath[0] == '\\' || addedPath[0] == '/')) { urlFileName[0] = '/'; urlFileName[1] = '\0'; } else if(!modified && (addedPath[0] == '\\' || addedPath[0] == '/')) { if(__runtimePlatform == win32) { // Entire Computer if(addedPath[0] == '/' && !addedPath[1]) { fileName[0] = addedPath[0]; fileName[1] = '\0'; modified = true; } // Root of drive else if(fileName[0] && fileName[1] == ':') { fileName[2] = '\0'; modified = true; } // Relative path root of drive else { fileName[0] = '\\'; fileName[1] = '\0'; modified = true; } } else { fileName[0] = '/'; fileName[1] = '\0'; modified = true; } c = 1; } for(; addedPath[c]; ) { // DANGER OF OVERFLOW HERE // char directory[MAX_FILENAME]; char directory[MAX_FILENAME * 16]; int len = 0; char ch; int count; for(;(ch = addedPath[c]) && (ch == '/' || ch == '\\'); c++); for(;(ch = addedPath[c]) && (ch != '/' && ch != '\\'); c++) { if(isURL && ch == '?') { break; } if(len < MAX_FILENAME) directory[len++] = ch; } directory[len] = '\0'; // Trim rightmost spaces for(count = len-1; count >= 0 && (directory[count] == ' ' || directory[count] == '\t'); count--) { directory[count] = '\0'; len--; } if(len > 0) { modified = true; if(strstr(directory, "..") == directory && (!directory[2] || directory[2] == DIR_SEP || directory[2] == '/')) { int strLen = strlen(fileName) - 1; if(strLen > -1) { // Go back one directory for(;strLen > -1 && (ch = fileName[strLen]) && (ch == '/' || ch == '\\'); strLen--); for(;strLen > -1 && (ch = fileName[strLen]) && (ch != '/' && ch != '\\' && ch != ':'); strLen--); for(;strLen > -1 && (ch = fileName[strLen]) && (ch == '/' || ch == '\\'); strLen--); if(isURL) { strLen = Max(strLen, urlFileName - fileName); } if(!strcmp(fileName + strLen + 1, "..")) { strcat(fileName, "/" /*DIR_SEPS*/); strcat(fileName, ".."); } else { if(__runtimePlatform == win32) { if(!strLen && fileName[0] == '\\' && fileName[1] == '\\') { if(!fileName[2]) return null; else { fileName[0] = '\\'; fileName[1] = '\\'; fileName[2] = '\0'; } } else fileName[strLen+1] = '\0'; } else { fileName[strLen+1] = '\0'; if(strLen<0) { fileName[0] = '/'; fileName[1] = '\0'; strLen = 2; } } } } else { strcpy(fileName, ".."); } } else if(strcmp(directory, ".")) { int strLen = strlen(fileName); bool notZeroLen = strLen > 0; // if(strLen > 1 && (fileName[strLen-1] == '/' || fileName[strLen-1] == '\\')) if(strLen > 0 && (fileName[strLen-1] == '/' || fileName[strLen-1] == '\\')) strLen--; if(notZeroLen /*&& fileName[strLen-1] != ':' && fileName[strLen-1] != '>'*/) fileName[strLen++] = '/'; fileName[strLen] = '\0'; if(strLen + strlen(directory) > MAX_LOCATION - 3) return null; // AN ERROR OCCURRED! strcat(fileName, directory); } } if(isURL && ch == '/') strcat(fileName, "/"); if(isURL && ch == '?') { strcat(fileName, addedPath+c); break; } } if(archiveName[0]) sprintf(string, "<%s>%s", archiveName, fileName); else strcpy(string, fileName); } return modified ? string : null; } public char * PathCat(char * string, const char * addedPath) { bool modified = false; if(addedPath) { char fileName[MAX_LOCATION] = "", archiveName[MAX_LOCATION] = ""; const char * file = null; int c = 0; bool isURL = false; bool isArchive = SplitArchivePath(string, archiveName, &file); char * urlFileName = null; char * protocolSymbol; strcpy(fileName, isArchive ? file : string); if(!isArchive) // TODO: Support for PathCat'ing .. outside of archive { protocolSymbol = (fileName[0] && fileName[0] != '.' && fileName[0] != '/' && fileName[0] != '\\' && fileName[1] != ':') ? strstr(fileName, "://") : null; if(protocolSymbol) { char * slash = strstr(protocolSymbol + 3, "/"); isURL = true; if(slash) urlFileName = slash; else urlFileName = fileName + strlen(fileName); } } protocolSymbol = (addedPath[0] && addedPath[0] != '.' && addedPath[0] != '/' && addedPath[0] != '\\' && addedPath[1] != ':') ? strstr(addedPath, "://") : null; if(protocolSymbol) { int len = protocolSymbol - addedPath + 3; memcpy(fileName, addedPath, len); fileName[len] = 0; isURL = true; c = len; } else if(runtimePlatform == win32) { if(addedPath[0] && addedPath[1] == ':' && addedPath[0] != '<') { fileName[0] = (char)toupper(addedPath[0]); fileName[1] = ':'; fileName[2] = '\0'; c = 2; modified = true; } else if(addedPath[0] == '\\' && addedPath[1] == '\\') { fileName[0] = fileName[1] = '\\'; fileName[2] = '\0'; c = 2; modified = true; } // A drive needs to be selected else if(fileName[0] == '/' && !archiveName[0] && strcmp(addedPath, "/")) return null; } if(!modified && isURL && (addedPath[0] == '\\' || addedPath[0] == '/')) { urlFileName[0] = '/'; urlFileName[1] = '\0'; } else if(!modified && (addedPath[0] == '\\' || addedPath[0] == '/')) { if(runtimePlatform == win32) { // Entire Computer if(addedPath[0] == '/' && !addedPath[1]) { fileName[0] = addedPath[0]; fileName[1] = '\0'; modified = true; } // Root of drive else if(fileName[0] && fileName[1] == ':') { fileName[2] = '\0'; modified = true; } // Relative path root of drive else { fileName[0] = '\\'; fileName[1] = '\0'; modified = true; } } else { fileName[0] = '/'; fileName[1] = '\0'; modified = true; } c = 1; } for(; addedPath[c]; ) { // DANGER OF OVERFLOW HERE // char directory[MAX_FILENAME]; char directory[MAX_FILENAME * 16]; int len = 0; char ch; int count; for(;(ch = addedPath[c]) && (ch == '/' || ch == '\\'); c++); for(;(ch = addedPath[c]) && (ch != '/' && ch != '\\'); c++) { if(isURL && ch == '?') { break; } if(len < MAX_FILENAME) directory[len++] = ch; } directory[len] = '\0'; // Trim rightmost spaces for(count = len-1; count >= 0 && (directory[count] == ' ' || directory[count] == '\t'); count--) { directory[count] = '\0'; len--; } if(len > 0) { modified = true; if(strstr(directory, "..") == directory && (!directory[2] || directory[2] == DIR_SEP)) { int strLen = strlen(fileName) - 1; if(strLen > -1) { bool separator = false; // Go back one directory for(;strLen > -1 && (ch = fileName[strLen]) && (ch == '/' || ch == '\\'); strLen--); for(;strLen > -1 && (ch = fileName[strLen]) && (ch != '/' && ch != '\\' && ch != ':'); strLen--); for(;strLen > -1 && (ch = fileName[strLen]) && (ch == '/' || ch == '\\'); strLen--) separator = true; if(isURL) { strLen = Max(strLen, urlFileName - fileName); } if(!strcmp(fileName + strLen + (separator ? 2 : 1), "..")) { strcat(fileName, DIR_SEPS); strcat(fileName, ".."); } else { if(runtimePlatform == win32) { if(!strLen && fileName[0] == '\\' && fileName[1] == '\\') { if(!fileName[2]) return null; else { fileName[0] = '\\'; fileName[1] = '\\'; fileName[2] = '\0'; } } else fileName[strLen+1] = '\0'; } else { fileName[strLen+1] = '\0'; if(strLen<0) { fileName[0] = '/'; fileName[1] = '\0'; strLen = 2; } } } } else { strcpy(fileName, ".."); } } else if(strcmp(directory, ".")) { int strLen = strlen(fileName); bool notZeroLen = strLen > 0; // if(strLen > 1 && (fileName[strLen-1] == '/' || fileName[strLen-1] == '\\')) if(strLen > 0 && (fileName[strLen-1] == '/' || fileName[strLen-1] == '\\')) strLen--; if(notZeroLen /*&& fileName[strLen-1] != ':' && fileName[strLen-1] != '>'*/) { if(isURL) fileName[strLen++] = '/'; else fileName[strLen++] = DIR_SEP; } fileName[strLen] = '\0'; if(strLen + strlen(directory) > MAX_LOCATION - 3) return null; // AN ERROR OCCURRED! strcat(fileName, directory); } } if(isURL && ch == '/') strcat(fileName, "/"); if(isURL && ch == '?') { strcat(fileName, addedPath+c); break; } } if(archiveName[0]) sprintf(string, "<%s>%s", archiveName, fileName); else strcpy(string, fileName); } return modified ? string : null; } public char * MakePathRelative(const char * path, const char * to, char * destination) { int len; // Don't process empty paths if(!path[0]) memmove(destination, path, strlen(path)+1); else { // TOFIX: DANGER OF OVERFLOW HERE char pathPart[MAX_FILENAME * 16], pathRest[MAX_LOCATION]; char toPart[MAX_FILENAME * 16], toRest[MAX_LOCATION]; bool different = false; strcpy(pathRest, path); strcpy(toRest, to); destination[0] = '\0'; for(;toRest[0];) { SplitDirectory(toRest, toPart, toRest); if(!different) SplitDirectory(pathRest, pathPart, pathRest); if(different || fstrcmp(toPart, pathPart)) { different = true; strcat(destination, ".."); strcat(destination, DIR_SEPS); } } if(different) PathCat(destination, pathPart); for(;pathRest[0];) { SplitDirectory(pathRest, pathPart, pathRest); PathCat(destination, pathPart); } } len = strlen(destination); if(len>1 && (destination[len-1] == '/' || destination[len-1] == '\\')) destination[--len] = '\0'; return destination; } public bool StripExtension(char * string) { int c; for(c = strlen(string); c>=0; c--) if(string[c] == '.') { string[c] = '\0'; return true; } else if(string[c] == '\\' || string[c] == '/') break; return false; } public char * ChangeExtension(const char * string, const char * ext, char * output) { if(string != output) strcpy(output, string); StripExtension(output); if(ext[0]) strcat(output, "."); strcat(output, ext); return output; } // --- String Stuff (Temporarily outside String class) --- public void PrintSize(char * string, uint size, int prec) { if(size > 1024) { char format[8]; sprintf(format, "%%.0%df", prec); if(size > 1024 * 1024 * 1024) { sprintf(string, format, size / (float)(1024 * 1024 * 1024)); strcat(string, " GB"); } else if(size > 1024 * 1024) { sprintf(string, format, size / (float)(1024 * 1024)); strcat(string, " MB"); } else { sprintf(string, format, size / (float)1024); strcat(string, " KB"); } } else sprintf(string, "%d B", size); } public void PrintBigSize(char * string, double size, int prec) { if(size > 1024) { char format[8]; sprintf(format, "%%.0%df", prec); if(size > 1024.0 * 1024.0 * 1024.0 * 1024.0) { sprintf(string, format, size / (1024 * 1024 * 1024.0 * 1024.0)); strcat(string, " TB"); } else if(size > 1024.0 * 1024.0 * 1024.0) { sprintf(string, format, size / (1024.0 * 1024.0 * 1024.0)); strcat(string, " GB"); } else if(size > 1024.0 * 1024.0) { sprintf(string, format, size / (1024.0 * 1024.0)); strcat(string, " MB"); } else { sprintf(string, format, size / 1024.0); strcat(string, " KB"); } } else sprintf(string, "%.0f B", size); } public char * SearchString(const char * buffer, int start, const char * subStr, bool matchCase, bool matchWord) { if(buffer && subStr) { const char * ptr; const char * strBuffer = buffer + start; int subLen = strlen(subStr); char beforeChar = start ? *(strBuffer-1) : 0; int (*strcompare)(const char *, const char *, uintsize) = matchCase ? strncmp : strnicmp; for(ptr = strBuffer; *ptr; ptr++) { if(matchCase ? (*subStr == *ptr) : (tolower(*subStr) == tolower(*ptr))) { if(matchWord) { if(!strcompare(ptr,subStr,subLen) && /* !IS_ALUNDER(ptr[subLen]) && !IS_ALUNDER(beforeChar)) */ (!IS_ALUNDER(subStr[subLen-1]) || !IS_ALUNDER(ptr[subLen])) && (!IS_ALUNDER(subStr[0]) || !IS_ALUNDER(beforeChar))) return (char *)ptr; } else { if(!strcompare(ptr,subStr,subLen)) return (char *)ptr; } } beforeChar = ptr[0]; } } return null; } public char * RSearchString(const char * buffer, const char * subStr, int maxLen, bool matchCase, bool matchWord) { if(buffer && subStr) { int subLen = strlen(subStr); const char * ptr1 = buffer + maxLen - subLen; const char * ptr2 = buffer + maxLen - subLen - 1; int (*strcompare)(const char *, const char *, uintsize) = matchCase ? strncmp : strnicmp; for(; ptr1 >=buffer; ptr1--, ptr2--) { if(tolower(*subStr) == tolower(*ptr1)) { if(matchWord) { if(!strcompare(ptr1,subStr,subLen) && //!IS_ALUNDER(ptr1[subLen]) && !IS_ALUNDER(*ptr2)) (!IS_ALUNDER(subStr[subLen-1]) || !IS_ALUNDER(ptr1[subLen])) && (!IS_ALUNDER(subStr[0]) || !IS_ALUNDER(*ptr2))) return (char *)ptr1; } else { if(!strcompare(ptr1,subStr,subLen)) return (char *)ptr1; } } } } return null; } //public define gnuMakeCharsNeedEscaping = "$%"; //public define windowsFileNameCharsNotAllowed = "*/:<>?\\\"|"; //public define linuxFileNameCharsNotAllowed = "/"; //public define windowsFileNameCharsNeedEscaping = " !%&'()+,;=[]^`{}~"; // "#$-.@_" are ok //public define linuxFileNameCharsNeedEscaping = " !\"$&'()*:;<=>?[\\`{|"; // "#%+,-.@]^_}~" are ok // fix #139 to remove " = 2" and warnings for backward compatible calls to Tokenize using 'true' for the 'esc' argument; public enum BackSlashEscaping : bool { forArgsPassing = 2 }; public int Tokenize(char * string, int maxTokens, char* tokens[], BackSlashEscaping esc) { const char * escChars, * escCharsQuoted; int count = 0; bool quoted = false, escaped = false; char * start = null, * output = string; char ch; if(__runtimePlatform == win32) { //define windowsFileNameCharsNeedEscaping = " !%&'()+,;=[]^`{}~"; // "#$-.@_" are ok escChars = " !\"%&'()+,;=[]^`{}~"; // windowsFileNameCharsNeedEscaping; escCharsQuoted = "\""; } else { //define linuxFileNameCharsNeedEscaping = " !\"$&'()*:;<=>?[\\`{|"; // "#%+,-.@]^_}~" are ok escChars = " !\"$&'()*:;<=>?[\\`{|"; // linuxFileNameCharsNeedEscaping; escCharsQuoted = "\"()$"; } for(; (ch = *string) && count= 0 && string[c] == ' '; c--); if(c >= 0) { memmove(output, string, c+1); output[c+1] = '\0'; } else output[0] = '\0'; return output; } public void ChangeCh(char * string, char ch1, char ch2) { int c; for(c=0; string[c]; c++) if(string[c] == ch1) string[c] = ch2; } public void ChangeChars(char * string, const char * chars, char alt) { int c; for(c=0; string[c]; c++) if(strchr(chars, string[c])) string[c] = alt; } public void RepeatCh(char * string, int count, char ch) { int c; for(c=0; c maxSize) newSize = maxSize; if(newSize && size) _string = renew _string char[newSize]; else if(newSize) _string = new char[newSize]; else delete _string; size = newSize; } } if(newLen + 1 > size) newLen = size-1; len = newLen; if(value) { memcpy(_string, value, newLen); _string[newLen] = 0; } } public: const char * OnGetString(char * tempString, void * fieldData, bool * needClass) { return _string; } bool OnGetDataFromString(const char * string) { property::string = (char *)string; return true; } property char * string { set { copyString(value, value ? strlen(value) : 0); } get { return _string; } } property const char * { get { return _string; } set { return { len = value ? strlen(value) : 0; _string = (char *)value; allocType = pointer; }; } } void concatf(const char * format, ...) { if(format && allocType != pointer) { int addedLen; va_list args; va_start(args, format); if(size < minSize) { _string = renew _string char[minSize]; size = minSize; } addedLen = vsnprintf(string + len, Max(0, size - 1 - len), format, args); if(addedLen > 0) { len += addedLen; _string[len] = 0; } va_end(args); } } void concat(ZString s) { if(s && allocType != pointer) { int addedLen = s.len; int newLen = len + addedLen; if(allocType == heap && newLen + 1 > size) { int newSize = newLen + 1; if(newSize > maxSize) newSize = maxSize; if(newSize > size) { _string = renew _string char[newLen]; size = newSize; } } if(newLen + 1 > size) addedLen = size - 1 - len; if(addedLen > 0) { memcpy(_string + len, s._string, addedLen); len += addedLen; _string[len] = 0; } } } void copy(ZString s) { copyString(s._string, s.len); } };