Ruby 2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)

etc.c
Go to the documentation of this file.
1 /************************************************
2
3 etc.c -
4
5 $Author$
6 created at: Tue Mar 22 18:39:19 JST 1994
7
8 ************************************************/
9
10 #include "ruby.h"
11 #include "ruby/encoding.h"
12 #include "ruby/io.h"
13
14 #include <sys/types.h>
15 #ifdef HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif
18
19 #ifdef HAVE_GETPWENT
20 #include <pwd.h>
21 #endif
22
23 #ifdef HAVE_GETGRENT
24 #include <grp.h>
25 #endif
26
27 #include <errno.h>
28
29 #ifdef HAVE_SYS_UTSNAME_H
30 #include <sys/utsname.h>
31 #endif
32
33 #ifdef HAVE_SCHED_GETAFFINITY
34 #include <sched.h>
35 #endif
36
37 static VALUE sPasswd;
38 #ifdef HAVE_GETGRENT
39 static VALUE sGroup;
40 #endif
41
42 #ifdef _WIN32
43 #include <shlobj.h>
44 #ifndef CSIDL_COMMON_APPDATA
45 #define CSIDL_COMMON_APPDATA 35
46 #endif
47 #define HAVE_UNAME 1
48 #endif
49
50 #ifndef _WIN32
51 char *getenv();
52 #endif
53 char *getlogin();
54
55 #define RUBY_ETC_VERSION "1.1.0"
56
57 #include "constdefs.h"
58
59 /* call-seq:
60 * getlogin -> String
61 *
62 * Returns the short user name of the currently logged in user.
63 * Unfortunately, it is often rather easy to fool ::getlogin.
64 *
65 * Avoid ::getlogin for security-related purposes.
66 *
67 * If ::getlogin fails, try ::getpwuid.
68 *
69 * See the unix manpage for <code>getpwuid(3)</code> for more detail.
70 *
71 * e.g.
72 * Etc.getlogin -> 'guest'
73 */
74 static VALUE
75 etc_getlogin(VALUE obj)
76 {
77 char *login;
78
79 #ifdef HAVE_GETLOGIN
80 login = getlogin();
81 if (!login) login = getenv("USER");
82 #else
83 login = getenv("USER");
84 #endif
85
86 if (login) {
87 #ifdef _WIN32
88 rb_encoding *extenc = rb_utf8_encoding();
89 #else
90 rb_encoding *extenc = rb_locale_encoding();
91 #endif
92 return rb_external_str_new_with_enc(login, strlen(login), extenc);
93 }
94
95 return Qnil;
96 }
97
98 #if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT)
99 static VALUE
100 safe_setup_str(const char *str)
101 {
102 if (str == 0) str = "";
103 return rb_str_new2(str);
104 }
105
106 static VALUE
107 safe_setup_locale_str(const char *str)
108 {
109 if (str == 0) str = "";
110 return rb_locale_str_new_cstr(str);
111 }
112
113 static VALUE
114 safe_setup_filesystem_str(const char *str)
115 {
116 if (str == 0) str = "";
117 return rb_filesystem_str_new_cstr(str);
118 }
119 #endif
120
121 #ifdef HAVE_GETPWENT
122 static VALUE
123 setup_passwd(struct passwd *pwd)
124 {
125 if (pwd == 0) rb_sys_fail("/etc/passwd");
126 return rb_struct_new(sPasswd,
127 safe_setup_locale_str(pwd->pw_name),
128 #ifdef HAVE_STRUCT_PASSWD_PW_PASSWD
129 safe_setup_str(pwd->pw_passwd),
130 #endif
131 UIDT2NUM(pwd->pw_uid),
132 GIDT2NUM(pwd->pw_gid),
133 #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
134 safe_setup_locale_str(pwd->pw_gecos),
135 #endif
136 safe_setup_filesystem_str(pwd->pw_dir),
137 safe_setup_filesystem_str(pwd->pw_shell),
138 #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
139 INT2NUM(pwd->pw_change),
140 #endif
141 #ifdef HAVE_STRUCT_PASSWD_PW_QUOTA
142 INT2NUM(pwd->pw_quota),
143 #endif
144 #ifdef HAVE_STRUCT_PASSWD_PW_AGE
145 PW_AGE2VAL(pwd->pw_age),
146 #endif
147 #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
148 safe_setup_locale_str(pwd->pw_class),
149 #endif
150 #ifdef HAVE_STRUCT_PASSWD_PW_COMMENT
151 safe_setup_locale_str(pwd->pw_comment),
152 #endif
153 #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
154 INT2NUM(pwd->pw_expire),
155 #endif
156 0 /*dummy*/
157 );
158 }
159 #endif
160
161 /* call-seq:
162 * getpwuid(uid) -> Passwd
163 *
164 * Returns the /etc/passwd information for the user with the given integer +uid+.
165 *
166 * The information is returned as a Passwd struct.
167 *
168 * If +uid+ is omitted, the value from <code>Passwd[:uid]</code> is returned
169 * instead.
170 *
171 * See the unix manpage for <code>getpwuid(3)</code> for more detail.
172 *
173 * === Example:
174 *
175 * Etc.getpwuid(0)
176 * #=> #<struct Etc::Passwd name="root", passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
177 */
178 static VALUE
179 etc_getpwuid(int argc, VALUE *argv, VALUE obj)
180 {
181 #if defined(HAVE_GETPWENT)
182 VALUE id;
183 rb_uid_t uid;
184 struct passwd *pwd;
185
186 if (rb_scan_args(argc, argv, "01", &id) == 1) {
187 uid = NUM2UIDT(id);
188 }
189 else {
190 uid = getuid();
191 }
192 pwd = getpwuid(uid);
193 if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %d", (int)uid);
194 return setup_passwd(pwd);
195 #else
196 return Qnil;
197 #endif
198 }
199
200 /* call-seq:
201 * getpwnam(name) -> Passwd
202 *
203 * Returns the /etc/passwd information for the user with specified login
204 * +name+.
205 *
206 * The information is returned as a Passwd struct.
207 *
208 * See the unix manpage for <code>getpwnam(3)</code> for more detail.
209 *
210 * === Example:
211 *
212 * Etc.getpwnam('root')
213 * #=> #<struct Etc::Passwd name="root", passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
214 */
215 static VALUE
216 etc_getpwnam(VALUE obj, VALUE nam)
217 {
218 #ifdef HAVE_GETPWENT
219 struct passwd *pwd;
220 const char *p = StringValueCStr(nam);
221
222 pwd = getpwnam(p);
223 if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %"PRIsVALUE, nam);
224 return setup_passwd(pwd);
225 #else
226 return Qnil;
227 #endif
228 }
229
230 #ifdef HAVE_GETPWENT
231 static int passwd_blocking = 0;
232 static VALUE
233 passwd_ensure(VALUE _)
234 {
235 endpwent();
236 passwd_blocking = (int)Qfalse;
237 return Qnil;
238 }
239
240 static VALUE
241 passwd_iterate(VALUE _)
242 {
243 struct passwd *pw;
244
245 setpwent();
246 while ((pw = getpwent()) != 0) {
247 rb_yield(setup_passwd(pw));
248 }
249 return Qnil;
250 }
251
252 static void
253 each_passwd(void)
254 {
255 if (passwd_blocking) {
256 rb_raise(rb_eRuntimeError, "parallel passwd iteration");
257 }
258 passwd_blocking = (int)Qtrue;
259 rb_ensure(passwd_iterate, 0, passwd_ensure, 0);
260 }
261 #endif
262
263 /* call-seq:
264 * Etc.passwd { |struct| block } -> Passwd
265 * Etc.passwd -> Passwd
266 *
267 * Provides a convenient Ruby iterator which executes a block for each entry
268 * in the /etc/passwd file.
269 *
270 * The code block is passed an Passwd struct.
271 *
272 * See ::getpwent above for details.
273 *
274 * Example:
275 *
276 * require 'etc'
277 *
278 * Etc.passwd {|u|
279 * puts u.name + " = " + u.gecos
280 * }
281 *
282 */
283 static VALUE
284 etc_passwd(VALUE obj)
285 {
286 #ifdef HAVE_GETPWENT
287 struct passwd *pw;
288
289 if (rb_block_given_p()) {
290 each_passwd();
291 }
292 else if ((pw = getpwent()) != 0) {
293 return setup_passwd(pw);
294 }
295 #endif
296 return Qnil;
297 }
298
299 /* call-seq:
300 * Etc::Passwd.each { |struct| block } -> Passwd
301 * Etc::Passwd.each -> Enumerator
302 *
303 * Iterates for each entry in the /etc/passwd file if a block is given.
304 *
305 * If no block is given, returns the Enumerator.
306 *
307 * The code block is passed an Passwd struct.
308 *
309 * See ::getpwent above for details.
310 *
311 * Example:
312 *
313 * require 'etc'
314 *
315 * Etc::Passwd.each {|u|
316 * puts u.name + " = " + u.gecos
317 * }
318 *
319 * Etc::Passwd.collect {|u| u.gecos}
320 * Etc::Passwd.collect {|u| u.gecos}
321 *
322 */
323 static VALUE
324 etc_each_passwd(VALUE obj)
325 {
326 #ifdef HAVE_GETPWENT
327 RETURN_ENUMERATOR(obj, 0, 0);
328 each_passwd();
329 #endif
330 return obj;
331 }
332
333 /* Resets the process of reading the /etc/passwd file, so that the next call
334 * to ::getpwent will return the first entry again.
335 */
336 static VALUE
337 etc_setpwent(VALUE obj)
338 {
339 #ifdef HAVE_GETPWENT
340 setpwent();
341 #endif
342 return Qnil;
343 }
344
345 /* Ends the process of scanning through the /etc/passwd file begun with
346 * ::getpwent, and closes the file.
347 */
348 static VALUE
349 etc_endpwent(VALUE obj)
350 {
351 #ifdef HAVE_GETPWENT
352 endpwent();
353 #endif
354 return Qnil;
355 }
356
357 /* Returns an entry from the /etc/passwd file.
358 *
359 * The first time it is called it opens the file and returns the first entry;
360 * each successive call returns the next entry, or +nil+ if the end of the file
361 * has been reached.
362 *
363 * To close the file when processing is complete, call ::endpwent.
364 *
365 * Each entry is returned as a Passwd struct.
366 *
367 */
368 static VALUE
369 etc_getpwent(VALUE obj)
370 {
371 #ifdef HAVE_GETPWENT
372 struct passwd *pw;
373
374 if ((pw = getpwent()) != 0) {
375 return setup_passwd(pw);
376 }
377 #endif
378 return Qnil;
379 }
380
381 #ifdef HAVE_GETGRENT
382 static VALUE
383 setup_group(struct group *grp)
384 {
385 VALUE mem;
386 char **tbl;
387
388 mem = rb_ary_new();
389 tbl = grp->gr_mem;
390 while (*tbl) {
391 rb_ary_push(mem, safe_setup_locale_str(*tbl));
392 tbl++;
393 }
394 return rb_struct_new(sGroup,
395 safe_setup_locale_str(grp->gr_name),
396 #ifdef HAVE_STRUCT_GROUP_GR_PASSWD
397 safe_setup_str(grp->gr_passwd),
398 #endif
399 GIDT2NUM(grp->gr_gid),
400 mem);
401 }
402 #endif
403
404 /* call-seq:
405 * getgrgid(group_id) -> Group
406 *
407 * Returns information about the group with specified integer +group_id+,
408 * as found in /etc/group.
409 *
410 * The information is returned as a Group struct.
411 *
412 * See the unix manpage for <code>getgrgid(3)</code> for more detail.
413 *
414 * === Example:
415 *
416 * Etc.getgrgid(100)
417 * #=> #<struct Etc::Group name="users", passwd="x", gid=100, mem=["meta", "root"]>
418 *
419 */
420 static VALUE
421 etc_getgrgid(int argc, VALUE *argv, VALUE obj)
422 {
423 #ifdef HAVE_GETGRENT
424 VALUE id;
425 gid_t gid;
426 struct group *grp;
427
428 if (rb_scan_args(argc, argv, "01", &id) == 1) {
429 gid = NUM2GIDT(id);
430 }
431 else {
432 gid = getgid();
433 }
434 grp = getgrgid(gid);
435 if (grp == 0) rb_raise(rb_eArgError, "can't find group for %d", (int)gid);
436 return setup_group(grp);
437 #else
438 return Qnil;
439 #endif
440 }
441
442 /* call-seq:
443 * getgrnam(name) -> Group
444 *
445 * Returns information about the group with specified +name+, as found in
446 * /etc/group.
447 *
448 * The information is returned as a Group struct.
449 *
450 * See the unix manpage for <code>getgrnam(3)</code> for more detail.
451 *
452 * === Example:
453 *
454 * Etc.getgrnam('users')
455 * #=> #<struct Etc::Group name="users", passwd="x", gid=100, mem=["meta", "root"]>
456 *
457 */
458 static VALUE
459 etc_getgrnam(VALUE obj, VALUE nam)
460 {
461 #ifdef HAVE_GETGRENT
462 struct group *grp;
463 const char *p = StringValueCStr(nam);
464
465 grp = getgrnam(p);
466 if (grp == 0) rb_raise(rb_eArgError, "can't find group for %"PRIsVALUE, nam);
467 return setup_group(grp);
468 #else
469 return Qnil;
470 #endif
471 }
472
473 #ifdef HAVE_GETGRENT
474 static int group_blocking = 0;
475 static VALUE
476 group_ensure(VALUE _)
477 {
478 endgrent();
479 group_blocking = (int)Qfalse;
480 return Qnil;
481 }
482
483
484 static VALUE
485 group_iterate(VALUE _)
486 {
487 struct group *pw;
488
489 setgrent();
490 while ((pw = getgrent()) != 0) {
491 rb_yield(setup_group(pw));
492 }
493 return Qnil;
494 }
495
496 static void
497 each_group(void)
498 {
499 if (group_blocking) {
500 rb_raise(rb_eRuntimeError, "parallel group iteration");
501 }
502 group_blocking = (int)Qtrue;
503 rb_ensure(group_iterate, 0, group_ensure, 0);
504 }
505 #endif
506
507 /* Provides a convenient Ruby iterator which executes a block for each entry
508 * in the /etc/group file.
509 *
510 * The code block is passed an Group struct.
511 *
512 * See ::getgrent above for details.
513 *
514 * Example:
515 *
516 * require 'etc'
517 *
518 * Etc.group {|g|
519 * puts g.name + ": " + g.mem.join(', ')
520 * }
521 *
522 */
523 static VALUE
524 etc_group(VALUE obj)
525 {
526 #ifdef HAVE_GETGRENT
527 struct group *grp;
528
529 if (rb_block_given_p()) {
530 each_group();
531 }
532 else if ((grp = getgrent()) != 0) {
533 return setup_group(grp);
534 }
535 #endif
536 return Qnil;
537 }
538
539 #ifdef HAVE_GETGRENT
540 /* call-seq:
541 * Etc::Group.each { |group| block } -> obj
542 * Etc::Group.each -> Enumerator
543 *
544 * Iterates for each entry in the /etc/group file if a block is given.
545 *
546 * If no block is given, returns the Enumerator.
547 *
548 * The code block is passed a Group struct.
549 *
550 * Example:
551 *
552 * require 'etc'
553 *
554 * Etc::Group.each {|g|
555 * puts g.name + ": " + g.mem.join(', ')
556 * }
557 *
558 * Etc::Group.collect {|g| g.name}
559 * Etc::Group.select {|g| !g.mem.empty?}
560 *
561 */
562 static VALUE
563 etc_each_group(VALUE obj)
564 {
565 RETURN_ENUMERATOR(obj, 0, 0);
566 each_group();
567 return obj;
568 }
569 #endif
570
571 /* Resets the process of reading the /etc/group file, so that the next call
572 * to ::getgrent will return the first entry again.
573 */
574 static VALUE
575 etc_setgrent(VALUE obj)
576 {
577 #ifdef HAVE_GETGRENT
578 setgrent();
579 #endif
580 return Qnil;
581 }
582
583 /* Ends the process of scanning through the /etc/group file begun by
584 * ::getgrent, and closes the file.
585 */
586 static VALUE
587 etc_endgrent(VALUE obj)
588 {
589 #ifdef HAVE_GETGRENT
590 endgrent();
591 #endif
592 return Qnil;
593 }
594
595 /* Returns an entry from the /etc/group file.
596 *
597 * The first time it is called it opens the file and returns the first entry;
598 * each successive call returns the next entry, or +nil+ if the end of the file
599 * has been reached.
600 *
601 * To close the file when processing is complete, call ::endgrent.
602 *
603 * Each entry is returned as a Group struct
604 */
605 static VALUE
606 etc_getgrent(VALUE obj)
607 {
608 #ifdef HAVE_GETGRENT
609 struct group *gr;
610
611 if ((gr = getgrent()) != 0) {
612 return setup_group(gr);
613 }
614 #endif
615 return Qnil;
616 }
617
618 #define numberof(array) (sizeof(array) / sizeof(*(array)))
619
620 #ifdef _WIN32
621 VALUE rb_w32_special_folder(int type);
622 UINT rb_w32_system_tmpdir(WCHAR *path, UINT len);
623 VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
624 #endif
625
626 /*
627 * Returns system configuration directory.
628 *
629 * This is typically "/etc", but is modified by the prefix used when Ruby was
630 * compiled. For example, if Ruby is built and installed in /usr/local,
631 * returns "/usr/local/etc" on other platforms than Windows.
632 * On Windows, this always returns the directory provided by the system.
633 */
634 static VALUE
635 etc_sysconfdir(VALUE obj)
636 {
637 #ifdef _WIN32
638 return rb_w32_special_folder(CSIDL_COMMON_APPDATA);
639 #else
640 return rb_filesystem_str_new_cstr(SYSCONFDIR);
641 #endif
642 }
643
644 /*
645 * Returns system temporary directory; typically "/tmp".
646 */
647 static VALUE
648 etc_systmpdir(VALUE _)
649 {
650 VALUE tmpdir;
651 #ifdef _WIN32
652 WCHAR path[_MAX_PATH];
653 UINT len = rb_w32_system_tmpdir(path, numberof(path));
654 if (!len) return Qnil;
655 tmpdir = rb_w32_conv_from_wchar(path, rb_filesystem_encoding());
656 #else
657 const char default_tmp[] = "/tmp";
658 const char *tmpstr = default_tmp;
659 size_t tmplen = strlen(default_tmp);
660 # if defined _CS_DARWIN_USER_TEMP_DIR
661 #ifndef MAXPATHLEN
662 #define MAXPATHLEN 1024
663 #endif
664 char path[MAXPATHLEN];
665 size_t len;
666 len = confstr(_CS_DARWIN_USER_TEMP_DIR, path, sizeof(path));
667 if (len > 0) {
668 tmpstr = path;
669 tmplen = len - 1;
670 if (len > sizeof(path)) tmpstr = 0;
671 }
672 # endif
673 tmpdir = rb_filesystem_str_new(tmpstr, tmplen);
674 # if defined _CS_DARWIN_USER_TEMP_DIR
675 if (!tmpstr) {
676 confstr(_CS_DARWIN_USER_TEMP_DIR, RSTRING_PTR(tmpdir), len);
677 }
678 # endif
679 #endif
680 #ifndef RB_PASS_KEYWORDS
681 /* untaint on Ruby < 2.7 */
682 FL_UNSET(tmpdir, FL_TAINT);
683 #endif
684 return tmpdir;
685 }
686
687 #ifdef HAVE_UNAME
688 /*
689 * Returns the system information obtained by uname system call.
690 *
691 * The return value is a hash which has 5 keys at least:
692 * :sysname, :nodename, :release, :version, :machine
693 *
694 * Example:
695 *
696 * require 'etc'
697 * require 'pp'
698 *
699 * pp Etc.uname
700 * #=> {:sysname=>"Linux",
701 * # :nodename=>"boron",
702 * # :release=>"2.6.18-6-xen-686",
703 * # :version=>"#1 SMP Thu Nov 5 19:54:42 UTC 2009",
704 * # :machine=>"i686"}
705 *
706 */
707 static VALUE
708 etc_uname(VALUE obj)
709 {
710 #ifdef _WIN32
711 OSVERSIONINFOW v;
712 SYSTEM_INFO s;
713 const char *sysname, *mach;
714 VALUE result, release, version;
715 VALUE vbuf, nodename = Qnil;
716 DWORD len = 0;
717 WCHAR *buf;
718
719 v.dwOSVersionInfoSize = sizeof(v);
720 if (!GetVersionExW(&v))
721 rb_sys_fail("GetVersionEx");
722
723 result = rb_hash_new();
724 switch (v.dwPlatformId) {
725 case VER_PLATFORM_WIN32s:
726 sysname = "Win32s";
727 break;
728 case VER_PLATFORM_WIN32_NT:
729 sysname = "Windows_NT";
730 break;
731 case VER_PLATFORM_WIN32_WINDOWS:
732 default:
733 sysname = "Windows";
734 break;
735 }
736 rb_hash_aset(result, ID2SYM(rb_intern("sysname")), rb_str_new_cstr(sysname));
737 release = rb_sprintf("%lu.%lu.%lu", v.dwMajorVersion, v.dwMinorVersion, v.dwBuildNumber);
738 rb_hash_aset(result, ID2SYM(rb_intern("release")), release);
739 version = rb_sprintf("%s Version %"PRIsVALUE": %"PRIsVALUE, sysname, release,
740 rb_w32_conv_from_wchar(v.szCSDVersion, rb_utf8_encoding()));
741 rb_hash_aset(result, ID2SYM(rb_intern("version")), version);
742
743 # if defined _MSC_VER && _MSC_VER < 1300
744 # define GET_COMPUTER_NAME(ptr, plen) GetComputerNameW(ptr, plen)
745 # else
746 # define GET_COMPUTER_NAME(ptr, plen) GetComputerNameExW(ComputerNameDnsFullyQualified, ptr, plen)
747 # endif
748 GET_COMPUTER_NAME(NULL, &len);
749 buf = ALLOCV_N(WCHAR, vbuf, len);
750 if (GET_COMPUTER_NAME(buf, &len)) {
751 nodename = rb_w32_conv_from_wchar(buf, rb_utf8_encoding());
752 }
753 ALLOCV_END(vbuf);
754 if (NIL_P(nodename)) nodename = rb_str_new(0, 0);
755 rb_hash_aset(result, ID2SYM(rb_intern("nodename")), nodename);
756
757 # ifndef PROCESSOR_ARCHITECTURE_AMD64
758 # define PROCESSOR_ARCHITECTURE_AMD64 9
759 # endif
760 # ifndef PROCESSOR_ARCHITECTURE_INTEL
761 # define PROCESSOR_ARCHITECTURE_INTEL 0
762 # endif
763 GetSystemInfo(&s);
764 switch (s.wProcessorArchitecture) {
765 case PROCESSOR_ARCHITECTURE_AMD64:
766 mach = "x64";
767 break;
768 case PROCESSOR_ARCHITECTURE_ARM:
769 mach = "ARM";
770 break;
771 case PROCESSOR_ARCHITECTURE_INTEL:
772 mach = "x86";
773 break;
774 default:
775 mach = "unknown";
776 break;
777 }
778
779 rb_hash_aset(result, ID2SYM(rb_intern("machine")), rb_str_new_cstr(mach));
780 #else
781 struct utsname u;
782 int ret;
783 VALUE result;
784
785 ret = uname(&u);
786 if (ret == -1)
787 rb_sys_fail("uname");
788
789 result = rb_hash_new();
790 rb_hash_aset(result, ID2SYM(rb_intern("sysname")), rb_str_new_cstr(u.sysname));
791 rb_hash_aset(result, ID2SYM(rb_intern("nodename")), rb_str_new_cstr(u.nodename));
792 rb_hash_aset(result, ID2SYM(rb_intern("release")), rb_str_new_cstr(u.release));
793 rb_hash_aset(result, ID2SYM(rb_intern("version")), rb_str_new_cstr(u.version));
794 rb_hash_aset(result, ID2SYM(rb_intern("machine")), rb_str_new_cstr(u.machine));
795 #endif
796
797 return result;
798 }
799 #else
800 #define etc_uname rb_f_notimplement
801 #endif
802
803 #ifdef HAVE_SYSCONF
804 /*
805 * Returns system configuration variable using sysconf().
806 *
807 * _name_ should be a constant under <code>Etc</code> which begins with <code>SC_</code>.
808 *
809 * The return value is an integer or nil.
810 * nil means indefinite limit. (sysconf() returns -1 but errno is not set.)
811 *
812 * Etc.sysconf(Etc::SC_ARG_MAX) #=> 2097152
813 * Etc.sysconf(Etc::SC_LOGIN_NAME_MAX) #=> 256
814 *
815 */
816 static VALUE
817 etc_sysconf(VALUE obj, VALUE arg)
818 {
819 int name;
820 long ret;
821
822 name = NUM2INT(arg);
823
824 errno = 0;
825 ret = sysconf(name);
826 if (ret == -1) {
827 if (errno == 0) /* no limit */
828 return Qnil;
829 rb_sys_fail("sysconf");
830 }
831 return LONG2NUM(ret);
832 }
833 #else
834 #define etc_sysconf rb_f_notimplement
835 #endif
836
837 #ifdef HAVE_CONFSTR
838 /*
839 * Returns system configuration variable using confstr().
840 *
841 * _name_ should be a constant under <code>Etc</code> which begins with <code>CS_</code>.
842 *
843 * The return value is a string or nil.
844 * nil means no configuration-defined value. (confstr() returns 0 but errno is not set.)
845 *
846 * Etc.confstr(Etc::CS_PATH) #=> "/bin:/usr/bin"
847 *
848 * # GNU/Linux
849 * Etc.confstr(Etc::CS_GNU_LIBC_VERSION) #=> "glibc 2.18"
850 * Etc.confstr(Etc::CS_GNU_LIBPTHREAD_VERSION) #=> "NPTL 2.18"
851 *
852 */
853 static VALUE
854 etc_confstr(VALUE obj, VALUE arg)
855 {
856 int name;
857 char localbuf[128], *buf = localbuf;
858 size_t bufsize = sizeof(localbuf), ret;
859 VALUE tmp;
860
861 name = NUM2INT(arg);
862
863 errno = 0;
864 ret = confstr(name, buf, bufsize);
865 if (bufsize < ret) {
866 bufsize = ret;
867 buf = ALLOCV_N(char, tmp, bufsize);
868 errno = 0;
869 ret = confstr(name, buf, bufsize);
870 }
871 if (bufsize < ret)
872 rb_bug("required buffer size for confstr() changed dynamically.");
873 if (ret == 0) {
874 if (errno == 0) /* no configuration-defined value */
875 return Qnil;
876 rb_sys_fail("confstr");
877 }
878 return rb_str_new_cstr(buf);
879 }
880 #else
881 #define etc_confstr rb_f_notimplement
882 #endif
883
884 #ifdef HAVE_FPATHCONF
885 /*
886 * Returns pathname configuration variable using fpathconf().
887 *
888 * _name_ should be a constant under <code>Etc</code> which begins with <code>PC_</code>.
889 *
890 * The return value is an integer or nil.
891 * nil means indefinite limit. (fpathconf() returns -1 but errno is not set.)
892 *
893 * require 'etc'
894 * IO.pipe {|r, w|
895 * p w.pathconf(Etc::PC_PIPE_BUF) #=> 4096
896 * }
897 *
898 */
899 static VALUE
900 io_pathconf(VALUE io, VALUE arg)
901 {
902 int name;
903 long ret;
904 rb_io_t *fptr;
905
906 name = NUM2INT(arg);
907
908 GetOpenFile(io, fptr);
909
910 errno = 0;
911 ret = fpathconf(fptr->fd, name);
912 if (ret == -1) {
913 if (errno == 0) /* no limit */
914 return Qnil;
915 rb_sys_fail("fpathconf");
916 }
917 return LONG2NUM(ret);
918 }
919 #else
920 #define io_pathconf rb_f_notimplement
921 #endif
922
923 #if (defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)) || defined(_WIN32)
924
925 #if defined(HAVE_SCHED_GETAFFINITY) && defined(CPU_ALLOC)
926 static int
927 etc_nprocessors_affin(void)
928 {
929 cpu_set_t *cpuset;
930 size_t size;
931 int ret;
932 int n;
933
934 /*
935 * XXX:
936 * man page says CPU_ALLOC takes number of cpus. But it is not accurate
937 * explanation. sched_getaffinity() returns EINVAL if cpuset bitmap is
938 * smaller than kernel internal bitmap.
939 * That said, sched_getaffinity() can fail when a kernel have sparse bitmap
940 * even if cpuset bitmap is larger than number of cpus.
941 * The precious way is to use /sys/devices/system/cpu/online. But there are
942 * two problems,
943 * - Costly calculation
944 * It is a minor issue, but possibly kill a benefit of a parallel processing.
945 * - No guarantee to exist /sys/devices/system/cpu/online
946 * This is an issue especially when using Linux containers.
947 * So, we use hardcode number for a workaround. Current linux kernel
948 * (Linux 3.17) support 8192 cpus at maximum. Then 16384 must be enough.
949 */
950 for (n=64; n <= 16384; n *= 2) {
951 size = CPU_ALLOC_SIZE(n);
952 if (size >= 1024) {
953 cpuset = xcalloc(1, size);
954 if (!cpuset)
955 return -1;
956 } else {
957 cpuset = alloca(size);
958 CPU_ZERO_S(size, cpuset);
959 }
960
961 ret = sched_getaffinity(0, size, cpuset);
962 if (ret == 0) {
963 /* On success, count number of cpus. */
964 ret = CPU_COUNT_S(size, cpuset);
965 }
966
967 if (size >= 1024) {
968 xfree(cpuset);
969 }
970 if (ret > 0) {
971 return ret;
972 }
973 }
974
975 return ret;
976 }
977 #endif
978
979 /*
980 * Returns the number of online processors.
981 *
982 * The result is intended as the number of processes to
983 * use all available processors.
984 *
985 * This method is implemented using:
986 * - sched_getaffinity(): Linux
987 * - sysconf(_SC_NPROCESSORS_ONLN): GNU/Linux, NetBSD, FreeBSD, OpenBSD, DragonFly BSD, OpenIndiana, Mac OS X, AIX
988 *
989 * Example:
990 *
991 * require 'etc'
992 * p Etc.nprocessors #=> 4
993 *
994 * The result might be smaller number than physical cpus especially when ruby
995 * process is bound to specific cpus. This is intended for getting better
996 * parallel processing.
997 *
998 * Example: (Linux)
999 *
1000 * linux$ taskset 0x3 ./ruby -retc -e "p Etc.nprocessors" #=> 2
1001 *
1002 */
1003 static VALUE
1004 etc_nprocessors(VALUE obj)
1005 {
1006 long ret;
1007
1008 #if !defined(_WIN32)
1009
1010 #if defined(HAVE_SCHED_GETAFFINITY) && defined(CPU_ALLOC)
1011 int ncpus;
1012
1013 ncpus = etc_nprocessors_affin();
1014 if (ncpus != -1) {
1015 return INT2NUM(ncpus);
1016 }
1017 /* fallback to _SC_NPROCESSORS_ONLN */
1018 #endif
1019
1020 errno = 0;
1021 ret = sysconf(_SC_NPROCESSORS_ONLN);
1022 if (ret == -1) {
1023 rb_sys_fail("sysconf(_SC_NPROCESSORS_ONLN)");
1024 }
1025 #else
1026 SYSTEM_INFO si;
1027 GetSystemInfo(&si);
1028 ret = (long)si.dwNumberOfProcessors;
1029 #endif
1030 return LONG2NUM(ret);
1031 }
1032 #else
1033 #define etc_nprocessors rb_f_notimplement
1034 #endif
1035
1036 /*
1037 * The Etc module provides access to information typically stored in
1038 * files in the /etc directory on Unix systems.
1039 *
1040 * The information accessible consists of the information found in the
1041 * /etc/passwd and /etc/group files, plus information about the system's
1042 * temporary directory (/tmp) and configuration directory (/etc).
1043 *
1044 * The Etc module provides a more reliable way to access information about
1045 * the logged in user than environment variables such as +$USER+.
1046 *
1047 * == Example:
1048 *
1049 * require 'etc'
1050 *
1051 * login = Etc.getlogin
1052 * info = Etc.getpwnam(login)
1053 * username = info.gecos.split(/,/).first
1054 * puts "Hello #{username}, I see your login name is #{login}"
1055 *
1056 * Note that the methods provided by this module are not always secure.
1057 * It should be used for informational purposes, and not for security.
1058 *
1059 * All operations defined in this module are class methods, so that you can
1060 * include the Etc module into your class.
1061 */
1062 void
1063 Init_etc(void)
1064 {
1065 VALUE mEtc;
1066
1067 mEtc = rb_define_module("Etc");
1068 rb_define_const(mEtc, "VERSION", rb_str_new_cstr(RUBY_ETC_VERSION));
1069 init_constants(mEtc);
1070
1071 rb_define_module_function(mEtc, "getlogin", etc_getlogin, 0);
1072
1073 rb_define_module_function(mEtc, "getpwuid", etc_getpwuid, -1);
1074 rb_define_module_function(mEtc, "getpwnam", etc_getpwnam, 1);
1075 rb_define_module_function(mEtc, "setpwent", etc_setpwent, 0);
1076 rb_define_module_function(mEtc, "endpwent", etc_endpwent, 0);
1077 rb_define_module_function(mEtc, "getpwent", etc_getpwent, 0);
1078 rb_define_module_function(mEtc, "passwd", etc_passwd, 0);
1079
1080 rb_define_module_function(mEtc, "getgrgid", etc_getgrgid, -1);
1081 rb_define_module_function(mEtc, "getgrnam", etc_getgrnam, 1);
1082 rb_define_module_function(mEtc, "group", etc_group, 0);
1083 rb_define_module_function(mEtc, "setgrent", etc_setgrent, 0);
1084 rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0);
1085 rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0);
1086 rb_define_module_function(mEtc, "sysconfdir", etc_sysconfdir, 0);
1087 rb_define_module_function(mEtc, "systmpdir", etc_systmpdir, 0);
1088 rb_define_module_function(mEtc, "uname", etc_uname, 0);
1089 rb_define_module_function(mEtc, "sysconf", etc_sysconf, 1);
1090 rb_define_module_function(mEtc, "confstr", etc_confstr, 1);
1091 rb_define_method(rb_cIO, "pathconf", io_pathconf, 1);
1092 rb_define_module_function(mEtc, "nprocessors", etc_nprocessors, 0);
1093
1094 sPasswd = rb_struct_define_under(mEtc, "Passwd",
1095 "name",
1096 #ifdef HAVE_STRUCT_PASSWD_PW_PASSWD
1097 "passwd",
1098 #endif
1099 "uid",
1100 "gid",
1101 #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
1102 "gecos",
1103 #endif
1104 "dir",
1105 "shell",
1106 #ifdef HAVE_STRUCT_PASSWD_PW_CHANGE
1107 "change",
1108 #endif
1109 #ifdef HAVE_STRUCT_PASSWD_PW_QUOTA
1110 "quota",
1111 #endif
1112 #ifdef HAVE_STRUCT_PASSWD_PW_AGE
1113 "age",
1114 #endif
1115 #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
1116 "uclass",
1117 #endif
1118 #ifdef HAVE_STRUCT_PASSWD_PW_COMMENT
1119 "comment",
1120 #endif
1121 #ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE
1122 "expire",
1123 #endif
1124 NULL);
1125 #if 0
1126 /* Define-const: Passwd
1127 *
1128 * Passwd is a Struct that contains the following members:
1129 *
1130 * name::
1131 * contains the short login name of the user as a String.
1132 * passwd::
1133 * contains the encrypted password of the user as a String.
1134 * an 'x' is returned if shadow passwords are in use. An '*' is returned
1135 * if the user cannot log in using a password.
1136 * uid::
1137 * contains the integer user ID (uid) of the user.
1138 * gid::
1139 * contains the integer group ID (gid) of the user's primary group.
1140 * dir::
1141 * contains the path to the home directory of the user as a String.
1142 * shell::
1143 * contains the path to the login shell of the user as a String.
1144 *
1145 * === The following members below are optional, and must be compiled with special flags:
1146 *
1147 * gecos::
1148 * contains a longer String description of the user, such as
1149 * a full name. Some Unix systems provide structured information in the
1150 * gecos field, but this is system-dependent.
1151 * must be compiled with +HAVE_STRUCT_PASSWD_PW_GECOS+
1152 * change::
1153 * password change time(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_CHANGE+
1154 * quota::
1155 * quota value(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_QUOTA+
1156 * age::
1157 * password age(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_AGE+
1158 * class::
1159 * user access class(string) must be compiled with +HAVE_STRUCT_PASSWD_PW_CLASS+
1160 * comment::
1161 * comment(string) must be compiled with +HAVE_STRUCT_PASSWD_PW_COMMENT+
1162 * expire::
1163 * account expiration time(integer) must be compiled with +HAVE_STRUCT_PASSWD_PW_EXPIRE+
1164 */
1165 rb_define_const(mEtc, "Passwd", sPasswd);
1166 #endif
1167 rb_define_const(rb_cStruct, "Passwd", sPasswd); /* deprecated name */
1168 rb_extend_object(sPasswd, rb_mEnumerable);
1169 rb_define_singleton_method(sPasswd, "each", etc_each_passwd, 0);
1170
1171 #ifdef HAVE_GETGRENT
1172 sGroup = rb_struct_define_under(mEtc, "Group", "name",
1173 #ifdef HAVE_STRUCT_GROUP_GR_PASSWD
1174 "passwd",
1175 #endif
1176 "gid", "mem", NULL);
1177
1178 #if 0
1179 /* Define-const: Group
1180 *
1181 * Group is a Struct that is only available when compiled with +HAVE_GETGRENT+.
1182 *
1183 * The struct contains the following members:
1184 *
1185 * name::
1186 * contains the name of the group as a String.
1187 * passwd::
1188 * contains the encrypted password as a String. An 'x' is
1189 * returned if password access to the group is not available; an empty
1190 * string is returned if no password is needed to obtain membership of
1191 * the group.
1192 *
1193 * Must be compiled with +HAVE_STRUCT_GROUP_GR_PASSWD+.
1194 * gid::
1195 * contains the group's numeric ID as an integer.
1196 * mem::
1197 * is an Array of Strings containing the short login names of the
1198 * members of the group.
1199 */
1200 rb_define_const(mEtc, "Group", sGroup);
1201 #endif
1202 rb_define_const(rb_cStruct, "Group", sGroup); /* deprecated name */
1203 rb_extend_object(sGroup, rb_mEnumerable);
1204 rb_define_singleton_method(sGroup, "each", etc_each_group, 0);
1205 #endif
1206 }
constdefs.h
rb_struct_define_under
VALUE rb_struct_define_under(VALUE, const char *,...)
Definition: struct.c:449
xcalloc
#define xcalloc
Definition: defines.h:213
rb_str_new2
#define rb_str_new2
Definition: intern.h:903
rb_filesystem_encoding
rb_encoding * rb_filesystem_encoding(void)
Definition: encoding.c:1387
id
const int id
Definition: nkf.c:209
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:1501
path
VALUE path
Definition: rb_mjit_min_header-2.7.0.h:7351
rb_block_given_p
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:897
etc_nprocessors
#define etc_nprocessors
Definition: etc.c:1033
rb_scan_args
#define rb_scan_args(argc, argvp, fmt,...)
Definition: rb_mjit_min_header-2.7.0.h:6372
_SC_NPROCESSORS_ONLN
#define _SC_NPROCESSORS_ONLN
Definition: rb_mjit_min_header-2.7.0.h:3374
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:1009
rb_locale_encoding
rb_encoding * rb_locale_encoding(void)
Definition: encoding.c:1372
VALUE
unsigned long VALUE
Definition: ruby.h:102
rb_eArgError
VALUE rb_eArgError
Definition: error.c:923
encoding.h
rb_intern
#define rb_intern(str)
fpathconf
long fpathconf(int __fd, int __name)
int
__inline__ int
Definition: rb_mjit_min_header-2.7.0.h:2839
rb_define_module
VALUE rb_define_module(const char *name)
Definition: class.c:772
endpwent
#define endpwent()
DWORD
IUnknown DWORD
Definition: win32ole.c:33
rb_define_singleton_method
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1755
NUM2GIDT
#define NUM2GIDT(v)
Definition: ruby.h:369
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1551
INT2NUM
#define INT2NUM(x)
Definition: ruby.h:1609
Qfalse
#define Qfalse
Definition: ruby.h:467
rb_io_t::fd
int fd
Definition: io.h:68
NULL
#define NULL
Definition: _sdbm.c:101
rb_filesystem_str_new_cstr
VALUE rb_filesystem_str_new_cstr(const char *)
Definition: string.c:1117
PRIsVALUE
#define PRIsVALUE
Definition: ruby.h:166
rb_w32_special_folder
VALUE rb_w32_special_folder(int type)
Definition: win32.c:499
sysconf
long sysconf(int __name)
ID2SYM
#define ID2SYM(x)
Definition: ruby.h:414
strlen
size_t strlen(const char *)
etc_uname
#define etc_uname
Definition: etc.c:800
MAXPATHLEN
#define MAXPATHLEN
Definition: dln.c:69
rb_struct_new
VALUE rb_struct_new(VALUE,...)
Definition: struct.c:733
Init_etc
void Init_etc(void)
Definition: etc.c:1063
v
int VALUE v
Definition: rb_mjit_min_header-2.7.0.h:12332
RUBY_ETC_VERSION
#define RUBY_ETC_VERSION
Definition: etc.c:55
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2669
getuid
rb_uid_t getuid(void)
Definition: win32.c:2765
LONG2NUM
#define LONG2NUM(x)
Definition: ruby.h:1644
obj
const VALUE VALUE obj
Definition: rb_mjit_min_header-2.7.0.h:5742
FL_TAINT
#define FL_TAINT
Definition: ruby.h:1283
UIDT2NUM
#define UIDT2NUM(v)
Definition: ruby.h:360
rb_encoding
const typedef OnigEncodingType rb_encoding
Definition: encoding.h:115
ALLOCV_END
#define ALLOCV_END(v)
Definition: ruby.h:1750
io_pathconf
#define io_pathconf
Definition: etc.c:920
ALLOCV_N
#define ALLOCV_N(type, v, n)
Definition: ruby.h:1749
long
#define long
Definition: rb_mjit_min_header-2.7.0.h:2880
FL_UNSET
#define FL_UNSET(x, f)
Definition: ruby.h:1361
etc_confstr
#define etc_confstr
Definition: etc.c:881
alloca
#define alloca(size)
Definition: rb_mjit_min_header-2.7.0.h:2487
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1195
ruby.h
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:2793
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:920
RETURN_ENUMERATOR
#define RETURN_ENUMERATOR(obj, argc, argv)
Definition: intern.h:279
size
int size
Definition: encoding.c:58
CSIDL_COMMON_APPDATA
#define CSIDL_COMMON_APPDATA
Definition: win32.c:420
rb_str_new_cstr
#define rb_str_new_cstr(str)
Definition: rb_mjit_min_header-2.7.0.h:6117
rb_extend_object
void rb_extend_object(VALUE obj, VALUE module)
Extend the object with the module.
Definition: eval.c:1700
StringValueCStr
#define StringValueCStr(v)
Definition: ruby.h:604
confstr
size_t confstr(int __name, char *__buf, size_t __len)
rb_locale_str_new_cstr
#define rb_locale_str_new_cstr(str)
Definition: rb_mjit_min_header-2.7.0.h:6124
gid_t
__gid_t gid_t
Definition: rb_mjit_min_header-2.7.0.h:1323
rb_define_module_function
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1771
n
const char size_t n
Definition: rb_mjit_min_header-2.7.0.h:5456
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4322
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:634
arg
VALUE arg
Definition: rb_mjit_min_header-2.7.0.h:5601
argv
char ** argv
Definition: ruby.c:223
rb_sprintf
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1197
rb_utf8_encoding
rb_encoding * rb_utf8_encoding(void)
Definition: encoding.c:1328
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
etc_sysconf
#define etc_sysconf
Definition: etc.c:834
rb_hash_aset
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:2779
NIL_P
#define NIL_P(v)
Definition: ruby.h:482
getlogin
char * getlogin()
Definition: win32.c:881
io.h
rb_external_str_new_with_enc
VALUE rb_external_str_new_with_enc(const char *ptr, long len, rb_encoding *)
Definition: string.c:1036
argc
int argc
Definition: ruby.c:222
rb_define_const
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2880
getenv
char * getenv()
getgid
rb_gid_t getgid(void)
Definition: win32.c:2779
xfree
#define xfree
Definition: defines.h:216
GetOpenFile
#define GetOpenFile(obj, fp)
Definition: io.h:127
rb_str_new
#define rb_str_new(str, len)
Definition: rb_mjit_min_header-2.7.0.h:6116
_
#define _(args)
Definition: dln.h:28
rb_w32_system_tmpdir
UINT rb_w32_system_tmpdir(WCHAR *path, UINT len)
Definition: win32.c:515
Qtrue
#define Qtrue
Definition: ruby.h:468
errno
int errno
NUM2UIDT
#define NUM2UIDT(v)
Definition: ruby.h:363
rb_filesystem_str_new
VALUE rb_filesystem_str_new(const char *, long)
Definition: string.c:1111
len
uint8_t len
Definition: escape.c:17
rb_cStruct
RUBY_EXTERN VALUE rb_cStruct
Definition: ruby.h:2045
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1237
rb_uid_t
#define rb_uid_t
Definition: rb_mjit_min_header-2.7.0.h:105
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:1114
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:723
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:715
Qnil
#define Qnil
Definition: ruby.h:469
rb_mEnumerable
VALUE rb_mEnumerable
Definition: enum.c:20
rb_io_t
Definition: io.h:66
numberof
#define numberof(array)
Definition: etc.c:618
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:39
rb_cIO
RUBY_EXTERN VALUE rb_cIO
Definition: ruby.h:2030
rb_w32_conv_from_wchar
VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc)
Definition: win32.c:2229
GIDT2NUM
#define GIDT2NUM(v)
Definition: ruby.h:366
name
const char * name
Definition: nkf.c:208