このパッケージはGPLにしたがって公開します。ディスク上のエントリを検索する場合に、SLIBを使用できるScheme処理系であれば動作するように書いたつもりです。
Schemeは抽象性が高く、システムインタフェースがあまり用意されていません。call-with-input-fileやopen-input-fileのような使い易い、しかも強力な入出力手続きは用意されていますが、それがどのように働くかの実装は処理系に任されています。システムインタフェースの仕様が定義されていないために、システムインタフェース手続きが処理系ごとに微妙に異なる結果となっています。標準の入出力手続きも、一度に処理できるのはひとつのファイルだけです。
そこで、unixや類似のシステムではlsコマンドを、WindowsとOS/2の場合はdirコマンドを呼び出すシステムコールを使用して、ファイル名操作を行なうこととしました。Windowsでsystem手続きからdirコマンドを呼び出した場合、長い、あるいはスペースを含むファイル名が返されません。SCMであれば長いファイル名とスペースを含むファイル名を返すことができますので、SCMについては固有のコードを入れています。
コマンドの実行結果はパイプ経由で、パイプを利用できない処理系の場合は一時ファイル経由でSchemeに取り込んでいます。
犬飼 大 (inukai.d@jeans.ocn.ne.jp)
Schemeの内部からlsコマンドやdirを実行するためには、処理系がsystem手続きを実装している必要があります。例えばOS/2用のmit-schemeにはsystem手続きが実装されておらず、このパッケージを実行することができません。
パイプ機能を実装していない処理系については、一時ファイル経由でコマンドの実行結果を取り込み、その後delete-file手続きで一時ファイルを削除しています。delete-fileが実装されていない場合は、この手続きを(system "rm TEMPORARY-FILE")か(system "del (あるいはdelete) TEMPORARY-FILE")で置き換える必要があります。
現行ディレクトリの取り込みにはgetcwd(mit-schemeではpwd)を使用していますので、この手続きも実装されている必要があります。
それ以外のコードについてはr5rs準拠と思います。
このパッケージは、SLIBライブラリのstring-search、line-i/o、common-list-functions、globを使用しています。処理-系はSLIBを利用できるように初期化しておく必要があります。SLIBを利用できない場合は、"strsrch.scm"、"lineio.scm"などをあらかじめ個別にロードしなければなりません。
ファイル"direntry.scm"内の手続きは、FreeBSD Release 4.2上ではscm5d4、STk-4.0.1、guile-1.4で、Linux (kernel 2.2r1)上ではscm5d4、STk-4.0.1、guile-1.4で、OS/2、Windows 98、Windows 2000ではscm5d4でテストしました。
論理型引数vector-output?はオプションです。手続きは、オープンした入力ポートを1つ引数にとる手続きを返します。返された手続きは渡された入力ポートから行を読み取って、引数が省略されているか引数vector-output?に#fが指定されている場合はそれをリストにして、#tが指定されている場合はそれをベクタにして返します。
例えばinportが次のテキストが入っているファイルに連結されているとします。
aaa bbb ccc ddd
手続きは入力ポートを読み取って次の結果を返します。
((port->string-list) inport) => ("aaa" "bbb" "ccc ddd")
((port->string-list #t) inport) => #("aaa" "bbb" "ccc ddd")
文字集合引数charsetはオプションです。この述語手続きは、引数 charが文字集合引数charsetに含まれる場合は#tを、含まれない場合は#fを返します。文字集合が引数に与えられなかった場合の文字集合は、char-whitespace?が#tを返すものです。
(char-in-set? #\space) => #t (char-in-set? #\newline) => #t (char-in-set? #\newline #\space) => #f (char-in-set? #\, #\space #\,) => #t
文字集合引数delimitersはオプションで、引数の意味はchar-in-set?とstring-last-splitの場合と同じです。手続きは文字列引数entryを
文字集合引数delimitersに含まれる文字で切り離した部分文字列に分解し、部分文字列をリストにして返します。
(decompose-string "This is a sample string.")
=> ("This" "is" "a" "sample" "string.")
(decompose-string "One, two, three and four are integers."
#\space #\,)
=> ("One" "two" "three" "and" "four" "are" "integers.")
(decompose-string "One, two, three and four are integers."
#\space #\, #\.)
=> ("One" "two" "three" "and" "four" "are" "integers")
手続きは、引数string-listに与えられた文字列に、引数delimitersに指定された文字を追加して、引数string-listに与えられた文字列を連結して返します。論理値引数prepend?は、文字列を連結するときに、区切り文字を連結する文字列の前に追加するか後ろに追加するかを制御します。
引数delimitersはオプションで、省略された場合は#\spaceに設定されます。手続きrecompose-stringは手続きdecompose-stringの逆ではありません。recompose-stringの引数delimitersには、引数string-list内の文字列引数と同じ順序で、追加する区切り文字を指定します。delimitersの数がstring-listの要素数よりも多い場合、delimitersはstring-listの要素数まで切り詰められます。delimitersの数がstring-listの要素数に満たない場合は、string-listの要素数までdelimitersの最後の要素がdelimitersに追加されます。
(recompose-string #f '("This" "is" "a" "sample" "string."))
=> "This is a sample string."
(recompose-string #t '("This" "is" "a" "sample" "string."))
=> " This is a sample string."
(recompose-string #f '("This" "is" "a" "sample" "string.") #\,)
=> "This,is,a,sample,string."
(recompose-string #f '("direntry" "scm" "is" "to be" "required.")
#\. #\space)
=> "direntry.scm is to be required."
(recompose-string #f '("A" "test" "string" "") #\space #\- #\.)
=> "A test-string."
(recompose-string #f '("A" "test" "string" " ") #\space #\- #\.)
=> "A test-string. "
引数delimitersはオプションです。手続きは、区切り文字集合delimitersに指定された文字が最後に発生した場所から前の文字列を部分文字列に分解した文字列リストをcarに、最後の区切り文字の後ろの文字列を部分文字列に分解した文字列リストをcdrにもつリストを返します。引数nthには、cdrのリストの要素数を指定します。引数delimitersが省略された場合の区切り文字集合は、手続きchar-whitespace?が#tを返すものです。
(string-last-split "This is a sample string." 1)
=> (("This" "is" "a" "sample") "string.")
(string-last-split "A-little-brown-fox" 1 #\-)
=> ("A" "little" "brown") "fox")
(string-last-split "A-little-brown-fox" 2 #\-)
=> (("A" "little") "brown" "fox")
(string-last-split "1, 2, 3 and 4" 1 #\, #\space)
=> (("1" "2" "3" "and") "4")
(string-last-split "This is a sample string." 0 #\,)
=> (("This is a sample string."))
(string-last-split "This is a sample string." 3 #\,)
=> (() "This is a sample string.")
(string-last-split "This is a sample string." 5 #\,)
=> (() "This is a sample string.")
手続きstring-last-splitが作成したconsリストから文字列リストを新たに作成し、それを返します。
(string-join-split (string-last-split "This is a sample string." 1))
=> ("This" "is" "a" "sample" "string.")
(string-join-split (string-last-split "A-little-brown-fox" 2 #\-))
=> ("A" "little" "brown" "fox")
元の文字列を作成し直したい場合は、手続きrecompose-stringを使用する必要があります。
(recompose-string #f
(string-join-split
(string-last-split "A-little-brown-fox" 2 #\-))
#\-)
=> "A-little-brown-fox"
引数command-stringは有効なシステムコマンドであればいかなる文字列でも構いません。command-stringは手続きsystemに渡されます。引数procには、入力ポートをひとつ引数にとる手続きを指定します。手続きcall-with-input-pipeは引数coomand-stringを使用してsystemコマンドを実行し、パイプをオープンして実行結果をパイプに渡します。パイプのもう一方の端はprocの入力ポートに連結されます。procを実行するとパイプはクローズされます。手続きはprocが返す値を返します。
例えば現在のディレクトリを"direntry"とします。
(load "direntry.scm")
(call-with-input-pipe "ls ."
(lambda (inport)
(do ((l (read-line inport)(read-line inport)))
((eof-object? l))
(write-line l))))
ChangeLog
About
direntry.scm
direntry.texi
=> ;; do式が返す値を返します。
引数name-stringに渡された文字列がディレクトリならば#tを、そうでなければ#fを返します。name-stringに渡された文字列がファイルシステムに存在しない場合にも#fが返されます。
(is-directory? ".") => #t (is-directory? "./direntry") => #t (is-directory? "./direntry/direntry.scm") => #f (is-directory? "/usr/local") => #t
引数name-stringに渡されたディレクトリが空であれば#tを、空でなければ#fを返します。
(directory-empty? "/usr/local") => #f
この手続きはdirectory-containsの下位手続きです。論理値引数directories?には、検索する対象がディレクトリの場合は#tを、それ以外の場合は#fを指定します。dirent:scan-directoryは、引数に文字列をとって文字列に一致するパスを返す手続きを返します。
返される手続きは、search-string、short-specs?、absolute?を引数にとります。short-specs?とabsolute?はオプションで、すべて省略された場合は両方共に#tが指定されます。手続きはunixのlsコマンドかms-dosのdirコマンドを使用してsystem手続きを実行し、short-specs?に#fが指定されている場合はファイルやディレクトリの詳細を返します。absolute?に#tが指定されている場合は、ファイルやディレクトリを絶対パスで返します。
現在のディレクトリを"/usr/local/lib/slib/direntry"とします。
((dirent:scan-directory #f) ".")
=> ("/usr/local/lib/slib/direntry/About"
"/usr/local/lib/slib/direntry/COPYING"
"/usr/local/lib/slib/direntry/ChangeLog"
"/usr/local/lib/slib/direntry/direntry.info"
"/usr/local/lib/slib/direntry/direntry.scm"
"/usr/local/lib/slib/direntry/direntry.texi")
((dirent:scan-directory #f) "." #t #t)
=> ("/usr/local/lib/slib/direntry/About"
"/usr/local/lib/slib/direntry/COPYING"
"/usr/local/lib/slib/direntry/ChangeLog"
"/usr/local/lib/slib/direntry/direntry.info"
"/usr/local/lib/slib/direntry/direntry.scm"
"/usr/local/lib/slib/direntry/direntry.texi")
((dirent:scan-directory #f) "." #t #f)
=> ("About" "COPYING" "ChangeLog" "direntry.info"
"direntry.scm" "direntry.texi")
((dirent:scan-directory #t) "." #t #f)
=> ("." "..")
((dirent:scan-directory #t) "." #t #t)
=> ("/usr/local/lib/slib/direntry/."
"/usr/local/lib/slib/direntry/..")
((dirent:scan-directory #t) "/usr/local/lib/slib" #f #f)
=> ("drwxr-xr-x 2 root wheel 512 3/21 05:00 direntry"
"drwxr-xr-x 2 root wheel 512 3/27 05:03 jfilter"
"drwxr-xr-x 2 root wheel 512 3/22 02:45 wb")
((dirent:scan-directory #f) "/usr/lib/libm.so.[0-9]" #t #f)
=> ("libm.so.2")
((dirent:scan-directory #f) "/usr/lib/libm.so.[0-9]" #t #t)
=> ("/usr/lib/libm.so.2")
((dirent:scan-directory #f) "/usr/lib/libm.so.[0-9]" #f #f)
=> ("-r--r--r-- 1 root wheel 118992 11/20 20:58 libm.so.2")
((dirent:scan-directory #f) "/usr/lib/libm.so.[0-9]" #f #t)
=> ("-r--r--r-- 1 root wheel 118992 11/20 20:58
/usr/lib/libm.so.2")
指定された文字列引数search-stringsに一致するパスを返します。引数directories?に#tが指定された場合はディレクトリへのパスが、#fが指定された場合はファイルへのパスが返されます。引数vector-output?に#tを指定した場合はパスは文字列のベクタとして、#fを指定した場合は文字列のリストとして返されます。
引数short-specs?、absolute?、search-stringsはすべてオプションで、任意の順序で任意の数を指定できます。最初に遭遇した論理値はshort-specs?に割り当てられ、2番目に遭遇した論理値はabsolute?に割り当てられます。3番目以降の論理値は無視されます。引数search-stringには複数の文字列か、複数の文字列を#\spaceで区切った1つの文字列を指定できます。#\spaceで区切った文字列は部分文字列のリストに変換されます。指定文字列1つ1つに一致するパスが手続きdirent:scan-directoryで走査されます。
オプション引数が省略された場合、short-specs?には#tが、absolute?にも#tが指定され、現在のディレクトリが走査されます。
(directory-contains #f #f "/usr/lib/libm.*" "/usr/lib/libc.*" #t #f)
=> ("libc.a" "libc.so" "libc.so.4" "libm.a" "libm.so"
"libm.so.2")
(directory-contains #f #f "/usr/lib/libm.* /usr/lib/libc.*" #t #f)
=> ("libc.a" "libc.so" "libc.so.4" "libm.a" "libm.so"
"libm.so.2")
(directory-contains #f #f "/usr/lib/libm.*" #t #t)
=> ("/usr/lib/libm.a" "/usr/lib/libm.so"
"/usr/lib/libm.so.2")
(directory-contains #f #f "/usr/lib/libm.*" #f #f)
=> ("-r--r--r-- 1 root wheel 118992 11/20 20:58 libm.so.2"
"-r--r--r-- 1 root wheel 274862 11/20 20:58 libm.a"
"lrwxrwxrwx 1 root wheel 9 2/ 9 09:43 libm.so -> libm.so.2")
(directory-contains #f #f "/usr/lib/libm.*" #f #t)
=> ("-r--r--r-- 1 root wheel 118992 11/20 20:58
/usr/lib/libm.so.2"
"-r--r--r-- 1 root wheel 274862 11/20 20:58
/usr/lib/libm.a"
"lrwxrwxrwx 1 root wheel 9 2/ 9 09:43
/usr/lib/libm.so -> libm.so.2")
手続きfiles、files-v、dirs、dirs-vは、手続きdirectory-containsへのショートカットです。
引数short-specs?、absolute?、search-stringsはすべてオプションで、任意の順序で任意の数を指定できます。手続きdirectory-contains参照。
引数search-stringsに一致するファイルへのパス名をリストにして返します。
引数short-specs?、absolute?、search-stringsはすべてオプションで、任意の順序で任意の数を指定できます。手続きdirectory-contains参照。
引数search-stringsに一致するファイルへのパス名をベクタにして返します。
引数short-specs?、absolute?、search-stringsはすべてオプションで、任意の順序で任意の数を指定できます。手続きdirectory-contains参照。
引数search-stringsに一致するディレクトリへのパス名をリストにして返します。
引数short-specs?、absolute?、search-stringsはすべてオプションで、任意の順序で任意の数を指定できます。手続きdirectory-contains参照。
引数search-stringsに一致するディレクトリへのパス名をベクタにして返します。
文字列引数pathname内の有効なディレクトリ部分を返します。
(directoryname-in-path "/usr/local/lib")
=> "/usr/local/lib"
(directoryname-in-path "/usr/local/bin/scm")
=> "/usr/local/bin"
(directoryname-in-path "/usr/local/lib/non-existing-name")
=> "/usr/local/lib"
(directoryname-in-path "/usr/local/lib/slib/nclients.scm")
=> "/usr/local/lib/slib"
(directoryname-in-path ".")
=> "/usr/local/lib/slib/direntry"
;; 現在のディレクトリへのパスが返されます。
引数pathname内のファイル名を返します。pathnameがディレクトリであるか、指定されたファイルがファイルシステム内に存在しない場合は空文字列が返されます。
(filename-in-path "/usr/local/lib/slib/nclients.scm")
=> "nclients.scm"
(filename-in-path "/usr/local/lib/slib")
=> ""
(filename-in-path "/usr/local/lib/non-existing-name")
=> ""
指定されたpathnameがディレクトリであるか、パスがファイルシステム内に存在しない場合にも、パス名の最後の部分を返します。
(basename-in-path "/usr/local/lib/slib/nclients.scm")
=> "nclients.scm"
(basename-in-path "/usr/local/lib/slib")
=> "slib"
(basename-in-path "/usr/local/lib/non-existing-name")
=> "non-existing-name"
引数updownはオプションです。手続きはpathnameに指定された文字列の最後の部分の、ピリオド(.)から後ろの部分(拡張子)を返します。引数updownは、返される文字列の大文字と小文字の変換を制御します。拡張子が存在しない場合は空文字列が返されます。
引数updownに#tを指定した場合には小文字への変換が、#fを指定した場合には大文字への変換が行なわれます。updownが省略された場合、変換は行なわれません。
(get-extension "scm.EXE") => "EXE" (get-extension "scm.EXE" #t) => "exe" (get-extension "scm.exe" #f) => "EXE"
適当なディレクトリ、例えばホームディレクトリ$HOMEに"direntry.zip"を展開して下さい。指定ディレクトリの下に"direntry"ディレクトリが作成されて、その中に内容が展開されます。
unzip direntry.zip -d ~.
次のようにして、実行するScheme処理系の初期化ファイルに、SLIBの*catalog*変数にパッケージ名のシンボルとパスのconsリストを書き加えます。
(require 'glob) ; *catalog*変数がまだ利用できない場合は
; 利用できるようにします。
(set! *catalog* (cons (cons 'directory-entries "your-home-directory/direntry") *catalog*))
このパッケージに利用価値があると考えられる場合はrootになって、SLIBディレクトリの下にあるmklibcat.scmを次のように書き換えて新しいSLIBCATを作成すれば、(require 'directory-entries)で利用できるようになります。
*** mklibcat.scm.orig Fri Mar 30 19:48:40 2001 --- mklibcat.scm Wed Mar 21 05:21:58 2001 *************** *** 37,42 **** --- 37,45 ---- (cons 'portable-scheme-debugger (in-vicinity (sub-vicinity (library-vicinity) "psd") "psd-slib")) + (cons 'directory-entries + (in-vicinity (sub-vicinity (library-vicinity) "direntry") + "direntry")) (cons 'jfilter (in-vicinity (sub-vicinity (library-vicinity) "jfilter") "jfilter")))
書き換えたらrootのままでSchemeを起動して次のように入力すると、新しいSLIBCATが作成されます。
(require 'new-catalog) (require 'directory-entries)
Jump to: b - c - d - f - g - i - p - r - s
This document was generated on 7 April 2001 using the texi2html translator version 1.52.