@@ -101,13 +101,14 @@ void ios_setBookmarkDictionaryName(NSString* name) {
101101void ios_printBookmarkedVersion (char * p) {
102102 // p is a directory. See if there is a bookmark that can make it shorter:
103103 NSString * pathString = [NSString stringWithUTF8String: p];
104- if ([pathString hasPrefix: @" /private" ]) {
105- pathString = [pathString stringByReplacingOccurrencesOfString: @" /private" withString: @" " ];
104+ NSString * privatePrefix = @" /private" ;
105+ if ([pathString hasPrefix: privatePrefix]) {
106+ pathString = [pathString substringFromIndex: [privatePrefix length ]];
106107 }
107108 NSString *homePath;
108109 homePath = [[NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES ) lastObject ] stringByDeletingLastPathComponent ];
109- if ([homePath hasPrefix: @" /private " ]) {
110- homePath = [homePath stringByReplacingOccurrencesOfString: @" /private " withString: @" " ];
110+ if ([homePath hasPrefix: privatePrefix ]) {
111+ homePath = [homePath substringFromIndex: [privatePrefix length ] ];
111112 }
112113 NSLog (@" ios_printBookmarkedVersion: %s %s " , homePath.UTF8String , pathString.UTF8String );
113114 if ([pathString hasPrefix: homePath]) {
@@ -126,8 +127,8 @@ void ios_printBookmarkedVersion(char* p) {
126127 }
127128 for (NSString * bookmark in tildeExpansionDictionary) {
128129 NSString * bookmarkPath = tildeExpansionDictionary[bookmark];
129- if ([bookmarkPath hasPrefix: @" /private " ]) {
130- bookmarkPath = [bookmarkPath stringByReplacingOccurrencesOfString: @" /private " withString: @" " ];
130+ if ([bookmarkPath hasPrefix: privatePrefix ]) {
131+ bookmarkPath = [bookmarkPath substringFromIndex: [privatePrefix length ] ];
131132 }
132133 if ([pathString hasPrefix: bookmarkPath]) {
133134 pathString = [pathString stringByReplacingOccurrencesOfString: bookmarkPath withString: bookmark];
@@ -203,6 +204,18 @@ void ios_signal(int signal) {
203204 }
204205}
205206
207+ NSString *ios_getLogicalPWD (const void * sessionId) {
208+ id sessionKey = @((NSUInteger )sessionId);
209+ if (sessionList == nil ) {
210+ return nil ;
211+ }
212+ sessionParameters *session = (sessionParameters*)[[sessionList objectForKey: sessionKey] pointerValue ];
213+ if (session == nil ) {
214+ return nil ;
215+ }
216+ return @(session->currentDir );
217+ }
218+
206219#undef getenv
207220void ios_setWindowSize (int width, int height, const void * sessionId) {
208221 // You can set the window size for a session that is not currently running (e.g. because "sh_session" is running).
@@ -244,6 +257,9 @@ void ios_setWindowSize(int width, int height, const void* sessionId) {
244257 if (strcmp (name, " ROWS" ) == 0 ) {
245258 return currentSession->lines ;
246259 }
260+ if (strcmp (name, " PWD" ) == 0 ) {
261+ return currentSession->currentDir ;
262+ }
247263 return libc_getenv (name);
248264}
249265
@@ -534,6 +550,8 @@ void initializeEnvironment() {
534550 getrlimit (RLIMIT_NOFILE, &limitFilesOpen);
535551}
536552
553+ NSString * pathJoin (NSString * segmentA, NSString * segmentB);
554+
537555static char * parseArgument (char * argument, char * command) {
538556 // expand all environment variables, convert "~" to $HOME (only if localFile)
539557 // we also pass the shell command for some specific behaviour (don't do this for that command)
@@ -641,6 +659,9 @@ void initializeEnvironment() {
641659 }
642660 }
643661 }
662+ if ([argumentString hasPrefix: @" ../" ] || [argumentString hasPrefix: @" ./.." ] || [argumentString isEqualToString: @" .." ]) {
663+ argumentString = pathJoin (@(currentSession->currentDir ), argumentString);
664+ }
644665 if (strcmp (command, " export" ) == 0 ) {
645666 argumentString = [[variableName stringByAppendingString: @" =" ] stringByAppendingString: argumentString];
646667 }
@@ -796,6 +817,7 @@ void __cd_to_dir(NSString *newDir, NSFileManager *fileManager) {
796817
797818 if (__allowed_cd_to_path (resultDir)) {
798819 strcpy (currentSession->previousDirectory , currentSession->currentDir );
820+ strcpy (currentSession->currentDir , [newDir UTF8String ]);
799821 return ;
800822 }
801823
@@ -902,29 +924,33 @@ int command_not_found(int argc, char** argv) {
902924}
903925
904926extern void newPreviousDirectory ();
927+
928+
905929int cd_main (int argc, char ** argv) {
906930 if (currentSession == NULL ) {
907931 return 1 ;
908932 }
909933 NSFileManager *fileManager = [[NSFileManager alloc ] init ];
910-
934+
911935 if (argc > 1 ) {
912936 NSString * newDir = @(argv[1 ]);
913937 if (strcmp (argv[1 ], " -" ) == 0 ) {
914938 // "cd -" option to pop back to previous directory
915- newDir = [ NSString stringWithCString: currentSession->previousDirectory encoding: NSUTF8StringEncoding] ;
939+ newDir = @( currentSession->previousDirectory ) ;
916940 }
941+ newDir = pathJoin (@(currentSession->currentDir ), newDir);
917942 __cd_to_dir (newDir, fileManager);
918943 } else { // [cd] Help, I'm lost, bring me back home
919- strcpy (currentSession->previousDirectory , [[fileManager currentDirectoryPath ] UTF8String ]);
920-
921944 if (miniRoot != nil ) {
922945 [fileManager changeCurrentDirectoryPath: miniRoot];
923946 } else {
924947 [fileManager changeCurrentDirectoryPath: [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES ) lastObject ]];
925948 }
949+
950+ strcpy (currentSession->previousDirectory , currentSession->currentDir );
951+ strcpy (currentSession->currentDir , fileManager.currentDirectoryPath .UTF8String );
926952 }
927- strcpy (currentSession-> currentDir , [[fileManager currentDirectoryPath ] UTF8String ]);
953+
928954 newPreviousDirectory (); // If a command is running, this changes the directory it goes back to.
929955 return 0 ;
930956}
@@ -2835,3 +2861,65 @@ int ios_system(const char* inputCmd) {
28352861 fflush (thread_stderr);
28362862 return currentSession->global_errno ;
28372863}
2864+
2865+ NSArray <NSString *> * pathNormalizeArray (NSArray <NSString *> * parts, BOOL allowAboveRoot) {
2866+ NSMutableArray <NSString *> * res = [[NSMutableArray alloc ] init ];
2867+ for (NSString * p in parts) {
2868+ // ignore empty parts
2869+ if (p.length == 0 || [p isEqualToString: @" ." ] || [p isEqualToString: @" /" ]) {
2870+ continue ;
2871+ }
2872+
2873+ if ([p isEqualToString: @" .." ]) {
2874+ if (res.count && ![@" .." isEqualToString: [res lastObject ]]) {
2875+ [res removeLastObject ];
2876+ } else if (allowAboveRoot) {
2877+ [res addObject: p];
2878+ }
2879+ } else {
2880+ [res addObject: p];
2881+ }
2882+ }
2883+
2884+ return res;
2885+ }
2886+
2887+ NSString * pathNormalize (NSString *path) {
2888+ BOOL isAbsolute = [path hasPrefix: @" /" ];
2889+ BOOL trailingSlash = [path hasSuffix: @" /" ];
2890+
2891+ NSString * result = [pathNormalizeArray ([path pathComponents ], !isAbsolute) componentsJoinedByString: @" /" ];
2892+
2893+ if (!result.length && !isAbsolute) {
2894+ result = @" ." ;
2895+ }
2896+
2897+ if (result.length && trailingSlash) {
2898+ result = [result stringByAppendingString: @" /" ];
2899+ }
2900+
2901+ return [(isAbsolute ? @" /" : @" " ) stringByAppendingString: result];
2902+ }
2903+
2904+
2905+ NSString * pathJoin (NSString * segmentA, NSString * segmentB) {
2906+ NSMutableString *path = [[NSMutableString alloc ] init ];
2907+ NSString * a = segmentA ?: @" " ;
2908+ NSString * b = segmentB ?: @" " ;
2909+
2910+ if ([b hasPrefix: @" /" ]) {
2911+ return pathNormalize (b);
2912+ }
2913+
2914+ if (a.length ) {
2915+ [path appendString: a];
2916+ if (b.length ) {
2917+ [path appendString: @" /" ];
2918+ [path appendString: b];
2919+ }
2920+ } else if (b.length ) {
2921+ [path appendString: b];
2922+ }
2923+
2924+ return pathNormalize (path);
2925+ }
0 commit comments