1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* ext/etc/etc.c: Etc.sysconf, Etc.confstr and IO#pathconf implemented.

* ext/etc/extconf.rb: Check sysconf(), confstr() and fpathconf().

* ext/etc/mkconstants.rb: New file.

 [ruby-core:62600] [Feature #9842]



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45984 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
akr 2014-05-18 01:48:47 +00:00
parent 63a23dc678
commit ea1a4f2929
8 changed files with 519 additions and 1 deletions

3
.gitignore vendored
View file

@ -110,6 +110,9 @@ y.tab.c
/ext/dl/callback/callback-*.c
/ext/dl/callback/callback.c
# /ext/etc/
/ext/etc/constdefs.h
# /ext/rbconfig/
/ext/rbconfig/sizeof/sizes.c

View file

@ -1,3 +1,13 @@
Sun May 18 10:46:04 2014 Tanaka Akira <akr@fsij.org>
* ext/etc/etc.c: Etc.sysconf, Etc.confstr and IO#pathconf implemented.
* ext/etc/extconf.rb: Check sysconf(), confstr() and fpathconf().
* ext/etc/mkconstants.rb: New file.
[ruby-core:62600] [Feature #9842]
Sun May 18 09:58:17 2014 Tanaka Akira <akr@fsij.org>
* ext/etc/etc.c: Etc.uname method implemented.

3
NEWS
View file

@ -86,6 +86,9 @@ with all sufficient information, see the ChangeLog file.
* Etc
* New methods:
* Etc.uname
* Etc.sysconf
* Etc.confstr
* IO#pathconf
* Find, Pathname
* Extended methods:

View file

@ -1,3 +1,8 @@
etc.o : etc.c $(HDRS) $(ruby_headers) \
etc.o : etc.c constdefs.h $(HDRS) $(ruby_headers) \
$(hdrdir)/ruby/encoding.h \
$(hdrdir)/ruby/oniguruma.h
constdefs.h : $(srcdir)/mkconstants.rb
@echo "generating constant definitions"
@$(RUBY) $(srcdir)/mkconstants.rb -o constdefs.h

View file

@ -9,6 +9,7 @@
#include "ruby.h"
#include "ruby/encoding.h"
#include "ruby/io.h"
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
@ -23,6 +24,8 @@
#include <grp.h>
#endif
#include <errno.h>
#ifdef HAVE_SYS_UTSNAME_H
#include <sys/utsname.h>
#endif
@ -44,6 +47,8 @@ char *getenv();
#endif
char *getlogin();
#include "constdefs.h"
/* call-seq:
* getlogin -> String
*
@ -684,6 +689,126 @@ etc_uname(VALUE obj)
#define etc_uname rb_f_notimplement
#endif
#ifdef HAVE_SYSCONF
/*
* Returns system configuration variable using sysconf().
*
* _name_ should be a constant undef <code>Etc</code> which begins with <code>SC_</code>.
*
* The return value is an integer or nil.
* nil means indefinite limit. (sysconf() returns -1 but errno is not set.)
*
* Etc.sysconf(Etc::SC_ARG_MAX) #=> 2097152
*
* # Number of processors.
* # It is not standardized.
* Etc.sysconf(Etc::SC_NPROCESSORS_ONLN) #=> 4
*
*/
static VALUE
etc_sysconf(VALUE obj, VALUE arg)
{
int name;
long ret;
name = NUM2INT(arg);
errno = 0;
ret = sysconf(name);
if (ret == -1) {
if (errno == 0) /* no limit */
return Qnil;
rb_sys_fail("sysconf");
}
return LONG2NUM(ret);
}
#else
#define etc_sysconf rb_f_notimplement
#endif
#ifdef HAVE_CONFSTR
/*
* Returns system configuration variable using confstr().
*
* _name_ should be a constant undef <code>Etc</code> which begins with <code>CS_</code>.
*
* The return value is a string or nil.
* nil means no configuration-defined value. (confstr() returns 0 but errno is not set.)
*
* Etc.confstr(Etc::CS_PATH) #=> "/bin:/usr/bin"
*
* # GNU/Linux
* Etc.confstr(Etc::CS_GNU_LIBC_VERSION) #=> "glibc 2.18"
* Etc.confstr(Etc::CS_GNU_LIBPTHREAD_VERSION) #=> "NPTL 2.18"
*
*/
static VALUE
etc_confstr(VALUE obj, VALUE arg)
{
int name;
char localbuf[128], *buf = localbuf;
size_t bufsize = sizeof(localbuf), ret;
VALUE tmp;
name = NUM2INT(arg);
errno = 0;
ret = confstr(name, buf, bufsize);
if (bufsize < ret) {
bufsize = ret;
buf = ALLOCV_N(char, tmp, bufsize);
errno = 0;
ret = confstr(name, buf, bufsize);
}
if (bufsize < ret)
rb_bug("required buffer size for confstr() changed dynamically.");
if (ret == 0) {
if (errno == 0) /* no configuration-defined value */
return Qnil;
rb_sys_fail("confstr");
}
return rb_str_new_cstr(buf);
}
#else
#define etc_confstr rb_f_notimplement
#endif
#ifdef HAVE_FPATHCONF
/*
* Returns pathname configuration variable using fpathconf().
*
* _name_ should be a constant undef <code>Etc</code> which begins with <code>PC_</code>.
*
* The return value is an integer or nil.
* nil means indefinite limit. (fpathconf() returns -1 but errno is not set.)
*
* open("/") {|f| p f.pathconf(Etc::PC_NAME_MAX) } #=> 255
*
*/
static VALUE
io_pathconf(VALUE io, VALUE arg)
{
int name;
long ret;
rb_io_t *fptr;
name = NUM2INT(arg);
GetOpenFile(io, fptr);
errno = 0;
ret = fpathconf(fptr->fd, name);
if (ret == -1) {
if (errno == 0) /* no limit */
return Qnil;
rb_sys_fail("fpathconf");
}
return LONG2NUM(ret);
}
#else
#define io_pathconf rb_f_notimplement
#endif
/*
* The Etc module provides access to information typically stored in
* files in the /etc directory on Unix systems.
@ -716,6 +841,8 @@ Init_etc(void)
VALUE mEtc;
mEtc = rb_define_module("Etc");
init_constants(mEtc);
rb_define_module_function(mEtc, "getlogin", etc_getlogin, 0);
rb_define_module_function(mEtc, "getpwuid", etc_getpwuid, -1);
@ -734,6 +861,9 @@ Init_etc(void)
rb_define_module_function(mEtc, "sysconfdir", etc_sysconfdir, 0);
rb_define_module_function(mEtc, "systmpdir", etc_systmpdir, 0);
rb_define_module_function(mEtc, "uname", etc_uname, 0);
rb_define_module_function(mEtc, "sysconf", etc_sysconf, 1);
rb_define_module_function(mEtc, "confstr", etc_confstr, 1);
rb_define_method(rb_cIO, "pathconf", io_pathconf, 1);
sPasswd = rb_struct_define_under(mEtc, "Passwd",
"name",

View file

@ -14,6 +14,10 @@ have_func("getgrent")
sysconfdir = RbConfig.expand(RbConfig::CONFIG["sysconfdir"].dup, "prefix"=>"", "DESTDIR"=>"")
$defs.push("-DSYSCONFDIR=#{Shellwords.escape(sysconfdir.dump)}")
have_func("sysconf")
have_func("confstr")
have_func("fpathconf")
have_struct_member('struct passwd', 'pw_gecos', 'pwd.h')
have_struct_member('struct passwd', 'pw_change', 'pwd.h')
have_struct_member('struct passwd', 'pw_quota', 'pwd.h')

329
ext/etc/mkconstants.rb Normal file
View file

@ -0,0 +1,329 @@
require 'optparse'
require 'erb'
C_ESC = {
"\\" => "\\\\",
'"' => '\"',
"\n" => '\n',
}
0x00.upto(0x1f) {|ch| C_ESC[[ch].pack("C")] ||= "\\%03o" % ch }
0x7f.upto(0xff) {|ch| C_ESC[[ch].pack("C")] = "\\%03o" % ch }
C_ESC_PAT = Regexp.union(*C_ESC.keys)
def c_str(str)
'"' + str.gsub(C_ESC_PAT) {|s| C_ESC[s]} + '"'
end
opt = OptionParser.new
opt.def_option('-h', 'help') {
puts opt
exit 0
}
opt_o = nil
opt.def_option('-o FILE', 'specify output file') {|filename|
opt_o = filename
}
opt_H = nil
opt.def_option('-H FILE', 'specify output header file') {|filename|
opt_H = filename
}
opt.parse!
h = {}
COMMENTS = Hash.new { |h, name| h[name] = name }
DATA.each_line {|s|
next if /\A\s*(\#|\z)/ =~ s
name, default_value, comment = s.chomp.split(/\s+/, 3)
default_value = nil if default_value == 'nil'
if h.has_key? name
warn "#{$.}: warning: duplicate name: #{name}"
next
end
h[name] = default_value
COMMENTS[name] = comment
}
DEFS = h.to_a
def each_const
DEFS.each {|name, default_value|
yield name, default_value
}
end
def each_name(pat)
DEFS.each {|name, default_value|
next if pat !~ name
yield name
}
end
ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_const_decls")
% each_const {|name, default_value|
#if !defined(<%=name%>)
# if defined(HAVE_CONST_<%=name.upcase%>)
# define <%=name%> <%=name%>
%if default_value
# else
# define <%=name%> <%=default_value%>
%end
# endif
#endif
% }
EOS
ERB.new(<<'EOS', nil, '%').def_method(Object, "gen_const_defs")
% each_const {|name, default_value|
#if defined(<%=name%>)
/* <%= COMMENTS[name] %> */
rb_define_const(mod, <%=c_str name.sub(/\A_*/, '')%>, INTEGER2NUM(<%=name%>));
#endif
% }
EOS
header_result = ERB.new(<<'EOS', nil, '%').result(binding)
/* autogenerated file */
<%= gen_const_decls %>
EOS
result = ERB.new(<<'EOS', nil, '%').result(binding)
/* autogenerated file */
#ifdef HAVE_LONG_LONG
#define INTEGER2NUM(n) \
(FIXNUM_MAX < (n) ? ULL2NUM(n) : \
FIXNUM_MIN > (LONG_LONG)(n) ? LL2NUM(n) : \
LONG2FIX(n))
#else
#define INTEGER2NUM(n) \
(FIXNUM_MAX < (n) ? ULONG2NUM(n) : \
FIXNUM_MIN > (long)(n) ? LONG2NUM(n) : \
LONG2FIX(n))
#endif
static void
init_constants(VALUE mod)
{
<%= gen_const_defs %>
}
EOS
if opt_H
File.open(opt_H, 'w') {|f|
f << header_result
}
else
result = header_result + result
end
if opt_o
File.open(opt_o, 'w') {|f|
f << result
}
else
$stdout << result
end
__END__
# SUSv4
_SC_AIO_LISTIO_MAX
_SC_AIO_MAX
_SC_AIO_PRIO_DELTA_MAX
_SC_ARG_MAX
_SC_ATEXIT_MAX
_SC_BC_BASE_MAX
_SC_BC_DIM_MAX
_SC_BC_SCALE_MAX
_SC_BC_STRING_MAX
_SC_CHILD_MAX
_SC_CLK_TCK
_SC_COLL_WEIGHTS_MAX
_SC_DELAYTIMER_MAX
_SC_EXPR_NEST_MAX
_SC_HOST_NAME_MAX
_SC_IOV_MAX
_SC_LINE_MAX
_SC_LOGIN_NAME_MAX
_SC_NGROUPS_MAX
_SC_GETGR_R_SIZE_MAX
_SC_GETPW_R_SIZE_MAX
_SC_MQ_OPEN_MAX
_SC_MQ_PRIO_MAX
_SC_OPEN_MAX
_SC_ADVISORY_INFO
_SC_BARRIERS
_SC_ASYNCHRONOUS_IO
_SC_CLOCK_SELECTION
_SC_CPUTIME
_SC_FSYNC
_SC_IPV6
_SC_JOB_CONTROL
_SC_MAPPED_FILES
_SC_MEMLOCK
_SC_MEMLOCK_RANGE
_SC_MEMORY_PROTECTION
_SC_MESSAGE_PASSING
_SC_MONOTONIC_CLOCK
_SC_PRIORITIZED_IO
_SC_PRIORITY_SCHEDULING
_SC_RAW_SOCKETS
_SC_READER_WRITER_LOCKS
_SC_REALTIME_SIGNALS
_SC_REGEXP
_SC_SAVED_IDS
_SC_SEMAPHORES
_SC_SHARED_MEMORY_OBJECTS
_SC_SHELL
_SC_SPAWN
_SC_SPIN_LOCKS
_SC_SPORADIC_SERVER
_SC_SS_REPL_MAX
_SC_SYNCHRONIZED_IO
_SC_THREAD_ATTR_STACKADDR
_SC_THREAD_ATTR_STACKSIZE
_SC_THREAD_CPUTIME
_SC_THREAD_PRIO_INHERIT
_SC_THREAD_PRIO_PROTECT
_SC_THREAD_PRIORITY_SCHEDULING
_SC_THREAD_PROCESS_SHARED
_SC_THREAD_ROBUST_PRIO_INHERIT
_SC_THREAD_ROBUST_PRIO_PROTECT
_SC_THREAD_SAFE_FUNCTIONS
_SC_THREAD_SPORADIC_SERVER
_SC_THREADS
_SC_TIMEOUTS
_SC_TIMERS
_SC_TRACE
_SC_TRACE_EVENT_FILTER
_SC_TRACE_EVENT_NAME_MAX
_SC_TRACE_INHERIT
_SC_TRACE_LOG
_SC_TRACE_NAME_MAX
_SC_TRACE_SYS_MAX
_SC_TRACE_USER_EVENT_MAX
_SC_TYPED_MEMORY_OBJECTS
_SC_VERSION
_SC_V7_ILP32_OFF32
_SC_V7_ILP32_OFFBIG
_SC_V7_LP64_OFF64
_SC_V7_LPBIG_OFFBIG
_SC_V6_ILP32_OFF32
_SC_V6_ILP32_OFFBIG
_SC_V6_LP64_OFF64
_SC_V6_LPBIG_OFFBIG
_SC_2_C_BIND
_SC_2_C_DEV
_SC_2_CHAR_TERM
_SC_2_FORT_DEV
_SC_2_FORT_RUN
_SC_2_LOCALEDEF
_SC_2_PBS
_SC_2_PBS_ACCOUNTING
_SC_2_PBS_CHECKPOINT
_SC_2_PBS_LOCATE
_SC_2_PBS_MESSAGE
_SC_2_PBS_TRACK
_SC_2_SW_DEV
_SC_2_UPE
_SC_2_VERSION
_SC_PAGE_SIZE
_SC_PAGESIZE
_SC_THREAD_DESTRUCTOR_ITERATIONS
_SC_THREAD_KEYS_MAX
_SC_THREAD_STACK_MIN
_SC_THREAD_THREADS_MAX
_SC_RE_DUP_MAX
_SC_RTSIG_MAX
_SC_SEM_NSEMS_MAX
_SC_SEM_VALUE_MAX
_SC_SIGQUEUE_MAX
_SC_STREAM_MAX
_SC_SYMLOOP_MAX
_SC_TIMER_MAX
_SC_TTY_NAME_MAX
_SC_TZNAME_MAX
_SC_XOPEN_CRYPT
_SC_XOPEN_ENH_I18N
_SC_XOPEN_REALTIME
_SC_XOPEN_REALTIME_THREADS
_SC_XOPEN_SHM
_SC_XOPEN_STREAMS
_SC_XOPEN_UNIX
_SC_XOPEN_UUCP
_SC_XOPEN_VERSION
# non-standard
_SC_PHYS_PAGES
_SC_AVPHYS_PAGES
_SC_NPROCESSORS_CONF
_SC_NPROCESSORS_ONLN
_SC_CPUSET_SIZE
# SUSv4
_CS_PATH
_CS_POSIX_V7_ILP32_OFF32_CFLAGS
_CS_POSIX_V7_ILP32_OFF32_LDFLAGS
_CS_POSIX_V7_ILP32_OFF32_LIBS
_CS_POSIX_V7_ILP32_OFFBIG_CFLAGS
_CS_POSIX_V7_ILP32_OFFBIG_LDFLAGS
_CS_POSIX_V7_ILP32_OFFBIG_LIBS
_CS_POSIX_V7_LP64_OFF64_CFLAGS
_CS_POSIX_V7_LP64_OFF64_LDFLAGS
_CS_POSIX_V7_LP64_OFF64_LIBS
_CS_POSIX_V7_LPBIG_OFFBIG_CFLAGS
_CS_POSIX_V7_LPBIG_OFFBIG_LDFLAGS
_CS_POSIX_V7_LPBIG_OFFBIG_LIBS
_CS_POSIX_V7_THREADS_CFLAGS
_CS_POSIX_V7_THREADS_LDFLAGS
_CS_POSIX_V7_WIDTH_RESTRICTED_ENVS
_CS_V7_ENV
_CS_POSIX_V6_ILP32_OFF32_CFLAGS
_CS_POSIX_V6_ILP32_OFF32_LDFLAGS
_CS_POSIX_V6_ILP32_OFF32_LIBS
_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS
_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS
_CS_POSIX_V6_ILP32_OFFBIG_LIBS
_CS_POSIX_V6_LP64_OFF64_CFLAGS
_CS_POSIX_V6_LP64_OFF64_LDFLAGS
_CS_POSIX_V6_LP64_OFF64_LIBS
_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS
_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS
_CS_POSIX_V6_LPBIG_OFFBIG_LIBS
_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS
_CS_V6_ENV
# non-standard
_CS_GNU_LIBC_VERSION
_CS_GNU_LIBPTHREAD_VERSION
# SUSv4
_PC_FILESIZEBITS
_PC_LINK_MAX
_PC_MAX_CANON
_PC_MAX_INPUT
_PC_NAME_MAX
_PC_PATH_MAX
_PC_PIPE_BUF
_PC_2_SYMLINKS
_PC_ALLOC_SIZE_MIN
_PC_REC_INCR_XFER_SIZE
_PC_REC_MAX_XFER_SIZE
_PC_REC_MIN_XFER_SIZE
_PC_REC_XFER_ALIGN
_PC_SYMLINK_MAX
_PC_CHOWN_RESTRICTED
_PC_NO_TRUNC
_PC_VDISABLE
_PC_ASYNC_IO
_PC_PRIO_IO
_PC_SYNC_IO
_PC_TIMESTAMP_RESOLUTION

View file

@ -125,4 +125,38 @@ class TestEtc < Test::Unit::TestCase
assert_kind_of(String, uname[sym])
}
end
def test_sysconf
begin
Etc.sysconf
rescue NotImplementedError
return
rescue ArgumentError
end
assert_kind_of(Integer, Etc.sysconf(Etc::SC_CLK_TCK))
end
def test_confstr
begin
Etc.confstr
rescue NotImplementedError
return
rescue ArgumentError
end
assert_kind_of(String, Etc.confstr(Etc::CS_PATH))
end
def test_pathconf
begin
Etc.confstr
rescue NotImplementedError
return
rescue ArgumentError
end
IO.pipe {|r, w|
val = r.pathconf(Etc::PC_PIPE_BUF)
assert(val.nil? || val.kind_of?(Integer))
}
end
end