@@ -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)
@@ -646,6 +664,9 @@ void initializeEnvironment() {
646664 }
647665 }
648666 }
667+ if ([argumentString hasPrefix: @" ../" ] || [argumentString hasPrefix: @" ./.." ] || [argumentString isEqualToString: @" .." ]) {
668+ argumentString = pathJoin (@(currentSession->currentDir ), argumentString);
669+ }
649670 if (strcmp (command, " export" ) == 0 ) {
650671 argumentString = [[variableName stringByAppendingString: @" =" ] stringByAppendingString: argumentString];
651672 }
@@ -801,6 +822,7 @@ void __cd_to_dir(NSString *newDir, NSFileManager *fileManager) {
801822
802823 if (__allowed_cd_to_path (resultDir)) {
803824 strcpy (currentSession->previousDirectory , currentSession->currentDir );
825+ strcpy (currentSession->currentDir , [newDir UTF8String ]);
804826 return ;
805827 }
806828
@@ -907,29 +929,32 @@ int command_not_found(int argc, char** argv) {
907929}
908930
909931extern void newPreviousDirectory (void );
932+
910933int cd_main (int argc, char ** argv) {
911934 if (currentSession == NULL ) {
912935 return 1 ;
913936 }
914937 NSFileManager *fileManager = [[NSFileManager alloc ] init ];
915-
938+
916939 if (argc > 1 ) {
917940 NSString * newDir = @(argv[1 ]);
918941 if (strcmp (argv[1 ], " -" ) == 0 ) {
919942 // "cd -" option to pop back to previous directory
920- newDir = [ NSString stringWithCString: currentSession->previousDirectory encoding: NSUTF8StringEncoding] ;
943+ newDir = @( currentSession->previousDirectory ) ;
921944 }
945+ newDir = pathJoin (@(currentSession->currentDir ), newDir);
922946 __cd_to_dir (newDir, fileManager);
923947 } else { // [cd] Help, I'm lost, bring me back home
924- strcpy (currentSession->previousDirectory , [[fileManager currentDirectoryPath ] UTF8String ]);
925-
926948 if (miniRoot != nil ) {
927949 [fileManager changeCurrentDirectoryPath: miniRoot];
928950 } else {
929951 [fileManager changeCurrentDirectoryPath: [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES ) lastObject ]];
930952 }
953+
954+ strcpy (currentSession->previousDirectory , currentSession->currentDir );
955+ strcpy (currentSession->currentDir , fileManager.currentDirectoryPath .UTF8String );
931956 }
932- strcpy (currentSession-> currentDir , [[fileManager currentDirectoryPath ] UTF8String ]);
957+
933958 newPreviousDirectory (); // If a command is running, this changes the directory it goes back to.
934959 return 0 ;
935960}
@@ -2840,3 +2865,65 @@ int ios_system(const char* inputCmd) {
28402865 fflush (thread_stderr);
28412866 return currentSession->global_errno ;
28422867}
2868+
2869+ NSArray <NSString *> * pathNormalizeArray (NSArray <NSString *> * parts, BOOL allowAboveRoot) {
2870+ NSMutableArray <NSString *> * res = [[NSMutableArray alloc ] init ];
2871+ for (NSString * p in parts) {
2872+ // ignore empty parts
2873+ if (p.length == 0 || [p isEqualToString: @" ." ] || [p isEqualToString: @" /" ]) {
2874+ continue ;
2875+ }
2876+
2877+ if ([p isEqualToString: @" .." ]) {
2878+ if (res.count && ![@" .." isEqualToString: [res lastObject ]]) {
2879+ [res removeLastObject ];
2880+ } else if (allowAboveRoot) {
2881+ [res addObject: p];
2882+ }
2883+ } else {
2884+ [res addObject: p];
2885+ }
2886+ }
2887+
2888+ return res;
2889+ }
2890+
2891+ NSString * pathNormalize (NSString *path) {
2892+ BOOL isAbsolute = [path hasPrefix: @" /" ];
2893+ BOOL trailingSlash = [path hasSuffix: @" /" ];
2894+
2895+ NSString * result = [pathNormalizeArray ([path pathComponents ], !isAbsolute) componentsJoinedByString: @" /" ];
2896+
2897+ if (!result.length && !isAbsolute) {
2898+ result = @" ." ;
2899+ }
2900+
2901+ if (result.length && trailingSlash) {
2902+ result = [result stringByAppendingString: @" /" ];
2903+ }
2904+
2905+ return [(isAbsolute ? @" /" : @" " ) stringByAppendingString: result];
2906+ }
2907+
2908+
2909+ NSString * pathJoin (NSString * segmentA, NSString * segmentB) {
2910+ NSMutableString *path = [[NSMutableString alloc ] init ];
2911+ NSString * a = segmentA ?: @" " ;
2912+ NSString * b = segmentB ?: @" " ;
2913+
2914+ if ([b hasPrefix: @" /" ]) {
2915+ return pathNormalize (b);
2916+ }
2917+
2918+ if (a.length ) {
2919+ [path appendString: a];
2920+ if (b.length ) {
2921+ [path appendString: @" /" ];
2922+ [path appendString: b];
2923+ }
2924+ } else if (b.length ) {
2925+ [path appendString: b];
2926+ }
2927+
2928+ return pathNormalize (path);
2929+ }
0 commit comments