11#include <string.h>
22#include "file_browser.h"
3+ #include "sv.h"
34
45static int file_cmp (const void * ap , const void * bp )
56{
@@ -25,6 +26,76 @@ Errno fb_open_dir(File_Browser *fb, const char *dir_path)
2526 return 0 ;
2627}
2728
29+ #define PATH_SEP "/"
30+ #define PATH_EMPTY ""
31+ #define PATH_DOT "."
32+ #define PATH_DOTDOT ".."
33+
34+ typedef struct {
35+ String_View * items ;
36+ size_t count ;
37+ size_t capacity ;
38+ } Comps ;
39+
40+ void normpath (String_View path , String_Builder * result )
41+ {
42+ size_t original_sb_size = result -> count ;
43+
44+ if (path .count == 0 ) {
45+ sb_append_cstr (result , PATH_DOT );
46+ return ;
47+ }
48+
49+ int initial_slashes = 0 ;
50+ while (path .count > 0 && * path .data == * PATH_SEP ) {
51+ initial_slashes += 1 ;
52+ sv_chop_left (& path , 1 );
53+ }
54+ if (initial_slashes > 2 ) {
55+ initial_slashes = 1 ;
56+ }
57+
58+ Comps new_comps = {0 };
59+
60+ while (path .count > 0 ) {
61+ String_View comp = sv_chop_by_delim (& path , '/' );
62+ if (comp .count == 0 || sv_eq (comp , SV (PATH_DOT ))) {
63+ continue ;
64+ }
65+ if (!sv_eq (comp , SV (PATH_DOTDOT ))) {
66+ da_append (& new_comps , comp );
67+ continue ;
68+ }
69+ if (initial_slashes == 0 && new_comps .count == 0 ) {
70+ da_append (& new_comps , comp );
71+ continue ;
72+ }
73+ if (new_comps .count > 0 && sv_eq (da_last (& new_comps ), SV (PATH_DOTDOT ))) {
74+ da_append (& new_comps , comp );
75+ continue ;
76+ }
77+ if (new_comps .count > 0 ) {
78+ new_comps .count -= 1 ;
79+ continue ;
80+ }
81+ }
82+
83+ for (int i = 0 ; i < initial_slashes ; ++ i ) {
84+ sb_append_cstr (result , PATH_SEP );
85+ }
86+
87+ for (size_t i = 0 ; i < new_comps .count ; ++ i ) {
88+ if (i > 0 ) sb_append_cstr (result , PATH_SEP );
89+ sb_append_buf (result , new_comps .items [i ].data , new_comps .items [i ].count );
90+ }
91+
92+ if (original_sb_size == result -> count ) {
93+ sb_append_cstr (result , PATH_DOT );
94+ }
95+
96+ free (new_comps .items );
97+ }
98+
2899Errno fb_change_dir (File_Browser * fb )
29100{
30101 assert (fb -> dir_path .count > 0 && "You need to call fb_open_dir() before fb_change_dir()" );
@@ -36,11 +107,17 @@ Errno fb_change_dir(File_Browser *fb)
36107
37108 fb -> dir_path .count -= 1 ;
38109
39- // TODO: fb_change_dir() does not support .. and . properly
110+ // TODO: fb->dir_path grows indefinitely if we hit the root
40111 sb_append_cstr (& fb -> dir_path , "/" );
41112 sb_append_cstr (& fb -> dir_path , dir_name );
113+
114+ String_Builder result = {0 };
115+ normpath (sb_to_sv (fb -> dir_path ), & result );
116+ da_move (& fb -> dir_path , result );
42117 sb_append_null (& fb -> dir_path );
43118
119+ printf ("Changed dir to %s\n" , fb -> dir_path .items );
120+
44121 fb -> files .count = 0 ;
45122 fb -> cursor = 0 ;
46123 Errno err = read_entire_dir (fb -> dir_path .items , & fb -> files );
0 commit comments