wasCSharpSQLite – Blame information for rev

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 #undef DEBUG
2 /*
3 * FileUtil.java --
4 *
5 * This file contains utility methods for file-related operations.
6 *
7 * Copyright (c) 1997 Sun Microsystems, Inc.
8 *
9 * See the file "license.terms" for information on usage and
10 * redistribution of this file, and for a DISCLAIMER OF ALL
11 * WARRANTIES.
12 *
13 * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
14 *
15 * RCS @(#) $Id: FileUtil.java,v 1.6 2003/02/02 00:59:16 mdejong Exp $
16 *
17 */
18 using System;
19 using System.Text;
20 using System.IO;
21 namespace tcl.lang
22 {
23  
24 /*
25 * This class implements utility methods for file-related operations.
26 */
27  
28 public class FileUtil
29 {
30  
31 internal const int PATH_RELATIVE = 0;
32 internal const int PATH_VOLUME_RELATIVE = 1;
33 internal const int PATH_ABSOLUTE = 2;
34  
35 /*
36 *-----------------------------------------------------------------------------
37 *
38 * getWinHomePath --
39 *
40 * In the Windows file system, one type of absolute path follows this
41 * regular expression: ^(//+[a-zA-Z]+/+[a-zA-Z]+)
42 *
43 * If "path" doesn't fit the pattern, then return 0.
44 * If the stopEarly bool is true, then return the index of the first
45 * non-slash character in path, as soon as we know that path fits the
46 * pattern. Otherwise, return the index of the slash (or end of string)
47 * following the entire absolute path.
48 *
49 * Results:
50 * Returns an integer index in path.
51 *
52 * Side effects:
53 * If "path" fits the pattern, and "stopEarly" is not chosen, the absolute
54 * path is coppied (without extra slashes) to "absBuf". Otherwise, absBuf
55 * is set to "".
56 *
57 *-----------------------------------------------------------------------------
58 */
59  
60 private static int getWinHomePath( string path, bool stopEarly, StringBuilder absBuf )
61 // Buffer to store side effect.
62 {
63 int pIndex, oldIndex, firstNonSlash;
64  
65 // The first 2 or more chars must be slashes.
66  
67 for ( pIndex = 0; pIndex < path.Length; pIndex++ )
68 {
69 if ( path[pIndex] != '/' )
70 {
71 break;
72 }
73 }
74 if ( pIndex < 2 )
75 {
76 absBuf.Length = 0;
77 return 0;
78 }
79 firstNonSlash = pIndex;
80  
81  
82 // The next 1 or more chars may not be slashes.
83  
84 for ( ; pIndex < path.Length; pIndex++ )
85 {
86 if ( path[pIndex] == '/' )
87 {
88 break;
89 }
90 }
91 if ( pIndex == firstNonSlash )
92 {
93 absBuf.Length = 0;
94 return 0;
95 }
96 absBuf.EnsureCapacity( absBuf.Length + path.Length );
97 absBuf.Append( "//" );
98 absBuf.Append( path.Substring( firstNonSlash, ( pIndex ) - ( firstNonSlash ) ) );
99  
100 // The next 1 or more chars must be slashes.
101  
102 oldIndex = pIndex;
103 for ( ; pIndex < path.Length; pIndex++ )
104 {
105 if ( path[pIndex] != '/' )
106 {
107 if ( pIndex == oldIndex )
108 {
109 absBuf.Length = 0;
110 return 0;
111 }
112  
113 // We know that the path fits the pattern.
114  
115 if ( stopEarly )
116 {
117 absBuf.Length = 0;
118 return firstNonSlash;
119 }
120 firstNonSlash = pIndex;
121  
122 // Traverse the path until a new slash (or end of string) is found.
123 // Return the index of the new slash.
124  
125 pIndex++;
126 for ( ; pIndex < path.Length; pIndex++ )
127 {
128 if ( path[pIndex] == '/' )
129 {
130 break;
131 }
132 }
133 absBuf.Append( '/' );
134 absBuf.Append( path.Substring( firstNonSlash, ( pIndex ) - ( firstNonSlash ) ) );
135 return pIndex;
136 }
137 }
138 absBuf.Length = 0;
139 return 0;
140 }
141 private static int beginsWithLetterColon( string path )
142 // Path to check start pattern.
143 {
144 if ( ( path.Length > 1 ) && ( System.Char.IsLetter( path[0] ) ) && ( path[1] == ':' ) )
145 {
146  
147 int pIndex;
148 for ( pIndex = 2; pIndex < path.Length; pIndex++ )
149 {
150 if ( path[pIndex] != '/' )
151 {
152 break;
153 }
154 }
155 return pIndex;
156 }
157 return 0;
158 }
159 private static int getWinAbsPath( string path, StringBuilder absBuf )
160 // Buffer to store side effect.
161 {
162 absBuf.Length = 0;
163  
164 if ( path.Length < 1 )
165 {
166 return 0;
167 }
168  
169 absBuf.EnsureCapacity( absBuf.Length + path.Length );
170  
171 int colonIndex = beginsWithLetterColon( path );
172 if ( colonIndex > 0 )
173 {
174 if ( colonIndex > 2 )
175 {
176 absBuf.Append( path.Substring( 0, ( 3 ) - ( 0 ) ) );
177 }
178 else
179 {
180 absBuf.Append( path.Substring( 0, ( 2 ) - ( 0 ) ) );
181 }
182 return colonIndex;
183 }
184 else
185 {
186 int absIndex = getWinHomePath( path, false, absBuf );
187 if ( absIndex > 0 )
188 {
189 return absIndex;
190 }
191 else if ( path[0] == '/' )
192 {
193 int pIndex;
194 for ( pIndex = 1; pIndex < path.Length; pIndex++ )
195 {
196 if ( path[pIndex] != '/' )
197 {
198 break;
199 }
200 }
201 absBuf.Append( "/" );
202 return pIndex;
203 }
204 }
205 return 0;
206 }
207 private static int getDegenerateUnixPath( string path )
208 // Path to check.
209 {
210 int pIndex = 0;
211  
212 while ( ( pIndex < path.Length ) && ( path[pIndex] == '/' ) )
213 {
214 ++pIndex;
215 }
216  
217 // "path" doesn't begin with a '/'.
218  
219 if ( pIndex == 0 )
220 {
221 return 0;
222 }
223 while ( pIndex < path.Length )
224 {
225 string tmpPath = path.Substring( pIndex );
226 if ( tmpPath.StartsWith( "./" ) )
227 {
228 pIndex += 2;
229 }
230 else if ( tmpPath.StartsWith( "../" ) )
231 {
232 pIndex += 3;
233 }
234 else
235 {
236 break;
237 }
238 while ( ( pIndex < path.Length ) && ( path[pIndex] == '/' ) )
239 {
240 ++pIndex;
241 }
242 }
243 if ( ( pIndex < path.Length ) && ( path[pIndex] == '.' ) )
244 {
245 ++pIndex;
246 }
247 if ( ( pIndex < path.Length ) && ( path[pIndex] == '.' ) )
248 {
249 ++pIndex;
250 }
251  
252 // pIndex may be 1 past the end of "path".
253  
254 return pIndex;
255 }
256 internal static int getPathType( string path )
257 // Path for which we find pathtype.
258 {
259 char c;
260 if ( path.Length < 1 )
261 {
262 return PATH_RELATIVE;
263 }
264  
265 switch ( JACL.PLATFORM )
266 {
267  
268 case JACL.PLATFORM_WINDOWS:
269 path = path.Replace( '\\', '/' );
270  
271 // Windows absolute pathes start with '~' or [a-zA-Z]:/ or home
272 // path.
273  
274 c = path[0];
275 if ( c == '~' )
276 {
277 return PATH_ABSOLUTE;
278 }
279 if ( c == '/' )
280 {
281 StringBuilder absBuf = new StringBuilder( 0 );
282 if ( getWinHomePath( path, true, absBuf ) > 0 )
283 {
284 return PATH_ABSOLUTE;
285 }
286 return PATH_VOLUME_RELATIVE;
287 }
288 int colonIndex = beginsWithLetterColon( path );
289 if ( colonIndex > 0 )
290 {
291 if ( colonIndex > 2 )
292 {
293 return PATH_ABSOLUTE;
294 }
295 return PATH_VOLUME_RELATIVE;
296 }
297 return PATH_RELATIVE;
298  
299  
300 case JACL.PLATFORM_MAC:
301 if ( path[0] == '~' )
302 {
303 return PATH_ABSOLUTE;
304 }
305  
306 switch ( path.IndexOf( (System.Char)':' ) )
307 {
308  
309 case -1:
310  
311 if ( ( path[0] == '/' ) && ( getDegenerateUnixPath( path ) < path.Length ) )
312 {
313 return PATH_ABSOLUTE;
314 }
315 break;
316  
317 case 0:
318  
319 return PATH_RELATIVE;
320  
321 default:
322  
323 return PATH_ABSOLUTE;
324  
325 }
326 return PATH_RELATIVE;
327  
328  
329 default:
330  
331 c = path[0];
332 if ( ( c == '/' ) || ( c == '~' ) )
333 {
334 return PATH_ABSOLUTE;
335 }
336 break;
337  
338 }
339 return PATH_RELATIVE;
340 }
341 internal static FileInfo getNewFileObj( Interp interp, string fileName )
342 {
343 fileName = translateFileName( interp, fileName );
344 System.Diagnostics.Debug.WriteLine( "File name is \"" + fileName + "\"" );
345 switch ( getPathType( fileName ) )
346 {
347  
348 case PATH_RELATIVE:
349 if ( fileName == ":memory:" )
350 return null;
351 System.Diagnostics.Debug.WriteLine( "File name is PATH_RELATIVE" );
352 return new FileInfo( interp.getWorkingDir().FullName + "\\" + fileName );
353  
354 case PATH_VOLUME_RELATIVE:
355 System.Diagnostics.Debug.WriteLine( "File name is PATH_VOLUME_RELATIVE" );
356  
357 // Something is very wrong if interp.getWorkingDir()
358 // does not start with C: or another drive letter
359 string cwd = interp.getWorkingDir().ToString();
360 int index = beginsWithLetterColon( cwd );
361 if ( index == 0 )
362 {
363 throw new TclRuntimeError( "interp working directory \"" + cwd + "\" does not start with a drive letter" );
364 }
365  
366 // We can not use the joinPath() method because joing("D:/", "/f.txt")
367 // returns "/f.txt" for some wacky reason. Just do it ourselves.
368 StringBuilder buff = new StringBuilder();
369 buff.Append( cwd.Substring( 0, ( 2 ) - ( 0 ) ) );
370 buff.Append( '\\' );
371 for ( int i = 0; i < fileName.Length; i++ )
372 {
373 if ( fileName[i] != '\\' )
374 {
375 // Once we skip all the \ characters at the front
376 // append the rest of the fileName onto the buffer
377 buff.Append( fileName.Substring( i ) );
378 break;
379 }
380 }
381  
382 fileName = buff.ToString();
383  
384 System.Diagnostics.Debug.WriteLine( "After PATH_VOLUME_RELATIVE join \"" + fileName + "\"" );
385  
386 return new FileInfo( fileName );
387  
388 case PATH_ABSOLUTE:
389 System.Diagnostics.Debug.WriteLine( "File name is PATH_ABSOLUTE" );
390 return new FileInfo( fileName );
391  
392 default:
393 throw new TclRuntimeError( "type for fileName \"" + fileName + "\" not matched in case statement" );
394  
395 }
396 }
397 private static void appendComponent( string component, int compIndex, int compSize, StringBuilder buf )
398 // Buffer to append the component.
399 {
400 for ( ; compIndex < component.Length; compIndex++ )
401 {
402 char c = component[compIndex];
403 if ( c == '/' )
404 {
405 // Eliminate duplicate slashes.
406  
407 while ( ( compIndex < compSize ) && ( component[compIndex + 1] == '/' ) )
408 {
409 compIndex++;
410 }
411  
412 // Only add a slash if following non-slash elements exist.
413  
414 if ( compIndex < compSize )
415 {
416 buf.EnsureCapacity( buf.Length + 1 );
417 buf.Append( '/' );
418 }
419 }
420 else
421 {
422 buf.EnsureCapacity( buf.Length + 1 );
423 buf.Append( c );
424 }
425 }
426 }
427 internal static string joinPath( Interp interp, TclObject[] argv, int startIndex, int endIndex )
428 {
429 StringBuilder result = new StringBuilder( 10 );
430  
431 switch ( JACL.PLATFORM )
432 {
433  
434 case JACL.PLATFORM_WINDOWS:
435  
436 for ( int i = startIndex; i < endIndex; i++ )
437 {
438  
439  
440 string p = argv[i].ToString().Replace( '\\', '/' );
441 int pIndex = 0;
442 int pLastIndex = p.Length - 1;
443  
444 if ( p.Length == 0 )
445 {
446 continue;
447 }
448  
449 StringBuilder absBuf = new StringBuilder( 0 );
450 pIndex = getWinAbsPath( p, absBuf );
451 if ( pIndex > 0 )
452 {
453 // If the path is absolute or volume relative (except those
454 // beginning with '~'), reset the result buffer to the absolute
455 // substring.
456  
457 result = absBuf;
458 }
459 else if ( p[0] == '~' )
460 {
461 // If the path begins with '~', reset the result buffer to "".
462  
463 result.Length = 0;
464 }
465 else
466 {
467 // This is a relative path. Remove the ./ from tilde prefixed
468 // elements unless it is the first component.
469  
470 if ( ( result.Length != 0 ) && ( String.Compare( p, pIndex, "./~", 0, 3 ) == 0 ) )
471 {
472 pIndex = 2;
473 }
474  
475 // Check to see if we need to append a separator before adding
476 // this relative component.
477  
478 if ( result.Length != 0 )
479 {
480 char c = result[result.Length - 1];
481 if ( ( c != '/' ) && ( c != ':' ) )
482 {
483 result.EnsureCapacity( result.Length + 1 );
484 result.Append( '/' );
485 }
486 }
487 }
488  
489 // Append the element.
490  
491 appendComponent( p, pIndex, pLastIndex, result );
492 pIndex = p.Length;
493 }
494 return result.ToString();
495  
496  
497 case JACL.PLATFORM_MAC:
498  
499  
500 bool needsSep = true;
501 for ( int i = startIndex; i < endIndex; i++ )
502 {
503  
504  
505 TclObject[] splitArrayObj = TclList.getElements( interp, splitPath( interp, argv[i].ToString() ) );
506  
507 if ( splitArrayObj.Length == 0 )
508 {
509 continue;
510 }
511  
512 // If 1st path element is absolute, reset the result to "" and
513 // append the 1st path element to it.
514  
515 int start = 0;
516  
517 string p = splitArrayObj[0].ToString();
518 if ( ( p[0] != ':' ) && ( p.IndexOf( (System.Char)':' ) != -1 ) )
519 {
520 result.Length = 0;
521 result.Append( p );
522 start++;
523 needsSep = false;
524 }
525  
526 // Now append the rest of the path elements, skipping
527 // : unless it is the first element of the path, and
528 // watching out for :: et al. so we don't end up with
529 // too many colons in the result.
530  
531 for ( int j = start; j < splitArrayObj.Length; j++ )
532 {
533  
534  
535 p = splitArrayObj[j].ToString();
536  
537 if ( p.Equals( ":" ) )
538 {
539 if ( result.Length != 0 )
540 {
541 continue;
542 }
543 else
544 {
545 needsSep = false;
546 }
547 }
548 else
549 {
550 char c = 'o';
551 if ( p.Length > 1 )
552 {
553 c = p[1];
554 }
555 if ( p[0] == ':' )
556 {
557 if ( !needsSep )
558 {
559 p = p.Substring( 1 );
560 }
561 }
562 else
563 {
564 if ( needsSep )
565 {
566 result.Append( ':' );
567 }
568 }
569 if ( c == ':' )
570 {
571 needsSep = false;
572 }
573 else
574 {
575 needsSep = true;
576 }
577 }
578 result.Append( p );
579 }
580 }
581 return result.ToString();
582  
583  
584 default:
585  
586 for ( int i = startIndex; i < endIndex; i++ )
587 {
588  
589  
590 string p = argv[i].ToString();
591 int pIndex = 0;
592 int pLastIndex = p.Length - 1;
593  
594 if ( p.Length == 0 )
595 {
596 continue;
597 }
598  
599 if ( p[pIndex] == '/' )
600 {
601 // If the path is absolute (except those beginning with '~'),
602 // reset the result buffer to the absolute substring.
603  
604 while ( ( pIndex <= pLastIndex ) && ( p[pIndex] == '/' ) )
605 {
606 pIndex++;
607 }
608 result.Length = 0;
609 result.Append( '/' );
610 }
611 else if ( p[pIndex] == '~' )
612 {
613 // If the path begins with '~', reset the result buffer to "".
614  
615 result.Length = 0;
616 }
617 else
618 {
619 // This is a relative path. Remove the ./ from tilde prefixed
620 // elements unless it is the first component.
621  
622 if ( ( result.Length != 0 ) && ( String.Compare( p, pIndex, "./~", 0, 3 ) == 0 ) )
623 {
624 pIndex += 2;
625 }
626  
627 // Append a separator if needed.
628  
629 if ( ( result.Length != 0 ) && ( result[result.Length - 1] != '/' ) )
630 {
631 result.EnsureCapacity( result.Length + 1 );
632 result.Append( '/' );
633 }
634 }
635  
636 // Append the element.
637  
638 appendComponent( p, pIndex, pLastIndex, result );
639 pIndex = p.Length;
640 }
641 break;
642  
643 }
644 return result.ToString();
645 }
646 internal static TclObject splitPath( Interp interp, string path )
647 {
648 TclObject resultListObj = TclList.newInstance();
649 TclObject componentObj;
650 string component = "";
651 string tmpPath;
652 bool foundComponent = false;
653 bool convertDotToColon = false;
654 bool isColonSeparator = false;
655 bool appendColon = false;
656 bool prependColon = false;
657 string thisDir = "./";
658  
659 // If the path is the empty string, returnan empty result list.
660  
661 if ( path.Length == 0 )
662 {
663 return resultListObj;
664 }
665  
666 // Handling the 1st component is file system dependent.
667  
668 switch ( JACL.PLATFORM )
669 {
670  
671 case JACL.PLATFORM_WINDOWS:
672 tmpPath = path.Replace( '\\', '/' );
673  
674 StringBuilder absBuf = new StringBuilder( 0 );
675 int absIndex = getWinAbsPath( tmpPath, absBuf );
676 if ( absIndex > 0 )
677 {
678 componentObj = TclString.newInstance( absBuf.ToString() );
679 TclList.append( interp, resultListObj, componentObj );
680 tmpPath = tmpPath.Substring( absIndex );
681 foundComponent = true;
682 }
683 break;
684  
685  
686 case JACL.PLATFORM_MAC:
687  
688 tmpPath = "";
689 thisDir = ":";
690  
691 switch ( path.IndexOf( (System.Char)':' ) )
692 {
693  
694 case -1:
695  
696 if ( path[0] != '/' )
697 {
698 tmpPath = path;
699 convertDotToColon = true;
700 if ( path[0] == '~' )
701 {
702 // If '~' is the first char, then append a colon to end
703 // of the 1st component.
704  
705 appendColon = true;
706 }
707 break;
708 }
709 int degenIndex = getDegenerateUnixPath( path );
710 if ( degenIndex < path.Length )
711 {
712 // First component of absolute unix path is followed by a ':',
713 // instead of being preceded by a degenerate unix-style
714 // pattern.
715  
716  
717 tmpPath = path.Substring( degenIndex );
718 convertDotToColon = true;
719 appendColon = true;
720 break;
721 }
722  
723 // Degenerate unix path can't be split. Return a list with one
724 // element: ":" prepended to "path".
725  
726 componentObj = TclString.newInstance( ":" + path );
727 TclList.append( interp, resultListObj, componentObj );
728 return resultListObj;
729  
730 case 0:
731  
732 if ( path.Length == 1 )
733 {
734 // If path == ":", then return a list with ":" as its only
735 // element.
736  
737 componentObj = TclString.newInstance( ":" );
738 TclList.append( interp, resultListObj, componentObj );
739 return resultListObj;
740 }
741  
742  
743 // For each component, if slashes exist in the remaining filename,
744 // prepend a colon to the component. Since this path is relative,
745 // pretend that we have already processed 1 components so a
746 // tilde-prefixed 1st component will have ":" prepended to it.
747  
748  
749 tmpPath = path.Substring( 1 );
750 foundComponent = true;
751 prependColon = true;
752 isColonSeparator = true;
753 break;
754  
755  
756 default:
757  
758 tmpPath = path;
759 appendColon = true;
760 prependColon = true;
761 isColonSeparator = true;
762 break;
763  
764 }
765 break;
766  
767  
768 default:
769  
770 if ( path[0] == '/' )
771 {
772 componentObj = TclString.newInstance( "/" );
773 TclList.append( interp, resultListObj, componentObj );
774 tmpPath = path.Substring( 1 );
775 foundComponent = true;
776 }
777 else
778 {
779 tmpPath = path;
780 }
781 break;
782  
783 }
784  
785 // Iterate over all of the components of the path.
786  
787 int sIndex = 0;
788 while ( sIndex != -1 )
789 {
790 if ( isColonSeparator )
791 {
792 sIndex = tmpPath.IndexOf( ":" );
793 // process adjacent ':'
794  
795 if ( sIndex == 0 )
796 {
797 componentObj = TclString.newInstance( "::" );
798 TclList.append( interp, resultListObj, componentObj );
799 foundComponent = true;
800 tmpPath = tmpPath.Substring( sIndex + 1 );
801 continue;
802 }
803 }
804 else
805 {
806 sIndex = tmpPath.IndexOf( "/" );
807 // Ignore a redundant '/'
808  
809 if ( sIndex == 0 )
810 {
811 tmpPath = tmpPath.Substring( sIndex + 1 );
812 continue;
813 }
814 }
815 if ( sIndex == -1 )
816 {
817 // Processing the last component. If it is empty, exit loop.
818  
819 if ( tmpPath.Length == 0 )
820 {
821 break;
822 }
823 component = tmpPath;
824 }
825 else
826 {
827 component = tmpPath.Substring( 0, ( sIndex ) - ( 0 ) );
828 }
829  
830 if ( convertDotToColon && ( component.Equals( "." ) || component.Equals( ".." ) ) )
831 {
832 // If platform = MAC, convert .. to :: or . to :
833  
834 component = component.Replace( '.', ':' );
835 }
836 if ( foundComponent )
837 {
838 if ( component[0] == '~' )
839 {
840 // If a '~' preceeds a component (other than the 1st one), then
841 // prepend "./" or ":" to the component.
842  
843 component = thisDir + component;
844 }
845 else if ( prependColon )
846 {
847 // If the prependColon flag is set, either unset it or prepend
848 // ":" to the component, depending on whether any '/'s remain
849 // in tmpPath.
850  
851 if ( tmpPath.IndexOf( (System.Char)'/' ) == -1 )
852 {
853 prependColon = false;
854 }
855 else
856 {
857 component = ":" + component;
858 }
859 }
860 }
861 else if ( appendColon )
862 {
863 //If platform = MAC, append a ':' to the first component.
864  
865 component = component + ":";
866 }
867 componentObj = TclString.newInstance( component );
868 TclList.append( interp, resultListObj, componentObj );
869 foundComponent = true;
870 tmpPath = tmpPath.Substring( sIndex + 1 );
871 }
872 return resultListObj;
873 }
874 internal static string doTildeSubst( Interp interp, string user )
875 {
876 string dir;
877  
878 if ( user.Length == 0 )
879 {
880 try
881 {
882  
883 dir = interp.getVar( "env", "HOME", TCL.VarFlag.GLOBAL_ONLY ).ToString();
884 }
885 catch ( System.Exception e )
886 {
887 throw new TclException( interp, "couldn't find HOME environment variable to expand path" );
888 }
889 return dir;
890 }
891  
892 // WARNING: Java does not support other users. "dir" is always null,
893 // but it should be the home directory (corresponding to the user name), as
894 // specified in the password file.
895  
896 dir = null;
897 if ( (System.Object)dir == null )
898 {
899 throw new TclException( interp, "user \"" + user + "\" doesn't exist" );
900 }
901 return dir;
902 }
903 public static string translateFileName( Interp interp, string path )
904 {
905 string fileName = "";
906  
907 if ( ( path.Length == 0 ) || ( path[0] != '~' ) )
908 {
909 // fileName = path;
910 TclObject[] joinArrayObj = new TclObject[1];
911 joinArrayObj[0] = TclString.newInstance( path );
912 fileName = joinPath( interp, joinArrayObj, 0, 1 );
913 }
914 else
915 {
916 TclObject[] splitArrayObj = TclList.getElements( interp, splitPath( interp, path ) );
917  
918  
919 string user = splitArrayObj[0].ToString().Substring( 1 );
920  
921  
922 // Strip the trailing ':' off of a Mac path
923 // before passing the user name to DoTildeSubst.
924  
925 if ( ( JACL.PLATFORM == JACL.PLATFORM_MAC ) && ( user.EndsWith( ":" ) ) )
926 {
927 user = user.Substring( 0, ( user.Length - 1 ) - ( 0 ) );
928 }
929  
930 user = doTildeSubst( interp, user );
931  
932 // if (splitArrayObj.length < 2) {
933 // fileName = user;
934 // } else {
935 splitArrayObj[0] = TclString.newInstance( user );
936 fileName = joinPath( interp, splitArrayObj, 0, splitArrayObj.Length );
937 // }
938 }
939  
940  
941 // Convert forward slashes to backslashes in Windows paths because
942 // some system interfaces don't accept forward slashes.
943  
944 if ( JACL.PLATFORM == JACL.PLATFORM_WINDOWS )
945 {
946 fileName = fileName.Replace( '/', '\\' );
947 }
948 return fileName;
949 }
950 internal static TclObject splitAndTranslate( Interp interp, string path )
951 {
952 TclObject splitResult = splitPath( interp, path );
953  
954 int len = TclList.getLength( interp, splitResult );
955 if ( len == 1 )
956 {
957  
958 string fileName = TclList.index( interp, splitResult, 0 ).ToString();
959 if ( fileName[0] == '~' )
960 {
961 string user = translateFileName( interp, fileName );
962 splitResult = splitPath( interp, user );
963 }
964 }
965 return splitResult;
966 }
967 } // end FileUtil class
968 }