@@ -286,7 +286,49 @@ mp_obj_t mp_vfs_getcwd(void) {
286286}
287287MP_DEFINE_CONST_FUN_OBJ_0 (mp_vfs_getcwd_obj , mp_vfs_getcwd );
288288
289- mp_obj_t mp_vfs_listdir (size_t n_args , const mp_obj_t * args ) {
289+ typedef struct _mp_vfs_ilistdir_it_t {
290+ mp_obj_base_t base ;
291+ mp_fun_1_t iternext ;
292+ union {
293+ mp_vfs_mount_t * vfs ;
294+ mp_obj_t iter ;
295+ } cur ;
296+ bool is_str ;
297+ bool is_iter ;
298+ } mp_vfs_ilistdir_it_t ;
299+
300+ STATIC mp_obj_t mp_vfs_ilistdir_it_iternext (mp_obj_t self_in ) {
301+ mp_vfs_ilistdir_it_t * self = MP_OBJ_TO_PTR (self_in );
302+ if (self -> is_iter ) {
303+ // continue delegating to root dir
304+ return mp_iternext (self -> cur .iter );
305+ } else if (self -> cur .vfs == NULL ) {
306+ // finished iterating mount points and no root dir is mounted
307+ return MP_OBJ_STOP_ITERATION ;
308+ } else {
309+ // continue iterating mount points
310+ mp_vfs_mount_t * vfs = self -> cur .vfs ;
311+ self -> cur .vfs = vfs -> next ;
312+ if (vfs -> len == 1 ) {
313+ // vfs is mounted at root dir, delegate to it
314+ mp_obj_t root = mp_obj_new_str ("/" , 1 , false);
315+ self -> is_iter = true;
316+ self -> cur .iter = mp_vfs_proxy_call (vfs , MP_QSTR_ilistdir , 1 , & root );
317+ return mp_iternext (self -> cur .iter );
318+ } else {
319+ // a mounted directory
320+ mp_obj_tuple_t * t = MP_OBJ_TO_PTR (mp_obj_new_tuple (3 , NULL ));
321+ t -> items [0 ] = mp_obj_new_str_of_type (
322+ self -> is_str ? & mp_type_str : & mp_type_bytes ,
323+ (const byte * )vfs -> str + 1 , vfs -> len - 1 );
324+ t -> items [1 ] = MP_OBJ_NEW_SMALL_INT (MP_S_IFDIR );
325+ t -> items [2 ] = MP_OBJ_NEW_SMALL_INT (0 ); // no inode number
326+ return MP_OBJ_FROM_PTR (t );
327+ }
328+ }
329+ }
330+
331+ mp_obj_t mp_vfs_ilistdir (size_t n_args , const mp_obj_t * args ) {
290332 mp_obj_t path_in ;
291333 if (n_args == 1 ) {
292334 path_in = args [0 ];
@@ -299,22 +341,29 @@ mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) {
299341
300342 if (vfs == MP_VFS_ROOT ) {
301343 // list the root directory
302- mp_obj_t dir_list = mp_obj_new_list (0 , NULL );
303- for (vfs = MP_STATE_VM (vfs_mount_table ); vfs != NULL ; vfs = vfs -> next ) {
304- if (vfs -> len == 1 ) {
305- // vfs is mounted at root dir, delegate to it
306- mp_obj_t root = mp_obj_new_str ("/" , 1 , false);
307- mp_obj_t dir_list2 = mp_vfs_proxy_call (vfs , MP_QSTR_listdir , 1 , & root );
308- dir_list = mp_binary_op (MP_BINARY_OP_ADD , dir_list , dir_list2 );
309- } else {
310- mp_obj_list_append (dir_list , mp_obj_new_str_of_type (mp_obj_get_type (path_in ),
311- (const byte * )vfs -> str + 1 , vfs -> len - 1 ));
312- }
313- }
314- return dir_list ;
344+ mp_vfs_ilistdir_it_t * iter = m_new_obj (mp_vfs_ilistdir_it_t );
345+ iter -> base .type = & mp_type_polymorph_iter ;
346+ iter -> iternext = mp_vfs_ilistdir_it_iternext ;
347+ iter -> cur .vfs = MP_STATE_VM (vfs_mount_table );
348+ iter -> is_str = mp_obj_get_type (path_in ) == & mp_type_str ;
349+ iter -> is_iter = false;
350+ return MP_OBJ_FROM_PTR (iter );
315351 }
316352
317- return mp_vfs_proxy_call (vfs , MP_QSTR_listdir , 1 , & path_out );
353+ return mp_vfs_proxy_call (vfs , MP_QSTR_ilistdir , 1 , & path_out );
354+ }
355+ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (mp_vfs_ilistdir_obj , 0 , 1 , mp_vfs_ilistdir );
356+
357+ mp_obj_t mp_vfs_listdir (size_t n_args , const mp_obj_t * args ) {
358+ mp_obj_t iter = mp_vfs_ilistdir (n_args , args );
359+ mp_obj_t dir_list = mp_obj_new_list (0 , NULL );
360+ mp_obj_t next ;
361+ while ((next = mp_iternext (iter )) != MP_OBJ_STOP_ITERATION ) {
362+ mp_obj_t * items ;
363+ mp_obj_get_array_fixed_n (next , 3 , & items );
364+ mp_obj_list_append (dir_list , items [0 ]);
365+ }
366+ return dir_list ;
318367}
319368MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (mp_vfs_listdir_obj , 0 , 1 , mp_vfs_listdir );
320369
0 commit comments