unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* [PATCH] Add "scandir" procedure
@ 2011-08-27 20:05 nalaginrut
  2011-08-30 16:06 ` Ludovic Courtès
  2011-12-18 20:30 ` Ludovic Courtès
  0 siblings, 2 replies; 22+ messages in thread
From: nalaginrut @ 2011-08-27 20:05 UTC (permalink / raw)
  To: guile-devel

Hi guys!
I found there isn't "scandir" in current Guile. And we may use "ftw" to
instead. I guess "ftw" traverse all sub-directoies. Yes, we may use nftw
to filter the level we don't need, but "ftw" seems always traverse all
sub-directories. If my guess is correct, I believe it's too slow for
someone, for a instance, me. :-)
But the efficiency is not the case.
The reason is that when I was trying to write a web server ,I need to
print directory content in HTML back to the client. And I found "ftw"
won't return "." and "..", moreover ,the result isn't sorted.
And I think "scandir" which provided by POSIX is a better solution. Many
dynamic language like PHP own a "scandir" implementation. I believe
Guile should have one. So I wrote an implementation into filesys.c.

There's a little difference of usage between C and Guile version. But
it's trivial if you're familiar with the C version.

The usage is like this:
-------------------------------
scandir dir [filter [sort]]
-------------------------------

"dir" must be a string which owned by a directory. You may run with one
arg directly:
------------------
(scandir "mmr")
==>("." ".." "a" "b" "c" "dd" "dir1" "dir2")
------------------

As you see, it returned a list contained all contents of directory
"mmr". So, you can do whatever you like with a list.

And you may use filter:
------------------------
(scandir "mmr"
   (lambda (fname)
       (if (string-contains fname "dir")
             #f
             #t)))
==> ("." ".." "a" "b" "c" "dd")
------------------------
It's easy to filter the file you want. Return #f will skip current file,
#t will add it to the result list.

And the third arg "sort" has only two possibility: 
'asort stands for alphasort
or
'vsort stands for versionsort
Call "scandir" with "sort" unspecified you'll get 'asort in default. If
you can't understand that, you may checkout the C version manual: 
----------------
man 3 scandir
----------------

Besides, there's a clumsy documentation in the REPL:
-------------
,d scandir
-------------

PS: There must be some bugs in this implementation, like portable
problem. I believe I didn't add some critical macro in it. But I think
there're lots of people know more than me in the mail-list. So I submit
it, and waiting for any advices or patches of patch. :-)
Anyway, I've tested it. It's function complete. Use it as you like!

My patch will be submitted in the next mail, I found some guy(like me)
doesn't like to open an attachment of obscure origin. ;-)


-- 
GNU Powered it
GPL Protected it
GOD Blessed it

HFG - NalaGinrut

--hacker key--
v4sw7CUSMhw6ln6pr8OSFck4ma9u8MLSOFw3WDXGm7g/l8Li6e7t4TNGSb8AGORTDLMen6g6RASZOGCHPa28s1MIr4p-x hackerkey.com
---end key---




^ permalink raw reply	[flat|nested] 22+ messages in thread
* Re: [PATCH] Add "scandir" procedure
@ 2011-08-27 20:18 Nala Ginrut
  0 siblings, 0 replies; 22+ messages in thread
From: Nala Ginrut @ 2011-08-27 20:18 UTC (permalink / raw)
  To: guile-devel

From a79c0db1ef1a932443e41ba6185b0d8c1a5774ed Mon Sep 17 00:00:00 2001
From: Nala Ginrut <NalaGinrut@gmail.com>
Date: Sun, 28 Aug 2011 03:19:15 +0800
Subject: [PATCH] Add scandir procedure

---
 libguile/_scm.h    |    3 ++
 libguile/filesys.c |   98 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 101 insertions(+), 0 deletions(-)

diff --git a/libguile/_scm.h b/libguile/_scm.h
index 48fb2cc..cd3f82c 100644
--- a/libguile/_scm.h
+++ b/libguile/_scm.h
@@ -166,6 +166,9 @@
 #define off_t_or_off64_t                CHOOSE_LARGEFILE(off_t,off64_t)
 #define open_or_open64                  CHOOSE_LARGEFILE(open,open64)
 #define readdir_or_readdir64            CHOOSE_LARGEFILE(readdir,readdir64)
+#define scandir_or_scandir64		CHOOSE_LARGEFILE(scandir,scandir64)
+#define alphasort_or_alphasort64	CHOOSE_LARGEFILE(alphasort,alphasort64)
+#define versionsort_or_versionsort64	CHOOSE_LARGEFILE(versionsort,versionsort64)
 #if SCM_HAVE_READDIR64_R == 1
 # define readdir_r_or_readdir64_r       CHOOSE_LARGEFILE(readdir_r,readdir64_r)
 #else
diff --git a/libguile/filesys.c b/libguile/filesys.c
index f600328..d4bf2f4 100644
--- a/libguile/filesys.c
+++ b/libguile/filesys.c
@@ -1670,6 +1670,104 @@ SCM_DEFINE (scm_opendir, "opendir", 1, 0, 0,
 }
 #undef FUNC_NAME
 
+SCM_DEFINE (scm_scandir, "scandir", 1, 2, 0,
+	    (SCM dir, SCM filter, SCM sort),
+	    "Return a list which contains all files and directories' name of the "
+	    "@var{dir}. The @var{sort} is the sort method of the result.\n"
+	    "The second arg @var{filter} is a proc with 2 args and return #t "
+	    "for keeping this result, and vice versa.\n"
+	    "If @var{sort} is unspecified, @code{alplasort} would be default.\n"
+	    "The optional @var{sort} must be symbol and could be:"
+	    "@defvar{asort} ==> for alphasort\n"
+	    "@defvar{vsort} ==> for versionsort")
+#define FUNC_NAME s_scm_scandir
+{
+  struct dirent_or_dirent64 **rdent;
+  int sort_type = 0;
+  int has_filter = 0;
+  int n = 0 ,i = 0;
+  SCM flag;
+  SCM ret = SCM_EOL;
+  SCM *prev;
+  SCM str;
+
+  SCM_VALIDATE_STRING (1, dir);
+
+  if (!SCM_UNBNDP (filter))
+    {
+      SCM_ASSERT (scm_is_true (scm_procedure_p (filter)),
+		  filter ,SCM_ARG2 ,FUNC_NAME);
+      has_filter = 1;
+    }
+  
+  if (!SCM_UNBNDP (sort))
+    {
+      SCM_ASSERT (scm_symbol_p(sort) ,sort ,SCM_ARG3 ,FUNC_NAME);
+      
+      if (scm_is_true (scm_eq_p (sort, scm_from_latin1_symbol ("asort"))))
+	sort_type = 0;	
+      else if (scm_is_true (scm_eq_p (sort, scm_from_latin1_symbol ("vsort"))))
+	sort_type = 1;
+      else
+	scm_error (scm_from_latin1_symbol ("invalid-sort-type"),
+		   "scandir", "Scandir got an invalid sort type: ~S",
+		   scm_list_1 (sort), scm_list_1 (sort));
+    }
+
+  scm_dynwind_begin (0);
+  errno = 0;
+
+  switch (sort_type)
+    {	
+    case 0: 
+      SCM_SYSCALL(n = scandir_or_scandir64 (scm_to_locale_string (dir), 
+					    &rdent, NULL, alphasort_or_alphasort64));
+      break;
+    case 1:
+      SCM_SYSCALL(n = scandir_or_scandir64 (scm_to_locale_string (dir), 
+					    &rdent, NULL, versionsort_or_versionsort64))	;
+      break;
+    default:
+      SCM_SYSERROR;
+    }
+
+  if (has_filter)
+    {
+      for (prev = &ret;i<n;i++)
+	{
+	  str = rdent[i]? scm_from_locale_stringn (rdent[i]->d_name ,NAMLEN (rdent[i])) : SCM_EOF_VAL;
+	  flag = scm_call_1 (filter ,str);
+	  free (rdent[i]);
+
+	  if (scm_is_true (flag))
+	    {
+	      *prev = scm_cons (str ,SCM_EOL);
+	      prev = SCM_CDRLOC (*prev);
+	    }
+	  
+	}
+    }
+  else
+    {
+      for (prev = &ret;i<n;i++)
+	{
+	  str = rdent[i]? scm_from_locale_stringn (rdent[i]->d_name ,NAMLEN (rdent[i])) : SCM_EOF_VAL;
+	  *prev = scm_cons (str ,SCM_EOL);
+	  prev = SCM_CDRLOC (*prev);
+	  free (rdent[i]);
+	}
+    }
+
+  if (errno != 0)
+    SCM_SYSERROR;
+
+  scm_dynwind_end ();
+
+  free (rdent);
+  
+  return ret;
+}
+#undef FUNC_NAME
 
 /* FIXME: The glibc manual has a portability note that readdir_r may not
    null-terminate its return string.  The circumstances outlined for this
-- 
1.7.0.4




^ permalink raw reply related	[flat|nested] 22+ messages in thread
* Re: [PATCH] Add "scandir" procedure
@ 2011-09-02  1:00 Nala Ginrut
  0 siblings, 0 replies; 22+ messages in thread
From: Nala Ginrut @ 2011-09-02  1:00 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 1618 bytes --]

On Fri, Sep 2, 2011 at 5:01 AM, Ludovic Courtès <ludo@gnu.org> wrote:

> Hi,
>
> Nala Ginrut <nalaginrut@gmail.com> skribis:
>
> > I don't mean 6 args is  improper. But maybe some guys just want an easy
> > thing, and maybe Guile newbies need a easy start with 'scandir'.
>
> Oh, I just meant to say you could build ‘scandir’ (and others) atop
> ‘file-system-fold’.
>
> The scandir(3) C function is really meant to be a higher-order function
> but its interface is awkward and mixes different concerns (traversal and
> filtering.)  Using something akin to the ‘directory-contents’ procedure
> I posted earlier, one could then use SRFI-1 to do actual filtering.
>
> > 'scandir' is a POSIX function, so many people will think it exists in
> Guile.
> > We have 'opendir' and 'readdir', but no 'scandir', that's strange.
>
> Yes, you’re right.  However, I feel that we can come up with something
> both simpler and more expressive, as sketched above.
>

yeah~I realized that the idea about a bunch of  gorgeous high-order
functions around one base function 'file-system-fold' is more creative and
flexible. It becomes happier to add new features into Guile than wrap a C
function. Anyway, C is more painful. ;-)
So, have you already implemented others like 'directory-content' instead of
'scandir' ? Or should we submit some patches for it?
What about the sort method? And I hope it won't dismiss "." and ".." in the
result.
Let me retell my need, I need the function returns a sorted list which
contained "." and "..". Is it easy to implement it with 'file-system-fold'?

[-- Attachment #2: Type: text/html, Size: 2504 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2012-01-08 15:22 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-08-27 20:05 [PATCH] Add "scandir" procedure nalaginrut
2011-08-30 16:06 ` Ludovic Courtès
2011-09-01  4:46   ` Nala Ginrut
2011-09-01 12:12     ` Ludovic Courtès
2011-09-01 16:05       ` Nala Ginrut
2011-09-01 21:01         ` Ludovic Courtès
     [not found]           ` <CAPjoZof=iV57JP4-HgFjGTbMnaa9ex_QfP17Mn12j3XE3GxPSA@mail.gmail.com>
     [not found]             ` <8739gfuxky.fsf@gnu.org>
2011-09-02 11:38               ` Nala Ginrut
2011-09-02 12:14                 ` Ludovic Courtès
2011-12-06 11:52   ` Andy Wingo
2011-12-10 14:52     ` Ludovic Courtès
2011-12-10 15:37       ` Andy Wingo
2011-12-10 19:05         ` Ludovic Courtès
2011-12-14  0:21         ` Ludovic Courtès
2012-01-08 15:22           ` Ludovic Courtès
2011-12-18 20:30 ` Ludovic Courtès
2011-12-19 19:20   ` Nala Ginrut
2011-12-19 21:38     ` Ludovic Courtès
2011-12-20  3:23       ` Nala Ginrut
2011-12-20  3:25         ` Nala Ginrut
2011-12-20 12:03           ` Ludovic Courtès
  -- strict thread matches above, loose matches on Subject: below --
2011-08-27 20:18 Nala Ginrut
2011-09-02  1:00 Nala Ginrut

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).