10 #if !defined(ECERE_BOOTSTRAP) // quick fix for now
11 #if defined(__WIN32__)
12 #define WIN32_LEAN_AND_MEAN
25 default extern Platform runtimePlatform;
27 #define IS_ALUNDER(ch) ((ch) == '_' || isalnum((ch)))
29 public define DIR_SEP = (GetRuntimePlatform() == win32) ? '\\' : '/';
30 public define DIR_SEPS = (GetRuntimePlatform() == win32) ? "\\" : "/";
32 // Maximum length for a vsprintf string
33 public define MAX_F_STRING = 1025;
35 // Maximum length for a directories and filenames strings
36 public define MAX_EXTENSION = 17; // 16 + \0
37 public define MAX_FILENAME = 274; // 256 chars + extension + dot + \0
38 public define MAX_DIRECTORY = 534; // 8 levels + 8 separators + \0
39 public define MAX_LOCATION = 797; // directory + filename + separator + \0
41 // --- File related String functions ---
42 public char * GetExtension(char * string, char * output)
45 int len = strlen(string);
46 int limit = Max(0, len-MAX_EXTENSION);
48 for(c = len; c>=limit; c--)
53 strcpy(output, string+c+1);
56 else if(ch == '/' || ch == '\\')
62 public char * StripLastDirectory(char * string, char * output)
65 if(runtimePlatform == win32 && !strcmp(string, "\\\\"))
72 int len = strlen(string);
73 for(c = len-2; c>=0; c--)
74 if(string[c] == '/' || string[c] == '\\')
76 else if(string[c] == '>' || (string[c] == ':' && c == 0))
82 if((runtimePlatform == win32) ? (c >= 0) : (c > 0))
84 memmove(output, string, c);
87 if(runtimePlatform == win32 && c == 1 && output[0] == '\\' && output[1] == '\\')
93 strcpy(output, DIR_SEPS);
98 // Return root on UNIX instead of null...
101 strcpy(output, DIR_SEPS);
113 public char * SplitDirectory(const char * string, char * part, char * rest)
118 for(;(ch = string[c]) && (ch == '/' || ch == '\\'); c++);
121 part[len++] = DIR_SEP;
124 for(;(ch = string[c]) && (ch != '/' && ch != '\\'); c++)
126 if(len < MAX_FILENAME)
131 for(;(ch = string[c]) && (ch == '/' || ch == '\\'); c++);
132 memmove(rest, string + c, strlen(string + c) + 1);
133 for(c = strlen(rest); c >= 0; c--)
134 if(ch != '/' && ch != '\\')
143 public char * GetLastDirectory(char * string, char * output)
146 int len = string ? strlen(string) : 0;
147 for(c = len-2; c>=0; c--)
148 if(string[c] == '/' || string[c] == '\\' || string[c] == ':' || string[c] == '>')
153 memmove(output, string+c, strlen(string+c)+1);
157 len = strlen(output);
158 if(len > 1 && (output[len-1] == '\\' || output[len-1] == '/'))
159 output[len-1] = '\0';
163 public bool SplitArchivePath(char * fileName, char * archiveName, char ** archiveFile)
166 if(fileName[0] == '<')
168 int c = strlen(fileName);
169 for(;c>0 && fileName[c] != '>'; c--);
172 strncpy(archiveName, fileName + 1, c - 1);
173 archiveName[c - 1] = '\0';
174 *archiveFile = fileName + c + 1;
178 else if(fileName[0] == ':')
180 strcpy(archiveName, ":");
181 *archiveFile = fileName + 1;
187 public char * PathCatSlash(char * string, char * addedPath)
189 bool modified = false;
192 char fileName[MAX_LOCATION] = "", archiveName[MAX_LOCATION] = "", * file;
197 if(SplitArchivePath(string, archiveName, &file))
198 strcpy(fileName, file);
201 strcpy(fileName, string);
204 if(strstr(string, "http://") == string)
206 char * slash = strstr(fileName + 7, "/");
211 urlFileName = fileName + strlen(fileName);
213 if(strstr(addedPath, "http://") == addedPath)
215 strcpy(fileName, "http://");
219 else if(GetRuntimePlatform() == win32)
221 if(addedPath[0] && addedPath[1] == ':' && addedPath[0] != '<')
223 fileName[0] = (char)toupper(addedPath[0]);
229 else if(addedPath[0] == '\\' && addedPath[1] == '\\')
231 fileName[0] = fileName[1] = '\\';
236 // A drive needs to be selected
237 /* TOCHECK: Cutting this out, can't handle relative path
238 else if(fileName[0] == '/' && !archiveName[0] && strcmp(addedPath, "/"))
243 if(!modified && isURL && (addedPath[0] == '\\' || addedPath[0] == '/'))
245 urlFileName[0] = '/';
246 urlFileName[1] = '\0';
248 else if(!modified && (addedPath[0] == '\\' || addedPath[0] == '/'))
250 if(GetRuntimePlatform() == win32)
253 if(addedPath[0] == '/' && !addedPath[1])
255 fileName[0] = addedPath[0];
260 else if(fileName[0] && fileName[1] == ':')
265 // Relative path root of drive
282 for(; addedPath[c]; )
284 // DANGER OF OVERFLOW HERE
285 // char directory[MAX_FILENAME];
286 char directory[MAX_FILENAME * 16];
291 for(;(ch = addedPath[c]) && (ch == '/' || ch == '\\'); c++);
292 for(;(ch = addedPath[c]) && (ch != '/' && ch != '\\'); c++)
294 if(isURL && ch == '?')
298 if(len < MAX_FILENAME)
299 directory[len++] = ch;
301 directory[len] = '\0';
303 // Trim rightmost spaces
304 for(count = len-1; count >= 0 && (directory[count] == ' ' || directory[count] == '\t'); count--)
306 directory[count] = '\0';
313 if(strstr(directory, "..") == directory && (!directory[2] || directory[2] == DIR_SEP || directory[2] == '/'))
315 int strLen = strlen(fileName) - 1;
318 // Go back one directory
319 for(;(ch = fileName[strLen]) && strLen > -1 && (ch == '/' || ch == '\\'); strLen--);
320 for(;(ch = fileName[strLen]) && strLen > -1 && (ch != '/' && ch != '\\' && ch != ':'); strLen--);
321 for(;(ch = fileName[strLen]) && strLen > -1 && (ch == '/' || ch == '\\'); strLen--);
325 strLen = Max(strLen, urlFileName - fileName);
327 if(!strcmp(fileName + strLen + 1, ".."))
329 strcat(fileName, "/" /*DIR_SEPS*/);
330 strcat(fileName, "..");
334 if(GetRuntimePlatform() == win32)
336 if(!strLen && fileName[0] == '\\' && fileName[1] == '\\')
348 fileName[strLen+1] = '\0';
352 fileName[strLen+1] = '\0';
364 strcpy(fileName, "..");
367 else if(strcmp(directory, "."))
369 int strLen = strlen(fileName);
370 bool notZeroLen = strLen > 0;
371 // if(strLen > 1 && (fileName[strLen-1] == '/' || fileName[strLen-1] == '\\'))
372 if(strLen > 0 && (fileName[strLen-1] == '/' || fileName[strLen-1] == '\\'))
374 if(notZeroLen /*&& fileName[strLen-1] != ':' && fileName[strLen-1] != '>'*/)
375 fileName[strLen++] = '/';
377 fileName[strLen] = '\0';
379 if(strLen + strlen(directory) > MAX_LOCATION - 3)
380 return null; // AN ERROR OCCURED!
382 strcat(fileName, directory);
385 if(isURL && ch == '/')
386 strcat(fileName, "/");
387 if(isURL && ch == '?')
389 strcat(fileName, addedPath+c);
394 sprintf(string, "<%s>%s", archiveName, fileName);
396 strcpy(string, fileName);
398 return modified ? string : null;
401 public char * PathCat(char * string, char * addedPath)
403 bool modified = false;
406 char fileName[MAX_LOCATION] = "", archiveName[MAX_LOCATION] = "", * file;
411 if(SplitArchivePath(string, archiveName, &file))
412 strcpy(fileName, file);
415 strcpy(fileName, string);
418 if(strstr(string, "http://") == string)
420 char * slash = strstr(fileName + 7, "/");
425 urlFileName = fileName + strlen(fileName);
427 if(strstr(addedPath, "http://") == addedPath)
429 strcpy(fileName, "http://");
433 else if(runtimePlatform == win32)
435 if(addedPath[0] && addedPath[1] == ':' && addedPath[0] != '<')
437 fileName[0] = (char)toupper(addedPath[0]);
443 else if(addedPath[0] == '\\' && addedPath[1] == '\\')
445 fileName[0] = fileName[1] = '\\';
450 // A drive needs to be selected
451 else if(fileName[0] == '/' && !archiveName[0] && strcmp(addedPath, "/"))
455 if(!modified && isURL && (addedPath[0] == '\\' || addedPath[0] == '/'))
457 urlFileName[0] = '/';
458 urlFileName[1] = '\0';
460 else if(!modified && (addedPath[0] == '\\' || addedPath[0] == '/'))
462 if(runtimePlatform == win32)
465 if(addedPath[0] == '/' && !addedPath[1])
467 fileName[0] = addedPath[0];
472 else if(fileName[0] && fileName[1] == ':')
477 // Relative path root of drive
494 for(; addedPath[c]; )
496 // DANGER OF OVERFLOW HERE
497 // char directory[MAX_FILENAME];
498 char directory[MAX_FILENAME * 16];
503 for(;(ch = addedPath[c]) && (ch == '/' || ch == '\\'); c++);
504 for(;(ch = addedPath[c]) && (ch != '/' && ch != '\\'); c++)
506 if(isURL && ch == '?')
510 if(len < MAX_FILENAME)
511 directory[len++] = ch;
513 directory[len] = '\0';
515 // Trim rightmost spaces
516 for(count = len-1; count >= 0 && (directory[count] == ' ' || directory[count] == '\t'); count--)
518 directory[count] = '\0';
525 if(strstr(directory, "..") == directory && (!directory[2] || directory[2] == DIR_SEP))
527 int strLen = strlen(fileName) - 1;
530 bool separator = false;
532 // Go back one directory
533 for(;(ch = fileName[strLen]) && strLen > -1 && (ch == '/' || ch == '\\'); strLen--);
534 for(;(ch = fileName[strLen]) && strLen > -1 && (ch != '/' && ch != '\\' && ch != ':'); strLen--);
535 for(;(ch = fileName[strLen]) && strLen > -1 && (ch == '/' || ch == '\\'); strLen--) separator = true;
539 strLen = Max(strLen, urlFileName - fileName);
541 if(!strcmp(fileName + strLen + (separator ? 2 : 1), ".."))
543 strcat(fileName, DIR_SEPS);
544 strcat(fileName, "..");
548 if(runtimePlatform == win32)
550 if(!strLen && fileName[0] == '\\' && fileName[1] == '\\')
562 fileName[strLen+1] = '\0';
566 fileName[strLen+1] = '\0';
578 strcpy(fileName, "..");
581 else if(strcmp(directory, "."))
583 int strLen = strlen(fileName);
584 bool notZeroLen = strLen > 0;
585 // if(strLen > 1 && (fileName[strLen-1] == '/' || fileName[strLen-1] == '\\'))
586 if(strLen > 0 && (fileName[strLen-1] == '/' || fileName[strLen-1] == '\\'))
588 if(notZeroLen /*&& fileName[strLen-1] != ':' && fileName[strLen-1] != '>'*/)
591 fileName[strLen++] = '/';
593 fileName[strLen++] = DIR_SEP;
596 fileName[strLen] = '\0';
598 if(strLen + strlen(directory) > MAX_LOCATION - 3)
599 return null; // AN ERROR OCCURED!
601 strcat(fileName, directory);
604 if(isURL && ch == '/')
605 strcat(fileName, "/");
606 if(isURL && ch == '?')
608 strcat(fileName, addedPath+c);
613 sprintf(string, "<%s>%s", archiveName, fileName);
615 strcpy(string, fileName);
617 return modified ? string : null;
620 public char * MakePathRelative(char * path, char * to, char * destination)
622 // Don't process empty paths
624 memmove(destination, path, strlen(path)+1);
627 // TOFIX: DANGER OF OVERFLOW HERE
628 char pathPart[MAX_FILENAME * 16], pathRest[MAX_LOCATION];
629 char toPart[MAX_FILENAME * 16], toRest[MAX_LOCATION];
630 bool different = false;
632 strcpy(pathRest, path);
635 destination[0] = '\0';
638 SplitDirectory(toRest, toPart, toRest);
640 SplitDirectory(pathRest, pathPart, pathRest);
642 if(different || fstrcmp(toPart, pathPart))
645 strcat(destination, "..");
646 strcat(destination, DIR_SEPS);
651 PathCat(destination, pathPart);
654 SplitDirectory(pathRest, pathPart, pathRest);
655 PathCat(destination, pathPart);
661 public bool StripExtension(char * string)
664 for(c = strlen(string); c>=0; c--)
670 else if(string[c] == '\\' || string[c] == '/')
675 public char * ChangeExtension(char * string, char * ext, char * output)
678 strcpy(output, string);
679 StripExtension(output);
686 // --- String Stuff (Temporarily outside String class) ---
687 public void PrintSize(char * string, uint size, int prec)
692 sprintf(format, "%%.0%df", prec);
693 if(size > 1024 * 1024 * 1024)
695 sprintf(string, format, size / (float)(1024 * 1024 * 1024));
696 strcat(string, " GB");
698 else if(size > 1024 * 1024)
700 sprintf(string, format, size / (float)(1024 * 1024));
701 strcat(string, " MB");
705 sprintf(string, format, size / (float)1024);
706 strcat(string, " KB");
710 sprintf(string, "%d B", size);
713 public void PrintBigSize(char * string, double size, int prec)
718 sprintf(format, "%%.0%df", prec);
719 if(size > 1024.0 * 1024.0 * 1024.0 * 1024.0)
721 sprintf(string, format, size / (1024 * 1024 * 1024.0 * 1024.0));
722 strcat(string, " TB");
724 else if(size > 1024.0 * 1024.0 * 1024.0)
726 sprintf(string, format, size / (1024.0 * 1024.0 * 1024.0));
727 strcat(string, " GB");
729 else if(size > 1024.0 * 1024.0)
731 sprintf(string, format, size / (1024.0 * 1024.0));
732 strcat(string, " MB");
736 sprintf(string, format, size / 1024.0);
737 strcat(string, " KB");
741 sprintf(string, "%.0f B", size);
744 public char * SearchString(char * buffer, int start, char * subStr, bool matchCase, bool matchWord)
749 char * strBuffer = buffer + start;
750 int subLen = strlen(subStr);
751 char beforeChar = start ? *(strBuffer-1) : 0;
752 int (*strcompare)(const char *, const char *, unsigned int) = matchCase ? strncmp : strnicmp;
754 for(ptr = strBuffer; *ptr; ptr++)
756 if(matchCase ? (*subStr == *ptr) : (tolower(*subStr) == tolower(*ptr)))
760 if(!strcompare(ptr,subStr,subLen) &&
762 !IS_ALUNDER(ptr[subLen]) &&
763 !IS_ALUNDER(beforeChar))
765 (!IS_ALUNDER(subStr[subLen-1]) || !IS_ALUNDER(ptr[subLen])) &&
766 (!IS_ALUNDER(subStr[0]) || !IS_ALUNDER(beforeChar)))
771 if(!strcompare(ptr,subStr,subLen))
781 public char * RSearchString(char * buffer, char * subStr, int maxLen, bool matchCase, bool matchWord)
785 int subLen = strlen(subStr);
786 char * ptr1 = buffer + maxLen - subLen;
787 char * ptr2 = buffer + maxLen - subLen - 1;
788 int (*strcompare)(const char *, const char *, unsigned int) = matchCase ? strncmp : strnicmp;
789 for(; ptr1 >=buffer; ptr1--, ptr2--)
791 if(tolower(*subStr) == tolower(*ptr1))
795 if(!strcompare(ptr1,subStr,subLen) &&
796 //!IS_ALUNDER(ptr1[subLen]) && !IS_ALUNDER(*ptr2))
797 (!IS_ALUNDER(subStr[subLen-1]) || !IS_ALUNDER(ptr1[subLen])) &&
798 (!IS_ALUNDER(subStr[0]) || !IS_ALUNDER(*ptr2)))
804 if(!strcompare(ptr1,subStr,subLen))
813 public int Tokenize(char * string, int maxTokens, char* tokens[], bool escapeBackSlashes)
818 bool escaped = false;
819 char * output = string;
821 for(; *string && count < maxTokens; string++, output++)
832 // ADDED THIS HERE...
836 else if(escapeBackSlashes && *string == '\\')
838 else if(*string == '\"')
847 memmove(start + 1, start, string - (char *)start);
851 else if(*string == ' ' && !quoted)
853 tokens[count++] = start;
858 else if(*string != ' ')
868 if(*string == '\\' && escapeBackSlashes)
873 if(start && count < maxTokens)
875 tokens[count++] = start;
881 public int TokenizeWith(char * string, int maxTokens, char* tokens[], char * tokenizers, bool escapeBackSlashes)
886 bool escaped = false;
887 char * output = string;
888 bool quotedFromStart = false;
890 for(; *string && count < maxTokens; string++, output++)
903 else if(escapeBackSlashes && *string == '\\')
905 else if(*string == '\"')
911 quotedFromStart = false;
917 else if(strchr(tokenizers, *string) && !quoted)
919 tokens[count++] = start;
923 // MOVED THIS INSIDE IF ABOVE...
924 //if(output != string)
925 // *output = *string;
927 else if(!strchr(tokenizers, *string))
931 quotedFromStart = true;
938 if(*string == '\\' && escapeBackSlashes)
943 if(start && count < maxTokens)
945 tokens[count++] = start;
951 public char * TrimLSpaces(char * string, char * output)
954 for(c = 0; string[c] && string[c] == ' '; c++);
955 memmove(output, string + c, strlen(string+c)+1);
959 public char * TrimRSpaces(char * string, char * output)
962 for(c = strlen(string)-1; c >= 0 && string[c] == ' '; c--);
965 memmove(output, string, c+1);
973 public void ChangeCh(char * string, char ch1, char ch2)
976 for(c=0; string[c]; c++)
977 if(string[c] == ch1) string[c] = ch2;
980 public void RepeatCh(char * string, int count, char ch)
983 for(c=0; c<count; c++)
988 public char * CopyString(char * string)
992 int len = strlen(string);
993 char * destination = new char[len+1];
995 memcpy(destination, string, len + 1);
1002 public bool GetString(char ** buffer, char * string, int max)
1006 bool quoted = false;
1008 if(!**buffer) { string[0]=0; return false; }
1012 if(!(ch = *((*buffer)++)))
1014 if( (ch!='\n') && (ch!='\r') && (ch!=' ') && (ch!=',') && (ch!='\t'))
1016 if(!*(*buffer)) break;
1020 for(c=0; c<max-1; c++)
1022 if(!quoted && ((ch=='\n')||(ch=='\r')||(ch==' ')||(ch==',')||(ch=='\t')))
1035 if(!(ch = *(*buffer)))
1048 public int GetValue(char ** buffer)
1051 GetString(buffer,string,20);
1052 return atoi(string);
1055 public uint GetHexValue(char ** buffer)
1058 GetString(buffer,string,20);
1059 return strtoul(string, null, 16);
1062 public char * StripQuotes(char * string, char * output)
1065 char * src = (string[0] == '\"') ? (string+1) : string;
1066 memmove(output, src, strlen(src)+1);
1067 len = strlen(output);
1068 if(len && output[len-1] == '\"')
1069 output[len-1] = '\0';
1073 public double FloatFromString(char * string)
1076 float dec = 0,res = 0;
1079 for(c = 0; string[c]; c++)
1082 if(ch == ' ') continue;
1085 if(neg == -1) break;
1088 else if((ch == '.') && !dec)
1090 else if(isdigit(ch))
1099 res = res * 10 + dig;