9 #if !defined(ECERE_BOOTSTRAP) // quick fix for now
10 #if defined(__WIN32__)
11 #define WIN32_LEAN_AND_MEAN
23 default extern Platform runtimePlatform;
25 #define IS_ALUNDER(ch) ((ch) == '_' || isalnum((ch)))
27 public define DIR_SEP = (GetRuntimePlatform() == win32) ? '\\' : '/';
28 public define DIR_SEPS = (GetRuntimePlatform() == win32) ? "\\" : "/";
30 // Maximum length for a vsprintf string
31 public define MAX_F_STRING = 1025;
33 // Maximum length for a directories and filenames strings
34 public define MAX_EXTENSION = 17; // 16 + \0
35 public define MAX_FILENAME = 274; // 256 chars + extension + dot + \0
36 public define MAX_DIRECTORY = 534; // 8 levels + 8 separators + \0
37 public define MAX_LOCATION = 797; // directory + filename + separator + \0
39 // --- File related String functions ---
40 public char * GetExtension(char * string, char * output)
43 int len = strlen(string);
44 int limit = Max(0, len-MAX_EXTENSION);
46 for(c = len; c>=limit; c--)
51 strcpy(output, string+c+1);
54 else if(ch == '/' || ch == '\\')
60 public char * StripLastDirectory(char * string, char * output)
63 if(runtimePlatform == win32 && !strcmp(string, "\\\\"))
70 int len = strlen(string);
71 for(c = len-2; c>=0; c--)
72 if(string[c] == '/' || string[c] == '\\')
74 else if(string[c] == '>' || (string[c] == ':' && c == 0))
80 if((runtimePlatform == win32) ? (c >= 0) : (c > 0))
82 strncpy(output, string, c);
85 if(runtimePlatform == win32 && c == 1 && output[0] == '\\' && output[1] == '\\')
91 strcpy(output, DIR_SEPS);
96 // Return root on UNIX instead of null...
99 strcpy(output, DIR_SEPS);
111 public char * SplitDirectory(const char * string, char * part, char * rest)
116 for(;(ch = string[c]) && (ch == '/' || ch == '\\'); c++);
119 part[len++] = DIR_SEP;
122 for(;(ch = string[c]) && (ch != '/' && ch != '\\'); c++)
124 if(len < MAX_FILENAME)
129 for(;(ch = string[c]) && (ch == '/' || ch == '\\'); c++);
130 strcpy(rest, string + c);
131 for(c = strlen(rest); c >= 0; c--)
132 if(ch != '/' && ch != '\\')
141 public char * GetLastDirectory(char * string, char * output)
144 int len = string ? strlen(string) : 0;
145 for(c = len-2; c>=0; c--)
146 if(string[c] == '/' || string[c] == '\\' || string[c] == ':' || string[c] == '>')
151 strcpy(output, string+c);
155 len = strlen(output);
156 if(len > 1 && (output[len-1] == '\\' || output[len-1] == '/'))
157 output[len-1] = '\0';
161 public bool SplitArchivePath(char * fileName, char * archiveName, char ** archiveFile)
164 if(fileName[0] == '<')
166 int c = strlen(fileName);
167 for(;c>0 && fileName[c] != '>'; c--);
170 strncpy(archiveName, fileName + 1, c - 1);
171 archiveName[c - 1] = '\0';
172 *archiveFile = fileName + c + 1;
176 else if(fileName[0] == ':')
178 strcpy(archiveName, ":");
179 *archiveFile = fileName + 1;
185 public char * PathCatSlash(char * string, char * addedPath)
187 bool modified = false;
190 char fileName[MAX_LOCATION] = "", archiveName[MAX_LOCATION] = "", * file;
195 if(SplitArchivePath(string, archiveName, &file))
196 strcpy(fileName, file);
199 strcpy(fileName, string);
202 if(strstr(string, "http://") == string)
204 char * slash = strstr(fileName + 7, "/");
209 urlFileName = fileName + strlen(fileName);
211 if(strstr(addedPath, "http://") == addedPath)
213 strcpy(fileName, "http://");
217 else if(GetRuntimePlatform() == win32)
219 if(addedPath[0] && addedPath[1] == ':' && addedPath[0] != '<')
221 fileName[0] = (char)toupper(addedPath[0]);
227 else if(addedPath[0] == '\\' && addedPath[1] == '\\')
229 fileName[0] = fileName[1] = '\\';
234 // A drive needs to be selected
235 /* TOCHECK: Cutting this out, can't handle relative path
236 else if(fileName[0] == '/' && !archiveName[0] && strcmp(addedPath, "/"))
241 if(!modified && isURL && (addedPath[0] == '\\' || addedPath[0] == '/'))
243 urlFileName[0] = '/';
244 urlFileName[1] = '\0';
246 else if(!modified && (addedPath[0] == '\\' || addedPath[0] == '/'))
248 if(GetRuntimePlatform() == win32)
251 if(addedPath[0] == '/' && !addedPath[1])
253 fileName[0] = addedPath[0];
258 else if(fileName[0] && fileName[1] == ':')
263 // Relative path root of drive
280 for(; addedPath[c]; )
282 // DANGER OF OVERFLOW HERE
283 // char directory[MAX_FILENAME];
284 char directory[MAX_FILENAME * 16];
289 for(;(ch = addedPath[c]) && (ch == '/' || ch == '\\'); c++);
290 for(;(ch = addedPath[c]) && (ch != '/' && ch != '\\'); c++)
292 if(isURL && ch == '?')
296 if(len < MAX_FILENAME)
297 directory[len++] = ch;
299 directory[len] = '\0';
301 // Trim rightmost spaces
302 for(count = len-1; count >= 0 && (directory[count] == ' ' || directory[count] == '\t'); count--)
304 directory[count] = '\0';
311 if(strstr(directory, "..") == directory && (!directory[2] || directory[2] == DIR_SEP || directory[2] == '/'))
313 int strLen = strlen(fileName) - 1;
316 // Go back one directory
317 for(;(ch = fileName[strLen]) && strLen > -1 && (ch == '/' || ch == '\\'); strLen--);
318 for(;(ch = fileName[strLen]) && strLen > -1 && (ch != '/' && ch != '\\' && ch != ':'); strLen--);
319 for(;(ch = fileName[strLen]) && strLen > -1 && (ch == '/' || ch == '\\'); strLen--);
323 strLen = Max(strLen, urlFileName - fileName);
325 if(!strcmp(fileName + strLen + 1, ".."))
327 strcat(fileName, "/" /*DIR_SEPS*/);
328 strcat(fileName, "..");
332 if(GetRuntimePlatform() == win32)
334 if(!strLen && fileName[0] == '\\' && fileName[1] == '\\')
346 fileName[strLen+1] = '\0';
350 fileName[strLen+1] = '\0';
362 strcpy(fileName, "..");
365 else if(strcmp(directory, "."))
367 int strLen = strlen(fileName);
368 bool notZeroLen = strLen > 0;
369 // if(strLen > 1 && (fileName[strLen-1] == '/' || fileName[strLen-1] == '\\'))
370 if(strLen > 0 && (fileName[strLen-1] == '/' || fileName[strLen-1] == '\\'))
372 if(notZeroLen /*&& fileName[strLen-1] != ':' && fileName[strLen-1] != '>'*/)
373 fileName[strLen++] = '/';
375 fileName[strLen] = '\0';
377 if(strLen + strlen(directory) > MAX_LOCATION - 3)
378 return null; // AN ERROR OCCURED!
380 strcat(fileName, directory);
383 if(isURL && ch == '/')
384 strcat(fileName, "/");
385 if(isURL && ch == '?')
387 strcat(fileName, addedPath+c);
392 sprintf(string, "<%s>%s", archiveName, fileName);
394 strcpy(string, fileName);
396 return modified ? string : null;
399 public char * PathCat(char * string, char * addedPath)
401 bool modified = false;
404 char fileName[MAX_LOCATION] = "", archiveName[MAX_LOCATION] = "", * file;
409 if(SplitArchivePath(string, archiveName, &file))
410 strcpy(fileName, file);
413 strcpy(fileName, string);
416 if(strstr(string, "http://") == string)
418 char * slash = strstr(fileName + 7, "/");
423 urlFileName = fileName + strlen(fileName);
425 if(strstr(addedPath, "http://") == addedPath)
427 strcpy(fileName, "http://");
431 else if(runtimePlatform == win32)
433 if(addedPath[0] && addedPath[1] == ':' && addedPath[0] != '<')
435 fileName[0] = (char)toupper(addedPath[0]);
441 else if(addedPath[0] == '\\' && addedPath[1] == '\\')
443 fileName[0] = fileName[1] = '\\';
448 // A drive needs to be selected
449 else if(fileName[0] == '/' && !archiveName[0] && strcmp(addedPath, "/"))
453 if(!modified && isURL && (addedPath[0] == '\\' || addedPath[0] == '/'))
455 urlFileName[0] = '/';
456 urlFileName[1] = '\0';
458 else if(!modified && (addedPath[0] == '\\' || addedPath[0] == '/'))
460 if(runtimePlatform == win32)
463 if(addedPath[0] == '/' && !addedPath[1])
465 fileName[0] = addedPath[0];
470 else if(fileName[0] && fileName[1] == ':')
475 // Relative path root of drive
492 for(; addedPath[c]; )
494 // DANGER OF OVERFLOW HERE
495 // char directory[MAX_FILENAME];
496 char directory[MAX_FILENAME * 16];
501 for(;(ch = addedPath[c]) && (ch == '/' || ch == '\\'); c++);
502 for(;(ch = addedPath[c]) && (ch != '/' && ch != '\\'); c++)
504 if(isURL && ch == '?')
508 if(len < MAX_FILENAME)
509 directory[len++] = ch;
511 directory[len] = '\0';
513 // Trim rightmost spaces
514 for(count = len-1; count >= 0 && (directory[count] == ' ' || directory[count] == '\t'); count--)
516 directory[count] = '\0';
523 if(strstr(directory, "..") == directory && (!directory[2] || directory[2] == DIR_SEP))
525 int strLen = strlen(fileName) - 1;
528 bool separator = false;
530 // Go back one directory
531 for(;(ch = fileName[strLen]) && strLen > -1 && (ch == '/' || ch == '\\'); strLen--);
532 for(;(ch = fileName[strLen]) && strLen > -1 && (ch != '/' && ch != '\\' && ch != ':'); strLen--);
533 for(;(ch = fileName[strLen]) && strLen > -1 && (ch == '/' || ch == '\\'); strLen--) separator = true;
537 strLen = Max(strLen, urlFileName - fileName);
539 if(!strcmp(fileName + strLen + (separator ? 2 : 1), ".."))
541 strcat(fileName, DIR_SEPS);
542 strcat(fileName, "..");
546 if(runtimePlatform == win32)
548 if(!strLen && fileName[0] == '\\' && fileName[1] == '\\')
560 fileName[strLen+1] = '\0';
564 fileName[strLen+1] = '\0';
576 strcpy(fileName, "..");
579 else if(strcmp(directory, "."))
581 int strLen = strlen(fileName);
582 bool notZeroLen = strLen > 0;
583 // if(strLen > 1 && (fileName[strLen-1] == '/' || fileName[strLen-1] == '\\'))
584 if(strLen > 0 && (fileName[strLen-1] == '/' || fileName[strLen-1] == '\\'))
586 if(notZeroLen /*&& fileName[strLen-1] != ':' && fileName[strLen-1] != '>'*/)
589 fileName[strLen++] = '/';
591 fileName[strLen++] = DIR_SEP;
594 fileName[strLen] = '\0';
596 if(strLen + strlen(directory) > MAX_LOCATION - 3)
597 return null; // AN ERROR OCCURED!
599 strcat(fileName, directory);
602 if(isURL && ch == '/')
603 strcat(fileName, "/");
604 if(isURL && ch == '?')
606 strcat(fileName, addedPath+c);
611 sprintf(string, "<%s>%s", archiveName, fileName);
613 strcpy(string, fileName);
615 return modified ? string : null;
618 public char * MakePathRelative(char * path, char * to, char * destination)
620 // Don't process empty paths
622 strcpy(destination, path);
625 // TOFIX: DANGER OF OVERFLOW HERE
626 char pathPart[MAX_FILENAME * 16], pathRest[MAX_LOCATION];
627 char toPart[MAX_FILENAME * 16], toRest[MAX_LOCATION];
628 bool different = false;
630 strcpy(pathRest, path);
633 destination[0] = '\0';
636 SplitDirectory(toRest, toPart, toRest);
638 SplitDirectory(pathRest, pathPart, pathRest);
640 if(different || fstrcmp(toPart, pathPart))
643 strcat(destination, "..");
644 strcat(destination, DIR_SEPS);
649 PathCat(destination, pathPart);
652 SplitDirectory(pathRest, pathPart, pathRest);
653 PathCat(destination, pathPart);
659 public bool StripExtension(char * string)
662 for(c = strlen(string); c>=0; c--)
668 else if(string[c] == '\\' || string[c] == '/')
673 public char * ChangeExtension(char * string, char * ext, char * output)
675 strcpy(output, string);
676 StripExtension(output);
683 // --- String Stuff (Temporarily outside String class) ---
684 public void PrintSize(char * string, uint size, int prec)
689 sprintf(format, "%%.0%df", prec);
690 if(size > 1024 * 1024 * 1024)
692 sprintf(string, format, size / (float)(1024 * 1024 * 1024));
693 strcat(string, " GB");
695 else if(size > 1024 * 1024)
697 sprintf(string, format, size / (float)(1024 * 1024));
698 strcat(string, " MB");
702 sprintf(string, format, size / (float)1024);
703 strcat(string, " KB");
707 sprintf(string, "%d B", size);
710 public void PrintBigSize(char * string, double size, int prec)
715 sprintf(format, "%%.0%df", prec);
716 if(size > 1024.0 * 1024.0 * 1024.0 * 1024.0)
718 sprintf(string, format, size / (1024 * 1024 * 1024.0 * 1024.0));
719 strcat(string, " TB");
721 else if(size > 1024.0 * 1024.0 * 1024.0)
723 sprintf(string, format, size / (1024.0 * 1024.0 * 1024.0));
724 strcat(string, " GB");
726 else if(size > 1024.0 * 1024.0)
728 sprintf(string, format, size / (1024.0 * 1024.0));
729 strcat(string, " MB");
733 sprintf(string, format, size / 1024.0);
734 strcat(string, " KB");
738 sprintf(string, "%.0f B", size);
741 public char * SearchString(char * buffer, int start, char * subStr, bool matchCase, bool matchWord)
746 char * strBuffer = buffer + start;
747 int subLen = strlen(subStr);
748 char beforeChar = start ? *(strBuffer-1) : 0;
749 int (*strcompare)(const char *, const char *, unsigned int) = matchCase ? strncmp : strnicmp;
751 for(ptr = strBuffer; *ptr; ptr++)
753 if(matchCase ? (*subStr == *ptr) : (tolower(*subStr) == tolower(*ptr)))
757 if(!strcompare(ptr,subStr,subLen) &&
759 !IS_ALUNDER(ptr[subLen]) &&
760 !IS_ALUNDER(beforeChar))
762 (!IS_ALUNDER(subStr[subLen-1]) || !IS_ALUNDER(ptr[subLen])) &&
763 (!IS_ALUNDER(subStr[0]) || !IS_ALUNDER(beforeChar)))
768 if(!strcompare(ptr,subStr,subLen))
778 public char * RSearchString(char * buffer, char * subStr, int maxLen, bool matchCase, bool matchWord)
782 int subLen = strlen(subStr);
783 char * ptr1 = buffer + maxLen - subLen;
784 char * ptr2 = buffer + maxLen - subLen - 1;
785 int (*strcompare)(const char *, const char *, unsigned int) = matchCase ? strncmp : strnicmp;
786 for(; ptr1 >=buffer; ptr1--, ptr2--)
788 if(tolower(*subStr) == tolower(*ptr1))
792 if(!strcompare(ptr1,subStr,subLen) &&
793 //!IS_ALUNDER(ptr1[subLen]) && !IS_ALUNDER(*ptr2))
794 (!IS_ALUNDER(subStr[subLen-1]) || !IS_ALUNDER(ptr1[subLen])) &&
795 (!IS_ALUNDER(subStr[0]) || !IS_ALUNDER(*ptr2)))
801 if(!strcompare(ptr1,subStr,subLen))
810 public int Tokenize(char * string, int maxTokens, char* tokens[], bool escapeBackSlashes)
815 bool escaped = false;
816 char * output = string;
818 for(; *string && count < maxTokens; string++, output++)
829 // ADDED THIS HERE...
833 else if(escapeBackSlashes && *string == '\\')
835 else if(*string == '\"')
844 memmove(start + 1, start, string - (char *)start);
848 else if(*string == ' ' && !quoted)
850 tokens[count++] = start;
855 else if(*string != ' ')
865 if(*string == '\\' && escapeBackSlashes)
870 if(start && count < maxTokens)
872 tokens[count++] = start;
878 public int TokenizeWith(char * string, int maxTokens, char* tokens[], char * tokenizers, bool escapeBackSlashes)
883 bool escaped = false;
884 char * output = string;
885 bool quotedFromStart = false;
887 for(; *string && count < maxTokens; string++, output++)
900 else if(escapeBackSlashes && *string == '\\')
902 else if(*string == '\"')
908 quotedFromStart = false;
914 else if(strchr(tokenizers, *string) && !quoted)
916 tokens[count++] = start;
920 // MOVED THIS INSIDE IF ABOVE...
921 //if(output != string)
922 // *output = *string;
924 else if(!strchr(tokenizers, *string))
928 quotedFromStart = true;
935 if(*string == '\\' && escapeBackSlashes)
940 if(start && count < maxTokens)
942 tokens[count++] = start;
948 public char * TrimLSpaces(char * string, char * output)
951 for(c = 0; string[c] && string[c] == ' '; c++);
952 strcpy(output, string + c);
956 public char * TrimRSpaces(char * string, char * output)
959 for(c = strlen(string)-1; c >= 0 && string[c] == ' '; c--);
962 memmove(output, string, c+1);
970 public void ChangeCh(char * string, char ch1, char ch2)
973 for(c=0; string[c]; c++)
974 if(string[c] == ch1) string[c] = ch2;
977 public void RepeatCh(char * string, int count, char ch)
980 for(c=0; c<count; c++)
985 public char * CopyString(char * string)
989 int len = strlen(string);
990 char * destination = new char[len+1];
992 memcpy(destination, string, len + 1);
999 public bool GetString(char ** buffer, char * string, int max)
1003 bool quoted = false;
1005 if(!**buffer) { string[0]=0; return false; }
1009 if(!(ch = *((*buffer)++)))
1011 if( (ch!='\n') && (ch!='\r') && (ch!=' ') && (ch!=',') && (ch!='\t'))
1013 if(!*(*buffer)) break;
1017 for(c=0; c<max-1; c++)
1019 if(!quoted && ((ch=='\n')||(ch=='\r')||(ch==' ')||(ch==',')||(ch=='\t')))
1032 if(!(ch = *(*buffer)))
1045 public int GetValue(char ** buffer)
1048 GetString(buffer,string,20);
1049 return atoi(string);
1052 public uint GetHexValue(char ** buffer)
1055 GetString(buffer,string,20);
1056 return strtoul(string, null, 16);
1059 public char * StripQuotes(char * string, char * output)
1063 strcpy(output,(string[0] == '\"') ? (string+1) : string);
1064 len = strlen(output);
1065 if(len && output[len-1] == '\"')
1066 output[len-1] = '\0';
1070 public double FloatFromString(char * string)
1073 float dec = 0,res = 0;
1076 for(c = 0; string[c]; c++)
1079 if(ch == ' ') continue;
1082 if(neg == -1) break;
1085 else if((ch == '.') && !dec)
1087 else if(isdigit(ch))
1096 res = res * 10 + dig;
1104 public bool GetAlNum(char ** buffer, char * string, int max)
1109 if(!**buffer) { string[0]=0; return false; }
1113 if(!(ch = *((*buffer)++)))
1117 if(!*(*buffer)) break;
1121 for(c=0; c<max-1; c++)
1129 if(!(ch = *(*buffer)))