From 3376271d9e3c6b96acb63720eb4d59643abeb32c Mon Sep 17 00:00:00 2001 From: matz Date: Fri, 7 May 1999 08:24:37 +0000 Subject: 990507 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_3@460 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 13 ++ MANIFEST | 1 - Makefile.in | 2 - dir.c | 182 +++++++++++++-- ext/Setup | 1 + ext/extmk.rb.in | 2 +- ext/extmk.rb.nt | 2 +- ext/pty/MANIFEST | 12 + ext/pty/README | 93 ++++++++ ext/pty/README.expect | 22 ++ ext/pty/README.expect.jp | 21 ++ ext/pty/README.jp | 89 +++++++ ext/pty/expect_sample.rb | 56 +++++ ext/pty/extconf.rb | 9 + ext/pty/lib/expect.rb | 36 +++ ext/pty/pty.c | 485 ++++++++++++++++++++++++++++++++++++++ ext/pty/script.rb | 38 +++ ext/pty/shl.rb | 96 ++++++++ ext/socket/extconf.rb | 33 +-- ext/socket/getaddrinfo.c | 28 ++- ext/socket/getnameinfo.c | 15 +- ext/socket/socket.c | 34 +-- glob.c | 595 ----------------------------------------------- lib/mkmf.rb | 2 +- 24 files changed, 1182 insertions(+), 685 deletions(-) create mode 100644 ext/pty/MANIFEST create mode 100644 ext/pty/README create mode 100644 ext/pty/README.expect create mode 100644 ext/pty/README.expect.jp create mode 100644 ext/pty/README.jp create mode 100644 ext/pty/expect_sample.rb create mode 100644 ext/pty/extconf.rb create mode 100644 ext/pty/lib/expect.rb create mode 100644 ext/pty/pty.c create mode 100644 ext/pty/script.rb create mode 100644 ext/pty/shl.rb delete mode 100644 glob.c diff --git a/ChangeLog b/ChangeLog index 9f42364299..6af4cde242 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +Fri May 7 17:03:57 1999 Yukihiro Matsumoto + + * dir.c (glob): removed GPL'ed glob.c completely. + +Fri May 7 08:17:19 1999 Yukihiro Matsumoto + + * ext/sdbm/extconf.rb: sdbm extension added to the distribution. + +Fri May 7 01:42:20 1999 Yukihiro Matsumoto + + * ext/socket/socket.c (tcp_s_gethostbyname): aboid using struct + sockaddr_storage. + Thu May 6 13:21:41 1999 Yukihiro Matsumoto * array.c (rb_ary_indexes): should not use rb_ary_concat(). diff --git a/MANIFEST b/MANIFEST index fde939ba12..7821f5f5fb 100644 --- a/MANIFEST +++ b/MANIFEST @@ -30,7 +30,6 @@ error.c eval.c file.c gc.c -glob.c hash.c inits.c install-sh diff --git a/Makefile.in b/Makefile.in index 0dea641c72..25eb14878a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -53,7 +53,6 @@ OBJS = array.o \ eval.o \ file.o \ gc.o \ - glob.o \ hash.o \ inits.o \ io.o \ @@ -234,7 +233,6 @@ eval.o: eval.c ruby.h config.h defines.h intern.h node.h env.h rubysig.h st.h dl file.o: file.c ruby.h config.h defines.h intern.h rubyio.h rubysig.h fnmatch.o: fnmatch.c config.h fnmatch.h gc.o: gc.c ruby.h config.h defines.h intern.h rubysig.h st.h node.h env.h re.h regex.h -glob.o: config.h glob.c fnmatch.h hash.o: hash.c ruby.h config.h defines.h intern.h st.h rubysig.h util.h inits.o: inits.c ruby.h config.h defines.h intern.h io.o: io.c ruby.h config.h defines.h intern.h rubyio.h rubysig.h diff --git a/dir.c b/dir.c index 31c574e536..c12fd542bc 100644 --- a/dir.c +++ b/dir.c @@ -47,14 +47,23 @@ # endif #endif +#ifdef HAVE_FNMATCH_H +#include +#else +#include "missing/fnmatch.h" +#endif + #include +#ifdef USE_CWGUSI +# include +#endif -#ifndef NT +#ifndef HAVE_STDLIB_H char *getenv(); #endif -#ifdef USE_CWGUSI -# include +#ifndef HAVE_STRING_H +char *strchr _((char*,char)); #endif VALUE rb_cDir; @@ -149,10 +158,10 @@ static VALUE dir_tell(dir) VALUE dir; { +#if !defined(__CYGWIN32__) && !defined(__BEOS__) DIR *dirp; - int pos; + long pos; -#if !defined(__CYGWIN32__) && !defined(__BEOS__) GetDIR(dir, dirp); pos = telldir(dirp); return rb_int2inum(pos); @@ -303,29 +312,158 @@ dir_s_rmdir(obj, dir) return Qtrue; } -#define isdelim(c) ((c)==' '||(c)=='\t'||(c)=='\n'||(c)=='\0') +/* Return nonzero if S has any special globbing chars in it. */ +static int +has_magic(s, send) + char *s, *send; +{ + register char *p = s; + register char c; + int open = 0; + + while ((c = *p++) != '\0') { + switch (c) { + case '?': + case '*': + return Qtrue; + + 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 Qtrue; + continue; + + case '\\': + if (*p++ == '\0') + return Qfalse; + } + + if (send && p >= send) break; + } + return Qfalse; +} + +struct glob1_arg { + void (*func)(); + char *basename; + VALUE arg; +}; + +static char* +extract_path(p, pend) + char *p, *pend; +{ + char *alloc; + int len; + + len = pend - p; + alloc = ALLOC_N(char, len+1); + memcpy(alloc, p, len); + if (len > 0 && pend[-1] == '/') { + alloc[len-1] = 0; + } + else { + alloc[len] = 0; + } + + return alloc; +} + +static char* +extract_elem(path) + char *path; +{ + char *pend; + + pend = strchr(path, '/'); + if (!pend) pend = path + strlen(path); + + return extract_path(path, pend); +} + +#ifndef S_ISDIR +# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) +#endif + +static void +glob(path, func, arg) + char *path; + void (*func)(); + VALUE arg; +{ + struct stat st; + char *p, *m; + + if (!has_magic(path, 0)) { + if (stat(path, &st) == 0) { + (*func)(path, arg); + } + return; + } + + p = path; + while (p) { + if (*p == '/') p++; + m = strchr(p, '/'); + if (has_magic(p, m)) { + char *dir, *base, *magic; + DIR *dirp; + struct dirent *dp; + + base = extract_path(path, p); + if (path == p) dir = "."; + else dir = base; + + dirp = opendir(dir); + if (dirp == NULL) { + free(base); + break; + } + magic = extract_elem(p); + for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { + if (fnmatch(magic, dp->d_name, FNM_PERIOD|FNM_PATHNAME) == 0) { + char *fix = ALLOC_N(char, strlen(base)+strlen(dp->d_name)+2); + + sprintf(fix, "%s%s%s", base, (p==path)?"":"/", dp->d_name); + if (!m) { + (*func)(fix, arg); + free(fix); + continue; + } + stat(fix, &st); /* should success */ + if (S_ISDIR(st.st_mode)) { + char *t = ALLOC_N(char, strlen(fix)+strlen(m)+2); + sprintf(t, "%s%s", fix, m); + glob(t, func, arg); + free(t); + } + free(fix); + } + } + closedir(dirp); + free(base); + free(magic); + } + p = m; + } +} -char **glob_filename(); -extern char *glob_error_return; +static void +push_pattern(path, ary) + char *path; + VALUE ary; +{ + rb_ary_push(ary, rb_tainted_str_new2(path)); +} static void push_globs(ary, s) VALUE ary; char *s; { - char **fnames, **ff; - - fnames = glob_filename(s); - if (fnames == (char**)-1) rb_sys_fail(s); - ff = fnames; - while (*ff) { - rb_ary_push(ary, rb_tainted_str_new2(*ff)); - free(*ff); - ff++; - } - if (fnames != &glob_error_return) { - free(fnames); - } + glob(s, push_pattern, ary); } static void @@ -374,6 +512,8 @@ push_braces(ary, s) } } +#define isdelim(c) ((c)==' '||(c)=='\t'||(c)=='\n'||(c)=='\0') + static VALUE dir_s_glob(dir, str) VALUE dir, str; diff --git a/ext/Setup b/ext/Setup index 6373af370d..830a5095ca 100644 --- a/ext/Setup +++ b/ext/Setup @@ -8,6 +8,7 @@ #kconv #md5 #pty +#sdbm #socket #tkutil #tcltklib diff --git a/ext/extmk.rb.in b/ext/extmk.rb.in index 32e9bb2b2b..db34b4252d 100644 --- a/ext/extmk.rb.in +++ b/ext/extmk.rb.in @@ -385,7 +385,7 @@ binsuffix = @binsuffix@ all: $(DLLIB) -clean:; @rm -f *.o *.a *.so *.sl +clean:; @rm -f *.o *.a *.so *.sl *.a @rm -f Makefile extconf.h conftest.* @rm -f core ruby$(binsuffix) *~ diff --git a/ext/extmk.rb.nt b/ext/extmk.rb.nt index 1b7c88f5dd..81bbb3e4dd 100644 --- a/ext/extmk.rb.nt +++ b/ext/extmk.rb.nt @@ -351,7 +351,7 @@ binsuffix = all: $(DLLIB) -clean:; @rm -f *.o *.a *.so *.sl +clean:; @rm -f *.o *.a *.so *.sl *.a @rm -f Makefile extconf.h conftest.* @rm -f core ruby$(binsuffix) *~ diff --git a/ext/pty/MANIFEST b/ext/pty/MANIFEST new file mode 100644 index 0000000000..be6ab42f99 --- /dev/null +++ b/ext/pty/MANIFEST @@ -0,0 +1,12 @@ +MANIFEST +Makefile +README +README.expect +README.expect.jp +README.jp +expect_sample.rb +extconf.rb +lib/expect.rb +pty.c +script.rb +shl.rb diff --git a/ext/pty/README b/ext/pty/README new file mode 100644 index 0000000000..a09469d39c --- /dev/null +++ b/ext/pty/README @@ -0,0 +1,93 @@ +pty extension version 0.3 by A.ito + +1. Introduction + +This extension module adds ruby a functionality to execute an +arbitrary command through pseudo tty (pty). + +2. Install + +Follow the instruction below. + +(1) Execute + + ruby extconf.rb + + then Makefile is generated. + +(3) Do make; make install. + +3. What you can do + +This extension module defines a module named PTY, which contains +following module fungtions: + + getpty(command) + spawn(command) + + This function reserves a pty, executes command over the pty + and returns an array. The return value is an array with three + elements. The first element in the array is for reading and the + second for writing. The third element is the process ID of the + child process. If this function is called with an iterator block, + the array is passed to the block as block parameters, and the + function itself returns nil. + + While the process spawned by this function is active, SIGCHLD + is captured to handle the change of the child process. When the + child process is suspended or finished, an exception is raised. + As all SIGCHLD signal is captured and processed by PTY module, + you can't use other function or method which spawns subprosesses + (including signal() and IO.popen()) while the PTY subprocesses + are active. Otherwise, unexpected exception will occur. To avoid + this problem, see protect_signal() below. + + If this function is called with an iterator block, SIGCHLD signal + is captured only within the block. Therefore, it is risky to use + File objects for PTY subprocess outside the iterator block. + + + protect_signal + + This function takes an iterator block. Within the iterator block, + no exception is raised even if any subprocess is terminated. + This function is used to enable functions like system() or IO.popen() + while PTY subprocess is active. For example, + + PTY.spawn("command_foo") do |r,w| + ... + ... + PTY.protect_signal do + system "some other commands" + end + ... + end + + disables to send exception when "some other commands" is + terminated. + + reset_signal + + Disables to handle SIGCHLD while PTY subprocess is active. + + +4. License + +(C) Copyright 1998 by Akinori Ito. + +This software may be redistributed freely for this purpose, in full +or in part, provided that this entire copyright notice is included +on any copies of this software and applications and derivations thereof. + +This software is provided on an "as is" basis, without warranty of any +kind, either expressed or implied, as to any matter including, but not +limited to warranty of fitness of purpose, or merchantability, or +results obtained from use of this software. + +5. Bug report + +Please feel free to send E-mail to + + aito@ei5sun.yz.yamagata-u.ac.jp + +for any bug report, opinion, contribution, etc. diff --git a/ext/pty/README.expect b/ext/pty/README.expect new file mode 100644 index 0000000000..fddbb6fdad --- /dev/null +++ b/ext/pty/README.expect @@ -0,0 +1,22 @@ + README for expect + by A. Ito, 28 October, 1998 + + Expect library adds IO class a method called expect(), which +does similar act to tcl's expect extension. + +The usage of the method is: + + IO#expect(pattern,timeout=9999999) + +where `pattern' is an instance of String or Regexp and `timeout' +is Fixnum, which can be omitted. + When the method is called without block, it waits until the +input which matches the pattern is obtained from the IO or the time +specified as the timeout passes. When the pattern is obtained from the +IO, the method returns an array. The first element of the array is the +entire string obtained from the IO until the pattern matches. The +following elements indicates the specific pattern which matched to the +anchor in the regular expression. If the method ends because of +timeout, it returns nil. + When the method is called with block, the array is passed as +the block parameter. diff --git a/ext/pty/README.expect.jp b/ext/pty/README.expect.jp new file mode 100644 index 0000000000..db84695ee5 --- /dev/null +++ b/ext/pty/README.expect.jp @@ -0,0 +1,21 @@ + README for expect + by A. Ito, 28 October, 1998 + + Expectライブラリは,tcl の expect パッケージと似たような機能を +IOクラスに追加します. + + 追加されるメソッドの使い方は次の通りです. + + IO#expect(pattern,timeout=9999999) + +pattern は String か Regexp のインスタンス,timeout は Fixnum +のインスタンスです.timeout は省略できます. + このメソッドがブロックなしで呼ばれた場合,まずレシーバである +IOオブジェクトから pattern にマッチするパターンが読みこまれる +まで待ちます.パターンが得られたら,そのパターンに関する配列を +返します.配列の最初の要素は,pattern にマッチするまでに読みこ +まれた内容の文字列です.2番目以降の要素は,pattern の正規表現 +の中にアンカーがあった場合に,そのアンカーにマッチする部分です. +もしタイムアウトが起きた場合は,このメソッドはnilを返します. + このメソッドがブロック付きで呼ばれた場合には,マッチした要素の +配列がブロック引数として渡され,ブロックが評価されます. diff --git a/ext/pty/README.jp b/ext/pty/README.jp new file mode 100644 index 0000000000..5ae4fb06a0 --- /dev/null +++ b/ext/pty/README.jp @@ -0,0 +1,89 @@ +pty 拡張モジュール version 0.3 by A.ito + +1. はじめに + +この拡張モジュールは,仮想tty (pty) を通して適当なコマンドを +実行する機能を ruby に提供します. + +2. インストール + +次のようにしてインストールしてください. + +(1) ruby extconf.rb + + を実行すると Makefile が生成されます. + +(2) make; make install を実行してください. + +3. 何ができるか + +この拡張モジュールは,PTY というモジュールを定義します.その中 +には,次のようなモジュール関数が含まれています. + + getpty(command) + spawn(command) + + この関数は,仮想ttyを確保し,指定されたコマンドをその仮想tty + の向こうで実行し,配列を返します.戻り値は3つの要素からなる + 配列です.最初の要素は仮想ttyから読み出すためのIOオブジェクト, + 2番目は書きこむためのIOオブジェクト,3番目は子プロセスのプロ + セスIDです.この関数がイテレータとして呼ばれた場合,これらの + 要素はブロックパラメータとして渡され,関数自体はnilを返します. + + この関数によって作られたサブプロセスが動いている間,子プロセス + の状態を監視するために SIGCHLD シグナルを捕捉します.子プロセス + が終了したり停止した場合には,例外が発生します.この間,すべての + SIGCHLD が PTY モジュールのシグナルハンドラに捕捉されるので, + サブプロセスを生成する他の関数(system() とか IO.popen()など)を + 使うと,予期しない例外が発生することがあります.これを防ぐため + には,下記のprotect_signal()を参照してください. + + この関数がブロックパラメータ付きで呼ばれた場合には,そのブロック + の中でのみ SIGCHLD が捕捉されます.したがって,ブロックパラメータ + として渡されたIOオブジェクトを,ブロックの外に持ち出して使うの + は勧められません. + + + protect_signal + + この関数はイテレータです.ここで指定されたブロックの中では, + 子プロセスが終了しても例外を発生しません.この関数を使うことで, + PTYの子プロセスが動いている間でも,system()や IO.popen()などの + 関数を安全に使うことができます.例えば, + + PTY.spawn("command_foo") do |r,w| + ... + ... + PTY.protect_signal do + system "some other commands" + end + ... + end + + このような記述により,"some other commands" が終了したときに + 例外が発生するのを防げます. + + reset_signal + + PTY の子プロセスが動いていても,そのプロセスの終了時に例外が発生 + しないようにします. + +4. 利用について + +伊藤彰則が著作権を保有します. + +ソースプログラムまたはドキュメントに元の著作権表示が改変されずに +表示されている場合に限り,誰でも,このソフトウェアを無償かつ著作 +権者に無断で利用・配布・改変できます.利用目的は限定されていませ +ん. + +このプログラムの利用・配布その他このプログラムに関係する行為によ +って生じたいかなる損害に対しても,作者は一切責任を負いません. + +5. バグ報告等 + +バグレポートは歓迎します. + + aito@ei5sun.yz.yamagata-u.ac.jp + +まで電子メールでバグレポートをお送りください. diff --git a/ext/pty/expect_sample.rb b/ext/pty/expect_sample.rb new file mode 100644 index 0000000000..c71adcb220 --- /dev/null +++ b/ext/pty/expect_sample.rb @@ -0,0 +1,56 @@ +# +# sample program of expect.rb +# +# by A. Ito +# +# This program reports the latest version of ruby interpreter +# by connecting to ftp server at netlab.co.jp. +# +require 'pty' +require 'expect' + +fnames = [] +PTY.spawn("ftp ftp.netlab.co.jp") do + |r_f,w_f| + w_f.sync = true + + $expect_verbose = true + + r_f.expect(/^Name.*: /) do + w_f.print "ftp\n" + end + + if !ENV['USER'].nil? + username = ENV['USER'] + elsif !ENV['LOGNAME'].nil? + username = ENV['LOGNAME'] + else + username = 'guest' + end + + r_f.expect('word:') do + w_f.print username+"@\n" + end + r_f.expect("ftp> ") do + w_f.print "cd pub/lang/ruby\n" + end + r_f.expect("ftp> ") do + w_f.print "dir\n" + end + + r_f.expect("ftp> ") do |output| + for x in output[0].split("\n") + if x =~ /(ruby.*\.tar\.gz)/ then + fnames.push $1 + end + end + end + begin + w_f.print "quit\n" + rescue + end +end + +print "The latest ruby interpreter is " +print fnames.sort.pop +print "\n" diff --git a/ext/pty/extconf.rb b/ext/pty/extconf.rb new file mode 100644 index 0000000000..de9517ec0c --- /dev/null +++ b/ext/pty/extconf.rb @@ -0,0 +1,9 @@ +require 'mkmf' + +have_header("sys/stropts.h") +have_func("setresuid") +if have_func("openpty") or + have_func("_getpty") or + have_func("ioctl") + create_makefile('pty') +end diff --git a/ext/pty/lib/expect.rb b/ext/pty/lib/expect.rb new file mode 100644 index 0000000000..54c69edadb --- /dev/null +++ b/ext/pty/lib/expect.rb @@ -0,0 +1,36 @@ +$expect_verbose = false + +class IO + def expect(pat,timeout=9999999) + buf = '' + case pat + when String + e_pat = Regexp.new(Regexp.quote(pat)) + when Regexp + e_pat = pat + end + while true + if IO.select([self],nil,nil,timeout).nil? then + result = nil + break + end + c = getc.chr + buf << c + if $expect_verbose + STDOUT.print c + STDOUT.flush + end + if buf =~ e_pat then + result = [buf,$1,$2,$3,$4,$5,$6,$7,$8,$9] + break + end + end + if iterator? then + yield result + else + return result + end + nil + end +end + diff --git a/ext/pty/pty.c b/ext/pty/pty.c new file mode 100644 index 0000000000..0995220995 --- /dev/null +++ b/ext/pty/pty.c @@ -0,0 +1,485 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#if !defined(HAVE_OPENPTY) && !defined(HAVE__GETPTY) +#include +#endif +#include +#include + +#include +#include + +#include +#ifdef HAVE_SYS_STROPTS_H +#include +#endif + +#define DEVICELEN 16 + +#if !defined(HAVE_OPENPTY) +#ifdef hpux +char *MasterDevice = "/dev/ptym/pty%s", + *SlaveDevice = "/dev/pty/tty%s", + *deviceNo[] = { + "p0","p1","p2","p3","p4","p5","p6","p7", + "p8","p9","pa","pb","pc","pd","pe","pf", + "q0","q1","q2","q3","q4","q5","q6","q7", + "q8","q9","qa","qb","qc","qd","qe","qf", + "r0","r1","r2","r3","r4","r5","r6","r7", + "r8","r9","ra","rb","rc","rd","re","rf", + "s0","s1","s2","s3","s4","s5","s6","s7", + "s8","s9","sa","sb","sc","sd","se","sf", + "t0","t1","t2","t3","t4","t5","t6","t7", + "t8","t9","ta","tb","tc","td","te","tf", + "u0","u1","u2","u3","u4","u5","u6","u7", + "u8","u9","ua","ub","uc","ud","ue","uf", + "v0","v1","v2","v3","v4","v5","v6","v7", + "v8","v9","va","vb","vc","vd","ve","vf", + "w0","w1","w2","w3","w4","w5","w6","w7", + "w8","w9","wa","wb","wc","wd","we","wf", + 0, + }; +#else /* NOT HPUX */ +#ifdef _IBMESA /* AIX/ESA */ +char *MasterDevice = "/dev/ptyp%s", + *SlaveDevice = "/dev/ttyp%s", + *deviceNo[] = { +"00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f", +"10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f", +"20","21","22","23","24","25","26","27","28","29","2a","2b","2c","2d","2e","2f", +"30","31","32","33","34","35","36","37","38","39","3a","3b","3c","3d","3e","3f", +"40","41","42","43","44","45","46","47","48","49","4a","4b","4c","4d","4e","4f", +"50","51","52","53","54","55","56","57","58","59","5a","5b","5c","5d","5e","5f", +"60","61","62","63","64","65","66","67","68","69","6a","6b","6c","6d","6e","6f", +"70","71","72","73","74","75","76","77","78","79","7a","7b","7c","7d","7e","7f", +"80","81","82","83","84","85","86","87","88","89","8a","8b","8c","8d","8e","8f", +"90","91","92","93","94","95","96","97","98","99","9a","9b","9c","9d","9e","9f", +"a0","a1","a2","a3","a4","a5","a6","a7","a8","a9","aa","ab","ac","ad","ae","af", +"b0","b1","b2","b3","b4","b5","b6","b7","b8","b9","ba","bb","bc","bd","be","bf", +"c0","c1","c2","c3","c4","c5","c6","c7","c8","c9","ca","cb","cc","cd","ce","cf", +"d0","d1","d2","d3","d4","d5","d6","d7","d8","d9","da","db","dc","dd","de","df", +"e0","e1","e2","e3","e4","e5","e6","e7","e8","e9","ea","eb","ec","ed","ee","ef", +"f0","f1","f2","f3","f4","f5","f6","f7","f8","f9","fa","fb","fc","fd","fe","ff", + }; +#else +char *MasterDevice = "/dev/pty%s", + *SlaveDevice = "/dev/tty%s", + *deviceNo[] = { + "p0","p1","p2","p3","p4","p5","p6","p7", + "p8","p9","pa","pb","pc","pd","pe","pf", + "q0","q1","q2","q3","q4","q5","q6","q7", + "q8","q9","qa","qb","qc","qd","qe","qf", + "r0","r1","r2","r3","r4","r5","r6","r7", + "r8","r9","ra","rb","rc","rd","re","rf", + 0, + }; +#endif /* _IBMESA */ +#endif /* HPUX */ +#endif /* !defined(HAVE_OPENPTY) */ + +char SlaveName[DEVICELEN]; + +extern int errno; + +#define MAX_PTY 16 +static int n_pty,last_pty; +static int chld_pid[MAX_PTY]; + +#ifndef HAVE_SETEUID +# ifdef HAVE_SETREUID +# define seteuid(e) setreuid(-1, (e)) +# else /* NOT HAVE_SETREUID */ +# ifdef HAVE_SETRESUID +# define seteuid(e) setresuid(-1, (e), -1) +# else /* NOT HAVE_SETRESUID */ + /* I can't set euid. (;_;) */ +# endif /* HAVE_SETRESUID */ +# endif /* HAVE_SETREUID */ +#endif /* NO_SETEUID */ + +struct pty_info { + int fd; + pid_t child_pid; +}; + +static void +set_signal_action(RETSIGTYPE (*action)()) +{ +#ifdef hpux + struct sigvec sv; + /* + * signal SIGCHLD should be delivered on stop of the child + */ + sv.sv_handler = action; + sv.sv_mask = sigmask(SIGCHLD); + sv.sv_flags = SV_BSDSIG; + sigvector(SIGCHLD, &sv, (struct sigvec *) 0); +#else /* not HPUX */ +#if defined(SA_NOCLDSTOP) + struct sigaction sa; + /* + * signal SIGCHLD should be delivered on stop of the child + * (for SVR4) + */ + sa.sa_handler = action; + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGCHLD); + sa.sa_flags = 0; /* SA_NOCLDSTOP flag is removed */ + sigaction(SIGCHLD, &sa, (struct sigaction *) 0); +#else + signal(SIGCHLD,action); +#endif +#endif /* not HPUX */ + +} + +static void +reset_signal_action() +{ + set_signal_action(SIG_DFL); +} + +static RETSIGTYPE +chld_changed() +{ + int cpid; + int i,n = -1; + int statusp; + + for (;;) { +#ifdef HAVE_WAITPID + cpid = waitpid(-1, &statusp, WUNTRACED|WNOHANG); +#else + cpid = wait3((int *) &statusp, WUNTRACED|WNOHANG, 0); +#endif + if (cpid == 0 || cpid == -1) + return; + for (i = 0; i < last_pty; i++) { + if (chld_pid[i] == cpid) { + n = i; + goto catched; + } + } + rb_raise(rb_eRuntimeError, "fork: %d", cpid); + } + catched: + +#ifdef IF_STOPPED + if (IF_STOPPED(statusp)) { /* suspend */ + rb_raise(rb_eRuntimeError, "Stopped: %d",cpid); + } +#else +#ifdef WIFSTOPPED + if (WIFSTOPPED(statusp)) { /* suspend */ + rb_raise(rb_eRuntimeError, "Stopped: %d",cpid); + } +#else +#error "Either IF_STOPPED or WIFSTOPPED is needed" +#endif /* WIFSTOPPED */ +#endif /* IF_STOPPED */ + if (n >= 0) { + chld_pid[n] = 0; + n_pty--; + if (n_pty == 0) + reset_signal_action(); + } + rb_raise(rb_eRuntimeError, "Child_changed: %d",cpid); +} + +static void getDevice _((int*, int*)); + +static void +establishShell(char *shellname, struct pty_info *info) +{ + static int i,j,master,slave,currentPid; + static char procName[32]; + char *p,*getenv(); + struct passwd *pwent; + RETSIGTYPE chld_changed(); + + if (shellname[0] == '\0') { + if ((p = getenv("SHELL")) != NULL) { + shellname = p; + } + else { + pwent = getpwuid(getuid()); + if (pwent && pwent->pw_shell) + shellname = pwent->pw_shell; + else + shellname = "/bin/sh"; + } + } + getDevice(&master,&slave); + + currentPid = getpid(); + set_signal_action(chld_changed); + if((i = vfork()) < 0) { + rb_sys_fail("fork failed"); + } + + if(i == 0) { /* child */ + int argc; + char *argv[1024]; + currentPid = getpid(); + + /* + * Set free from process group and controlling terminal + */ +#ifdef HAVE_SETSID + (void) setsid(); +#else /* HAS_SETSID */ +# ifdef HAVE_SETPGRP +# ifdef SETGRP_VOID + if (setpgrp() == -1) + perror("setpgrp()"); +# else /* SETGRP_VOID */ + if (setpgrp(0, currentPid) == -1) + rb_sys_fail("setpgrp()"); + if ((i = open("/dev/tty", O_RDONLY)) < 0) + rb_sys_fail("/dev/tty"); + else { + if (ioctl(i, TIOCNOTTY, (char *)0)) + perror("ioctl(TIOCNOTTY)"); + close(i); + } +# endif /* SETGRP_VOID */ +# endif /* HAVE_SETPGRP */ +#endif /* HAS_SETSID */ + + /* + * obtain new controlling terminal + */ +#if defined(TIOCSCTTY) + close(master); + (void) ioctl(slave, TIOCSCTTY, (char *)0); + /* errors ignored for sun */ +#else + close(slave); + slave = open(SlaveName, O_RDWR); + if (slave < 0) { + perror("open: pty slave"); + _exit(1); + } + close(master); +#endif + dup2(slave,0); + dup2(slave,1); + dup2(slave,2); + close(slave); + + seteuid(getuid()); + + argc = 0; + for (i = 0; shellname[i];) { + while (isspace(shellname[i])) i++; + for (j = i; shellname[j] && !isspace(shellname[j]); j++); + argv[argc] = (char*)xmalloc(j-i+1); + strncpy(argv[argc],&shellname[i],j-i); + argv[argc][j-i] = 0; + i = j; + argc++; + } + argv[argc] = NULL; + execvp(argv[0],argv); + sleep(1); + _exit(1); + } + + close(slave); + + if (n_pty == last_pty) { + chld_pid[n_pty] = i; + n_pty++; + last_pty++; + } + else { + for (j = 0; j < last_pty; j++) { + if (chld_pid[j] == 0) { + chld_pid[j] = i; + n_pty++; + } + } + } + info->child_pid = i; + info->fd = master; +} + +#ifdef HAVE_OPENPTY +/* + * Use openpty(3) of 4.3BSD Reno and later, + * or the same interface function. + */ +static void +getDevice(master,slave) + int *master,*slave; +{ + if (openpty(master, slave, SlaveName, + (struct termios *)0, (struct winsize *)0) == -1) { + rb_raise(rb_eRuntimeError, "openpty() failed"); + } +} +#else /* HAVE_OPENPTY */ +#ifdef HAVE__GETPTY +static void +getDevice(master,slave) + int *master,*slave; +{ + char *name; + + if (!(name = _getpty(master, O_RDWR, 0622, 0))) { + rb_raise(rb_eRuntimeError, "_getpty() failed"); + } + + *slave = open(name, O_RDWR); + strcpy(SlaveName, name); +} +#else /* HAVE__GETPTY */ +static void +getDevice(master,slave) + int *master,*slave; +{ + char **p; + int i,j; + char MasterName[DEVICELEN]; + +#ifdef HAVE_DEV_PTMX + char *pn; + void (*s)(); + + extern char *ptsname(int); + extern int unlockpt(int); + extern int grantpt(int); + + if((i = open("/dev/ptmx", O_RDWR, 0)) != -1) { + s = signal(SIGCHLD, SIG_DFL); + if(grantpt(i) != -1) { + signal(SIGCHLD, s); + if(unlockpt(i) != -1) { + if((pn = ptsname(i)) != NULL) { + if((j = open(pn, O_RDWR, 0)) != -1) { + if(ioctl(j, I_PUSH, "ptem") != -1) { + if(ioctl(j, I_PUSH, "ldterm") != -1) { + *master = i; + *slave = j; + strcpy(SlaveName, pn); + return; + } + } + } + } + } + } + close(i); + } + rb_raise(rb_eRuntimeError, "Cannot get Master/Slave device"); +#else + for (p = deviceNo; *p != NULL; p++) { + sprintf(MasterName ,MasterDevice,*p); + if ((i = open(MasterName,O_RDWR,0)) >= 0) { + *master = i; + sprintf(SlaveName ,SlaveDevice,*p); + if ((j = open(SlaveName,O_RDWR,0)) >= 0) { + *slave = j; + chown(SlaveName, getuid(), getgid()); + chmod(SlaveName, 0622); + return; + } + close(i); + } + } + rb_raise(rb_eRuntimeError, "Cannot get %s\n", SlaveDevice); +#endif +} +#endif /* HAVE__GETPTY */ +#endif /* HAVE_OPENPTY */ + +static void +freeDevice() +{ + chmod(SlaveName, 0666); + chown(SlaveName, 0, 0); +} + +/* ruby function: getpty */ +static VALUE +pty_getpty(self, shell) + VALUE self, shell; +{ + VALUE res; + struct pty_info info; + OpenFile *wfptr,*rfptr; + NEWOBJ(rport, struct RFile); + NEWOBJ(wport, struct RFile); + + if (n_pty == MAX_PTY+1) { + rb_raise(rb_eRuntimeError, "Too many ptys are open"); + } + + OBJSETUP(rport, rb_cFile, T_FILE); + MakeOpenFile(rport, rfptr); + + OBJSETUP(wport, rb_cFile, T_FILE); + MakeOpenFile(wport, wfptr); + + establishShell(RSTRING(shell)->ptr,&info); + + rfptr->mode = rb_io_mode_flags("r"); + rfptr->f = fdopen(info.fd, "r"); + rfptr->path = strdup(RSTRING(shell)->ptr); + rb_obj_call_init((VALUE)rport, 1, &shell); + + wfptr->mode = rb_io_mode_flags("w"); + wfptr->f = fdopen(dup(info.fd), "w"); + wfptr->path = strdup(RSTRING(shell)->ptr); + rb_obj_call_init((VALUE)wport, 1, &shell); + + res = rb_ary_new2(2); + rb_ary_store(res,0,(VALUE)rport); + rb_ary_store(res,1,(VALUE)wport); + rb_ary_store(res,2,INT2FIX(info.child_pid)); + + if (rb_iterator_p()) { + rb_yield((VALUE)res); + reset_signal_action(); + return Qnil; + } + else { + return (VALUE)res; + } +} + +/* ruby function: protect_signal */ +static VALUE +pty_protect(self) + VALUE self; +{ + reset_signal_action(); + rb_yield(Qnil); + set_signal_action(chld_changed); + return self; +} + +static VALUE +pty_reset_signal(self) + VALUE self; +{ + reset_signal_action(); + return self; +} + +static VALUE cPTY; + +void +Init_pty() +{ + cPTY = rb_define_module("PTY"); + rb_define_module_function(cPTY,"getpty",pty_getpty,1); + rb_define_module_function(cPTY,"spawn",pty_getpty,1); + rb_define_module_function(cPTY,"protect_signal",pty_protect,0); + rb_define_module_function(cPTY,"reset_signal",pty_reset_signal,0); +} diff --git a/ext/pty/script.rb b/ext/pty/script.rb new file mode 100644 index 0000000000..6c4027e6b3 --- /dev/null +++ b/ext/pty/script.rb @@ -0,0 +1,38 @@ +require 'pty' + +if ARGV.size == 0 then + ofile = "typescript" +else + ofile = ARGV[0] +end + +logfile = File.open(ofile,"a") + +system "stty -echo raw lnext ^_" + +PTY.spawn("/bin/csh") do + |r_pty,w_pty| + + Thread.new do + while true + w_pty.print STDIN.getc.chr + w_pty.flush + end + end + + begin + while true + c = r_pty.getc + next if c.nil? + print c.chr + STDOUT.flush + logfile.print c.chr + end + rescue + # print $@,':',$!,"\n" + logfile.close + end +end + +system "stty echo -raw lnext ^v" + diff --git a/ext/pty/shl.rb b/ext/pty/shl.rb new file mode 100644 index 0000000000..0c04a2735c --- /dev/null +++ b/ext/pty/shl.rb @@ -0,0 +1,96 @@ +# +# old-fashioned 'shl' like program +# by A. Ito +# +# commands: +# c creates new shell +# C-z suspends shell +# p lists all shell +# 0,1,... choose shell +# q quit + +require 'pty' + +$shells = [] +$n_shells = 0 + +$r_pty = nil +$w_pty = nil + +def writer + PTY.protect_signal do + system "stty -echo raw" + end + begin + while true + c = STDIN.getc + if c == 26 then # C-z + $reader.raise(nil) + return 'Suspend' + end + $w_pty.print c.chr + $w_pty.flush + end + rescue + $reader.raise(nil) + return 'Exit' + ensure + PTY.protect_signal do + system "stty echo -raw" + end + end +end + +$reader = Thread.new { + while true + begin + next if $r_pty.nil? + c = $r_pty.getc + if c.nil? then + Thread.stop + end + print c.chr + STDOUT.flush + rescue + Thread.stop + end + end +} + +# $reader.raise(nil) + + +while true + print ">> " + STDOUT.flush + case gets + when /^c/i + $shells[$n_shells] = PTY.spawn("/bin/csh") + $r_pty,$w_pty = $shells[$n_shells] + $n_shells += 1 + $reader.run + if writer == 'Exit' + $n_shells -= 1 + $shells[$n_shells] = nil + end + when /^p/i + for i in 0..$n_shells + unless $shells[i].nil? + print i,"\n" + end + end + when /^([0-9]+)/ + n = $1.to_i + if $shells[n].nil? + print "\##{i} doesn't exist\n" + else + $r_pty,$w_pty = $shells[n] + $reader.run + if writer == 'Exit' then + $shells[n] = nil + end + end + when /^q/i + exit + end +end diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb index 28a96f4b38..12b24667b4 100644 --- a/ext/socket/extconf.rb +++ b/ext/socket/extconf.rb @@ -239,45 +239,20 @@ end $objs = ["socket.o"] if $getaddr_info_ok - if have_func("getaddrinfo") and - have_func("getnameinfo") + if have_func("getaddrinfo") and have_func("getnameinfo") have_getaddrinfo = true end end if have_getaddrinfo $CFLAGS="-DHAVE_GETADDRINFO "+$CFLAGS - if try_link(< -#include -#include -#include -#include -int -main() -{ - struct sockaddr_storage storage; - struct sockaddr_storage *addr = 0; - - addr->__ss_family = &storage.__ss_family; - addr->__ss_len = &storage.__ss_len; - return 0; -} -EOF - sockaddr_storage=true - $CFLAGS+=" -DHAVE_SS_LEN" - end else sockaddr_storage=true $CFLAGS="-I. "+$CFLAGS $objs += "getaddrinfo.o" $objs += "getnameinfo.o" - have_func("inet_ntop") - have_func("inet_pton") -end - -if sockaddr_storage - $CFLAGS="-DSOCKADDR_STORAGE=sockaddr_storage "+$CFLAGS + have_func("inet_ntop") or have_func("inet_ntoa") + have_func("inet_pton") or have_func("inet_aton") end have_header("sys/un.h") @@ -287,7 +262,7 @@ if have_func(test_func) unless have_func("gethostname") have_func("uname") end - if ENV["SOCKS_SERVER"] # test if SOCKSsocket needed + if ENV["SOCKS_SERVER"] or enable_config("socks", false) if have_library("socks", "Rconnect") $CFLAGS="-DSOCKS" end diff --git a/ext/socket/getaddrinfo.c b/ext/socket/getaddrinfo.c index fc3f654cee..64d29b17ab 100644 --- a/ext/socket/getaddrinfo.c +++ b/ext/socket/getaddrinfo.c @@ -212,20 +212,32 @@ str_isnumber(p) #ifndef HAVE_INET_PTON -#ifndef INADDR_NONE -# define INADDR_NONE 0xffffffff -#endif - static int inet_pton(af, hostname, pton) int af; const char *hostname; - char *pton; + void *pton; { struct in_addr in; - in.s_addr = inet_addr(hostname); - if (in.s_addr == INADDR_NONE) - return 0; + +#ifdef HAVE_INET_ATON + if (!inet_aton(hostname, &in.s_addr)) + return 0; +#else + int d1, d2, d3, d4; + char ch; + + if (sscanf(hostname, "%d.%d.%d.%d%c", &d1, &d2, &d3, &d4, &ch) == 4 && + 0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 && + 0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) { + in.s_addr = htonl( + ((long) d1 << 24) | ((long) d2 << 16) | + ((long) d3 << 8) | ((long) d4 << 0)); + } + else { + return 0; + } +#endif memcpy(pton, &in, sizeof(in)); return 1; } diff --git a/ext/socket/getnameinfo.c b/ext/socket/getnameinfo.c index e217b50895..e4a57c6554 100644 --- a/ext/socket/getnameinfo.c +++ b/ext/socket/getnameinfo.c @@ -83,16 +83,23 @@ struct sockinet { #define ENI_SALEN 6 #ifndef HAVE_INET_NTOP -static char * +static const char * inet_ntop(af, addr, numaddr, numaddr_len) int af; - char *addr; + __const void *addr; char *numaddr; - int numaddr_len; + size_t numaddr_len; { +#ifdef HAVE_INET_NTOA struct in_addr in; memcpy(&in.s_addr, addr, sizeof(in.s_addr)); - strcpy(numaddr, inet_ntoa(in)); + strncpy(numaddr, numaddr_len, inet_ntoa(in)); +#else + unsigned long x = ntohl(*(unsigned long*)addr); + snprintf(numaddr, numaddr_len, "%d.%d.%d.%d", + (int) (x>>24) & 0xff, (int) (x>>16) & 0xff, + (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff); +#endif return numaddr; } #endif diff --git a/ext/socket/socket.c b/ext/socket/socket.c index b0f108a2c1..6126ddf2b9 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -49,14 +49,6 @@ extern int rb_thread_select(int, fd_set*, fd_set*, fd_set*, struct timeval*); /* #endif #include "sockport.h" -#ifdef SOCKADDR_STORAGE -# define SS_LEN(ss) (ss)->ss_len -#else -# define SOCKADDR_STORAGE sockaddr -# undef ss_family -# define ss_family sa_family -#endif - VALUE rb_cBasicSocket; VALUE rb_cIPSocket; VALUE rb_cTCPSocket; @@ -700,7 +692,7 @@ static VALUE tcp_s_gethostbyname(obj, host) VALUE obj, host; { - struct SOCKADDR_STORAGE addr; + struct sockaddr addr; struct hostent *h; char **pch; VALUE ary, names; @@ -717,7 +709,7 @@ tcp_s_gethostbyname(obj, host) else { setipaddr(STR2CSTR(host), (struct sockaddr *)&addr); } - switch (addr.ss_family) { + switch (addr.sa_family) { case AF_INET: { struct sockaddr_in *sin; @@ -760,7 +752,7 @@ tcp_s_gethostbyname(obj, host) rb_ary_push(ary, INT2NUM(h->h_addrtype)); #ifdef h_addr for (pch = h->h_addr_list; *pch; pch++) { - switch (addr.ss_family) { + switch (addr.sa_family) { case AF_INET: { struct sockaddr_in sin; @@ -849,7 +841,7 @@ tcp_accept(sock) VALUE sock; { OpenFile *fptr; - struct SOCKADDR_STORAGE from; + struct sockaddr from; int fromlen; GetOpenFile(sock, fptr); @@ -915,7 +907,7 @@ ip_addr(sock) VALUE sock; { OpenFile *fptr; - struct SOCKADDR_STORAGE addr; + struct sockaddr addr; int len = sizeof addr; GetOpenFile(sock, fptr); @@ -930,7 +922,7 @@ ip_peeraddr(sock) VALUE sock; { OpenFile *fptr; - struct SOCKADDR_STORAGE addr; + struct sockaddr addr; int len = sizeof addr; GetOpenFile(sock, fptr); @@ -944,7 +936,7 @@ static VALUE ip_s_getaddress(obj, host) VALUE obj, host; { - struct SOCKADDR_STORAGE addr; + struct sockaddr addr; if (rb_obj_is_kind_of(host, rb_cInteger)) { int i = NUM2INT(host); @@ -1068,7 +1060,7 @@ static VALUE udp_bind(sock, host, port) VALUE sock, host, port; { - struct SOCKADDR_STORAGE addr; + struct sockaddr addr; OpenFile *fptr; struct addrinfo *res0, *res; @@ -1538,7 +1530,7 @@ static VALUE sock_s_gethostbyname(obj, host) VALUE obj, host; { - struct SOCKADDR_STORAGE addr; + struct sockaddr addr; struct hostent *h; if (rb_obj_is_kind_of(host, rb_cInteger)) { @@ -1553,7 +1545,7 @@ sock_s_gethostbyname(obj, host) else { setipaddr(STR2CSTR(host), (struct sockaddr *)&addr); } - switch (addr.ss_family) { + switch (addr.sa_family) { case AF_INET: { struct sockaddr_in *sin; @@ -1709,7 +1701,7 @@ sock_s_getnameinfo(argc, argv) int fl; struct addrinfo hints, *res = NULL; int error; - struct SOCKADDR_STORAGE ss; + struct sockaddr ss; struct sockaddr *sap; sa = flags = Qnil; @@ -1720,11 +1712,9 @@ sock_s_getnameinfo(argc, argv) rb_raise(rb_eTypeError, "sockaddr length too big"); } memcpy(&ss, RSTRING(sa)->ptr, RSTRING(sa)->len); -#ifdef HAVE_SS_LEN - if (RSTRING(sa)->len != SS_LEN(&ss)) { + if (RSTRING(sa)->len != SA_LEN(&ss)) { rb_raise(rb_eTypeError, "sockaddr size differs - should not happen"); } -#endif sap = (struct sockaddr *)&ss; } else if (TYPE(sa) == T_ARRAY) { diff --git a/glob.c b/glob.c deleted file mode 100644 index 57723d8fc7..0000000000 --- a/glob.c +++ /dev/null @@ -1,595 +0,0 @@ -/* 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. */ - -#include "config.h" - -#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) - #pragma alloca -#endif /* _AIX && RISC6000 && !__GNUC__ */ - -#if defined (HAVE_ALLOCA_H) -# include -#endif - -#if defined (HAVE_UNISTD_H) -# include -#endif - -#if defined (HAVE_STDLIB_H) -# include -#else -# if defined (SHELL) -# include "ansi_stdlib.h" -# endif /* SHELL */ -#endif - -#include - -#if defined (HAVE_DIRENT_H) -# include -# define D_NAMLEN(d) strlen ((d)->d_name) -#elif HAVE_DIRECT_H -# include -# define D_NAMLEN(d) strlen ((d)->d_name) -#else /* !HAVE_DIRENT_H */ -# define D_NAMLEN(d) ((d)->d_namlen) -# if defined (HAVE_SYS_NDIR_H) -# include -# endif -# if defined (HAVE_SYS_DIR_H) -# include -# endif /* HAVE_SYS_DIR_H */ -# if defined (HAVE_NDIR_H) -# include -# endif -# if !defined (dirent) -# define dirent direct -# endif -#endif /* !HAVE_DIRENT_H */ - -#if defined (_POSIX_SOURCE) || defined(DJGPP) || defined(USE_CWGUSI) -/* Posix does not require that the d_ino field be present, and some - systems do not provide it. */ -# define REAL_DIR_ENTRY(dp) 1 -#elif defined (__BORLANDC__) -# define REAL_DIR_ENTRY(dp) 1 -#else -# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) -#endif /* _POSIX_SOURCE */ - -#if defined (HAVE_STRING_H) -# include -#else /* !HAVE_STRING_H */ -# include -#endif /* !HAVE_STRING_H */ - -#if !defined (HAVE_BCOPY) && !defined (bcopy) -# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n))) -#endif /* !HAVE_BCOPY */ - -/* If the opendir () on your system lets you open non-directory files, - then we consider that not robust. */ -#if defined (OPENDIR_NOT_ROBUST) -# if defined (SHELL) -# include "posixstat.h" -# else /* !SHELL */ -# include -# endif /* !SHELL */ -#endif /* OPENDIR_NOT_ROBUST */ - -#ifdef HAVE_FNMATCH_H -#include -#else -#include "missing/fnmatch.h" -#endif - -extern void *xmalloc (), *xrealloc (); -#if !defined (HAVE_STDLIB_H) -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 void throw_to_top_level (); - -extern int interrupt_state; -#endif /* SHELL */ - -#if defined(NT) && defined(_MSC_VER) -#include "missing/dir.h" -#endif - -/* 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 dirent *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 *) xmalloc (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] != '.' && - (pat[0] != '\\' || pat[1] != '.')) - 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 *) xmalloc (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 **) xmalloc ((count + 1) * sizeof (char *)); - lose |= name_vector == NULL; - } - - /* Have we run out of memory? */ -#if defined (SHELL) - lost: -#endif - 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 **) xmalloc ((i + 1) * sizeof (char *)); - if (result == NULL) - return (NULL); - - for (i = 0; array[i] != NULL; i++) - { - result[i] = (char *) xmalloc (l + (add_slash ? 1 : 0) - + strlen (array[i]) + 1); - if (result[i] == NULL) - return (NULL); -#if 1 - strcpy (result[i], dir); - if (add_slash) - result[i][l] = '/'; - strcpy (result[i] + l + add_slash, array[i]); -#else - (void)sprintf (result[i], "%s%s%s", dir, add_slash ? "/" : "", array[i]); -#endif - } - 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; -{ -#ifndef strrchr - char *strrchr(); -#endif - - char **result; - unsigned int result_size; - char *directory_name, *filename; - unsigned int directory_len; - - result = (char **) xmalloc (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) - { - free ((char *) result); - return ((char **) &glob_error_return); - } - else if (*directories == NULL) - { - free ((char *) directories); - free ((char *) result); - 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 **)xrealloc(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 **) xrealloc ((char *) result, 2 * sizeof (char *)); - if (result == NULL) - return (NULL); - result[0] = (char *) xmalloc (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. */ diff --git a/lib/mkmf.rb b/lib/mkmf.rb index aceb665e0b..c697ade271 100644 --- a/lib/mkmf.rb +++ b/lib/mkmf.rb @@ -360,7 +360,7 @@ binsuffix = #{CONFIG["binsuffix"]} all: $(DLLIB) -clean:; @rm -f *.o *.so *.sl +clean:; @rm -f *.o *.so *.sl *.a @rm -f Makefile extconf.h conftest.* @rm -f core ruby$(binsuffix) *~ -- cgit v1.2.3