summaryrefslogtreecommitdiff
path: root/gnuglob.c
diff options
context:
space:
mode:
authorYukihiro Matsumoto <matz@ruby-lang.org>1994-10-13 12:13:48 +0900
committerTakashi Kokubun <takashikkbn@gmail.com>2019-08-17 22:09:30 +0900
commiteed5c920dd5429bac6075e9bc98d82360392b424 (patch)
tree825427093bc27339080dbbcaebc1563703bae357 /gnuglob.c
parent6e3090413652b6592346556149fed1e9aec5495d (diff)
version 0.51v0_51
https://cache.ruby-lang.org/pub/ruby/1.0/ruby-0.51.tar.gz Thu Oct 13 12:13:48 1994 Yukihiro Matsumoto (matz@ix-02) * eval.c(SETUP_ARGS): 付加演算子が配列でない時には配列に変換する. * parse.y: 括弧なしのメソッド呼び出しでも`*'による付加引数が使える ようにした. ただし, 通常引数が一つもない場合は乗算演算子と区別が つかないので, 必ず括弧が必要. Wed Oct 12 10:09:07 1994 Yukihiro Matsumoto (matz@ix-02) * eval.c(rb_call): キャッシュの計算をinline化. キャッシュミスがあ れば関数呼び出しでメソッドを検索する. methods.cはなくなった. * eval.c(rb_eval): ローカル変数用の領域をalloca()するように変更. サイズの変更が必要になれば改めてmalloc()するように. * parse.y: error recoveryの際にlex_stateを更新しておくように. Tue Oct 11 17:10:46 1994 Yukihiro Matsumoto (matz@ix-02) * socket.c(for_fd): ファイル記述子(Fixnum)からソケットインスタンス を得るメソッド. たとえばinetdから起動されたサーバで標準入出力に ソケット操作を行なうために使う. つまりSocket.for_fd($stdin)で標 準入力に対応するソケットオブジェクトが得られる. * io.c(to_i): IOクラスのインスタンスを整数に変換するとそのファイル 記述子を返すように. * numeric.c(num2int): to_iメソッドを使って, できる限り整数に変換す る. 以前はnum2fixだけが全てのオブジェクトに対してto_iメソッドを 適用していた. * sprintf.c(Fsprintf): 整数表示の際, オブジェクトをできる限り整数 に変換するように(to_iメソッドを使う). Fri Oct 7 14:06:32 1994 Yukihiro Matsumoto (matz@ix-02) * eval.c(Fcaller): 必要性がよく分からないのでドキュメントから削除. 将来デバッガを作る時に復活させよう. * eval.c(rb_call): Cで記述されたメソッド呼び出しでは環境をスタック にセーブしないことによって高速化. Wed Oct 5 15:00:58 1994 Yukihiro Matsumoto (matz@ix-02) * ruby.h: 一時env.hに移動してたQselfの定義を復活. ただし今回は関数 として実現(env.hでは変数として再定義してある). * ruby.h: TRUEでsyntax errorにならないよう#undefを追加. * eval.c(rb_eval): thread化に挑戦したが, 失敗(速くならなかった). が, Scopingなどの無駄なコードの削除とメソッド呼び出しの引数セッ トのinline化で若干の高速化を実現した. 副作用として, argc, argv形 式の関数呼び出しの仕様が変化した(argvにselfを含まなくなった). * eval.c(rb_call): メソッド呼び出しの高速化. Tue Oct 4 11:40:53 1994 Yukihiro Matsumoto (matz@ix-02) * ruby-mode.el: 修飾子に対応した. * parse.y: 多重代入にrestをつけた. この機能を使えばoptional引数の 解析が簡単にできる(はず). * pack.c(unpack): uuencode形式のdecodeの際に文字列の長さが間違って いた. Mon Oct 3 15:58:41 1994 Yukihiro Matsumoto (matz@ix-02) * file.c(type): ファイルタイプを文字列で返すメソッド. Fri Sep 30 11:36:07 1994 Yukihiro Matsumoto (matz@ix-02) * object.c: デフォルトの真の値である%TRUEの値を1(Fixnum)からtに変 更した. to_sで文字列に変換した時にも`t'と表示される. 更に踏み込 んで`t'を予約語にしてlispのようにしようかとも思ったが, そこまで は決心できなかった. 一文字のローカル変数はかなり使いそうな気がす るので…. * array.c,dict.c: equalを再定義しているクラスで, hashを正しく定義 した. Wed Sep 28 23:30:28 1994 Yukihiro Matsumoto (matz@dyna) * eval.c(Ffail): 今までfailはカーネルクラスのメソッドであったが, 構文に組み込んだ. この変更によって, 1)`fail'は予約語となり, ロー カル変数に用いることができなくなった. 2)`fail'単体で例外を発生す るようになった. 3)failはメソッドではなくなったので再定義される可 能性がなくなった. * dic.c, dbm.c(indexes): Arrayのindexesと同様の機能を持つメソッド を追加. * array.c(indexes): 引数をインデックスとする要素の配列を返す. 整数 の配列を引数とする時には引数の要素をインデックスとする要素の配列 を返す. Mon Sep 19 13:42:31 1994 Yukihiro Matsumoto (matz@ix-02) * array.c(aset): 部分配列に対する代入で配列以外のオブジェクトが指 定された場合に多重代入と同じルールで配列化するようにした. * io.c(print): 引数として与えられた各オブジェクトにprint_onメッセー ジを与えるように. 実行速度は落ちるが柔軟性は増す. Fri Sep 16 14:59:18 1994 Yukihiro Matsumoto (matz@ix-02) * glob.c: ワイルドカードの導入. bashに使われているGNUのglobルーチ ンを流用した. Mon Sep 12 18:36:58 1994 Yukihiro Matsumoto (matz@ix-02) * parse.y(value_expr): 式がnilの時に対応. * class.c: ICLASSのclassが必ずClass/Moduleを指すように. Tue Sep 6 16:23:28 1994 Yukihiro Matsumoto (matz@ix-02) * re.c: 正規表現内で「\数字」形式が指定できるように. * parse.y:「do expr using var ... end」形式はなくなった. 寂しい気 もする. *BACKWARD INCOMPATIBILITY* Mon Sep 5 10:59:01 1994 Yukihiro Matsumoto (matz@ix-02) * numeric.c(next): Numericクラスにもnextを提供. * string.c(upto): uptoを提供. * range.c(each): nextを使ったインタフェースからuptoを使うように変 更した. この方が一つのメソッドで処理をまとめで行なうことができる. Fri Sep 2 15:25:39 1994 Yukihiro Matsumoto (matz@ix-02) * dict.c(each): 戻り値を[key, value]のペアに変更. 今までのeachは each_valueとして残る. *BACKWARD INCOMPATIBILITY* Thu Sep 1 10:49:04 1994 Yukihiro Matsumoto (matz@ix-02) * 成功した(特別な戻り値を持たない)システムコールは`0'を返すように. Wed Aug 31 00:26:51 1994 Yukihiro Matsumoto (matz@dyna) * string.c: チェックサムを得るメソッド`sum'を作った. * class.c(include_class_new): ICLASSのclassをもとのクラスにした. gcの際に元クラスをマークする必要があるのが, フィールドを増やす余 地が無いので, classフィールドを流用した. 私の見積りが間違ってい て, ICLASSのインスタンスにメッセージを送る事があれば, おかしな動 作をするだろう. * eval.c(masign): 式(a,b = nil)の値を[nil]からnilに変更した. Mon Aug 29 11:56:09 1994 Yukihiro Matsumoto (matz@ix-02) * class.c: rb_define_mfuncを無くして, メタクラスにモジュールをイン クルードするようにした. * error.c(yyerror): 同じ行で複数のsyntax errorをリポートしないよう にした. * file.c: FileTestモジュールにファイルテストメソッドを分離した. * parse.y: 演算子を指定する時のlex_stateを正しく設定した. Sat Aug 27 01:23:34 1994 Yukihiro Matsumoto (matz@dyna) * parse.y: if/whileなどの複合式をprimaryに移動した. これによって例 えば「if cond then a else b end.message()」のような式が書けるよ うになった. Fri Aug 26 10:46:30 1994 Yukihiro Matsumoto (matz@ix-02) * spec: 整理された文法にしたがって書き直した. * parse.y: ここ数日で混乱していた文法を整理した. 括弧を省略したメ ソッド呼び出しができるようになったこと, modifierが付けられるよう になったこと, returnにリストが渡せるようになったことが主な変更点 である. * process周りが怪しいがとにかくSolaris 2.3で動くように. * parse.y: 曖昧性がない場合にはメソッド呼び出しの引数の括弧を省略 できるように. 省略できるメソッド呼び出しの条件は, 1)かならず1個 以上の引数を必要とすること, 2)第1引数が`+', `-', `(', `[', `{', `/'など, 式の始まりに置かれた時と途中に現れた時とで解釈が違う記 号で始まらないこと, である. Thu Aug 25 13:54:58 1994 Yukihiro Matsumoto (matz@ix-02) * parse.y(cond): 条件式の展開部にbugがあった. Wed Aug 24 00:01:15 1994 Yukihiro Matsumoto (matz@dyna) * parse.y: returnはコンマで区切ったリストも受け取るように. つまり, return a, b, cはreturn [a, b, c]と同じ意味になる. * parse.y: yield以外の大域脱出制御式をexprからexpr0に移した. よっ てメソッドの引数に制御式を使えなくなる(これで困る人はいないはず). * parse.y: `+'の定数展開の際に演算子の優先順位を忘れていた. * eval.c: untilの戻り値はnilになった. * parse.y: modifierとしてのif/unless/while/untilを追加. * parse.y: 文法からendの後ろにつけるキーワードを削除. ほとんど使わ なかった上に, emacsではruby-modeがあれば対応のチェックが機械的に 出来るため. Tue Aug 23 18:08:33 1994 Yukihiro Matsumoto (matz@ix-02) * eval.c: スクリプト実行開始前に例外が発生した時にcore dumpした. 組み込み用にコードを変更した時にenbugしてしまった. Tue Aug 23 00:07:17 1994 Yukihiro Matsumoto (matz@dyna) * eval.c: doの戻り値がいつもnilになっていた. * parse.y: loop制御変数の多重代入化にbugがあった. * parse.y(expand_op): 文字列も畳み込みの対象に. Mon Aug 22 10:50:01 1994 Yukihiro Matsumoto (matz@ix-02) * parse.y(expand_op): `+'に関しては結合則を使って, より多く定数畳 み込みを行なうように. * ruby.c(proc_options): argcが0の時にも対応. * parse.y: forなどの制御変数に多重代入も使えるように. Sat Aug 20 00:59:40 1994 Yukihiro Matsumoto (matz@dyna) * parse.y(call_op): 演算子`~'の取り扱いをルール部へ移動. Fri Aug 19 11:44:13 1994 Yukihiro Matsumoto (matz@ix-02) * main.c: rubyをほかのプログラムに組み込めるようにmain()を分割した. それにともない, プログラムの呼び出し構造を修正した. * parse.y: 条件式の定義を変更. ifなどの条件式の中でだけ`&&'や`||' および`!'の引数が条件式になるように. この変更により条件式以外の 場所での `&&', `||', `!'演算子の動作が直観に一致する. * parse.y: 実引数の`*'の後に続く引数はexprに制限した. 今までは全て の文が有効であったが, ここで定義文があってもしょうがない. Thu Aug 18 10:21:45 1994 Yukihiro Matsumoto (matz@ix-02) * re.c: 正規表現ルーチンの初期化部分を削除してしまっていた. これで はemacsの正規表現になってしまう. * version.c: copyright表示を追加. * version.c: バージョン表示をstderrに. * configure.in: gccがない場合testに失敗していた. Fri Aug 12 14:12:23 1994 Yukihiro Matsumoto (matz@ix-02) * array.c(astore): 配列の拡大する時にある程度の大きさをまとめて拡 大するように. * io.c(Fprint): 配列に対しては一度文字列に変換することなく, 直接内 容を出力するように. * string.c(str_new): memmoveからmemcpyへ置き換えた. これでもかなり 速度が違う. * ruby.h: データメンバの取り出しで名前を文字列からIDで指定するよう にした. かなりの高速化になる. * io.c: $ARGFという変数で引数列からなる仮想ファイルをオブジェクト として扱えるようにした. 今まではトップレベルのgets()などを使って アクセスしていたが, どうもオブジェクト指向的ではなかった. Thu Aug 11 11:43:15 1994 Yukihiro Matsumoto (matz@ix-02) * gc.c: mark_location()の間違った呼び出し方の行が残っていた. * method.c: プロトタイプ宣言が足りなかった.
Diffstat (limited to 'gnuglob.c')
-rw-r--r--gnuglob.c572
1 files changed, 572 insertions, 0 deletions
diff --git a/gnuglob.c b/gnuglob.c
new file mode 100644
index 0000000000..e5eecc1a79
--- /dev/null
+++ b/gnuglob.c
@@ -0,0 +1,572 @@
+/* File-name wildcard pattern matching for GNU.
+ Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* To whomever it may concern: I have never seen the code which most
+ Unix programs use to perform this function. I wrote this from scratch
+ based on specifications for the pattern matching. --RMS. */
+
+#if defined (SHELL)
+# if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+# else
+# include "ansi_stdlib.h"
+# endif /* HAVE_STDLIB_H */
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if !defined (SHELL) && (defined (_POSIX_VERSION) || defined (USGr3))
+# if !defined (HAVE_DIRENT_H)
+# define HAVE_DIRENT_H
+# endif /* !HAVE_DIRENT_H */
+#endif /* !SHELL && (_POSIX_VERSION || USGr3) */
+
+#if defined (HAVE_DIRENT_H)
+# include <dirent.h>
+# if !defined (direct)
+# define direct dirent
+# endif /* !direct */
+# define D_NAMLEN(d) strlen ((d)->d_name)
+#else /* !HAVE_DIRENT_H */
+# define D_NAMLEN(d) ((d)->d_namlen)
+# if defined (USG)
+# if defined (Xenix)
+# include <sys/ndir.h>
+# else /* !Xenix (but USG...) */
+# include "ndir.h"
+# endif /* !Xenix */
+# else /* !USG */
+# include <sys/dir.h>
+# endif /* !USG */
+#endif /* !HAVE_DIRENT_H */
+
+#if defined (_POSIX_SOURCE)
+/* Posix does not require that the d_ino field be present, and some
+ systems do not provide it. */
+# define REAL_DIR_ENTRY(dp) 1
+#else
+# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
+#endif /* _POSIX_SOURCE */
+
+#if defined (USG) || defined (NeXT)
+# if !defined (HAVE_STRING_H)
+# define HAVE_STRING_H
+# endif /* !HAVE_STRING_H */
+#endif /* USG || NeXT */
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#if defined (USG)
+# if !defined (isc386)
+# include <memory.h>
+# endif /* !isc386 */
+# if defined (RISC6000)
+extern void bcopy ();
+# else /* !RISC6000 */
+# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n)))
+# endif /* !RISC6000 */
+#endif /* USG */
+
+#include "fnmatch.h"
+
+/* If the opendir () on your system lets you open non-directory files,
+ then we consider that not robust. Define OPENDIR_NOT_ROBUST in the
+ SYSDEP_CFLAGS for your machines entry in machines.h. */
+#if defined (OPENDIR_NOT_ROBUST)
+# if defined (SHELL)
+# include "posixstat.h"
+# else /* !SHELL */
+# include <sys/stat.h>
+# endif /* !SHELL */
+#endif /* OPENDIR_NOT_ROBUST */
+
+#if !defined (HAVE_STDLIB_H)
+extern char *malloc (), *realloc ();
+extern void free ();
+#endif /* !HAVE_STDLIB_H */
+
+#if !defined (NULL)
+# if defined (__STDC__)
+# define NULL ((void *) 0)
+# else
+# define NULL 0x0
+# endif /* __STDC__ */
+#endif /* !NULL */
+
+#if defined (SHELL)
+extern int interrupt_state;
+#endif /* SHELL */
+
+/* Global variable which controls whether or not * matches .*.
+ Non-zero means don't match .*. */
+int noglob_dot_filenames = 1;
+
+/* Global variable to return to signify an error in globbing. */
+char *glob_error_return;
+
+
+/* Return nonzero if PATTERN has any special globbing chars in it. */
+int
+glob_pattern_p (pattern)
+ char *pattern;
+{
+ register char *p = pattern;
+ register char c;
+ int open = 0;
+
+ while ((c = *p++) != '\0')
+ switch (c)
+ {
+ case '?':
+ case '*':
+ return (1);
+
+ case '[': /* Only accept an open brace if there is a close */
+ open++; /* brace to match it. Bracket expressions must be */
+ continue; /* complete, according to Posix.2 */
+ case ']':
+ if (open)
+ return (1);
+ continue;
+
+ case '\\':
+ if (*p++ == '\0')
+ return (0);
+ }
+
+ return (0);
+}
+
+/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */
+static void
+dequote_pathname (pathname)
+ char *pathname;
+{
+ register int i, j;
+
+ for (i = j = 0; pathname && pathname[i]; )
+ {
+ if (pathname[i] == '\\')
+ i++;
+
+ pathname[j++] = pathname[i++];
+
+ if (!pathname[i - 1])
+ break;
+ }
+ pathname[j] = '\0';
+}
+
+
+/* Return a vector of names of files in directory DIR
+ whose names match glob pattern PAT.
+ The names are not in any particular order.
+ Wildcards at the beginning of PAT do not match an initial period.
+
+ The vector is terminated by an element that is a null pointer.
+
+ To free the space allocated, first free the vector's elements,
+ then free the vector.
+
+ Return 0 if cannot get enough memory to hold the pointer
+ and the names.
+
+ Return -1 if cannot access directory DIR.
+ Look in errno for more information. */
+
+char **
+glob_vector (pat, dir)
+ char *pat;
+ char *dir;
+{
+ struct globval
+ {
+ struct globval *next;
+ char *name;
+ };
+
+ DIR *d;
+ register struct direct *dp;
+ struct globval *lastlink;
+ register struct globval *nextlink;
+ register char *nextname;
+ unsigned int count;
+ int lose, skip;
+ register char **name_vector;
+ register unsigned int i;
+#if defined (OPENDIR_NOT_ROBUST)
+ struct stat finfo;
+
+ if (stat (dir, &finfo) < 0)
+ return ((char **) &glob_error_return);
+
+ if (!S_ISDIR (finfo.st_mode))
+ return ((char **) &glob_error_return);
+#endif /* OPENDIR_NOT_ROBUST */
+
+ d = opendir (dir);
+ if (d == NULL)
+ return ((char **) &glob_error_return);
+
+ lastlink = 0;
+ count = 0;
+ lose = 0;
+ skip = 0;
+
+ /* If PAT is empty, skip the loop, but return one (empty) filename. */
+ if (!pat || !*pat)
+ {
+ nextlink = (struct globval *)alloca (sizeof (struct globval));
+ nextlink->next = lastlink;
+ nextname = (char *) malloc (1);
+ if (!nextname)
+ lose = 1;
+ else
+ {
+ lastlink = nextlink;
+ nextlink->name = nextname;
+ nextname[0] = '\0';
+ count++;
+ }
+ skip = 1;
+ }
+
+ /* Scan the directory, finding all names that match.
+ For each name that matches, allocate a struct globval
+ on the stack and store the name in it.
+ Chain those structs together; lastlink is the front of the chain. */
+ while (!skip)
+ {
+ int flags; /* Flags passed to fnmatch (). */
+#if defined (SHELL)
+ /* Make globbing interruptible in the bash shell. */
+ if (interrupt_state)
+ {
+ closedir (d);
+ lose = 1;
+ goto lost;
+ }
+#endif /* SHELL */
+
+ dp = readdir (d);
+ if (dp == NULL)
+ break;
+
+ /* If this directory entry is not to be used, try again. */
+ if (!REAL_DIR_ENTRY (dp))
+ continue;
+
+ /* If a dot must be explicity matched, check to see if they do. */
+ if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.')
+ continue;
+
+ flags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME;
+
+ if (fnmatch (pat, dp->d_name, flags) != FNM_NOMATCH)
+ {
+ nextlink = (struct globval *) alloca (sizeof (struct globval));
+ nextlink->next = lastlink;
+ nextname = (char *) malloc (D_NAMLEN (dp) + 1);
+ if (nextname == NULL)
+ {
+ lose = 1;
+ break;
+ }
+ lastlink = nextlink;
+ nextlink->name = nextname;
+ bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1);
+ ++count;
+ }
+ }
+ (void) closedir (d);
+
+ if (!lose)
+ {
+ name_vector = (char **) malloc ((count + 1) * sizeof (char *));
+ lose |= name_vector == NULL;
+ }
+
+ /* Have we run out of memory? */
+ lost:
+ if (lose)
+ {
+ /* Here free the strings we have got. */
+ while (lastlink)
+ {
+ free (lastlink->name);
+ lastlink = lastlink->next;
+ }
+#if defined (SHELL)
+ if (interrupt_state)
+ throw_to_top_level ();
+#endif /* SHELL */
+ return (NULL);
+ }
+
+ /* Copy the name pointers from the linked list into the vector. */
+ for (i = 0; i < count; ++i)
+ {
+ name_vector[i] = lastlink->name;
+ lastlink = lastlink->next;
+ }
+
+ name_vector[count] = NULL;
+ return (name_vector);
+}
+
+/* Return a new array which is the concatenation of each string in ARRAY
+ to DIR. This function expects you to pass in an allocated ARRAY, and
+ it takes care of free()ing that array. Thus, you might think of this
+ function as side-effecting ARRAY. */
+static char **
+glob_dir_to_array (dir, array)
+ char *dir, **array;
+{
+ register unsigned int i, l;
+ int add_slash;
+ char **result;
+
+ l = strlen (dir);
+ if (l == 0)
+ return (array);
+
+ add_slash = dir[l - 1] != '/';
+
+ i = 0;
+ while (array[i] != NULL)
+ ++i;
+
+ result = (char **) malloc ((i + 1) * sizeof (char *));
+ if (result == NULL)
+ return (NULL);
+
+ for (i = 0; array[i] != NULL; i++)
+ {
+ result[i] = (char *) malloc (l + (add_slash ? 1 : 0)
+ + strlen (array[i]) + 1);
+ if (result[i] == NULL)
+ return (NULL);
+ sprintf (result[i], "%s%s%s", dir, add_slash ? "/" : "", array[i]);
+ }
+ result[i] = NULL;
+
+ /* Free the input array. */
+ for (i = 0; array[i] != NULL; i++)
+ free (array[i]);
+ free ((char *) array);
+
+ return (result);
+}
+
+/* Do globbing on PATHNAME. Return an array of pathnames that match,
+ marking the end of the array with a null-pointer as an element.
+ If no pathnames match, then the array is empty (first element is null).
+ If there isn't enough memory, then return NULL.
+ If a file system error occurs, return -1; `errno' has the error code. */
+char **
+glob_filename (pathname)
+ char *pathname;
+{
+ char *strrchr();
+
+ char **result;
+ unsigned int result_size;
+ char *directory_name, *filename;
+ unsigned int directory_len;
+
+ result = (char **) malloc (sizeof (char *));
+ result_size = 1;
+ if (result == NULL)
+ return (NULL);
+
+ result[0] = NULL;
+
+ /* Find the filename. */
+ filename = strrchr (pathname, '/');
+ if (filename == NULL)
+ {
+ filename = pathname;
+ directory_name = "";
+ directory_len = 0;
+ }
+ else
+ {
+ directory_len = (filename - pathname) + 1;
+ directory_name = (char *) alloca (directory_len + 1);
+
+ bcopy (pathname, directory_name, directory_len);
+ directory_name[directory_len] = '\0';
+ ++filename;
+ }
+
+ /* If directory_name contains globbing characters, then we
+ have to expand the previous levels. Just recurse. */
+ if (glob_pattern_p (directory_name))
+ {
+ char **directories;
+ register unsigned int i;
+
+ if (directory_name[directory_len - 1] == '/')
+ directory_name[directory_len - 1] = '\0';
+
+ directories = glob_filename (directory_name);
+
+ if (directories == NULL)
+ goto memory_error;
+ else if (directories == (char **)&glob_error_return)
+ return ((char **) &glob_error_return);
+ else if (*directories == NULL)
+ {
+ free ((char *) directories);
+ return ((char **) &glob_error_return);
+ }
+
+ /* We have successfully globbed the preceding directory name.
+ For each name in DIRECTORIES, call glob_vector on it and
+ FILENAME. Concatenate the results together. */
+ for (i = 0; directories[i] != NULL; ++i)
+ {
+ char **temp_results;
+
+ /* Scan directory even on a NULL pathname. That way, `*h/'
+ returns only directories ending in `h', instead of all
+ files ending in `h' with a `/' appended. */
+ temp_results = glob_vector (filename, directories[i]);
+
+ /* Handle error cases. */
+ if (temp_results == NULL)
+ goto memory_error;
+ else if (temp_results == (char **)&glob_error_return)
+ /* This filename is probably not a directory. Ignore it. */
+ ;
+ else
+ {
+ char **array;
+ register unsigned int l;
+
+ array = glob_dir_to_array (directories[i], temp_results);
+ l = 0;
+ while (array[l] != NULL)
+ ++l;
+
+ result =
+ (char **)realloc (result, (result_size + l) * sizeof (char *));
+
+ if (result == NULL)
+ goto memory_error;
+
+ for (l = 0; array[l] != NULL; ++l)
+ result[result_size++ - 1] = array[l];
+
+ result[result_size - 1] = NULL;
+
+ /* Note that the elements of ARRAY are not freed. */
+ free ((char *) array);
+ }
+ }
+ /* Free the directories. */
+ for (i = 0; directories[i]; i++)
+ free (directories[i]);
+
+ free ((char *) directories);
+
+ return (result);
+ }
+
+ /* If there is only a directory name, return it. */
+ if (*filename == '\0')
+ {
+ result = (char **) realloc ((char *) result, 2 * sizeof (char *));
+ if (result == NULL)
+ return (NULL);
+ result[0] = (char *) malloc (directory_len + 1);
+ if (result[0] == NULL)
+ goto memory_error;
+ bcopy (directory_name, result[0], directory_len + 1);
+ result[1] = NULL;
+ return (result);
+ }
+ else
+ {
+ char **temp_results;
+
+ /* There are no unquoted globbing characters in DIRECTORY_NAME.
+ Dequote it before we try to open the directory since there may
+ be quoted globbing characters which should be treated verbatim. */
+ if (directory_len > 0)
+ dequote_pathname (directory_name);
+
+ /* We allocated a small array called RESULT, which we won't be using.
+ Free that memory now. */
+ free (result);
+
+ /* Just return what glob_vector () returns appended to the
+ directory name. */
+ temp_results =
+ glob_vector (filename, (directory_len == 0 ? "." : directory_name));
+
+ if (temp_results == NULL || temp_results == (char **)&glob_error_return)
+ return (temp_results);
+
+ return (glob_dir_to_array (directory_name, temp_results));
+ }
+
+ /* We get to memory_error if the program has run out of memory, or
+ if this is the shell, and we have been interrupted. */
+ memory_error:
+ if (result != NULL)
+ {
+ register unsigned int i;
+ for (i = 0; result[i] != NULL; ++i)
+ free (result[i]);
+ free ((char *) result);
+ }
+#if defined (SHELL)
+ if (interrupt_state)
+ throw_to_top_level ();
+#endif /* SHELL */
+ return (NULL);
+}
+
+#if defined (TEST)
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ unsigned int i;
+
+ for (i = 1; i < argc; ++i)
+ {
+ char **value = glob_filename (argv[i]);
+ if (value == NULL)
+ puts ("Out of memory.");
+ else if (value == &glob_error_return)
+ perror (argv[i]);
+ else
+ for (i = 0; value[i] != NULL; i++)
+ puts (value[i]);
+ }
+
+ exit (0);
+}
+#endif /* TEST. */